Bug 1449024 - Extend Tabs component to allow a toggle button beside the tabs. r=Honza
MozReview-Commit-ID: 5ydMfGVis8c
new file mode 100644
--- /dev/null
+++ b/devtools/client/shared/components/Sidebar.js
@@ -0,0 +1,87 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+
+const SidebarToggle = createFactory(require("devtools/client/shared/components/SidebarToggle"));
+const Tabs = createFactory(require("devtools/client/shared/components/tabs/Tabs").Tabs);
+
+class Sidebar extends PureComponent {
+ static get propTypes() {
+ return {
+ children: PropTypes.oneOfType([
+ PropTypes.array,
+ PropTypes.element
+ ]).isRequired,
+ onAfterChange: PropTypes.func,
+ onAllTabsMenuClick: PropTypes.func,
+ renderOnlySelected: PropTypes.bool,
+ showAllTabsMenu: PropTypes.bool,
+ sidebarToggleButton: PropTypes.shape({
+ collapsed: PropTypes.bool.isRequired,
+ collapsePaneTitle: PropTypes.string.isRequired,
+ expandPaneTitle: PropTypes.string.isRequired,
+ onClick: PropTypes.func.isRequired,
+ }),
+ tabActive: PropTypes.number,
+ };
+ }
+
+ constructor(props) {
+ super(props);
+ this.renderSidebarToggle = this.renderSidebarToggle.bind(this);
+ }
+
+ renderSidebarToggle() {
+ if (!this.props.sidebarToggleButton) {
+ return null;
+ }
+
+ const {
+ collapsed,
+ collapsePaneTitle,
+ expandPaneTitle,
+ onClick,
+ } = this.props.sidebarToggleButton;
+
+ return (
+ SidebarToggle({
+ collapsed,
+ collapsePaneTitle,
+ expandPaneTitle,
+ onClick,
+ })
+ );
+ }
+
+ render() {
+ const { renderSidebarToggle } = this;
+ const {
+ children,
+ onAfterChange,
+ onAllTabsMenuClick,
+ renderOnlySelected,
+ showAllTabsMenu,
+ tabActive,
+ } = this.props;
+
+ return (
+ Tabs({
+ onAfterChange,
+ onAllTabsMenuClick,
+ renderOnlySelected,
+ renderSidebarToggle,
+ showAllTabsMenu,
+ tabActive,
+ },
+ children
+ )
+ );
+ }
+}
+
+module.exports = Sidebar;
--- a/devtools/client/shared/components/moz.build
+++ b/devtools/client/shared/components/moz.build
@@ -13,16 +13,17 @@ DIRS += [
DevToolsModules(
'AutoCompletePopup.js',
'Frame.js',
'HSplitBox.js',
'NotificationBox.css',
'NotificationBox.js',
'SearchBox.js',
+ 'Sidebar.js',
'SidebarToggle.css',
'SidebarToggle.js',
'StackTrace.js',
'VirtualizedTree.js',
'VisibilityHandler.js',
)
MOCHITEST_CHROME_MANIFESTS += ['test/mochitest/chrome.ini']
--- a/devtools/client/shared/components/tabs/TabBar.js
+++ b/devtools/client/shared/components/tabs/TabBar.js
@@ -6,36 +6,47 @@
/* eslint-env browser */
"use strict";
const { Component, createFactory } = require("devtools/client/shared/vendor/react");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
-const Tabs = createFactory(require("devtools/client/shared/components/tabs/Tabs").Tabs);
const Menu = require("devtools/client/framework/menu");
const MenuItem = require("devtools/client/framework/menu-item");
+const Sidebar = createFactory(require("devtools/client/shared/components/Sidebar"));
+
// Shortcuts
const { div } = dom;
/**
* Renders Tabbar component.
*/
class Tabbar extends Component {
static get propTypes() {
return {
children: PropTypes.array,
menuDocument: PropTypes.object,
onSelect: PropTypes.func,
showAllTabsMenu: PropTypes.bool,
activeTabId: PropTypes.string,
renderOnlySelected: PropTypes.bool,
+ sidebarToggleButton: PropTypes.shape({
+ // Set to true if collapsed.
+ collapsed: PropTypes.bool.isRequired,
+ // Tooltip text used when the button indicates expanded state.
+ collapsePaneTitle: PropTypes.string.isRequired,
+ // Tooltip text used when the button indicates collapsed state.
+ expandPaneTitle: PropTypes.string.isRequired,
+ // Click callback
+ onClick: PropTypes.func.isRequired,
+ }),
};
}
static get defaultProps() {
return {
menuDocument: window.parent.document,
showAllTabsMenu: false,
};
@@ -249,20 +260,21 @@ class Tabbar extends Component {
return tab.panel;
}
render() {
let tabs = this.state.tabs.map((tab) => this.renderTab(tab));
return (
div({className: "devtools-sidebar-tabs"},
- Tabs({
+ Sidebar({
onAllTabsMenuClick: this.onAllTabsMenuClick,
renderOnlySelected: this.props.renderOnlySelected,
showAllTabsMenu: this.props.showAllTabsMenu,
+ sidebarToggleButton: this.props.sidebarToggleButton,
tabActive: this.state.activeTab,
onAfterChange: this.onTabChanged,
},
tabs
)
)
);
}
--- a/devtools/client/shared/components/tabs/Tabs.js
+++ b/devtools/client/shared/components/tabs/Tabs.js
@@ -46,16 +46,19 @@ define(function(require, exports, module
onAfterChange: PropTypes.func,
children: PropTypes.oneOfType([
PropTypes.array,
PropTypes.element
]).isRequired,
showAllTabsMenu: PropTypes.bool,
onAllTabsMenuClick: PropTypes.func,
+ // To render a sidebar toggle button before the tab menu provide a function that
+ // returns a React component for the button.
+ renderSidebarToggle: PropTypes.func,
// Set true will only render selected panel on DOM. It's complete
// opposite of the created array, and it's useful if panels content
// is unpredictable and update frequently.
renderOnlySelected: PropTypes.bool,
};
}
static get defaultProps() {
@@ -323,18 +326,23 @@ define(function(require, exports, module
// space for all tabs (and overflow happened).
let allTabsMenu = this.state.overflow ? (
dom.div({
className: "all-tabs-menu",
onClick: this.props.onAllTabsMenuClick,
})
) : null;
+ // Get the sidebar toggle button if a renderSidebarToggle function is provided.
+ let sidebarToggle = this.props.renderSidebarToggle ?
+ this.props.renderSidebarToggle() : null;
+
return (
dom.nav({className: "tabs-navigation"},
+ sidebarToggle,
dom.ul({className: "tabs-menu", role: "tablist"},
tabs
),
allTabsMenu
)
);
}