@datum-cloud/datum-ui 0.3.0-alpha.3670fb2 → 0.3.0-alpha.7487874

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.
Files changed (132) hide show
  1. package/dist/app-navigation/index.mjs +12 -0
  2. package/dist/app-navigation-CCvjPijd.mjs +416 -0
  3. package/dist/autocomplete/index.mjs +1 -1
  4. package/dist/{autocomplete-B9bCkXtz.mjs → autocomplete-DcKO7pj5.mjs} +1 -1
  5. package/dist/avatar-stack/index.mjs +2 -2
  6. package/dist/{avatar-stack-Bh-tLz0X.mjs → avatar-stack-B21McFeb.mjs} +1 -1
  7. package/dist/{calendar-date-picker-mlbzp3xR.mjs → calendar-date-picker-Bw6Mrr-P.mjs} +2 -1
  8. package/dist/components/base/index.d.ts +1 -0
  9. package/dist/components/base/index.d.ts.map +1 -1
  10. package/dist/components/base/sidebar/index.d.ts +2 -0
  11. package/dist/components/base/sidebar/index.d.ts.map +1 -0
  12. package/dist/components/{features → base}/sidebar/sidebar.d.ts +1 -1
  13. package/dist/components/base/sidebar/sidebar.d.ts.map +1 -0
  14. package/dist/components/base/skeleton/index.d.ts +1 -1
  15. package/dist/components/base/skeleton/index.d.ts.map +1 -1
  16. package/dist/components/base/skeleton/skeleton.d.ts +22 -0
  17. package/dist/components/base/skeleton/skeleton.d.ts.map +1 -0
  18. package/dist/components/base/typography/typography.d.ts +2 -2
  19. package/dist/components/features/app-navigation/app-navigation.d.ts +14 -0
  20. package/dist/components/features/app-navigation/app-navigation.d.ts.map +1 -0
  21. package/dist/components/features/app-navigation/index.d.ts +4 -0
  22. package/dist/components/features/app-navigation/index.d.ts.map +1 -0
  23. package/dist/components/features/{sidebar/nav-main.d.ts → app-navigation/nav-menu.d.ts} +3 -3
  24. package/dist/components/features/app-navigation/nav-menu.d.ts.map +1 -0
  25. package/dist/components/features/calendar-date-picker/calendar-date-picker.d.ts +2 -1
  26. package/dist/components/features/calendar-date-picker/calendar-date-picker.d.ts.map +1 -1
  27. package/dist/components/features/data-table/components/active-filters.d.ts +1 -1
  28. package/dist/components/features/data-table/components/active-filters.d.ts.map +1 -1
  29. package/dist/components/features/data-table/components/loading.d.ts.map +1 -1
  30. package/dist/components/features/data-table/components/search.d.ts +1 -1
  31. package/dist/components/features/data-table/components/search.d.ts.map +1 -1
  32. package/dist/components/features/data-table/core/client-provider.d.ts +6 -7
  33. package/dist/components/features/data-table/core/client-provider.d.ts.map +1 -1
  34. package/dist/components/features/data-table/core/data-table-context.d.ts +14 -0
  35. package/dist/components/features/data-table/core/data-table-context.d.ts.map +1 -1
  36. package/dist/components/features/data-table/core/filter-engine.d.ts +5 -0
  37. package/dist/components/features/data-table/core/filter-engine.d.ts.map +1 -1
  38. package/dist/components/features/data-table/core/server-provider.d.ts +6 -7
  39. package/dist/components/features/data-table/core/server-provider.d.ts.map +1 -1
  40. package/dist/components/features/data-table/core/store.d.ts.map +1 -1
  41. package/dist/components/features/data-table/data-table.d.ts +1 -1
  42. package/dist/components/features/data-table/filters/checkbox-filter.d.ts +1 -1
  43. package/dist/components/features/data-table/filters/checkbox-filter.d.ts.map +1 -1
  44. package/dist/components/features/data-table/filters/date-picker-filter.d.ts +1 -1
  45. package/dist/components/features/data-table/filters/date-picker-filter.d.ts.map +1 -1
  46. package/dist/components/features/data-table/filters/select-filter.d.ts +1 -1
  47. package/dist/components/features/data-table/filters/select-filter.d.ts.map +1 -1
  48. package/dist/components/features/data-table/hooks/index.d.ts +1 -1
  49. package/dist/components/features/data-table/hooks/index.d.ts.map +1 -1
  50. package/dist/components/features/data-table/hooks/use-data-table-client.d.ts +2 -15
  51. package/dist/components/features/data-table/hooks/use-data-table-client.d.ts.map +1 -1
  52. package/dist/components/features/data-table/hooks/use-data-table-server.d.ts +2 -25
  53. package/dist/components/features/data-table/hooks/use-data-table-server.d.ts.map +1 -1
  54. package/dist/components/features/data-table/hooks/use-is-client.d.ts +8 -0
  55. package/dist/components/features/data-table/hooks/use-is-client.d.ts.map +1 -0
  56. package/dist/components/features/data-table/hooks/use-selectors.d.ts +4 -35
  57. package/dist/components/features/data-table/hooks/use-selectors.d.ts.map +1 -1
  58. package/dist/components/features/data-table/index.d.ts +2 -4
  59. package/dist/components/features/data-table/index.d.ts.map +1 -1
  60. package/dist/components/features/data-table/types.d.ts +23 -30
  61. package/dist/components/features/data-table/types.d.ts.map +1 -1
  62. package/dist/components/features/index.d.ts +1 -1
  63. package/dist/components/features/index.d.ts.map +1 -1
  64. package/dist/data-table/index.mjs +395 -363
  65. package/dist/date-picker/index.mjs +2 -2
  66. package/dist/dropdown/index.mjs +1 -1
  67. package/dist/dropzone/index.mjs +1 -1
  68. package/dist/empty-content/index.mjs +1 -1
  69. package/dist/form/index.mjs +3 -3
  70. package/dist/grid/index.mjs +1 -1
  71. package/dist/hooks/index.mjs +2 -2
  72. package/dist/index.mjs +34 -32
  73. package/dist/input-number/index.mjs +1 -1
  74. package/dist/input-with-addons/index.mjs +1 -1
  75. package/dist/loader-overlay/index.mjs +1 -1
  76. package/dist/map/index.mjs +1 -1
  77. package/dist/{map-ClJD-qxm.mjs → map-2RG9pYZR.mjs} +1 -1
  78. package/dist/more-actions/index.mjs +2 -2
  79. package/dist/{more-actions-DbC8dyed.mjs → more-actions-BODYgG1C.mjs} +2 -2
  80. package/dist/page-title/index.mjs +1 -1
  81. package/dist/sidebar/index.mjs +4 -5
  82. package/dist/{sidebar-C4NqSr4r.mjs → sidebar-BW76ss_f.mjs} +6 -415
  83. package/dist/skeleton/index.mjs +2 -1
  84. package/dist/skeleton-DZ31pU4B.mjs +28 -0
  85. package/dist/stepper/index.mjs +1 -1
  86. package/dist/styles/root.css +3 -0
  87. package/dist/switch/index.mjs +1 -1
  88. package/dist/table/index.mjs +1 -1
  89. package/dist/tabs/index.mjs +1 -1
  90. package/dist/tag-input/index.mjs +1 -1
  91. package/dist/task-queue/index.mjs +3 -3
  92. package/dist/{task-queue-dropdown-fo3TX58Q.mjs → task-queue-dropdown-DtS0IKci.mjs} +3 -3
  93. package/dist/textarea/index.mjs +1 -1
  94. package/dist/theme/index.mjs +1 -1
  95. package/dist/toast/index.mjs +1 -1
  96. package/dist/tooltip/index.mjs +1 -1
  97. package/dist/typography/index.mjs +1 -1
  98. package/dist/{use-copy-to-clipboard-C7xqNxBX.mjs → use-copy-to-clipboard-C9cT2Qb-.mjs} +1 -1
  99. package/dist/{use-stepper-CB1injte.mjs → use-stepper-DJd8o9dV.mjs} +8 -8
  100. package/dist/visually-hidden/index.mjs +1 -1
  101. package/package.json +85 -79
  102. package/dist/components/features/data-table/hooks/use-data-table-context.d.ts +0 -2
  103. package/dist/components/features/data-table/hooks/use-data-table-context.d.ts.map +0 -1
  104. package/dist/components/features/sidebar/app-sidebar.d.ts +0 -14
  105. package/dist/components/features/sidebar/app-sidebar.d.ts.map +0 -1
  106. package/dist/components/features/sidebar/index.d.ts +0 -4
  107. package/dist/components/features/sidebar/index.d.ts.map +0 -1
  108. package/dist/components/features/sidebar/nav-main.d.ts.map +0 -1
  109. package/dist/components/features/sidebar/sidebar.d.ts.map +0 -1
  110. /package/dist/{col-RfO7d6AR.mjs → col-DCneNxQj.mjs} +0 -0
  111. /package/dist/{dropdown-Cs7Xr8w7.mjs → dropdown-Dgm_b6Mm.mjs} +0 -0
  112. /package/dist/{dropzone-BT5fEDEF.mjs → dropzone-DR6O9OdU.mjs} +0 -0
  113. /package/dist/{empty-content-iDu3NUqG.mjs → empty-content-Dm7_5jO9.mjs} +0 -0
  114. /package/dist/{input-number-D9ydFith.mjs → input-number-D1HCcTXO.mjs} +0 -0
  115. /package/dist/{input-with-addons-CdgiUQce.mjs → input-with-addons-DN9LGwUU.mjs} +0 -0
  116. /package/dist/{loader-overlay-D83QeQNj.mjs → loader-overlay-CpA0zV8D.mjs} +0 -0
  117. /package/dist/{map-leaflet-imports-CdzvEnzY.mjs → map-leaflet-imports-CgEyVRnp.mjs} +0 -0
  118. /package/dist/{page-title-SGchAF6Y.mjs → page-title-D62FV6vD.mjs} +0 -0
  119. /package/dist/{skeleton-Cs6Q5GQc.mjs → skeleton-CkE23wsL.mjs} +0 -0
  120. /package/dist/{stepper-BG9DIzN5.mjs → stepper-CZeks9Ex.mjs} +0 -0
  121. /package/dist/{switch-B2VVauH6.mjs → switch-Cn9IM2gC.mjs} +0 -0
  122. /package/dist/{table-Dc3HfbM4.mjs → table-Dpzh0VPK.mjs} +0 -0
  123. /package/dist/{tabs-Ccb4uqbe.mjs → tabs-OYVCDOif.mjs} +0 -0
  124. /package/dist/{tag-input-BfHaKoMF.mjs → tag-input-DorFQ9bA.mjs} +0 -0
  125. /package/dist/{textarea-X4OjkqLJ.mjs → textarea-KZUKGHlO.mjs} +0 -0
  126. /package/dist/{theme.provider-Nun_O9-O.mjs → theme.provider-BG3cS9xe.mjs} +0 -0
  127. /package/dist/{to-api-format-zI26rEBI.mjs → to-api-format-CzPt5UAX.mjs} +0 -0
  128. /package/dist/{tooltip-DZFG1iMs.mjs → tooltip-U3XxlW4l.mjs} +0 -0
  129. /package/dist/{typography-T7WgvO77.mjs → typography-DdrxIJMd.mjs} +0 -0
  130. /package/dist/{use-debounce-Ctljs3MB.mjs → use-debounce-Dc95PFRX.mjs} +0 -0
  131. /package/dist/{use-toast-DN-fZBzJ.mjs → use-toast-DBmysDS6.mjs} +0 -0
  132. /package/dist/{visuallyhidden-CgkVhApW.mjs → visuallyhidden-CfBnXfvh.mjs} +0 -0
