diff --git a/packages/utah-design-system/src/components/Table.stories.tsx b/packages/utah-design-system/src/components/Table.stories.tsx new file mode 100644 index 00000000..b84db015 --- /dev/null +++ b/packages/utah-design-system/src/components/Table.stories.tsx @@ -0,0 +1,82 @@ +import type { Meta } from '@storybook/react'; +import { useMemo, useState } from 'react'; +import { TableBody } from 'react-aria-components'; +import { Cell, Column, Row, Table, TableHeader } from './Table'; + +const meta: Meta = { + component: Table, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +}; + +export default meta; + +let rows = [ + { id: 1, name: 'Games', date: '6/7/2020', type: 'File folder' }, + { id: 2, name: 'Program Files', date: '4/7/2021', type: 'File folder' }, + { id: 3, name: 'bootmgr', date: '11/20/2010', type: 'System file' }, + { id: 4, name: 'log.txt', date: '1/18/2016', type: 'Text Document' }, + { id: 5, name: 'Proposal.ppt', date: '6/18/2022', type: 'PowerPoint file' }, + { id: 6, name: 'Taxes.pdf', date: '12/6/2023', type: 'PDF Document' }, + { id: 7, name: 'Photos', date: '8/2/2021', type: 'File folder' }, + { id: 8, name: 'Documents', date: '3/18/2023', type: 'File folder' }, + { id: 9, name: 'Budget.xls', date: '1/6/2024', type: 'Excel file' }, +]; + +export const Example = (args: any) => { + let [sortDescriptor, setSortDescriptor] = useState({ + column: 'name', + direction: 'ascending', + }); + + let items = useMemo(() => { + // @ts-ignore + let items = rows + .slice() + .sort((a, b) => + a[sortDescriptor.column].localeCompare(b[sortDescriptor.column]), + ); + if (sortDescriptor.direction === 'descending') { + items.reverse(); + } + return items; + }, [sortDescriptor]); + + return ( + + + + Name + + + Type + + + Date Modified + + + + {(row) => ( + + {row.name} + {row.type} + {row.date} + + )} + +
+ ); +}; + +Example.args = { + onRowAction: null, + onCellAction: null, + selectionMode: 'none', +}; diff --git a/packages/utah-design-system/src/components/Table.tsx b/packages/utah-design-system/src/components/Table.tsx new file mode 100644 index 00000000..f39f3489 --- /dev/null +++ b/packages/utah-design-system/src/components/Table.tsx @@ -0,0 +1,145 @@ +import { ArrowUp } from 'lucide-react'; +import { + Cell as AriaCell, + Column as AriaColumn, + Row as AriaRow, + Table as AriaTable, + TableHeader as AriaTableHeader, + Button, + CellProps, + Collection, + ColumnProps, + ColumnResizer, + Group, + ResizableTableContainer, + RowProps, + TableHeaderProps, + TableProps, + composeRenderProps, + useTableOptions, +} from 'react-aria-components'; +import { tv } from 'tailwind-variants'; +import { Checkbox } from './Checkbox'; +import { composeTailwindRenderProps, focusRing } from './utils'; + +export function Table(props: TableProps) { + return ( + + + + ); +} + +const columnStyles = tv({ + extend: focusRing, + base: 'flex h-5 flex-1 items-center gap-1 overflow-hidden px-2', +}); + +const resizerStyles = tv({ + extend: focusRing, + base: 'box-content h-5 w-px translate-x-[8px] cursor-col-resize rounded bg-gray-400 bg-clip-content px-[8px] py-1 -outline-offset-2 resizing:w-[2px] resizing:bg-blue-600 resizing:pl-[7px] dark:bg-zinc-500 forced-colors:bg-[ButtonBorder] forced-colors:resizing:bg-[Highlight]', +}); + +export function Column(props: ColumnProps) { + return ( + + {composeRenderProps( + props.children, + (children, { allowsSorting, sortDirection }) => ( +
+ + {children} + {allowsSorting && ( + + {sortDirection && ( + + )} + + )} + + {!props.width && } +
+ ), + )} +
+ ); +} + +export function TableHeader(props: TableHeaderProps) { + let { selectionBehavior, selectionMode, allowsDragging } = useTableOptions(); + + return ( + + {/* Add extra columns for drag and drop and selection. */} + {allowsDragging && } + {selectionBehavior === 'toggle' && ( + + {selectionMode === 'multiple' && } + + )} + {props.children} + + ); +} + +const rowStyles = tv({ + extend: focusRing, + base: 'group/row relative cursor-default select-none text-sm text-zinc-700 -outline-offset-2 hover:bg-slate-200 selected:bg-secondary-600 selected:text-white selected:hover:bg-secondary-500 disabled:text-gray-300 dark:text-zinc-300 dark:hover:bg-zinc-700 dark:disabled:text-zinc-600', +}); + +export function Row({ + id, + columns, + children, + ...otherProps +}: RowProps) { + let { selectionBehavior, allowsDragging } = useTableOptions(); + + return ( + + {allowsDragging && ( + + + + )} + {selectionBehavior === 'toggle' && ( + + + + )} + {children} + + ); +} + +const cellStyles = tv({ + extend: focusRing, + base: 'truncate border-b p-2 -outline-offset-2 [--selected-border:theme(colors.secondary.800)] group-last/row:border-b-0 group-selected/row:border-[--selected-border] dark:border-b-zinc-700 dark:[--selected-border:theme(colors.secondary.500)] [:has(+[data-selected])_&]:border-[--selected-border]', +}); + +export function Cell(props: CellProps) { + return ; +} diff --git a/packages/utah-design-system/src/index.js b/packages/utah-design-system/src/index.js index 8c24ead1..7eadbc34 100644 --- a/packages/utah-design-system/src/index.js +++ b/packages/utah-design-system/src/index.js @@ -20,6 +20,7 @@ export * from './components/Select.tsx'; export * from './components/Sherlock.jsx'; export * from './components/SocialMedia.jsx'; export * from './components/Spinner.jsx'; +export * from './components/Table.tsx'; export * from './components/TagGroup.tsx'; export * from './components/TextField.tsx'; export * from './components/UtahIdLogin.tsx';