Skip to content

Commit

Permalink
Make Cell & HeaderCell generic (#474)
Browse files Browse the repository at this point in the history
* Update core components to pass around generic type params

* Update example

* Update tests and ts example

* Perform a preliminary flattening of children so that fragments are properly handled

* Prevent unnecessary re-flattening

* Update docs and add test for failing typecheck
  • Loading branch information
lorefnon authored Nov 24, 2023
1 parent 79a6dd8 commit f988cb5
Show file tree
Hide file tree
Showing 14 changed files with 1,389 additions and 1,146 deletions.
59 changes: 59 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ const App = () => (
| autoHeight | boolean | The height of the table will be automatically expanded according to the number of data rows, and no vertical scroll bar will appear |
| bordered | boolean | Show border |
| cellBordered | boolean | Show cell border |
| children | (components: { Cell, HeaderCell, ColumnGroup }) => React.ReactNode | Render props that receives parameterized Cell, HeaderCell, ColumnGroup components - making typescript usage more convenient |
| data \* | object[] | Table data |
| defaultExpandAllRows | boolean | Expand all nodes By default |
| defaultExpandedRowKeys | string[] | Specify the default expanded row by `rowkey` |
Expand Down Expand Up @@ -238,3 +239,61 @@ const NameCell = ({ rowData, ...props }) => (
[coverage]: https://coveralls.io/github/rsuite/rsuite-table
[actions-svg]: https://github.com/rsuite/rsuite-table/workflows/Node.js%20CI/badge.svg?branch=main
[actions-home]: https://github.com/rsuite/rsuite-table/actions?query=branch%3Amain+workflow%3A%22Node.js+CI%22

### Type safety

We can pass generic type parameters to Table, Cell etc. for better type-safety when using typescript.

Passing a render prop to Table is recommended when using TS, as this will ensure that
the right generic type parameter is automatically propagated to the Cell component.

```ts
const products: Product[] = [{ name: "Pineapple" }];

<Table<Product, string> ref={table} data={products}>
{({ Column, HeaderCell, Cell }) => (
<>
<Column>
<HeaderCell>Name</HeaderCell>
{/* No need for passing explicit type parameter to Cell */}
<Cell>{row => row.name}</Cell>
</Column>
</>
)}
</Table>;
```

In fact, the type parameter from table can be inferred from the data passed to it, so the type parameter to Table can also be skipped.

```ts
const products: Product[] = [{ name: "Pineapple" }];

<Table data={products}>
{({ Column, HeaderCell, Cell }) => (
<>
<Column>
<HeaderCell>Name</HeaderCell>
<Cell>{row => row.name}</Cell>
</Column>
</>
)}
</Table>;
```

When writing reusable components, it is recommended to make your components generic as well. For example:

```ts
interface ImageCellProps<TKey extends string, TRow extends Record<TKey, string>> {
rowData: TRow,
dataKey: TKey,
// ... any other props
}

const ImageCell = <TKey extends string, TRow extends Record<TKey, string>>(
{ rowData, dataKey, ...rest }: ImageCellProps<TKey, TRow>
) => (
<Cell<TRow, TKey> {...rest}>
<img src={rowData[dataKey]} width="50" />
</Cell>
);
```
99 changes: 53 additions & 46 deletions docs/examples/Virtualized.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,52 +38,59 @@ const LargeListsTable = () => {
console.log(data);
}}
>
<Column width={70} align="center" fixed>
<HeaderCell>Id</HeaderCell>
<Cell dataKey="id" />
</Column>

<Column width={80} align="center">
<HeaderCell>Avartar</HeaderCell>
<ImageCell dataKey="avartar" />
</Column>

<Column width={130} fullText>
<HeaderCell>First Name</HeaderCell>
<Cell dataKey="firstName" />
</Column>

<Column width={130} fullText>
<HeaderCell>Last Name</HeaderCell>
<Cell dataKey="lastName" />
</Column>

<Column width={200} fullText>
<HeaderCell>City</HeaderCell>
<Cell dataKey="city" />
</Column>

<Column width={200} fullText>
<HeaderCell>Street</HeaderCell>
<Cell dataKey="street" />
</Column>

<Column width={200} fullText>
<HeaderCell>Company</HeaderCell>
<Cell dataKey="company" />
</Column>
<Column width={200} fullText>
<HeaderCell>phone</HeaderCell>
<Cell dataKey="phone" />
</Column>
<Column width={200} fullText>
<HeaderCell>amount</HeaderCell>
<Cell dataKey="amount" />
</Column>
<Column width={200} fullText>
<HeaderCell>age</HeaderCell>
<Cell dataKey="age" />
</Column>
{({ Column, HeaderCell, Cell }) => (
<>
<Column width={70} align="center" fixed>
<HeaderCell>Id</HeaderCell>
<Cell dataKey="id" />
</Column>

<Column width={80} align="center">
<HeaderCell>Avartar</HeaderCell>
<ImageCell dataKey="avartar" />
</Column>

<Column width={130} fullText>
<HeaderCell>First Name</HeaderCell>
<Cell dataKey="firstName" />
</Column>

<Column width={130} fullText>
<HeaderCell>Last Name</HeaderCell>
<Cell dataKey="lastName" />
</Column>

<Column width={200} fullText>
<HeaderCell>City</HeaderCell>
<Cell dataKey="city" />
</Column>

<Column width={200} fullText>
<HeaderCell>Street</HeaderCell>
<Cell dataKey="street" />
</Column>

<Column width={200} fullText>
<HeaderCell>Company</HeaderCell>
<Cell dataKey="company" />
</Column>

<Column width={200} fullText>
<HeaderCell>phone</HeaderCell>
<Cell dataKey="phone" />
</Column>

<Column width={200} fullText>
<HeaderCell>amount</HeaderCell>
<Cell dataKey="amount" />
</Column>

<Column width={200} fullText>
<HeaderCell>age</HeaderCell>
<Cell dataKey="age" />
</Column>
</>
)}
</Table>
<button
onClick={() => {
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
"@types/prop-types": "^15.7.1",
"@types/react": "^18.0.17",
"@types/react-dom": "^18.0.6",
"@types/react-is": "^18.2.4",
"@typescript-eslint/eslint-plugin": "^6.9.0",
"@typescript-eslint/parser": "^6.9.0",
"autoprefixer": "^8.3.0",
Expand Down
9 changes: 9 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

1 comment on commit f988cb5

@vercel
Copy link

@vercel vercel bot commented on f988cb5 Nov 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.