diff --git a/.changeset/unlucky-otters-dress.md b/.changeset/unlucky-otters-dress.md new file mode 100644 index 00000000000..6945ff68c0a --- /dev/null +++ b/.changeset/unlucky-otters-dress.md @@ -0,0 +1,5 @@ +--- +"@aws-amplify/ui-react": minor +--- + +feat(collection): Add `table` type to `Collection` UI primitive diff --git a/packages/react/src/primitives/Collection/Collection.tsx b/packages/react/src/primitives/Collection/Collection.tsx index c77c2177908..321ea3d49d5 100644 --- a/packages/react/src/primitives/Collection/Collection.tsx +++ b/packages/react/src/primitives/Collection/Collection.tsx @@ -16,8 +16,10 @@ import type { ElementType, GridCollectionProps, ListCollectionProps, + TableCollectionProps, } from '../types'; import { getItemsAtPage, itemHasText, getPageCount } from './utils'; +import { Table, TableBody } from '../Table'; const DEFAULT_PAGE_SIZE = 10; const TYPEAHEAD_DELAY_MS = 300; @@ -41,6 +43,18 @@ const GridCollection = ({ {Array.isArray(items) ? items.map(children) : null} ); +const TableCollection = ({ + children, + items, + tableHeader: TableHeader, + ...rest +}: TableCollectionProps) => ( + + + {Array.isArray(items) ? items.map(children) : null} +
+); + const renderCollectionOrNoResultsFound = ( collection: React.JSX.Element | null, items: Item[], @@ -114,6 +128,13 @@ export const Collection = ({ items={items} {...rest} /> + ) : type === 'table' ? ( + >).tableHeader!} + {...rest} + /> ) : null; return ( diff --git a/packages/react/src/primitives/Collection/__tests__/Collection.test.tsx b/packages/react/src/primitives/Collection/__tests__/Collection.test.tsx index a7eaa2fa630..c5ba19d7f89 100644 --- a/packages/react/src/primitives/Collection/__tests__/Collection.test.tsx +++ b/packages/react/src/primitives/Collection/__tests__/Collection.test.tsx @@ -10,6 +10,7 @@ import { Flex } from '../../Flex'; import { Text } from '../../Text'; import { ComponentText } from '../../shared/constants'; import { ComponentPropsToStylePropsMap } from '../../types'; +import { TableCell, TableHead, TableRow } from '../../Table'; const emojis = [ { @@ -282,4 +283,45 @@ describe('Collection component', () => { const noResults = await screen.findByText(customText); expect(noResults).toBeDefined(); }); + + it('should render table with table header when type is table', async () => { + const borderStyle = '1px solid red'; + render( + ( + + Title + Emoji + + )} + > + {(item, _index) => ( + + {item.title} + {item.emoji} + + )} + + ); + + const collection = await screen.findByTestId(testList); + const items = getElementByClassName( + collection, + ComponentClassName.CollectionItems + ); + + expect( + items?.style.getPropertyValue( + kebabCase(ComponentPropsToStylePropsMap.border) + ) + ).toBe(borderStyle); + + const tdNode = items?.children[1].children[0].children[0]; + expect(tdNode?.nodeName).toBe('TD'); + expect(tdNode?.innerHTML).toBe('LOL'); + }); }); diff --git a/packages/react/src/primitives/types/collection.ts b/packages/react/src/primitives/types/collection.ts index e22f4704822..e5a18879283 100644 --- a/packages/react/src/primitives/types/collection.ts +++ b/packages/react/src/primitives/types/collection.ts @@ -81,6 +81,14 @@ export type ListCollectionProps = Omit & CollectionBaseProps; export type GridCollectionProps = Omit & CollectionBaseProps; +export type TableCollectionProps = Omit & + CollectionBaseProps & { + /** + * @description + * Custom table header component to be rendered at the top of the table + */ + tableHeader: () => React.ReactNode; + }; /** * Omits `React.ReactNode` as children to prevent intersection type for `children` of @@ -98,6 +106,7 @@ export type BaseCollectionProps< ( | ReplaceChildren<{ type: 'list' } & ListCollectionProps, Item> | ReplaceChildren<{ type: 'grid' } & GridCollectionProps, Item> + | ReplaceChildren<{ type: 'table' } & TableCollectionProps, Item> ); export type CollectionProps<