Skip to content

Commit 8319d5a

Browse files
authored
feat(collection): Add table type to Collection UI primitive (#6665)
* feat(collection): Add table type to collection primitive * chore(collection): Use partial type to avoid type parsing linter error * chore(collection): Add changeset for adding `table` type to `Collection` UI primitive
1 parent 4708848 commit 8319d5a

File tree

4 files changed

+77
-0
lines changed

4 files changed

+77
-0
lines changed

.changeset/unlucky-otters-dress.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@aws-amplify/ui-react": minor
3+
---
4+
5+
feat(collection): Add `table` type to `Collection` UI primitive

packages/react/src/primitives/Collection/Collection.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ import type {
1616
ElementType,
1717
GridCollectionProps,
1818
ListCollectionProps,
19+
TableCollectionProps,
1920
} from '../types';
2021
import { getItemsAtPage, itemHasText, getPageCount } from './utils';
22+
import { Table, TableBody } from '../Table';
2123

2224
const DEFAULT_PAGE_SIZE = 10;
2325
const TYPEAHEAD_DELAY_MS = 300;
@@ -41,6 +43,18 @@ const GridCollection = <Item,>({
4143
<Grid {...rest}>{Array.isArray(items) ? items.map(children) : null}</Grid>
4244
);
4345

46+
const TableCollection = <Item,>({
47+
children,
48+
items,
49+
tableHeader: TableHeader,
50+
...rest
51+
}: TableCollectionProps<Item>) => (
52+
<Table {...rest}>
53+
<TableHeader />
54+
<TableBody>{Array.isArray(items) ? items.map(children) : null}</TableBody>
55+
</Table>
56+
);
57+
4458
const renderCollectionOrNoResultsFound = <Item,>(
4559
collection: React.JSX.Element | null,
4660
items: Item[],
@@ -114,6 +128,13 @@ export const Collection = <Item, Element extends ElementType>({
114128
items={items}
115129
{...rest}
116130
/>
131+
) : type === 'table' ? (
132+
<TableCollection
133+
className={ComponentClassName.CollectionItems}
134+
items={items}
135+
tableHeader={(rest as Partial<TableCollectionProps<Item>>).tableHeader!}
136+
{...rest}
137+
/>
117138
) : null;
118139

119140
return (

packages/react/src/primitives/Collection/__tests__/Collection.test.tsx

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { Flex } from '../../Flex';
1010
import { Text } from '../../Text';
1111
import { ComponentText } from '../../shared/constants';
1212
import { ComponentPropsToStylePropsMap } from '../../types';
13+
import { TableCell, TableHead, TableRow } from '../../Table';
1314

1415
const emojis = [
1516
{
@@ -282,4 +283,45 @@ describe('Collection component', () => {
282283
const noResults = await screen.findByText(customText);
283284
expect(noResults).toBeDefined();
284285
});
286+
287+
it('should render table with table header when type is table', async () => {
288+
const borderStyle = '1px solid red';
289+
render(
290+
<Collection
291+
testId={testList}
292+
type="table"
293+
items={emojis}
294+
border={borderStyle}
295+
tableHeader={() => (
296+
<TableRow>
297+
<TableHead>Title</TableHead>
298+
<TableHead>Emoji</TableHead>
299+
</TableRow>
300+
)}
301+
>
302+
{(item, _index) => (
303+
<TableRow>
304+
<TableCell>{item.title}</TableCell>
305+
<TableCell>{item.emoji}</TableCell>
306+
</TableRow>
307+
)}
308+
</Collection>
309+
);
310+
311+
const collection = await screen.findByTestId(testList);
312+
const items = getElementByClassName<HTMLDivElement>(
313+
collection,
314+
ComponentClassName.CollectionItems
315+
);
316+
317+
expect(
318+
items?.style.getPropertyValue(
319+
kebabCase(ComponentPropsToStylePropsMap.border)
320+
)
321+
).toBe(borderStyle);
322+
323+
const tdNode = items?.children[1].children[0].children[0];
324+
expect(tdNode?.nodeName).toBe('TD');
325+
expect(tdNode?.innerHTML).toBe('LOL');
326+
});
285327
});

packages/react/src/primitives/types/collection.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,14 @@ export type ListCollectionProps<Item> = Omit<BaseFlexProps, 'children'> &
8181
CollectionBaseProps<Item>;
8282
export type GridCollectionProps<Item> = Omit<BaseGridProps, 'children'> &
8383
CollectionBaseProps<Item>;
84+
export type TableCollectionProps<Item> = Omit<BaseGridProps, 'children'> &
85+
CollectionBaseProps<Item> & {
86+
/**
87+
* @description
88+
* Custom table header component to be rendered at the top of the table
89+
*/
90+
tableHeader: () => React.ReactNode;
91+
};
8492

8593
/**
8694
* Omits `React.ReactNode` as children to prevent intersection type for `children` of
@@ -98,6 +106,7 @@ export type BaseCollectionProps<
98106
(
99107
| ReplaceChildren<{ type: 'list' } & ListCollectionProps<Item>, Item>
100108
| ReplaceChildren<{ type: 'grid' } & GridCollectionProps<Item>, Item>
109+
| ReplaceChildren<{ type: 'table' } & TableCollectionProps<Item>, Item>
101110
);
102111

103112
export type CollectionProps<

0 commit comments

Comments
 (0)