-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(PHC-4380): create ReactTableModule #331
- Loading branch information
Shawn Zhu
committed
Mar 20, 2023
1 parent
2c5973d
commit b832083
Showing
6 changed files
with
350 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
184 changes: 184 additions & 0 deletions
184
src/components/TableModule/ReactTableModule.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
import React, { useRef } from 'react'; | ||
import { ComponentStory, ComponentMeta } from '@storybook/react'; | ||
import { createColumnHelper, Row } from '@tanstack/react-table'; | ||
import { Checkbox } from '../Checkbox'; | ||
|
||
import { ReactTableModule } from './ReactTableModule'; | ||
|
||
export default { | ||
title: 'Components/TableModule2', | ||
component: ReactTableModule, | ||
argTypes: {}, | ||
} as ComponentMeta<typeof ReactTableModule>; | ||
|
||
type Food = { | ||
description: string; | ||
calories: string; | ||
fat: string; | ||
carbs: string; | ||
category: string; | ||
}; | ||
|
||
const data: Food[] = [ | ||
{ | ||
description: 'Frozen yoghurt', | ||
calories: '159', | ||
fat: '6.0', | ||
carbs: '24', | ||
category: 'yogurt', | ||
}, | ||
{ | ||
description: 'Ice cream sandwich', | ||
calories: '237', | ||
fat: '9.0', | ||
carbs: '37', | ||
category: 'ice cream', | ||
}, | ||
{ | ||
description: 'Eclair', | ||
calories: '262', | ||
fat: '16.0', | ||
carbs: '24', | ||
category: 'dessert', | ||
}, | ||
{ | ||
description: 'Cupcake', | ||
calories: '305', | ||
fat: '3.7', | ||
carbs: '67', | ||
category: 'cake', | ||
}, | ||
]; | ||
|
||
const columnHelper = createColumnHelper<Food>(); | ||
|
||
const columns = [ | ||
columnHelper.accessor('description', { | ||
cell: (info) => info.getValue(), | ||
header: 'Description', | ||
}), | ||
columnHelper.accessor((row) => row.calories, { | ||
id: 'calories', | ||
cell: (info) => <i>{info.getValue()}</i>, | ||
header: () => <span>Calories</span>, | ||
}), | ||
columnHelper.accessor('fat', { | ||
header: () => 'Fat', | ||
cell: (info) => info.renderValue(), | ||
}), | ||
columnHelper.accessor('carbs', { | ||
header: () => <span>Carbs</span>, | ||
}), | ||
columnHelper.accessor('category', { | ||
header: 'Category', | ||
}), | ||
]; | ||
|
||
const config = [ | ||
{ | ||
header: { | ||
label: 'Description', | ||
}, | ||
cell: { | ||
content: (dataValue: any) => { | ||
return dataValue.description; | ||
}, | ||
}, | ||
}, | ||
{ | ||
header: { | ||
label: 'Calories', | ||
}, | ||
cell: { | ||
content: (dataValue: any) => { | ||
return dataValue.calories; | ||
}, | ||
}, | ||
}, | ||
{ | ||
header: { | ||
label: 'Fat', | ||
}, | ||
cell: { | ||
content: (dataValue: any) => { | ||
return dataValue.fat; | ||
}, | ||
}, | ||
}, | ||
{ | ||
header: { | ||
label: 'Carbs', | ||
}, | ||
cell: { | ||
content: (dataValue: any) => { | ||
return dataValue.carbs; | ||
}, | ||
}, | ||
}, | ||
{ | ||
header: { | ||
label: 'Category', | ||
}, | ||
cell: { | ||
content: (dataValue: any) => { | ||
return dataValue.category; | ||
}, | ||
}, | ||
}, | ||
]; | ||
|
||
const Template: ComponentStory<typeof ReactTableModule> = (args) => { | ||
const tableRef = useRef<HTMLTableElement>(null); | ||
|
||
const [rowSelection, setRowSelection] = React.useState({}); | ||
|
||
if (args.enableRowSelection) { | ||
args.state = { rowSelection }; | ||
args.onRowSelectionChange = setRowSelection; | ||
} | ||
|
||
return ( | ||
<div style={{ overflow: 'auto', width: '80%', height: '400px' }}> | ||
<ReactTableModule {...args} ref={tableRef} /> | ||
</div> | ||
); | ||
}; | ||
|
||
export const Default = Template.bind({}); | ||
Default.args = { | ||
data, | ||
config, | ||
}; | ||
|
||
export const RowSelection = Template.bind({}); | ||
const selectionColumn = { | ||
id: 'select', | ||
header: ({ table }) => ( | ||
<Checkbox | ||
{...{ | ||
label: ' ', | ||
checked: table.getIsAllRowsSelected(), | ||
indeterminate: table.getIsSomeRowsSelected(), | ||
onChange: table.getToggleAllRowsSelectedHandler(), | ||
}} | ||
/> | ||
), | ||
cell: ({ row }) => ( | ||
<div className="px-1"> | ||
<Checkbox | ||
{...{ | ||
label: ' ', | ||
checked: row.getIsSelected(), | ||
disabled: !row.getCanSelect(), | ||
onChange: row.getToggleSelectedHandler(), | ||
}} | ||
/> | ||
</div> | ||
), | ||
}; | ||
|
||
RowSelection.args = { | ||
data, | ||
columns: [selectionColumn, ...columns], | ||
enableRowSelection: true, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
import * as React from 'react'; | ||
import clsx from 'clsx'; | ||
|
||
import { | ||
getCoreRowModel, | ||
useReactTable, | ||
ColumnDef, | ||
OnChangeFn, | ||
TableState, | ||
} from '@tanstack/react-table'; | ||
|
||
import { | ||
TableModuleProps, | ||
useStyles, | ||
testIds, | ||
} from '../TableModule/TableModule'; | ||
import { TableModuleRow } from '../TableModule/TableModuleRow'; | ||
import { TableHeaderCell } from '../TableModule/TableHeaderCell'; | ||
import { DotLoader } from '../DotLoader/index'; | ||
import { getTestProps } from '../../testUtils/getTestProps'; | ||
import { mapTableConfigToColumnDef } from './utils'; | ||
|
||
export interface ReactTableProps<T> extends TableModuleProps { | ||
data: Array<T>; | ||
columns?: ColumnDef<T, any>[]; | ||
enableRowSelection?: boolean; | ||
onRowSelectionChange?: OnChangeFn<T>; | ||
state?: Partial<TableState>; | ||
} | ||
|
||
export const ReactTableModule = React.memo( | ||
React.forwardRef<HTMLTableElement, ReactTableProps<any>>( | ||
( | ||
{ | ||
columns, | ||
config, | ||
className, | ||
data, | ||
enableRowSelection, | ||
isLoading = false, | ||
onRowSelectionChange, | ||
rowRole, | ||
maxCellWidth, | ||
rowClickLabel, | ||
state, | ||
...rootProps | ||
}, | ||
forwardedRef | ||
) => { | ||
const classes = useStyles({}); | ||
|
||
if (columns === undefined && !!config) { | ||
columns = config.map(mapTableConfigToColumnDef); | ||
} | ||
|
||
const table = useReactTable({ | ||
data, | ||
columns, | ||
enableRowSelection, | ||
getCoreRowModel: getCoreRowModel(), | ||
onRowSelectionChange, | ||
state, | ||
}); | ||
|
||
const headings = table.getHeaderGroups()[0].headers; | ||
|
||
return ( | ||
<table | ||
role="table" | ||
className={clsx(classes.root, className)} | ||
ref={forwardedRef} | ||
{...rootProps} | ||
> | ||
<thead className={classes.tableHeader}> | ||
{table.getHeaderGroups().map((headerGroup) => ( | ||
<tr | ||
key={headerGroup.id} | ||
className={classes.tableRow} | ||
role="row" | ||
{...getTestProps(testIds.headerRow)} | ||
> | ||
{headerGroup.headers.map((header, i) => ( | ||
<TableHeaderCell | ||
index={i} | ||
key={header.id} | ||
header={{ label: header.id }} | ||
></TableHeaderCell> | ||
))} | ||
</tr> | ||
))} | ||
</thead> | ||
<tbody role="rowgroup"> | ||
{!isLoading && | ||
data && | ||
table | ||
.getRowModel() | ||
.rows.map((row, rowIndex) => ( | ||
<TableModuleRow | ||
key={`tableRow-${rowIndex}`} | ||
data={row} | ||
rowRole={rowRole} | ||
maxCellWidth={maxCellWidth} | ||
row={row} | ||
headingsLength={headings?.length} | ||
cells={row.getVisibleCells()} | ||
rowClickLabel={rowClickLabel} | ||
/> | ||
))} | ||
{isLoading && ( | ||
<tr | ||
className={classes.tableRow} | ||
{...getTestProps(testIds.isLoadingRow)} | ||
> | ||
<td | ||
className={classes.tableLoadingCell} | ||
colSpan={table.getHeaderGroups()[0].headers.length} | ||
> | ||
<DotLoader size={0} /> | ||
</td> | ||
</tr> | ||
)} | ||
</tbody> | ||
</table> | ||
); | ||
} | ||
) | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { createColumnHelper, ColumnDef } from '@tanstack/react-table'; | ||
import { TableConfiguration } from './types'; | ||
|
||
const columnHelper = createColumnHelper(); | ||
|
||
/** | ||
* returns react table ColumnDef. | ||
* @param config legacy configuration of TableModule | ||
*/ | ||
export const mapTableConfigToColumnDef = ( | ||
config: TableConfiguration<any> | ||
): ColumnDef<any, any> => { | ||
// TODO support accessor columnFn | ||
return { | ||
id: config.header.label || config.header.content(config.header), | ||
accessorFn: config.cell.content, | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5619,6 +5619,18 @@ | |
"@svgr/plugin-svgo" "^4.2.0" | ||
loader-utils "^1.2.3" | ||
|
||
"@tanstack/react-table@^8.7.9": | ||
version "8.7.9" | ||
resolved "https://registry.yarnpkg.com/@tanstack/react-table/-/react-table-8.7.9.tgz#9efcd168fb0080a7e0bc213b5eac8b55513babf4" | ||
integrity sha512-6MbbQn5AupSOkek1+6IYu+1yZNthAKTRZw9tW92Vi6++iRrD1GbI3lKTjJalf8lEEKOqapPzQPE20nywu0PjCA== | ||
dependencies: | ||
"@tanstack/table-core" "8.7.9" | ||
|
||
"@tanstack/[email protected]": | ||
version "8.7.9" | ||
resolved "https://registry.yarnpkg.com/@tanstack/table-core/-/table-core-8.7.9.tgz#0e975f8a5079972f1827a569079943d43257c42f" | ||
integrity sha512-4RkayPMV1oS2SKDXfQbFoct1w5k+pvGpmX18tCXMofK/VDRdA2hhxfsQlMvsJ4oTX8b0CI4Y3GDKn5T425jBCw== | ||
|
||
"@testing-library/dom@^7.2.1", "@testing-library/dom@^7.22.3": | ||
version "7.31.2" | ||
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-7.31.2.tgz#df361db38f5212b88555068ab8119f5d841a8c4a" | ||
|