From 8f621583a3d87b49a4d15d9fadcd3ece28fd6426 Mon Sep 17 00:00:00 2001 From: Uyen Doan Date: Thu, 19 Dec 2024 10:24:30 -0600 Subject: [PATCH 01/18] added more examples for table --- apps/website/src/content/docs/table.mdx | 28 +++++++++++-- examples/Table.main.css | 2 +- examples/Table.main.jsx | 45 +-------------------- examples/Table.selectMulti.jsx | 0 examples/Table.selectSingle.jsx | 0 examples/Table.subRows.css | 3 ++ examples/Table.subRows.jsx | 52 +++++++++++++++++++++++++ examples/Table.virtualization.css | 3 ++ examples/Table.virtualization.jsx | 51 ++++++++++++++++++++++++ examples/index.tsx | 10 +++++ 10 files changed, 147 insertions(+), 47 deletions(-) create mode 100644 examples/Table.selectMulti.jsx create mode 100644 examples/Table.selectSingle.jsx create mode 100644 examples/Table.subRows.css create mode 100644 examples/Table.subRows.jsx create mode 100644 examples/Table.virtualization.css create mode 100644 examples/Table.virtualization.jsx diff --git a/apps/website/src/content/docs/table.mdx b/apps/website/src/content/docs/table.mdx index b1d6e02db4d..618f4df3171 100644 --- a/apps/website/src/content/docs/table.mdx +++ b/apps/website/src/content/docs/table.mdx @@ -6,15 +6,37 @@ thumbnail: Table

{frontmatter.description}

