@datakable/react 1.0.1 → 2.0.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.
@@ -1 +1 @@
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 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":"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","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.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
- /** `render:cell`: the slot whose component threw, `columns[1].cell`. */
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: "those cells rendered ⚠";
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: "those cells rendered ⚠";
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
- /** `render:cell`: the slot whose component threw, `columns[1].cell`. */
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: "those cells rendered ⚠";
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: "those cells rendered ⚠";
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'>;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
15
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
16
+
17
+ // src/messages.ts
18
+ var messages_exports = {};
19
+ module.exports = __toCommonJS(messages_exports);
20
+ var import_core = require("@datakable/core");
21
+ var import_render_codes = require("./render-codes.cjs");
22
+ __reExport(messages_exports, require("@datakable/core/messages"), module.exports);
23
+ (0, import_core.installMessages)(import_render_codes.renderMessages);
24
+ // Annotate the CommonJS export names for ESM import in node:
25
+ 0 && (module.exports = {
26
+ ...require("@datakable/core/messages")
27
+ });
28
+ //# sourceMappingURL=messages.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/messages.ts"],"sourcesContent":["/**\n * `@datakable/react/messages`: full diagnostic text in production builds (§8.2, §12), core's codes\n * plus `<DataTable />`'s. `import '@datakable/react/messages'` once in the app entry; development\n * builds already have it. Imports no React, so `datakable/messages` (#63) works without it.\n */\nimport { installMessages } from '@datakable/core'\nimport { renderMessages } from './render-codes'\n\nexport * from '@datakable/core/messages'\n\ninstallMessages(renderMessages)\n"],"mappings":";;;;;;;;;;;;;;;;;AAAA;AAAA;AAKA,kBAAgC;AAChC,0BAA+B;AAE/B,6BAAc,qCARd;AAAA,IAUA,6BAAgB,kCAAc;","names":[]}
@@ -0,0 +1 @@
1
+ export * from '@datakable/core/messages';
@@ -0,0 +1 @@
1
+ export * from '@datakable/core/messages';
@@ -0,0 +1,6 @@
1
+ // src/messages.ts
2
+ import { installMessages } from "@datakable/core";
3
+ import { renderMessages } from "./render-codes.js";
4
+ export * from "@datakable/core/messages";
5
+ installMessages(renderMessages);
6
+ //# sourceMappingURL=messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/messages.ts"],"sourcesContent":["/**\n * `@datakable/react/messages`: full diagnostic text in production builds (§8.2, §12), core's codes\n * plus `<DataTable />`'s. `import '@datakable/react/messages'` once in the app entry; development\n * builds already have it. Imports no React, so `datakable/messages` (#63) works without it.\n */\nimport { installMessages } from '@datakable/core'\nimport { renderMessages } from './render-codes'\n\nexport * from '@datakable/core/messages'\n\ninstallMessages(renderMessages)\n"],"mappings":";AAKA,SAAS,uBAAuB;AAChC,SAAS,sBAAsB;AAE/B,cAAc;AAEd,gBAAgB,cAAc;","names":[]}
@@ -35,17 +35,19 @@ function registerRenderOperations() {
35
35
  var cellSlot = (0, import_core.defineSlot)({
36
36
  name: "cell",
37
37
  returns: "sync",
38
- fallback: "those cells rendered \u26A0"
38
+ fallback: "cells-warn"
39
+ // prose key: 'those cells rendered ⚠' (core diagnostics/prose.ts)
39
40
  });
40
41
  var invalidCellSlot = (0, import_core.defineSlot)({
41
42
  name: "invalidCell",
42
43
  returns: "sync",
43
- fallback: "those cells rendered \u26A0"
44
+ fallback: "cells-warn"
45
+ // prose key: 'those cells rendered ⚠' (core diagnostics/prose.ts)
44
46
  });
45
47
  var renderMessages = {
46
48
  DK_RENDER_FAILED: {
47
- 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)`,
48
- 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",
49
51
  fix: (d) => d.op === "render:cell" ? [
50
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`,
51
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 /** `render:cell`: the slot whose component threw, `columns[1].cell`. */\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: 'those cells rendered ⚠',\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: 'those cells rendered ⚠',\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 : `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 : '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;AAqCA,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;AACZ,CAAC;AAGM,IAAM,sBAAkB,wBAAW;AAAA,EACxC,MAAM;AAAA,EACN,SAAS;AAAA,EACT,UAAU;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,mDAAmD,EAAE,YAAY,IAAI,EAAE,SAAS,KAAK,EAAE;AAAA,IAE7F,QAAQ,CAAC,MACP,EAAE,OAAO,gBACL,4LAGA;AAAA,IAEN,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":[]}
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":[]}
@@ -11,17 +11,19 @@ function registerRenderOperations() {
11
11
  var cellSlot = defineSlot({
12
12
  name: "cell",
13
13
  returns: "sync",
14
- fallback: "those cells rendered \u26A0"
14
+ fallback: "cells-warn"
15
+ // prose key: 'those cells rendered ⚠' (core diagnostics/prose.ts)
15
16
  });
16
17
  var invalidCellSlot = defineSlot({
17
18
  name: "invalidCell",
18
19
  returns: "sync",
19
- fallback: "those cells rendered \u26A0"
20
+ fallback: "cells-warn"
21
+ // prose key: 'those cells rendered ⚠' (core diagnostics/prose.ts)
20
22
  });
21
23
  var renderMessages = {
22
24
  DK_RENDER_FAILED: {
23
- 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)`,
24
- 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",
25
27
  fix: (d) => d.op === "render:cell" ? [
26
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`,
27
29
  `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 /** `render:cell`: the slot whose component threw, `columns[1].cell`. */\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: 'those cells rendered ⚠',\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: 'those cells rendered ⚠',\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 : `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 : '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;AAqCA,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;AACZ,CAAC;AAGM,IAAM,kBAAkB,WAAW;AAAA,EACxC,MAAM;AAAA,EACN,SAAS;AAAA,EACT,UAAU;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,mDAAmD,EAAE,YAAY,IAAI,EAAE,SAAS,KAAK,EAAE;AAAA,IAE7F,QAAQ,CAAC,MACP,EAAE,OAAO,gBACL,4LAGA;AAAA,IAEN,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":[]}
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){opacity:.6;transition:opacity .15s}: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}}
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}}
@@ -0,0 +1,2 @@
1
+ // The optional stylesheet: a side-effect import (`import '<package>/styles.css'`). No exports.
2
+ export {}
@@ -0,0 +1,2 @@
1
+ // The optional stylesheet: a side-effect import (`import '<package>/styles.css'`). No exports.
2
+ export {}
@@ -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.0.1";
31
+ var version = "2.0.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) ref.current = createInstance(options);
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
- unstable: /* @__PURE__ */ new Map(),
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 sameShape(a, b) {
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 n = unstable ? (inst.unstable.get(key) ?? 0) + 1 : 0;
373
- inst.unstable.set(key, n);
374
- if (n < UNSTABLE_AFTER || inst.warned.has(key)) return;
375
- inst.warned.add(key);
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
  }