@dmsi/wedgekit-react 0.0.206 → 0.0.208

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 (42) hide show
  1. package/dist/{chunk-WNQ53SVY.js → chunk-E6Y7ZHQX.js} +45 -1
  2. package/dist/{chunk-RXPS5GVE.js → chunk-EFX3RPW4.js} +3 -3
  3. package/dist/{chunk-WXHRJSDG.js → chunk-ERW3AMED.js} +1 -1
  4. package/dist/{chunk-2JRZCC2K.js → chunk-JITZWSPR.js} +3 -3
  5. package/dist/{chunk-WE55TGZZ.js → chunk-NIHZMIOL.js} +1 -1
  6. package/dist/{chunk-M3433XEJ.js → chunk-T3F37S6Z.js} +15 -1
  7. package/dist/{chunk-2B5T4NCT.js → chunk-UKSJPFN2.js} +2 -2
  8. package/dist/components/DataGridCell.cjs +68 -65
  9. package/dist/components/DataGridCell.js +7 -6
  10. package/dist/components/DateInput.cjs +23 -23
  11. package/dist/components/DateInput.js +4 -4
  12. package/dist/components/DateRangeInput.cjs +23 -23
  13. package/dist/components/DateRangeInput.js +4 -4
  14. package/dist/components/Menu.cjs +38 -35
  15. package/dist/components/Menu.js +6 -4
  16. package/dist/components/MenuOption.cjs +7 -4
  17. package/dist/components/MenuOption.js +5 -2
  18. package/dist/components/Modal.cjs +15 -12
  19. package/dist/components/Modal.js +5 -3
  20. package/dist/components/NestedMenu.cjs +9 -6
  21. package/dist/components/NestedMenu.js +5 -2
  22. package/dist/components/PDFViewer.cjs +22 -19
  23. package/dist/components/PDFViewer.js +5 -3
  24. package/dist/components/ProjectBar.cjs +3 -0
  25. package/dist/components/ProjectBar.js +4 -1
  26. package/dist/components/Time.js +2 -1
  27. package/dist/components/index.cjs +190 -124
  28. package/dist/components/index.js +56 -36
  29. package/dist/components/useMenuSystem.cjs +22 -19
  30. package/dist/components/useMenuSystem.js +5 -2
  31. package/dist/hooks/index.cjs +66 -2
  32. package/dist/hooks/index.js +8 -3
  33. package/dist/utils/index.cjs +25 -0
  34. package/dist/utils/index.js +3 -1
  35. package/package.json +1 -1
  36. package/src/components/DataGrid/index.tsx +57 -31
  37. package/src/hooks/index.ts +1 -0
  38. package/src/hooks/useTableLayout.ts +68 -0
  39. package/src/utils/index.ts +1 -0
  40. package/src/utils/mergeObjectArrays.ts +18 -0
  41. package/src/utils.ts +1 -0
  42. /package/dist/{chunk-6LN6QT6M.js → chunk-VXWSAIB5.js} +0 -0
@@ -12,18 +12,20 @@ import {
12
12
  DataGridCell,
13
13
  DragAlongCell,
14
14
  DraggableCellHeader
15
- } from "../chunk-RXPS5GVE.js";
15
+ } from "../chunk-EFX3RPW4.js";
16
16
  import {
17
17
  Menu
18
- } from "../chunk-2JRZCC2K.js";
19
- import "../chunk-WE55TGZZ.js";
18
+ } from "../chunk-JITZWSPR.js";
19
+ import "../chunk-NIHZMIOL.js";
20
20
  import {
21
21
  MenuOption
22
- } from "../chunk-WXHRJSDG.js";
22
+ } from "../chunk-ERW3AMED.js";
23
23
  import {
24
- useInfiniteScroll
25
- } from "../chunk-WNQ53SVY.js";
26
- import "../chunk-6LN6QT6M.js";
24
+ useInfiniteScroll,
25
+ useTableLayout
26
+ } from "../chunk-E6Y7ZHQX.js";
27
+ import "../chunk-VXWSAIB5.js";
28
+ import "../chunk-T3F37S6Z.js";
27
29
  import {
28
30
  Search
29
31
  } from "../chunk-2WRRRPEB.js";