- +Tables are an important element in most web-based applications. We’ve presented a set of flexible standards to allow for a variety of table styles. As always, the specifics of how you style your table should be determined by the desired user experience and the goals of the application. + +Bentley makes extensive use of tables and data grids throughout its web applications. Use the following flexible grid format below in most circumstances as it provides functionality “built in” to the design, and because users learning how to consistently sort, filter, and search tables is an important skill to leverage. + +## Usage + +The most basic `Table` can be implemented by passing three props: + +- `data`: an array containing table data displayed on the table. This array must be memoized. +- `columns`: an array containing table column objects. Each column object require to have a `Header`, which will be displayed as a column title, and `id`. +- `emptyTableContent`: a JSX element table content shown when there is no data. -Tables are an important element in most web-based applications. We’ve presented a set of flexible standards to allow for a variety of table styles. As always, the specifics of how you style your table should be determined by the desired user experience and the goals of the application. +**Note**: The `Table` component is built based on `react-table` v7. For more information about `react-table`, see this [doc](https://react-table.tanstack.com/docs/api/overview). -Bentley makes extensive use of tables and data grids throughout its web applications. Use the following flexible grid format below in most circumstances as it provides functionality “built in” to the design, and because users learning how to consistently sort, filter, and search tables is an important skill to leverage. +## Subrows + +Each table row can be expanded t + + + + + +## Expandable content + +## Virtualization + +## Selection ## Props diff --git a/examples/Table.main.css b/examples/Table.main.css index ed47216eb69..c07051439e9 100644 --- a/examples/Table.main.css +++ b/examples/Table.main.css @@ -1,3 +1,3 @@ .demo-container { - min-width: min(100%, 350px); + width: 500px; } diff --git a/examples/Table.main.jsx b/examples/Table.main.jsx index 332e8eee3c3..deb20540c72 100644 --- a/examples/Table.main.jsx +++ b/examples/Table.main.jsx @@ -3,24 +3,14 @@ * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ import * as React from 'react'; -import { Table, DefaultCell } from '@itwin/itwinui-react'; +import { Table } from '@itwin/itwinui-react'; export default () => { const generateItem = React.useCallback((index, parentRow = '', depth = 0) => { const keyValue = parentRow ? `${parentRow}.${index + 1}` : `${index + 1}`; - const rating = Math.round(Math.random() * 5); return { product: `Product ${keyValue}`, price: ((index % 10) + 1) * 15, - quantity: ((index % 10) + 1) * 150, - rating: rating, - status: rating >= 4 ? 'positive' : rating === 3 ? 'warning' : 'negative', - subRows: - depth < 1 - ? Array(Math.round(index % 2)) - .fill(null) - .map((_, index) => generateItem(index, keyValue, depth + 1)) - : [], }; }, []); @@ -38,50 +28,19 @@ export default () => { id: 'product', Header: 'Product', accessor: 'product', - width: '40%', }, { id: 'price', Header: 'Price', accessor: 'price', - Cell: (props) => { - return <>${props.value}; - }, - }, - { - id: 'rating', - Header: 'Rating', - accessor: 'rating', - cellRenderer: (props) => { - return ( - - {props.cellProps.row.original.rating}/5 - - ); - }, }, ], [], ); - const rowProps = React.useCallback((row) => { - return { - status: row.original.status, - }; - }, []); - return (
- +
); }; diff --git a/examples/Table.selectMulti.jsx b/examples/Table.selectMulti.jsx new file mode 100644 index 00000000000..e69de29bb2d diff --git a/examples/Table.selectSingle.jsx b/examples/Table.selectSingle.jsx new file mode 100644 index 00000000000..e69de29bb2d diff --git a/examples/Table.subRows.css b/examples/Table.subRows.css new file mode 100644 index 00000000000..c07051439e9 --- /dev/null +++ b/examples/Table.subRows.css @@ -0,0 +1,3 @@ +.demo-container { + width: 500px; +} diff --git a/examples/Table.subRows.jsx b/examples/Table.subRows.jsx new file mode 100644 index 00000000000..96b9c8ac17a --- /dev/null +++ b/examples/Table.subRows.jsx @@ -0,0 +1,52 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Bentley Systems, Incorporated. All rights reserved. + * See LICENSE.md in the project root for license terms and full copyright notice. + *--------------------------------------------------------------------------------------------*/ +import * as React from 'react'; +import { Table } from '@itwin/itwinui-react'; + +export default () => { + const generateItem = React.useCallback((index, parentRow = '', depth = 0) => { + const keyValue = parentRow ? `${parentRow}.${index + 1}` : `${index + 1}`; + return { + product: `Product ${keyValue}`, + price: ((index % 10) + 1) * 15, + subRows: [ + { + product: `Sub Product ${keyValue}`, + price: (((index % 10) + 1) * 15) / 2, + }, + ], + }; + }, []); + + const data = React.useMemo( + () => + Array(3) + .fill(null) + .map((_, index) => generateItem(index)), + [generateItem], + ); + + const columns = React.useMemo( + () => [ + { + id: 'product', + Header: 'Product', + accessor: 'product', + }, + { + id: 'price', + Header: 'Price', + accessor: 'price', + }, + ], + [], + ); + + return ( +
+
+ + ); +}; diff --git a/examples/Table.virtualization.css b/examples/Table.virtualization.css new file mode 100644 index 00000000000..4c99fcaed47 --- /dev/null +++ b/examples/Table.virtualization.css @@ -0,0 +1,3 @@ +.demo-container { + height: 100%; +} diff --git a/examples/Table.virtualization.jsx b/examples/Table.virtualization.jsx new file mode 100644 index 00000000000..8c1d722a153 --- /dev/null +++ b/examples/Table.virtualization.jsx @@ -0,0 +1,51 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Bentley Systems, Incorporated. All rights reserved. + * See LICENSE.md in the project root for license terms and full copyright notice. + *--------------------------------------------------------------------------------------------*/ +import * as React from 'react'; +import { Table } from '@itwin/itwinui-react'; + +export default () => { + const generateItem = React.useCallback((index, parentRow = '', depth = 0) => { + const keyValue = parentRow ? `${parentRow}.${index + 1}` : `${index + 1}`; + return { + product: `Product ${keyValue}`, + price: ((index % 10) + 1) * 15, + }; + }, []); + + const data = React.useMemo( + () => + Array(1000) + .fill(null) + .map((_, index) => generateItem(index)), + [generateItem], + ); + + const columns = React.useMemo( + () => [ + { + id: 'product', + Header: 'Product', + accessor: 'product', + }, + { + id: 'price', + Header: 'Price', + accessor: 'price', + }, + ], + [], + ); + + return ( +
+
+ + ); +}; diff --git a/examples/index.tsx b/examples/index.tsx index 95031d8b2c6..3c29e78abed 100644 --- a/examples/index.tsx +++ b/examples/index.tsx @@ -1224,6 +1224,16 @@ import { default as TableMainExampleRaw } from './Table.main'; const TableMainExample = withThemeProvider(TableMainExampleRaw); export { TableMainExample }; +import { default as TableSubRowsExampleRaw } from './Table.subRows'; +const TableSubRowsExample = withThemeProvider(TableSubRowsExampleRaw); +export { TableSubRowsExample }; + +import { default as TableVirtualizationExampleRaw } from './Table.virtualization'; +const TableVirtualizationExample = withThemeProvider( + TableVirtualizationExampleRaw, +); +export { TableVirtualizationExample }; + // ---------------------------------------------------------------------------- import { default as TabsMainExampleRaw } from './Tabs.main'; From e5538121439a1e5131cb2b9bd421a4803976ddd4 Mon Sep 17 00:00:00 2001 From: Uyen Doan Date: Thu, 19 Dec 2024 16:04:20 -0600 Subject: [PATCH 02/18] subrows and expandable contents --- apps/website/src/content/docs/table.mdx | 43 +++++++++++++++-- examples/Table.expandableContent.css | 3 ++ examples/Table.expandableContent.jsx | 62 +++++++++++++++++++++++++ examples/Table.virtualization.css | 4 +- examples/index.tsx | 6 +++ 5 files changed, 114 insertions(+), 4 deletions(-) create mode 100644 examples/Table.expandableContent.css create mode 100644 examples/Table.expandableContent.jsx diff --git a/apps/website/src/content/docs/table.mdx b/apps/website/src/content/docs/table.mdx index 618f4df3171..637be57552b 100644 --- a/apps/website/src/content/docs/table.mdx +++ b/apps/website/src/content/docs/table.mdx @@ -24,9 +24,34 @@ The most basic `Table` can be implemented by passing three props: **Note**: The `Table` component is built based on `react-table` v7. For more information about `react-table`, see this [doc](https://react-table.tanstack.com/docs/api/overview). -## Subrows - -Each table row can be expanded t +## Subrow + +The `Table` component supports hierarchical data structures, allowing end users to display subrows, which can be expanded or collapsed. Each data entry in the `data` array should have `subRows` array. + +```jsx +const data = React.useMemo(() => { + return [ + { + name: 'Row 1', + description: 'Description', + subRows: [{ name: 'Subrow 1', description: 'Description 1' }], + }, + { + name: 'Row 2', + description: 'Description', + subRows: [ + { + name: 'Subrow 2', + description: 'Description 2', + subRows: [{ name: 'Subrow 2.1', description: 'Description 2.1' }], + }, + ], + }, + ]; +}, []); +``` + +If subrows has any items, then expander will be shown for that row. This feature is useful for displaying related data in a structured and organized manner. @@ -34,8 +59,20 @@ Each table row can be expanded t ## Expandable content +The `Table` component allows end users to customize their own expandable content within rows by rendering a JSX element using the `subComponent` prop. This feature enables end users to provide additional details or complex data structures in a desired format that can be revealed when a row is expanded. + + + + + +**Note**: As there are features that are designed exclusively for expandable content but not for subrows and vice versa, these two features cannot be passed into the `Table` at the same time. + ## Virtualization + + + + ## Selection ## Props diff --git a/examples/Table.expandableContent.css b/examples/Table.expandableContent.css new file mode 100644 index 00000000000..c07051439e9 --- /dev/null +++ b/examples/Table.expandableContent.css @@ -0,0 +1,3 @@ +.demo-container { + width: 500px; +} diff --git a/examples/Table.expandableContent.jsx b/examples/Table.expandableContent.jsx new file mode 100644 index 00000000000..e7406ca6212 --- /dev/null +++ b/examples/Table.expandableContent.jsx @@ -0,0 +1,62 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Bentley Systems, Incorporated. All rights reserved. + * See LICENSE.md in the project root for license terms and full copyright notice. + *--------------------------------------------------------------------------------------------*/ +import * as React from 'react'; +import { Table, Text } from '@itwin/itwinui-react'; + +export default () => { + const generateItem = React.useCallback((index, parentRow = '', depth = 0) => { + const keyValue = parentRow ? `${parentRow}.${index + 1}` : `${index + 1}`; + return { + product: `Product ${keyValue}`, + price: ((index % 10) + 1) * 15, + }; + }, []); + + const data = React.useMemo( + () => + Array(3) + .fill(null) + .map((_, index) => generateItem(index)), + [generateItem], + ); + + const columns = React.useMemo( + () => [ + { + id: 'product', + Header: 'Product', + accessor: 'product', + }, + { + id: 'price', + Header: 'Price', + accessor: 'price', + }, + ], + [], + ); + + const expandedSubComponent = React.useCallback( + (row) => ( +
+ + {row.original.product}: ${row.original.price} + +
+ ), + [], + ); + + return ( +
+
+ + ); +}; diff --git a/examples/Table.virtualization.css b/examples/Table.virtualization.css index 4c99fcaed47..272e96fa820 100644 --- a/examples/Table.virtualization.css +++ b/examples/Table.virtualization.css @@ -1,3 +1,5 @@ .demo-container { - height: 100%; + height: 300px; + width: 500px; + overflow: auto; } diff --git a/examples/index.tsx b/examples/index.tsx index 3c29e78abed..c2dc6f07416 100644 --- a/examples/index.tsx +++ b/examples/index.tsx @@ -1234,6 +1234,12 @@ const TableVirtualizationExample = withThemeProvider( ); export { TableVirtualizationExample }; +import { default as TableExpandableContentExampleRaw } from './Table.expandableContent'; +const TableExpandableContentExample = withThemeProvider( + TableExpandableContentExampleRaw, +); +export { TableExpandableContentExample }; + // ---------------------------------------------------------------------------- import { default as TabsMainExampleRaw } from './Tabs.main'; From b5702d4a374ad8acf90c86ced0affac3b01dbb57 Mon Sep 17 00:00:00 2001 From: Uyen Doan Date: Thu, 19 Dec 2024 16:42:29 -0600 Subject: [PATCH 03/18] more examples for selection and virtualization --- apps/website/src/content/docs/table.mdx | 8 ++++ examples/Table.selectMulti.css | 3 ++ examples/Table.selectMulti.jsx | 51 ++++++++++++++++++++++++ examples/Table.selectSingle.css | 3 ++ examples/Table.selectSingle.jsx | 52 +++++++++++++++++++++++++ examples/Table.virtualization.css | 1 - examples/Table.virtualization.jsx | 1 + examples/index.tsx | 8 ++++ 8 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 examples/Table.selectMulti.css create mode 100644 examples/Table.selectSingle.css diff --git a/apps/website/src/content/docs/table.mdx b/apps/website/src/content/docs/table.mdx index 637be57552b..fad5e16f7a8 100644 --- a/apps/website/src/content/docs/table.mdx +++ b/apps/website/src/content/docs/table.mdx @@ -69,12 +69,20 @@ The `Table` component allows end users to customize their own expandable content ## Virtualization +For tables with large datasets, the `enableVirtualization` prop can be set to `true` to enhance performance by only rendering the rows that are currently in the viewport. + ## Selection +There are two available selection modes, `"single"` and `"multi"`. + + + + + ## Props diff --git a/examples/Table.selectMulti.css b/examples/Table.selectMulti.css new file mode 100644 index 00000000000..c07051439e9 --- /dev/null +++ b/examples/Table.selectMulti.css @@ -0,0 +1,3 @@ +.demo-container { + width: 500px; +} diff --git a/examples/Table.selectMulti.jsx b/examples/Table.selectMulti.jsx index e69de29bb2d..fa964b1e59e 100644 --- a/examples/Table.selectMulti.jsx +++ b/examples/Table.selectMulti.jsx @@ -0,0 +1,51 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Bentley Systems, Incorporated. All rights reserved. + * See LICENSE.md in the project root for license terms and full copyright notice. + *--------------------------------------------------------------------------------------------*/ +import * as React from 'react'; +import { Table } from '@itwin/itwinui-react'; + +export default () => { + const generateItem = React.useCallback((index, parentRow = '', depth = 0) => { + const keyValue = parentRow ? `${parentRow}.${index + 1}` : `${index + 1}`; + return { + product: `Product ${keyValue}`, + price: ((index % 10) + 1) * 15, + }; + }, []); + + const data = React.useMemo( + () => + Array(3) + .fill(null) + .map((_, index) => generateItem(index)), + [generateItem], + ); + + const columns = React.useMemo( + () => [ + { + id: 'product', + Header: 'Product', + accessor: 'product', + }, + { + id: 'price', + Header: 'Price', + accessor: 'price', + }, + ], + [], + ); + + return ( +
+
+ + ); +}; diff --git a/examples/Table.selectSingle.css b/examples/Table.selectSingle.css new file mode 100644 index 00000000000..c07051439e9 --- /dev/null +++ b/examples/Table.selectSingle.css @@ -0,0 +1,3 @@ +.demo-container { + width: 500px; +} diff --git a/examples/Table.selectSingle.jsx b/examples/Table.selectSingle.jsx index e69de29bb2d..ea9789c8562 100644 --- a/examples/Table.selectSingle.jsx +++ b/examples/Table.selectSingle.jsx @@ -0,0 +1,52 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Bentley Systems, Incorporated. All rights reserved. + * See LICENSE.md in the project root for license terms and full copyright notice. + *--------------------------------------------------------------------------------------------*/ +import * as React from 'react'; +import { Table } from '@itwin/itwinui-react'; + +export default () => { + const generateItem = React.useCallback((index, parentRow = '', depth = 0) => { + const keyValue = parentRow ? `${parentRow}.${index + 1}` : `${index + 1}`; + return { + product: `Product ${keyValue}`, + price: ((index % 10) + 1) * 15, + }; + }, []); + + const data = React.useMemo( + () => + Array(3) + .fill(null) + .map((_, index) => generateItem(index)), + [generateItem], + ); + + const columns = React.useMemo( + () => [ + { + id: 'product', + Header: 'Product', + accessor: 'product', + }, + { + id: 'price', + Header: 'Price', + accessor: 'price', + }, + ], + [], + ); + + return ( +
+
+ + ); +}; diff --git a/examples/Table.virtualization.css b/examples/Table.virtualization.css index 272e96fa820..165c5bd1c35 100644 --- a/examples/Table.virtualization.css +++ b/examples/Table.virtualization.css @@ -1,5 +1,4 @@ .demo-container { - height: 300px; width: 500px; overflow: auto; } diff --git a/examples/Table.virtualization.jsx b/examples/Table.virtualization.jsx index 8c1d722a153..a51c0595b0d 100644 --- a/examples/Table.virtualization.jsx +++ b/examples/Table.virtualization.jsx @@ -44,6 +44,7 @@ export default () => { columns={columns} emptyTableContent='No data.' data={data} + style={{ height: '300px' }} enableVirtualization /> diff --git a/examples/index.tsx b/examples/index.tsx index c2dc6f07416..91f4de0b9cc 100644 --- a/examples/index.tsx +++ b/examples/index.tsx @@ -1240,6 +1240,14 @@ const TableExpandableContentExample = withThemeProvider( ); export { TableExpandableContentExample }; +import { default as TableSelectMultiExampleRaw } from './Table.selectMulti'; +const TableSelectMultiExample = withThemeProvider(TableSelectMultiExampleRaw); +export { TableSelectMultiExample }; + +import { default as TableSelectSingleExampleRaw } from './Table.selectSingle'; +const TableSelectSingleExample = withThemeProvider(TableSelectSingleExampleRaw); +export { TableSelectSingleExample }; + // ---------------------------------------------------------------------------- import { default as TabsMainExampleRaw } from './Tabs.main'; From a275271b3d2582c1fde17ec72fd2f391e567faad Mon Sep 17 00:00:00 2001 From: Uyen Doan Date: Thu, 19 Dec 2024 17:10:05 -0600 Subject: [PATCH 04/18] row selection section --- apps/website/src/content/docs/table.mdx | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/apps/website/src/content/docs/table.mdx b/apps/website/src/content/docs/table.mdx index fad5e16f7a8..8254916f27a 100644 --- a/apps/website/src/content/docs/table.mdx +++ b/apps/website/src/content/docs/table.mdx @@ -69,7 +69,7 @@ The `Table` component allows end users to customize their own expandable content ## Virtualization -For tables with large datasets, the `enableVirtualization` prop can be set to `true` to enhance performance by only rendering the rows that are currently in the viewport. +For tables with large datasets, the `enableVirtualization` prop can be set to `true` to enhance performance by only rendering the rows that are currently in the viewport. More importantly, height on the table is required for virtualization to work. @@ -77,7 +77,25 @@ For tables with large datasets, the `enableVirtualization` prop can be set to `t ## Selection -There are two available selection modes, `"single"` and `"multi"`. +The `Table` component supports row selection, allowing users to select one or more rows for actions by setting the `isSelectable` prop to `true`. + +```jsx {6} +
+``` + +There are two available selection modes: `"single"` and `"multi"` (default). These modes can be specified using the `selectionMode` prop. For single row selection mode, users can select each row by clicking on the desired row. + + + + + +Multi-row selection can be enabled by setting the `selectionMode` prop to `"multi"` or by omitting the `selectionMode` prop altogether. When the `isSelectable` prop is set, the table defaults to multi-selectable. In this mode, a row with checkboxes for toggling selection is added. End users can select or deselect multiple rows by clicking on the row while holding the `Shift` or `Ctrl`/`Command` keys, or by using the checkboxes. From 5a7744ea84eccea1c803e5a645d0612ccc8d9931 Mon Sep 17 00:00:00 2001 From: Uyen Doan Date: Thu, 19 Dec 2024 17:27:00 -0600 Subject: [PATCH 05/18] density --- apps/website/src/content/docs/table.mdx | 8 ++++ examples/Table.density.css | 6 +++ examples/Table.density.jsx | 61 +++++++++++++++++++++++++ examples/index.tsx | 4 ++ 4 files changed, 79 insertions(+) create mode 100644 examples/Table.density.css create mode 100644 examples/Table.density.jsx diff --git a/apps/website/src/content/docs/table.mdx b/apps/website/src/content/docs/table.mdx index 8254916f27a..77982f6d021 100644 --- a/apps/website/src/content/docs/table.mdx +++ b/apps/website/src/content/docs/table.mdx @@ -101,6 +101,14 @@ Multi-row selection can be enabled by setting the `selectionMode` prop to `"mult +## Density + +There are three available density modes which define the height of each row: `"default"`, `"condensed"`, and `"extra-condensed"`. + + + + + ## Props diff --git a/examples/Table.density.css b/examples/Table.density.css new file mode 100644 index 00000000000..eed53a609ad --- /dev/null +++ b/examples/Table.density.css @@ -0,0 +1,6 @@ +.demo-container { + width: 300px; + display: flex; + flex-direction: column; + gap: var(--iui-size-xs); +} diff --git a/examples/Table.density.jsx b/examples/Table.density.jsx new file mode 100644 index 00000000000..a348f239ce4 --- /dev/null +++ b/examples/Table.density.jsx @@ -0,0 +1,61 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Bentley Systems, Incorporated. All rights reserved. + * See LICENSE.md in the project root for license terms and full copyright notice. + *--------------------------------------------------------------------------------------------*/ +import * as React from 'react'; +import { Flex, LabeledSelect, Table } from '@itwin/itwinui-react'; + +export default () => { + const [density, setDensity] = React.useState('default'); + const generateItem = React.useCallback((index, parentRow = '', depth = 0) => { + const keyValue = parentRow ? `${parentRow}.${index + 1}` : `${index + 1}`; + return { + product: `Product ${keyValue}`, + price: ((index % 10) + 1) * 15, + }; + }, []); + + const data = React.useMemo( + () => + Array(3) + .fill(null) + .map((_, index) => generateItem(index)), + [generateItem], + ); + + const columns = React.useMemo( + () => [ + { + id: 'product', + Header: 'Product', + accessor: 'product', + }, + { + id: 'price', + Header: 'Price', + accessor: 'price', + }, + ], + [], + ); + + return ( +
+ setDensity(value)} + /> +
+ + ); +}; diff --git a/examples/index.tsx b/examples/index.tsx index 91f4de0b9cc..7dd2d955ae3 100644 --- a/examples/index.tsx +++ b/examples/index.tsx @@ -1248,6 +1248,10 @@ import { default as TableSelectSingleExampleRaw } from './Table.selectSingle'; const TableSelectSingleExample = withThemeProvider(TableSelectSingleExampleRaw); export { TableSelectSingleExample }; +import { default as TableDensityExampleRaw } from './Table.density'; +const TableDensityExample = withThemeProvider(TableDensityExampleRaw); +export { TableDensityExample }; + // ---------------------------------------------------------------------------- import { default as TabsMainExampleRaw } from './Tabs.main'; From 13932af0183bd384f263342a6d594ab7acd46383 Mon Sep 17 00:00:00 2001 From: Uyen Doan Date: Fri, 20 Dec 2024 14:11:04 -0600 Subject: [PATCH 06/18] pagination --- apps/website/src/content/docs/table.mdx | 59 ++++++++++++++++++++++++- examples/Table.density.css | 2 +- examples/Table.pagination.css | 3 ++ examples/Table.pagination.jsx | 59 +++++++++++++++++++++++++ examples/index.tsx | 4 ++ 5 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 examples/Table.pagination.css create mode 100644 examples/Table.pagination.jsx diff --git a/apps/website/src/content/docs/table.mdx b/apps/website/src/content/docs/table.mdx index 77982f6d021..052084b1e85 100644 --- a/apps/website/src/content/docs/table.mdx +++ b/apps/website/src/content/docs/table.mdx @@ -103,12 +103,69 @@ Multi-row selection can be enabled by setting the `selectionMode` prop to `"mult ## Density -There are three available density modes which define the height of each row: `"default"`, `"condensed"`, and `"extra-condensed"`. +There are three available density options which define the height of each row: `"default"`, `"condensed"`, and `"extra-condensed"`. +## Pagination + +The `Table` component supports pagination, which allows end users to divide large datasets into pages. This feature enhances the user experience by making it easier to navigate, view and manage data in smaller and manageable chunks. + +### Page size + +A memoized variable can be used to hold a list of page size options. + +```jsx +const pageSizeList = React.useMemo(() => [10, 25, 50], []); +``` + +The initial page size can be set using the `pageSize` prop, which defaults to 25. Additionally, the `initialState` prop can be used to specify the initial page size by setting a page size number to its `pageSize` option. + +```jsx {6} +
+``` + +```jsx {6} +
+``` + +### Paginator + +The `paginatorRenderer` can be used to take this page size list and render the corresponding selected rows per page as users change the option. + +```jsx +const paginator = React.useCallback( + (props) => , + [pageSizeList], +); +``` + +This prop is a function that takes `TablePaginatorRendererProps` as an argument and returns pagination component. It is highly recommended that the [`TablePaginator`](#tablepaginator) is returned by this function to handle all state management as it is efficient enough for basic use-cases. + + + + + ## Props +### Table + + +### TablePaginator + + diff --git a/examples/Table.density.css b/examples/Table.density.css index eed53a609ad..b36ac018b73 100644 --- a/examples/Table.density.css +++ b/examples/Table.density.css @@ -1,5 +1,5 @@ .demo-container { - width: 300px; + width: 500px; display: flex; flex-direction: column; gap: var(--iui-size-xs); diff --git a/examples/Table.pagination.css b/examples/Table.pagination.css new file mode 100644 index 00000000000..c07051439e9 --- /dev/null +++ b/examples/Table.pagination.css @@ -0,0 +1,3 @@ +.demo-container { + width: 500px; +} diff --git a/examples/Table.pagination.jsx b/examples/Table.pagination.jsx new file mode 100644 index 00000000000..f2ad3af14a9 --- /dev/null +++ b/examples/Table.pagination.jsx @@ -0,0 +1,59 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Bentley Systems, Incorporated. All rights reserved. + * See LICENSE.md in the project root for license terms and full copyright notice. + *--------------------------------------------------------------------------------------------*/ +import * as React from 'react'; +import { Table, TablePaginator } from '@itwin/itwinui-react'; + +export default () => { + const generateItem = React.useCallback((index, parentRow = '', depth = 0) => { + const keyValue = parentRow ? `${parentRow}.${index + 1}` : `${index + 1}`; + return { + product: `Product ${keyValue}`, + price: ((index % 10) + 1) * 15, + }; + }, []); + + const data = React.useMemo( + () => + Array(100) + .fill(null) + .map((_, index) => generateItem(index)), + [generateItem], + ); + + const columns = React.useMemo( + () => [ + { + id: 'product', + Header: 'Product', + accessor: 'product', + }, + { + id: 'price', + Header: 'Price', + accessor: 'price', + }, + ], + [], + ); + + const pageSizeList = React.useMemo(() => [10, 25, 50], []); + const paginator = React.useCallback( + (props) => , + [pageSizeList], + ); + + return ( +
+
+ + ); +}; diff --git a/examples/index.tsx b/examples/index.tsx index 7dd2d955ae3..56fcfc04280 100644 --- a/examples/index.tsx +++ b/examples/index.tsx @@ -1252,6 +1252,10 @@ import { default as TableDensityExampleRaw } from './Table.density'; const TableDensityExample = withThemeProvider(TableDensityExampleRaw); export { TableDensityExample }; +import { default as TablePaginationExampleRaw } from './Table.pagination'; +const TablePaginationExample = withThemeProvider(TablePaginationExampleRaw); +export { TablePaginationExample }; + // ---------------------------------------------------------------------------- import { default as TabsMainExampleRaw } from './Tabs.main'; From 35cc5e365a661b5e2d35e7c22b558b07d1f2979b Mon Sep 17 00:00:00 2001 From: Uyen Doan Date: Mon, 23 Dec 2024 11:24:32 -0600 Subject: [PATCH 07/18] mdx structure --- apps/website/src/content/docs/table.mdx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/apps/website/src/content/docs/table.mdx b/apps/website/src/content/docs/table.mdx index 052084b1e85..1a653895b63 100644 --- a/apps/website/src/content/docs/table.mdx +++ b/apps/website/src/content/docs/table.mdx @@ -24,7 +24,7 @@ The most basic `Table` can be implemented by passing three props: **Note**: The `Table` component is built based on `react-table` v7. For more information about `react-table`, see this [doc](https://react-table.tanstack.com/docs/api/overview). -## Subrow +### Subrow The `Table` component supports hierarchical data structures, allowing end users to display subrows, which can be expanded or collapsed. Each data entry in the `data` array should have `subRows` array. @@ -57,7 +57,7 @@ If subrows has any items, then expander will be shown for that row. This feature -## Expandable content +### Expandable content The `Table` component allows end users to customize their own expandable content within rows by rendering a JSX element using the `subComponent` prop. This feature enables end users to provide additional details or complex data structures in a desired format that can be revealed when a row is expanded. @@ -67,7 +67,7 @@ The `Table` component allows end users to customize their own expandable content **Note**: As there are features that are designed exclusively for expandable content but not for subrows and vice versa, these two features cannot be passed into the `Table` at the same time. -## Virtualization +### Virtualization For tables with large datasets, the `enableVirtualization` prop can be set to `true` to enhance performance by only rendering the rows that are currently in the viewport. More importantly, height on the table is required for virtualization to work. @@ -75,7 +75,7 @@ For tables with large datasets, the `enableVirtualization` prop can be set to `t -## Selection +### Selection The `Table` component supports row selection, allowing users to select one or more rows for actions by setting the `isSelectable` prop to `true`. @@ -101,7 +101,7 @@ Multi-row selection can be enabled by setting the `selectionMode` prop to `"mult -## Density +### Density There are three available density options which define the height of each row: `"default"`, `"condensed"`, and `"extra-condensed"`. @@ -109,11 +109,11 @@ There are three available density options which define the height of each row: ` -## Pagination +### Pagination The `Table` component supports pagination, which allows end users to divide large datasets into pages. This feature enhances the user experience by making it easier to navigate, view and manage data in smaller and manageable chunks. -### Page size +#### Page size A memoized variable can be used to hold a list of page size options. @@ -143,7 +143,7 @@ The initial page size can be set using the `pageSize` prop, which defaults to 25 /> ``` -### Paginator +#### Paginator The `paginatorRenderer` can be used to take this page size list and render the corresponding selected rows per page as users change the option. @@ -160,6 +160,8 @@ This prop is a function that takes `TablePaginatorRendererProps` as an argument +### Editing + ## Props ### Table From 59e906a9e1434918ae393e2709860e55c410735b Mon Sep 17 00:00:00 2001 From: Uyen Doan Date: Wed, 8 Jan 2025 14:53:31 -0600 Subject: [PATCH 08/18] added column manager examples --- apps/website/src/content/docs/table.mdx | 41 ++++++++++-- examples/Table.columnManager.css | 3 + examples/Table.columnManager.jsx | 86 +++++++++++++++++++++++++ examples/index.tsx | 6 ++ 4 files changed, 131 insertions(+), 5 deletions(-) create mode 100644 examples/Table.columnManager.css create mode 100644 examples/Table.columnManager.jsx diff --git a/apps/website/src/content/docs/table.mdx b/apps/website/src/content/docs/table.mdx index 1a653895b63..399f4a2ccc0 100644 --- a/apps/website/src/content/docs/table.mdx +++ b/apps/website/src/content/docs/table.mdx @@ -81,7 +81,7 @@ The `Table` component supports row selection, allowing users to select one or mo ```jsx {6}
``` @@ -160,7 +160,38 @@ This prop is a function that takes `TablePaginatorRendererProps` as an argument -### Editing +### Column manager + +The `ActionColumn` component allows you to perform actions on column items by adding the column manager to the Table header. It is recommended to place this column at the end of the column object array with its `columnManager` option set to `"true"`. The column manager includes a popover that contains information about each column, enabling you to decide which columns should be visible. + +```jsx {4} +const columns = React.useMemo( + () => [ + /* … */ + ActionColumn({ columnManager: true }), + ], + [], +); +``` + +Additionally, you can override the `Cell` prop of the `ActionColumn` to include a row action menu at the end of each table row. This menu enhances the user experience by providing convenient access to row-specific actions, such as editing or deleting entries. + + + + + +As a side note, the `initialState` prop allows you to initially hide specific columns in the column manager popover when the table is rendered by setting its `hiddenColumns` property to an array of the columns you want to hide. + +```jsx {7} +
+``` ## Props diff --git a/examples/Table.columnManager.css b/examples/Table.columnManager.css new file mode 100644 index 00000000000..c07051439e9 --- /dev/null +++ b/examples/Table.columnManager.css @@ -0,0 +1,3 @@ +.demo-container { + width: 500px; +} diff --git a/examples/Table.columnManager.jsx b/examples/Table.columnManager.jsx new file mode 100644 index 00000000000..9a8c543d278 --- /dev/null +++ b/examples/Table.columnManager.jsx @@ -0,0 +1,86 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Bentley Systems, Incorporated. All rights reserved. + * See LICENSE.md in the project root for license terms and full copyright notice. + *--------------------------------------------------------------------------------------------*/ +import * as React from 'react'; +import { + ActionColumn, + DropdownMenu, + MenuItem, + IconButton, + Table, +} from '@itwin/itwinui-react'; +import { SvgMore } from '@itwin/itwinui-icons-react'; + +export default () => { + const generateItem = React.useCallback((index, parentRow = '', depth = 0) => { + const keyValue = parentRow ? `${parentRow}.${index + 1}` : `${index + 1}`; + return { + product: `Product ${keyValue}`, + price: ((index % 10) + 1) * 15, + }; + }, []); + + const menuItems = React.useCallback((close) => { + return [ + close()}> + Edit + , + close()}> + Delete + , + ]; + }, []); + + const data = React.useMemo( + () => + Array(3) + .fill(null) + .map((_, index) => generateItem(index)), + [generateItem], + ); + + const columns = React.useMemo( + () => [ + { + id: 'product', + Header: 'Product', + accessor: 'product', + }, + { + id: 'price', + Header: 'Price', + accessor: 'price', + }, + { + ...ActionColumn({ columnManager: true }), + Cell: () => ( + e.stopPropagation()} + > + e.stopPropagation()} + > + + + + ), + sticky: 'right', + }, + ], + [], + ); + + return ( +
+
+ + ); +}; diff --git a/examples/index.tsx b/examples/index.tsx index a9b28e35738..7e1c0d2b3b9 100644 --- a/examples/index.tsx +++ b/examples/index.tsx @@ -1266,6 +1266,12 @@ import { default as TablePaginationExampleRaw } from './Table.pagination'; const TablePaginationExample = withThemeProvider(TablePaginationExampleRaw); export { TablePaginationExample }; +import { default as TableColumnManagerExampleRaw } from './Table.columnManager'; +const TableColumnManagerExample = withThemeProvider( + TableColumnManagerExampleRaw, +); +export { TableColumnManagerExample }; + // ---------------------------------------------------------------------------- import { default as TabsMainExampleRaw } from './Tabs.main'; From 752d960755df18c896a0abd3dfd8e9800290355d Mon Sep 17 00:00:00 2001 From: Uyen Doan Date: Wed, 8 Jan 2025 15:02:09 -0600 Subject: [PATCH 09/18] wording selection --- apps/website/src/content/docs/table.mdx | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/website/src/content/docs/table.mdx b/apps/website/src/content/docs/table.mdx index 399f4a2ccc0..560778ae695 100644 --- a/apps/website/src/content/docs/table.mdx +++ b/apps/website/src/content/docs/table.mdx @@ -89,18 +89,35 @@ The `Table` component supports row selection, allowing users to select one or mo /> ``` +#### Single-row selection + There are two available selection modes: `"single"` and `"multi"` (default). These modes can be specified using the `selectionMode` prop. For single row selection mode, users can select each row by clicking on the desired row. -Multi-row selection can be enabled by setting the `selectionMode` prop to `"multi"` or by omitting the `selectionMode` prop altogether. When the `isSelectable` prop is set, the table defaults to multi-selectable. In this mode, a row with checkboxes for toggling selection is added. End users can select or deselect multiple rows by clicking on the row while holding the `Shift` or `Ctrl`/`Command` keys, or by using the checkboxes. +#### Multiple-row selection + +Multiple-row selection can be enabled by setting the `selectionMode` prop to `"multi"` or by omitting the `selectionMode` prop altogether. When the `isSelectable` prop is set, the table defaults to multi-selectable. In this mode, a row with checkboxes for toggling selection is added. End users can select or deselect multiple rows by clicking on the row while holding the `Shift` or `Ctrl`/`Command` keys, or by using the checkboxes. +The `initialState` prop is useful when you want specific rows to be selected by default. This prop accepts an array of row IDs, ensuring that these rows are rendered with the appropriate selection styling. + +```jsx {7} +
+``` + ### Density There are three available density options which define the height of each row: `"default"`, `"condensed"`, and `"extra-condensed"`. From 0129dac9750b051bfff7e8611a9289b1591817f4 Mon Sep 17 00:00:00 2001 From: Uyen Doan Date: Wed, 8 Jan 2025 16:01:51 -0600 Subject: [PATCH 10/18] added editing example --- apps/website/src/content/docs/table.mdx | 10 ++++ examples/Table.editing.css | 3 ++ examples/Table.editing.jsx | 62 +++++++++++++++++++++++++ examples/index.tsx | 4 ++ 4 files changed, 79 insertions(+) create mode 100644 examples/Table.editing.css create mode 100644 examples/Table.editing.jsx diff --git a/apps/website/src/content/docs/table.mdx b/apps/website/src/content/docs/table.mdx index 560778ae695..ee7eaf902e3 100644 --- a/apps/website/src/content/docs/table.mdx +++ b/apps/website/src/content/docs/table.mdx @@ -210,6 +210,16 @@ As a side note, the `initialState` prop allows you to initially hide specific co /> ``` +### Editing + + + + + +### Filtering + +### Sorting + ## Props ### Table diff --git a/examples/Table.editing.css b/examples/Table.editing.css new file mode 100644 index 00000000000..c07051439e9 --- /dev/null +++ b/examples/Table.editing.css @@ -0,0 +1,3 @@ +.demo-container { + width: 500px; +} diff --git a/examples/Table.editing.jsx b/examples/Table.editing.jsx new file mode 100644 index 00000000000..d908d09dfbc --- /dev/null +++ b/examples/Table.editing.jsx @@ -0,0 +1,62 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Bentley Systems, Incorporated. All rights reserved. + * See LICENSE.md in the project root for license terms and full copyright notice. + *--------------------------------------------------------------------------------------------*/ +import * as React from 'react'; +import { EditableCell, DefaultCell, Table } from '@itwin/itwinui-react'; + +export default () => { + const [data, setData] = React.useState([ + { name: 'Name1', description: 'Description1' }, + { name: 'Name2', description: 'Description2' }, + { name: 'Name3', description: 'Fetching...' }, + ]); + + const onCellEdit = React.useCallback((columnId, value, rowData) => { + setData((oldData) => { + const newData = [...oldData]; + const index = oldData.indexOf(rowData); + const newObject = { ...newData[index] }; + newObject[columnId] = value; + newData[index] = newObject; + return newData; + }); + }, []); + + const cellRenderer = React.useCallback( + (props) => ( + <> + {props.cellProps.value !== 'Fetching...' ? ( + + ) : ( + + )} + + ), + [onCellEdit], + ); + + const columns = React.useMemo( + () => [ + { + id: 'product', + Header: 'Product', + cellRenderer, + accessor: 'product', + }, + { + id: 'price', + Header: 'Price', + cellRenderer, + accessor: 'price', + }, + ], + [cellRenderer], + ); + + return ( +
+
+ + ); +}; diff --git a/examples/index.tsx b/examples/index.tsx index 7e1c0d2b3b9..4fb60d7e571 100644 --- a/examples/index.tsx +++ b/examples/index.tsx @@ -1272,6 +1272,10 @@ const TableColumnManagerExample = withThemeProvider( ); export { TableColumnManagerExample }; +import { default as TableEditingExampleRaw } from './Table.editing'; +const TableEditingExample = withThemeProvider(TableEditingExampleRaw); +export { TableEditingExample }; + // ---------------------------------------------------------------------------- import { default as TabsMainExampleRaw } from './Tabs.main'; From 4c25609f645c9b271b12dafaefc2b276862c94d7 Mon Sep 17 00:00:00 2001 From: Uyen Doan Date: Fri, 10 Jan 2025 14:49:12 -0600 Subject: [PATCH 11/18] wip --- examples/Table.editing.jsx | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/examples/Table.editing.jsx b/examples/Table.editing.jsx index d908d09dfbc..217c0d325e7 100644 --- a/examples/Table.editing.jsx +++ b/examples/Table.editing.jsx @@ -7,9 +7,9 @@ import { EditableCell, DefaultCell, Table } from '@itwin/itwinui-react'; export default () => { const [data, setData] = React.useState([ - { name: 'Name1', description: 'Description1' }, - { name: 'Name2', description: 'Description2' }, - { name: 'Name3', description: 'Fetching...' }, + { product: 'Product 1', price: '$15' }, + { product: 'Product 2', price: '$30' }, + { product: 'Product 3', price: 'Fetching...' }, ]); const onCellEdit = React.useCallback((columnId, value, rowData) => { @@ -41,22 +41,25 @@ export default () => { { id: 'product', Header: 'Product', - cellRenderer, accessor: 'product', + cellRenderer, }, { id: 'price', Header: 'Price', - cellRenderer, accessor: 'price', + cellRenderer, }, ], [cellRenderer], ); return ( -
-
- +
); }; From 965f5e43ba0f496ebb889f7bea01ad6a9424dc4f Mon Sep 17 00:00:00 2001 From: Uyen Doan Date: Fri, 10 Jan 2025 14:49:27 -0600 Subject: [PATCH 12/18] wip --- apps/website/src/content/docs/table.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/website/src/content/docs/table.mdx b/apps/website/src/content/docs/table.mdx index ee7eaf902e3..9850e46e987 100644 --- a/apps/website/src/content/docs/table.mdx +++ b/apps/website/src/content/docs/table.mdx @@ -212,6 +212,8 @@ As a side note, the `initialState` prop allows you to initially hide specific co ### Editing +To enable editing for each Table cell + From a9121e77e7d2c5f7e7f338052190cf97733288de Mon Sep 17 00:00:00 2001 From: Uyen Doan Date: Mon, 13 Jan 2025 15:38:34 -0600 Subject: [PATCH 13/18] added sorting and editing examples --- apps/website/src/content/docs/table.mdx | 56 +++++++++++++++++++++++-- examples/Table.columnManager.jsx | 7 +--- examples/Table.filtering.css | 0 examples/Table.filtering.jsx | 0 examples/Table.sorting.css | 3 ++ examples/Table.sorting.jsx | 41 ++++++++++++++++++ examples/index.tsx | 4 ++ 7 files changed, 102 insertions(+), 9 deletions(-) create mode 100644 examples/Table.filtering.css create mode 100644 examples/Table.filtering.jsx create mode 100644 examples/Table.sorting.css create mode 100644 examples/Table.sorting.jsx diff --git a/apps/website/src/content/docs/table.mdx b/apps/website/src/content/docs/table.mdx index 9850e46e987..5366fcac3fd 100644 --- a/apps/website/src/content/docs/table.mdx +++ b/apps/website/src/content/docs/table.mdx @@ -212,16 +212,66 @@ As a side note, the `initialState` prop allows you to initially hide specific co ### Editing -To enable editing for each Table cell +To enable editing for each `Table` cell, the `EditableCell` component should be passed into `cellRenderer` of the column object. + +```jsx {7} +const columns = React.useMemo( + () => [ + ..., + { + Header: 'Name', + accessor: 'name', + cellRenderer: (props) => , + }, + ], + [], +); +``` + +This component takes the callback function `onCellEdit` which is used to handle cell edit events and update the table data accordingly. + +```jsx +const onCellEdit = React.useCallback( + (columnId: string, value: string, rowData: T) => { + setData((oldData) => { + const newData = [...oldData]; + const index = oldData.indexOf(rowData); + const newObject = { ...newData[index] }; + newObject[columnId] = value; + newData[index] = newObject; + return newData; + }); +},[]); +``` -### Filtering - ### Sorting +To enable sorting in the `Table`, set the `isSortable` prop to `true`. This will allow the columns to display an arrow when hovered, indicating whether the column is sorted in ascending or descending order. + + + + + +By default, columns are sorted in ascending order first when the arrow is clicked. To prioritize descending sorting instead, set the `sortDescFirst` property to `true` in the column object. + +```jsx {7} +const columns = React.useMemo( + () => [ + ..., + { + Header: 'Name', + accessor: 'name', + sortDescFirst: true, + }, + ], + [], +); +``` + ## Props ### Table diff --git a/examples/Table.columnManager.jsx b/examples/Table.columnManager.jsx index 9a8c543d278..d3729c93215 100644 --- a/examples/Table.columnManager.jsx +++ b/examples/Table.columnManager.jsx @@ -75,12 +75,7 @@ export default () => { return (
-
+
); }; diff --git a/examples/Table.filtering.css b/examples/Table.filtering.css new file mode 100644 index 00000000000..e69de29bb2d diff --git a/examples/Table.filtering.jsx b/examples/Table.filtering.jsx new file mode 100644 index 00000000000..e69de29bb2d diff --git a/examples/Table.sorting.css b/examples/Table.sorting.css new file mode 100644 index 00000000000..c07051439e9 --- /dev/null +++ b/examples/Table.sorting.css @@ -0,0 +1,3 @@ +.demo-container { + width: 500px; +} diff --git a/examples/Table.sorting.jsx b/examples/Table.sorting.jsx new file mode 100644 index 00000000000..5bdfc99a7b4 --- /dev/null +++ b/examples/Table.sorting.jsx @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Bentley Systems, Incorporated. All rights reserved. + * See LICENSE.md in the project root for license terms and full copyright notice. + *--------------------------------------------------------------------------------------------*/ +import * as React from 'react'; +import { Table } from '@itwin/itwinui-react'; + +export default () => { + const data = [ + { product: 'Product 1', price: '$15' }, + { product: 'Product 2', price: '$45' }, + { product: 'Product 3', price: '$30' }, + ]; + + const columns = React.useMemo( + () => [ + { + id: 'product', + Header: 'Product', + accessor: 'product', + }, + { + id: 'price', + Header: 'Price', + accessor: 'price', + }, + ], + [], + ); + + return ( +
+
+ + ); +}; diff --git a/examples/index.tsx b/examples/index.tsx index 4fb60d7e571..8b9d90affca 100644 --- a/examples/index.tsx +++ b/examples/index.tsx @@ -1276,6 +1276,10 @@ import { default as TableEditingExampleRaw } from './Table.editing'; const TableEditingExample = withThemeProvider(TableEditingExampleRaw); export { TableEditingExample }; +import { default as TableSortingExampleRaw } from './Table.sorting'; +const TableSortingExample = withThemeProvider(TableSortingExampleRaw); +export { TableSortingExample }; + // ---------------------------------------------------------------------------- import { default as TabsMainExampleRaw } from './Tabs.main'; From 9131a2f7576923ac178513af2ac7292b4ab36c6b Mon Sep 17 00:00:00 2001 From: Uyen Doan Date: Thu, 23 Jan 2025 10:09:36 -0600 Subject: [PATCH 14/18] added docs about default and global filtering --- apps/website/src/content/docs/table.mdx | 64 +++++++++++++++++++++-- examples/Table.columnManager.jsx | 2 +- examples/Table.density.jsx | 2 +- examples/Table.expandableContent.jsx | 2 +- examples/Table.filtering.css | 3 ++ examples/Table.filtering.jsx | 60 +++++++++++++++++++++ examples/Table.globalFiltering.css | 3 ++ examples/Table.globalFiltering.jsx | 69 +++++++++++++++++++++++++ examples/Table.main.jsx | 2 +- examples/Table.pagination.jsx | 2 +- examples/Table.selectMulti.jsx | 2 +- examples/Table.selectSingle.jsx | 2 +- examples/Table.sorting.jsx | 20 +++++-- examples/Table.subRows.jsx | 2 +- examples/Table.virtualization.jsx | 2 +- examples/index.tsx | 10 ++++ 16 files changed, 229 insertions(+), 18 deletions(-) create mode 100644 examples/Table.globalFiltering.css create mode 100644 examples/Table.globalFiltering.jsx diff --git a/apps/website/src/content/docs/table.mdx b/apps/website/src/content/docs/table.mdx index 5366fcac3fd..2a452c9a8d7 100644 --- a/apps/website/src/content/docs/table.mdx +++ b/apps/website/src/content/docs/table.mdx @@ -217,7 +217,7 @@ To enable editing for each `Table` cell, the `EditableCell` component should be ```jsx {7} const columns = React.useMemo( () => [ - ..., + /* … */ { Header: 'Name', accessor: 'name', @@ -250,18 +250,18 @@ const onCellEdit = React.useCallback( ### Sorting -To enable sorting in the `Table`, set the `isSortable` prop to `true`. This will allow the columns to display an arrow when hovered, indicating whether the column is sorted in ascending or descending order. +To enable sorting in the `Table`, the `isSortable` prop can be set to `true`. This will allow the columns to display an arrow when hovered, indicating whether the column is sorted in ascending or descending order. -By default, columns are sorted in ascending order first when the arrow is clicked. To prioritize descending sorting instead, set the `sortDescFirst` property to `true` in the column object. +By default, columns are sorted in ascending order first when the arrow is clicked. To prioritize descending sorting instead, you can set the `sortDescFirst` property to `true` in the column object. ```jsx {7} const columns = React.useMemo( () => [ - ..., + /* … */ { Header: 'Name', accessor: 'name', @@ -272,6 +272,62 @@ const columns = React.useMemo( ); ``` +If there is any column that does not allow sorting, the `disableSortBy` prop needs to be set to `true` in the column object. + +```jsx {7} +const columns = React.useMemo( + () => [ + /* … */ + { + Header: 'Name', + accessor: 'name', + disableSortBy: true, + }, + ], + [], +); +``` + +#### Manual sorting + +The `manualSortBy` prop is useful when sorting needs to be handled manually by the developer rather than automatically by the table library. This is particularly useful when you are fetching data from a server or need custom sorting logic. + +```jsx {6} +
+``` + +The `manualSortBy` prop must be used in conjunction with the `onSort` callback, allowing end users to implement custom sorting logic programmatically. This function must be memoized. + +### Filtering + +For basic filtering in the `Table`, you can pass the `Filter` prop to the column object. The `Filter` prop accepts a JSX element to display a filter component, which can be customized or use iTwinUI's pre-built `tableFilter` components. This `tableFilter` object provides three filter components: + +- `TextFilter`: a basic string filter with a single input field. +- `NumberRangeFilter`: a number range filter. It only works with `number` type object properties. If the data is required to be different type e.g. `string`, you can use `accessor` property in column description: `accessor: (rowData) => Number(rowData.numberProp)`. +- `DateRangeFilter`: a date range filter. By default it handles user input in `en-us` date format. If there are other specific formats that need to be displayed, date range options `formatDate`, `parseInput` and `placeholder` can passed into the filter component. + + + + + +#### Global filtering + +In addition to filtering data in individual columns, global filtering can be useful for searching through the entire table. The `globalFilterValue` prop can be used to set a default filter value when the table is rendered or to update the table based on a state filter variable. + + + + + +**Note**: The `autoResetGlobalFilter` prop can be used to reset the table filter whenever a change is detected in the filter value. + +#### Custom filtering + ## Props ### Table diff --git a/examples/Table.columnManager.jsx b/examples/Table.columnManager.jsx index d3729c93215..22a0a74a9f8 100644 --- a/examples/Table.columnManager.jsx +++ b/examples/Table.columnManager.jsx @@ -13,7 +13,7 @@ import { import { SvgMore } from '@itwin/itwinui-icons-react'; export default () => { - const generateItem = React.useCallback((index, parentRow = '', depth = 0) => { + const generateItem = React.useCallback((index, parentRow = '') => { const keyValue = parentRow ? `${parentRow}.${index + 1}` : `${index + 1}`; return { product: `Product ${keyValue}`, diff --git a/examples/Table.density.jsx b/examples/Table.density.jsx index a348f239ce4..b8c849c1e45 100644 --- a/examples/Table.density.jsx +++ b/examples/Table.density.jsx @@ -7,7 +7,7 @@ import { Flex, LabeledSelect, Table } from '@itwin/itwinui-react'; export default () => { const [density, setDensity] = React.useState('default'); - const generateItem = React.useCallback((index, parentRow = '', depth = 0) => { + const generateItem = React.useCallback((index, parentRow = '') => { const keyValue = parentRow ? `${parentRow}.${index + 1}` : `${index + 1}`; return { product: `Product ${keyValue}`, diff --git a/examples/Table.expandableContent.jsx b/examples/Table.expandableContent.jsx index e7406ca6212..002c472042d 100644 --- a/examples/Table.expandableContent.jsx +++ b/examples/Table.expandableContent.jsx @@ -6,7 +6,7 @@ import * as React from 'react'; import { Table, Text } from '@itwin/itwinui-react'; export default () => { - const generateItem = React.useCallback((index, parentRow = '', depth = 0) => { + const generateItem = React.useCallback((index, parentRow = '') => { const keyValue = parentRow ? `${parentRow}.${index + 1}` : `${index + 1}`; return { product: `Product ${keyValue}`, diff --git a/examples/Table.filtering.css b/examples/Table.filtering.css index e69de29bb2d..c07051439e9 100644 --- a/examples/Table.filtering.css +++ b/examples/Table.filtering.css @@ -0,0 +1,3 @@ +.demo-container { + width: 500px; +} diff --git a/examples/Table.filtering.jsx b/examples/Table.filtering.jsx index e69de29bb2d..76e7461765f 100644 --- a/examples/Table.filtering.jsx +++ b/examples/Table.filtering.jsx @@ -0,0 +1,60 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Bentley Systems, Incorporated. All rights reserved. + * See LICENSE.md in the project root for license terms and full copyright notice. + *--------------------------------------------------------------------------------------------*/ +import * as React from 'react'; +import { Table, tableFilters } from '@itwin/itwinui-react'; + +export default () => { + const data = React.useMemo( + () => [ + { + product: 'Product 1', + price: 15, + date: '2021-05-31T21:00:00.000Z', + }, + { + product: 'Product 2', + price: 45, + date: '2021-06-01T21:00:00.000Z', + }, + { + product: 'Product 3', + price: 10, + date: '2021-06-02T21:00:00.000Z', + }, + ], + [], + ); + + const columns = React.useMemo( + () => [ + { + id: 'product', + Header: 'Product', + accessor: 'product', + Filter: tableFilters.TextFilter(), + }, + { + id: 'price', + Header: 'Price', + accessor: 'price', + Filter: tableFilters.NumberRangeFilter(), + filter: 'between', + }, + { + id: 'date', + Header: 'Date', + accessor: 'date', + Filter: tableFilters.DateRangeFilter(), + }, + ], + [], + ); + + return ( +
+
+ + ); +}; diff --git a/examples/Table.globalFiltering.css b/examples/Table.globalFiltering.css new file mode 100644 index 00000000000..c07051439e9 --- /dev/null +++ b/examples/Table.globalFiltering.css @@ -0,0 +1,3 @@ +.demo-container { + width: 500px; +} diff --git a/examples/Table.globalFiltering.jsx b/examples/Table.globalFiltering.jsx new file mode 100644 index 00000000000..7812474eb0c --- /dev/null +++ b/examples/Table.globalFiltering.jsx @@ -0,0 +1,69 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Bentley Systems, Incorporated. All rights reserved. + * See LICENSE.md in the project root for license terms and full copyright notice. + *--------------------------------------------------------------------------------------------*/ +import * as React from 'react'; +import { Input, Table } from '@itwin/itwinui-react'; + +export default () => { + const data = React.useMemo( + () => [ + { + product: 'Product 1', + price: 15, + date: '2021-05-31T21:00:00.000Z', + }, + { + product: 'Product 2', + price: 45, + date: '2021-06-01T21:00:00.000Z', + }, + { + product: 'Product 3', + price: 10, + date: '2021-06-02T21:00:00.000Z', + }, + ], + [], + ); + + const columns = React.useMemo( + () => [ + { + id: 'product', + Header: 'Product', + accessor: 'product', + }, + { + id: 'price', + Header: 'Price', + accessor: 'price', + }, + { + id: 'date', + Header: 'Date', + accessor: 'date', + }, + ], + [], + ); + + const [globalFilter, setGlobalFilter] = React.useState(''); + + return ( +
+ setGlobalFilter(e.target.value)} + /> +
+ + ); +}; diff --git a/examples/Table.main.jsx b/examples/Table.main.jsx index deb20540c72..26276ad132c 100644 --- a/examples/Table.main.jsx +++ b/examples/Table.main.jsx @@ -6,7 +6,7 @@ import * as React from 'react'; import { Table } from '@itwin/itwinui-react'; export default () => { - const generateItem = React.useCallback((index, parentRow = '', depth = 0) => { + const generateItem = React.useCallback((index, parentRow = '') => { const keyValue = parentRow ? `${parentRow}.${index + 1}` : `${index + 1}`; return { product: `Product ${keyValue}`, diff --git a/examples/Table.pagination.jsx b/examples/Table.pagination.jsx index f2ad3af14a9..1fb85830060 100644 --- a/examples/Table.pagination.jsx +++ b/examples/Table.pagination.jsx @@ -6,7 +6,7 @@ import * as React from 'react'; import { Table, TablePaginator } from '@itwin/itwinui-react'; export default () => { - const generateItem = React.useCallback((index, parentRow = '', depth = 0) => { + const generateItem = React.useCallback((index, parentRow = '') => { const keyValue = parentRow ? `${parentRow}.${index + 1}` : `${index + 1}`; return { product: `Product ${keyValue}`, diff --git a/examples/Table.selectMulti.jsx b/examples/Table.selectMulti.jsx index fa964b1e59e..6609b34295c 100644 --- a/examples/Table.selectMulti.jsx +++ b/examples/Table.selectMulti.jsx @@ -6,7 +6,7 @@ import * as React from 'react'; import { Table } from '@itwin/itwinui-react'; export default () => { - const generateItem = React.useCallback((index, parentRow = '', depth = 0) => { + const generateItem = React.useCallback((index, parentRow = '') => { const keyValue = parentRow ? `${parentRow}.${index + 1}` : `${index + 1}`; return { product: `Product ${keyValue}`, diff --git a/examples/Table.selectSingle.jsx b/examples/Table.selectSingle.jsx index ea9789c8562..5f4f5b7185b 100644 --- a/examples/Table.selectSingle.jsx +++ b/examples/Table.selectSingle.jsx @@ -6,7 +6,7 @@ import * as React from 'react'; import { Table } from '@itwin/itwinui-react'; export default () => { - const generateItem = React.useCallback((index, parentRow = '', depth = 0) => { + const generateItem = React.useCallback((index, parentRow = '') => { const keyValue = parentRow ? `${parentRow}.${index + 1}` : `${index + 1}`; return { product: `Product ${keyValue}`, diff --git a/examples/Table.sorting.jsx b/examples/Table.sorting.jsx index 5bdfc99a7b4..fea95667082 100644 --- a/examples/Table.sorting.jsx +++ b/examples/Table.sorting.jsx @@ -6,11 +6,21 @@ import * as React from 'react'; import { Table } from '@itwin/itwinui-react'; export default () => { - const data = [ - { product: 'Product 1', price: '$15' }, - { product: 'Product 2', price: '$45' }, - { product: 'Product 3', price: '$30' }, - ]; + const generateItem = React.useCallback((index, parentRow = '') => { + const keyValue = parentRow ? `${parentRow}.${index + 1}` : `${index + 1}`; + return { + product: `Product ${keyValue}`, + price: ((index % 10) + 1) * 15, + }; + }, []); + + const data = React.useMemo( + () => + Array(3) + .fill(null) + .map((_, index) => generateItem(index)), + [generateItem], + ); const columns = React.useMemo( () => [ diff --git a/examples/Table.subRows.jsx b/examples/Table.subRows.jsx index 96b9c8ac17a..79ffb8625d7 100644 --- a/examples/Table.subRows.jsx +++ b/examples/Table.subRows.jsx @@ -6,7 +6,7 @@ import * as React from 'react'; import { Table } from '@itwin/itwinui-react'; export default () => { - const generateItem = React.useCallback((index, parentRow = '', depth = 0) => { + const generateItem = React.useCallback((index, parentRow = '') => { const keyValue = parentRow ? `${parentRow}.${index + 1}` : `${index + 1}`; return { product: `Product ${keyValue}`, diff --git a/examples/Table.virtualization.jsx b/examples/Table.virtualization.jsx index a51c0595b0d..d58355f0e2e 100644 --- a/examples/Table.virtualization.jsx +++ b/examples/Table.virtualization.jsx @@ -6,7 +6,7 @@ import * as React from 'react'; import { Table } from '@itwin/itwinui-react'; export default () => { - const generateItem = React.useCallback((index, parentRow = '', depth = 0) => { + const generateItem = React.useCallback((index, parentRow = '') => { const keyValue = parentRow ? `${parentRow}.${index + 1}` : `${index + 1}`; return { product: `Product ${keyValue}`, diff --git a/examples/index.tsx b/examples/index.tsx index 8b9d90affca..d2bd8066994 100644 --- a/examples/index.tsx +++ b/examples/index.tsx @@ -1280,6 +1280,16 @@ import { default as TableSortingExampleRaw } from './Table.sorting'; const TableSortingExample = withThemeProvider(TableSortingExampleRaw); export { TableSortingExample }; +import { default as TableFilteringExampleRaw } from './Table.filtering'; +const TableFilteringExample = withThemeProvider(TableFilteringExampleRaw); +export { TableFilteringExample }; + +import { default as TableGlobalFilteringExampleRaw } from './Table.globalFiltering'; +const TableGlobalFilteringExample = withThemeProvider( + TableGlobalFilteringExampleRaw, +); +export { TableGlobalFilteringExample }; + // ---------------------------------------------------------------------------- import { default as TabsMainExampleRaw } from './Tabs.main'; From c659fe786c0b8ed81dc6ddf02f1ce6a738c0da00 Mon Sep 17 00:00:00 2001 From: Uyen Doan Date: Thu, 23 Jan 2025 11:35:03 -0600 Subject: [PATCH 15/18] added manual filtering --- apps/website/src/content/docs/table.mdx | 6 +- examples/Table.manualFiltering.css | 4 + examples/Table.manualFiltering.jsx | 141 ++++++++++++++++++++++++ examples/index.tsx | 6 + 4 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 examples/Table.manualFiltering.css create mode 100644 examples/Table.manualFiltering.jsx diff --git a/apps/website/src/content/docs/table.mdx b/apps/website/src/content/docs/table.mdx index 2a452c9a8d7..cbded58dcd6 100644 --- a/apps/website/src/content/docs/table.mdx +++ b/apps/website/src/content/docs/table.mdx @@ -326,7 +326,11 @@ In addition to filtering data in individual columns, global filtering can be use **Note**: The `autoResetGlobalFilter` prop can be used to reset the table filter whenever a change is detected in the filter value. -#### Custom filtering +#### Manual filtering + + + + ## Props diff --git a/examples/Table.manualFiltering.css b/examples/Table.manualFiltering.css new file mode 100644 index 00000000000..fcda39c391f --- /dev/null +++ b/examples/Table.manualFiltering.css @@ -0,0 +1,4 @@ +.demo-container { + width: 500px; + height: 300px; +} diff --git a/examples/Table.manualFiltering.jsx b/examples/Table.manualFiltering.jsx new file mode 100644 index 00000000000..148408f1bb7 --- /dev/null +++ b/examples/Table.manualFiltering.jsx @@ -0,0 +1,141 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Bentley Systems, Incorporated. All rights reserved. + * See LICENSE.md in the project root for license terms and full copyright notice. + *--------------------------------------------------------------------------------------------*/ +import * as React from 'react'; +import { BaseFilter, Radio, Table } from '@itwin/itwinui-react'; + +export default () => { + const rowsCount = React.useMemo(() => 100, []); + const [filter, setFilter] = React.useState(''); + const [isLoading, setIsLoading] = React.useState(false); + const [filteredData, setFilteredData] = React.useState(undefined); + + const generateData = (start, end) => { + return Array(end - start) + .fill(null) + .map((_, index) => { + if (filteredData !== undefined && !filter) { + return filteredData[index]; + } else { + return { + product: `Product ${start + index}`, + price: `$${index}`, + }; + } + }); + }; + + const [data, setData] = React.useState(() => generateData(0, 100)); + + const isPassFilter = React.useCallback((dataRow, filter) => { + // check that the name passes a filter, if there is one + if (!filter.name || (filter.name && dataRow.name.includes(filter.name))) { + return true; + } + return false; + }, []); + + const generateFilteredData = React.useCallback( + (filter) => { + let dataNumber = 0; + const dataArray = []; + let newData = { product: '', price: '' }; + do { + do { + newData = { + product: `Product${dataNumber}`, + price: `$${dataNumber}`, + }; + dataNumber++; + } while (!isPassFilter(newData, filter) && dataNumber < rowsCount); + if (isPassFilter(newData, filter)) { + dataArray.push(newData); + } + } while (dataNumber < rowsCount); + + setFilteredData(dataArray); + return dataArray; + }, + [isPassFilter, rowsCount], + ); + + const CustomFilter = () => { + const handleChange = (isChecked, filter) => { + setFilter(isChecked ? filter : ''); + setIsLoading(true); + setData([]); + // simulate a filtered request + setTimeout(() => { + setIsLoading(false); + const filteredData = generateFilteredData({ + product: isChecked ? filter : '', + price: '', + }); + setData(filteredData.slice(0, rowsCount)); + }, 500); + }; + + return ( + + { + handleChange(value === 'on', '3'); + }} + checked={filter === '3'} + autoFocus={filter === '3'} + /> + { + handleChange(value === 'on', '5'); + }} + checked={filter === '5'} + autoFocus={filter === '5'} + /> + { + handleChange(value === 'on', '7'); + }} + checked={filter === '7'} + autoFocus={filter === '7'} + /> + { + handleChange(value === 'on', ''); + }} + checked={filter === ''} + autoFocus={filter === ''} + /> + + ); + }; + + const columns = [ + { + id: 'product', + Header: 'Product', + accessor: 'product', + Filter: CustomFilter, + }, + { + id: 'price', + Header: 'Price', + accessor: 'price', + }, + ]; + + return ( +
+ ); +}; diff --git a/examples/index.tsx b/examples/index.tsx index d2bd8066994..2de3e628e41 100644 --- a/examples/index.tsx +++ b/examples/index.tsx @@ -1290,6 +1290,12 @@ const TableGlobalFilteringExample = withThemeProvider( ); export { TableGlobalFilteringExample }; +import { default as TableManualFilteringExampleRaw } from './Table.manualFiltering'; +const TableManualFilteringExample = withThemeProvider( + TableManualFilteringExampleRaw, +); +export { TableManualFilteringExample }; + // ---------------------------------------------------------------------------- import { default as TabsMainExampleRaw } from './Tabs.main'; From 2be6c60428e3ae45bc936df8566b314c2299db95 Mon Sep 17 00:00:00 2001 From: Uyen Doan Date: Thu, 23 Jan 2025 16:35:59 -0600 Subject: [PATCH 16/18] custom filter --- apps/website/src/content/docs/table.mdx | 2 ++ examples/Table.manualFiltering.jsx | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/website/src/content/docs/table.mdx b/apps/website/src/content/docs/table.mdx index cbded58dcd6..d1c12cc90a5 100644 --- a/apps/website/src/content/docs/table.mdx +++ b/apps/website/src/content/docs/table.mdx @@ -328,6 +328,8 @@ In addition to filtering data in individual columns, global filtering can be use #### Manual filtering +The `Table` supports custom filtering, allowing users to filter columns based on their specific needs. To implement custom filtering, you can use the `BaseFilter` component as a wrapper for your custom filter component. Then, this custom filter component can be passed into the `Filter` option of the column object. + diff --git a/examples/Table.manualFiltering.jsx b/examples/Table.manualFiltering.jsx index 148408f1bb7..d23d27ac497 100644 --- a/examples/Table.manualFiltering.jsx +++ b/examples/Table.manualFiltering.jsx @@ -30,7 +30,10 @@ export default () => { const isPassFilter = React.useCallback((dataRow, filter) => { // check that the name passes a filter, if there is one - if (!filter.name || (filter.name && dataRow.name.includes(filter.name))) { + if ( + !filter.product || + (filter.product && dataRow.product.includes(filter.product)) + ) { return true; } return false; From fea9939c756874acb59815ce0e66c436549230f8 Mon Sep 17 00:00:00 2001 From: Uyen Doan Date: Thu, 23 Jan 2025 22:24:45 -0600 Subject: [PATCH 17/18] getRowId vs rowProps --- apps/website/src/content/docs/table.mdx | 29 ++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/apps/website/src/content/docs/table.mdx b/apps/website/src/content/docs/table.mdx index d1c12cc90a5..59b24c2afbd 100644 --- a/apps/website/src/content/docs/table.mdx +++ b/apps/website/src/content/docs/table.mdx @@ -24,6 +24,33 @@ The most basic `Table` can be implemented by passing three props: **Note**: The `Table` component is built based on `react-table` v7. For more information about `react-table`, see this [doc](https://react-table.tanstack.com/docs/api/overview). +#### `rowProps` vs. `getRowId` + +The `Table` component provides two important props, `rowProps` and `getRowId` which serve different purposes in customizing and managing the table row data. + +The `rowProps` prop is a function that allows passing additional properties to the rows, such as custom attributes, event handlers, or styles based on the data. This can be useful for customizing the behavior and appearance of each row. The type `React.ComponentPropsWithRef<'div'>` ensures that the properties passed are valid for a `div` element, which is the default element used for table rows. This prop provides the flexibility to customize the id of the HTML `div` row element. + +```jsx {3} +const rowProps = React.useCallback((row) => { + return { + id: row.id, + status: row.original.status, + }; +}, []); +``` + +On the other hand, `getRowId` is used to specify a unique identifier in each row's internal data. This is particularly useful when the data does not have a unique `id` field for each object or when a different field is needed to be used as the unique identifier. + +```jsx {6} +
'my-id' + row.name} +/> +``` + ### Subrow The `Table` component supports hierarchical data structures, allowing end users to display subrows, which can be expanded or collapsed. Each data entry in the `data` array should have `subRows` array. @@ -310,7 +337,7 @@ For basic filtering in the `Table`, you can pass the `Filter` prop to the column - `TextFilter`: a basic string filter with a single input field. - `NumberRangeFilter`: a number range filter. It only works with `number` type object properties. If the data is required to be different type e.g. `string`, you can use `accessor` property in column description: `accessor: (rowData) => Number(rowData.numberProp)`. -- `DateRangeFilter`: a date range filter. By default it handles user input in `en-us` date format. If there are other specific formats that need to be displayed, date range options `formatDate`, `parseInput` and `placeholder` can passed into the filter component. +- `DateRangeFilter`: a date range filter. By default, it handles user input in `en-us` date format. If there are other specific formats that need to be displayed, `formatDate`, `parseInput` and `placeholder` are the date range filter options that can passed into the filter component. From c8579799ffa5d869ac4e584748c87d1b583f2b78 Mon Sep 17 00:00:00 2001 From: Uyen Doan Date: Fri, 24 Jan 2025 14:17:10 -0600 Subject: [PATCH 18/18] added aria-label to IconButton --- examples/Table.columnManager.jsx | 1 + examples/Table.manualFiltering.css | 1 - examples/Table.manualFiltering.jsx | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/Table.columnManager.jsx b/examples/Table.columnManager.jsx index 22a0a74a9f8..30689e231b2 100644 --- a/examples/Table.columnManager.jsx +++ b/examples/Table.columnManager.jsx @@ -60,6 +60,7 @@ export default () => { onClick={(e) => e.stopPropagation()} > e.stopPropagation()} > diff --git a/examples/Table.manualFiltering.css b/examples/Table.manualFiltering.css index fcda39c391f..c07051439e9 100644 --- a/examples/Table.manualFiltering.css +++ b/examples/Table.manualFiltering.css @@ -1,4 +1,3 @@ .demo-container { width: 500px; - height: 300px; } diff --git a/examples/Table.manualFiltering.jsx b/examples/Table.manualFiltering.jsx index d23d27ac497..712bb12d978 100644 --- a/examples/Table.manualFiltering.jsx +++ b/examples/Table.manualFiltering.jsx @@ -138,6 +138,7 @@ export default () => { data={data} isLoading={isLoading} emptyTableContent='No data.' + style={{ height: '300px' }} manualFilters={true} /> );