UNPKG

compote-ui

Version:

An opinionated UI component library for Svelte, built on top of [Ark UI](https://ark-ui.com) with additional components and features not available in the core Ark UI library.

176 lines (141 loc) • 6.87 kB
# Column Options Column helper: ```ts const col = DataTable.createDataTableColumnHelper<Row>(); ``` Accessors: ```ts col.accessor('fieldName', { header: 'Field' }); col.accessorFn((row) => row.a + row.b, { id: 'sum', header: 'Sum' }); col.group('Group', [col.accessor('name', { header: 'Name' })]); col.columns([col.accessor('id', { header: 'ID' })]); ``` Common options: - `header: string` - `type?: 'text' | 'number' | 'currency' | 'percent' | 'boolean' | 'select' | 'url' | 'phone' | 'date' | 'time' | 'date-time' | 'action'` - `align?: 'left' | 'center' | 'right'` - `size?: number` - `minSize?: number` - `maxSize?: number` - `enableResizing?: boolean` - `enableHiding?: boolean` - `enableSorting?: boolean` - `enableColumnFilter?: boolean` - `filterFn?: FilterFn | string` - `formatOptions?: Intl.NumberFormatOptions | Intl.DateTimeFormatOptions` - `formatLocale?: string` - `cell?: (value, row) => string | number | boolean | null | undefined` - `cellComponent?: Component` - `cellProps?: (value, row) => Record<string, unknown>` - `cellSnippet?: Snippet` - `pinned?: 'left' | 'right'` — sticky during horizontal scroll. Inside a `col.group(...)`, pinning a member column also pins the group header fragment above it, so the label stays visible while the rest of that group scrolls. - `grow?: boolean` - `sum?: boolean` - `footer?: (values: unknown[]) => string | number | undefined` Type defaults: - `number`, `currency`: right aligned, size `120` - `percent`: right aligned, size `100` - `date`: center aligned, size `110` - `time`: center aligned, size `80` - `date-time`: center aligned, size `160` - `boolean`: center aligned, size `90` - `url`: center aligned, sorting disabled, size `60` - `phone`: left aligned, size `160` - `action`: center aligned, size `60`, sorting/hiding/column-filter all disabled — layout-only, carries no value to format or filter. Supply a `cellComponent`/`cellSnippet` for the row action buttons; the defaults keep the actions column out of the column-visibility menu and filter toolbar automatically. Use one `grow: true` column to absorb extra horizontal space. ## Date columns: display and filter `date`, `time` and `date-time` cells are read the same way for display and for the date filter, in the column's display zone — `formatOptions.timeZone` when set, otherwise the viewer's local zone: - `'2024-03-15'` (and a `CalendarDate`) is a calendar day. It always shows and filters as 15 March, also in zones west of UTC — it is never turned into a midnight-UTC instant. - `Date`, epoch milliseconds, strings with an offset (`Z`, `+02:00`, DB `+02`) and `ZonedDateTime` are instants, shown and filtered on the day they fall on in the display zone. - A datetime without an offset (`'2024-03-15T10:30'`) is wall-clock time in the display zone. - Unreadable values (e.g. `'2024-02-30'`) render as `-` and never match an active filter. `date` and `date-time` columns filter by calendar-day range. The filter value is `[from?, to?]`, each `YYYY-MM-DD` or empty (open-ended); both days are inclusive, a reversed range is swapped, and an empty range removes the filter. Instants are judged by their calendar day, so 23- and 25-hour DST days need no special handling. `time` columns keep the text filter. ```ts table.getColumn('createdAt')?.setFilterValue(['2024-03-01', '2024-03-31']); // March table.getColumn('createdAt')?.setFilterValue([undefined, '2024-03-31']); // up to 31 March ``` ## Select columns with multiple values A `type: 'select'` column may return an array (tags, multi-select attributes). The Funnel then lists each item as its own option with a row count, a row matches when any of its items is selected, and the cell renders the items joined with `, `. A row counts once per option even when its array repeats an item. Missing values — `null`, `undefined`, `''` or an empty array — share one `(empty)` option. The filter value is an array of selected options: each is the `String()` of the cell value, and the empty option is `null` — so a real `'null'` string stays its own option: ```ts table.getColumn('tags')?.setFilterValue(['Battery', null]); // Battery or no tags ``` ```ts col.accessorFn((row) => row.tags.map((tag) => tag.name), { id: 'tags', header: 'Tags', type: 'select' }); ``` ## Locale for number/currency/percent Priority: `formatLocale` prop → `useLocaleContext().locale` → browser default. Wrap the app in `<LocaleProvider locale="sr-RS">` to set the context locale for every formatted column. ## Custom cellComponent ```svelte <!-- PriceCell.svelte --> <script lang="ts"> let { value, prices }: { value: number; prices: { vendor: string; price: number }[] } = $props(); </script> <span>{value}</span> ``` ```ts col.accessorFn((row) => Math.min(...row.prices.map((p) => p.price)), { id: 'minPrice', header: 'Best Price', type: 'currency', align: 'right', cellComponent: PriceCell, cellProps: (value, row) => ({ value, prices: row.prices }) }); ``` ## Row height and cell alignment Body cells are fixed at `h-9` (36px), matching the header, with content vertically centered — any control up to 36px tall (every `Button` `icon-xs`/`icon-sm`/`icon`/`icon-lg` size) fits without changing row height. Do **not** add negative margins (e.g. `-my-1`) to cell components to compensate for row growth — in the virtualized table that fights the virtualizer's 37px row estimate. Cells are `truncate` (single-line, `overflow: hidden`), so give action columns a little extra `size` if a focus ring on a control near the edge gets clipped. ## DataTable.Search Global filter input searching across all text columns, debounced (default 300ms). - `table: DataTableInstance<T>` — required - `placeholder?: string` (default `'Search...'`) - `class?: ClassValue` - `debounceMs?: number` (default `300`) Text/number columns stay searchable even when the first row's value is `null`/`undefined`; booleans and object-valued columns are excluded from global search. Also available as `VirtualDataTable.Search` for the virtualized variant. ## DataTable.Root props `table: DataTableInstance<T>` (required), `caption?: string` (sr-only `<caption>`), `emptyMessage?: string` (default `'No rows found'`), `class?: ClassValue`, `headerFilters?: boolean` (default `false`; funnel filter popups in column headers — see "Filter from column headers" in SKILL.md), `onRowClick?: (details: { row: T; event: MouseEvent }) => void`, `onRowDoubleClick?: (details: { row: T; event: MouseEvent }) => void` — `row` is `row.original`. Clicks on the row-selection checkbox and url-cell buttons do **not** trigger either handler. `VirtualDataTable.Root` shares the same props. ```svelte <DataTable.Root {table} onRowDoubleClick={({ row, event }) => { if (event.ctrlKey || event.metaKey) openInNewTab(row.id); else navigateTo(row.id); }} /> ```