From 01360a6fa7a627ad2a982e329e60c70280a79e1e Mon Sep 17 00:00:00 2001 From: Vince Picone Date: Tue, 23 Apr 2019 15:51:52 -0500 Subject: [PATCH] feat: Table toolbar v10 (#2247) * chore: update carbon-components for storybook * feat: add initial toolbar updates * fix: default props * test: update snapshots * test: update tests * test: fix tests * test: update snapshots * chore: update peer deps * feat: add new modifiers, update stories, add knobs This commit adds all of the new modifiers and removes the unusued ones. All of the datatable stories have been updated to reflect new markup and to expose knobs to adjust shared modifiers. The dynamic content story was updated to use the new menu system. This also adds support for styles that have not been added yet (row size). * test: update snapshots * test: update snapshots * fix: update proptypes and use cx lib * test: update snapshots * fix: add sortable prop and update snaps * chore: refine story responsibilities This updates the stories so that they only use the feature they are showcasing. This will prevent users from bringing in DataTable features that they don't need. A "kitchen sink" data table might be useful as well. * fix: add a11y updates * test: fix tests * Update src/components/DataTable/TableToolbar.js Co-Authored-By: vpicone * fix: remove tab index Received the following linting error when attempting to define tabindex on the section component: `tabIndex` should only be declared on interactive elements.eslint(jsx-a11y/no-noninteractive-tabindex) * test: update snapshots --- .storybook/config.js | 6 + notes.md | 2 + package.json | 2 +- src/components/DataTable/DataTable-story.js | 117 +- src/components/DataTable/DataTable.js | 36 +- src/components/DataTable/README.md | 4 +- src/components/DataTable/Table.js | 40 +- src/components/DataTable/TableBatchAction.js | 5 +- src/components/DataTable/TableBatchActions.js | 16 +- src/components/DataTable/TableBody.js | 26 +- src/components/DataTable/TableHeader.js | 2 +- src/components/DataTable/TableToolbar.js | 16 +- .../DataTable/TableToolbarAction.js | 86 +- src/components/DataTable/TableToolbarMenu.js | 64 + .../DataTable/TableToolbarSearch.js | 74 +- .../DataTable/__tests__/DataTable-test.js | 125 +- ...ction-test.js => TableToolbarMenu-test.js} | 10 +- .../__snapshots__/DataTable-test.js.snap | 1854 +++++++---------- .../__snapshots__/Table-test.js.snap | 6 +- .../TableBatchAction-test.js.snap | 33 +- .../TableBatchActions-test.js.snap | 64 +- .../__snapshots__/TableBody-test.js.snap | 8 +- .../__snapshots__/TableCell-test.js.snap | 14 +- .../TableExpandHeader-test.js.snap | 6 +- .../__snapshots__/TableExpandRow-test.js.snap | 14 +- .../__snapshots__/TableHead-test.js.snap | 6 +- .../__snapshots__/TableHeader-test.js.snap | 48 +- .../__snapshots__/TableRow-test.js.snap | 14 +- .../__snapshots__/TableSelectAll-test.js.snap | 6 +- .../__snapshots__/TableSelectRow-test.js.snap | 6 +- .../__snapshots__/TableToolbar-test.js.snap | 3 +- .../TableToolbarAction-test.js.snap | 71 - .../TableToolbarMenu-test.js.snap | 172 ++ .../TableToolbarSearch-test.js.snap | 19 +- src/components/DataTable/index.js | 3 + src/components/DataTable/stories/default.js | 73 +- .../DataTable/stories/with-batch-actions.js | 64 +- .../DataTable/stories/with-boolean-column.js | 39 +- .../DataTable/stories/with-dynamic-content.js | 73 +- .../DataTable/stories/with-expansion.js | 7 +- .../stories/with-selection--radio.js | 10 +- .../DataTable/stories/with-selection.js | 6 +- .../DataTable/stories/with-sorting.js | 10 +- .../DataTable/stories/with-toolbar.js | 53 +- src/components/Search/Search-test.js | 6 - src/components/Search/Search.js | 8 - 46 files changed, 1640 insertions(+), 1687 deletions(-) create mode 100644 notes.md create mode 100644 src/components/DataTable/TableToolbarMenu.js rename src/components/DataTable/__tests__/{TableToolbarAction-test.js => TableToolbarMenu-test.js} (75%) delete mode 100644 src/components/DataTable/__tests__/__snapshots__/TableToolbarAction-test.js.snap create mode 100644 src/components/DataTable/__tests__/__snapshots__/TableToolbarMenu-test.js.snap diff --git a/.storybook/config.js b/.storybook/config.js index 10e74d00bd68..8eb5d0aab102 100644 --- a/.storybook/config.js +++ b/.storybook/config.js @@ -2,6 +2,7 @@ import React from 'react'; import { configure, addDecorator } from '@storybook/react'; import { withInfo } from '@storybook/addon-info'; import { withOptions } from '@storybook/addon-options'; +import { configureActions } from '@storybook/addon-actions'; import { initializeRTL } from 'storybook-addon-rtl'; // import { checkA11y } from 'storybook-addon-a11y'; import Container from './Container'; @@ -19,6 +20,11 @@ addDecorator( }) ); +configureActions({ + depth: 100, + limit: 20, +}); + addDecorator(story => ); // addDecorator(checkA11y); diff --git a/notes.md b/notes.md new file mode 100644 index 000000000000..06351fc7df5a --- /dev/null +++ b/notes.md @@ -0,0 +1,2 @@ +Use overflow menu for settings +toolbar actions become overflow menu items diff --git a/package.json b/package.json index a3d4c87dd400..4fe24059f432 100644 --- a/package.json +++ b/package.json @@ -125,7 +125,7 @@ } }, "peerDependencies": { - "carbon-components": "^10.0.0", + "carbon-components": "^10.1.0", "carbon-icons": "^7.0.7", "react": "^16.8.6", "react-dom": "^16.8.6" diff --git a/src/components/DataTable/DataTable-story.js b/src/components/DataTable/DataTable-story.js index 2a868da76c9f..c38dc3daf8e7 100644 --- a/src/components/DataTable/DataTable-story.js +++ b/src/components/DataTable/DataTable-story.js @@ -6,15 +6,19 @@ */ import { storiesOf } from '@storybook/react'; -import { withKnobs, boolean } from '@storybook/addon-knobs'; +import { withKnobs, boolean, select } from '@storybook/addon-knobs'; import { withReadme } from 'storybook-readme'; import readme from './README.md'; const readmeURL = 'https://goo.gl/dq6CEK'; const props = () => ({ - short: boolean('Short variant (short)', false), - shouldShowBorder: boolean('Table Border variant (shouldShowBorder)', true), + useZebraStyles: boolean('Zebra row styles (useZebraStyles)', false), + size: select( + 'Row height (size)', + { compact: 'compact', short: 'short', tall: 'tall', none: null }, + null + ), }); storiesOf('DataTable', module) @@ -39,118 +43,135 @@ storiesOf('DataTable', module) ) .add( 'with toolbar', - withReadme(readme, require('./stories/with-toolbar').default), + withReadme(readme, () => + require('./stories/with-toolbar').default(props()) + ), { info: { text: ` - DataTable with toolbar and filtering. + DataTable with action menu and filtering. - You can find more detailed information surrounding usage of this component - at the following url: ${readmeURL} - `, + You can find more detailed information surrounding usage of this component + at the following url: ${readmeURL} + `, }, } ) .add( 'with sorting', - withReadme(readme, require('./stories/with-sorting').default), + withReadme(readme, () => + require('./stories/with-sorting').default(props()) + ), { info: { text: ` - DataTable with sorting + DataTable with sorting - You can find more detailed information surrounding usage of this component - at the following url: ${readmeURL} - `, + You can find more detailed information surrounding usage of this component + at the following url: ${readmeURL} + `, }, } ) .add( 'with selection', - withReadme(readme, require('./stories/with-selection').default), + withReadme(readme, () => + require('./stories/with-selection').default(props()) + ), { info: { text: ` - DataTable with selection + DataTable with selection - You can find more detailed information surrounding usage of this component - at the following url: ${readmeURL} - `, + You can find more detailed information surrounding usage of this component + at the following url: ${readmeURL} + `, }, } ) + .add( 'with radio button selection', - withReadme(readme, require('./stories/with-selection--radio').default), + withReadme(readme, () => + require('./stories/with-selection--radio').default(props()) + ), { info: { text: ` - DataTable with radio button selection + DataTable with radio button selection - You can find more detailed information surrounding usage of this component - at the following url: ${readmeURL} - `, + You can find more detailed information surrounding usage of this component + at the following url: ${readmeURL} + `, }, } ) .add( 'with expansion', - withReadme(readme, require('./stories/with-expansion').default), + withReadme(readme, () => + require('./stories/with-expansion').default(props()) + ), { info: { text: ` - DataTable with expansion + DataTable with expansion - You can find more detailed information surrounding usage of this component - at the following url: ${readmeURL} - `, + You can find more detailed information surrounding usage of this component + at the following url: ${readmeURL} + `, }, } ) .add( 'with batch actions', - withReadme(readme, require('./stories/with-batch-actions').default), + withReadme(readme, () => + require('./stories/with-batch-actions').default(props()) + ), { info: { text: ` - Uses alongside and - to create the toolbar and placeholder for where the batch action menu will - be displayed. + Uses alongside and + to create the toolbar and placeholder for where the batch action menu will + be displayed. - You can use the \`getBatchActionProps\` prop getter on the - component to have it wire up the ghost menu for you. + You can use the \`getBatchActionProps\` prop getter on the + component to have it wire up the ghost menu for you. - Individual components take in any kind of event handler - prop that you would expect to use, like \`onClick\`. You can use these - alongside the \`selectedRows\` property in your \`render\` prop function - to pass along this info to your batch action handler. + Individual components take in any kind of event handler + prop that you would expect to use, like \`onClick\`. You can use these + alongside the \`selectedRows\` property in your \`render\` prop function + to pass along this info to your batch action handler. - You can find more detailed information surrounding usage of this component - at the following url: ${readmeURL} - `, + You can find more detailed information surrounding usage of this component + at the following url: ${readmeURL} + `, }, } ) .add( 'with dynamic content', - withReadme(readme, require('./stories/with-dynamic-content').default), + withReadme(readme, () => + require('./stories/with-dynamic-content').default(props()) + ), { info: { text: ` - Showcases DataTable behavior when rows are added to the component, - and when cell data changes dynamically. - `, + Showcases DataTable behavior when rows are added to the component, + and when cell data changes dynamically. + `, }, } ) .add( 'with boolean column', - withReadme(readme, require('./stories/with-boolean-column').default), + withReadme(readme, () => + require('./stories/with-boolean-column').default(props()) + ), { info: { text: ` - DataTable with toolbar and filtering with column has boolean value. - `, + DataTable with toolbar and filtering with column has boolean value. + `, }, } ); diff --git a/src/components/DataTable/DataTable.js b/src/components/DataTable/DataTable.js index 6ea8917ac3b1..d1eda0b7f154 100644 --- a/src/components/DataTable/DataTable.js +++ b/src/components/DataTable/DataTable.js @@ -98,16 +98,6 @@ export default class DataTable extends React.Component { */ translateWithId: PropTypes.func, - /** - * Optional boolean to create a short data table. - */ - short: PropTypes.bool, - - /** - * Optional boolean to remove borders from data table. - */ - shouldShowBorder: PropTypes.bool, - /** * Specify whether the control should be a radio button or inline checkbox */ @@ -119,8 +109,6 @@ export default class DataTable extends React.Component { filterRows: defaultFilterRows, locale: 'en', translateWithId, - short: false, - shouldShowBorder: true, }; static translationKeys = Object.values(translationKeys); @@ -163,7 +151,12 @@ export default class DataTable extends React.Component { * @param {Function} config.onClick a custom click handler for the header * @returns {Object} */ - getHeaderProps = ({ header, onClick, isSortable = true, ...rest }) => { + getHeaderProps = ({ + header, + onClick, + isSortable = this.props.isSortable, + ...rest + }) => { const { sortDirection, sortHeaderKey } = this.state; return { ...rest, @@ -287,9 +280,18 @@ export default class DataTable extends React.Component { * Helper utility to get the Table Props. */ getTableProps = () => { - const { short, shouldShowBorder } = this.props; + const { + useZebraStyles, + size, + isSortable, + useStaticWidth, + shouldShowBorder, + } = this.props; return { - short, + useZebraStyles, + size, + isSortable, + useStaticWidth, shouldShowBorder, }; }; @@ -453,7 +455,9 @@ export default class DataTable extends React.Component { * @param {Event} event */ handleOnInputValueChange = event => { - this.setState({ filterInputValue: event.target.value }); + if (event.currentTarget) { + this.setState({ filterInputValue: event.currentTarget.value }); + } }; render() { diff --git a/src/components/DataTable/README.md b/src/components/DataTable/README.md index ad154f5059ef..1c1cbc746a99 100644 --- a/src/components/DataTable/README.md +++ b/src/components/DataTable/README.md @@ -393,9 +393,9 @@ In practice, the combination of these components looks like the following: ( + render={({ rows, headers, getHeaderProps, getRowProps, getTableProps }) => ( - +
{/* add the expand header before all other headers */} diff --git a/src/components/DataTable/Table.js b/src/components/DataTable/Table.js index d357436d911b..97fb1f0745c4 100644 --- a/src/components/DataTable/Table.js +++ b/src/components/DataTable/Table.js @@ -13,18 +13,22 @@ import { settings } from 'carbon-components'; const { prefix } = settings; export const Table = ({ - zebra, className, children, - short, - shouldShowBorder, + useZebraStyles, + size, isSortable, + useStaticWidth, + shouldShowBorder, ...other }) => { const componentClass = cx(`${prefix}--data-table`, className, { - [`${prefix}--data-table--zebra`]: zebra, - [`${prefix}--data-table--short`]: short, + [`${prefix}--data-table--compact`]: size === 'compact', + [`${prefix}--data-table--short`]: size === 'short', + [`${prefix}--data-table--tall`]: size === 'tall', [`${prefix}--data-table--sort`]: isSortable, + [`${prefix}--data-table--zebra`]: useZebraStyles, + [`${prefix}--data-table--static`]: useStaticWidth, [`${prefix}--data-table--no-border`]: !shouldShowBorder, }); return ( @@ -35,36 +39,36 @@ export const Table = ({ }; Table.propTypes = { - /** - * The CSS class names. - */ className: PropTypes.string, /** - * `true` to add zebra striping. + * `true` to add useZebraStyles striping. */ - zebra: PropTypes.bool, + useZebraStyles: PropTypes.bool, /** - * `true` for short data table. + * `normal` Change the row height of table */ - short: PropTypes.bool, + size: PropTypes.oneOf(['compact', 'small', 'normal', 'tall']), /** - * `false` Applies styles for data tables with sorting functionality. + * `false` If true, will use a width of 'auto' instead of 100% */ - isSortable: PropTypes.bool, + useStaticWidth: PropTypes.bool, /** - * `true` for data table without borders. + * `false` If true, will remove the table border */ shouldShowBorder: PropTypes.bool, + + /** + * `false` If true, will apply sorting styles + */ + isSortable: PropTypes.bool, }; Table.defaultProps = { - zebra: true, - short: false, - shouldShowBorder: true, + isSortable: false, }; export default Table; diff --git a/src/components/DataTable/TableBatchAction.js b/src/components/DataTable/TableBatchAction.js index ae36ac8cb299..10ed554001c5 100644 --- a/src/components/DataTable/TableBatchAction.js +++ b/src/components/DataTable/TableBatchAction.js @@ -10,9 +10,7 @@ import React from 'react'; import iconAddSolid from '@carbon/icons-react/lib/add--filled/16'; import Button from '../Button'; -const TableBatchAction = props => ( - +

@@ -53,11 +62,6 @@ const TableBatchActions = ({ : t('carbon.table.batch.item.selected', { totalSelected })}

-
); diff --git a/src/components/DataTable/TableBody.js b/src/components/DataTable/TableBody.js index d4af9c291482..71e0389a8563 100644 --- a/src/components/DataTable/TableBody.js +++ b/src/components/DataTable/TableBody.js @@ -5,11 +5,27 @@ * LICENSE file in the root directory of this source tree. */ -import wrapComponent from '../../tools/wrapComponent'; +import React from 'react'; +import PropTypes from 'prop-types'; -const TableBody = wrapComponent({ - name: 'TableBody', - type: 'tbody', -}); +const TableBody = ({ children, className, ...rest }) => ( +
+ {children} + +); + +TableBody.propTypes = { + className: PropTypes.string, + children: PropTypes.node, + + /** + * `polite` Adjust the notification behavior of screen readers + */ + 'aria-live': PropTypes.oneOf(['polite', 'assertive', 'off']), +}; + +TableBody.defaultProps = { + 'aria-live': 'polite', +}; export default TableBody; diff --git a/src/components/DataTable/TableHeader.js b/src/components/DataTable/TableHeader.js index 65fc5d718b13..7feee188594f 100644 --- a/src/components/DataTable/TableHeader.js +++ b/src/components/DataTable/TableHeader.js @@ -59,7 +59,7 @@ const TableHeader = ({ if (!isSortable) { return ( ); } diff --git a/src/components/DataTable/TableToolbar.js b/src/components/DataTable/TableToolbar.js index e2ef7e183a8a..2c21089187c6 100644 --- a/src/components/DataTable/TableToolbar.js +++ b/src/components/DataTable/TableToolbar.js @@ -4,16 +4,16 @@ * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ - +import React from 'react'; import { settings } from 'carbon-components'; -import wrapComponent from '../../tools/wrapComponent'; const { prefix } = settings; -const TableToolbar = wrapComponent({ - name: 'TableToolbar', - type: 'section', - className: `${prefix}--table-toolbar`, -}); - +const TableToolbar = ({ children }) => ( +
+ {children} +
+); export default TableToolbar; diff --git a/src/components/DataTable/TableToolbarAction.js b/src/components/DataTable/TableToolbarAction.js index 1777a90e97bf..8bd53fa062e9 100644 --- a/src/components/DataTable/TableToolbarAction.js +++ b/src/components/DataTable/TableToolbarAction.js @@ -5,96 +5,18 @@ * LICENSE file in the root directory of this source tree. */ -import cx from 'classnames'; -import warning from 'warning'; import PropTypes from 'prop-types'; import React from 'react'; -import { settings } from 'carbon-components'; -import Icon from '../Icon'; -import isRequiredOneOf from '../../prop-types/isRequiredOneOf'; -import { breakingChangesX } from '../../internal/FeatureFlags'; +import OverflowMenuItem from '../OverflowMenuItem'; -const { prefix } = settings; - -let didWarnAboutDeprecation = false; - -const TableToolbarAction = ({ - className, - renderIcon, - icon, - iconName, - iconDescription, - ...rest -}) => { - if (__DEV__ && breakingChangesX && (icon || iconName)) { - warning( - didWarnAboutDeprecation, - 'The `icon`/`iconName` properties in the `TableToolbarAction` component is being removed in the next release of ' + - '`carbon-components-react`. Please use `renderIcon` instead.' - ); - didWarnAboutDeprecation = true; - } - - const toolbarActionClasses = cx(className, `${prefix}--toolbar-action`); - const tableToolbarActionIcon = (() => { - if (Object(renderIcon) === renderIcon) { - const IconTag = renderIcon; - return ( - - ); - } else if (!breakingChangesX && (icon || iconName)) { - return ( - - ); - } - return null; - })(); - return ( - - ); +const TableToolbarAction = ({ children, ...rest }) => { + return ; }; TableToolbarAction.propTypes = { children: PropTypes.node, className: PropTypes.string, - - ...isRequiredOneOf({ - /** - * Optional prop to allow overriding the toolbar icon rendering. - * Can be a React component class - */ - renderIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - - /** - * Specify the icon for the toolbar action - */ - icon: PropTypes.shape({ - width: PropTypes.string, - height: PropTypes.string, - viewBox: PropTypes.string.isRequired, - svgData: PropTypes.object.isRequired, - }), - - /** - * Specify the name of the icon for the toolbar action - */ - iconName: PropTypes.string, - }), - - /** - * Specify the description of the icon for the toolbar action - */ - iconDescription: PropTypes.string.isRequired, + onClick: PropTypes.func.isRequired, }; export default TableToolbarAction; diff --git a/src/components/DataTable/TableToolbarMenu.js b/src/components/DataTable/TableToolbarMenu.js new file mode 100644 index 000000000000..ec5597d68b25 --- /dev/null +++ b/src/components/DataTable/TableToolbarMenu.js @@ -0,0 +1,64 @@ +/** + * Copyright IBM Corp. 2016, 2018 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import cx from 'classnames'; +import PropTypes from 'prop-types'; +import React from 'react'; +import { settings } from 'carbon-components'; +import OverflowMenu from '../OverflowMenu'; +import Settings16 from '@carbon/icons-react/lib/settings/16'; + +const { prefix } = settings; + +const TableToolbarMenu = ({ + className, + renderIcon, + iconDescription, + children, + ...rest +}) => { + const toolbarActionClasses = cx( + className, + `${prefix}--toolbar-action ${prefix}--overflow-menu` + ); + return ( + + {children} + + ); +}; + +TableToolbarMenu.defaultProps = { + renderIcon: Settings16, + iconDescription: 'Settings', +}; + +TableToolbarMenu.propTypes = { + children: PropTypes.node.isRequired, + + /** + * Provide an optional class name for the toolbar menu + */ + className: PropTypes.string, + + /** + * Optional prop to allow overriding the default menu icon + */ + renderIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + + /** + * The description of the menu icon. + */ + iconDescription: PropTypes.string.isRequired, +}; + +export default TableToolbarMenu; diff --git a/src/components/DataTable/TableToolbarSearch.js b/src/components/DataTable/TableToolbarSearch.js index 4a778e1add3c..9886d7493dac 100644 --- a/src/components/DataTable/TableToolbarSearch.js +++ b/src/components/DataTable/TableToolbarSearch.js @@ -7,7 +7,7 @@ import cx from 'classnames'; import PropTypes from 'prop-types'; -import React from 'react'; +import React, { useRef, useState, useEffect } from 'react'; import { settings } from 'carbon-components'; import Search from '../Search'; import setupGetInstanceId from './tools/instanceId'; @@ -27,25 +27,75 @@ const translateWithId = id => { const TableToolbarSearch = ({ className, searchContainerClass, - onChange, + onChange: onChangeProp, translateWithId: t, placeHolderText, labelText, + expanded: expandedProp, + defaultExpanded, + onExpand, + persistant, id = `data-table-search-${getInstanceId()}`, ...rest }) => { - const searchContainerClasses = cx( - searchContainerClass, - `${prefix}--toolbar-search-container` - ); + const { current: controlled } = useRef(expandedProp !== undefined); + const [expandedState, setExpandedState] = useState(defaultExpanded); + const expanded = controlled ? expandedProp : expandedState; + + const searchRef = useRef(null); + const [value, setValue] = useState(''); + + useEffect(() => { + if (searchRef.current) { + searchRef.current.querySelector('input').focus(); + } + }); + + const searchContainerClasses = cx({ + [searchContainerClass]: searchContainerClass, + [`${prefix}--toolbar-action`]: true, + [`${prefix}--toolbar-search-container-active`]: expanded, + [`${prefix}--toolbar-search-container-expandable`]: !persistant, + [`${prefix}--toolbar-search-container-persistant`]: persistant, + }); + + const searchClasses = cx({ + className, + [`${prefix}--search-maginfier`]: true, + }); + + const handleExpand = (event, value = !expanded) => { + if (!controlled && !persistant) { + setExpandedState(value); + } + if (onExpand) { + onExpand(event, value); + } + }; + + const onChange = e => { + setValue(e.target.value); + if (onChangeProp) { + onChangeProp(e); + } + }; + return ( -
+
handleExpand(event, true)} + onFocus={event => handleExpand(event, true)} + onBlur={event => !value && handleExpand(event, false)} + className={searchContainerClasses}> wrapper.find('TableHeader button').at(index); const getRowAt = (wrapper, index) => wrapper.find('tbody tr').at(index); -const getFilterInput = wrapper => wrapper.find('TableToolbarSearch input'); +const getFilterInput = wrapper => + wrapper.find('TableToolbarSearch Search input'); const getSelectAll = wrapper => wrapper.find('TableSelectAll input[type="checkbox"]'); const getLastCallFor = mocker => @@ -78,53 +77,66 @@ describe('DataTable', () => { }, ], locale: 'en', - render: jest.fn(({ rows, headers, getHeaderProps, onInputChange }) => ( - - - - - - - - - - -
- {children} + {children}
- - - {headers.map(header => ( - - {header.header} - - ))} - - - - {rows.map(row => ( - - {row.cells.map(cell => ( - {cell.value} + render: jest.fn( + ({ + rows, + headers, + getHeaderProps, + onInputChange, + getBatchActionProps, + }) => ( + + + + Ghost + Ghost + Ghost + + + + + + Action 1 + + + Action 2 + + + Action 3 + + + + + +
+ + + {headers.map(header => ( + + {header.header} + ))} - ))} - -
-
- )), + + + {rows.map(row => ( + + {row.cells.map(cell => ( + {cell.value} + ))} + + ))} + + + + ) + ), }; }); @@ -135,9 +147,8 @@ describe('DataTable', () => { describe('sorting', () => { it('should sort a row by a header when a header is clicked', () => { - const wrapper = mount(); + const wrapper = mount(); const header = getHeaderAt(wrapper, 0); - header.simulate('click'); expect(wrapper.state('rowIds')).toEqual(['a', 'b', 'c']); @@ -149,7 +160,7 @@ describe('DataTable', () => { }); it('should re-sort new row props by the current sort state', () => { - const wrapper = mount(); + const wrapper = mount(); const header = getHeaderAt(wrapper, 0); header.simulate('click'); @@ -160,7 +171,8 @@ describe('DataTable', () => { }); it('should reset to ASC ordering when another header is clicked', () => { - const wrapper = mount(); + const wrapper = mount(); + const firstHeader = getHeaderAt(wrapper, 0); const secondHeader = getHeaderAt(wrapper, 1); @@ -183,11 +195,8 @@ describe('DataTable', () => { expect(wrapper.state('rowIds').length).toBe(mockProps.rows.length); - filterInput.simulate('change', { - target: { - value: 'Field 1', - }, - }); + filterInput.getDOMNode().value = 'Field 1'; + filterInput.simulate('change'); expect(mockProps.render).toHaveBeenCalledWith( expect.objectContaining({ diff --git a/src/components/DataTable/__tests__/TableToolbarAction-test.js b/src/components/DataTable/__tests__/TableToolbarMenu-test.js similarity index 75% rename from src/components/DataTable/__tests__/TableToolbarAction-test.js rename to src/components/DataTable/__tests__/TableToolbarMenu-test.js index 2ccb5d907afc..714488afbd71 100644 --- a/src/components/DataTable/__tests__/TableToolbarAction-test.js +++ b/src/components/DataTable/__tests__/TableToolbarMenu-test.js @@ -8,12 +8,12 @@ import React from 'react'; import { mount } from 'enzyme'; import Download16 from '@carbon/icons-react/lib/download/16'; -import { TableToolbarAction } from '../'; +import { TableToolbarMenu } from '..'; -describe('DataTable.TableToolbarAction', () => { +describe('DataTable.TableToolbarMenu', () => { it('should render', () => { const wrapper = mount( - { }); }); -describe('Custom icon in DataTable.TableToolbarAction', () => { +describe('Custom icon in DataTable.TableToolbarMenu', () => { it('should render', () => { const iconAction = mount( - + ); const originalIcon = mount().find('svg'); const icon = iconAction.find('svg'); diff --git a/src/components/DataTable/__tests__/__snapshots__/DataTable-test.js.snap b/src/components/DataTable/__tests__/__snapshots__/DataTable-test.js.snap index 7b761aac6685..f23d1d9a839b 100644 --- a/src/components/DataTable/__tests__/__snapshots__/DataTable-test.js.snap +++ b/src/components/DataTable/__tests__/__snapshots__/DataTable-test.js.snap @@ -55,15 +55,13 @@ exports[`DataTable selection -- radio buttons should not have select-all checkbo title="DataTable with selection" > - +
, }, @@ -91,8 +91,6 @@ exports[`DataTable selection -- radio buttons should not have select-all checkbo } } rows={Array []} - short={false} - shouldShowBorder={true} sortRow={[Function]} translateWithId={[Function]} > @@ -115,12 +113,10 @@ exports[`DataTable selection -- radio buttons should not have select-all checkbo />
@@ -128,7 +124,7 @@ exports[`DataTable selection -- radio buttons should not have select-all checkbo - - + +
- + Field A + - + Field B +
@@ -453,15 +321,13 @@ exports[`DataTable selection -- radio buttons should render 1`] = ` title="DataTable with selection" > - + @@ -580,12 +446,10 @@ exports[`DataTable selection -- radio buttons should render 1`] = ` />
@@ -593,7 +457,7 @@ exports[`DataTable selection -- radio buttons should render 1`] = ` - - + + @@ -1073,9 +809,7 @@ exports[`DataTable selection should have select-all default to un-checked if no title="DataTable with selection" >
- + Field A + - + Field B +
@@ -1089,7 +823,7 @@ exports[`DataTable selection should have select-all default to un-checked if no /> - +
, }, @@ -1117,8 +853,6 @@ exports[`DataTable selection should have select-all default to un-checked if no } } rows={Array []} - short={false} - shouldShowBorder={true} sortRow={[Function]} translateWithId={[Function]} > @@ -1141,12 +875,10 @@ exports[`DataTable selection should have select-all default to un-checked if no />
@@ -1202,7 +934,7 @@ exports[`DataTable selection should have select-all default to un-checked if no - - + +
- + Field A + - + Field B +
@@ -1526,9 +1130,7 @@ exports[`DataTable selection should render 1`] = ` title="DataTable with selection" > @@ -1542,7 +1144,7 @@ exports[`DataTable selection should render 1`] = ` /> - + @@ -1661,12 +1263,10 @@ exports[`DataTable selection should render 1`] = ` />
@@ -1722,7 +1322,7 @@ exports[`DataTable selection should render 1`] = ` - - + + @@ -2236,14 +1708,14 @@ exports[`DataTable should render 1`] = ` title="DataTable with toolbar" > - - - + - + Ghost + + + Ghost + + + Ghost + + + + - + > + + Action 1 + + + Action 2 + + + Action 3 + +
- + Field A + - + Field B +
- + Field 2:A @@ -2428,8 +1960,6 @@ exports[`DataTable should render 1`] = ` }, ] } - short={false} - shouldShowBorder={true} sortRow={[Function]} translateWithId={[Function]} > @@ -2453,256 +1983,508 @@ exports[`DataTable should render 1`] = `
-
- +
- - - - - - - - + + + + + + + + - - - - - - + Cancel + +
-
+ +
+

+ + 0 item selected + +

+
-
+
- - - - - - - + + + + + + +
+ + + + - - +
+ + + + open and close list of options + + + + + +
+ + + +
@@ -2808,7 +2688,7 @@ exports[`DataTable should render 1`] = ` - - + + diff --git a/src/components/DataTable/__tests__/__snapshots__/Table-test.js.snap b/src/components/DataTable/__tests__/__snapshots__/Table-test.js.snap index 2b2c93aec09a..6933584cecb5 100644 --- a/src/components/DataTable/__tests__/__snapshots__/Table-test.js.snap +++ b/src/components/DataTable/__tests__/__snapshots__/Table-test.js.snap @@ -3,12 +3,10 @@ exports[`DataTable.Table should render 1`] = `
- + Field A + - + Field B +
`; diff --git a/src/components/DataTable/__tests__/__snapshots__/TableBatchAction-test.js.snap b/src/components/DataTable/__tests__/__snapshots__/TableBatchAction-test.js.snap index 570941617bb9..4c7da1c0354f 100644 --- a/src/components/DataTable/__tests__/__snapshots__/TableBatchAction-test.js.snap +++ b/src/components/DataTable/__tests__/__snapshots__/TableBatchAction-test.js.snap @@ -4,12 +4,39 @@ exports[`DataTable.TableBatchAction should render 1`] = ` + + +
@@ -21,12 +47,6 @@ exports[`DataTable.TableBatchActions should render 1`] = ` 10 items selected

-
@@ -43,6 +63,32 @@ exports[`DataTable.TableBatchActions should render 2`] = `
+ +
+ + + +
+
@@ -53,12 +99,6 @@ exports[`DataTable.TableBatchActions should render 2`] = ` 10 items selected

-
diff --git a/src/components/DataTable/__tests__/__snapshots__/TableBody-test.js.snap b/src/components/DataTable/__tests__/__snapshots__/TableBody-test.js.snap index 4b7e4953dac3..60a392275c12 100644 --- a/src/components/DataTable/__tests__/__snapshots__/TableBody-test.js.snap +++ b/src/components/DataTable/__tests__/__snapshots__/TableBody-test.js.snap @@ -2,17 +2,17 @@ exports[`DataTable.TableBody should render 1`] = `
diff --git a/src/components/DataTable/__tests__/__snapshots__/TableCell-test.js.snap b/src/components/DataTable/__tests__/__snapshots__/TableCell-test.js.snap index d2c70ee132c9..d85d4fb42d20 100644 --- a/src/components/DataTable/__tests__/__snapshots__/TableCell-test.js.snap +++ b/src/components/DataTable/__tests__/__snapshots__/TableCell-test.js.snap @@ -2,15 +2,17 @@ exports[`DataTable.TableCell should render 1`] = `
- - + +
diff --git a/src/components/DataTable/__tests__/__snapshots__/TableExpandRow-test.js.snap b/src/components/DataTable/__tests__/__snapshots__/TableExpandRow-test.js.snap index 8677a0147fbe..ccfb5c082487 100644 --- a/src/components/DataTable/__tests__/__snapshots__/TableExpandRow-test.js.snap +++ b/src/components/DataTable/__tests__/__snapshots__/TableExpandRow-test.js.snap @@ -2,15 +2,17 @@ exports[`DataTable.TableExpandRow should render 1`] = `
- - + +
@@ -24,7 +22,11 @@ exports[`DataTable.TableHeader should have an active and ascending class if sort @@ -37,12 +39,10 @@ exports[`DataTable.TableHeader should have an active and ascending class if sort exports[`DataTable.TableHeader should have an active class if it is the sort header and the sort state is not NONE 1`] = `
- Header + + Header +
@@ -59,7 +59,11 @@ exports[`DataTable.TableHeader should have an active class if it is the sort hea @@ -72,12 +76,10 @@ exports[`DataTable.TableHeader should have an active class if it is the sort hea exports[`DataTable.TableHeader should render 1`] = `
- Header + + Header +
@@ -94,7 +96,11 @@ exports[`DataTable.TableHeader should render 1`] = ` @@ -107,12 +113,10 @@ exports[`DataTable.TableHeader should render 1`] = ` exports[`DataTable.TableHeader should render 2`] = `
- Header + + Header +
@@ -129,7 +133,11 @@ exports[`DataTable.TableHeader should render 2`] = ` diff --git a/src/components/DataTable/__tests__/__snapshots__/TableRow-test.js.snap b/src/components/DataTable/__tests__/__snapshots__/TableRow-test.js.snap index b92f018192be..8d864b64eaf6 100644 --- a/src/components/DataTable/__tests__/__snapshots__/TableRow-test.js.snap +++ b/src/components/DataTable/__tests__/__snapshots__/TableRow-test.js.snap @@ -2,15 +2,17 @@ exports[`DataTable.TableRow should render 1`] = `
- Header + + Header +
- - + + diff --git a/src/components/DataTable/__tests__/__snapshots__/TableSelectAll-test.js.snap b/src/components/DataTable/__tests__/__snapshots__/TableSelectAll-test.js.snap index 66a523f45428..4af95573f1e8 100644 --- a/src/components/DataTable/__tests__/__snapshots__/TableSelectAll-test.js.snap +++ b/src/components/DataTable/__tests__/__snapshots__/TableSelectAll-test.js.snap @@ -2,12 +2,10 @@ exports[`DataTable.TableSelectAll should render 1`] = `
diff --git a/src/components/DataTable/__tests__/__snapshots__/TableSelectRow-test.js.snap b/src/components/DataTable/__tests__/__snapshots__/TableSelectRow-test.js.snap index 4bf4abf86cf2..fd154a758329 100644 --- a/src/components/DataTable/__tests__/__snapshots__/TableSelectRow-test.js.snap +++ b/src/components/DataTable/__tests__/__snapshots__/TableSelectRow-test.js.snap @@ -2,12 +2,10 @@ exports[`DataTable.TableSelectRow should render 1`] = `
diff --git a/src/components/DataTable/__tests__/__snapshots__/TableToolbar-test.js.snap b/src/components/DataTable/__tests__/__snapshots__/TableToolbar-test.js.snap index 56dbfb6406cd..f50c3f3723b9 100644 --- a/src/components/DataTable/__tests__/__snapshots__/TableToolbar-test.js.snap +++ b/src/components/DataTable/__tests__/__snapshots__/TableToolbar-test.js.snap @@ -5,7 +5,8 @@ exports[`DataTable.TableToolbar should render 1`] = ` className="custom-class" >
`; diff --git a/src/components/DataTable/__tests__/__snapshots__/TableToolbarAction-test.js.snap b/src/components/DataTable/__tests__/__snapshots__/TableToolbarAction-test.js.snap deleted file mode 100644 index aab61b78306e..000000000000 --- a/src/components/DataTable/__tests__/__snapshots__/TableToolbarAction-test.js.snap +++ /dev/null @@ -1,71 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`DataTable.TableToolbarAction should render 1`] = ` - - - -`; diff --git a/src/components/DataTable/__tests__/__snapshots__/TableToolbarMenu-test.js.snap b/src/components/DataTable/__tests__/__snapshots__/TableToolbarMenu-test.js.snap new file mode 100644 index 000000000000..9dfa8e9c192e --- /dev/null +++ b/src/components/DataTable/__tests__/__snapshots__/TableToolbarMenu-test.js.snap @@ -0,0 +1,172 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`DataTable.TableToolbarMenu should render 1`] = ` + + + + +
+ + + + open and close list of options + + + + +
+
+
+
+
+`; diff --git a/src/components/DataTable/__tests__/__snapshots__/TableToolbarSearch-test.js.snap b/src/components/DataTable/__tests__/__snapshots__/TableToolbarSearch-test.js.snap index 7027c12eceaa..cff45019c6e5 100644 --- a/src/components/DataTable/__tests__/__snapshots__/TableToolbarSearch-test.js.snap +++ b/src/components/DataTable/__tests__/__snapshots__/TableToolbarSearch-test.js.snap @@ -5,24 +5,31 @@ exports[`DataTable.TableToolbarSearch should render 1`] = ` className="custom-class" id="custom-id" onChange={[MockFunction]} + persistant={false} translateWithId={[Function]} >
- - -
+ {...props} + render={({ rows, headers, getHeaderProps, getRowProps, getTableProps }) => ( + +
- {headers.map(header => ( {header.header} @@ -96,7 +38,6 @@ export default ({ short, shouldShowBorder }) => ( {rows.map(row => ( - {row.cells.map(cell => ( {cell.value} ))} diff --git a/src/components/DataTable/stories/with-batch-actions.js b/src/components/DataTable/stories/with-batch-actions.js index df7aa4f03d42..b1897fb277e5 100644 --- a/src/components/DataTable/stories/with-batch-actions.js +++ b/src/components/DataTable/stories/with-batch-actions.js @@ -7,9 +7,10 @@ import React from 'react'; import { action } from '@storybook/addon-actions'; -import Download16 from '@carbon/icons-react/lib/download/16'; -import Edit16 from '@carbon/icons-react/lib/edit/16'; -import Settings16 from '@carbon/icons-react/lib/settings/16'; +import Delete from '@carbon/icons-react/lib/delete/16'; +import Save from '@carbon/icons-react/lib/save/16'; +import Download from '@carbon/icons-react/lib/download/16'; + import Button from '../../Button'; import DataTable, { Table, @@ -27,13 +28,16 @@ import DataTable, { TableToolbarAction, TableToolbarContent, TableToolbarSearch, + TableToolbarMenu, } from '../../DataTable'; + import { batchActionClick, initialRows, headers } from './shared'; -export default () => ( +export default props => ( ( getBatchActionProps, onInputChange, selectedRows, + getTableProps, }) => ( - - Ghost + + Delete - - Ghost + + Save - - Ghost + + Download - - - - + + + alert('Alert 1')}> + Action 1 + + alert('Alert 2')}> + Action 2 + + alert('Alert 3')}> + Action 3 + + -
+
diff --git a/src/components/DataTable/stories/with-boolean-column.js b/src/components/DataTable/stories/with-boolean-column.js index 3d8a378ce550..3e5e5aafd5cf 100644 --- a/src/components/DataTable/stories/with-boolean-column.js +++ b/src/components/DataTable/stories/with-boolean-column.js @@ -6,11 +6,6 @@ */ import React from 'react'; -import { action } from '@storybook/addon-actions'; -import Download16 from '@carbon/icons-react/lib/download/16'; -import Edit16 from '@carbon/icons-react/lib/edit/16'; -import Settings16 from '@carbon/icons-react/lib/settings/16'; -import Button from '../../Button'; import Checkbox from '../../Checkbox'; import DataTable, { Table, @@ -20,10 +15,6 @@ import DataTable, { TableHead, TableHeader, TableRow, - TableToolbar, - TableToolbarAction, - TableToolbarContent, - TableToolbarSearch, } from '../../DataTable'; // import { initialRows, headers } from './shared'; @@ -91,36 +82,14 @@ export const headers = [ }, ]; -export default () => ( +export default props => ( ( + {...props} + render={({ rows, headers, getHeaderProps, getRowProps, getTableProps }) => ( - - - - - - - - - -
+
{headers.map(header => ( diff --git a/src/components/DataTable/stories/with-dynamic-content.js b/src/components/DataTable/stories/with-dynamic-content.js index 27c372dc2f28..7cc4fd88d3ad 100644 --- a/src/components/DataTable/stories/with-dynamic-content.js +++ b/src/components/DataTable/stories/with-dynamic-content.js @@ -6,7 +6,10 @@ */ import React from 'react'; -import { action } from '@storybook/addon-actions'; +import Delete from '@carbon/icons-react/lib/delete/16'; +import Save from '@carbon/icons-react/lib/save/16'; +import Download from '@carbon/icons-react/lib/download/16'; + import DataTable, { Table, TableBatchAction, @@ -26,14 +29,11 @@ import DataTable, { TableToolbarAction, TableToolbarContent, TableToolbarSearch, + TableToolbarMenu, } from '../../DataTable'; -import Button from '../../Button'; -import Download16 from '@carbon/icons-react/lib/download/16'; -import Edit16 from '@carbon/icons-react/lib/edit/16'; -import Settings16 from '@carbon/icons-react/lib/settings/16'; import { batchActionClick, initialRows, headers } from './shared'; -export default () => { +export default props => { const insertInRandomPosition = (array, element) => { const index = Math.floor(Math.random() * (array.length + 1)); return [...array.slice(0, index), element, ...array.slice(index)]; @@ -99,6 +99,7 @@ export default () => { { getRowProps, onInputChange, selectedRows, + getTableProps, }) => ( - - + description="Use the toolbar menu to add rows and headers"> - - Ghost + + Delete - - Ghost + + Save - - Ghost + + Download - - - - + + + + Add row + + + Add header + + -
+
@@ -184,6 +182,5 @@ export default () => { ); } } - - return ; + return ; }; diff --git a/src/components/DataTable/stories/with-expansion.js b/src/components/DataTable/stories/with-expansion.js index 4a9e73a9eddf..b806ced16dec 100644 --- a/src/components/DataTable/stories/with-expansion.js +++ b/src/components/DataTable/stories/with-expansion.js @@ -20,13 +20,14 @@ import DataTable, { } from '../../DataTable'; import { initialRows, headers } from './shared'; -export default () => ( +export default props => ( ( + {...props} + render={({ rows, headers, getHeaderProps, getRowProps, getTableProps }) => ( -
+
diff --git a/src/components/DataTable/stories/with-selection--radio.js b/src/components/DataTable/stories/with-selection--radio.js index 8742a70569f8..2a7420994b82 100644 --- a/src/components/DataTable/stories/with-selection--radio.js +++ b/src/components/DataTable/stories/with-selection--radio.js @@ -18,10 +18,11 @@ import DataTable, { } from '..'; import { initialRows, headers } from './shared'; -export default () => ( +export default props => ( ( getHeaderProps, getRowProps, getSelectionProps, + getTableProps, }) => ( - -
+ +
diff --git a/src/components/DataTable/stories/with-selection.js b/src/components/DataTable/stories/with-selection.js index 010ccc99538c..b5f53d678b15 100644 --- a/src/components/DataTable/stories/with-selection.js +++ b/src/components/DataTable/stories/with-selection.js @@ -19,19 +19,21 @@ import DataTable, { } from '../../DataTable'; import { initialRows, headers } from './shared'; -export default () => ( +export default props => ( ( - +
diff --git a/src/components/DataTable/stories/with-sorting.js b/src/components/DataTable/stories/with-sorting.js index 5be31bd8d54a..e696be41f3c8 100644 --- a/src/components/DataTable/stories/with-sorting.js +++ b/src/components/DataTable/stories/with-sorting.js @@ -17,17 +17,19 @@ import DataTable, { } from '../../DataTable'; import { initialRows, headers } from './shared'; -export default () => ( +export default props => ( ( + isSortable={true} + {...props} + render={({ rows, headers, getHeaderProps, getRowProps, getTableProps }) => ( -
+
{headers.map(header => ( - + {header.header} ))} diff --git a/src/components/DataTable/stories/with-toolbar.js b/src/components/DataTable/stories/with-toolbar.js index ff65991ce65f..60f86d316331 100644 --- a/src/components/DataTable/stories/with-toolbar.js +++ b/src/components/DataTable/stories/with-toolbar.js @@ -20,42 +20,43 @@ import DataTable, { TableToolbarAction, TableToolbarContent, TableToolbarSearch, -} from '../../DataTable'; -import Download16 from '@carbon/icons-react/lib/download/16'; -import Edit16 from '@carbon/icons-react/lib/edit/16'; -import Settings16 from '@carbon/icons-react/lib/settings/16'; + TableToolbarMenu, +} from '..'; + import { initialRows, headers } from './shared'; -export default () => ( +export default props => ( ( + {...props} + render={({ + rows, + headers, + getHeaderProps, + getRowProps, + getTableProps, + onInputChange, + }) => ( - - - - - + + + + Action 1 + + + Action 2 + + + Action 3 + + + -
+
{headers.map(header => ( diff --git a/src/components/Search/Search-test.js b/src/components/Search/Search-test.js index 8c3c6a2e3224..d9ba50eda3a5 100644 --- a/src/components/Search/Search-test.js +++ b/src/components/Search/Search-test.js @@ -66,12 +66,6 @@ describe('Search', () => { wrapper.setProps({ placeHolderText: 'Enter text' }); expect(wrapper.find('input').props().placeholder).toEqual('Enter text'); }); - - it('should specify light version as expected', () => { - expect(wrapper.props().light).toEqual(false); - wrapper.setProps({ light: true }); - expect(wrapper.props().light).toEqual(true); - }); }); describe('label', () => { diff --git a/src/components/Search/Search.js b/src/components/Search/Search.js index ea67abd79ca5..def4390074b9 100644 --- a/src/components/Search/Search.js +++ b/src/components/Search/Search.js @@ -55,11 +55,6 @@ export default class Search extends Component { */ closeButtonLabelText: PropTypes.string, - /** - * `true` to use the light version. - */ - light: PropTypes.bool, - /** * Specify the value of the */ @@ -76,7 +71,6 @@ export default class Search extends Component { small: false, placeHolderText: '', onChange: () => {}, - light: false, }; state = { @@ -131,7 +125,6 @@ export default class Search extends Component { labelText, closeButtonLabelText, small, - light, ...other } = this.props; @@ -141,7 +134,6 @@ export default class Search extends Component { [`${prefix}--search`]: true, [`${prefix}--search--${componentsX ? 'xl' : 'lg'}`]: !small, [`${prefix}--search--sm`]: small, - [`${prefix}--search--light`]: light, [className]: className, });