@datakable/react 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -4
- package/dist/codes.cjs +0 -1
- package/dist/codes.cjs.map +1 -1
- package/dist/codes.js +0 -2
- package/dist/codes.js.map +1 -1
- package/dist/data-table.cjs +192 -83
- package/dist/data-table.cjs.map +1 -1
- package/dist/data-table.js +194 -83
- package/dist/data-table.js.map +1 -1
- package/dist/index.cjs +0 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -3
- package/dist/index.d.ts +10 -3
- package/dist/index.js +0 -2
- package/dist/index.js.map +1 -1
- package/dist/render-codes.cjs +6 -5
- package/dist/render-codes.cjs.map +1 -1
- package/dist/render-codes.js +6 -6
- package/dist/render-codes.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/styles.css.d.cts +2 -0
- package/dist/styles.css.d.ts +2 -0
- package/dist/use-data-table.cjs +26 -25
- package/dist/use-data-table.cjs.map +1 -1
- package/dist/use-data-table.js +26 -24
- package/dist/use-data-table.js.map +1 -1
- package/package.json +21 -5
package/dist/data-table.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/data-table.tsx"],"sourcesContent":["import {\n type AnyFeature,\n boundaryDiagnostics,\n defaultFormat,\n deriveColumns,\n describeReturn,\n emitTableDiagnostic,\n type InvalidRowsMode,\n keepDiagnostics,\n matchesSlot,\n type RowIssue,\n type RowModelStatus,\n type SearchStatus,\n slotDiagnostics,\n type TableSchema,\n type TableState,\n} from '@datakable/core'\nimport {\n Component,\n type ComponentType,\n type ReactNode,\n useEffect,\n useLayoutEffect,\n useMemo,\n} from 'react'\nimport {\n cellSlot,\n invalidCellSlot,\n registerRenderOperations,\n renderDiagnostics,\n} from './render-codes'\nimport { type UseDataTableOptions, useDataTable } from './use-data-table'\n\n// The codes this module emits (bundlers keep the definitions; see core's `keepDiagnostics`).\nkeepDiagnostics(renderDiagnostics, boundaryDiagnostics, slotDiagnostics)\n\n// The ops its boundaries stand for (§3.4: `render:table`, `render:cell`). Registered at import:\n// the dist is one file per module (T37), so hook-only bundles (`useDataTable` without\n// `<DataTable />`) never include this module, and this call ships only with `<DataTable />`.\nregisterRenderOperations()\n\n// No @types/node here: declare just what is read.\ndeclare const process: { env: { NODE_ENV?: string } }\n\n/** No layout effects on the server (React 18 warns about them there). */\nconst useIsomorphicLayoutEffect = typeof window === 'undefined' ? useEffect : useLayoutEffect\n\n// --- public types --------------------------------------------------------------------------------\n\n/** Props of `components.SearchInput`: the search feature's `input`, bound both ways. */\nexport interface SearchInputProps {\n /** `state.search.input` (updates as the user types). */\n value: string\n /** `state.search.status`: `pending` while a debounce waits, `searching` while a request runs. */\n status: SearchStatus\n /** `setSearch(value)`. */\n onChange(value: string): void\n /** `flushSearch()` (Enter). */\n onSubmit(): void\n /** `clearSearch()` (Esc). */\n onClear(): void\n}\n\n/** Props of `components.Pagination` (the pagination feature's state and API). */\nexport interface PaginationProps {\n pageIndex: number\n pageSize: number\n pageCount: number\n canPrev: boolean\n canNext: boolean\n prev(): void\n next(): void\n setPageIndex(index: number): void\n setPageSize(size: number): void\n}\n\n/** Props of `components.Empty`: shown when the table has loaded and has no rows to show. */\nexport interface EmptyProps {\n /** `true` when there is data but filters / search removed every row. */\n filtered: boolean\n}\n\n/** Props of `components.Loading`: the first load (`isInitialLoad`, nothing to show yet). */\nexport interface LoadingProps {\n status: RowModelStatus\n}\n\n/** Props of `components.Error`: the first load failed, or the body failed to render. */\nexport interface ErrorProps {\n status: RowModelStatus\n /**\n * `'load'`: `status === 'error'` on the first load. `'render'`: a component in the body outside\n * the cells threw (a component inside a cell renders `⚠` in that cell only).\n */\n reason: 'load' | 'render'\n /** `'load'`: `refetch()`. `'render'`: renders the body again. */\n retry(): void\n}\n\n/** `<DataTable components={...} />`: replaces the default parts (unstyled, `data-*` hooks only). */\nexport interface DataTableComponents {\n SearchInput?: ComponentType<SearchInputProps>\n Pagination?: ComponentType<PaginationProps>\n Empty?: ComponentType<EmptyProps>\n Loading?: ComponentType<LoadingProps>\n Error?: ComponentType<ErrorProps>\n}\n\n/** What `<DataTable table={...} />` reads: the value `useDataTable` returns. */\nexport interface DataTableSource {\n readonly state: TableState\n readonly rowModel: {\n readonly rows: readonly DataTableRow[]\n readonly filteredCount: number\n readonly totalCount: number\n readonly status: RowModelStatus\n readonly isInitialLoad: boolean\n }\n getOptions(): { readonly columns?: readonly unknown[] | undefined }\n getData(): readonly unknown[]\n refetch(): Promise<unknown>\n}\n\n/** The part of a `Row` (§6.6) `<DataTable />` renders from. */\ninterface DataTableRow {\n readonly key: string | number\n readonly index: number\n readonly original: unknown\n readonly valid: boolean\n readonly issues: readonly RowIssue[]\n getValue(id: string): unknown\n getCellIssues(id: string): readonly RowIssue[]\n}\n\n/** `<DataTable />`'s own props, next to `table` or the `useDataTable` options. */\nexport interface DataTableOwnProps {\n components?: DataTableComponents | undefined\n caption?: ReactNode\n}\n\n/**\n * `<DataTable table={useDataTable(...)} />`, or `<DataTable data={rows} />` with the\n * `useDataTable` options as props (zero-config: columns derived from the data).\n */\nexport type DataTableProps<\n T = unknown,\n Sch = undefined,\n M extends InvalidRowsMode = InvalidRowsMode,\n> = DataTableOwnProps &\n (\n | { table: DataTableSource }\n | (UseDataTableOptions<T, TableState, Sch, M> & {\n features?: readonly AnyFeature[]\n table?: undefined\n })\n )\n\n// --- component -----------------------------------------------------------------------------------\n\n/**\n * The zero-config table (§10). Renders what the installed features provide: sort buttons with\n * `aria-sort`, a search input bound to `input` (Enter = `flushSearch`, Esc = `clearSearch`),\n * pagination, and the Loading / Error / Empty states from `status` + `isInitialLoad` (§6.6).\n * Unstyled: style it through the `data-*` hooks (`data-status`, `data-initial-load`,\n * `data-invalid`, `data-sort`, …) or replace parts with `components`.\n *\n * `@datakable/react`'s `DataTable` installs no features with `data`; `datakable`'s installs the\n * default preset.\n */\nexport function DataTable<\n T,\n const Sch extends TableSchema | undefined = undefined,\n const M extends InvalidRowsMode = 'drop',\n>(props: DataTableProps<T, Sch, M>): ReactNode\nexport function DataTable(\n props: DataTableOwnProps & { table?: DataTableSource | undefined },\n): ReactNode {\n if (props.table !== undefined) {\n return (\n <DataTableView table={props.table} components={props.components} caption={props.caption} />\n )\n }\n return <ZeroConfig {...(props as DataTableOwnProps & { table?: undefined })} />\n}\n\nfunction ZeroConfig(props: DataTableOwnProps & { table?: undefined }) {\n const { components, caption, table: _, ...options } = props\n const view = useDataTable(options as never) as unknown as DataTableSource\n return <DataTableView table={view} components={components} caption={caption} />\n}\n\n/** Loose access to the installed features' APIs (the table is typed per feature set). */\ntype Api = DataTableSource & {\n toggleSort?(id: string, opts?: { multi?: boolean }): void\n getSortDirection?(id: string): 'asc' | 'desc' | false\n setSearch?(q: string): Promise<unknown>\n flushSearch?(): Promise<unknown>\n clearSearch?(): void\n setPageIndex?(i: number): void\n setPageSize?(n: number): void\n nextPage?(): void\n prevPage?(): void\n getPageCount?(): number\n canNextPage?(): boolean\n canPrevPage?(): boolean\n}\n\n/** The column fields `<DataTable />` reads (types are checked where the columns are written). */\ninterface ColumnLike {\n key?: unknown\n id?: unknown\n header?: unknown\n sortable?: unknown\n cell?: (ctx: { row: unknown; value: unknown }) => ReactNode\n format?: (value: unknown) => unknown\n invalidCell?: (ctx: {\n original: unknown\n value: unknown\n issues: readonly RowIssue[]\n }) => ReactNode\n}\n\ninterface Column {\n readonly def: ColumnLike\n readonly index: number\n readonly id: string\n readonly header: ReactNode\n}\n\n/** A cell callback that threw or broke its contract during this render (reported after commit). */\ninterface Failure {\n slot: string\n column: string\n row: number\n error?: unknown\n /** Bad return: what the contract expects and the type received. */\n expected?: string\n received?: string\n}\n\nconst WARN = '⚠'\nconst BUSY: readonly RowModelStatus[] = ['validating', 'pending', 'searching', 'fetching']\nconst LOADING: readonly RowModelStatus[] = ['validating', 'searching', 'fetching']\n\n/**\n * The table loads its rows asynchronously: a `fetcher`, or a feature with a `searchFn` (its\n * `defineOptions` values). With nothing applied yet, its `'pending'` is a load waiting to start\n * (deferred until the client, §7.2), so `<DataTable />` shows Loading — also in the server HTML.\n */\nfunction hasAsyncSource(table: DataTableSource): boolean {\n const options = table.getOptions() as { fetcher?: unknown; features?: unknown }\n if (typeof options.fetcher === 'function') return true\n if (!Array.isArray(options.features)) return false\n for (const f of options.features as readonly {\n options?: { values?: { searchFn?: unknown } }\n }[]) {\n if (typeof f?.options?.values?.searchFn === 'function') return true\n }\n return false\n}\n\nfunction resolveColumns(defs: readonly unknown[]): Column[] {\n const out: Column[] = []\n for (let index = 0; index < defs.length; index++) {\n const def = defs[index] as ColumnLike | null | undefined\n if (def === null || typeof def !== 'object') continue\n const id = typeof def.key === 'string' ? def.key : def.id\n if (typeof id !== 'string') continue\n out.push({ def, index, id, header: typeof def.header === 'string' ? def.header : id })\n }\n return out\n}\n\nconst segment = (s: PropertyKey | { readonly key: PropertyKey }) =>\n String(typeof s === 'object' ? s.key : s)\n\n/**\n * The redacted issue text for `title` (§5.1): the issue paths only. Schema messages embed the\n * received value, so they are never shown.\n */\nfunction issueTitle(issues: readonly RowIssue[]): string {\n const paths = new Set<string>()\n for (const i of issues) paths.add(i.path?.length ? i.path.map(segment).join('.') : '(row)')\n return `Invalid: ${[...paths].join(', ')}`\n}\n\n/** The table behind a `useDataTable` view (its prototype), for reporting diagnostics. */\nconst tableOf = (view: object): object =>\n Object.hasOwn(view, 'rowModel') ? (Object.getPrototypeOf(view) as object) : view\n\nfunction report(table: object, failures: readonly Failure[]) {\n const bySlot = new Map<string, Failure[]>()\n for (const f of failures) {\n const k = `${f.slot}\\0${f.expected === undefined ? 'throw' : 'return'}`\n const list = bySlot.get(k)\n if (list) list.push(f)\n else bySlot.set(k, [f])\n }\n for (const list of bySlot.values()) {\n const first = list[0] as Failure\n const rows = list.slice(0, 3).map((f) => f.row)\n const fallback = 'those cells rendered ⚠'\n try {\n if (first.expected === undefined) {\n const e = first.error\n emitTableDiagnostic(\n table,\n 'DK_CALLBACK_FAILED',\n {\n slot: first.slot,\n column: first.column,\n rows,\n count: list.length,\n fallback,\n ...(e instanceof Error ? { errorName: e.name } : {}),\n },\n { cause: e },\n )\n } else if (process.env.NODE_ENV !== 'production') {\n emitTableDiagnostic(table, 'DK_CALLBACK_BAD_RETURN', {\n slot: first.slot,\n column: first.column,\n expected: first.expected,\n received: first.received ?? 'undefined',\n count: list.length,\n rows,\n fallback,\n })\n }\n } catch {\n // Not a table made by createTable (a hand-made `table` prop): nothing to report to.\n }\n }\n}\n\n/**\n * Renders one cell's content; a throwing or contract-breaking callback renders `⚠`. An object\n * returned by `cell` / `invalidCell` (an element, an array) may hold components that throw while\n * React renders them, so it gets its own boundary; primitives cannot, so they get none (no cost).\n */\nfunction cellContent(\n col: Column,\n row: DataTableRow,\n failures: Failure[],\n table: object,\n): ReactNode {\n const def = col.def\n const value = row.getValue(col.id)\n const issues = row.valid ? undefined : row.getCellIssues(col.id)\n let slot = 'cell'\n try {\n if (issues !== undefined && issues.length > 0) {\n if (def.invalidCell) {\n slot = 'invalidCell'\n const out = def.invalidCell({ original: row.original, value, issues })\n if (matchesSlot(invalidCellSlot, out)) return guard(out, table, col, row, 'invalidCell')\n return bad(failures, col, row, slot, 'a value (not a Promise)', out)\n }\n return (\n <>\n {defaultFormat(value)}{' '}\n <span data-dk-invalid-marker=\"\" aria-hidden=\"true\">\n {WARN}\n </span>\n </>\n )\n }\n if (def.cell) {\n const out = def.cell({ row: row.original, value })\n if (matchesSlot(cellSlot, out)) return guard(out, table, col, row, 'cell')\n return bad(failures, col, row, slot, 'a value (not a Promise)', out)\n }\n if (def.format) {\n slot = 'format'\n const out = def.format(value)\n if (typeof out === 'string') return out\n bad(failures, col, row, slot, 'a string', out)\n return defaultFormat(value)\n }\n return defaultFormat(value)\n } catch (error) {\n failures.push({ slot: `columns[${col.index}].${slot}`, column: col.id, row: row.index, error })\n return WARN\n }\n}\n\n/** Wraps object content in a per-cell boundary (`render:cell`); primitives pass through as-is. */\nfunction guard(\n out: ReactNode,\n table: object,\n col: Column,\n row: DataTableRow,\n slot: 'cell' | 'invalidCell',\n): ReactNode {\n if (typeof out !== 'object' || out === null) return out\n return (\n <CellBoundary table={table} col={col} slot={slot} row={row.index} original={row.original}>\n {out}\n </CellBoundary>\n )\n}\n\nfunction bad(\n failures: Failure[],\n col: Column,\n row: DataTableRow,\n slot: string,\n expected: string,\n out: unknown,\n): ReactNode {\n failures.push({\n slot: `columns[${col.index}].${slot}`,\n column: col.id,\n row: row.index,\n expected,\n received: describeReturn(out),\n })\n return WARN\n}\n\nconst ariaSort = (dir: 'asc' | 'desc' | false) =>\n dir === 'asc' ? 'ascending' : dir === 'desc' ? 'descending' : 'none'\n\nfunction DataTableView(props: {\n table: DataTableSource\n components: DataTableComponents | undefined\n caption: ReactNode\n}) {\n const view = props.table as Api\n const parts = props.components ?? {}\n const { state, rowModel } = view\n const { rows, status, isInitialLoad } = rowModel\n const defs = view.getOptions().columns\n const data = view.getData()\n // Zero-config columns follow the data; given columns follow their reference (§10).\n const derivedFrom = defs === undefined ? data : undefined\n const columns = useMemo(\n () => resolveColumns(defs ?? (derivedFrom ? deriveColumns(derivedFrom) : [])),\n [defs, derivedFrom],\n )\n const failures: Failure[] = []\n const table = tableOf(view)\n // After commit, never during render: a sink may set state.\n useIsomorphicLayoutEffect(() => {\n if (failures.length > 0) report(table, failures)\n })\n\n const sortable = typeof view.toggleSort === 'function'\n const searchState = state.search as { input: string; status: SearchStatus } | undefined\n const paged = typeof view.getPageCount === 'function'\n // Loading (§6.6, §10): nothing to show yet and rows on their way — in flight, or deferred async\n // work that has not started (SSR, §7.2: 'pending').\n const loading =\n isInitialLoad && (LOADING.includes(status) || (status === 'pending' && hasAsyncSource(view)))\n const failed = isInitialLoad && status === 'error'\n const span = Math.max(columns.length, 1)\n const retryLoad = () => void view.refetch()\n\n const Search = parts.SearchInput ?? DefaultSearchInput\n const Pager = parts.Pagination ?? DefaultPagination\n const Empty = parts.Empty ?? DefaultEmpty\n const Loading = parts.Loading ?? DefaultLoading\n const ErrorState = parts.Error ?? DefaultError\n\n let body: ReactNode\n if (loading) {\n body = stateRow(span, 'loading', <Loading status={status} />)\n } else if (failed) {\n body = stateRow(span, 'error', <ErrorState status={status} reason=\"load\" retry={retryLoad} />)\n } else if (rows.length === 0) {\n body = stateRow(span, 'empty', <Empty filtered={rowModel.totalCount > 0} />)\n } else {\n body = rows.map((row) => {\n const valid = row.valid\n return (\n <tr\n key={row.key}\n data-invalid={valid ? undefined : 'true'}\n aria-invalid={valid ? undefined : 'true'}\n title={valid ? undefined : issueTitle(row.issues)}\n >\n {columns.map((col) => {\n const issues = valid ? undefined : row.getCellIssues(col.id)\n const broken = issues !== undefined && issues.length > 0\n return (\n <td\n key={col.index}\n data-invalid={broken ? 'true' : undefined}\n aria-invalid={broken ? 'true' : undefined}\n title={broken ? issueTitle(issues) : undefined}\n >\n {cellContent(col, row, failures, table)}\n </td>\n )\n })}\n </tr>\n )\n })\n }\n\n return (\n <div\n data-datakable=\"\"\n data-status={status}\n data-initial-load={isInitialLoad ? 'true' : 'false'}\n aria-busy={BUSY.includes(status) ? 'true' : undefined}\n >\n {searchState && (\n <div data-dk-search=\"\" data-status={searchState.status}>\n <Search\n value={searchState.input}\n status={searchState.status}\n onChange={(q) => void view.setSearch?.(q)}\n onSubmit={() => void view.flushSearch?.()}\n onClear={() => view.clearSearch?.()}\n />\n </div>\n )}\n {!loading && !failed && status !== 'idle' && (\n <RefreshIndicator status={status} retry={retryLoad} />\n )}\n <table>\n {props.caption != null && <caption>{props.caption}</caption>}\n <thead>\n <tr>\n {columns.map((col) => {\n const canSort = sortable && col.def.sortable !== false\n const dir = canSort ? (view.getSortDirection?.(col.id) ?? false) : false\n return (\n <th\n key={col.index}\n scope=\"col\"\n aria-sort={canSort ? ariaSort(dir) : undefined}\n data-sort={dir || undefined}\n >\n {canSort ? (\n <button\n type=\"button\"\n onClick={(e) => view.toggleSort?.(col.id, { multi: e.shiftKey })}\n >\n {col.header}\n <span data-dk-sort-indicator=\"\" aria-hidden=\"true\">\n {dir === 'asc' ? ' ▲' : dir === 'desc' ? ' ▼' : ''}\n </span>\n </button>\n ) : (\n col.header\n )}\n </th>\n )\n })}\n </tr>\n </thead>\n <tbody>\n <BodyBoundary\n table={table}\n resetKey={rowModel}\n fallback={(retry) =>\n stateRow(span, 'error', <ErrorState status={status} reason=\"render\" retry={retry} />)\n }\n >\n {body}\n </BodyBoundary>\n </tbody>\n </table>\n {paged && (\n <Pager\n pageIndex={(state.pagination as { pageIndex: number }).pageIndex}\n pageSize={(state.pagination as { pageSize: number }).pageSize}\n pageCount={view.getPageCount?.() ?? 0}\n canPrev={view.canPrevPage?.() ?? false}\n canNext={view.canNextPage?.() ?? false}\n prev={() => view.prevPage?.()}\n next={() => view.nextPage?.()}\n setPageIndex={(i) => view.setPageIndex?.(i)}\n setPageSize={(n) => view.setPageSize?.(n)}\n />\n )}\n </div>\n )\n}\n\nfunction stateRow(span: number, kind: string, content: ReactNode) {\n return (\n <tr data-dk-state={kind}>\n <td colSpan={span}>{content}</td>\n </tr>\n )\n}\n\n// --- error boundaries (DK_RENDER_FAILED) ---------------------------------------------------------\n\ninterface BoundaryProps {\n table: object\n /** A new value (the next row model) renders the body again. */\n resetKey: unknown\n fallback(retry: () => void): ReactNode\n children: ReactNode\n}\n\n/**\n * Catches a component that throws inside the body outside any cell boundary (§10: a\n * `components.Empty` / `Loading` / `Error` part): reports `DK_RENDER_FAILED` (`render:table`) and\n * shows the Error state; the header, search and pagination keep working.\n */\nclass BodyBoundary extends Component<BoundaryProps, { failed: boolean; key: unknown }> {\n override state = { failed: false, key: this.props.resetKey }\n\n static getDerivedStateFromError() {\n return { failed: true }\n }\n\n static getDerivedStateFromProps(props: BoundaryProps, state: { key: unknown }) {\n return props.resetKey === state.key ? null : { failed: false, key: props.resetKey }\n }\n\n override componentDidCatch(error: unknown) {\n try {\n emitTableDiagnostic(\n this.props.table,\n 'DK_RENDER_FAILED',\n { op: 'render:table', ...(error instanceof Error ? { errorName: error.name } : {}) },\n { cause: error },\n )\n } catch {\n // Not a table made by createTable: nothing to report to.\n }\n }\n\n retry = () => this.setState({ failed: false })\n\n override render() {\n return this.state.failed ? this.props.fallback(this.retry) : this.props.children\n }\n}\n\ninterface CellBoundaryProps {\n table: object\n col: Column\n slot: 'cell' | 'invalidCell'\n /** The row's index in the data (`row.index`). */\n row: number\n /** The row's data: a new object (or new columns) renders a failed cell again. */\n original: unknown\n children: ReactNode\n}\n\ninterface CellBoundaryState {\n failed: boolean\n original: unknown\n def: ColumnLike\n}\n\n/**\n * One cell's boundary (`render:cell`, §3.4): a component returned by `cell` / `invalidCell` that\n * throws renders `⚠` in that cell only and reports `DK_RENDER_FAILED` (deduped per column); the\n * other cells, rows and the table keep working. Only wraps object content (see `guard`).\n */\nclass CellBoundary extends Component<CellBoundaryProps, CellBoundaryState> {\n override state: CellBoundaryState = {\n failed: false,\n original: this.props.original,\n def: this.props.col.def,\n }\n\n static getDerivedStateFromError() {\n return { failed: true }\n }\n\n static getDerivedStateFromProps(props: CellBoundaryProps, state: CellBoundaryState) {\n return props.original === state.original && props.col.def === state.def\n ? null\n : { failed: false, original: props.original, def: props.col.def }\n }\n\n override componentDidCatch(error: unknown) {\n const { table, col, slot, row } = this.props\n try {\n emitTableDiagnostic(\n table,\n 'DK_RENDER_FAILED',\n {\n op: 'render:cell',\n slot: `columns[${col.index}].${slot}`,\n column: col.id,\n row,\n ...(error instanceof Error ? { errorName: error.name } : {}),\n },\n { cause: error },\n )\n } catch {\n // Not a table made by createTable: nothing to report to.\n }\n }\n\n override render() {\n return this.state.failed ? WARN : this.props.children\n }\n}\n\n// --- default parts (unstyled) --------------------------------------------------------------------\n\nfunction DefaultSearchInput({ value, status, onChange, onSubmit, onClear }: SearchInputProps) {\n return (\n <>\n <input\n type=\"search\"\n aria-label=\"Search\"\n value={value}\n onChange={(e) => onChange(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') onSubmit()\n else if (e.key === 'Escape') onClear()\n }}\n />\n {(status === 'pending' || status === 'searching') && (\n <span role=\"status\" data-dk-spinner=\"\" aria-label=\"Searching\" />\n )}\n </>\n )\n}\n\nfunction DefaultPagination(p: PaginationProps) {\n return (\n <nav aria-label=\"Pagination\" data-dk-pagination=\"\">\n <button type=\"button\" aria-label=\"Previous page\" disabled={!p.canPrev} onClick={p.prev}>\n ‹\n </button>\n <span data-dk-page=\"\">\n Page {p.pageIndex + 1} of {Math.max(p.pageCount, 1)}\n </span>\n <button type=\"button\" aria-label=\"Next page\" disabled={!p.canNext} onClick={p.next}>\n ›\n </button>\n </nav>\n )\n}\n\nconst DefaultEmpty = ({ filtered }: EmptyProps) => <>{filtered ? 'No matching rows' : 'No rows'}</>\n\nconst DefaultLoading = (_: LoadingProps) => <span role=\"status\">Loading…</span>\n\nfunction DefaultError({ reason, retry }: ErrorProps) {\n return (\n <div role=\"alert\">\n {reason === 'load' ? 'Could not load the rows.' : 'Could not display the rows.'}{' '}\n <button type=\"button\" onClick={retry}>\n Retry\n </button>\n </div>\n )\n}\n\n/** Over stale rows (§6.6): the table is busy, or a later update failed. */\nfunction RefreshIndicator({ status, retry }: { status: RowModelStatus; retry(): void }) {\n if (status === 'error') {\n return (\n <div data-dk-refresh=\"\" data-status={status} role=\"alert\">\n Could not refresh; showing the previous rows.{' '}\n <button type=\"button\" onClick={retry}>\n Retry\n </button>\n </div>\n )\n }\n return (\n <div data-dk-refresh=\"\" data-status={status} role=\"status\">\n Updating…\n </div>\n )\n}\n"],"mappings":";;;AAAA;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EAIA;AAAA,OAGK;AACP;AAAA,EACE;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAmC,oBAAoB;AAoJjD,SAoLE,UApLF,KAoLE,YApLF;AAjJN,gBAAgB,mBAAmB,qBAAqB,eAAe;AAKvE,yBAAyB;AAMzB,IAAM,4BAA4B,OAAO,WAAW,cAAc,YAAY;AAiIvE,SAAS,UACd,OACW;AACX,MAAI,MAAM,UAAU,QAAW;AAC7B,WACE,oBAAC,iBAAc,OAAO,MAAM,OAAO,YAAY,MAAM,YAAY,SAAS,MAAM,SAAS;AAAA,EAE7F;AACA,SAAO,oBAAC,cAAY,GAAI,OAAqD;AAC/E;AAEA,SAAS,WAAW,OAAkD;AACpE,QAAM,EAAE,YAAY,SAAS,OAAO,GAAG,GAAG,QAAQ,IAAI;AACtD,QAAM,OAAO,aAAa,OAAgB;AAC1C,SAAO,oBAAC,iBAAc,OAAO,MAAM,YAAwB,SAAkB;AAC/E;AAmDA,IAAM,OAAO;AACb,IAAM,OAAkC,CAAC,cAAc,WAAW,aAAa,UAAU;AACzF,IAAM,UAAqC,CAAC,cAAc,aAAa,UAAU;AAOjF,SAAS,eAAe,OAAiC;AACvD,QAAM,UAAU,MAAM,WAAW;AACjC,MAAI,OAAO,QAAQ,YAAY,WAAY,QAAO;AAClD,MAAI,CAAC,MAAM,QAAQ,QAAQ,QAAQ,EAAG,QAAO;AAC7C,aAAW,KAAK,QAAQ,UAEnB;AACH,QAAI,OAAO,GAAG,SAAS,QAAQ,aAAa,WAAY,QAAO;AAAA,EACjE;AACA,SAAO;AACT;AAEA,SAAS,eAAe,MAAoC;AAC1D,QAAM,MAAgB,CAAC;AACvB,WAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS;AAChD,UAAM,MAAM,KAAK,KAAK;AACtB,QAAI,QAAQ,QAAQ,OAAO,QAAQ,SAAU;AAC7C,UAAM,KAAK,OAAO,IAAI,QAAQ,WAAW,IAAI,MAAM,IAAI;AACvD,QAAI,OAAO,OAAO,SAAU;AAC5B,QAAI,KAAK,EAAE,KAAK,OAAO,IAAI,QAAQ,OAAO,IAAI,WAAW,WAAW,IAAI,SAAS,GAAG,CAAC;AAAA,EACvF;AACA,SAAO;AACT;AAEA,IAAM,UAAU,CAAC,MACf,OAAO,OAAO,MAAM,WAAW,EAAE,MAAM,CAAC;AAM1C,SAAS,WAAW,QAAqC;AACvD,QAAM,QAAQ,oBAAI,IAAY;AAC9B,aAAW,KAAK,OAAQ,OAAM,IAAI,EAAE,MAAM,SAAS,EAAE,KAAK,IAAI,OAAO,EAAE,KAAK,GAAG,IAAI,OAAO;AAC1F,SAAO,YAAY,CAAC,GAAG,KAAK,EAAE,KAAK,IAAI,CAAC;AAC1C;AAGA,IAAM,UAAU,CAAC,SACf,OAAO,OAAO,MAAM,UAAU,IAAK,OAAO,eAAe,IAAI,IAAe;AAE9E,SAAS,OAAO,OAAe,UAA8B;AAC3D,QAAM,SAAS,oBAAI,IAAuB;AAC1C,aAAW,KAAK,UAAU;AACxB,UAAM,IAAI,GAAG,EAAE,IAAI,KAAK,EAAE,aAAa,SAAY,UAAU,QAAQ;AACrE,UAAM,OAAO,OAAO,IAAI,CAAC;AACzB,QAAI,KAAM,MAAK,KAAK,CAAC;AAAA,QAChB,QAAO,IAAI,GAAG,CAAC,CAAC,CAAC;AAAA,EACxB;AACA,aAAW,QAAQ,OAAO,OAAO,GAAG;AAClC,UAAM,QAAQ,KAAK,CAAC;AACpB,UAAM,OAAO,KAAK,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,GAAG;AAC9C,UAAM,WAAW;AACjB,QAAI;AACF,UAAI,MAAM,aAAa,QAAW;AAChC,cAAM,IAAI,MAAM;AAChB;AAAA,UACE;AAAA,UACA;AAAA,UACA;AAAA,YACE,MAAM,MAAM;AAAA,YACZ,QAAQ,MAAM;AAAA,YACd;AAAA,YACA,OAAO,KAAK;AAAA,YACZ;AAAA,YACA,GAAI,aAAa,QAAQ,EAAE,WAAW,EAAE,KAAK,IAAI,CAAC;AAAA,UACpD;AAAA,UACA,EAAE,OAAO,EAAE;AAAA,QACb;AAAA,MACF,WAAW,QAAQ,IAAI,aAAa,cAAc;AAChD,4BAAoB,OAAO,0BAA0B;AAAA,UACnD,MAAM,MAAM;AAAA,UACZ,QAAQ,MAAM;AAAA,UACd,UAAU,MAAM;AAAA,UAChB,UAAU,MAAM,YAAY;AAAA,UAC5B,OAAO,KAAK;AAAA,UACZ;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AACF;AAOA,SAAS,YACP,KACA,KACA,UACA,OACW;AACX,QAAM,MAAM,IAAI;AAChB,QAAM,QAAQ,IAAI,SAAS,IAAI,EAAE;AACjC,QAAM,SAAS,IAAI,QAAQ,SAAY,IAAI,cAAc,IAAI,EAAE;AAC/D,MAAI,OAAO;AACX,MAAI;AACF,QAAI,WAAW,UAAa,OAAO,SAAS,GAAG;AAC7C,UAAI,IAAI,aAAa;AACnB,eAAO;AACP,cAAM,MAAM,IAAI,YAAY,EAAE,UAAU,IAAI,UAAU,OAAO,OAAO,CAAC;AACrE,YAAI,YAAY,iBAAiB,GAAG,EAAG,QAAO,MAAM,KAAK,OAAO,KAAK,KAAK,aAAa;AACvF,eAAO,IAAI,UAAU,KAAK,KAAK,MAAM,2BAA2B,GAAG;AAAA,MACrE;AACA,aACE,iCACG;AAAA,sBAAc,KAAK;AAAA,QAAG;AAAA,QACvB,oBAAC,UAAK,0BAAuB,IAAG,eAAY,QACzC,gBACH;AAAA,SACF;AAAA,IAEJ;AACA,QAAI,IAAI,MAAM;AACZ,YAAM,MAAM,IAAI,KAAK,EAAE,KAAK,IAAI,UAAU,MAAM,CAAC;AACjD,UAAI,YAAY,UAAU,GAAG,EAAG,QAAO,MAAM,KAAK,OAAO,KAAK,KAAK,MAAM;AACzE,aAAO,IAAI,UAAU,KAAK,KAAK,MAAM,2BAA2B,GAAG;AAAA,IACrE;AACA,QAAI,IAAI,QAAQ;AACd,aAAO;AACP,YAAM,MAAM,IAAI,OAAO,KAAK;AAC5B,UAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,UAAI,UAAU,KAAK,KAAK,MAAM,YAAY,GAAG;AAC7C,aAAO,cAAc,KAAK;AAAA,IAC5B;AACA,WAAO,cAAc,KAAK;AAAA,EAC5B,SAAS,OAAO;AACd,aAAS,KAAK,EAAE,MAAM,WAAW,IAAI,KAAK,KAAK,IAAI,IAAI,QAAQ,IAAI,IAAI,KAAK,IAAI,OAAO,MAAM,CAAC;AAC9F,WAAO;AAAA,EACT;AACF;AAGA,SAAS,MACP,KACA,OACA,KACA,KACA,MACW;AACX,MAAI,OAAO,QAAQ,YAAY,QAAQ,KAAM,QAAO;AACpD,SACE,oBAAC,gBAAa,OAAc,KAAU,MAAY,KAAK,IAAI,OAAO,UAAU,IAAI,UAC7E,eACH;AAEJ;AAEA,SAAS,IACP,UACA,KACA,KACA,MACA,UACA,KACW;AACX,WAAS,KAAK;AAAA,IACZ,MAAM,WAAW,IAAI,KAAK,KAAK,IAAI;AAAA,IACnC,QAAQ,IAAI;AAAA,IACZ,KAAK,IAAI;AAAA,IACT;AAAA,IACA,UAAU,eAAe,GAAG;AAAA,EAC9B,CAAC;AACD,SAAO;AACT;AAEA,IAAM,WAAW,CAAC,QAChB,QAAQ,QAAQ,cAAc,QAAQ,SAAS,eAAe;AAEhE,SAAS,cAAc,OAIpB;AACD,QAAM,OAAO,MAAM;AACnB,QAAM,QAAQ,MAAM,cAAc,CAAC;AACnC,QAAM,EAAE,OAAO,SAAS,IAAI;AAC5B,QAAM,EAAE,MAAM,QAAQ,cAAc,IAAI;AACxC,QAAM,OAAO,KAAK,WAAW,EAAE;AAC/B,QAAM,OAAO,KAAK,QAAQ;AAE1B,QAAM,cAAc,SAAS,SAAY,OAAO;AAChD,QAAM,UAAU;AAAA,IACd,MAAM,eAAe,SAAS,cAAc,cAAc,WAAW,IAAI,CAAC,EAAE;AAAA,IAC5E,CAAC,MAAM,WAAW;AAAA,EACpB;AACA,QAAM,WAAsB,CAAC;AAC7B,QAAM,QAAQ,QAAQ,IAAI;AAE1B,4BAA0B,MAAM;AAC9B,QAAI,SAAS,SAAS,EAAG,QAAO,OAAO,QAAQ;AAAA,EACjD,CAAC;AAED,QAAM,WAAW,OAAO,KAAK,eAAe;AAC5C,QAAM,cAAc,MAAM;AAC1B,QAAM,QAAQ,OAAO,KAAK,iBAAiB;AAG3C,QAAM,UACJ,kBAAkB,QAAQ,SAAS,MAAM,KAAM,WAAW,aAAa,eAAe,IAAI;AAC5F,QAAM,SAAS,iBAAiB,WAAW;AAC3C,QAAM,OAAO,KAAK,IAAI,QAAQ,QAAQ,CAAC;AACvC,QAAM,YAAY,MAAM,KAAK,KAAK,QAAQ;AAE1C,QAAM,SAAS,MAAM,eAAe;AACpC,QAAM,QAAQ,MAAM,cAAc;AAClC,QAAM,QAAQ,MAAM,SAAS;AAC7B,QAAM,UAAU,MAAM,WAAW;AACjC,QAAM,aAAa,MAAM,SAAS;AAElC,MAAI;AACJ,MAAI,SAAS;AACX,WAAO,SAAS,MAAM,WAAW,oBAAC,WAAQ,QAAgB,CAAE;AAAA,EAC9D,WAAW,QAAQ;AACjB,WAAO,SAAS,MAAM,SAAS,oBAAC,cAAW,QAAgB,QAAO,QAAO,OAAO,WAAW,CAAE;AAAA,EAC/F,WAAW,KAAK,WAAW,GAAG;AAC5B,WAAO,SAAS,MAAM,SAAS,oBAAC,SAAM,UAAU,SAAS,aAAa,GAAG,CAAE;AAAA,EAC7E,OAAO;AACL,WAAO,KAAK,IAAI,CAAC,QAAQ;AACvB,YAAM,QAAQ,IAAI;AAClB,aACE;AAAA,QAAC;AAAA;AAAA,UAEC,gBAAc,QAAQ,SAAY;AAAA,UAClC,gBAAc,QAAQ,SAAY;AAAA,UAClC,OAAO,QAAQ,SAAY,WAAW,IAAI,MAAM;AAAA,UAE/C,kBAAQ,IAAI,CAAC,QAAQ;AACpB,kBAAM,SAAS,QAAQ,SAAY,IAAI,cAAc,IAAI,EAAE;AAC3D,kBAAM,SAAS,WAAW,UAAa,OAAO,SAAS;AACvD,mBACE;AAAA,cAAC;AAAA;AAAA,gBAEC,gBAAc,SAAS,SAAS;AAAA,gBAChC,gBAAc,SAAS,SAAS;AAAA,gBAChC,OAAO,SAAS,WAAW,MAAM,IAAI;AAAA,gBAEpC,sBAAY,KAAK,KAAK,UAAU,KAAK;AAAA;AAAA,cALjC,IAAI;AAAA,YAMX;AAAA,UAEJ,CAAC;AAAA;AAAA,QAlBI,IAAI;AAAA,MAmBX;AAAA,IAEJ,CAAC;AAAA,EACH;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,kBAAe;AAAA,MACf,eAAa;AAAA,MACb,qBAAmB,gBAAgB,SAAS;AAAA,MAC5C,aAAW,KAAK,SAAS,MAAM,IAAI,SAAS;AAAA,MAE3C;AAAA,uBACC,oBAAC,SAAI,kBAAe,IAAG,eAAa,YAAY,QAC9C;AAAA,UAAC;AAAA;AAAA,YACC,OAAO,YAAY;AAAA,YACnB,QAAQ,YAAY;AAAA,YACpB,UAAU,CAAC,MAAM,KAAK,KAAK,YAAY,CAAC;AAAA,YACxC,UAAU,MAAM,KAAK,KAAK,cAAc;AAAA,YACxC,SAAS,MAAM,KAAK,cAAc;AAAA;AAAA,QACpC,GACF;AAAA,QAED,CAAC,WAAW,CAAC,UAAU,WAAW,UACjC,oBAAC,oBAAiB,QAAgB,OAAO,WAAW;AAAA,QAEtD,qBAAC,WACE;AAAA,gBAAM,WAAW,QAAQ,oBAAC,aAAS,gBAAM,SAAQ;AAAA,UAClD,oBAAC,WACC,8BAAC,QACE,kBAAQ,IAAI,CAAC,QAAQ;AACpB,kBAAM,UAAU,YAAY,IAAI,IAAI,aAAa;AACjD,kBAAM,MAAM,UAAW,KAAK,mBAAmB,IAAI,EAAE,KAAK,QAAS;AACnE,mBACE;AAAA,cAAC;AAAA;AAAA,gBAEC,OAAM;AAAA,gBACN,aAAW,UAAU,SAAS,GAAG,IAAI;AAAA,gBACrC,aAAW,OAAO;AAAA,gBAEjB,oBACC;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,SAAS,CAAC,MAAM,KAAK,aAAa,IAAI,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC;AAAA,oBAE9D;AAAA,0BAAI;AAAA,sBACL,oBAAC,UAAK,0BAAuB,IAAG,eAAY,QACzC,kBAAQ,QAAQ,YAAO,QAAQ,SAAS,YAAO,IAClD;AAAA;AAAA;AAAA,gBACF,IAEA,IAAI;AAAA;AAAA,cAhBD,IAAI;AAAA,YAkBX;AAAA,UAEJ,CAAC,GACH,GACF;AAAA,UACA,oBAAC,WACC;AAAA,YAAC;AAAA;AAAA,cACC;AAAA,cACA,UAAU;AAAA,cACV,UAAU,CAAC,UACT,SAAS,MAAM,SAAS,oBAAC,cAAW,QAAgB,QAAO,UAAS,OAAc,CAAE;AAAA,cAGrF;AAAA;AAAA,UACH,GACF;AAAA,WACF;AAAA,QACC,SACC;AAAA,UAAC;AAAA;AAAA,YACC,WAAY,MAAM,WAAqC;AAAA,YACvD,UAAW,MAAM,WAAoC;AAAA,YACrD,WAAW,KAAK,eAAe,KAAK;AAAA,YACpC,SAAS,KAAK,cAAc,KAAK;AAAA,YACjC,SAAS,KAAK,cAAc,KAAK;AAAA,YACjC,MAAM,MAAM,KAAK,WAAW;AAAA,YAC5B,MAAM,MAAM,KAAK,WAAW;AAAA,YAC5B,cAAc,CAAC,MAAM,KAAK,eAAe,CAAC;AAAA,YAC1C,aAAa,CAAC,MAAM,KAAK,cAAc,CAAC;AAAA;AAAA,QAC1C;AAAA;AAAA;AAAA,EAEJ;AAEJ;AAEA,SAAS,SAAS,MAAc,MAAc,SAAoB;AAChE,SACE,oBAAC,QAAG,iBAAe,MACjB,8BAAC,QAAG,SAAS,MAAO,mBAAQ,GAC9B;AAEJ;AAiBA,IAAM,eAAN,cAA2B,UAA4D;AAAA,EAAvF;AAAA;AACE,SAAS,QAAQ,EAAE,QAAQ,OAAO,KAAK,KAAK,MAAM,SAAS;AAuB3D,iBAAQ,MAAM,KAAK,SAAS,EAAE,QAAQ,MAAM,CAAC;AAAA;AAAA,EArB7C,OAAO,2BAA2B;AAChC,WAAO,EAAE,QAAQ,KAAK;AAAA,EACxB;AAAA,EAEA,OAAO,yBAAyB,OAAsB,OAAyB;AAC7E,WAAO,MAAM,aAAa,MAAM,MAAM,OAAO,EAAE,QAAQ,OAAO,KAAK,MAAM,SAAS;AAAA,EACpF;AAAA,EAES,kBAAkB,OAAgB;AACzC,QAAI;AACF;AAAA,QACE,KAAK,MAAM;AAAA,QACX;AAAA,QACA,EAAE,IAAI,gBAAgB,GAAI,iBAAiB,QAAQ,EAAE,WAAW,MAAM,KAAK,IAAI,CAAC,EAAG;AAAA,QACnF,EAAE,OAAO,MAAM;AAAA,MACjB;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAIS,SAAS;AAChB,WAAO,KAAK,MAAM,SAAS,KAAK,MAAM,SAAS,KAAK,KAAK,IAAI,KAAK,MAAM;AAAA,EAC1E;AACF;AAwBA,IAAM,eAAN,cAA2B,UAAgD;AAAA,EAA3E;AAAA;AACE,SAAS,QAA2B;AAAA,MAClC,QAAQ;AAAA,MACR,UAAU,KAAK,MAAM;AAAA,MACrB,KAAK,KAAK,MAAM,IAAI;AAAA,IACtB;AAAA;AAAA,EAEA,OAAO,2BAA2B;AAChC,WAAO,EAAE,QAAQ,KAAK;AAAA,EACxB;AAAA,EAEA,OAAO,yBAAyB,OAA0B,OAA0B;AAClF,WAAO,MAAM,aAAa,MAAM,YAAY,MAAM,IAAI,QAAQ,MAAM,MAChE,OACA,EAAE,QAAQ,OAAO,UAAU,MAAM,UAAU,KAAK,MAAM,IAAI,IAAI;AAAA,EACpE;AAAA,EAES,kBAAkB,OAAgB;AACzC,UAAM,EAAE,OAAO,KAAK,MAAM,IAAI,IAAI,KAAK;AACvC,QAAI;AACF;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,UACE,IAAI;AAAA,UACJ,MAAM,WAAW,IAAI,KAAK,KAAK,IAAI;AAAA,UACnC,QAAQ,IAAI;AAAA,UACZ;AAAA,UACA,GAAI,iBAAiB,QAAQ,EAAE,WAAW,MAAM,KAAK,IAAI,CAAC;AAAA,QAC5D;AAAA,QACA,EAAE,OAAO,MAAM;AAAA,MACjB;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAES,SAAS;AAChB,WAAO,KAAK,MAAM,SAAS,OAAO,KAAK,MAAM;AAAA,EAC/C;AACF;AAIA,SAAS,mBAAmB,EAAE,OAAO,QAAQ,UAAU,UAAU,QAAQ,GAAqB;AAC5F,SACE,iCACE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAW;AAAA,QACX;AAAA,QACA,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,QACxC,WAAW,CAAC,MAAM;AAChB,cAAI,EAAE,QAAQ,QAAS,UAAS;AAAA,mBACvB,EAAE,QAAQ,SAAU,SAAQ;AAAA,QACvC;AAAA;AAAA,IACF;AAAA,KACE,WAAW,aAAa,WAAW,gBACnC,oBAAC,UAAK,MAAK,UAAS,mBAAgB,IAAG,cAAW,aAAY;AAAA,KAElE;AAEJ;AAEA,SAAS,kBAAkB,GAAoB;AAC7C,SACE,qBAAC,SAAI,cAAW,cAAa,sBAAmB,IAC9C;AAAA,wBAAC,YAAO,MAAK,UAAS,cAAW,iBAAgB,UAAU,CAAC,EAAE,SAAS,SAAS,EAAE,MAAM,oBAExF;AAAA,IACA,qBAAC,UAAK,gBAAa,IAAG;AAAA;AAAA,MACd,EAAE,YAAY;AAAA,MAAE;AAAA,MAAK,KAAK,IAAI,EAAE,WAAW,CAAC;AAAA,OACpD;AAAA,IACA,oBAAC,YAAO,MAAK,UAAS,cAAW,aAAY,UAAU,CAAC,EAAE,SAAS,SAAS,EAAE,MAAM,oBAEpF;AAAA,KACF;AAEJ;AAEA,IAAM,eAAe,CAAC,EAAE,SAAS,MAAkB,gCAAG,qBAAW,qBAAqB,WAAU;AAEhG,IAAM,iBAAiB,CAAC,MAAoB,oBAAC,UAAK,MAAK,UAAS,2BAAQ;AAExE,SAAS,aAAa,EAAE,QAAQ,MAAM,GAAe;AACnD,SACE,qBAAC,SAAI,MAAK,SACP;AAAA,eAAW,SAAS,6BAA6B;AAAA,IAA+B;AAAA,IACjF,oBAAC,YAAO,MAAK,UAAS,SAAS,OAAO,mBAEtC;AAAA,KACF;AAEJ;AAGA,SAAS,iBAAiB,EAAE,QAAQ,MAAM,GAA8C;AACtF,MAAI,WAAW,SAAS;AACtB,WACE,qBAAC,SAAI,mBAAgB,IAAG,eAAa,QAAQ,MAAK,SAAQ;AAAA;AAAA,MACV;AAAA,MAC9C,oBAAC,YAAO,MAAK,UAAS,SAAS,OAAO,mBAEtC;AAAA,OACF;AAAA,EAEJ;AACA,SACE,oBAAC,SAAI,mBAAgB,IAAG,eAAa,QAAQ,MAAK,UAAS,4BAE3D;AAEJ;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/data-table.tsx"],"sourcesContent":["'use client'\n\nimport {\n type AnyFeature,\n boundaryDiagnostics,\n defaultFormat,\n deriveColumns,\n describeReturn,\n emitTableDiagnostic,\n type InvalidRowsMode,\n keepDiagnostics,\n matchesSlot,\n pipelineDiagnostics,\n type RowIssue,\n type RowModelStatus,\n type SearchStatus,\n slotDiagnostics,\n type TableSchema,\n type TableState,\n} from '@datakable/core'\nimport {\n Component,\n type ComponentType,\n type CSSProperties,\n type ReactNode,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n} from 'react'\nimport {\n cellSlot,\n invalidCellSlot,\n registerRenderOperations,\n renderDiagnostics,\n} from './render-codes'\nimport { type UseDataTableOptions, useDataTable } from './use-data-table'\n\n// The codes this module emits (bundlers keep the definitions; see core's `keepDiagnostics`).\nkeepDiagnostics(renderDiagnostics, boundaryDiagnostics, slotDiagnostics, pipelineDiagnostics)\n\n// The ops its boundaries stand for (§3.4: `render:table`, `render:cell`). Registered at import:\n// the dist is one file per module (T37), so hook-only bundles (`useDataTable` without\n// `<DataTable />`) never include this module, and this call ships only with `<DataTable />`.\nregisterRenderOperations()\n\n// No @types/node here: declare just what is read.\ndeclare const process: { env: { NODE_ENV?: string } }\n\n/** No layout effects on the server (React 18 warns about them there). */\nconst useIsomorphicLayoutEffect = typeof window === 'undefined' ? useEffect : useLayoutEffect\n\n// --- public types --------------------------------------------------------------------------------\n\n/** Props of `components.SearchInput`: the search feature's `input`, bound both ways. */\nexport interface SearchInputProps {\n /** `state.search.input` (updates as the user types). */\n value: string\n /** `state.search.status`: `pending` while a debounce waits, `searching` while a request runs. */\n status: SearchStatus\n /** `setSearch(value)`. */\n onChange(value: string): void\n /** `flushSearch()` (Enter). */\n onSubmit(): void\n /** `clearSearch()` (Esc). */\n onClear(): void\n /** The input's accessible name: `'Search <caption>'` with a text `caption`, else `'Search'`. */\n label: string\n}\n\n/** Props of `components.Pagination` (the pagination feature's state and API). */\nexport interface PaginationProps {\n pageIndex: number\n pageSize: number\n pageCount: number\n canPrev: boolean\n canNext: boolean\n prev(): void\n next(): void\n setPageIndex(index: number): void\n setPageSize(size: number): void\n /** The pager's accessible name: `'<caption> pagination'` with a text `caption`, else `'Pagination'`. */\n label: string\n}\n\n/** Props of `components.Empty`: shown when the table has loaded and has no rows to show. */\nexport interface EmptyProps {\n /** `true` when there is data but filters / search removed every row. */\n filtered: boolean\n}\n\n/** Props of `components.Loading`: the first load (`isInitialLoad`, nothing to show yet). */\nexport interface LoadingProps {\n status: RowModelStatus\n}\n\n/** Props of `components.Error`: the first load failed, or the body failed to render. */\nexport interface ErrorProps {\n status: RowModelStatus\n /**\n * `'load'`: `status === 'error'` on the first load. `'render'`: a component in the body outside\n * the cells threw (a component inside a cell renders `⚠` in that cell only).\n */\n reason: 'load' | 'render'\n /** `'load'`: `refetch()`. `'render'`: renders the body again. */\n retry(): void\n}\n\n/** `<DataTable components={...} />`: replaces the default parts (unstyled, `data-*` hooks only). */\nexport interface DataTableComponents {\n SearchInput?: ComponentType<SearchInputProps>\n Pagination?: ComponentType<PaginationProps>\n Empty?: ComponentType<EmptyProps>\n Loading?: ComponentType<LoadingProps>\n Error?: ComponentType<ErrorProps>\n}\n\n/** What `<DataTable table={...} />` reads: the value `useDataTable` returns. */\nexport interface DataTableSource {\n readonly state: TableState\n readonly rowModel: {\n readonly rows: readonly DataTableRow[]\n readonly filteredCount: number\n readonly totalCount: number\n readonly status: RowModelStatus\n readonly isInitialLoad: boolean\n }\n getOptions(): { readonly columns?: readonly unknown[] | undefined }\n getData(): readonly unknown[]\n refetch(): Promise<unknown>\n}\n\n/** The part of a `Row` (§6.6) `<DataTable />` renders from. */\ninterface DataTableRow {\n readonly key: string | number\n readonly index: number\n readonly original: unknown\n readonly valid: boolean\n readonly issues: readonly RowIssue[]\n getValue(id: string): unknown\n getCellIssues(id: string): readonly RowIssue[]\n}\n\n/** `<DataTable />`'s own props, next to `table` or the `useDataTable` options. */\nexport interface DataTableOwnProps {\n components?: DataTableComponents | undefined\n caption?: ReactNode\n}\n\n/**\n * `<DataTable table={useDataTable(...)} />`, or `<DataTable data={rows} />` with the\n * `useDataTable` options as props (zero-config: columns derived from the data).\n */\nexport type DataTableProps<\n T = unknown,\n Sch = undefined,\n M extends InvalidRowsMode = InvalidRowsMode,\n> = DataTableOwnProps &\n (\n | { table: DataTableSource }\n | (UseDataTableOptions<T, TableState, Sch, M> & {\n features?: readonly AnyFeature[]\n table?: undefined\n })\n )\n\n// --- component -----------------------------------------------------------------------------------\n\n/**\n * The zero-config table (§10). Renders what the installed features provide: sort buttons with\n * `aria-sort`, a search input bound to `input` (Enter = `flushSearch`, Esc = `clearSearch`),\n * pagination, and the Loading / Error / Empty states from `status` + `isInitialLoad` (§6.6).\n * Unstyled: style it through the `data-*` hooks (`data-status`, `data-initial-load`,\n * `data-invalid`, `data-sort`, …) or replace parts with `components`.\n *\n * `@datakable/react`'s `DataTable` installs no features with `data`; `datakable`'s installs the\n * default preset.\n */\nexport function DataTable<\n T,\n const Sch extends TableSchema | undefined = undefined,\n const M extends InvalidRowsMode = 'drop',\n>(props: DataTableProps<T, Sch, M>): ReactNode\nexport function DataTable(\n props: DataTableOwnProps & { table?: DataTableSource | undefined },\n): ReactNode {\n if (props.table !== undefined) {\n return (\n <DataTableView table={props.table} components={props.components} caption={props.caption} />\n )\n }\n return <ZeroConfig {...(props as DataTableOwnProps & { table?: undefined })} />\n}\n\nfunction ZeroConfig(props: DataTableOwnProps & { table?: undefined }) {\n const { components, caption, table: _, ...options } = props\n const view = useDataTable(options as never) as unknown as DataTableSource\n return <DataTableView table={view} components={components} caption={caption} />\n}\n\n/** Loose access to the installed features' APIs (the table is typed per feature set). */\ntype Api = DataTableSource & {\n toggleSort?(id: string, opts?: { multi?: boolean }): void\n setSearch?(q: string): Promise<unknown>\n flushSearch?(): Promise<unknown>\n clearSearch?(): void\n setPageIndex?(i: number): void\n setPageSize?(n: number): void\n nextPage?(): void\n prevPage?(): void\n getPageCount?(): number\n canNextPage?(): boolean\n canPrevPage?(): boolean\n}\n\n/** The column fields `<DataTable />` reads (types are checked where the columns are written). */\ninterface ColumnLike {\n key?: unknown\n id?: unknown\n header?: unknown\n sortable?: unknown\n cell?: (ctx: { row: unknown; value: unknown }) => ReactNode\n format?: (value: unknown) => unknown\n invalidCell?: (ctx: {\n original: unknown\n value: unknown\n issues: readonly RowIssue[]\n }) => ReactNode\n}\n\ninterface Column {\n readonly def: ColumnLike\n readonly index: number\n readonly id: string\n readonly header: ReactNode\n}\n\n/** A cell callback that threw or broke its contract during this render (reported after commit). */\ninterface Failure {\n slot: string\n column: string\n row: number\n error?: unknown\n /** Bad return: what the contract expects and the type received. */\n expected?: string\n received?: string\n /** A value the default formatter cannot render (`DK_UNRENDERABLE_VALUE`): its type. */\n lost?: string\n index?: number\n}\n\nconst WARN = '⚠'\n/** A failed cell's content: the `⚠` with its text alternative (#60). One element for every cell. */\nconst FAILED = (\n <span role=\"img\" aria-label=\"Could not display this value\">\n {WARN}\n </span>\n)\nconst BUSY: readonly RowModelStatus[] = ['validating', 'pending', 'searching', 'fetching']\nconst LOADING: readonly RowModelStatus[] = ['validating', 'searching', 'fetching']\n\n/**\n * The table loads its rows asynchronously: a `fetcher`, or a feature with a `searchFn` (its\n * `defineOptions` values). With nothing applied yet, its `'pending'` is a load waiting to start\n * (deferred until the client, §7.2), so `<DataTable />` shows Loading — also in the server HTML.\n */\nfunction hasAsyncSource(table: DataTableSource): boolean {\n const options = table.getOptions() as { fetcher?: unknown; features?: unknown }\n if (typeof options.fetcher === 'function') return true\n if (!Array.isArray(options.features)) return false\n for (const f of options.features as readonly {\n options?: { values?: { searchFn?: unknown } }\n }[]) {\n if (typeof f?.options?.values?.searchFn === 'function') return true\n }\n return false\n}\n\nfunction resolveColumns(defs: readonly unknown[]): Column[] {\n const out: Column[] = []\n for (let index = 0; index < defs.length; index++) {\n const def = defs[index] as ColumnLike | null | undefined\n if (def === null || typeof def !== 'object') continue\n const id = typeof def.key === 'string' ? def.key : def.id\n if (typeof id !== 'string') continue\n out.push({ def, index, id, header: typeof def.header === 'string' ? def.header : id })\n }\n return out\n}\n\nconst segment = (s: PropertyKey | { readonly key: PropertyKey }) =>\n String(typeof s === 'object' ? s.key : s)\n\n/**\n * The redacted issue text for `title` (§5.1): the issue paths only. Schema messages embed the\n * received value, so they are never shown.\n */\nfunction issueTitle(issues: readonly RowIssue[]): string {\n const paths = new Set<string>()\n for (const i of issues) paths.add(i.path?.length ? i.path.map(segment).join('.') : '(row)')\n return `Invalid: ${[...paths].join(', ')}`\n}\n\n/** The table behind a `useDataTable` view (its prototype), for reporting diagnostics. */\nconst tableOf = (view: object): object =>\n Object.hasOwn(view, 'rowModel') ? (Object.getPrototypeOf(view) as object) : view\n\nfunction report(table: object, failures: readonly Failure[]) {\n const bySlot = new Map<string, Failure[]>()\n for (const f of failures) {\n const k = `${f.slot}\\0${f.lost ? '' : f.expected === undefined ? 'throw' : 'return'}`\n const list = bySlot.get(k)\n if (list) list.push(f)\n else bySlot.set(k, [f])\n }\n for (const list of bySlot.values()) {\n const first = list[0] as Failure\n const rows = list.slice(0, 3).map((f) => f.row)\n const fallback = 'cells-warn' // prose key: 'those cells rendered ⚠'\n try {\n if (first.lost !== undefined) {\n // Deduped by the table per column and data reference, like the column cache's report.\n emitTableDiagnostic(table, 'DK_UNRENDERABLE_VALUE', {\n column: first.column,\n index: first.index as number,\n count: list.length,\n rows,\n valueType: first.lost,\n })\n } else if (first.expected === undefined) {\n const e = first.error\n emitTableDiagnostic(\n table,\n 'DK_CALLBACK_FAILED',\n {\n slot: first.slot,\n column: first.column,\n rows,\n count: list.length,\n fallback,\n ...(e instanceof Error ? { errorName: e.name } : {}),\n },\n { cause: e },\n )\n } else if (process.env.NODE_ENV !== 'production') {\n emitTableDiagnostic(table, 'DK_CALLBACK_BAD_RETURN', {\n slot: first.slot,\n column: first.column,\n expected: first.expected,\n received: first.received ?? 'undefined',\n count: list.length,\n rows,\n fallback,\n })\n }\n } catch {\n // Not a table made by createTable (a hand-made `table` prop): nothing to report to.\n }\n }\n}\n\n/**\n * The value `defaultFormat` could not render in the current cell (an object, array or function,\n * never `undefined`). One module-level callback: no closure per cell.\n */\nlet lost: unknown\nconst onLost = (v: unknown) => {\n lost = v\n}\n\n/**\n * Renders one cell's content; a throwing or contract-breaking callback renders `⚠`. An object\n * returned by `cell` / `invalidCell` (an element, an array) may hold components that throw while\n * React renders them, so it gets its own boundary; primitives cannot, so they get none (no cost).\n */\nfunction cellContent(\n col: Column,\n row: DataTableRow,\n failures: Failure[],\n table: object,\n): ReactNode {\n const def = col.def\n const value = row.getValue(col.id)\n const issues = row.valid ? undefined : row.getCellIssues(col.id)\n let slot = 'cell'\n try {\n if (issues !== undefined && issues.length > 0) {\n if (def.invalidCell) {\n slot = 'invalidCell'\n const out = def.invalidCell({ original: row.original, value, issues })\n if (matchesSlot(invalidCellSlot, out)) return guard(out, table, col, row, 'invalidCell')\n return bad(failures, col, row, slot, 'a value (not a Promise)', out)\n }\n return (\n <>\n {defaultFormat(value)}{' '}\n <span data-dk-invalid-marker=\"\" aria-hidden=\"true\">\n {WARN}\n </span>\n </>\n )\n }\n if (def.cell) {\n const out = def.cell({ row: row.original, value })\n if (matchesSlot(cellSlot, out)) return guard(out, table, col, row, 'cell')\n return bad(failures, col, row, slot, 'a value (not a Promise)', out)\n }\n if (def.format) {\n slot = 'format'\n const out = def.format(value)\n if (typeof out === 'string') return out\n bad(failures, col, row, slot, 'a string', out)\n return defaultFormat(value)\n }\n const text = defaultFormat(value, onLost)\n if (lost !== undefined) {\n const { id: column, index } = col\n const type = Array.isArray(lost) ? 'array' : typeof lost\n failures.push({ slot: `columns[${index}]`, column, index, row: row.index, lost: type })\n lost = undefined\n }\n return text\n } catch (error) {\n failures.push({ slot: `columns[${col.index}].${slot}`, column: col.id, row: row.index, error })\n return FAILED\n }\n}\n\n/** Wraps object content in a per-cell boundary (`render:cell`); primitives pass through as-is. */\nfunction guard(\n out: ReactNode,\n table: object,\n col: Column,\n row: DataTableRow,\n slot: 'cell' | 'invalidCell',\n): ReactNode {\n if (typeof out !== 'object' || out === null) return out\n return (\n <Boundary\n table={table}\n col={col}\n slot={slot}\n row={row.index}\n resetKey={row.original}\n fallback={failedCell}\n >\n {out}\n </Boundary>\n )\n}\n\nfunction bad(\n failures: Failure[],\n col: Column,\n row: DataTableRow,\n slot: string,\n expected: string,\n out: unknown,\n): ReactNode {\n failures.push({\n slot: `columns[${col.index}].${slot}`,\n column: col.id,\n row: row.index,\n expected,\n received: describeReturn(out),\n })\n return FAILED\n}\n\ntype Page = { pageIndex: number; pageSize: number }\n\n/** Visually hidden, still read by screen readers (inline: the table ships no CSS). */\nconst HIDDEN: CSSProperties = {\n position: 'absolute',\n width: 1,\n height: 1,\n overflow: 'hidden',\n clipPath: 'inset(50%)',\n whiteSpace: 'nowrap',\n}\n\nconst serverPaged = (view: Api) =>\n (view.getOptions() as { features?: readonly { stage?: string; mode?: string }[] }).features?.some(\n (f) => f?.stage === 'paginate' && f.mode === 'server',\n ) === true\n\n/**\n * The pager of the rendered snapshot, like the pagination API computes it live: the hydrating\n * render must match the server HTML even when the table changed meanwhile (#16). Client mode\n * pages over the row model's `filteredCount`; server mode over the fetched `rowCount`, which only\n * the table knows (and no render changes).\n */\nfunction pages(view: Api, page: Page, count: number, server: boolean) {\n if (server) {\n return {\n ...page,\n pageCount: view.getPageCount?.() ?? 0,\n canPrev: view.canPrevPage?.() ?? false,\n canNext: view.canNextPage?.() ?? false,\n }\n }\n const pageCount = Math.ceil(count / page.pageSize)\n const index = Math.min(page.pageIndex, Math.max(pageCount - 1, 0))\n return { ...page, pageCount, canPrev: index > 0, canNext: index + 1 < pageCount }\n}\n\nconst ariaSort = (dir: 'asc' | 'desc' | false) =>\n dir === 'asc' ? 'ascending' : dir === 'desc' ? 'descending' : 'none'\n\nfunction DataTableView(props: {\n table: DataTableSource\n components: DataTableComponents | undefined\n caption: ReactNode\n}) {\n const view = props.table as Api\n const parts = props.components ?? {}\n const { state, rowModel } = view\n const { rows, status, isInitialLoad } = rowModel\n const defs = view.getOptions().columns\n const data = view.getData()\n // Zero-config columns follow the data; given columns follow their reference (§10).\n const derivedFrom = defs === undefined ? data : undefined\n const columns = useMemo(\n () => resolveColumns(defs ?? (derivedFrom ? deriveColumns(derivedFrom) : [])),\n [defs, derivedFrom],\n )\n const failures: Failure[] = []\n const table = tableOf(view)\n // After commit, never during render: a sink may set state.\n useIsomorphicLayoutEffect(() => {\n if (failures.length > 0) report(table, failures)\n })\n\n const sortable = typeof view.toggleSort === 'function'\n const sortBy = (state.sorting as { by: readonly { id: string; desc?: boolean }[] } | undefined)\n ?.by\n const searchState = state.search as { input: string; status: SearchStatus } | undefined\n const paged = typeof view.getPageCount === 'function'\n // Loading (§6.6, §10): nothing to show yet and rows on their way — in flight, or deferred async\n // work that has not started (SSR, §7.2: 'pending').\n const loading =\n isInitialLoad && (LOADING.includes(status) || (status === 'pending' && hasAsyncSource(view)))\n const failed = isInitialLoad && status === 'error'\n const span = Math.max(columns.length, 1)\n const tableEl = useRef<HTMLTableElement>(null)\n /**\n * Retry unmounts the focused Retry button (Error → Loading → rows, or the refresh error): focus\n * the table first, else it falls to `<body>` (#56). Only when focus is in a state row or the\n * refresh indicator, so a retry called from elsewhere leaves focus alone.\n */\n const keepFocus = () => {\n const t = tableEl.current\n const from = document.activeElement?.closest('[data-dk-state],[data-dk-refresh]')\n if (t && from && t.parentElement?.contains(from)) {\n t.tabIndex = -1\n t.focus()\n }\n }\n const retryLoad = () => {\n keepFocus()\n void view.refetch()\n }\n const server = paged && serverPaged(view)\n const pager = paged ? pages(view, state.pagination as Page, rowModel.filteredCount, server) : null\n\n // Status messages (#54): one polite live region, in the markup from the first render (a region\n // inserted with its text is often not announced). Written after commit, only when the message\n // changes, so the first render (and the hydrating one) matches the server HTML.\n // Worded unlike the visible parts (\"No rows\", \"Searching…\"), so a text query finds one element.\n const n = rowModel.filteredCount\n const count = `${n} row${n === 1 ? '' : 's'}`\n const page = pager ? `${pager.pageIndex + 1} of ${Math.max(pager.pageCount, 1)}` : ''\n let said = ''\n if (searchState?.status === 'pending' || searchState?.status === 'searching') {\n said = 'Searching rows…'\n } else if (status === 'idle' && !loading) {\n // Server mode: `filteredCount` is the page's rows, so only the page (or \"0 rows\").\n said = server && n ? `Page ${page}` : page ? `${count}, page ${page}` : count\n }\n const liveEl = useRef<HTMLDivElement>(null)\n const saidBefore = useRef<string | null>(null)\n useEffect(() => {\n const el = liveEl.current\n if (el && saidBefore.current !== null && saidBefore.current !== said) el.textContent = said\n saidBefore.current = said\n })\n\n // A text caption names the search box and the pager, so two tables get distinct names (#59).\n const cap = props.caption\n const named = typeof cap === 'string' || typeof cap === 'number' ? `${cap}` : ''\n\n const Empty = parts.Empty ?? DefaultEmpty\n const Loading = parts.Loading ?? DefaultLoading\n const ErrorState = parts.Error ?? DefaultError\n\n let body: ReactNode\n if (loading) {\n body = stateRow(span, 'loading', <Loading status={status} />)\n } else if (failed) {\n body = stateRow(span, 'error', <ErrorState status={status} reason=\"load\" retry={retryLoad} />)\n } else if (rows.length === 0) {\n body = stateRow(span, 'empty', <Empty filtered={rowModel.totalCount > 0} />)\n } else {\n body = rows.map((row) => {\n const valid = row.valid\n return (\n <tr\n key={row.key}\n data-invalid={valid ? undefined : 'true'}\n aria-invalid={valid ? undefined : 'true'}\n title={valid ? undefined : issueTitle(row.issues)}\n >\n {columns.map((col) => {\n const issues = valid ? undefined : row.getCellIssues(col.id)\n const broken = issues !== undefined && issues.length > 0\n return (\n <td\n key={col.index}\n data-invalid={broken ? 'true' : undefined}\n aria-invalid={broken ? 'true' : undefined}\n title={broken ? issueTitle(issues) : undefined}\n >\n {cellContent(col, row, failures, table)}\n </td>\n )\n })}\n </tr>\n )\n })\n }\n\n // The server runs no effects: report now (setting state is a no-op there).\n if (typeof window === 'undefined' && failures.length > 0) report(table, failures)\n\n return (\n <div\n data-datakable=\"\"\n data-status={status}\n data-initial-load={isInitialLoad ? 'true' : 'false'}\n aria-busy={BUSY.includes(status) ? 'true' : undefined}\n >\n {searchState && (\n <div data-dk-search=\"\" data-status={searchState.status}>\n {part(table, 'SearchInput', parts.SearchInput, DefaultSearchInput, {\n value: searchState.input,\n status: searchState.status,\n onChange: (q) => void view.setSearch?.(q),\n onSubmit: () => void view.flushSearch?.(),\n onClear: () => view.clearSearch?.(),\n label: named ? `Search ${named}` : 'Search',\n })}\n </div>\n )}\n {!loading && !failed && status !== 'idle' && (\n <RefreshIndicator status={status} retry={retryLoad} />\n )}\n <table ref={tableEl}>\n {props.caption != null && <caption>{props.caption}</caption>}\n <thead>\n <tr>\n {columns.map((col) => {\n const canSort = sortable && col.def.sortable !== false\n // From the rendered state, not the live table (the hydrating render, #16).\n const e = canSort ? sortBy?.find((x) => x.id === col.id) : undefined\n const dir = e ? (e.desc ? 'desc' : 'asc') : false\n return (\n <th\n key={col.index}\n scope=\"col\"\n aria-sort={canSort ? ariaSort(dir) : undefined}\n data-sort={dir || undefined}\n >\n {canSort ? (\n <button\n type=\"button\"\n onClick={(e) => view.toggleSort?.(col.id, { multi: e.shiftKey })}\n >\n {col.header}\n <span data-dk-sort-indicator=\"\" aria-hidden=\"true\">\n {dir === 'asc' ? ' ▲' : dir === 'desc' ? ' ▼' : ''}\n </span>\n </button>\n ) : (\n col.header\n )}\n </th>\n )\n })}\n </tr>\n </thead>\n <tbody>\n <Boundary\n table={table}\n resetKey={rowModel}\n fallback={(retry) =>\n stateRow(\n span,\n 'error',\n <ErrorState\n status={status}\n reason=\"render\"\n retry={() => {\n keepFocus()\n retry()\n }}\n />,\n )\n }\n >\n {body}\n </Boundary>\n </tbody>\n </table>\n {pager &&\n part(table, 'Pagination', parts.Pagination, DefaultPagination, {\n ...pager,\n prev: () => view.prevPage?.(),\n next: () => view.nextPage?.(),\n setPageIndex: (i) => view.setPageIndex?.(i),\n setPageSize: (n) => view.setPageSize?.(n),\n label: named ? `${named} pagination` : 'Pagination',\n })}\n <div aria-live=\"polite\" style={HIDDEN} ref={liveEl} />\n </div>\n )\n}\n\n/**\n * A search / pager part (outside the body): a custom one that throws is replaced by the default\n * part (`DK_RENDER_FAILED` at `components.<name>`) until another component is passed.\n */\nfunction part<P extends object>(\n table: object,\n name: 'SearchInput' | 'Pagination',\n Custom: ComponentType<P> | undefined,\n Default: ComponentType<P>,\n props: P,\n): ReactNode {\n if (!Custom) return <Default {...props} />\n return (\n <Boundary\n table={table}\n slot={`components.${name}`}\n resetKey={Custom}\n fallback={() => <Default {...props} />}\n >\n <Custom {...props} />\n </Boundary>\n )\n}\n\nfunction stateRow(span: number, kind: string, content: ReactNode) {\n return (\n <tr data-dk-state={kind}>\n <td colSpan={span}>{content}</td>\n </tr>\n )\n}\n\n// --- error boundaries (DK_RENDER_FAILED) ---------------------------------------------------------\n\ninterface BoundaryProps {\n table: object\n /**\n * A part outside the body: `components.SearchInput` (reported as the slot). A cell boundary:\n * `cell` / `invalidCell` (reported as `columns[<index>].<slot>`).\n */\n slot?: string\n /** A cell boundary (`render:cell`): the cell's column. A new `def` renders a failed cell again. */\n col?: Column\n /** A cell boundary: the row's index in the data (`row.index`). */\n row?: number\n /** A new value (the next row model; a cell's row data) renders the children again. */\n resetKey: unknown\n fallback(retry: () => void): ReactNode\n children: ReactNode\n}\n\ninterface BoundaryState {\n failed: boolean\n key: unknown\n def: ColumnLike | undefined\n}\n\n/**\n * Catches a component that throws (`DK_RENDER_FAILED`) and renders `fallback` instead; the rest of\n * the table keeps working. Three uses: the body outside any cell (`render:table`, §10: a\n * `components.Empty` / `Loading` / `Error` part) shows the Error state; a custom search / pager\n * part (`render:table` at `components.<name>`) is replaced by the default part; and one cell\n * (`render:cell`, §3.4, with `col`): a component returned by `cell` / `invalidCell` renders `⚠` in\n * that cell only (deduped per column). A cell boundary only wraps object content (see `guard`).\n */\nclass Boundary extends Component<BoundaryProps, BoundaryState> {\n override state: BoundaryState = {\n failed: false,\n key: this.props.resetKey,\n def: this.props.col?.def,\n }\n\n static getDerivedStateFromError() {\n return { failed: true }\n }\n\n static getDerivedStateFromProps(props: BoundaryProps, state: BoundaryState) {\n const def = props.col?.def\n return props.resetKey === state.key && def === state.def\n ? null\n : { failed: false, key: props.resetKey, def }\n }\n\n override componentDidCatch(error: unknown) {\n const { table, col, slot, row } = this.props\n try {\n emitTableDiagnostic(\n table,\n 'DK_RENDER_FAILED',\n {\n op: col ? 'render:cell' : 'render:table',\n ...(slot ? { slot: col ? `columns[${col.index}].${slot}` : slot } : {}),\n ...(col ? { column: col.id, row: row as number } : {}),\n ...(error instanceof Error ? { errorName: error.name } : {}),\n },\n { cause: error },\n )\n } catch {\n // Not a table made by createTable: nothing to report to.\n }\n }\n\n retry = () => this.setState({ failed: false })\n\n override render() {\n return this.state.failed ? this.props.fallback(this.retry) : this.props.children\n }\n}\n\n/** A failed cell's fallback (one function for every cell boundary: no closure per cell). */\nconst failedCell = () => FAILED\n\n// --- default parts (unstyled) --------------------------------------------------------------------\n\nfunction DefaultSearchInput({\n value,\n status,\n onChange,\n onSubmit,\n onClear,\n label,\n}: SearchInputProps) {\n return (\n <>\n <input\n type=\"search\"\n aria-label={label}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') onSubmit()\n else if (e.key === 'Escape') onClear()\n }}\n />\n {(status === 'pending' || status === 'searching') && (\n // Decorative: the live region says \"Searching…\" (an empty status announces nothing).\n <span data-dk-spinner=\"\" aria-hidden=\"true\" />\n )}\n </>\n )\n}\n\n/**\n * `aria-disabled`, not `disabled`, at the first / last page: a disabled button loses focus (to\n * `<body>`) the moment paging makes it unavailable (#55).\n */\nfunction DefaultPagination(p: PaginationProps) {\n return (\n <nav aria-label={p.label} data-dk-pagination=\"\">\n <button\n type=\"button\"\n aria-label=\"Previous page\"\n aria-disabled={!p.canPrev || undefined}\n onClick={p.canPrev ? p.prev : undefined}\n >\n ‹\n </button>\n <span data-dk-page=\"\">\n Page {p.pageIndex + 1} of {Math.max(p.pageCount, 1)}\n </span>\n <button\n type=\"button\"\n aria-label=\"Next page\"\n aria-disabled={!p.canNext || undefined}\n onClick={p.canNext ? p.next : undefined}\n >\n ›\n </button>\n </nav>\n )\n}\n\nconst DefaultEmpty = ({ filtered }: EmptyProps) => <>{filtered ? 'No matching rows' : 'No rows'}</>\n\nconst DefaultLoading = (_: LoadingProps) => <span role=\"status\">Loading…</span>\n\nfunction DefaultError({ reason, retry }: ErrorProps) {\n return (\n <div role=\"alert\">\n {reason === 'load' ? 'Could not load the rows.' : 'Could not display the rows.'}{' '}\n <button type=\"button\" onClick={retry}>\n Retry\n </button>\n </div>\n )\n}\n\n/** Over stale rows (§6.6): the table is busy, or a later update failed. */\nfunction RefreshIndicator({ status, retry }: { status: RowModelStatus; retry(): void }) {\n if (status === 'error') {\n return (\n <div data-dk-refresh=\"\" data-status={status} role=\"alert\">\n Could not refresh; showing the previous rows.{' '}\n <button type=\"button\" onClick={retry}>\n Retry\n </button>\n </div>\n )\n }\n return (\n <div data-dk-refresh=\"\" data-status={status} role=\"status\">\n Updating…\n </div>\n )\n}\n"],"mappings":"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","names":["e","n"]}
|
package/dist/index.cjs
CHANGED
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from '@datakable/core'\nexport { reactDiagnostics } from './codes'\nexport {\n DataTable,\n type DataTableComponents,\n type DataTableOwnProps,\n type DataTableProps,\n type DataTableSource,\n type EmptyProps,\n type ErrorProps,\n type LoadingProps,\n type PaginationProps,\n type SearchInputProps,\n} from './data-table'\nexport { cellSlot, invalidCellSlot, renderDiagnostics, renderMessages } from './render-codes'\nexport { type UseDataTableOptions, type UseDataTableResult, useDataTable } from './use-data-table'\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from '@datakable/core'\nexport { reactDiagnostics } from './codes'\nexport {\n DataTable,\n type DataTableComponents,\n type DataTableOwnProps,\n type DataTableProps,\n type DataTableSource,\n type EmptyProps,\n type ErrorProps,\n type LoadingProps,\n type PaginationProps,\n type SearchInputProps,\n} from './data-table'\nexport { cellSlot, invalidCellSlot, renderDiagnostics, renderMessages } from './render-codes'\nexport { type UseDataTableOptions, type UseDataTableResult, useDataTable } from './use-data-table'\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAAc,4BAAd;AACA,mBAAiC;AACjC,wBAWO;AACP,0BAA6E;AAC7E,4BAAgF;","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -89,6 +89,8 @@ interface SearchInputProps {
|
|
|
89
89
|
onSubmit(): void;
|
|
90
90
|
/** `clearSearch()` (Esc). */
|
|
91
91
|
onClear(): void;
|
|
92
|
+
/** The input's accessible name: `'Search <caption>'` with a text `caption`, else `'Search'`. */
|
|
93
|
+
label: string;
|
|
92
94
|
}
|
|
93
95
|
/** Props of `components.Pagination` (the pagination feature's state and API). */
|
|
94
96
|
interface PaginationProps {
|
|
@@ -101,6 +103,8 @@ interface PaginationProps {
|
|
|
101
103
|
next(): void;
|
|
102
104
|
setPageIndex(index: number): void;
|
|
103
105
|
setPageSize(size: number): void;
|
|
106
|
+
/** The pager's accessible name: `'<caption> pagination'` with a text `caption`, else `'Pagination'`. */
|
|
107
|
+
label: string;
|
|
104
108
|
}
|
|
105
109
|
/** Props of `components.Empty`: shown when the table has loaded and has no rows to show. */
|
|
106
110
|
interface EmptyProps {
|
|
@@ -191,7 +195,10 @@ declare module '@datakable/core' {
|
|
|
191
195
|
* `invalidCell`) or `render:table` (the body boundary: a component outside the cells).
|
|
192
196
|
*/
|
|
193
197
|
op: 'render:table' | 'render:cell';
|
|
194
|
-
/**
|
|
198
|
+
/**
|
|
199
|
+
* The slot whose component threw: `columns[1].cell` (`render:cell`), or a part outside the
|
|
200
|
+
* body, `components.SearchInput` / `components.Pagination` (`render:table`).
|
|
201
|
+
*/
|
|
195
202
|
slot?: string;
|
|
196
203
|
/** `render:cell`: the column id. */
|
|
197
204
|
column?: string;
|
|
@@ -226,13 +233,13 @@ declare module '@datakable/core' {
|
|
|
226
233
|
declare const cellSlot: {
|
|
227
234
|
readonly name: "cell";
|
|
228
235
|
readonly returns: "sync";
|
|
229
|
-
readonly fallback: "
|
|
236
|
+
readonly fallback: "cells-warn";
|
|
230
237
|
};
|
|
231
238
|
/** `columns[i].invalidCell` (§5.1): renders a flagged cell; same contract as `cell`. */
|
|
232
239
|
declare const invalidCellSlot: {
|
|
233
240
|
readonly name: "invalidCell";
|
|
234
241
|
readonly returns: "sync";
|
|
235
|
-
readonly fallback: "
|
|
242
|
+
readonly fallback: "cells-warn";
|
|
236
243
|
};
|
|
237
244
|
/** Message text (§8.2): development builds, or production via `datakable/messages`. */
|
|
238
245
|
declare const renderMessages: DiagnosticMessages<'DK_RENDER_FAILED'>;
|
package/dist/index.d.ts
CHANGED
|
@@ -89,6 +89,8 @@ interface SearchInputProps {
|
|
|
89
89
|
onSubmit(): void;
|
|
90
90
|
/** `clearSearch()` (Esc). */
|
|
91
91
|
onClear(): void;
|
|
92
|
+
/** The input's accessible name: `'Search <caption>'` with a text `caption`, else `'Search'`. */
|
|
93
|
+
label: string;
|
|
92
94
|
}
|
|
93
95
|
/** Props of `components.Pagination` (the pagination feature's state and API). */
|
|
94
96
|
interface PaginationProps {
|
|
@@ -101,6 +103,8 @@ interface PaginationProps {
|
|
|
101
103
|
next(): void;
|
|
102
104
|
setPageIndex(index: number): void;
|
|
103
105
|
setPageSize(size: number): void;
|
|
106
|
+
/** The pager's accessible name: `'<caption> pagination'` with a text `caption`, else `'Pagination'`. */
|
|
107
|
+
label: string;
|
|
104
108
|
}
|
|
105
109
|
/** Props of `components.Empty`: shown when the table has loaded and has no rows to show. */
|
|
106
110
|
interface EmptyProps {
|
|
@@ -191,7 +195,10 @@ declare module '@datakable/core' {
|
|
|
191
195
|
* `invalidCell`) or `render:table` (the body boundary: a component outside the cells).
|
|
192
196
|
*/
|
|
193
197
|
op: 'render:table' | 'render:cell';
|
|
194
|
-
/**
|
|
198
|
+
/**
|
|
199
|
+
* The slot whose component threw: `columns[1].cell` (`render:cell`), or a part outside the
|
|
200
|
+
* body, `components.SearchInput` / `components.Pagination` (`render:table`).
|
|
201
|
+
*/
|
|
195
202
|
slot?: string;
|
|
196
203
|
/** `render:cell`: the column id. */
|
|
197
204
|
column?: string;
|
|
@@ -226,13 +233,13 @@ declare module '@datakable/core' {
|
|
|
226
233
|
declare const cellSlot: {
|
|
227
234
|
readonly name: "cell";
|
|
228
235
|
readonly returns: "sync";
|
|
229
|
-
readonly fallback: "
|
|
236
|
+
readonly fallback: "cells-warn";
|
|
230
237
|
};
|
|
231
238
|
/** `columns[i].invalidCell` (§5.1): renders a flagged cell; same contract as `cell`. */
|
|
232
239
|
declare const invalidCellSlot: {
|
|
233
240
|
readonly name: "invalidCell";
|
|
234
241
|
readonly returns: "sync";
|
|
235
|
-
readonly fallback: "
|
|
242
|
+
readonly fallback: "cells-warn";
|
|
236
243
|
};
|
|
237
244
|
/** Message text (§8.2): development builds, or production via `datakable/messages`. */
|
|
238
245
|
declare const renderMessages: DiagnosticMessages<'DK_RENDER_FAILED'>;
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from '@datakable/core'\nexport { reactDiagnostics } from './codes'\nexport {\n DataTable,\n type DataTableComponents,\n type DataTableOwnProps,\n type DataTableProps,\n type DataTableSource,\n type EmptyProps,\n type ErrorProps,\n type LoadingProps,\n type PaginationProps,\n type SearchInputProps,\n} from './data-table'\nexport { cellSlot, invalidCellSlot, renderDiagnostics, renderMessages } from './render-codes'\nexport { type UseDataTableOptions, type UseDataTableResult, useDataTable } from './use-data-table'\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from '@datakable/core'\nexport { reactDiagnostics } from './codes'\nexport {\n DataTable,\n type DataTableComponents,\n type DataTableOwnProps,\n type DataTableProps,\n type DataTableSource,\n type EmptyProps,\n type ErrorProps,\n type LoadingProps,\n type PaginationProps,\n type SearchInputProps,\n} from './data-table'\nexport { cellSlot, invalidCellSlot, renderDiagnostics, renderMessages } from './render-codes'\nexport { type UseDataTableOptions, type UseDataTableResult, useDataTable } from './use-data-table'\n"],"mappings":";AAAA,cAAc;AACd,SAAS,wBAAwB;AACjC;AAAA,EACE;AAAA,OAUK;AACP,SAAS,UAAU,iBAAiB,mBAAmB,sBAAsB;AAC7E,SAA4D,oBAAoB;","names":[]}
|
package/dist/render-codes.cjs
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use client";
|
|
2
1
|
"use strict";
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -36,17 +35,19 @@ function registerRenderOperations() {
|
|
|
36
35
|
var cellSlot = (0, import_core.defineSlot)({
|
|
37
36
|
name: "cell",
|
|
38
37
|
returns: "sync",
|
|
39
|
-
fallback: "
|
|
38
|
+
fallback: "cells-warn"
|
|
39
|
+
// prose key: 'those cells rendered ⚠' (core diagnostics/prose.ts)
|
|
40
40
|
});
|
|
41
41
|
var invalidCellSlot = (0, import_core.defineSlot)({
|
|
42
42
|
name: "invalidCell",
|
|
43
43
|
returns: "sync",
|
|
44
|
-
fallback: "
|
|
44
|
+
fallback: "cells-warn"
|
|
45
|
+
// prose key: 'those cells rendered ⚠' (core diagnostics/prose.ts)
|
|
45
46
|
});
|
|
46
47
|
var renderMessages = {
|
|
47
48
|
DK_RENDER_FAILED: {
|
|
48
|
-
problem: (d) => d.op === "render:cell" ? `a component returned by ${d.slot} (column "${d.column}") threw${d.errorName ? ` ${d.errorName}` : ""} while rendering row #${d.row}` : `a component rendered inside the table body threw${d.errorName ? ` ${d.errorName}` : ""} (outside the cells: a components.Empty / Loading / Error part)`,
|
|
49
|
-
impact: (d) => d.op === "render:cell" ? "that cell renders \u26A0; the other cells and rows, the header, search, pagination and the table API keep working, and the cell renders again when its row's data or the columns change" : "the table body shows the Error state; the header, search and pagination keep working, and the body renders again on the next row model or Retry",
|
|
49
|
+
problem: (d) => d.op === "render:cell" ? `a component returned by ${d.slot} (column "${d.column}") threw${d.errorName ? ` ${d.errorName}` : ""} while rendering row #${d.row}` : d.slot ? `the ${d.slot} component threw${d.errorName ? ` ${d.errorName}` : ""}` : `a component rendered inside the table body threw${d.errorName ? ` ${d.errorName}` : ""} (outside the cells: a components.Empty / Loading / Error part)`,
|
|
50
|
+
impact: (d) => d.op === "render:cell" ? "that cell renders \u26A0; the other cells and rows, the header, search, pagination and the table API keep working, and the cell renders again when its row's data or the columns change" : d.slot ? "the default part renders in its place, bound to the table, until another component is passed; the rest of the table keeps working" : "the table body shows the Error state; the header, search and pagination keep working, and the body renders again on the next row model or Retry",
|
|
50
51
|
fix: (d) => d.op === "render:cell" ? [
|
|
51
52
|
`find the throwing component in context.cause (passed to onDiagnostic) and make it total: guard null / undefined / unexpected values of column "${d.column}" instead of throwing`,
|
|
52
53
|
`for your own fallback instead of \u26A0, wrap the component in an error boundary inside ${d.slot}`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/render-codes.ts"],"sourcesContent":["import {\n type DiagnosticMessages,\n defineDiagnostic,\n defineSlot,\n registerOperation,\n} from '@datakable/core'\n\ndeclare module '@datakable/core' {\n interface DiagnosticCatalog {\n DK_RENDER_FAILED: {\n /**\n * The render operation: `render:cell` (a cell's boundary: a component returned by `cell` /\n * `invalidCell`) or `render:table` (the body boundary: a component outside the cells).\n */\n op: 'render:table' | 'render:cell'\n
|
|
1
|
+
{"version":3,"sources":["../src/render-codes.ts"],"sourcesContent":["import {\n type DiagnosticMessages,\n defineDiagnostic,\n defineSlot,\n registerOperation,\n} from '@datakable/core'\n\ndeclare module '@datakable/core' {\n interface DiagnosticCatalog {\n DK_RENDER_FAILED: {\n /**\n * The render operation: `render:cell` (a cell's boundary: a component returned by `cell` /\n * `invalidCell`) or `render:table` (the body boundary: a component outside the cells).\n */\n op: 'render:table' | 'render:cell'\n /**\n * The slot whose component threw: `columns[1].cell` (`render:cell`), or a part outside the\n * body, `components.SearchInput` / `components.Pagination` (`render:table`).\n */\n slot?: string\n /** `render:cell`: the column id. */\n column?: string\n /** `render:cell`: the row's index in the data (the first failure; later ones are deduped). */\n row?: number\n /** `error.name` only; the full error is `context.cause`. */\n errorName?: string\n }\n }\n\n /** §3.4: React error boundaries, not interceptor chains (nothing runs interceptors on them). */\n interface Operations {\n 'render:table': { kind: 'sync'; input: undefined; output: undefined }\n 'render:cell': {\n kind: 'sync'\n input: { column: string; slot: 'cell' | 'invalidCell'; row: number }\n output: undefined\n }\n }\n}\n\n/**\n * Registers `render:table` / `render:cell` (§3.4: owned by `@datakable/react`, not core). Neither\n * is hot: no interceptor chain runs per cell, so `on: '*'` interceptors get no hot-op warning for\n * them. Idempotent (an identical re-registration is a no-op).\n */\nexport function registerRenderOperations(): void {\n registerOperation('render:table', { kind: 'sync', hot: false })\n registerOperation('render:cell', { kind: 'sync', hot: false })\n}\n\n// No @types/node here: declare just what is read.\ndeclare const process: { env: { NODE_ENV?: string } }\n\n/**\n * `columns[i].cell` (§4.1, §10): renders a React node synchronously. A thenable is a contract\n * violation (`DK_CALLBACK_BAD_RETURN`); `<DataTable />` renders `⚠` instead.\n */\nexport const cellSlot = defineSlot({\n name: 'cell',\n returns: 'sync',\n fallback: 'cells-warn', // prose key: 'those cells rendered ⚠' (core diagnostics/prose.ts)\n})\n\n/** `columns[i].invalidCell` (§5.1): renders a flagged cell; same contract as `cell`. */\nexport const invalidCellSlot = defineSlot({\n name: 'invalidCell',\n returns: 'sync',\n fallback: 'cells-warn', // prose key: 'those cells rendered ⚠' (core diagnostics/prose.ts)\n})\n\n/** Message text (§8.2): development builds, or production via `datakable/messages`. */\nexport const renderMessages: DiagnosticMessages<'DK_RENDER_FAILED'> = {\n DK_RENDER_FAILED: {\n problem: (d) =>\n d.op === 'render:cell'\n ? `a component returned by ${d.slot} (column \"${d.column}\") threw` +\n `${d.errorName ? ` ${d.errorName}` : ''} while rendering row #${d.row}`\n : d.slot\n ? `the ${d.slot} component threw${d.errorName ? ` ${d.errorName}` : ''}`\n : `a component rendered inside the table body threw${d.errorName ? ` ${d.errorName}` : ''} ` +\n '(outside the cells: a components.Empty / Loading / Error part)',\n impact: (d) =>\n d.op === 'render:cell'\n ? 'that cell renders ⚠; the other cells and rows, the header, search, pagination and the ' +\n \"table API keep working, and the cell renders again when its row's data or the columns \" +\n 'change'\n : d.slot\n ? 'the default part renders in its place, bound to the table, until another component ' +\n 'is passed; the rest of the table keeps working'\n : 'the table body shows the Error state; the header, search and pagination keep working, ' +\n 'and the body renders again on the next row model or Retry',\n fix: (d) =>\n d.op === 'render:cell'\n ? [\n `find the throwing component in context.cause (passed to onDiagnostic) and make it ` +\n `total: guard null / undefined / unexpected values of column \"${d.column}\" ` +\n 'instead of throwing',\n 'for your own fallback instead of ⚠, wrap the component in an error boundary inside ' +\n `${d.slot}`,\n ]\n : [\n 'find the throwing component in context.cause (passed to onDiagnostic) and make it ' +\n 'total: guard null / undefined / unexpected values instead of throwing',\n 'a component returned by a column cell / invalidCell is caught per cell (⚠); a throw in ' +\n 'the cell function itself is DK_CALLBACK_FAILED',\n ],\n },\n}\n\n/** Codes owned by `<DataTable />` (§8.3, react). Emitted in production too; text behind NODE_ENV. */\nexport const renderDiagnostics = [\n defineDiagnostic(\n {\n code: 'DK_RENDER_FAILED',\n level: 'error',\n where: (d) =>\n d.slot ? { kind: 'operation', op: d.op, slot: d.slot } : { kind: 'operation', op: d.op },\n },\n // Written out (not an imported flag) so a consumer's bundler folds it while parsing (§8.2).\n process.env.NODE_ENV !== 'production' && renderMessages.DK_RENDER_FAILED,\n ),\n]\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAKO;AAwCA,SAAS,2BAAiC;AAC/C,qCAAkB,gBAAgB,EAAE,MAAM,QAAQ,KAAK,MAAM,CAAC;AAC9D,qCAAkB,eAAe,EAAE,MAAM,QAAQ,KAAK,MAAM,CAAC;AAC/D;AASO,IAAM,eAAW,wBAAW;AAAA,EACjC,MAAM;AAAA,EACN,SAAS;AAAA,EACT,UAAU;AAAA;AACZ,CAAC;AAGM,IAAM,sBAAkB,wBAAW;AAAA,EACxC,MAAM;AAAA,EACN,SAAS;AAAA,EACT,UAAU;AAAA;AACZ,CAAC;AAGM,IAAM,iBAAyD;AAAA,EACpE,kBAAkB;AAAA,IAChB,SAAS,CAAC,MACR,EAAE,OAAO,gBACL,2BAA2B,EAAE,IAAI,aAAa,EAAE,MAAM,WACnD,EAAE,YAAY,IAAI,EAAE,SAAS,KAAK,EAAE,yBAAyB,EAAE,GAAG,KACrE,EAAE,OACA,OAAO,EAAE,IAAI,mBAAmB,EAAE,YAAY,IAAI,EAAE,SAAS,KAAK,EAAE,KACpE,mDAAmD,EAAE,YAAY,IAAI,EAAE,SAAS,KAAK,EAAE;AAAA,IAE/F,QAAQ,CAAC,MACP,EAAE,OAAO,gBACL,4LAGA,EAAE,OACA,sIAEA;AAAA,IAER,KAAK,CAAC,MACJ,EAAE,OAAO,gBACL;AAAA,MACE,kJACkE,EAAE,MAAM;AAAA,MAE1E,2FACK,EAAE,IAAI;AAAA,IACb,IACA;AAAA,MACE;AAAA,MAEA;AAAA,IAEF;AAAA,EACR;AACF;AAGO,IAAM,oBAAoB;AAAA,MAC/B;AAAA,IACE;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,OAAO,CAAC,MACN,EAAE,OAAO,EAAE,MAAM,aAAa,IAAI,EAAE,IAAI,MAAM,EAAE,KAAK,IAAI,EAAE,MAAM,aAAa,IAAI,EAAE,GAAG;AAAA,IAC3F;AAAA;AAAA,IAEA,QAAQ,IAAI,aAAa,gBAAgB,eAAe;AAAA,EAC1D;AACF;","names":[]}
|
package/dist/render-codes.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
1
|
// src/render-codes.ts
|
|
4
2
|
import {
|
|
5
3
|
defineDiagnostic,
|
|
@@ -13,17 +11,19 @@ function registerRenderOperations() {
|
|
|
13
11
|
var cellSlot = defineSlot({
|
|
14
12
|
name: "cell",
|
|
15
13
|
returns: "sync",
|
|
16
|
-
fallback: "
|
|
14
|
+
fallback: "cells-warn"
|
|
15
|
+
// prose key: 'those cells rendered ⚠' (core diagnostics/prose.ts)
|
|
17
16
|
});
|
|
18
17
|
var invalidCellSlot = defineSlot({
|
|
19
18
|
name: "invalidCell",
|
|
20
19
|
returns: "sync",
|
|
21
|
-
fallback: "
|
|
20
|
+
fallback: "cells-warn"
|
|
21
|
+
// prose key: 'those cells rendered ⚠' (core diagnostics/prose.ts)
|
|
22
22
|
});
|
|
23
23
|
var renderMessages = {
|
|
24
24
|
DK_RENDER_FAILED: {
|
|
25
|
-
problem: (d) => d.op === "render:cell" ? `a component returned by ${d.slot} (column "${d.column}") threw${d.errorName ? ` ${d.errorName}` : ""} while rendering row #${d.row}` : `a component rendered inside the table body threw${d.errorName ? ` ${d.errorName}` : ""} (outside the cells: a components.Empty / Loading / Error part)`,
|
|
26
|
-
impact: (d) => d.op === "render:cell" ? "that cell renders \u26A0; the other cells and rows, the header, search, pagination and the table API keep working, and the cell renders again when its row's data or the columns change" : "the table body shows the Error state; the header, search and pagination keep working, and the body renders again on the next row model or Retry",
|
|
25
|
+
problem: (d) => d.op === "render:cell" ? `a component returned by ${d.slot} (column "${d.column}") threw${d.errorName ? ` ${d.errorName}` : ""} while rendering row #${d.row}` : d.slot ? `the ${d.slot} component threw${d.errorName ? ` ${d.errorName}` : ""}` : `a component rendered inside the table body threw${d.errorName ? ` ${d.errorName}` : ""} (outside the cells: a components.Empty / Loading / Error part)`,
|
|
26
|
+
impact: (d) => d.op === "render:cell" ? "that cell renders \u26A0; the other cells and rows, the header, search, pagination and the table API keep working, and the cell renders again when its row's data or the columns change" : d.slot ? "the default part renders in its place, bound to the table, until another component is passed; the rest of the table keeps working" : "the table body shows the Error state; the header, search and pagination keep working, and the body renders again on the next row model or Retry",
|
|
27
27
|
fix: (d) => d.op === "render:cell" ? [
|
|
28
28
|
`find the throwing component in context.cause (passed to onDiagnostic) and make it total: guard null / undefined / unexpected values of column "${d.column}" instead of throwing`,
|
|
29
29
|
`for your own fallback instead of \u26A0, wrap the component in an error boundary inside ${d.slot}`
|
package/dist/render-codes.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/render-codes.ts"],"sourcesContent":["import {\n type DiagnosticMessages,\n defineDiagnostic,\n defineSlot,\n registerOperation,\n} from '@datakable/core'\n\ndeclare module '@datakable/core' {\n interface DiagnosticCatalog {\n DK_RENDER_FAILED: {\n /**\n * The render operation: `render:cell` (a cell's boundary: a component returned by `cell` /\n * `invalidCell`) or `render:table` (the body boundary: a component outside the cells).\n */\n op: 'render:table' | 'render:cell'\n
|
|
1
|
+
{"version":3,"sources":["../src/render-codes.ts"],"sourcesContent":["import {\n type DiagnosticMessages,\n defineDiagnostic,\n defineSlot,\n registerOperation,\n} from '@datakable/core'\n\ndeclare module '@datakable/core' {\n interface DiagnosticCatalog {\n DK_RENDER_FAILED: {\n /**\n * The render operation: `render:cell` (a cell's boundary: a component returned by `cell` /\n * `invalidCell`) or `render:table` (the body boundary: a component outside the cells).\n */\n op: 'render:table' | 'render:cell'\n /**\n * The slot whose component threw: `columns[1].cell` (`render:cell`), or a part outside the\n * body, `components.SearchInput` / `components.Pagination` (`render:table`).\n */\n slot?: string\n /** `render:cell`: the column id. */\n column?: string\n /** `render:cell`: the row's index in the data (the first failure; later ones are deduped). */\n row?: number\n /** `error.name` only; the full error is `context.cause`. */\n errorName?: string\n }\n }\n\n /** §3.4: React error boundaries, not interceptor chains (nothing runs interceptors on them). */\n interface Operations {\n 'render:table': { kind: 'sync'; input: undefined; output: undefined }\n 'render:cell': {\n kind: 'sync'\n input: { column: string; slot: 'cell' | 'invalidCell'; row: number }\n output: undefined\n }\n }\n}\n\n/**\n * Registers `render:table` / `render:cell` (§3.4: owned by `@datakable/react`, not core). Neither\n * is hot: no interceptor chain runs per cell, so `on: '*'` interceptors get no hot-op warning for\n * them. Idempotent (an identical re-registration is a no-op).\n */\nexport function registerRenderOperations(): void {\n registerOperation('render:table', { kind: 'sync', hot: false })\n registerOperation('render:cell', { kind: 'sync', hot: false })\n}\n\n// No @types/node here: declare just what is read.\ndeclare const process: { env: { NODE_ENV?: string } }\n\n/**\n * `columns[i].cell` (§4.1, §10): renders a React node synchronously. A thenable is a contract\n * violation (`DK_CALLBACK_BAD_RETURN`); `<DataTable />` renders `⚠` instead.\n */\nexport const cellSlot = defineSlot({\n name: 'cell',\n returns: 'sync',\n fallback: 'cells-warn', // prose key: 'those cells rendered ⚠' (core diagnostics/prose.ts)\n})\n\n/** `columns[i].invalidCell` (§5.1): renders a flagged cell; same contract as `cell`. */\nexport const invalidCellSlot = defineSlot({\n name: 'invalidCell',\n returns: 'sync',\n fallback: 'cells-warn', // prose key: 'those cells rendered ⚠' (core diagnostics/prose.ts)\n})\n\n/** Message text (§8.2): development builds, or production via `datakable/messages`. */\nexport const renderMessages: DiagnosticMessages<'DK_RENDER_FAILED'> = {\n DK_RENDER_FAILED: {\n problem: (d) =>\n d.op === 'render:cell'\n ? `a component returned by ${d.slot} (column \"${d.column}\") threw` +\n `${d.errorName ? ` ${d.errorName}` : ''} while rendering row #${d.row}`\n : d.slot\n ? `the ${d.slot} component threw${d.errorName ? ` ${d.errorName}` : ''}`\n : `a component rendered inside the table body threw${d.errorName ? ` ${d.errorName}` : ''} ` +\n '(outside the cells: a components.Empty / Loading / Error part)',\n impact: (d) =>\n d.op === 'render:cell'\n ? 'that cell renders ⚠; the other cells and rows, the header, search, pagination and the ' +\n \"table API keep working, and the cell renders again when its row's data or the columns \" +\n 'change'\n : d.slot\n ? 'the default part renders in its place, bound to the table, until another component ' +\n 'is passed; the rest of the table keeps working'\n : 'the table body shows the Error state; the header, search and pagination keep working, ' +\n 'and the body renders again on the next row model or Retry',\n fix: (d) =>\n d.op === 'render:cell'\n ? [\n `find the throwing component in context.cause (passed to onDiagnostic) and make it ` +\n `total: guard null / undefined / unexpected values of column \"${d.column}\" ` +\n 'instead of throwing',\n 'for your own fallback instead of ⚠, wrap the component in an error boundary inside ' +\n `${d.slot}`,\n ]\n : [\n 'find the throwing component in context.cause (passed to onDiagnostic) and make it ' +\n 'total: guard null / undefined / unexpected values instead of throwing',\n 'a component returned by a column cell / invalidCell is caught per cell (⚠); a throw in ' +\n 'the cell function itself is DK_CALLBACK_FAILED',\n ],\n },\n}\n\n/** Codes owned by `<DataTable />` (§8.3, react). Emitted in production too; text behind NODE_ENV. */\nexport const renderDiagnostics = [\n defineDiagnostic(\n {\n code: 'DK_RENDER_FAILED',\n level: 'error',\n where: (d) =>\n d.slot ? { kind: 'operation', op: d.op, slot: d.slot } : { kind: 'operation', op: d.op },\n },\n // Written out (not an imported flag) so a consumer's bundler folds it while parsing (§8.2).\n process.env.NODE_ENV !== 'production' && renderMessages.DK_RENDER_FAILED,\n ),\n]\n"],"mappings":";AAAA;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAwCA,SAAS,2BAAiC;AAC/C,oBAAkB,gBAAgB,EAAE,MAAM,QAAQ,KAAK,MAAM,CAAC;AAC9D,oBAAkB,eAAe,EAAE,MAAM,QAAQ,KAAK,MAAM,CAAC;AAC/D;AASO,IAAM,WAAW,WAAW;AAAA,EACjC,MAAM;AAAA,EACN,SAAS;AAAA,EACT,UAAU;AAAA;AACZ,CAAC;AAGM,IAAM,kBAAkB,WAAW;AAAA,EACxC,MAAM;AAAA,EACN,SAAS;AAAA,EACT,UAAU;AAAA;AACZ,CAAC;AAGM,IAAM,iBAAyD;AAAA,EACpE,kBAAkB;AAAA,IAChB,SAAS,CAAC,MACR,EAAE,OAAO,gBACL,2BAA2B,EAAE,IAAI,aAAa,EAAE,MAAM,WACnD,EAAE,YAAY,IAAI,EAAE,SAAS,KAAK,EAAE,yBAAyB,EAAE,GAAG,KACrE,EAAE,OACA,OAAO,EAAE,IAAI,mBAAmB,EAAE,YAAY,IAAI,EAAE,SAAS,KAAK,EAAE,KACpE,mDAAmD,EAAE,YAAY,IAAI,EAAE,SAAS,KAAK,EAAE;AAAA,IAE/F,QAAQ,CAAC,MACP,EAAE,OAAO,gBACL,4LAGA,EAAE,OACA,sIAEA;AAAA,IAER,KAAK,CAAC,MACJ,EAAE,OAAO,gBACL;AAAA,MACE,kJACkE,EAAE,MAAM;AAAA,MAE1E,2FACK,EAAE,IAAI;AAAA,IACb,IACA;AAAA,MACE;AAAA,MAEA;AAAA,IAEF;AAAA,EACR;AACF;AAGO,IAAM,oBAAoB;AAAA,EAC/B;AAAA,IACE;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,OAAO,CAAC,MACN,EAAE,OAAO,EAAE,MAAM,aAAa,IAAI,EAAE,IAAI,MAAM,EAAE,KAAK,IAAI,EAAE,MAAM,aAAa,IAAI,EAAE,GAAG;AAAA,IAC3F;AAAA;AAAA,IAEA,QAAQ,IAAI,aAAa,gBAAgB,eAAe;AAAA,EAC1D;AACF;","names":[]}
|
package/dist/styles.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
:where([data-datakable]){--dk-font-size: .875rem;--dk-fg: #1f2328;--dk-muted: #59636e;--dk-bg: #fff;--dk-subtle: #f6f8fa;--dk-border: #d1d9e0;--dk-accent: #0969da;--dk-danger: #d1242f;--dk-danger-bg: #ffebe9;--dk-radius: 6px;--dk-cell-py: .5rem;--dk-cell-px: .75rem;font-size:var(--dk-font-size);color:var(--dk-fg);background:var(--dk-bg);font-variant-numeric:tabular-nums}@media(prefers-color-scheme:dark){:where([data-datakable]){--dk-fg: #f0f6fc;--dk-muted: #9198a1;--dk-bg: #0d1117;--dk-subtle: #151b23;--dk-border: #3d444d;--dk-accent: #4493f8;--dk-danger: #f85149;--dk-danger-bg: #25171c}}:where([data-datakable] table){width:100%;border-collapse:collapse}:where([data-datakable] caption){padding:var(--dk-cell-py) var(--dk-cell-px);color:var(--dk-muted);text-align:start}:where([data-datakable] th,[data-datakable] td){padding:var(--dk-cell-py) var(--dk-cell-px);border-bottom:1px solid var(--dk-border);text-align:start}:where([data-datakable] thead th){background:var(--dk-subtle);font-weight:600;white-space:nowrap}:where([data-datakable] tbody tr:hover){background:var(--dk-subtle)}:where([data-datakable] button){font:inherit;color:inherit;padding:.25rem .625rem;background:var(--dk-bg);border:1px solid var(--dk-border);border-radius:var(--dk-radius);cursor:pointer}:where([data-datakable] button:disabled){opacity:.5;cursor:not-allowed}:where([data-datakable] button:focus-visible,[data-datakable] input:focus-visible){outline:2px solid var(--dk-accent);outline-offset:1px}:where([data-datakable] th[aria-sort] button){font-weight:inherit;padding:0;background:none;border:0}:where([data-datakable] th[aria-sort=ascending],[data-datakable] th[aria-sort=descending]){color:var(--dk-accent)}:where([data-datakable] [data-dk-sort-indicator]){font-size:.75em}:where([data-datakable] [data-dk-search]){display:flex;align-items:center;gap:.5rem;margin-bottom:.5rem}:where([data-datakable] [data-dk-search] input){font:inherit;color:inherit;min-width:12rem;padding:.375rem .625rem;background:var(--dk-bg);border:1px solid var(--dk-border);border-radius:var(--dk-radius)}:where([data-datakable] [data-dk-spinner]){width:1em;height:1em;border:2px solid var(--dk-border);border-top-color:var(--dk-accent);border-radius:50%;animation:dk-spin .7s linear infinite}@keyframes dk-spin{to{transform:rotate(1turn)}}:where([data-datakable] [data-dk-state] td){padding:2rem var(--dk-cell-px);color:var(--dk-muted);text-align:center}:where([data-datakable] tr[data-dk-state]:hover){background:none}:where([data-datakable] [data-dk-state=loading] td){font-style:italic}:where([data-datakable] [data-dk-state=error] td){color:var(--dk-danger)}:where([data-datakable] [data-dk-refresh]){margin-bottom:.5rem;color:var(--dk-muted)}:where([data-datakable] [data-dk-refresh][data-status=error]){padding:.375rem var(--dk-cell-px);color:var(--dk-danger);background:var(--dk-danger-bg);border-radius:var(--dk-radius)}:where([data-datakable][aria-busy=true]:not([data-initial-load=true]) tbody){
|
|
1
|
+
:where([data-datakable]){--dk-font-size: .875rem;--dk-fg: #1f2328;--dk-muted: #59636e;--dk-bg: #fff;--dk-subtle: #f6f8fa;--dk-border: #d1d9e0;--dk-control-border: #818b98;--dk-accent: #0969da;--dk-danger: #d1242f;--dk-danger-bg: #ffebe9;--dk-radius: 6px;--dk-cell-py: .5rem;--dk-cell-px: .75rem;font-size:var(--dk-font-size);color:var(--dk-fg);background:var(--dk-bg);font-variant-numeric:tabular-nums}@media(prefers-color-scheme:dark){:where([data-datakable]){--dk-fg: #f0f6fc;--dk-muted: #9198a1;--dk-bg: #0d1117;--dk-subtle: #151b23;--dk-border: #3d444d;--dk-control-border: #6e7681;--dk-accent: #4493f8;--dk-danger: #f85149;--dk-danger-bg: #25171c}}:where([data-datakable] table){width:100%;border-collapse:collapse}:where([data-datakable] caption){padding:var(--dk-cell-py) var(--dk-cell-px);color:var(--dk-muted);text-align:start}:where([data-datakable] th,[data-datakable] td){padding:var(--dk-cell-py) var(--dk-cell-px);border-bottom:1px solid var(--dk-border);text-align:start}:where([data-datakable] thead th){background:var(--dk-subtle);font-weight:600;white-space:nowrap}:where([data-datakable] tbody tr:hover){background:var(--dk-subtle)}:where([data-datakable] button){font:inherit;color:inherit;padding:.25rem .625rem;background:var(--dk-bg);border:1px solid var(--dk-border);border-radius:var(--dk-radius);cursor:pointer}:where([data-datakable] button:disabled,[data-datakable] button[aria-disabled=true]){opacity:.5;cursor:not-allowed}:where([data-datakable] button:focus-visible,[data-datakable] input:focus-visible){outline:2px solid var(--dk-accent);outline-offset:1px}:where([data-datakable] th[aria-sort] button){font-weight:inherit;padding:0;background:none;border:0}:where([data-datakable] th[aria-sort=ascending],[data-datakable] th[aria-sort=descending]){color:var(--dk-accent)}:where([data-datakable] [data-dk-sort-indicator]){font-size:.75em}:where([data-datakable] [data-dk-search]){display:flex;align-items:center;gap:.5rem;margin-bottom:.5rem}:where([data-datakable] [data-dk-search] input){font:inherit;color:inherit;min-width:12rem;padding:.375rem .625rem;background:var(--dk-bg);border:1px solid var(--dk-control-border);border-radius:var(--dk-radius)}:where([data-datakable] [data-dk-spinner]){width:1em;height:1em;border:2px solid var(--dk-border);border-top-color:var(--dk-accent);border-radius:50%;animation:dk-spin .7s linear infinite}@keyframes dk-spin{to{transform:rotate(1turn)}}:where([data-datakable] [data-dk-state] td){padding:2rem var(--dk-cell-px);color:var(--dk-muted);text-align:center}:where([data-datakable] tr[data-dk-state]:hover){background:none}:where([data-datakable] [data-dk-state=loading] td){font-style:italic}:where([data-datakable] [data-dk-state=error] td){color:var(--dk-danger)}:where([data-datakable] [data-dk-refresh]){margin-bottom:.5rem;color:var(--dk-muted)}:where([data-datakable] [data-dk-refresh][data-status=error]){padding:.375rem var(--dk-cell-px);color:var(--dk-danger);background:var(--dk-danger-bg);border-radius:var(--dk-radius)}:where([data-datakable][aria-busy=true]:not([data-initial-load=true]) tbody){cursor:progress}:where([data-datakable] tr[data-invalid=true]){background:var(--dk-danger-bg)}:where([data-datakable] td[data-invalid=true]){color:var(--dk-danger);box-shadow:inset 2px 0 var(--dk-danger)}:where([data-datakable] [data-dk-invalid-marker]){color:var(--dk-danger)}:where([data-datakable] [data-dk-pagination]){display:flex;align-items:center;justify-content:flex-end;gap:.5rem;margin-top:.5rem}:where([data-datakable] [data-dk-page]){color:var(--dk-muted)}@media(prefers-reduced-motion:reduce){:where([data-datakable] [data-dk-spinner]){animation:none;border-color:var(--dk-accent)}:where([data-datakable] *){transition:none}}
|
package/dist/use-data-table.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
"use client";
|
|
2
1
|
"use strict";
|
|
2
|
+
"use client";
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -28,7 +28,7 @@ var import_core = require("@datakable/core");
|
|
|
28
28
|
var import_react = require("react");
|
|
29
29
|
|
|
30
30
|
// package.json
|
|
31
|
-
var version = "1.
|
|
31
|
+
var version = "1.1.0";
|
|
32
32
|
|
|
33
33
|
// src/use-data-table.ts
|
|
34
34
|
var import_codes = require("./codes.cjs");
|
|
@@ -50,7 +50,13 @@ var UNSTABLE_AFTER = 2;
|
|
|
50
50
|
var registered = false;
|
|
51
51
|
function useDataTable(options) {
|
|
52
52
|
const ref = (0, import_react.useRef)(null);
|
|
53
|
-
if (ref.current === null)
|
|
53
|
+
if (ref.current === null) {
|
|
54
|
+
ref.current = createInstance(options);
|
|
55
|
+
if (process.env.NODE_ENV !== "production" && typeof window !== "undefined" && import_react.version.startsWith("18.")) {
|
|
56
|
+
const inst2 = ref.current;
|
|
57
|
+
queueMicrotask(() => release(inst2));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
54
60
|
const inst = ref.current;
|
|
55
61
|
const table = inst.table;
|
|
56
62
|
const [, rerender] = (0, import_react.useReducer)((n) => n + 1, 0);
|
|
@@ -98,6 +104,11 @@ function useDataTable(options) {
|
|
|
98
104
|
});
|
|
99
105
|
return view;
|
|
100
106
|
}
|
|
107
|
+
function release(inst) {
|
|
108
|
+
if (inst.mounted || inst.destroyed) return;
|
|
109
|
+
inst.destroyed = true;
|
|
110
|
+
inst.table.destroy();
|
|
111
|
+
}
|
|
101
112
|
function createInstance(options) {
|
|
102
113
|
const inst = {
|
|
103
114
|
table: void 0,
|
|
@@ -131,8 +142,8 @@ function createInstance(options) {
|
|
|
131
142
|
server: void 0,
|
|
132
143
|
hydrating: false,
|
|
133
144
|
seen: options,
|
|
134
|
-
|
|
135
|
-
warned: /* @__PURE__ */ new Set()
|
|
145
|
+
// Development only (`checkUnstable`): no Map / Set per table in production.
|
|
146
|
+
...process.env.NODE_ENV !== "production" ? { unstable: /* @__PURE__ */ new Map(), warned: /* @__PURE__ */ new Set() } : {}
|
|
136
147
|
};
|
|
137
148
|
if (process.env.NODE_ENV !== "production" && !registered) {
|
|
138
149
|
registered = true;
|
|
@@ -227,7 +238,7 @@ function checkHydration(inst) {
|
|
|
227
238
|
}
|
|
228
239
|
}
|
|
229
240
|
function sync(inst, options, selfCaused) {
|
|
230
|
-
if (process.env.NODE_ENV !== "production") checkUnstable(inst, options);
|
|
241
|
+
if (process.env.NODE_ENV !== "production" && !selfCaused) checkUnstable(inst, options);
|
|
231
242
|
const prev = inst.synced;
|
|
232
243
|
if (!selfCaused) inst.selfData = false;
|
|
233
244
|
let partial;
|
|
@@ -307,21 +318,8 @@ function sameItems(a, b) {
|
|
|
307
318
|
for (let i = 0; i < a.length; i++) if (!Object.is(a[i], b[i])) return false;
|
|
308
319
|
return true;
|
|
309
320
|
}
|
|
310
|
-
function sameRows(a, b) {
|
|
311
|
-
if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false;
|
|
312
|
-
for (let i = 0; i < a.length; i++) {
|
|
313
|
-
const x = a[i];
|
|
314
|
-
const y = b[i];
|
|
315
|
-
if (Object.is(x, y)) continue;
|
|
316
|
-
if (!isObject(x) || !isObject(y)) return false;
|
|
317
|
-
const keys = Object.keys(x);
|
|
318
|
-
if (keys.length !== Object.keys(y).length) return false;
|
|
319
|
-
for (const k of keys) if (!Object.hasOwn(y, k) || !Object.is(x[k], y[k])) return false;
|
|
320
|
-
}
|
|
321
|
-
return true;
|
|
322
|
-
}
|
|
323
321
|
var loose = (v) => typeof v === "function" || isObject(v);
|
|
324
|
-
function
|
|
322
|
+
function sameRows(a, b, shape) {
|
|
325
323
|
if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false;
|
|
326
324
|
for (let i = 0; i < a.length; i++) {
|
|
327
325
|
const x = a[i];
|
|
@@ -335,11 +333,12 @@ function sameShape(a, b) {
|
|
|
335
333
|
const vx = x[k];
|
|
336
334
|
const vy = y[k];
|
|
337
335
|
if (Object.is(vx, vy)) continue;
|
|
338
|
-
if (!(loose(vx) && loose(vy) && typeof vx === typeof vy)) return false;
|
|
336
|
+
if (!(shape && loose(vx) && loose(vy) && typeof vx === typeof vy)) return false;
|
|
339
337
|
}
|
|
340
338
|
}
|
|
341
339
|
return true;
|
|
342
340
|
}
|
|
341
|
+
var sameShape = (a, b) => sameRows(a, b, true);
|
|
343
342
|
function changedFeatureOption(a, b) {
|
|
344
343
|
if (!Array.isArray(a) || !Array.isArray(b) || a === b) return void 0;
|
|
345
344
|
for (let i = 0; i < a.length; i++) {
|
|
@@ -369,10 +368,12 @@ function checkUnstable(inst, options) {
|
|
|
369
368
|
track(inst, "features", option !== void 0, option);
|
|
370
369
|
}
|
|
371
370
|
function track(inst, key, unstable, option = key) {
|
|
372
|
-
const
|
|
373
|
-
inst.
|
|
374
|
-
|
|
375
|
-
|
|
371
|
+
const seen = inst.unstable;
|
|
372
|
+
const warned = inst.warned;
|
|
373
|
+
const n = unstable ? (seen.get(key) ?? 0) + 1 : 0;
|
|
374
|
+
seen.set(key, n);
|
|
375
|
+
if (n < UNSTABLE_AFTER || warned.has(key)) return;
|
|
376
|
+
warned.add(key);
|
|
376
377
|
if (key === "columns") (0, import_core.emitTableDiagnostic)(inst.table, "DK_UNSTABLE_COLUMNS", { renders: n });
|
|
377
378
|
else (0, import_core.emitTableDiagnostic)(inst.table, "DK_UNSTABLE_OPTION", { option, renders: n });
|
|
378
379
|
}
|