@dmsi/wedgekit-react 0.0.207 → 0.0.209

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 (45) hide show
  1. package/dist/{chunk-WNQ53SVY.js → chunk-E6Y7ZHQX.js} +45 -1
  2. package/dist/{chunk-WXHRJSDG.js → chunk-ERW3AMED.js} +1 -1
  3. package/dist/{chunk-2JRZCC2K.js → chunk-JITZWSPR.js} +3 -3
  4. package/dist/{chunk-WE55TGZZ.js → chunk-NIHZMIOL.js} +1 -1
  5. package/dist/{chunk-RXPS5GVE.js → chunk-Q3TNALWH.js} +17 -26
  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 +814 -824
  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 +963 -905
  28. package/dist/components/index.js +70 -45
  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/TableBody/TableBodyRow.tsx +0 -4
  37. package/src/components/DataGrid/TableBody/index.tsx +14 -3
  38. package/src/components/DataGrid/index.tsx +58 -35
  39. package/src/components/DataGridCell.tsx +11 -17
  40. package/src/hooks/index.ts +1 -0
  41. package/src/hooks/useTableLayout.ts +68 -0
  42. package/src/utils/index.ts +1 -0
  43. package/src/utils/mergeObjectArrays.ts +18 -0
  44. package/src/utils.ts +1 -0
  45. /package/dist/{chunk-6LN6QT6M.js → chunk-VXWSAIB5.js} +0 -0
@@ -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
  };