@@ -12,11 +12,12 @@ import { t as Label } from "../label-_ste_Re3.mjs";
12
12
  import { i as DropdownMenuItem, l as DropdownMenuTrigger, r as DropdownMenuContent, t as DropdownMenu } from "../dropdown-menu-DAFyO-qD.mjs";
13
13
  import { i as PopoverTrigger, r as PopoverContent, t as Popover } from "../popover-Ds9624qY.mjs";
14
14
  import { i as SelectItem, l as SelectTrigger, n as SelectContent, t as Select, u as SelectValue } from "../select-CwVIFWFO.mjs";
15
- import { t as Skeleton } from "../skeleton-Cs6Q5GQc.mjs";
16
- import { c as TableRow, i as TableCell, n as TableBody, o as TableHead, s as TableHeader, t as Table } from "../table-Dc3HfbM4.mjs";
17
- import { t as CalendarDatePicker } from "../calendar-date-picker-mlbzp3xR.mjs";
15
+ import "../skeleton-CkE23wsL.mjs";
16
+ import { t as Skeleton } from "../skeleton-DZ31pU4B.mjs";
17
+ import { c as TableRow, i as TableCell, n as TableBody, o as TableHead, s as TableHeader, t as Table } from "../table-Dpzh0VPK.mjs";
18
+ import { t as CalendarDatePicker } from "../calendar-date-picker-Bw6Mrr-P.mjs";
18
19
  import { ArrowDown, ArrowUp, ArrowUpDown, Check, ChevronDown, ChevronLeft, ChevronRight, MoreHorizontal, X } from "lucide-react";
19
- import { createContext, memo, use, useCallback, useEffect, useId, useMemo, useRef, useState, useSyncExternalStore } from "react";
20
+ import { createContext, memo, use, useCallback, useContext, useEffect, useId, useMemo, useRef, useState, useSyncExternalStore } from "react";
20
21
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
21
22
  import { parseAsInteger, parseAsString, useQueryStates } from "nuqs";
22
23
  import { flexRender, getCoreRowModel, getPaginationRowModel, getSortedRowModel, useReactTable } from "@tanstack/react-table";
