diff --git a/src/TabbedTable/Tab.jsx b/src/TabbedTable/Tab.jsx new file mode 100644 index 000000000..d1ee2707c --- /dev/null +++ b/src/TabbedTable/Tab.jsx @@ -0,0 +1,13 @@ +import * as PropTypes from "prop-types"; +import {Table} from "clever-components"; +import MorePropTypes from "clever-components/dist/utils/MorePropTypes"; + + +export default function Tab() { + throw new Error("Configuration component - not meant to be rendered."); +} + +Tab.propTypes = { + children: MorePropTypes.instanceOfComponent(Table), + name: PropTypes.string.isRequired, +}; diff --git a/src/TabbedTable/TabbedTable.jsx b/src/TabbedTable/TabbedTable.jsx new file mode 100644 index 000000000..4b42ec4d5 --- /dev/null +++ b/src/TabbedTable/TabbedTable.jsx @@ -0,0 +1,80 @@ +import * as PropTypes from "prop-types"; +import * as React from "react"; +import * as classnames from "classnames"; +import MorePropTypes from "clever-components/dist/utils/MorePropTypes"; + +import Tab from "./Tab"; + +import "./TabbedTable.less"; + + +export default class TabbedTable extends React.PureComponent { + static cssClass = { + TAB_BAR: "TabbedTable--TabBar", + TITLE: "TabbedTable--Title", + TABS: "TabbedTable--Tabs", + TAB_NAME: "TabbedTable--TabName", + SELECTED_TAB_NAME: "TabbedTable--SelectedTabName", + }; + + static propTypes = { + children: PropTypes.arrayOf(PropTypes.oneOfType([ + MorePropTypes.instanceOfComponent(Tab), + PropTypes.oneOf([null, false]), // allow for conditionally including tabs + ])).isRequired, + title: PropTypes.string, + }; + + constructor(props) { + super(props); + + this.state = { + selectedTabIndex: 0, + }; + } + + _onSelect(e, tabIndex) { + e.preventDefault(); + this.setState({selectedTabIndex: tabIndex}); + } + + render() { + const {cssClass} = TabbedTable; + const {children, title} = this.props; + const {selectedTabIndex} = this.state; + + const tabLinks = React.Children.map(children, (tab, i) => { + if (!tab) { + return null; + } + return ( + this._onSelect(e, i)} + key={tab.props.name} + > + {tab.props.name} + + ); + }); + + const selectedTab = children[selectedTabIndex]; + const tableToRender = React.Children.only(selectedTab.props.children); + return ( +
+
+ {title &&

{title}

} + + + {tabLinks} + +
+ {tableToRender} +
+ ); + } +} + +TabbedTable.Tab = Tab; diff --git a/src/TabbedTable/TabbedTable.less b/src/TabbedTable/TabbedTable.less new file mode 100644 index 000000000..8cc895d38 --- /dev/null +++ b/src/TabbedTable/TabbedTable.less @@ -0,0 +1,34 @@ +@import (reference) "~clever-components/dist/less/index"; + +.TabbedTable--TabBar { + .margin--bottom--m; +} + +.TabbedTable--Title { + display: inline-block; + border-right: @size_4xs solid @neutral_gray; + color: @neutral_black; + padding: @size_2xs @size_m; + .margin--right--m; + .text--large; + .text--semi-bold; +} + +.TabbedTable--Tabs { + font-size: @size_s; + color: @neutral_dark_gray; +} + +.TabbedTable--TabName { + .margin--left--s; + color: @neutral_dark_gray; +} + +.TabbedTable--TabName:hover { + cursor: pointer; +} + +.TabbedTable--SelectedTabName { + color: @primary_blue; + .text--semi-bold; +} diff --git a/src/index.js b/src/index.js index 0a52a5262..e6f7d9da5 100644 --- a/src/index.js +++ b/src/index.js @@ -51,3 +51,4 @@ export {Number}; import Tooltip from "./Tooltip"; export {Tooltip}; +export {TabbedTable} from "./TabbedTable/TabbedTable"; diff --git a/src/less/components.less b/src/less/components.less index 2742ca149..bdd7385a6 100644 --- a/src/less/components.less +++ b/src/less/components.less @@ -15,3 +15,4 @@ @import "../Icon/Icon"; @import "../LeftNav/LeftNav"; @import "../AlertBox/AlertBox"; +@import "../TabbedTable/TabbedTable"; diff --git a/test/TabbedTable_test.jsx b/test/TabbedTable_test.jsx new file mode 100644 index 000000000..c73f07b15 --- /dev/null +++ b/test/TabbedTable_test.jsx @@ -0,0 +1,21 @@ +import assert from "assert"; +import React from "react"; +import sinon from "sinon"; +import {shallow} from "enzyme"; +import {TabbedTable} from "../src"; + +describe("TabbedTable", () => { + it("renders (something)", () => { + /* + Write tests here that assert qualities about + TabbedTable's type, classes, properties, + and event handling. + + Refer to enzyme's API and examples for Mocha: + http://airbnb.io/enzyme/ + + Refer to sinon's API for mocking event functions: + http://sinonjs.org/docs/ + */ + }); +});