@@ -65,7 +67,7 @@ import {
65
67
  } from "../chunk-BBZEL7EG.js";
66
68
 
67
69
  // src/components/DataGrid/index.tsx
68
- import React3, { useCallback, useId, useState as useState3 } from "react";
70
+ import React3, { useCallback, useEffect, useId, useState as useState3 } from "react";
69
71
  import {
70
72
  flexRender as flexRender3,
71
73
  getCoreRowModel,
@@ -659,12 +661,29 @@ function DataGrid({
659
661
  useMenuDefaultMinWidth
660
662
  }) {
661
663
  var _a, _b, _c, _d, _e, _f, _g;
662
- const [columnOrder, setColumnOrder] = useState3(
663
- () => columns.map((c) => c.id)
664
- );
665
664
  const [localSorting, setLocalSorting] = useState3([]);
666
665
  const [localColumnFilters, setLocalColumnFilters] = useState3([]);
667
666
  const [localRowSelection, setLocalRowSelection] = useState3({});
667
+ const {
668
+ columns: tableColumns,
669
+ setColumns: setTableColumns,
670
+ layoutSignal
671
+ } = useTableLayout(columns, id != null ? id : testid);
672
+ const [columnOrder, setColumnOrder] = useState3(
673
+ tableColumns.map((c) => c.id)
674
+ );
675
+ const [columnVisibility, setColumnVisibility] = useState3(
676
+ Object.fromEntries(
677
+ tableColumns.filter((column) => !!column.id).map((column) => {
678
+ var _a2, _b2;
679
+ return [column.id, (_b2 = (_a2 = column.meta) == null ? void 0 : _a2.visible) != null ? _b2 : true];
680
+ })
681
+ )
682
+ );
683
+ useEffect(() => {
684
+ setColumnOrder(tableColumns.map((c) => c.id));
685
+ resetColumnVisibility();
686
+ }, [layoutSignal]);
668
687
  const sortingState = pagination ? externalSorting != null ? externalSorting : localSorting : localSorting;
669
688
  const setSortingState = pagination ? (updaterOrValue) => {
670
689
  const value = typeof updaterOrValue === "function" ? updaterOrValue(
@@ -684,36 +703,32 @@ function DataGrid({
684
703
  } : setLocalRowSelection;
685
704
  const dndId = useId();
686
705
  const containerRef = React3.useRef(null);
687
- const [columnVisibility, setColumnVisibility] = useState3(() => {
688
- const initialVisibility = {};
689
- columns.forEach((column) => {
690
- var _a2, _b2;
691
- if (column.id) {
692
- initialVisibility[column.id] = (_b2 = (_a2 = column.meta) == null ? void 0 : _a2.visible) != null ? _b2 : true;
693
- }
694
- });
695
- return initialVisibility;
696
- });
697
706
  const toggleColumnVisibility = useCallback(
698
707
  (columnId, isVisible) => {
699
- setColumnVisibility((prev) => __spreadProps(__spreadValues({}, prev), { [columnId]: isVisible }));
708
+ setTableColumns((prev) => {
709
+ const persistedIndex = prev.findIndex((col) => col.id === columnId);
710
+ if (persistedIndex !== -1) {
711
+ prev[persistedIndex].meta = __spreadProps(__spreadValues({}, prev[persistedIndex].meta), {
712
+ visible: isVisible
713
+ });
714
+ }
715
+ return [...prev];
716
+ }, true);
700
717
  },
701
- [setColumnVisibility]
718
+ [setTableColumns]
702
719
  );
703
720
  const resetColumnVisibility = useCallback(() => {
704
- setColumnVisibility(() => {
705
- const initialVisibility = {};
706
- columns.forEach((column) => {
707
- var _a2, _b2;
708
- if (column.id) {
709
- initialVisibility[column.id] = (_b2 = (_a2 = column.meta) == null ? void 0 : _a2.visible) != null ? _b2 : true;
710
- }
711
- });
712
- return initialVisibility;
713
- });
714
- }, [columns]);
721
+ setColumnVisibility(
722
+ Object.fromEntries(
723
+ tableColumns.filter((column) => !!column.id).map((column) => {
724
+ var _a2, _b2;
725
+ return [column.id, (_b2 = (_a2 = column.meta) == null ? void 0 : _a2.visible) != null ? _b2 : true];
726
+ })
727
+ )
728
+ );
729
+ }, [tableColumns]);
715
730
  const table = useReactTable({
716
- columns,
731
+ columns: tableColumns,
717
732
  data,
718
733
  getCoreRowModel: getCoreRowModel(),
719
734
  getSortedRowModel: getSortedRowModel(),
@@ -797,7 +812,12 @@ function DataGrid({
797
812
  setColumnOrder((prev) => {
798
813
  const oldIndex = prev.indexOf(active.id);
799
814
  const newIndex = prev.indexOf(over.id);
800
- return arrayMove(prev, oldIndex, newIndex);
815
+ const newOrder = arrayMove(prev, oldIndex, newIndex);
816
+ setTableColumns((prev2) => {
817
+ const res = newOrder.map((id2) => prev2.find((col) => col.id === id2)).filter(Boolean);
818
+ return res;
819
+ });
820
+ return newOrder;
801
821
  });
802
822
  }
803
823
  };
@@ -39,7 +39,7 @@ __export(useMenuSystem_exports, {
39
39
  useSubMenuSystem: () => useSubMenuSystem
40
40
  });
41
41
  module.exports = __toCommonJS(useMenuSystem_exports);
42
- var import_react4 = require("react");
42
+ var import_react5 = require("react");
43
43
 
44
44
  // src/hooks/useKeydown.ts
45
45
  var import_react = require("react");
@@ -62,23 +62,26 @@ var useMatchesMedia = (query) => {
62
62
  };
63
63
  var useMatchesMobile = () => useMatchesMedia("(width < 48rem)");
64
64
 
65
+ // src/hooks/useTableLayout.ts
66
+ var import_react4 = require("react");
67
+
65
68
  // src/components/useMenuSystem.tsx
66
69
  function useSubMenuSystem(mobilePositionTo) {
67
- const [activeMenus, setActiveMenus] = (0, import_react4.useState)(
70
+ const [activeMenus, setActiveMenus] = (0, import_react5.useState)(
68
71
  {}
69
72
  );
70
- const [activeMenu, setActiveMenu] = (0, import_react4.useState)("");
71
- const [currentSubMenuLevel, setCurrentSubMenuLevel] = (0, import_react4.useState)(
73
+ const [activeMenu, setActiveMenu] = (0, import_react5.useState)("");
74
+ const [currentSubMenuLevel, setCurrentSubMenuLevel] = (0, import_react5.useState)(
72
75
  null
73
76
  );
74
- const menuRootRef = (0, import_react4.useRef)(null);
75
- const subMenuRefs = (0, import_react4.useRef)({});
76
- const hoverTimeoutRef = (0, import_react4.useRef)(null);
77
- const closeTimeoutRef = (0, import_react4.useRef)(null);
78
- const mouseStopTimeoutRef = (0, import_react4.useRef)(null);
79
- const isMouseMovingRef = (0, import_react4.useRef)(false);
80
- const pendingOpenActionRef = (0, import_react4.useRef)(null);
81
- const pendingCloseActionRef = (0, import_react4.useRef)(null);
77
+ const menuRootRef = (0, import_react5.useRef)(null);
78
+ const subMenuRefs = (0, import_react5.useRef)({});
79
+ const hoverTimeoutRef = (0, import_react5.useRef)(null);
80
+ const closeTimeoutRef = (0, import_react5.useRef)(null);
81
+ const mouseStopTimeoutRef = (0, import_react5.useRef)(null);
82
+ const isMouseMovingRef = (0, import_react5.useRef)(false);
83
+ const pendingOpenActionRef = (0, import_react5.useRef)(null);
84
+ const pendingCloseActionRef = (0, import_react5.useRef)(null);
82
85
  const isMobile = useMatchesMobile();
83
86
  const toggleMenu = (menuId, level) => {
84
87
  if (closeTimeoutRef.current) {
@@ -118,7 +121,7 @@ function useSubMenuSystem(mobilePositionTo) {
118
121
  return newActiveMenus;
119
122
  });
120
123
  };
121
- const executePendingActions = (0, import_react4.useCallback)(() => {
124
+ const executePendingActions = (0, import_react5.useCallback)(() => {
122
125
  if (pendingCloseActionRef.current) {
123
126
  pendingCloseActionRef.current();
124
127
  pendingCloseActionRef.current = null;
@@ -207,7 +210,7 @@ function useSubMenuSystem(mobilePositionTo) {
207
210
  const isMenuActive = (menuId, level) => {
208
211
  return activeMenus[level] === menuId;
209
212
  };
210
- (0, import_react4.useEffect)(() => {
213
+ (0, import_react5.useEffect)(() => {
211
214
  const handleClickOutside = (event) => {
212
215
  var _a;
213
216
  if (Object.keys(activeMenus).length === 0) return;
@@ -226,7 +229,7 @@ function useSubMenuSystem(mobilePositionTo) {
226
229
  document.removeEventListener("mousedown", handleClickOutside);
227
230
  };
228
231
  }, [activeMenus]);
229
- (0, import_react4.useEffect)(() => {
232
+ (0, import_react5.useEffect)(() => {
230
233
  return () => {
231
234
  if (hoverTimeoutRef.current) {
232
235
  clearTimeout(hoverTimeoutRef.current);
@@ -304,13 +307,13 @@ function useSubMenuSystem(mobilePositionTo) {
304
307
  };
305
308
  }
306
309
  function useMenuPosition(elementRef, position = "bottom", options) {
307
- const [menuPosition, setMenuPosition] = (0, import_react4.useState)({
310
+ const [menuPosition, setMenuPosition] = (0, import_react5.useState)({
308
311
  top: 0,
309
312
  left: 0,
310
313
  minWidth: 0
311
314
  });
312
315
  const isMobile = options == null ? void 0 : options.isMobile;
313
- const updatePosition = (0, import_react4.useCallback)(() => {
316
+ const updatePosition = (0, import_react5.useCallback)(() => {
314
317
  var _a, _b, _c;
315
318
  if (!(elementRef == null ? void 0 : elementRef.current)) return;
316
319
  const triggerRect = elementRef.current.getBoundingClientRect();
@@ -358,7 +361,7 @@ function useMenuPosition(elementRef, position = "bottom", options) {
358
361
  minWidth: triggerRect.width
359
362
  });
360
363
  }, [elementRef, position, options == null ? void 0 : options.menuRef, options == null ? void 0 : options.topOffset, isMobile]);
361
- (0, import_react4.useEffect)(() => {
364
+ (0, import_react5.useEffect)(() => {
362
365
  if (!(options == null ? void 0 : options.isOpen) || !(options == null ? void 0 : options.setIsOpen)) return;
363
366
  const handleClickOutside = (event) => {
364
367
  var _a, _b, _c, _d, _e;
@@ -384,7 +387,7 @@ function useMenuPosition(elementRef, position = "bottom", options) {
384
387
  options == null ? void 0 : options.menuRef,
385
388
  options == null ? void 0 : options.additionalRefs
386
389
  ]);
387
- (0, import_react4.useEffect)(() => {
390
+ (0, import_react5.useEffect)(() => {
388
391
  updatePosition();
389
392
  const resizeObserver = new ResizeObserver(updatePosition);
390
393
  if (elementRef == null ? void 0 : elementRef.current) {
@@ -2,8 +2,11 @@
2
2
  import {
3
3
  useMenuPosition,
4
4
  useSubMenuSystem
5
- } from "../chunk-WE55TGZZ.js";
6
- import "../chunk-WNQ53SVY.js";
5
+ } from "../chunk-NIHZMIOL.js";
6
+ import "../chunk-E6Y7ZHQX.js";
7
+ import "../chunk-VXWSAIB5.js";
8
+ import "../chunk-T3F37S6Z.js";
9
+ import "../chunk-5UH6QUFB.js";
7
10
  import "../chunk-BBZEL7EG.js";
8
11
  export {
9
12
  useMenuPosition,
@@ -2,7 +2,21 @@
2
2
  var __defProp = Object.defineProperty;
3
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
8
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
+ var __spreadValues = (a, b) => {
10
+ for (var prop in b || (b = {}))
11
+ if (__hasOwnProp.call(b, prop))
12
+ __defNormalProp(a, prop, b[prop]);
13
+ if (__getOwnPropSymbols)
14
+ for (var prop of __getOwnPropSymbols(b)) {
15
+ if (__propIsEnum.call(b, prop))
16
+ __defNormalProp(a, prop, b[prop]);
17
+ }
18
+ return a;
19
+ };
6
20
  var __export = (target, all) => {
7
21
  for (var name in all)
8
22
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -23,7 +37,8 @@ __export(hooks_exports, {
23
37
  useInfiniteScroll: () => useInfiniteScroll,
24
38
  useKeydown: () => useKeydown,
25
39
  useMatchesMedia: () => useMatchesMedia,
26
- useMatchesMobile: () => useMatchesMobile
40
+ useMatchesMobile: () => useMatchesMobile,
41
+ useTableLayout: () => useTableLayout
27
42
  });
28
43
  module.exports = __toCommonJS(hooks_exports);
29
44
 
@@ -99,10 +114,59 @@ var useMatchesMedia = (query) => {
99
114
  return matches;
100
115
  };
101
116
  var useMatchesMobile = () => useMatchesMedia("(width < 48rem)");
117
+
118
+ // src/utils/mergeObjectArrays.ts
119
+ function mergeObjectArrays(arr1, arr2) {
120
+ const maxLength = Math.max(arr1.length, arr2.length);
121
+ return Array.from(
122
+ { length: maxLength },
123
+ (_, i) => __spreadValues(__spreadValues({}, arr1[i] || {}), arr2[i] || {})
124
+ );
125
+ }
126
+
127
+ // src/hooks/useTableLayout.ts
128
+ var import_react4 = require("react");
129
+ function useTableLayout(initialColumns, key) {
130
+ const [columns, setColumns] = (0, import_react4.useState)(initialColumns);
131
+ const [isReady, setIsReady] = (0, import_react4.useState)(false);
132
+ const [layoutSignal, setLayoutSignal] = (0, import_react4.useState)(0);
133
+ (0, import_react4.useEffect)(() => {
134
+ if (!key) return setIsReady(true);
135
+ const savedLayout = localStorage.getItem(`${key}-tableLayout`);
136
+ if (savedLayout) {
137
+ setColumns(
138
+ mergeObjectArrays(
139
+ initialColumns,
140
+ JSON.parse(savedLayout)
141
+ )
142
+ );
143
+ }
144
+ if (!savedLayout) handleSaveLayout(initialColumns, true);
145
+ setLayoutSignal((prev) => prev + 1);
146
+ setIsReady(true);
147
+ }, []);
148
+ const handleSaveLayout = (0, import_react4.useCallback)(
149
+ (setter, _internal) => {
150
+ if (!isReady && !_internal) return null;
151
+ const newColumns = typeof setter === "function" ? setter(columns) : setter;
152
+ if (JSON.stringify(newColumns) === JSON.stringify(columns) && !_internal)
153
+ return null;
154
+ if (key) {
155
+ localStorage.setItem(`${key}-tableLayout`, JSON.stringify(newColumns));
156
+ }
157
+ setColumns(newColumns);
158
+ setLayoutSignal((prev) => prev + 1);
159
+ return newColumns;
160
+ },
161
+ [columns, isReady, key]
162
+ );
163
+ return { columns, setColumns: handleSaveLayout, layoutSignal, isReady };
164
+ }
102
165
  // Annotate the CommonJS export names for ESM import in node:
103
166
  0 && (module.exports = {
104
167
  useInfiniteScroll,
105
168
  useKeydown,
106
169
  useMatchesMedia,
107
- useMatchesMobile
170
+ useMatchesMobile,
171
+ useTableLayout
108
172
  });
@@ -2,12 +2,17 @@ import {
2
2
  useInfiniteScroll,
3
3
  useKeydown,
4
4
  useMatchesMedia,
5
- useMatchesMobile
6
- } from "../chunk-WNQ53SVY.js";
5
+ useMatchesMobile,
6
+ useTableLayout
7
+ } from "../chunk-E6Y7ZHQX.js";
8
+ import "../chunk-VXWSAIB5.js";
9
+ import "../chunk-T3F37S6Z.js";
10
+ import "../chunk-5UH6QUFB.js";
7
11
  import "../chunk-BBZEL7EG.js";
8
12
  export {
9
13
  useInfiniteScroll,
10
14
  useKeydown,
11
15
  useMatchesMedia,
12
- useMatchesMobile
16
+ useMatchesMobile,
17
+ useTableLayout
13
18
  };
@@ -2,7 +2,21 @@
2
2
  var __defProp = Object.defineProperty;
3
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
8
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
+ var __spreadValues = (a, b) => {
10
+ for (var prop in b || (b = {}))
11
+ if (__hasOwnProp.call(b, prop))
12
+ __defNormalProp(a, prop, b[prop]);
13
+ if (__getOwnPropSymbols)
14
+ for (var prop of __getOwnPropSymbols(b)) {
15
+ if (__propIsEnum.call(b, prop))
16
+ __defNormalProp(a, prop, b[prop]);
17
+ }
18
+ return a;
19
+ };
6
20
  var __export = (target, all) => {
7
21
  for (var name in all)
8
22
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -34,6 +48,7 @@ __export(utils_exports, {
34
48
  isValidDate: () => isValidDate,
35
49
  isValidDateRange: () => isValidDateRange,
36
50
  isValidDateRangeOrder: () => isValidDateRangeOrder,
51
+ mergeObjectArrays: () => mergeObjectArrays,
37
52
  parseDateParts: () => parseDateParts,
38
53
  parseInputDate: () => parseInputDate
39
54
  });
@@ -197,6 +212,15 @@ function isValidDateRangeOrder(fromDate, toDate) {
197
212
  const to = new Date(toDate);
198
213
  return to >= from;
199
214
  }
215
+
216
+ // src/utils/mergeObjectArrays.ts
217
+ function mergeObjectArrays(arr1, arr2) {
218
+ const maxLength = Math.max(arr1.length, arr2.length);
219
+ return Array.from(
220
+ { length: maxLength },
221
+ (_, i) => __spreadValues(__spreadValues({}, arr1[i] || {}), arr2[i] || {})
222
+ );
223
+ }
200
224
  // Annotate the CommonJS export names for ESM import in node:
201
225
  0 && (module.exports = {
202
226
  calculateCursorPosition,
@@ -213,6 +237,7 @@ function isValidDateRangeOrder(fromDate, toDate) {
213
237
  isValidDate,
214
238
  isValidDateRange,
215
239
  isValidDateRangeOrder,
240
+ mergeObjectArrays,
216
241
  parseDateParts,
217
242
  parseInputDate
218
243
  });
@@ -10,9 +10,10 @@ import {
10
10
  isValidDate,
11
11
  isValidDateRange,
12
12
  isValidDateRangeOrder,
13
+ mergeObjectArrays,
13
14
  parseDateParts,
14
15
  parseInputDate
15
- } from "../chunk-M3433XEJ.js";
16
+ } from "../chunk-T3F37S6Z.js";
16
17
  import {
17
18
  formatCurrencyDisplay,
18
19
  formatDecimalValue,
@@ -34,6 +35,7 @@ export {
34
35
  isValidDate,
35
36
  isValidDateRange,
36
37
  isValidDateRangeOrder,
38
+ mergeObjectArrays,
37
39
  parseDateParts,
38
40
  parseInputDate
39
41
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dmsi/wedgekit-react",
3
3
  "private": false,
4
- "version": "0.0.206",
4
+ "version": "0.0.208",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "build": "tsup",
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { useInfiniteScroll } from "../../hooks";
3
+ import { useInfiniteScroll, useTableLayout } from "../../hooks";
4
4
  import { componentGap, componentPadding } from "../../classNames";
5
5
  import {
6
6
  Button,
@@ -15,7 +15,7 @@ import {
15
15
  Select,
16
16
  Subheader,
17
17
  } from "..";
18
- import React, { useCallback, useId, useState } from "react";
18
+ import React, { useCallback, useEffect, useId, useState } from "react";
19
19
  import {
20
20
  ColumnFiltersState,
21
21
  flexRender,
@@ -81,15 +81,35 @@ export function DataGrid<T extends Record<string, unknown>>({
81
81
  predeterminedRightPins = [],
82
82
  useMenuDefaultMinWidth,
83
83
  }: DataGridProps<T>) {
84
- const [columnOrder, setColumnOrder] = useState<string[]>(() =>
85
- columns.map((c) => c.id!),
86
- );
87
84
  const [localSorting, setLocalSorting] = useState<SortingState>([]);
88
85
  const [localColumnFilters, setLocalColumnFilters] =
89
86
  useState<ColumnFiltersState>([]);
90
87
  const [localRowSelection, setLocalRowSelection] = useState<
91
88
  Record<string, boolean>
92
89
  >({});
90
+ const {
91
+ columns: tableColumns,
92
+ setColumns: setTableColumns,
93
+ layoutSignal,
94
+ } = useTableLayout<T>(columns, id ?? testid);
95
+ const [columnOrder, setColumnOrder] = useState<string[]>(
96
+ tableColumns.map((c) => c.id!),
97
+ );
98
+
99
+ const [columnVisibility, setColumnVisibility] = useState<
100
+ Record<string, boolean>
101
+ >(
102
+ Object.fromEntries(
103
+ tableColumns
104
+ .filter((column) => !!column.id)
105
+ .map((column) => [column.id, column.meta?.visible ?? true]),
106
+ ),
107
+ );
108
+
109
+ useEffect(() => {
110
+ setColumnOrder(tableColumns.map((c) => c.id!));
111
+ resetColumnVisibility();
112
+ }, [layoutSignal]);
93
113
 
94
114
  const sortingState = pagination
95
115
  ? (externalSorting ?? localSorting)
@@ -149,39 +169,35 @@ export function DataGrid<T extends Record<string, unknown>>({
149
169
  const dndId = useId();
150
170
  const containerRef = React.useRef<HTMLDivElement>(null);
151
171
 
152
- const [columnVisibility, setColumnVisibility] = useState<
153
- Record<string, boolean>
154
- >(() => {
155
- const initialVisibility: Record<string, boolean> = {};
156
- columns.forEach((column) => {
157
- if (column.id) {
158
- initialVisibility[column.id] = column.meta?.visible ?? true;
159
- }
160
- });
161
- return initialVisibility;
162
- });
163
-
164
172
  const toggleColumnVisibility = useCallback(
165
173
  (columnId: string, isVisible: boolean) => {
166
- setColumnVisibility((prev) => ({ ...prev, [columnId]: isVisible }));
174
+ setTableColumns((prev) => {
175
+ const persistedIndex = prev.findIndex((col) => col.id === columnId);
176
+ if (persistedIndex !== -1) {
177
+ prev[persistedIndex].meta = {
178
+ ...prev[persistedIndex].meta,
179
+ visible: isVisible,
180
+ };
181
+ }
182
+ return [...prev];
183
+ // @ts-expect-error Internal usage only
184
+ }, true);
167
185
  },
168
- [setColumnVisibility],
186
+ [setTableColumns],
169
187
  );
170
188
 
171
189
  const resetColumnVisibility = useCallback(() => {
172
- setColumnVisibility(() => {
173
- const initialVisibility: Record<string, boolean> = {};
174
- columns.forEach((column) => {
175
- if (column.id) {
176
- initialVisibility[column.id] = column.meta?.visible ?? true;
177
- }
178
- });
179
- return initialVisibility;
180
- });
181
- }, [columns]);
190
+ setColumnVisibility(
191
+ Object.fromEntries(
192
+ tableColumns
193
+ .filter((column) => !!column.id)
194
+ .map((column) => [column.id, column.meta?.visible ?? true]),
195
+ ),
196
+ );
197
+ }, [tableColumns]);
182
198
 
183
199
  const table = useReactTable<T>({
184
- columns,
200
+ columns: tableColumns,
185
201
  data,
186
202
  getCoreRowModel: getCoreRowModel(),
187
203
  getSortedRowModel: getSortedRowModel(),
@@ -278,7 +294,15 @@ export function DataGrid<T extends Record<string, unknown>>({
278
294
  setColumnOrder((prev) => {
279
295
  const oldIndex = prev.indexOf(active.id as string);
280
296
  const newIndex = prev.indexOf(over.id as string);
281
- return arrayMove(prev, oldIndex, newIndex);
297
+ const newOrder = arrayMove(prev, oldIndex, newIndex);
298
+ setTableColumns((prev) => {
299
+ // Mirror columnOrder's string = id
300
+ const res = newOrder
301
+ .map((id) => prev.find((col) => col.id === id)!)
302
+ .filter(Boolean);
303
+ return res;
304
+ });
305
+ return newOrder;
282
306
  });
283
307
  }
284
308
  };
@@ -670,3 +694,5 @@ function adaptTableStateSetter<T>(
670
694
  }
671
695
 
672
696
  export type { ColumnDef } from "@tanstack/react-table";
697
+
698
+ export default DataGrid;
@@ -1,3 +1,4 @@
1
1
  export { useKeydown } from "./useKeydown";
2
2
  export { useInfiniteScroll } from "./useInfiniteScroll";
3
3
  export { useMatchesMedia, useMatchesMobile } from "./useMatchesMedia";
4
+ export { useTableLayout } from "./useTableLayout";
@@ -0,0 +1,68 @@
1
+ "use client";
2
+
3
+ import { mergeObjectArrays } from "../utils";
4
+ import { ColumnDef } from "@dmsi/wedgekit-react/components";
5
+ import { useState, useEffect, SetStateAction, useCallback } from "react";
6
+ export type PersistedTableLayout<T> = {
7
+ columns: ColumnDef<T>[];
8
+ setColumns: (setter: SetStateAction<ColumnDef<T>[]>) => ColumnDef<T>[] | null;
9
+ layoutSignal: number;
10
+ isReady: boolean;
11
+ };
12
+
13
+ /**
14
+ * Custom hook to manage table layout persistence.
15
+ * @template T The type of the objects in the arrays.
16
+ * @param key {string}
17
+ * @param initialColumns {() => Array<ColumnDef<T>>}
18
+ * @param dependencyArr {unknown[]}
19
+ * @returns {{ columns: ColumnDef<T>[]; setColumns: React.Dispatch<React.SetStateAction<ColumnDef<T>[]>> }}
20
+ */
21
+ export function useTableLayout<T>(
22
+ initialColumns: Array<ColumnDef<T>>,
23
+ key?: string,
24
+ ): PersistedTableLayout<T> {
25
+ const [columns, setColumns] = useState<ColumnDef<T>[]>(initialColumns);
26
+ const [isReady, setIsReady] = useState(false);
27
+ const [layoutSignal, setLayoutSignal] = useState(0);
28
+
29
+ useEffect(() => {
30
+ if (!key) return setIsReady(true);
31
+ const savedLayout = localStorage.getItem(`${key}-tableLayout`);
32
+ if (savedLayout) {
33
+ setColumns(
34
+ mergeObjectArrays<ColumnDef<T>>(
35
+ initialColumns,
36
+ JSON.parse(savedLayout),
37
+ ),
38
+ );
39
+ }
40
+ if (!savedLayout) handleSaveLayout(initialColumns, true);
41
+ setLayoutSignal((prev) => prev + 1);
42
+ setIsReady(true);
43
+
44
+ // Load the layout from local storage on init
45
+ // eslint-disable-next-line react-hooks/exhaustive-deps
46
+ }, []);
47
+
48
+ const handleSaveLayout = useCallback(
49
+ (setter: React.SetStateAction<ColumnDef<T>[]>, _internal?: boolean) => {
50
+ if (!isReady && !_internal) return null;
51
+ // get value from passed setter
52
+ const newColumns =
53
+ typeof setter === "function" ? setter(columns) : setter;
54
+ if (JSON.stringify(newColumns) === JSON.stringify(columns) && !_internal)
55
+ return null;
56
+ if (key) {
57
+ localStorage.setItem(`${key}-tableLayout`, JSON.stringify(newColumns));
58
+ }
59
+ setColumns(newColumns);
60
+ setLayoutSignal((prev) => prev + 1);
61
+
62
+ return newColumns;
63
+ },
64
+ [columns, isReady, key],
65
+ );
66
+
67
+ return { columns, setColumns: handleSaveLayout, layoutSignal, isReady };
68
+ }
@@ -1,2 +1,3 @@
1
1
  export * from "./formatting";
2
2
  export * from "./date";
3
+ export { mergeObjectArrays } from "./mergeObjectArrays";