Bug 1449024 - Extend Tabs component to allow a toggle button beside the tabs. r=Honza draft
authorGabriel Luong <gabriel.luong@gmail.com>
Mon, 02 Apr 2018 22:55:21 -0400
changeset 776432 6caf3c2f7015b8614de33d83258aa6a925558a87
parent 776411 3a78edaef5e7d49c3032b1219415a76dfdded206
push id104880
push userbmo:gl@mozilla.com
push dateTue, 03 Apr 2018 02:56:40 +0000
reviewersHonza
bugs1449024
milestone61.0a1
Bug 1449024 - Extend Tabs component to allow a toggle button beside the tabs. r=Honza MozReview-Commit-ID: 5ydMfGVis8c
devtools/client/shared/components/Sidebar.js
devtools/client/shared/components/moz.build
devtools/client/shared/components/tabs/TabBar.js
devtools/client/shared/components/tabs/Tabs.js
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
         )
       );
     }