Skip to content

Commit

Permalink
docs(Table): add virtualization example (#6813)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lukas742 authored Jan 13, 2025
1 parent 185f0d8 commit 13f6fb1
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 3 deletions.
8 changes: 8 additions & 0 deletions .storybook/preview-head.html
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,14 @@
padding-block: 0.125rem !important;
}

/*ui5-table: height for virtualized table according to content-density mode*/
.tableHeightContentDensity {
height: 396px;
}
.ui5-content-density-compact .tableHeightContentDensity {
height: 288px;
}

/* TODO remove this workaround as soon as https://github.com/storybookjs/storybook/issues/20497 is fixed */
.docs-story > div > div[scale] {
min-height: 20px;
Expand Down
72 changes: 70 additions & 2 deletions packages/main/src/webComponents/Table/Table.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ const GrowingTable = () => {
<summary>Show code</summary>

```jsx
function TableWithRowSelection() {
function TableWithRowSelection(props) {
const [mode, setMode] = useState(TableSelectionMode.Multiple);
return (
<>
Expand All @@ -129,7 +129,7 @@ function TableWithRowSelection() {
))}
</SegmentedButton>
<Table
{...otherProps}
{...props}
headerRow={
<TableHeaderRow sticky>
<TableHeaderCell width={'200px'} minWidth={'200px'}>
Expand Down Expand Up @@ -193,6 +193,74 @@ function TableWithRowSelection() {

</details>

## Table with virtualized rows

`Table` with virtualization feature (`<TableVirtualizer {...props) />`):

<Canvas of={ComponentStories.VirtualizedTableRows} />

<details>

<summary>Show code</summary>

```tsx
// enrich data with `position` (if not already available)
const dataLargeWithPosition = dataLarge.map((item, index) => ({
...item,
position: index
}));

function VirtualizedTable(props) {
const [data, setData] = useState(dataLargeWithPosition.slice(0, 9));

const handleRangeChange: TableVirtualizerPropTypes['onRangeChange'] = (e) => {
const { first, last } = e.detail;

// render two rows before and after the visible area of the table body container
const overscanCountStart = Math.max(first - 2, 0);
const overscanCountEnd = Math.min(last + 2, dataLargeWithPosition.length);
setData(dataLargeWithPosition.slice(overscanCountStart, overscanCountEnd));
};
return (
<Table
{...props}
// headerRow + 8 visible rows:
// 9 * 44px = 396px (content-density: Cozy)
// 9 * 32px = 288px (content-density: Compact)
style={{ height: '396px' }}
headerRow={
<TableHeaderRow sticky>
<TableHeaderCell>Name</TableHeaderCell>
<TableHeaderCell>Age</TableHeaderCell>
<TableHeaderCell>Friend Name</TableHeaderCell>
<TableHeaderCell>Friend Age</TableHeaderCell>
</TableHeaderRow>
}
features={<TableVirtualizer rowCount={500} rowHeight={44} onRangeChange={handleRangeChange} />}
>
{data.map((row) => (
<TableRow key={row.position} position={row.position}>
<TableCell>
<span>{row.name}</span>
</TableCell>
<TableCell>
<span>{row.age}</span>
</TableCell>
<TableCell>
<span>{row.friend.name}</span>
</TableCell>
<TableCell>
<span>{row.friend.age}</span>
</TableCell>
</TableRow>
))}
</Table>
);
}
```

</details>

<Markdown>{SubcomponentsSection}</Markdown>

## TableHeaderRow
Expand Down
74 changes: 73 additions & 1 deletion packages/main/src/webComponents/Table/Table.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import dataLarge from '@sb/mockData/Friends500.json';
import type { Meta, StoryObj } from '@storybook/react';
import TableGrowingMode from '@ui5/webcomponents/dist/types/TableGrowingMode.js';
import TableSelectionMode from '@ui5/webcomponents/dist/types/TableSelectionMode.js';
import type { TableVirtualizerPropTypes } from '@ui5/webcomponents-react';
import { SegmentedButton, SegmentedButtonItem } from '@ui5/webcomponents-react';
import { useState } from 'react';
import { useEffect, useState } from 'react';
import { TableCell } from '../TableCell/index.js';
import { TableGrowing } from '../TableGrowing/index.js';
import { TableHeaderCell } from '../TableHeaderCell/index.js';
import { TableHeaderRow } from '../TableHeaderRow/index.js';
import { TableRow } from '../TableRow/index.js';
import { TableSelection } from '../TableSelection/index.js';
import { TableVirtualizer } from '../TableVirtualizer/index.js';
import { Table } from './index.js';

const meta = {
Expand Down Expand Up @@ -182,3 +185,72 @@ export const WithSelection: Story = {
);
}
};

const dataLargeWithPosition = dataLarge.map((item, index) => ({ ...item, position: index }));

export const VirtualizedTableRows: Story = {
args: { className: 'tableHeightContentDensity' },
render(args) {
const [data, setData] = useState(dataLargeWithPosition.slice(0, 9));
const [isCozy, setIsCozy] = useState(true);

const handleRangeChange: TableVirtualizerPropTypes['onRangeChange'] = (e) => {
const { first, last } = e.detail;

// overscanCount = 2
const overscanCountStart = Math.max(first - 2, 0);
const overscanCountEnd = Math.min(last + 2, dataLargeWithPosition.length);
setData(dataLargeWithPosition.slice(overscanCountStart, overscanCountEnd));
};

// adjust row height according to content-density mode (only for demo purposes)
useEffect(() => {
const body = document.body;
if (!body) return;

const observer = new MutationObserver((mutationsList) => {
mutationsList.forEach((mutation) => {
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
setIsCozy(!body.classList.contains('ui5-content-density-compact'));
}
});
});
observer.observe(body, { attributes: true, attributeFilter: ['class'] });
return () => {
observer.disconnect();
};
}, []);

return (
<Table
{...args}
headerRow={
<TableHeaderRow sticky>
<TableHeaderCell>Name</TableHeaderCell>
<TableHeaderCell>Age</TableHeaderCell>
<TableHeaderCell>Friend Name</TableHeaderCell>
<TableHeaderCell>Friend Age</TableHeaderCell>
</TableHeaderRow>
}
features={<TableVirtualizer rowCount={500} rowHeight={isCozy ? 44 : 32} onRangeChange={handleRangeChange} />}
>
{data.map((row) => (
<TableRow key={row.position} position={row.position}>
<TableCell>
<span>{row.name}</span>
</TableCell>
<TableCell>
<span>{row.age}</span>
</TableCell>
<TableCell>
<span>{row.friend.name}</span>
</TableCell>
<TableCell>
<span>{row.friend.age}</span>
</TableCell>
</TableRow>
))}
</Table>
);
}
};

0 comments on commit 13f6fb1

Please sign in to comment.