/** * @fileoverview DataTable — typed, dependency-free data grid built on the * Saasflare Table primitives. Consumers pass `data: T[]` + typed `columns` and * get client-side multi-column sort, row selection (controlled/uncontrolled), * client-side pagination (via {@link usePagination}), sticky header, density, * and empty/loading states out of the box — zero TanStack, zero wiring. * @module packages/ui/components/ui/data-table * @layer composed * * Server-side / TanStack: pass `manualSort` + `manualPagination` and drive * state from `onSortChange` / `onPageChange`. The component stays * dependency-free; `@tanstack/react-table` is NEVER a dependency of `@saasflare/ui`. * * @component * @example * import { DataTable } from "@saasflare/ui"; * */ import * as React from "react"; import { type SaasflareComponentProps } from "../../providers"; import { type DataTableColumn, type DataTableSort, type DataTableAlign, type DataTableDensity, type DataTableSelectionMode } from "../../hooks/use-data-table"; export type { DataTableColumn, DataTableSort, DataTableAlign, DataTableDensity }; /** * Props for {@link DataTable}, generic over the row type `T`. * * Sorting, selection, and pagination each work controlled or uncontrolled; * pass `manualSort` / `manualPagination` to hand ordering and slicing over to * a server or TanStack layer while keeping the rendering here. */ interface DataTableProps extends Omit, "children" | keyof SaasflareComponentProps>, SaasflareComponentProps { /** Row data. */ data: T[]; /** Typed column definitions. */ columns: DataTableColumn[]; /** Stable row key. String key of `T` or a function. Falls back to row index (logs a dev warning, since index keys break selection across sort/paginate). */ getRowId?: keyof T | ((row: T, index: number) => string); /** Uncontrolled initial sort. */ defaultSort?: DataTableSort[]; /** Controlled sort state. Presence switches sorting to controlled. */ sort?: DataTableSort[]; /** Fires on header activation with the next sort array. */ onSortChange?: (sort: DataTableSort[]) => void; /** Allow stacking multiple sort columns (shift-click adds a column). Default `false` (single-column). */ multiSort?: boolean; /** Skip internal sorting (server/TanStack drives order). Header still emits `onSortChange`. Default `false`. */ manualSort?: boolean; /** `"none"` (default) | `"single"` | `"multiple"`. Renders a leading checkbox column when not `"none"`. */ selectionMode?: DataTableSelectionMode; /** Uncontrolled initial selected row-id set. */ defaultSelectedKeys?: string[]; /** Controlled selected row-id set. */ selectedKeys?: string[]; /** Fires with the next selected row-id array. */ onSelectedKeysChange?: (keys: string[]) => void; /** Predicate to disable selection for specific rows (their checkbox is disabled + excluded from select-all). */ isRowSelectable?: (row: T) => boolean; /** Rows per page. Omit / `0` disables pagination (renders all rows, no footer). */ pageSize?: number; /** Uncontrolled initial page (1-indexed). Default `1`. */ defaultPage?: number; /** Controlled page (1-indexed). */ page?: number; /** Fires on page change. */ onPageChange?: (page: number) => void; /** Skip internal pagination/slicing (server drives the window). `data` is treated as the current page; pass `rowCount` for the footer. Default `false`. */ manualPagination?: boolean; /** Total row count when `manualPagination` — drives the page-count math in the footer. */ rowCount?: number; /** Loading flag — renders `loadingRows` skeleton rows; disables sort/select while true. */ loading?: boolean; /** Skeleton row count while `loading`. Default = `pageSize || 5`. */ loadingRows?: number; /** Rendered in a full-width body row when `data` is empty and not loading. Defaults to a built-in message. */ emptyState?: React.ReactNode; /** Pin the header on vertical scroll within a `maxHeight` container. Default `false`. */ stickyHeader?: boolean; /** Max body height (enables internal scroll; required for `stickyHeader` to be useful). e.g. `"24rem"`. */ maxHeight?: number | string; /** Density preset. Default `"comfortable"`. */ density?: DataTableDensity; /** Optional row click handler. Receives row + index. Adds `cursor-pointer` + keyboard activation when set. */ onRowClick?: (row: T, index: number) => void; /** Accessible caption (visually hidden by default) describing the table. */ caption?: React.ReactNode; /** Hide the built-in pagination footer even when paginated (consumer renders own Pagination). Default `false`. */ hidePagination?: boolean; } /** * Dependency-free, typed, sortable + selectable + paginated data table built on * the Saasflare Table primitives. Resolves the four design axes * (surface/radius/animated/iconWeight) and emits data-surface/data-radius/data-animated. * * Selection note: the header "select all" checkbox operates on the * **current page** only (it toggles the visible page's selectable rows; * off-page selections are preserved). * * @component * @layer composed * * @example * */ declare function DataTable(props: DataTableProps): React.JSX.Element; export { DataTable, type DataTableProps };