Skip to content

Commit

Permalink
feat: add pagination prop to data-table (#16)
Browse files Browse the repository at this point in the history
  • Loading branch information
bouassaba authored Nov 10, 2024
1 parent 369cf4a commit 0d27cb8
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 121 deletions.
5 changes: 1 addition & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@koupr/ui",
"version": "1.10.8",
"version": "1.10.9",
"license": "MIT",
"type": "module",
"source": "src/index.ts",
Expand All @@ -11,9 +11,6 @@
"type": "git",
"url": "https://github.com/kouprlabs/koupr-ui.git"
},
"engines": {
"node": ">=20.x"
},
"scripts": {
"build": "rollup -c && node ./scripts/cleanup.js",
"tsc": "tsc",
Expand Down
136 changes: 74 additions & 62 deletions src/components/data-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface DataTableProps<T> {
items: T[]
columns: DataTableColumn<T>[]
actions?: DataTableAction<T>[]
pagination?: ReactElement
}

export interface DataTableColumn<T> {
Expand All @@ -39,70 +40,81 @@ export interface DataTableAction<T> {
onClick?: (item: T) => void
}

export function DataTable<T>({ items, columns, actions }: DataTableProps<T>) {
export function DataTable<T>({
items,
columns,
actions,
pagination,
}: DataTableProps<T>) {
return (
<Table variant="simple">
<Thead>
<Tr>
{columns.map((column, columnIndex) => (
<Th key={columnIndex}>{column.title}</Th>
))}
{actions ? <Th></Th> : null}
</Tr>
</Thead>
<Tbody>
{items.map((item, itemIndex) => (
<Tr key={`row-${itemIndex}`}>
{columns.map((column, colIndex) => (
<Td key={`row-${itemIndex}-col-${colIndex}`}>
{column.renderCell(item)}
</Td>
<div className={cx('flex', 'flex-col', 'gap-3.5')}>
<Table variant="simple">
<Thead>
<Tr>
{columns.map((column, columnIndex) => (
<Th key={columnIndex}>{column.title}</Th>
))}
{actions ? (
<Td className={cx('koupr-text-right')}>
<Menu>
<MenuButton
as={IconButton}
icon={<IconMoreVert />}
variant="ghost"
title="Action menu"
aria-label="Action menu"
/>
<Portal>
<MenuList>
{actions
?.filter(
(action) =>
!!(!action.isHidden && !action.isHiddenFn?.(item)),
)
.map((action, actionIndex) => (
<MenuItem
key={`row-${itemIndex}-action-${actionIndex}`}
icon={action.icon}
className={cx({
'koupr-text-red-500': !!(
action.isDestructive ||
action.isDestructiveFn?.(item)
),
})}
isDisabled={
!!(
action.isDisabled || action.isDisabledFn?.(item)
)
}
onClick={() => action.onClick?.(item)}
>
{action.label}
</MenuItem>
))}
</MenuList>
</Portal>
</Menu>
</Td>
) : null}
{actions ? <Th></Th> : null}
</Tr>
))}
</Tbody>
</Table>
</Thead>
<Tbody>
{items.map((item, itemIndex) => (
<Tr key={`row-${itemIndex}`}>
{columns.map((column, colIndex) => (
<Td key={`row-${itemIndex}-col-${colIndex}`}>
{column.renderCell(item)}
</Td>
))}
{actions ? (
<Td className={cx('koupr-text-right')}>
<Menu>
<MenuButton
as={IconButton}
icon={<IconMoreVert />}
variant="ghost"
title="Action menu"
aria-label="Action menu"
/>
<Portal>
<MenuList>
{actions
?.filter(
(action) =>
!!(
!action.isHidden && !action.isHiddenFn?.(item)
),
)
.map((action, actionIndex) => (
<MenuItem
key={`row-${itemIndex}-action-${actionIndex}`}
icon={action.icon}
className={cx({
'koupr-text-red-500': !!(
action.isDestructive ||
action.isDestructiveFn?.(item)
),
})}
isDisabled={
!!(
action.isDisabled ||
action.isDisabledFn?.(item)
)
}
onClick={() => action.onClick?.(item)}
>
{action.label}
</MenuItem>
))}
</MenuList>
</Portal>
</Menu>
</Td>
) : null}
</Tr>
))}
</Tbody>
</Table>
{pagination ? <div className={cx('self-end')}>{pagination}</div> : null}
</div>
)
}
106 changes: 51 additions & 55 deletions src/stories/common/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,59 +20,55 @@ export const List = () => {
})

return (
<div className={cx('flex', 'flex-col', 'gap-3.5')}>
<DataTable
items={items}
columns={[
{
title: 'Name',
renderCell: (item) => (
<div
className={cx('flex', 'flex-row', 'gap-1.5', 'items-center')}
>
<Avatar
name={item.name}
size="sm"
className={cx('w-[40px]', 'h-[40px]')}
/>
<Link className={cx('no-underline')}>{item.name}</Link>
</div>
),
},
{
title: 'Symbol',
renderCell: (item) => <span>{item.symbol}</span>,
},
{
title: 'Date of Birth',
renderCell: (item) => (
<span>{new Date(item.dateOfBirth).toLocaleString()}</span>
),
},
]}
actions={[
{
label: 'Mark As Favorite',
icon: <IconFavorite />,
onClick: (item) => console.log(`Marking ${item.name} as favorite!`),
},
{
label: 'Start Conversation',
icon: <IconChat />,
isDisabled: true,
onClick: (item) =>
console.log(`Starting a conversation with ${item.name}.`),
},
{
label: 'Remove From Organization',
icon: <IconLogout />,
isDestructive: true,
onClick: (item) =>
console.log(`Removing ${item.name} from organization...`),
},
]}
/>
<div className={cx('self-end')}>
<DataTable
items={items}
columns={[
{
title: 'Name',
renderCell: (item) => (
<div className={cx('flex', 'flex-row', 'gap-1.5', 'items-center')}>
<Avatar
name={item.name}
size="sm"
className={cx('w-[40px]', 'h-[40px]')}
/>
<Link className={cx('no-underline')}>{item.name}</Link>
</div>
),
},
{
title: 'Symbol',
renderCell: (item) => <span>{item.symbol}</span>,
},
{
title: 'Date of Birth',
renderCell: (item) => (
<span>{new Date(item.dateOfBirth).toLocaleString()}</span>
),
},
]}
actions={[
{
label: 'Mark As Favorite',
icon: <IconFavorite />,
onClick: (item) => console.log(`Marking ${item.name} as favorite!`),
},
{
label: 'Start Conversation',
icon: <IconChat />,
isDisabled: true,
onClick: (item) =>
console.log(`Starting a conversation with ${item.name}.`),
},
{
label: 'Remove From Organization',
icon: <IconLogout />,
isDestructive: true,
onClick: (item) =>
console.log(`Removing ${item.name} from organization...`),
},
]}
pagination={
<PagePagination
totalElements={100}
totalPages={25}
Expand All @@ -82,7 +78,7 @@ export const List = () => {
setPage={setPage}
setSize={setSize}
/>
</div>
</div>
}
/>
)
}

0 comments on commit 0d27cb8

Please sign in to comment.