@akshar-technosoft/ui 1.2.2 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -31,8 +31,17 @@ export { GeneralHelper } from './components/general.cjs';
31
31
  interface PersistGroupRegistry {
32
32
  }
33
33
  type PersistGroupId = keyof PersistGroupRegistry extends never ? string : keyof PersistGroupRegistry & string;
34
+ /** Every slot across every registered group — the un-narrowed fallback `PersistSlotFor` resolves
35
+ * to when a specific group isn't pinned (e.g. `shared` typed before `persist.group` is set). */
34
36
  type PersistSlotId = keyof PersistGroupRegistry extends never ? string : PersistGroupRegistry[keyof PersistGroupRegistry] & string;
35
- type PersistConfig = {
37
+ /**
38
+ * `shared`'s value type, narrowed to ONE group's own slots instead of every group's. `G` is
39
+ * whatever `DataTableProps`'s own group type param resolves to for this table (see there for how
40
+ * it gets pinned) — a real group key narrows to just that group's slots; `undefined` (no group
41
+ * pinned yet) falls back to `PersistSlotId`, every group's slots, same as before this existed.
42
+ */
43
+ type PersistSlotFor<G extends PersistGroupId | undefined> = G extends keyof PersistGroupRegistry ? PersistGroupRegistry[G] & string : PersistSlotId;
44
+ type PersistConfig<G extends PersistGroupId | undefined = PersistGroupId> = {
36
45
  /**
37
46
  * Unique id for this table ACROSS THE WHOLE APP (it's the storage map key, and the
38
47
  * localStorage key when `local: true`). Two tables with the same key share one saved state —
@@ -43,8 +52,11 @@ type PersistConfig = {
43
52
  * Namespace for `shared` filter slots — ONLY tables with the same group exchange those values
44
53
  * (a "party" slot in group "inhouse" never leaks into group "sales"). Required for `shared`
45
54
  * to do anything; a `shared` filter on a table without a group is inert (dev warning).
55
+ *
56
+ * Setting this is also what narrows `filters[].shared`'s autocomplete/type-check to just THIS
57
+ * group's own slots — see `DataTableProps`'s `G` type param.
46
58
  */
47
- group?: PersistGroupId;
59
+ group?: G;
48
60
  /**
49
61
  * Also write to localStorage so state survives refresh/re-login.
50
62
  * NOTE: unlike zustand's `persist` middleware, the default here is IN-MEMORY (back-navigation
@@ -119,8 +131,10 @@ type AggregationConfig<TData> = {
119
131
  format?: (value: any, func: AggregationFunction) => string;
120
132
  accessor?: (row: TData) => number | null;
121
133
  };
122
- /** Fields shared by every filter control, independent of how it locates its value. */
123
- type FilterControlConfig = {
134
+ /** Fields shared by every filter control, independent of how it locates its value. `G` narrows
135
+ * `shared` to one persist group's own slots — see `DataTableProps`'s `G` type param for how a
136
+ * real value gets pinned instead of the default (every group's slots, undiscriminated). */
137
+ type FilterControlConfig<G extends PersistGroupId | undefined = undefined> = {
124
138
  /** Input placeholder and the filter's display label (also used on chips and the grouped picker). */
125
139
  placeholder: string;
126
140
  /**
@@ -176,7 +190,7 @@ type FilterControlConfig = {
176
190
  * group opens already filtered to it). The slot stores only the value, so pages can bind it to
177
191
  * different filter keys, or even to an `externalSearch` filter. Requires `persist.group`.
178
192
  */
179
- shared?: PersistSlotId;
193
+ shared?: PersistSlotFor<G>;
180
194
  /**
181
195
  * Set false to exclude this one filter from persistence (scan boxes, one-shot searches) while
182
196
  * the rest of the table persists. Inert without the table-level `persist` prop. @default true
@@ -198,7 +212,7 @@ type FilterControlConfig = {
198
212
  * Reach for {@link CustomFilterConfig} instead only when the match is not a plain contains on one
199
213
  * field, for example matching inside an array of objects or across several fields at once.
200
214
  */
201
- type PathFilterConfig<T> = FilterControlConfig & {
215
+ type PathFilterConfig<T, G extends PersistGroupId | undefined = undefined> = FilterControlConfig<G> & {
202
216
  /** Dot path into the row (validated against `T`). Serves as both the value source and the id. */
203
217
  key: Paths<T>;
204
218
  id?: never;
@@ -223,7 +237,7 @@ type PathFilterConfig<T> = FilterControlConfig & {
223
237
  * filterFn: (row, v) => !v || row.lots.some(l => l.isUrgent) },
224
238
  * ];
225
239
  */
226
- type CustomFilterConfig<T> = FilterControlConfig & {
240
+ type CustomFilterConfig<T, G extends PersistGroupId | undefined = undefined> = FilterControlConfig<G> & {
227
241
  /** Any unique string identifying this filter. Not required to be a real field, since `filterFn`
228
242
  * reads the row directly. */
229
243
  id: string;
@@ -236,8 +250,11 @@ type CustomFilterConfig<T> = FilterControlConfig & {
236
250
  * {@link PathFilterConfig} — pass `key` (a real dot path). The common case: flat or nested fields.
237
251
  * {@link CustomFilterConfig} — pass `id` + `filterFn`. For arrays of objects or multi field matches.
238
252
  * Either way the filtering runs through TanStack's model and AND combines; you never edit `columns`.
253
+ *
254
+ * `G` — the table's persist group, for narrowing `shared`'s autocomplete to that one group's
255
+ * slots. Left to its default almost everywhere; see `DataTableProps` for where it's actually set.
239
256
  */
240
- type FilterConfig<T> = PathFilterConfig<T> | CustomFilterConfig<T>;
257
+ type FilterConfig<T, G extends PersistGroupId | undefined = undefined> = PathFilterConfig<T, G> | CustomFilterConfig<T, G>;
241
258
  type PaginationConfig = {
242
259
  /** Rows per page initially. @default 10 */
243
260
  pageSize?: number;
@@ -494,7 +511,19 @@ type GroupColumnDef<TData> = ColumnDef<TData> & {
494
511
  */
495
512
  pinIndex?: number;
496
513
  };
497
- type DataTableProps<TData> = {
514
+ /**
515
+ * `G` — this table's persist group, ONLY relevant for narrowing `filters[].shared`'s
516
+ * autocomplete/type-check to that one group's own slots (see `PersistSlotFor`). You never set it
517
+ * explicitly for an inline `<DataTable persist={{group:"QC"}} filters={[...]} />` call: TS infers
518
+ * it from `persist.group` and checks `filters` against it in the same pass, same as `TData`
519
+ * infers from `data`/`columns`.
520
+ *
521
+ * It DOES need spelling out when `filters` is a separately declared `const` (the common pattern —
522
+ * `const filters: DataTableProps<Row>["filters"] = [...]`), because that array gets its type at
523
+ * its own declaration, independent of a `persist` prop written later in the same file. Add the
524
+ * group there too: `DataTableProps<Row, "QC">["filters"]`.
525
+ */
526
+ type DataTableProps<TData, G extends PersistGroupId | undefined = undefined> = {
498
527
  /** Row data. Rendered client-side (filter/sort/paginate all in-memory unless server-driven). */
499
528
  data: TData[];
500
529
  /** Column definitions. TanStack `ColumnDef` plus a few extras; see {@link GroupColumnDef}. */
@@ -502,7 +531,7 @@ type DataTableProps<TData> = {
502
531
  /** Toolbar filter controls (see {@link FilterConfig}); place each on the bar or behind the global
503
532
  * search's field picker via `FilterConfig.placement`. Debug: filters live in the toolbar, so none
504
533
  * render unless `settings.showToolbar: true`. */
505
- filters?: FilterConfig<TData>[];
534
+ filters?: FilterConfig<TData, G>[];
506
535
  /** Pagination config — its presence enables pagination. Omit to render all rows. */
507
536
  pagination?: PaginationConfig;
508
537
  /** Feature and presentation toggles; see {@link TableSettings} for the full dependency map. */
@@ -603,13 +632,18 @@ type DataTableProps<TData> = {
603
632
  * Restore is synchronous (seeded before first render — no unfiltered flash); external filters
604
633
  * are replayed through `onExternalSearch` on mount (see `readPersistedExternal` to seed the
605
634
  * page's own query instead). Selection is never persisted. See {@link PersistConfig}.
635
+ *
636
+ * Setting `group` here is also what narrows every filter's `shared` (in the SAME `filters`
637
+ * array literal) to just this group's own slots instead of every group's — see `DataTableProps`'s
638
+ * `G` type param doc above for the one case (a separately-declared `filters` const) where you
639
+ * have to spell `G` out yourself for that to kick in.
606
640
  * @example persist="qc-completed"
607
641
  * @example persist={{ key: "qc-completed", group: "inhouse", local: true }}
608
642
  */
609
- persist?: string | PersistConfig;
643
+ persist?: string | PersistConfig<G>;
610
644
  };
611
645
 
612
- declare function DataTable<T>({ data, columns: initialColumns, filters, pagination, settings, header, footer, className, maxHeight, loading, error, emptyMessage, onRowSelectionChange, onExport, onRefresh, onTableReady, children, isRowSelectable, getRowId, defaultSelectedRows, onExternalSearch, aggregations, onAggregationChange, rowClassName, persist: persistProp, }: DataTableProps<T>): react_jsx_runtime.JSX.Element;
646
+ declare function DataTable<T, G extends PersistGroupId | undefined = undefined>({ data, columns: initialColumns, filters, pagination, settings, header, footer, className, maxHeight, loading, error, emptyMessage, onRowSelectionChange, onExport, onRefresh, onTableReady, children, isRowSelectable, getRowId, defaultSelectedRows, onExternalSearch, aggregations, onAggregationChange, rowClassName, persist: persistProp, }: DataTableProps<T, G>): react_jsx_runtime.JSX.Element;
613
647
 
614
648
  declare const buttonVariants: (props?: ({
615
649
  variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | null | undefined;
@@ -636,6 +670,42 @@ interface DataTableActionBarSelectionProps<TData> {
636
670
  }
637
671
  declare function DataTableActionBarSelection<TData>({ table }: DataTableActionBarSelectionProps<TData>): react_jsx_runtime.JSX.Element | null;
638
672
 
673
+ /** The union of every `key`/`id` declared in a `filters` array — same array you already pass
674
+ * to `<DataTable filters={...} />`, so there's nothing new to author or keep in sync. Accepts
675
+ * `| undefined` because `DataTableProps<T>["filters"]` (the type most call sites annotate their
676
+ * local `filters` const with) is optional. Deliberately structural (`key?`/`id?`) and a plain
677
+ * indexed access, NOT `FilterConfig<any>` + conditional inference: `PathFilterConfig.key` is the
678
+ * recursive `Paths<T>`, and inferring through it against a union pattern made the checker blow
679
+ * its instantiation-depth budget (TS2589) at real call sites. Indexed access reads the same keys
680
+ * without re-instantiating any of that machinery. */
681
+ type FilterKeys<F extends readonly {
682
+ key?: string;
683
+ id?: string;
684
+ }[] | undefined> = Extract<NonNullable<F>[number]["key" | "id"], string>;
685
+ /**
686
+ * Live, typed escape hatch onto a table's filter state — for the case DataTable itself can't
687
+ * cover: reading (or driving) a specific filter's CURRENT value from outside the table's own
688
+ * subtree, as if it were a controlled `useState`.
689
+ *
690
+ * DataTable keeps `columnFilters` as private internal state — there's no prop/ref that exposes
691
+ * it. But when the table's `persist` is on (the default now syncs filters to the URL, not just
692
+ * memory — see `use-table-persist.ts`), the URL itself becomes that bridge: any component
693
+ * anywhere can read or write a filter's value through it, live, without prop-drilling and
694
+ * without DataTable exposing anything new.
695
+ *
696
+ * Reuses `useSearchParams` (react-router) directly — no separate subscription/store to keep in
697
+ * sync, no effect, so no loop to guard against; `value` is a pure per-render derivation and
698
+ * `setValue` writes with `replace: true` so it doesn't spam browser history.
699
+ *
700
+ * @example
701
+ * const [lotNo, setLotNo] = useTableFilterParam(lotReportFilters, "LotNo")
702
+ */
703
+ declare function useTableFilterParam<F extends readonly {
704
+ key?: string;
705
+ id?: string;
706
+ }[] | undefined, K extends FilterKeys<F>>(_filters: F, // not read at runtime — only anchors `K` to this table's real filter keys
707
+ key: K): readonly [string | undefined, (next: string | undefined) => void];
708
+
639
709
  type DataTemplateField<T> = {
640
710
  key: keyof T;
641
711
  label: string;
@@ -848,4 +918,4 @@ declare const OfflineUI: () => react_jsx_runtime.JSX.Element;
848
918
 
849
919
  declare const Unauthorized: () => react_jsx_runtime.JSX.Element;
850
920
 
851
- export { AppContainer, type AppContainerProps, AppContent, AppContentFooter, AppContentHeader, type AppContentProps, AppFooter, type AppFooterProps, AppHeader, type AppHeaderProps, AppSheet, type AppSheetProps, CurrencyTransfer, DataTable, DataTableActionBar, DataTableActionBarAction, DataTableActionBarSelection, type DataTableProps, DataTemplate, DataTemplateActionBar, DataTemplateActionBarAction, DataTemplateActionBarSelection, type DataTemplateProps, ErrorComponent, type GroupColumnDef, Loader, NotFound, OfflineUI, type PersistConfig, type PersistGroupRegistry, type TableExportColumn, type TableExportView, Unauthorized, getTableExportView, readPersistedExternal };
921
+ export { AppContainer, type AppContainerProps, AppContent, AppContentFooter, AppContentHeader, type AppContentProps, AppFooter, type AppFooterProps, AppHeader, type AppHeaderProps, AppSheet, type AppSheetProps, CurrencyTransfer, DataTable, DataTableActionBar, DataTableActionBarAction, DataTableActionBarSelection, type DataTableProps, DataTemplate, DataTemplateActionBar, DataTemplateActionBarAction, DataTemplateActionBarSelection, type DataTemplateProps, ErrorComponent, type FilterKeys, type GroupColumnDef, Loader, NotFound, OfflineUI, type PersistConfig, type PersistGroupId, type PersistGroupRegistry, type PersistSlotFor, type PersistSlotId, type TableExportColumn, type TableExportView, Unauthorized, getTableExportView, readPersistedExternal, useTableFilterParam };
package/dist/index.d.ts CHANGED
@@ -31,8 +31,17 @@ export { GeneralHelper } from './components/general.js';
31
31
  interface PersistGroupRegistry {
32
32
  }
33
33
  type PersistGroupId = keyof PersistGroupRegistry extends never ? string : keyof PersistGroupRegistry & string;
34
+ /** Every slot across every registered group — the un-narrowed fallback `PersistSlotFor` resolves
35
+ * to when a specific group isn't pinned (e.g. `shared` typed before `persist.group` is set). */
34
36
  type PersistSlotId = keyof PersistGroupRegistry extends never ? string : PersistGroupRegistry[keyof PersistGroupRegistry] & string;
35
- type PersistConfig = {
37
+ /**
38
+ * `shared`'s value type, narrowed to ONE group's own slots instead of every group's. `G` is
39
+ * whatever `DataTableProps`'s own group type param resolves to for this table (see there for how
40
+ * it gets pinned) — a real group key narrows to just that group's slots; `undefined` (no group
41
+ * pinned yet) falls back to `PersistSlotId`, every group's slots, same as before this existed.
42
+ */
43
+ type PersistSlotFor<G extends PersistGroupId | undefined> = G extends keyof PersistGroupRegistry ? PersistGroupRegistry[G] & string : PersistSlotId;
44
+ type PersistConfig<G extends PersistGroupId | undefined = PersistGroupId> = {
36
45
  /**
37
46
  * Unique id for this table ACROSS THE WHOLE APP (it's the storage map key, and the
38
47
  * localStorage key when `local: true`). Two tables with the same key share one saved state —
@@ -43,8 +52,11 @@ type PersistConfig = {
43
52
  * Namespace for `shared` filter slots — ONLY tables with the same group exchange those values
44
53
  * (a "party" slot in group "inhouse" never leaks into group "sales"). Required for `shared`
45
54
  * to do anything; a `shared` filter on a table without a group is inert (dev warning).
55
+ *
56
+ * Setting this is also what narrows `filters[].shared`'s autocomplete/type-check to just THIS
57
+ * group's own slots — see `DataTableProps`'s `G` type param.
46
58
  */
47
- group?: PersistGroupId;
59
+ group?: G;
48
60
  /**
49
61
  * Also write to localStorage so state survives refresh/re-login.
50
62
  * NOTE: unlike zustand's `persist` middleware, the default here is IN-MEMORY (back-navigation
@@ -119,8 +131,10 @@ type AggregationConfig<TData> = {
119
131
  format?: (value: any, func: AggregationFunction) => string;
120
132
  accessor?: (row: TData) => number | null;
121
133
  };
122
- /** Fields shared by every filter control, independent of how it locates its value. */
123
- type FilterControlConfig = {
134
+ /** Fields shared by every filter control, independent of how it locates its value. `G` narrows
135
+ * `shared` to one persist group's own slots — see `DataTableProps`'s `G` type param for how a
136
+ * real value gets pinned instead of the default (every group's slots, undiscriminated). */
137
+ type FilterControlConfig<G extends PersistGroupId | undefined = undefined> = {
124
138
  /** Input placeholder and the filter's display label (also used on chips and the grouped picker). */
125
139
  placeholder: string;
126
140
  /**
@@ -176,7 +190,7 @@ type FilterControlConfig = {
176
190
  * group opens already filtered to it). The slot stores only the value, so pages can bind it to
177
191
  * different filter keys, or even to an `externalSearch` filter. Requires `persist.group`.
178
192
  */
179
- shared?: PersistSlotId;
193
+ shared?: PersistSlotFor<G>;
180
194
  /**
181
195
  * Set false to exclude this one filter from persistence (scan boxes, one-shot searches) while
182
196
  * the rest of the table persists. Inert without the table-level `persist` prop. @default true
@@ -198,7 +212,7 @@ type FilterControlConfig = {
198
212
  * Reach for {@link CustomFilterConfig} instead only when the match is not a plain contains on one
199
213
  * field, for example matching inside an array of objects or across several fields at once.
200
214
  */
201
- type PathFilterConfig<T> = FilterControlConfig & {
215
+ type PathFilterConfig<T, G extends PersistGroupId | undefined = undefined> = FilterControlConfig<G> & {
202
216
  /** Dot path into the row (validated against `T`). Serves as both the value source and the id. */
203
217
  key: Paths<T>;
204
218
  id?: never;
@@ -223,7 +237,7 @@ type PathFilterConfig<T> = FilterControlConfig & {
223
237
  * filterFn: (row, v) => !v || row.lots.some(l => l.isUrgent) },
224
238
  * ];
225
239
  */
226
- type CustomFilterConfig<T> = FilterControlConfig & {
240
+ type CustomFilterConfig<T, G extends PersistGroupId | undefined = undefined> = FilterControlConfig<G> & {
227
241
  /** Any unique string identifying this filter. Not required to be a real field, since `filterFn`
228
242
  * reads the row directly. */
229
243
  id: string;
@@ -236,8 +250,11 @@ type CustomFilterConfig<T> = FilterControlConfig & {
236
250
  * {@link PathFilterConfig} — pass `key` (a real dot path). The common case: flat or nested fields.
237
251
  * {@link CustomFilterConfig} — pass `id` + `filterFn`. For arrays of objects or multi field matches.
238
252
  * Either way the filtering runs through TanStack's model and AND combines; you never edit `columns`.
253
+ *
254
+ * `G` — the table's persist group, for narrowing `shared`'s autocomplete to that one group's
255
+ * slots. Left to its default almost everywhere; see `DataTableProps` for where it's actually set.
239
256
  */
240
- type FilterConfig<T> = PathFilterConfig<T> | CustomFilterConfig<T>;
257
+ type FilterConfig<T, G extends PersistGroupId | undefined = undefined> = PathFilterConfig<T, G> | CustomFilterConfig<T, G>;
241
258
  type PaginationConfig = {
242
259
  /** Rows per page initially. @default 10 */
243
260
  pageSize?: number;
@@ -494,7 +511,19 @@ type GroupColumnDef<TData> = ColumnDef<TData> & {
494
511
  */
495
512
  pinIndex?: number;
496
513
  };
497
- type DataTableProps<TData> = {
514
+ /**
515
+ * `G` — this table's persist group, ONLY relevant for narrowing `filters[].shared`'s
516
+ * autocomplete/type-check to that one group's own slots (see `PersistSlotFor`). You never set it
517
+ * explicitly for an inline `<DataTable persist={{group:"QC"}} filters={[...]} />` call: TS infers
518
+ * it from `persist.group` and checks `filters` against it in the same pass, same as `TData`
519
+ * infers from `data`/`columns`.
520
+ *
521
+ * It DOES need spelling out when `filters` is a separately declared `const` (the common pattern —
522
+ * `const filters: DataTableProps<Row>["filters"] = [...]`), because that array gets its type at
523
+ * its own declaration, independent of a `persist` prop written later in the same file. Add the
524
+ * group there too: `DataTableProps<Row, "QC">["filters"]`.
525
+ */
526
+ type DataTableProps<TData, G extends PersistGroupId | undefined = undefined> = {
498
527
  /** Row data. Rendered client-side (filter/sort/paginate all in-memory unless server-driven). */
499
528
  data: TData[];
500
529
  /** Column definitions. TanStack `ColumnDef` plus a few extras; see {@link GroupColumnDef}. */
@@ -502,7 +531,7 @@ type DataTableProps<TData> = {
502
531
  /** Toolbar filter controls (see {@link FilterConfig}); place each on the bar or behind the global
503
532
  * search's field picker via `FilterConfig.placement`. Debug: filters live in the toolbar, so none
504
533
  * render unless `settings.showToolbar: true`. */
505
- filters?: FilterConfig<TData>[];
534
+ filters?: FilterConfig<TData, G>[];
506
535
  /** Pagination config — its presence enables pagination. Omit to render all rows. */
507
536
  pagination?: PaginationConfig;
508
537
  /** Feature and presentation toggles; see {@link TableSettings} for the full dependency map. */
@@ -603,13 +632,18 @@ type DataTableProps<TData> = {
603
632
  * Restore is synchronous (seeded before first render — no unfiltered flash); external filters
604
633
  * are replayed through `onExternalSearch` on mount (see `readPersistedExternal` to seed the
605
634
  * page's own query instead). Selection is never persisted. See {@link PersistConfig}.
635
+ *
636
+ * Setting `group` here is also what narrows every filter's `shared` (in the SAME `filters`
637
+ * array literal) to just this group's own slots instead of every group's — see `DataTableProps`'s
638
+ * `G` type param doc above for the one case (a separately-declared `filters` const) where you
639
+ * have to spell `G` out yourself for that to kick in.
606
640
  * @example persist="qc-completed"
607
641
  * @example persist={{ key: "qc-completed", group: "inhouse", local: true }}
608
642
  */
609
- persist?: string | PersistConfig;
643
+ persist?: string | PersistConfig<G>;
610
644
  };
611
645
 
612
- declare function DataTable<T>({ data, columns: initialColumns, filters, pagination, settings, header, footer, className, maxHeight, loading, error, emptyMessage, onRowSelectionChange, onExport, onRefresh, onTableReady, children, isRowSelectable, getRowId, defaultSelectedRows, onExternalSearch, aggregations, onAggregationChange, rowClassName, persist: persistProp, }: DataTableProps<T>): react_jsx_runtime.JSX.Element;
646
+ declare function DataTable<T, G extends PersistGroupId | undefined = undefined>({ data, columns: initialColumns, filters, pagination, settings, header, footer, className, maxHeight, loading, error, emptyMessage, onRowSelectionChange, onExport, onRefresh, onTableReady, children, isRowSelectable, getRowId, defaultSelectedRows, onExternalSearch, aggregations, onAggregationChange, rowClassName, persist: persistProp, }: DataTableProps<T, G>): react_jsx_runtime.JSX.Element;
613
647
 
614
648
  declare const buttonVariants: (props?: ({
615
649
  variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | null | undefined;
@@ -636,6 +670,42 @@ interface DataTableActionBarSelectionProps<TData> {
636
670
  }
637
671
  declare function DataTableActionBarSelection<TData>({ table }: DataTableActionBarSelectionProps<TData>): react_jsx_runtime.JSX.Element | null;
638
672
 
673
+ /** The union of every `key`/`id` declared in a `filters` array — same array you already pass
674
+ * to `<DataTable filters={...} />`, so there's nothing new to author or keep in sync. Accepts
675
+ * `| undefined` because `DataTableProps<T>["filters"]` (the type most call sites annotate their
676
+ * local `filters` const with) is optional. Deliberately structural (`key?`/`id?`) and a plain
677
+ * indexed access, NOT `FilterConfig<any>` + conditional inference: `PathFilterConfig.key` is the
678
+ * recursive `Paths<T>`, and inferring through it against a union pattern made the checker blow
679
+ * its instantiation-depth budget (TS2589) at real call sites. Indexed access reads the same keys
680
+ * without re-instantiating any of that machinery. */
681
+ type FilterKeys<F extends readonly {
682
+ key?: string;
683
+ id?: string;
684
+ }[] | undefined> = Extract<NonNullable<F>[number]["key" | "id"], string>;
685
+ /**
686
+ * Live, typed escape hatch onto a table's filter state — for the case DataTable itself can't
687
+ * cover: reading (or driving) a specific filter's CURRENT value from outside the table's own
688
+ * subtree, as if it were a controlled `useState`.
689
+ *
690
+ * DataTable keeps `columnFilters` as private internal state — there's no prop/ref that exposes
691
+ * it. But when the table's `persist` is on (the default now syncs filters to the URL, not just
692
+ * memory — see `use-table-persist.ts`), the URL itself becomes that bridge: any component
693
+ * anywhere can read or write a filter's value through it, live, without prop-drilling and
694
+ * without DataTable exposing anything new.
695
+ *
696
+ * Reuses `useSearchParams` (react-router) directly — no separate subscription/store to keep in
697
+ * sync, no effect, so no loop to guard against; `value` is a pure per-render derivation and
698
+ * `setValue` writes with `replace: true` so it doesn't spam browser history.
699
+ *
700
+ * @example
701
+ * const [lotNo, setLotNo] = useTableFilterParam(lotReportFilters, "LotNo")
702
+ */
703
+ declare function useTableFilterParam<F extends readonly {
704
+ key?: string;
705
+ id?: string;
706
+ }[] | undefined, K extends FilterKeys<F>>(_filters: F, // not read at runtime — only anchors `K` to this table's real filter keys
707
+ key: K): readonly [string | undefined, (next: string | undefined) => void];
708
+
639
709
  type DataTemplateField<T> = {
640
710
  key: keyof T;
641
711
  label: string;
@@ -848,4 +918,4 @@ declare const OfflineUI: () => react_jsx_runtime.JSX.Element;
848
918
 
849
919
  declare const Unauthorized: () => react_jsx_runtime.JSX.Element;
850
920
 
851
- export { AppContainer, type AppContainerProps, AppContent, AppContentFooter, AppContentHeader, type AppContentProps, AppFooter, type AppFooterProps, AppHeader, type AppHeaderProps, AppSheet, type AppSheetProps, CurrencyTransfer, DataTable, DataTableActionBar, DataTableActionBarAction, DataTableActionBarSelection, type DataTableProps, DataTemplate, DataTemplateActionBar, DataTemplateActionBarAction, DataTemplateActionBarSelection, type DataTemplateProps, ErrorComponent, type GroupColumnDef, Loader, NotFound, OfflineUI, type PersistConfig, type PersistGroupRegistry, type TableExportColumn, type TableExportView, Unauthorized, getTableExportView, readPersistedExternal };
921
+ export { AppContainer, type AppContainerProps, AppContent, AppContentFooter, AppContentHeader, type AppContentProps, AppFooter, type AppFooterProps, AppHeader, type AppHeaderProps, AppSheet, type AppSheetProps, CurrencyTransfer, DataTable, DataTableActionBar, DataTableActionBarAction, DataTableActionBarSelection, type DataTableProps, DataTemplate, DataTemplateActionBar, DataTemplateActionBarAction, DataTemplateActionBarSelection, type DataTemplateProps, ErrorComponent, type FilterKeys, type GroupColumnDef, Loader, NotFound, OfflineUI, type PersistConfig, type PersistGroupId, type PersistGroupRegistry, type PersistSlotFor, type PersistSlotId, type TableExportColumn, type TableExportView, Unauthorized, getTableExportView, readPersistedExternal, useTableFilterParam };