diff --git a/packages/react/src/components/DataTable/DataTable.js b/packages/react/src/components/DataTable/DataTable.js index 5b119aad5aca..532a95eac896 100644 --- a/packages/react/src/components/DataTable/DataTable.js +++ b/packages/react/src/components/DataTable/DataTable.js @@ -233,9 +233,10 @@ export default class DataTable extends React.Component { * * @param {object} config * @param {Function} config.onClick a custom click handler for the expand header + * @param {Function} config.onExpand a custom click handler called when header is expanded * @returns {object} */ - getExpandHeaderProps = ({ onClick, ...rest } = {}) => { + getExpandHeaderProps = ({ onClick, onExpand, ...rest } = {}) => { const { translateWithId: t } = this.props; const { isExpandedAll, rowIds, rowsById } = this.state; const isExpanded = @@ -251,6 +252,7 @@ export default class DataTable extends React.Component { // handler onExpand: composeEventHandlers([ this.handleOnExpandAll, + onExpand, onClick ? this.handleOnExpandHeaderClick(onClick, { isExpanded, diff --git a/packages/react/src/components/DataTable/__tests__/TableExpandHeader-test.js b/packages/react/src/components/DataTable/__tests__/TableExpandHeader-test.js index 065a8ff1f189..52c0681d8a87 100644 --- a/packages/react/src/components/DataTable/__tests__/TableExpandHeader-test.js +++ b/packages/react/src/components/DataTable/__tests__/TableExpandHeader-test.js @@ -5,9 +5,24 @@ * LICENSE file in the root directory of this source tree. */ -import React from 'react'; +import React, { useState, useEffect } from 'react'; import { mount } from 'enzyme'; -import { Table, TableHead, TableRow, TableExpandHeader } from '../'; +import DataTable, { + Table, + TableHead, + TableHeader, + TableRow, + TableExpandHeader, + TableContainer, + TableBody, + TableExpandRow, + TableCell, + TableExpandedRow, +} from '../'; +import { Pagination } from '../../../'; +import { rows, headers } from '../stories/shared'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; describe('DataTable.TableExpandHeader', () => { it('should render', () => { @@ -28,3 +43,180 @@ describe('DataTable.TableExpandHeader', () => { expect(wrapper).toMatchSnapshot(); }); }); + +describe('TableExpandHeader', () => { + it('should call onExpand', () => { + const onExpand = jest.fn(); + render( + + {({ + headers, + getTableProps, + getHeaderProps, + getExpandHeaderProps, + getTableContainerProps, + }) => ( + + + + + + {headers.map((header, i) => ( + + {header.header} + + ))} + + +
+
+ )} +
+ ); + + userEvent.click(screen.getByRole('button')); + + expect(onExpand).toHaveBeenCalled(); + }); + + it('should update toggle button', () => { + const PaginationExample = () => { + const [rows, setRows] = useState([]); + const headers = [ + { + key: 'value', + header: 'Value', + }, + { + key: 'timestamp', + header: 'Submitted At', + }, + ]; + + const allRows = [ + { + id: 'f66f9f0e293e622b046ab4826f99d071a377418fd69bf1685c8d23c371f517cc', + value: 'First', + timestamp: '2022-06-06T12:57:27', + }, + { + id: 'd0d95500fccef68dd1e7cb36f381984d340e9a81657b00e578ef175b195d4983', + value: 'Sewcond', + timestamp: '2022-06-06T12:57:27', + }, + { + id: 'fad0a998e49fb8a9f5681f34f3288bea55559853d971c541607d22fd25773ed8', + value: 'third', + timestamp: '2022-06-06T12:57:27', + }, + { + id: 'c8ad923e8b0ff106d104e95d695f84e695525364c0acdc74786e4c59a457c637', + value: 'Fourth', + timestamp: '2022-06-06T12:57:20', + }, + { + id: '0f7b8a2912a59a737a6e7e1d3c4807d64ad0c8f54d383d9a118851f2c8f98ab6', + value: 'Fifth', + timestamp: '2022-06-06T12:57:21', + }, + { + id: 'fad0a998e49fb8a9f5681f34f3288bea07659834a971c541607d22fd25773ed8', + value: 'Sixth', + timestamp: '2022-06-06T12:57:27', + }, + ]; + + const paginate = ({ page, pageSize }) => { + const start = (page - 1) * pageSize; + const end = page * pageSize; + return allRows.slice(start, end); + }; + + useEffect(() => { + setRows(paginate({ page: 1, pageSize: 2 })); + }, []); // eslint-disable-line react-hooks/exhaustive-deps + + return ( + <> + + {({ + rows, + headers, + getTableProps, + getHeaderProps, + getRowProps, + getExpandHeaderProps, + }) => ( + + + + + {headers.map((header) => ( + + {header.header} + + ))} + + + + {rows.map((row, index) => ( + + + {row.cells.map((cell) => ( + {cell.value} + ))} + + + Some content for {row.id} + + + ))} + +
+ )} +
+ { + setRows(paginate({ page, pageSize })); + }} + page={1} + pageSize={2} + pageSizes={[2]} + size="md" + totalItems={allRows.length} + /> + + ); + }; + + render(); + + userEvent.click(screen.getByLabelText('Expand all rows')); + + expect(screen.getAllByRole('button')[0]).toHaveAttribute( + 'aria-label', + 'Collapse all rows' + ); + + userEvent.click(screen.getByLabelText('Next page')); + expect(screen.getAllByRole('button')[0]).toHaveAttribute( + 'aria-label', + 'Expand all rows' + ); + }); +}); diff --git a/packages/react/src/components/DataTable/state/getDerivedStateFromProps.js b/packages/react/src/components/DataTable/state/getDerivedStateFromProps.js index 3d151daea38d..573e4507d07e 100644 --- a/packages/react/src/components/DataTable/state/getDerivedStateFromProps.js +++ b/packages/react/src/components/DataTable/state/getDerivedStateFromProps.js @@ -47,6 +47,10 @@ const getDerivedStateFromProps = (props, prevState) => { state.rowIds = rowIds; } + state.isExpandedAll = state.rowIds.every((id) => { + return state.rowsById[id].isExpanded === true; + }); + return state; }; diff --git a/packages/react/src/components/DataTable/stories/expansion/DataTable-expansion.stories.js b/packages/react/src/components/DataTable/stories/expansion/DataTable-expansion.stories.js index 850afe6bde80..7c45aeec778e 100644 --- a/packages/react/src/components/DataTable/stories/expansion/DataTable-expansion.stories.js +++ b/packages/react/src/components/DataTable/stories/expansion/DataTable-expansion.stories.js @@ -6,7 +6,7 @@ */ import './DataTable-expansion-story.scss'; -import React from 'react'; +import React, { useState, useEffect } from 'react'; import DataTable, { Table, TableBody, @@ -19,6 +19,7 @@ import DataTable, { TableHeader, TableRow, } from '../..'; +import { Pagination } from '../../../../'; import { rows, headers } from '../shared'; import mdx from '../../DataTable.mdx'; @@ -147,6 +148,119 @@ export const BatchExpansion = () => ( /> ); +// REMOVE BEFORE MERGE +export const TestToggle = () => { + const [rows, setRows] = useState([]); + const headers = [ + { + key: 'value', + header: 'Value', + }, + { + key: 'timestamp', + header: 'Submitted At', + }, + ]; + + const allRows = [ + { + id: 'f66f9f0e293e622b046ab4826f99d071a377418fd69bf1685c8d23c371f517cc', + value: 'First', + timestamp: '2022-06-06T12:57:27', + }, + { + id: 'd0d95500fccef68dd1e7cb36f381984d340e9a81657b00e578ef175b195d4983', + value: 'Sewcond', + timestamp: '2022-06-06T12:57:27', + }, + { + id: 'fad0a998e49fb8a9f5681f34f3288bea55559853d971c541607d22fd25773ed8', + value: 'third', + timestamp: '2022-06-06T12:57:27', + }, + { + id: 'c8ad923e8b0ff106d104e95d695f84e695525364c0acdc74786e4c59a457c637', + value: 'Fourth', + timestamp: '2022-06-06T12:57:20', + }, + { + id: '0f7b8a2912a59a737a6e7e1d3c4807d64ad0c8f54d383d9a118851f2c8f98ab6', + value: 'Fifth', + timestamp: '2022-06-06T12:57:21', + }, + { + id: 'fad0a998e49fb8a9f5681f34f3288bea07659834a971c541607d22fd25773ed8', + value: 'Sixth', + timestamp: '2022-06-06T12:57:27', + }, + ]; + + const paginate = ({ page, pageSize }) => { + const start = (page - 1) * pageSize; + const end = page * pageSize; + return allRows.slice(start, end); + }; + + useEffect(() => { + setRows(paginate({ page: 1, pageSize: 2 })); + }, []); // eslint-disable-line react-hooks/exhaustive-deps + + return ( + <> + + {({ + rows, + headers, + getTableProps, + getHeaderProps, + getRowProps, + getExpandHeaderProps, + }) => ( + + + + + {headers.map((header) => ( + + {header.header} + + ))} + + + + {rows.map((row, index) => ( + + + {row.cells.map((cell) => ( + {cell.value} + ))} + + + Some content for {row.id} + + + ))} + +
+ )} +
+ { + setRows(paginate({ page, pageSize })); + }} + page={1} + pageSize={2} + pageSizes={[2]} + size="md" + totalItems={allRows.length} + /> + + ); +}; + export const Playground = (args) => ( {({