@@ -157,6 +158,16 @@ function withSelectionColumn(columns, options = {}) {
157
158
 
158
159
  //#endregion
159
160
  //#region src/components/features/data-table/core/filter-engine.ts
161
+ /**
162
+ * Resolve a dot-path on an object (e.g. "status.registrationApproval").
163
+ * Falls back to a flat key lookup when the path has no dots.
164
+ */
165
+ function resolvePath(obj, path) {
166
+ if (obj == null) return void 0;
167
+ const record = obj;
168
+ if (!path.includes(".")) return record[path];
169
+ return path.split(".").reduce((acc, key) => acc != null ? acc[key] : void 0, record);
170
+ }
160
171
  const FILTER_STRATEGIES = {
161
172
  "checkbox": (cellValue, filterValue) => {
162
173
  if (filterValue == null) return true;
@@ -200,14 +211,13 @@ function applyFilters(data, filters, search, registeredFilters, customFilterFns,
200
211
  console.warn(`[DataTable] No filter strategy registered for column "${column}". Filter ignored.`);
201
212
  continue;
202
213
  }
203
- const cellValue = row[column];
204
- if (!fn(cellValue, value)) return false;
214
+ if (!fn(resolvePath(row, column), value)) return false;
205
215
  }
206
216
  if (hasSearch) {
207
217
  const query = search.toLowerCase();
208
218
  if (searchConfig.searchFn) return searchConfig.searchFn(row, search);
209
219
  if (searchConfig.searchableColumns && searchConfig.searchableColumns.length > 0) return searchConfig.searchableColumns.some((col) => {
210
- const cellValue = row[col];
220
+ const cellValue = resolvePath(row, col);
211
221
  return cellValue != null && String(cellValue).toLowerCase().includes(query);
212
222
  });
213
223
  return Object.values(row).some((val) => {
@@ -243,7 +253,8 @@ function createDataTableStore(options) {
243
253
  mode: options.mode,
244
254
  isLoading: false,
245
255
  error: null,
246
- inlineContents: []
256
+ inlineContents: [],
257
+ _version: 0
247
258
  };
248
259
  if (options.defaultFilters && Object.keys(options.defaultFilters).length > 0) state = {
249
260
  ...state,
@@ -253,7 +264,10 @@ function createDataTableStore(options) {
253
264
  for (const listener of listeners) listener();
254
265
  }
255
266
  function setState(next) {
256
- state = next;
267
+ state = {
268
+ ...next,
269
+ _version: state._version + 1
270
+ };
257
271
  notify();
258
272
  }
259
273
  return {
@@ -442,6 +456,22 @@ function createDataTableStore(options) {
442
456
  //#region src/components/features/data-table/core/data-table-context.tsx
443
457
  const DataTableStoreContext = createContext(null);
444
458
  const TableInstanceContext = createContext(null);
459
+ /**
460
+ * Monotonic counter that increments on every store mutation.
461
+ * Table-dependent hooks consume this context to force re-renders
462
+ * through React's {children} composition boundary, since the
463
+ * mutable table singleton (stable ref) cannot trigger context updates.
464
+ */
465
+ const DataTableRenderKeyContext = createContext(0);
466
+ /**
467
+ * Forces a re-render when the store changes. Used by table-dependent hooks.
468
+ * Uses useContext (not use()) because use() does not reliably register
469
+ * context subscriptions in SSR/hydration scenarios (React Router SSR),
470
+ * preventing re-renders when the context value changes.
471
+ */
472
+ function useRenderKey() {
473
+ return useContext(DataTableRenderKeyContext);
474
+ }
445
475
  const DataTableContext = createContext(null);
446
476
  function useDataTableStore() {
447
477
  const store = use(DataTableStoreContext);
@@ -482,7 +512,7 @@ function useSliceSelector(selector) {
482
512
  cachedRef.current = next;
483
513
  return next;
484
514
  }, [store, selector]);
485
- return useSyncExternalStore(store.subscribe, getSnapshot);
515
+ return useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);
486
516
  }
487
517
  function useDataTableFilters() {
488
518
  const store = useDataTableStore();
@@ -511,20 +541,23 @@ function useDataTableSorting() {
511
541
  }), [store]));
512
542
  }
513
543
  function useDataTableSelection() {
544
+ useRenderKey();
514
545
  const store = useDataTableStore();
515
546
  const table = useTableInstance();
516
- return useSliceSelector(useCallback((state) => ({
517
- rowSelection: state.rowSelection,
547
+ return {
548
+ rowSelection: store.getSnapshot().rowSelection,
518
549
  setRowSelection: store.setRowSelection,
519
550
  selectedRows: table.getFilteredSelectedRowModel().rows.map((r) => r.original)
520
- }), [store, table]));
551
+ };
521
552
  }
522
553
  function useDataTablePagination() {
554
+ useRenderKey();
523
555
  const store = useDataTableStore();
524
556
  const table = useTableInstance();
557
+ const state = store.getSnapshot();
525
558
  const nextPage = useCallback(() => table.nextPage(), [table]);
526
559
  const prevPage = useCallback(() => table.previousPage(), [table]);
527
- return useSliceSelector(useCallback((state) => ({
560
+ return {
528
561
  canNextPage: table.getCanNextPage(),
529
562
  canPrevPage: table.getCanPreviousPage(),
530
563
  nextPage,
@@ -535,20 +568,16 @@ function useDataTablePagination() {
535
568
  pageSize: state.pageSize,
536
569
  setPageSize: store.setPageSize,
537
570
  totalRows: state.filteredData.length
538
- }), [
539
- store,
540
- table,
541
- nextPage,
542
- prevPage
543
- ]));
571
+ };
544
572
  }
545
573
  function useDataTableRows() {
574
+ useRenderKey();
546
575
  const table = useTableInstance();
547
- return useSliceSelector(useCallback((_state) => ({
576
+ return {
548
577
  rows: table.getRowModel().rows,
549
578
  headerGroups: table.getHeaderGroups(),
550
579
  totalColumns: table.getAllColumns().length
551
- }), [table]));
580
+ };
552
581
  }
553
582
  function useDataTableLoading() {
554
583
  return useSliceSelector(useCallback((state) => ({
@@ -564,41 +593,6 @@ function useDataTableInlineContents() {
564
593
  unregisterInlineContent: store.unregisterInlineContent
565
594
  }), [store]));
566
595
  }
567
- function useDataTableContext() {
568
- const store = useDataTableStore();
569
- const table = useTableInstance();
570
- const state = useSyncExternalStore(store.subscribe, store.getSnapshot);
571
- return {
572
- table,
573
- mode: state.mode,
574
- sorting: state.sorting,
575
- filters: state.filters,
576
- search: state.search,
577
- rowSelection: state.rowSelection,
578
- isLoading: state.isLoading,
579
- setSorting: store.setSorting,
580
- setFilter: store.setFilter,
581
- clearFilter: store.clearFilter,
582
- clearAllFilters: store.clearAllFilters,
583
- setSearch: store.setSearch,
584
- clearSearch: store.clearSearch,
585
- setRowSelection: store.setRowSelection,
586
- pagination: {
587
- canNextPage: table.getCanNextPage(),
588
- canPrevPage: table.getCanPreviousPage(),
589
- nextPage: () => table.nextPage(),
590
- prevPage: () => table.previousPage(),
591
- pageIndex: state.pageIndex,
592
- pageCount: table.getPageCount(),
593
- setPageIndex: store.setPageIndex,
594
- pageSize: state.pageSize,
595
- setPageSize: store.setPageSize
596
- },
597
- inlineContents: state.inlineContents,
598
- registerInlineContent: store.registerInlineContent,
599
- unregisterInlineContent: store.unregisterInlineContent
600
- };
601
- }
602
596
 
603
597
  //#endregion
604
598
  //#region src/components/features/data-table/components/active-filters.tsx
@@ -621,14 +615,15 @@ function FilterGroup({ label, children, className }) {
621
615
  });
622
616
  }
623
617
  const EMPTY_LABELS = {};
624
- function ActiveFiltersInner({ label = "Selected Filters", filterLabels = EMPTY_LABELS, formatFilterValue: formatter, clearAll = "icon", clearAllLabel = "Clear all", className, groupClassName, badgeClassName }) {
618
+ function ActiveFiltersInner({ label = "Selected Filters", excludeFilters, filterLabels = EMPTY_LABELS, formatFilterValue: formatter, clearAll = "icon", clearAllLabel = "Clear all", className, groupClassName, badgeClassName }) {
625
619
  const { filters, setFilter, clearFilter, clearAllFilters } = useDataTableFilters();
626
620
  const { search, clearSearch } = useDataTableSearch();
627
- const activeFilterEntries = Object.entries(filters).filter(([, value]) => value != null && value !== "" && !(Array.isArray(value) && value.length === 0));
628
- const hasSearch = search.length > 0;
621
+ const excludeSet = useMemo(() => new Set(excludeFilters ?? []), [excludeFilters]);
622
+ const activeFilterEntries = Object.entries(filters).filter(([key, value]) => !excludeSet.has(key) && value != null && value !== "" && !(Array.isArray(value) && value.length === 0));
623
+ const showSearch = search.length > 0 && !excludeSet.has("search");
629
624
  const hasFilters = activeFilterEntries.length > 0;
630
- if (!hasSearch && !hasFilters) return null;
631
- const totalGroups = activeFilterEntries.length + (hasSearch ? 1 : 0);
625
+ if (!showSearch && !hasFilters) return null;
626
+ const totalGroups = activeFilterEntries.length + (showSearch ? 1 : 0);
632
627
  const removeArrayItem = (column, items, item) => {
633
628
  const remaining = items.filter((v) => v !== item);
634
629
  if (remaining.length > 0) setFilter(column, remaining);
@@ -636,7 +631,7 @@ function ActiveFiltersInner({ label = "Selected Filters", filterLabels = EMPTY_L
636
631
  };
637
632
  const handleClearAll = () => {
638
633
  clearAllFilters();
639
- if (hasSearch) clearSearch();
634
+ if (search.length > 0) clearSearch();
640
635
  };
641
636
  const badgeCn = cn("flex items-center gap-1.5 px-2 py-0.5 text-xs", badgeClassName);
642
637
  return /* @__PURE__ */ jsxs("div", {
@@ -649,7 +644,7 @@ function ActiveFiltersInner({ label = "Selected Filters", filterLabels = EMPTY_L
649
644
  "data-slot": "dt-active-filters-label",
650
645
  children: label
651
646
  }),
652
- hasSearch && /* @__PURE__ */ jsx(FilterGroup, {
647
+ showSearch && /* @__PURE__ */ jsx(FilterGroup, {
653
648
  label: "Search",
654
649
  className: groupClassName,
655
650
  children: /* @__PURE__ */ jsxs(Badge, {
@@ -914,19 +909,8 @@ function DataTableLoading({ rows = DEFAULT_LOADING_ROWS, columns = 4, className
914
909
  return /* @__PURE__ */ jsx("div", {
915
910
  className,
916
911
  "data-slot": "dt-loading",
917
- children: /* @__PURE__ */ jsxs("div", {
918
- className: "rounded-md border",
919
- children: [/* @__PURE__ */ jsx("div", {
920
- className: "border-b",
921
- children: /* @__PURE__ */ jsx("div", {
922
- className: "flex gap-4 p-4",
923
- children: Array.from({ length: columns }, (_, i) => /* @__PURE__ */ jsx(Skeleton, { className: "h-4 flex-1" }, i))
924
- })
925
- }), Array.from({ length: rows }, (_, rowIndex) => /* @__PURE__ */ jsx("div", {
926
- className: "flex gap-4 border-b p-4 last:border-b-0",
927
- children: Array.from({ length: columns }, (_, colIndex) => /* @__PURE__ */ jsx(Skeleton, { className: "h-4 flex-1" }, colIndex))
928
- }, rowIndex))]
929
- })
912
+ style: { overflowX: "auto" },
913
+ children: /* @__PURE__ */ jsxs(Table, { children: [/* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsx(TableRow, { children: Array.from({ length: columns }, (_, i) => /* @__PURE__ */ jsx(TableHead, { children: /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-24" }) }, i)) }) }), /* @__PURE__ */ jsx(TableBody, { children: Array.from({ length: rows }, (_, rowIndex) => /* @__PURE__ */ jsx(TableRow, { children: Array.from({ length: columns }, (_, colIndex) => /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-full" }) }, colIndex)) }, rowIndex)) })] })
930
914
  });
931
915
  }
932
916
 
@@ -1025,9 +1009,9 @@ function DataTablePagination({ pageSizes = DEFAULT_PAGE_SIZES, className }) {
1025
1009
  return /* @__PURE__ */ jsx(Button, {
1026
1010
  theme: isActive ? "solid" : "outline",
1027
1011
  size: "small",
1028
- className: cn("h-8 min-w-8 px-2", isActive && "font-semibold"),
1012
+ className: cn("h-8 min-w-8 px-2", isActive && "pointer-events-none font-semibold"),
1029
1013
  onClick: () => setPageIndex(page - 1),
1030
- disabled: isActive,
1014
+ "aria-disabled": isActive || void 0,
1031
1015
  "aria-label": `Page ${page}`,
1032
1016
  "aria-current": isActive ? "page" : void 0,
1033
1017
  children: page
@@ -1091,7 +1075,7 @@ function DataTableRowActions({ row, actions, isLoading = false, className }) {
1091
1075
 
1092
1076
  //#endregion
1093
1077
  //#region src/components/features/data-table/components/search.tsx
1094
- function DataTableSearch({ placeholder = "Search...", debounceMs = DEFAULT_DEBOUNCE_MS, className }) {
1078
+ function DataTableSearch({ placeholder = "Search...", debounceMs = DEFAULT_DEBOUNCE_MS, className, disabled }) {
1095
1079
  const { search, setSearch } = useDataTableSearch();
1096
1080
  const [inputValue, setInputValue] = useState(search);
1097
1081
  useEffect(() => {
@@ -1113,68 +1097,351 @@ function DataTableSearch({ placeholder = "Search...", debounceMs = DEFAULT_DEBOU
1113
1097
  value: inputValue,
1114
1098
  onChange: (e) => setInputValue(e.target.value),
1115
1099
  className,
1100
+ disabled,
1116
1101
  "aria-label": placeholder,
1117
1102
  "data-slot": "dt-search"
1118
1103
  });
1119
1104
  }
1120
1105
 
1121
1106
  //#endregion
1122
- //#region src/components/features/data-table/core/client-provider.tsx
1123
- function ClientProvider({ store, table, className, children }) {
1124
- return /* @__PURE__ */ jsx(DataTableStoreContext, {
1125
- value: store,
1126
- children: /* @__PURE__ */ jsx(TableInstanceContext, {
1127
- value: table,
1128
- children: /* @__PURE__ */ jsx("div", {
1129
- className,
1130
- children
1131
- })
1132
- })
1107
+ //#region src/components/features/data-table/hooks/use-data-table-client.ts
1108
+ function useDataTableClient(options) {
1109
+ const { data, columns, pageSize, getRowId, enableRowSelection = false, defaultSort, defaultFilters, searchableColumns, searchFn, filterFns, stateAdapter } = options;
1110
+ const store = useMemo(() => createDataTableStore({
1111
+ data,
1112
+ mode: "client",
1113
+ defaultSort,
1114
+ defaultFilters,
1115
+ pageSize,
1116
+ searchableColumns,
1117
+ searchFn,
1118
+ filterFns
1119
+ }), []);
1120
+ const isInitialRender = useRef(true);
1121
+ useEffect(() => {
1122
+ if (isInitialRender.current) {
1123
+ isInitialRender.current = false;
1124
+ return;
1125
+ }
1126
+ store.setData(data);
1127
+ }, [data, store]);
1128
+ const resolvedColumns = useMemo(() => enableRowSelection ? withSelectionColumn(columns, typeof enableRowSelection === "object" ? enableRowSelection : {}) : columns, [columns, enableRowSelection]);
1129
+ const { filteredData, sorting, rowSelection, pageIndex, pageSize: storePageSize, filters, search } = useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);
1130
+ const table = useReactTable({
1131
+ data: filteredData,
1132
+ columns: resolvedColumns,
1133
+ state: {
1134
+ sorting,
1135
+ rowSelection,
1136
+ pagination: {
1137
+ pageIndex,
1138
+ pageSize: storePageSize
1139
+ }
1140
+ },
1141
+ onSortingChange: (updater) => {
1142
+ const next = typeof updater === "function" ? updater(sorting) : updater;
1143
+ store.setSorting(next);
1144
+ },
1145
+ onRowSelectionChange: (updater) => {
1146
+ const next = typeof updater === "function" ? updater(rowSelection) : updater;
1147
+ store.setRowSelection(next);
1148
+ },
1149
+ onPaginationChange: (updater) => {
1150
+ const next = typeof updater === "function" ? updater({
1151
+ pageIndex,
1152
+ pageSize: storePageSize
1153
+ }) : updater;
1154
+ store.setPagination(next.pageIndex, next.pageSize);
1155
+ },
1156
+ getCoreRowModel: getCoreRowModel(),
1157
+ getSortedRowModel: getSortedRowModel(),
1158
+ getPaginationRowModel: getPaginationRowModel(),
1159
+ getRowId,
1160
+ enableRowSelection: !!enableRowSelection
1133
1161
  });
1162
+ const hydratedRef = useRef(false);
1163
+ useEffect(() => {
1164
+ if (stateAdapter && !hydratedRef.current) {
1165
+ hydratedRef.current = true;
1166
+ const persisted = stateAdapter.read();
1167
+ if (persisted.sorting && persisted.sorting.length > 0) store.setSorting(persisted.sorting);
1168
+ if (persisted.filters) {
1169
+ for (const [key, value] of Object.entries(persisted.filters)) if (value != null) store.setFilter(key, value);
1170
+ }
1171
+ if (persisted.search) store.setSearch(persisted.search);
1172
+ if (persisted.pageIndex != null && persisted.pageIndex > 0) store.setPageIndex(persisted.pageIndex);
1173
+ if (persisted.pageSize != null) store.setPageSize(persisted.pageSize);
1174
+ }
1175
+ }, []);
1176
+ const isFirstWrite = useRef(true);
1177
+ useEffect(() => {
1178
+ if (!stateAdapter) return;
1179
+ if (isFirstWrite.current) {
1180
+ isFirstWrite.current = false;
1181
+ return;
1182
+ }
1183
+ stateAdapter.write({
1184
+ sorting,
1185
+ filters,
1186
+ search,
1187
+ pageIndex,
1188
+ pageSize: storePageSize
1189
+ });
1190
+ }, [
1191
+ sorting,
1192
+ filters,
1193
+ search,
1194
+ pageIndex,
1195
+ storePageSize,
1196
+ stateAdapter
1197
+ ]);
1198
+ return {
1199
+ store,
1200
+ table
1201
+ };
1134
1202
  }
1135
1203
 
1136
1204
  //#endregion
1137
- //#region src/components/features/data-table/core/server-provider.tsx
1138
- function ServerProvider({ store, table, className, children }) {
1205
+ //#region src/components/features/data-table/hooks/use-is-client.ts
1206
+ /**
1207
+ * Returns `false` during SSR and `true` after hydration.
1208
+ * Used to gate components that depend on client-only APIs
1209
+ * (e.g. TanStack Table's internal useSyncExternalStore call
1210
+ * which omits the getServerSnapshot argument).
1211
+ */
1212
+ function useIsClient() {
1213
+ const [isClient, setIsClient] = useState(false);
1214
+ useEffect(() => setIsClient(true), []);
1215
+ return isClient;
1216
+ }
1217
+
1218
+ //#endregion
1219
+ //#region src/components/features/data-table/core/client-provider.tsx
1220
+ /**
1221
+ * Inner component that calls useDataTableClient.
1222
+ * Only rendered on the client (gated by ClientProvider).
1223
+ */
1224
+ function ClientProviderInner({ className, children, ssrFallback: _ssrFallback, ...options }) {
1225
+ const { store, table } = useDataTableClient(options);
1139
1226
  return /* @__PURE__ */ jsx(DataTableStoreContext, {
1140
1227
  value: store,
1141
1228
  children: /* @__PURE__ */ jsx(TableInstanceContext, {
1142
1229
  value: table,
1143
- children: /* @__PURE__ */ jsx("div", {
1144
- className,
1145
- children
1230
+ children: /* @__PURE__ */ jsx(DataTableRenderKeyContext, {
1231
+ value: store.getSnapshot()._version,
1232
+ children: /* @__PURE__ */ jsx("div", {
1233
+ className,
1234
+ children
1235
+ })
1146
1236
  })
1147
1237
  })
1148
1238
  });
1149
1239
  }
1240
+ function ClientProvider(props) {
1241
+ if (!useIsClient()) return /* @__PURE__ */ jsx(Fragment$1, { children: props.ssrFallback === void 0 ? /* @__PURE__ */ jsx(DataTableLoading, {
1242
+ columns: props.columns.length,
1243
+ className: props?.className
1244
+ }) : props.ssrFallback });
1245
+ return /* @__PURE__ */ jsx(ClientProviderInner, { ...props });
1246
+ }
1150
1247
 
1151
1248
  //#endregion
1152
- //#region src/components/features/data-table/filters/checkbox-filter.tsx
1153
- const MAX_VISIBLE_BADGES = 2;
1154
- function CheckboxFilter({ column, label, options, className, checkboxPopoverClassName }) {
1155
- const { filters, setFilter, clearFilter, registerFilter, unregisterFilter } = useDataTableFilters();
1156
- const [open, setOpen] = useState(false);
1249
+ //#region src/components/features/data-table/hooks/use-data-table-server.ts
1250
+ function useDataTableServer(options) {
1251
+ const { columns, fetchFn, transform, limit = 20, getRowId, enableRowSelection = false, defaultSort, defaultFilters, stateAdapter } = options;
1252
+ const fetchRef = useRef(fetchFn);
1253
+ const transformRef = useRef(transform);
1157
1254
  useEffect(() => {
1158
- registerFilter(column, "checkbox");
1159
- return () => unregisterFilter(column);
1255
+ fetchRef.current = fetchFn;
1256
+ }, [fetchFn]);
1257
+ useEffect(() => {
1258
+ transformRef.current = transform;
1259
+ }, [transform]);
1260
+ const cursorMapRef = useRef(/* @__PURE__ */ new Map());
1261
+ const hasNextPageRef = useRef(false);
1262
+ const store = useMemo(() => createDataTableStore({
1263
+ data: [],
1264
+ mode: "server",
1265
+ defaultSort,
1266
+ defaultFilters,
1267
+ pageSize: limit
1268
+ }), []);
1269
+ const { sorting, filters, search, rowSelection, pageSize, pageIndex } = useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);
1270
+ const prevQueryRef = useRef({
1271
+ sorting,
1272
+ filters,
1273
+ search,
1274
+ pageSize
1275
+ });
1276
+ useEffect(() => {
1277
+ const prev = prevQueryRef.current;
1278
+ if (prev.sorting !== sorting || prev.filters !== filters || prev.search !== search || prev.pageSize !== pageSize) {
1279
+ cursorMapRef.current = /* @__PURE__ */ new Map();
1280
+ hasNextPageRef.current = false;
1281
+ if (pageIndex !== 0) {
1282
+ prevQueryRef.current = {
1283
+ sorting,
1284
+ filters,
1285
+ search,
1286
+ pageSize
1287
+ };
1288
+ store.setPageIndex(0);
1289
+ return;
1290
+ }
1291
+ }
1292
+ prevQueryRef.current = {
1293
+ sorting,
1294
+ filters,
1295
+ search,
1296
+ pageSize
1297
+ };
1298
+ let cancelled = false;
1299
+ store.setLoading(true);
1300
+ const cursor = cursorMapRef.current.get(pageIndex);
1301
+ fetchRef.current({
1302
+ sorting,
1303
+ filters,
1304
+ search,
1305
+ cursor,
1306
+ limit: pageSize
1307
+ }).then((response) => {
1308
+ if (cancelled) return;
1309
+ const result = transformRef.current(response);
1310
+ store.setServerData(result.data);
1311
+ store.setError(null);
1312
+ if (result.cursor) cursorMapRef.current.set(pageIndex + 1, result.cursor);
1313
+ hasNextPageRef.current = result.hasNextPage;
1314
+ }).catch((error) => {
1315
+ if (cancelled) return;
1316
+ store.setServerData([]);
1317
+ store.setError(error instanceof Error ? error : new Error(String(error)));
1318
+ hasNextPageRef.current = false;
1319
+ }).finally(() => {
1320
+ if (!cancelled) store.setLoading(false);
1321
+ });
1322
+ return () => {
1323
+ cancelled = true;
1324
+ };
1160
1325
  }, [
1161
- column,
1162
- registerFilter,
1163
- unregisterFilter
1326
+ sorting,
1327
+ filters,
1328
+ search,
1329
+ pageSize,
1330
+ pageIndex,
1331
+ store
1164
1332
  ]);
1165
- const selectedValues = filters[column] ?? [];
1166
- const updateValues = (newValues) => {
1167
- if (newValues.length > 0) setFilter(column, newValues);
1168
- else clearFilter(column);
1169
- };
1170
- const handleToggle = (optionValue, checked) => {
1171
- updateValues(checked ? [...selectedValues, optionValue] : selectedValues.filter((v) => v !== optionValue));
1172
- };
1173
- const removeValue = (optionValue) => {
1174
- updateValues(selectedValues.filter((v) => v !== optionValue));
1175
- };
1176
- const visibleBadges = selectedValues.slice(0, MAX_VISIBLE_BADGES);
1177
- const remainingCount = selectedValues.length - MAX_VISIBLE_BADGES;
1333
+ const resolvedColumns = useMemo(() => enableRowSelection ? withSelectionColumn(columns, typeof enableRowSelection === "object" ? enableRowSelection : {}) : columns, [columns, enableRowSelection]);
1334
+ const table = useReactTable({
1335
+ data: store.getSnapshot().data,
1336
+ columns: resolvedColumns,
1337
+ state: {
1338
+ sorting,
1339
+ rowSelection,
1340
+ pagination: {
1341
+ pageIndex,
1342
+ pageSize
1343
+ }
1344
+ },
1345
+ manualPagination: true,
1346
+ manualSorting: true,
1347
+ manualFiltering: true,
1348
+ pageCount: hasNextPageRef.current ? pageIndex + 2 : pageIndex + 1,
1349
+ getCoreRowModel: getCoreRowModel(),
1350
+ getRowId,
1351
+ enableRowSelection: !!enableRowSelection,
1352
+ onSortingChange: (updater) => {
1353
+ const next = typeof updater === "function" ? updater(sorting) : updater;
1354
+ store.setSorting(next);
1355
+ },
1356
+ onRowSelectionChange: (updater) => {
1357
+ const next = typeof updater === "function" ? updater(rowSelection) : updater;
1358
+ store.setRowSelection(next);
1359
+ },
1360
+ onPaginationChange: (updater) => {
1361
+ const next = typeof updater === "function" ? updater({
1362
+ pageIndex,
1363
+ pageSize
1364
+ }) : updater;
1365
+ store.setPagination(next.pageIndex, next.pageSize);
1366
+ }
1367
+ });
1368
+ useEffect(() => {
1369
+ if (stateAdapter) stateAdapter.write({
1370
+ sorting,
1371
+ filters,
1372
+ search,
1373
+ pageSize
1374
+ });
1375
+ }, [
1376
+ sorting,
1377
+ filters,
1378
+ search,
1379
+ pageSize,
1380
+ stateAdapter
1381
+ ]);
1382
+ return {
1383
+ store,
1384
+ table
1385
+ };
1386
+ }
1387
+
1388
+ //#endregion
1389
+ //#region src/components/features/data-table/core/server-provider.tsx
1390
+ /**
1391
+ * Inner component that calls useDataTableServer.
1392
+ * Only rendered on the client (gated by ServerProvider).
1393
+ */
1394
+ function ServerProviderInner({ className, children, ssrFallback: _ssrFallback, ...options }) {
1395
+ const { store, table } = useDataTableServer(options);
1396
+ return /* @__PURE__ */ jsx(DataTableStoreContext, {
1397
+ value: store,
1398
+ children: /* @__PURE__ */ jsx(TableInstanceContext, {
1399
+ value: table,
1400
+ children: /* @__PURE__ */ jsx(DataTableRenderKeyContext, {
1401
+ value: store.getSnapshot()._version,
1402
+ children: /* @__PURE__ */ jsx("div", {
1403
+ className,
1404
+ children
1405
+ })
1406
+ })
1407
+ })
1408
+ });
1409
+ }
1410
+ function ServerProvider(props) {
1411
+ if (!useIsClient()) return /* @__PURE__ */ jsx(Fragment$1, { children: props.ssrFallback === void 0 ? /* @__PURE__ */ jsx(DataTableLoading, {
1412
+ columns: props.columns.length,
1413
+ className: props?.className
1414
+ }) : props.ssrFallback });
1415
+ return /* @__PURE__ */ jsx(ServerProviderInner, { ...props });
1416
+ }
1417
+
1418
+ //#endregion
1419
+ //#region src/components/features/data-table/filters/checkbox-filter.tsx
1420
+ const MAX_VISIBLE_BADGES = 2;
1421
+ function CheckboxFilter({ column, label, options, className, checkboxPopoverClassName, disabled }) {
1422
+ const { filters, setFilter, clearFilter, registerFilter, unregisterFilter } = useDataTableFilters();
1423
+ const [open, setOpen] = useState(false);
1424
+ useEffect(() => {
1425
+ registerFilter(column, "checkbox");
1426
+ return () => unregisterFilter(column);
1427
+ }, [
1428
+ column,
1429
+ registerFilter,
1430
+ unregisterFilter
1431
+ ]);
1432
+ const selectedValues = filters[column] ?? [];
1433
+ const updateValues = (newValues) => {
1434
+ if (newValues.length > 0) setFilter(column, newValues);
1435
+ else clearFilter(column);
1436
+ };
1437
+ const handleToggle = (optionValue, checked) => {
1438
+ updateValues(checked ? [...selectedValues, optionValue] : selectedValues.filter((v) => v !== optionValue));
1439
+ };
1440
+ const removeValue = (optionValue) => {
1441
+ updateValues(selectedValues.filter((v) => v !== optionValue));
1442
+ };
1443
+ const visibleBadges = selectedValues.slice(0, MAX_VISIBLE_BADGES);
1444
+ const remainingCount = selectedValues.length - MAX_VISIBLE_BADGES;
1178
1445
  return /* @__PURE__ */ jsxs(Popover, {
1179
1446
  open,
1180
1447
  onOpenChange: setOpen,
@@ -1182,7 +1449,8 @@ function CheckboxFilter({ column, label, options, className, checkboxPopoverClas
1182
1449
  asChild: true,
1183
1450
  children: /* @__PURE__ */ jsxs(Button, {
1184
1451
  theme: "outline",
1185
- className: cn("justify-between gap-1", className),
1452
+ disabled,
1453
+ className: cn("h-10 justify-between gap-1", className),
1186
1454
  "data-slot": "dt-filter",
1187
1455
  "data-testid": "dt-filter-trigger",
1188
1456
  children: [selectedValues.length > 0 ? /* @__PURE__ */ jsxs("div", {
@@ -1261,7 +1529,7 @@ function CheckboxFilter({ column, label, options, className, checkboxPopoverClas
1261
1529
 
1262
1530
  //#endregion
1263
1531
  //#region src/components/features/data-table/filters/date-picker-filter.tsx
1264
- function DatePickerFilter({ column, label, className, datePickerPopoverClassName, disableFuture, disablePast, minDate, maxDate }) {
1532
+ function DatePickerFilter({ column, label, className, datePickerPopoverClassName, disableFuture, disablePast, minDate, maxDate, disabled }) {
1265
1533
  const { filters, setFilter, clearFilter, registerFilter, unregisterFilter } = useDataTableFilters();
1266
1534
  const rawValue = filters[column];
1267
1535
  useEffect(() => {
@@ -1286,8 +1554,9 @@ function DatePickerFilter({ column, label, className, datePickerPopoverClassName
1286
1554
  numberOfMonths: 1,
1287
1555
  closeOnSelect: true,
1288
1556
  placeholder: label,
1289
- triggerClassName: className,
1557
+ triggerClassName: cn("h-10", className),
1290
1558
  variant: "outline",
1559
+ disabled,
1291
1560
  disableFuture,
1292
1561
  disablePast,
1293
1562
  minDate,
@@ -1303,7 +1572,7 @@ function DatePickerFilter({ column, label, className, datePickerPopoverClassName
1303
1572
 
1304
1573
  //#endregion
1305
1574
  //#region src/components/features/data-table/filters/select-filter.tsx
1306
- function SelectFilter({ column, label, options, placeholder, searchable = true, className, selectPopoverClassName }) {
1575
+ function SelectFilter({ column, label, options, placeholder, searchable = true, className, selectPopoverClassName, disabled }) {
1307
1576
  const { filters, setFilter, clearFilter, registerFilter, unregisterFilter } = useDataTableFilters();
1308
1577
  const [open, setOpen] = useState(false);
1309
1578
  const value = filters[column];
@@ -1325,7 +1594,8 @@ function SelectFilter({ column, label, options, placeholder, searchable = true,
1325
1594
  theme: "outline",
1326
1595
  role: "combobox",
1327
1596
  "aria-expanded": open,
1328
- className: cn("justify-between", className),
1597
+ disabled,
1598
+ className: cn("h-10 justify-between", className),
1329
1599
  "data-slot": "dt-filter",
1330
1600
  "data-testid": "dt-filter-trigger",
1331
1601
  children: [/* @__PURE__ */ jsx("span", {
@@ -1388,242 +1658,4 @@ const DataTable = {
1388
1658
  };
1389
1659
 
1390
1660
  //#endregion
1391
- //#region src/components/features/data-table/hooks/use-data-table-client.ts
1392
- function useDataTableClient(options) {
1393
- const { data, columns, pageSize, getRowId, enableRowSelection = false, defaultSort, defaultFilters, searchableColumns, searchFn, filterFns, stateAdapter } = options;
1394
- const store = useMemo(() => createDataTableStore({
1395
- data,
1396
- mode: "client",
1397
- defaultSort,
1398
- defaultFilters,
1399
- pageSize,
1400
- searchableColumns,
1401
- searchFn,
1402
- filterFns
1403
- }), []);
1404
- const isInitialRender = useRef(true);
1405
- useEffect(() => {
1406
- if (isInitialRender.current) {
1407
- isInitialRender.current = false;
1408
- return;
1409
- }
1410
- store.setData(data);
1411
- }, [data, store]);
1412
- const resolvedColumns = useMemo(() => enableRowSelection ? withSelectionColumn(columns, typeof enableRowSelection === "object" ? enableRowSelection : {}) : columns, [columns, enableRowSelection]);
1413
- const { filteredData, sorting, rowSelection, pageIndex, pageSize: storePageSize, filters, search } = useSyncExternalStore(store.subscribe, store.getSnapshot);
1414
- const table = useReactTable({
1415
- data: filteredData,
1416
- columns: resolvedColumns,
1417
- state: {
1418
- sorting,
1419
- rowSelection,
1420
- pagination: {
1421
- pageIndex,
1422
- pageSize: storePageSize
1423
- }
1424
- },
1425
- onSortingChange: (updater) => {
1426
- const next = typeof updater === "function" ? updater(sorting) : updater;
1427
- store.setSorting(next);
1428
- },
1429
- onRowSelectionChange: (updater) => {
1430
- const next = typeof updater === "function" ? updater(rowSelection) : updater;
1431
- store.setRowSelection(next);
1432
- },
1433
- onPaginationChange: (updater) => {
1434
- const next = typeof updater === "function" ? updater({
1435
- pageIndex,
1436
- pageSize: storePageSize
1437
- }) : updater;
1438
- store.setPagination(next.pageIndex, next.pageSize);
1439
- },
1440
- getCoreRowModel: getCoreRowModel(),
1441
- getSortedRowModel: getSortedRowModel(),
1442
- getPaginationRowModel: getPaginationRowModel(),
1443
- getRowId,
1444
- enableRowSelection: !!enableRowSelection
1445
- });
1446
- const hydratedRef = useRef(false);
1447
- useEffect(() => {
1448
- if (stateAdapter && !hydratedRef.current) {
1449
- hydratedRef.current = true;
1450
- const persisted = stateAdapter.read();
1451
- if (persisted.sorting && persisted.sorting.length > 0) store.setSorting(persisted.sorting);
1452
- if (persisted.filters) {
1453
- for (const [key, value] of Object.entries(persisted.filters)) if (value != null) store.setFilter(key, value);
1454
- }
1455
- if (persisted.search) store.setSearch(persisted.search);
1456
- if (persisted.pageIndex != null && persisted.pageIndex > 0) store.setPageIndex(persisted.pageIndex);
1457
- if (persisted.pageSize != null) store.setPageSize(persisted.pageSize);
1458
- }
1459
- }, []);
1460
- const isFirstWrite = useRef(true);
1461
- useEffect(() => {
1462
- if (!stateAdapter) return;
1463
- if (isFirstWrite.current) {
1464
- isFirstWrite.current = false;
1465
- return;
1466
- }
1467
- stateAdapter.write({
1468
- sorting,
1469
- filters,
1470
- search,
1471
- pageIndex,
1472
- pageSize: storePageSize
1473
- });
1474
- }, [
1475
- sorting,
1476
- filters,
1477
- search,
1478
- pageIndex,
1479
- storePageSize,
1480
- stateAdapter
1481
- ]);
1482
- return {
1483
- store,
1484
- table
1485
- };
1486
- }
1487
-
1488
- //#endregion
1489
- //#region src/components/features/data-table/hooks/use-data-table-server.ts
1490
- function useDataTableServer(options) {
1491
- const { columns, fetchFn, transform, limit = 20, getRowId, enableRowSelection = false, defaultSort, defaultFilters, stateAdapter } = options;
1492
- const fetchRef = useRef(fetchFn);
1493
- const transformRef = useRef(transform);
1494
- useEffect(() => {
1495
- fetchRef.current = fetchFn;
1496
- }, [fetchFn]);
1497
- useEffect(() => {
1498
- transformRef.current = transform;
1499
- }, [transform]);
1500
- const cursorMapRef = useRef(/* @__PURE__ */ new Map());
1501
- const hasNextPageRef = useRef(false);
1502
- const store = useMemo(() => createDataTableStore({
1503
- data: [],
1504
- mode: "server",
1505
- defaultSort,
1506
- defaultFilters,
1507
- pageSize: limit
1508
- }), []);
1509
- const { sorting, filters, search, rowSelection, pageSize, pageIndex } = useSyncExternalStore(store.subscribe, store.getSnapshot);
1510
- const prevQueryRef = useRef({
1511
- sorting,
1512
- filters,
1513
- search,
1514
- pageSize
1515
- });
1516
- useEffect(() => {
1517
- const prev = prevQueryRef.current;
1518
- if (prev.sorting !== sorting || prev.filters !== filters || prev.search !== search || prev.pageSize !== pageSize) {
1519
- cursorMapRef.current = /* @__PURE__ */ new Map();
1520
- hasNextPageRef.current = false;
1521
- if (pageIndex !== 0) {
1522
- prevQueryRef.current = {
1523
- sorting,
1524
- filters,
1525
- search,
1526
- pageSize
1527
- };
1528
- store.setPageIndex(0);
1529
- return;
1530
- }
1531
- }
1532
- prevQueryRef.current = {
1533
- sorting,
1534
- filters,
1535
- search,
1536
- pageSize
1537
- };
1538
- let cancelled = false;
1539
- store.setLoading(true);
1540
- const cursor = cursorMapRef.current.get(pageIndex);
1541
- fetchRef.current({
1542
- sorting,
1543
- filters,
1544
- search,
1545
- cursor,
1546
- limit: pageSize
1547
- }).then((response) => {
1548
- if (cancelled) return;
1549
- const result = transformRef.current(response);
1550
- store.setServerData(result.data);
1551
- store.setError(null);
1552
- if (result.nextCursor) cursorMapRef.current.set(pageIndex + 1, result.nextCursor);
1553
- hasNextPageRef.current = result.hasNextPage;
1554
- }).catch((error) => {
1555
- if (cancelled) return;
1556
- store.setServerData([]);
1557
- store.setError(error instanceof Error ? error : new Error(String(error)));
1558
- hasNextPageRef.current = false;
1559
- }).finally(() => {
1560
- if (!cancelled) store.setLoading(false);
1561
- });
1562
- return () => {
1563
- cancelled = true;
1564
- };
1565
- }, [
1566
- sorting,
1567
- filters,
1568
- search,
1569
- pageSize,
1570
- pageIndex,
1571
- store
1572
- ]);
1573
- const resolvedColumns = useMemo(() => enableRowSelection ? withSelectionColumn(columns, typeof enableRowSelection === "object" ? enableRowSelection : {}) : columns, [columns, enableRowSelection]);
1574
- const table = useReactTable({
1575
- data: store.getSnapshot().data,
1576
- columns: resolvedColumns,
1577
- state: {
1578
- sorting,
1579
- rowSelection,
1580
- pagination: {
1581
- pageIndex,
1582
- pageSize
1583
- }
1584
- },
1585
- manualPagination: true,
1586
- manualSorting: true,
1587
- manualFiltering: true,
1588
- pageCount: hasNextPageRef.current ? pageIndex + 2 : pageIndex + 1,
1589
- getCoreRowModel: getCoreRowModel(),
1590
- getRowId,
1591
- enableRowSelection: !!enableRowSelection,
1592
- onSortingChange: (updater) => {
1593
- const next = typeof updater === "function" ? updater(sorting) : updater;
1594
- store.setSorting(next);
1595
- },
1596
- onRowSelectionChange: (updater) => {
1597
- const next = typeof updater === "function" ? updater(rowSelection) : updater;
1598
- store.setRowSelection(next);
1599
- },
1600
- onPaginationChange: (updater) => {
1601
- const next = typeof updater === "function" ? updater({
1602
- pageIndex,
1603
- pageSize
1604
- }) : updater;
1605
- store.setPagination(next.pageIndex, next.pageSize);
1606
- }
1607
- });
1608
- useEffect(() => {
1609
- if (stateAdapter) stateAdapter.write({
1610
- sorting,
1611
- filters,
1612
- search,
1613
- pageSize
1614
- });
1615
- }, [
1616
- sorting,
1617
- filters,
1618
- search,
1619
- pageSize,
1620
- stateAdapter
1621
- ]);
1622
- return {
1623
- store,
1624
- table
1625
- };
1626
- }
1627
-
1628
- //#endregion
1629
- export { DEFAULT_DEBOUNCE_MS, DEFAULT_LOADING_ROWS, DEFAULT_PAGE_SIZE, DEFAULT_PAGE_SIZES, DataTable, createDataTableStore, createSelectionColumn, useDataTableClient, useDataTableContext, useDataTableFilters, useDataTableInlineContents, useDataTableLoading, useDataTablePagination, useDataTableRows, useDataTableSearch, useDataTableSelection, useDataTableServer, useDataTableSorting, useNuqsAdapter };
1661
+ export { DEFAULT_DEBOUNCE_MS, DEFAULT_LOADING_ROWS, DEFAULT_PAGE_SIZE, DEFAULT_PAGE_SIZES, DataTable, createDataTableStore, createSelectionColumn, useDataTableFilters, useDataTableInlineContents, useDataTableLoading, useDataTablePagination, useDataTableRows, useDataTableSearch, useDataTableSelection, useDataTableSorting, useNuqsAdapter };