@@ -377,9 +401,6 @@ export function DataGrid<T extends Record<string, unknown>>({
377
401
  }
378
402
 
379
403
  if (typeof header.column.columnDef.header === "string") {
380
- const customHeaderWidth =
381
- header.column.columnDef.meta?.headerWidth;
382
-
383
404
  const cellValue = table
384
405
  .getRowModel()
385
406
  .rows[0]?.getValue(header.column.id);
@@ -396,7 +417,7 @@ export function DataGrid<T extends Record<string, unknown>>({
396
417
  header={header}
397
418
  locked={header.column.columnDef.meta?.locked}
398
419
  center={centerHeader}
399
- width={customHeaderWidth}
420
+ // width={`${header.column.getSize()}px`}
400
421
  className={clsx(
401
422
  header.column.getCanSort()
402
423
  ? "cursor-pointer"
@@ -670,3 +691,5 @@ function adaptTableStateSetter<T>(
670
691
  }
671
692
 
672
693
  export type { ColumnDef } from "@tanstack/react-table";
694
+
695
+ export default DataGrid;
@@ -14,20 +14,20 @@ import clsx from "clsx";
14
14
  import {
15
15
  ComponentProps,
16
16
  CSSProperties,
17
- memo,
18
17
  PropsWithChildren,
19
18
  RefObject,
20
19
  useEffect,
21
20
  useRef,
22
21
  useState,
22
+ memo,
23
23
  } from "react";
24
24
  import { componentPadding, paddingUsingComponentGap } from "../classNames";
25
- import { AsProps } from "../types";
25
+ import { MenuOption } from "./MenuOption";
26
+ import { Menu } from "./Menu";
26
27
  import { Icon } from "./Icon";
27
28
  import { Search } from "./Search";
28
- import { Menu } from "./Menu";
29
- import { MenuOption } from "./MenuOption";
30
29
  import { useSubMenuSystem } from "./useMenuSystem";
30
+ import type { AsProps } from "../types";
31
31
 
32
32
  type Tags = "td" | "th";
33
33
 
@@ -44,6 +44,7 @@ type DataGridCellProps = PropsWithChildren<{
44
44
  warning?: boolean;
45
45
  center?: boolean;
46
46
  width?: string;
47
+ minWidth?: string;
47
48
  }>;
48
49
 
49
50
  export const DataGridCell = memo(
@@ -63,6 +64,7 @@ export const DataGridCell = memo(
63
64
  warning,
64
65
  center,
65
66
  width,
67
+ minWidth,
66
68
  testid,
67
69
  ...props
68
70
  }: AsProps<Tags> & DataGridCellProps) => {
@@ -171,7 +173,7 @@ export const DataGridCell = memo(
171
173
  id={id}
172
174
  data-testid={testid}
173
175
  className={clsx("flex h-10", !width && "flex-1")}
174
- style={{ width }}
176
+ style={{ width, minWidth }}
175
177
  {...props}
176
178
  data-theme={type === "header" && !locked ? "brand" : undefined}
177
179
  >
@@ -260,7 +262,7 @@ export function DataCellHeader<T>({
260
262
  const style: CSSProperties = {
261
263
  position: "relative",
262
264
  whiteSpace: "nowrap",
263
- width: header.column.columnDef.meta?.headerWidth ?? header.column.getSize(),
265
+ minWidth: header.column.getSize(),
264
266
  "--color-text-primary-normal": "var(--color-text-brand-primary-normal)",
265
267
  "--color-icon-on-action-primary-normal":
266
268
  "var(--color-text-brand-primary-normal)",
@@ -277,6 +279,7 @@ export function DataCellHeader<T>({
277
279
  type="header"
278
280
  component="header"
279
281
  style={style}
282
+ minWidth={`${header.column.getSize()}px`}
280
283
  onClick={header.column.getToggleSortingHandler()}
281
284
  onRightClick={() => setShowMenu(!showMenu)}
282
285
  {...props}
@@ -470,7 +473,6 @@ export function DraggableCellHeader<T extends Record<string, any>>({
470
473
  transition: "width transform 0.2s ease-in-out",
471
474
  whiteSpace: "nowrap",
472
475
  zIndex: isDragging ? 1 : 0,
473
- width: header.column.columnDef.meta?.headerWidth ?? header.column.getSize(),
474
476
  "--color-text-primary-normal": "var(--color-action-000)",
475
477
  "--color-icon-on-action-primary-normal": "var(--color-action-000)",
476
478
  userSelect: "none",
@@ -510,20 +512,12 @@ export function DragAlongCell<T extends RowData, TValue>({
510
512
  position: "relative",
511
513
  transform: CSS.Translate.toString(transform),
512
514
  transition: "width transform 0.2s ease-in-out",
513
- width: cell.column.columnDef.meta?.headerWidth ?? cell.column.getSize(),
515
+ minWidth: cell.column.getSize(),
514
516
  zIndex: isDragging ? 1 : 0,
515
517
  };
516
518
 
517
519
  return (
518
- <DataGridCell
519
- style={style}
520
- ref={setNodeRef}
521
- width={
522
- (cell.column.columnDef.meta?.headerWidth as string | undefined) ??
523
- `${cell.column.getSize()}px`
524
- }
525
- {...props}
526
- >
520
+ <DataGridCell style={style} ref={setNodeRef} {...props}>
527
521
  {children}
528
522
  </DataGridCell>
529
523
  );
@@ -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";
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Merges two arrays of objects element-wise.
3
+ *
4
+ * @template T The type of the objects in the arrays.
5
+ * @param {T[]} arr1 The first array.
6
+ * @param {T[]} arr2 The second array.
7
+ * @returns {T[]} A new array containing the merged objects.
8
+ */
9
+ export function mergeObjectArrays<T extends object>(arr1: T[], arr2: T[]): T[] {
10
+ const maxLength = Math.max(arr1.length, arr2.length);
11
+
12
+ // Create a new array with a length equal to the longer of the two arrays.
13
+ // For each index, merge the objects from arr1 and arr2.
14
+ return Array.from(
15
+ { length: maxLength },
16
+ (_, i) => ({ ...(arr1[i] || {}), ...(arr2[i] || {}) }) as T,
17
+ );
18
+ }
package/src/utils.ts CHANGED
@@ -21,3 +21,4 @@ export function findDocumentRoot(
21
21
  }
22
22
  return window.document.body;
23
23
  }
24
+ export * from "./utils/index";
File without changes