@versini/ui-datagrid 4.2.12 → 4.2.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,224 +1,80 @@
1
1
  /*!
2
- @versini/ui-datagrid v4.2.12
2
+ @versini/ui-datagrid v4.2.13
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
6
6
  import { SortDirections } from "../7.js";
7
-
8
-
9
- /**
10
- * Gets the opposite sort direction.
11
- */ function getOppositeSortDirection(direction) {
7
+ function getOppositeSortDirection(direction) {
12
8
  return direction === SortDirections.ASC ? SortDirections.DESC : SortDirections.ASC;
13
9
  }
14
- /**
15
- * Toggles the sort direction or returns default if no current direction.
16
- */ function toggleSortDirection(currentDirection, defaultDirection = SortDirections.ASC) {
17
- if (!currentDirection) {
18
- return defaultDirection;
19
- }
10
+ function toggleSortDirection(currentDirection, defaultDirection = SortDirections.ASC) {
11
+ if (!currentDirection) return defaultDirection;
20
12
  return getOppositeSortDirection(currentDirection);
21
13
  }
22
- /**
23
- * Creates a sort comparator for dates. Handles Date objects, ISO strings, and
24
- * timestamps.
25
- *
26
- * @param direction - Sort direction (asc or desc)
27
- * @param nullPosition - Where to place null/undefined values ('start' or 'end')
28
- *
29
- * @example
30
- * ```ts
31
- * const items = [{ date: '2024-01-15' }, { date: '2024-01-10' }];
32
- * const sorted = items.sort((a, b) =>
33
- * sortByDate('asc')(a.date, b.date)
34
- * );
35
- * ```
36
- *
37
- */ function sortByDate(direction, nullPosition = "end") {
14
+ function sortByDate(direction, nullPosition = "end") {
38
15
  return (a, b)=>{
39
- const aIsNull = a === null || a === undefined;
40
- const bIsNull = b === null || b === undefined;
41
- // Handle null values.
42
- if (aIsNull && bIsNull) {
43
- return 0;
44
- }
45
- if (aIsNull) {
46
- return nullPosition === "start" ? -1 : 1;
47
- }
48
- if (bIsNull) {
49
- return nullPosition === "start" ? 1 : -1;
50
- }
16
+ const aIsNull = null == a;
17
+ const bIsNull = null == b;
18
+ if (aIsNull && bIsNull) return 0;
19
+ if (aIsNull) return "start" === nullPosition ? -1 : 1;
20
+ if (bIsNull) return "start" === nullPosition ? 1 : -1;
51
21
  const aTime = a instanceof Date ? a.getTime() : new Date(a).getTime();
52
22
  const bTime = b instanceof Date ? b.getTime() : new Date(b).getTime();
53
- // Handle invalid dates.
54
- if (Number.isNaN(aTime) && Number.isNaN(bTime)) {
55
- return 0;
56
- }
57
- if (Number.isNaN(aTime)) {
58
- return nullPosition === "start" ? -1 : 1;
59
- }
60
- if (Number.isNaN(bTime)) {
61
- return nullPosition === "start" ? 1 : -1;
62
- }
23
+ if (Number.isNaN(aTime) && Number.isNaN(bTime)) return 0;
24
+ if (Number.isNaN(aTime)) return "start" === nullPosition ? -1 : 1;
25
+ if (Number.isNaN(bTime)) return "start" === nullPosition ? 1 : -1;
63
26
  return direction === SortDirections.ASC ? aTime - bTime : bTime - aTime;
64
27
  };
65
28
  }
66
- /**
67
- * Creates a sort comparator for numbers.
68
- *
69
- * @param direction - Sort direction (asc or desc)
70
- * @param nullPosition - Where to place null/undefined values ('start' or 'end')
71
- *
72
- * @example
73
- * ```ts
74
- * const items = [{ count: 5 }, { count: 2 }, { count: 10 }];
75
- * const sorted = items.sort((a, b) =>
76
- * sortByNumber('desc')(a.count, b.count)
77
- * );
78
- * ```
79
- *
80
- */ function sortByNumber(direction, nullPosition = "end") {
29
+ function sortByNumber(direction, nullPosition = "end") {
81
30
  return (a, b)=>{
82
- const aIsNull = a === null || a === undefined;
83
- const bIsNull = b === null || b === undefined;
84
- // Handle null values.
85
- if (aIsNull && bIsNull) {
86
- return 0;
87
- }
88
- if (aIsNull) {
89
- return nullPosition === "start" ? -1 : 1;
90
- }
91
- if (bIsNull) {
92
- return nullPosition === "start" ? 1 : -1;
93
- }
94
- // Handle NaN.
31
+ const aIsNull = null == a;
32
+ const bIsNull = null == b;
33
+ if (aIsNull && bIsNull) return 0;
34
+ if (aIsNull) return "start" === nullPosition ? -1 : 1;
35
+ if (bIsNull) return "start" === nullPosition ? 1 : -1;
95
36
  const aIsNaN = Number.isNaN(a);
96
37
  const bIsNaN = Number.isNaN(b);
97
- if (aIsNaN && bIsNaN) {
98
- return 0;
99
- }
100
- if (aIsNaN) {
101
- return nullPosition === "start" ? -1 : 1;
102
- }
103
- if (bIsNaN) {
104
- return nullPosition === "start" ? 1 : -1;
105
- }
38
+ if (aIsNaN && bIsNaN) return 0;
39
+ if (aIsNaN) return "start" === nullPosition ? -1 : 1;
40
+ if (bIsNaN) return "start" === nullPosition ? 1 : -1;
106
41
  return direction === SortDirections.ASC ? a - b : b - a;
107
42
  };
108
43
  }
109
- /**
110
- * Creates a sort comparator for strings. Uses localeCompare for proper Unicode
111
- * sorting.
112
- *
113
- * @param direction - Sort direction (asc or desc)
114
- * @param options - Options for string comparison
115
- *
116
- * @example
117
- * ```ts
118
- * const items = [{ name: 'Zebra' }, { name: 'apple' }];
119
- * const sorted = items.sort((a, b) =>
120
- * sortByString('asc', { caseInsensitive: true })(a.name, b.name)
121
- * );
122
- * ```
123
- *
124
- */ function sortByString(direction, options) {
44
+ function sortByString(direction, options) {
125
45
  const { nullPosition = "end", caseInsensitive = true, locale } = options ?? {};
126
46
  return (a, b)=>{
127
- const aIsNull = a === null || a === undefined || a === "";
128
- const bIsNull = b === null || b === undefined || b === "";
129
- // Handle null/empty values.
130
- if (aIsNull && bIsNull) {
131
- return 0;
132
- }
133
- if (aIsNull) {
134
- return nullPosition === "start" ? -1 : 1;
135
- }
136
- if (bIsNull) {
137
- return nullPosition === "start" ? 1 : -1;
138
- }
47
+ const aIsNull = null == a || "" === a;
48
+ const bIsNull = null == b || "" === b;
49
+ if (aIsNull && bIsNull) return 0;
50
+ if (aIsNull) return "start" === nullPosition ? -1 : 1;
51
+ if (bIsNull) return "start" === nullPosition ? 1 : -1;
139
52
  const compareOptions = {
140
53
  sensitivity: caseInsensitive ? "base" : "variant"
141
54
  };
142
- const comparison = locale ? a.localeCompare(b, locale, compareOptions) : a.localeCompare(b, undefined, compareOptions);
55
+ const comparison = locale ? a.localeCompare(b, locale, compareOptions) : a.localeCompare(b, void 0, compareOptions);
143
56
  return direction === SortDirections.ASC ? comparison : -comparison;
144
57
  };
145
58
  }
146
- /**
147
- * Creates a sort comparator for booleans.
148
- *
149
- * @param direction - Sort direction (asc = false first, desc = true first)
150
- *
151
- * @example
152
- * ```ts
153
- * const items = [{ active: true }, { active: false }];
154
- * const sorted = items.sort((a, b) =>
155
- * sortByBoolean('desc')(a.active, b.active)
156
- * );
157
- * // Result: [{ active: true }, { active: false }]
158
- * ```
159
- *
160
- */ function sortByBoolean(direction) {
59
+ function sortByBoolean(direction) {
161
60
  return (a, b)=>{
162
- // Treat null/undefined as false for comparison.
163
- const aVal = a === true ? 1 : 0;
164
- const bVal = b === true ? 1 : 0;
61
+ const aVal = true === a ? 1 : 0;
62
+ const bVal = true === b ? 1 : 0;
165
63
  return direction === SortDirections.ASC ? aVal - bVal : bVal - aVal;
166
64
  };
167
65
  }
168
- /**
169
- * Helper to create a sort handler function. Returns the new sort config when a
170
- * column header is clicked.
171
- *
172
- * @param currentConfig - Current sort configuration
173
- * @param cellId - ID of the clicked cell
174
- * @param defaultDirection - Default direction when clicking a new column
175
- *
176
- * @example
177
- * ```tsx
178
- * const [sortConfig, setSortConfig] = useState<SortConfig>({
179
- * sortedCell: 'date',
180
- * sortDirection: 'desc',
181
- * });
182
- *
183
- * const handleSort = (cellId: string) => {
184
- * setSortConfig(getNextSortConfig(sortConfig, cellId));
185
- * };
186
- * ```
187
- *
188
- */ function getNextSortConfig(currentConfig, cellId, defaultDirection = SortDirections.DESC) {
189
- if (currentConfig.sortedCell === cellId) {
190
- // Toggle direction on same column.
191
- return {
192
- sortedCell: cellId,
193
- sortDirection: getOppositeSortDirection(currentConfig.sortDirection)
194
- };
195
- }
196
- // New column, use default direction.
66
+ function getNextSortConfig(currentConfig, cellId, defaultDirection = SortDirections.DESC) {
67
+ if (currentConfig.sortedCell === cellId) return {
68
+ sortedCell: cellId,
69
+ sortDirection: getOppositeSortDirection(currentConfig.sortDirection)
70
+ };
197
71
  return {
198
72
  sortedCell: cellId,
199
73
  sortDirection: defaultDirection
200
74
  };
201
75
  }
202
- /**
203
- * Generic sort function that sorts an array by a specified key.
204
- *
205
- * @param items - Array to sort
206
- * @param key - Key to sort by
207
- * @param direction - Sort direction
208
- * @param sortType - Type of sorting ('date', 'number', 'string', 'boolean')
209
- *
210
- * @example
211
- * ```ts
212
- * const items = [
213
- * { id: 1, name: 'Alice', createdAt: '2024-01-01' },
214
- * { id: 2, name: 'Bob', createdAt: '2024-01-15' },
215
- * ];
216
- *
217
- * const sorted = sortItems(items, 'createdAt', 'desc', 'date');
218
- * ```
219
- *
220
- */ function sortItems(items, key, direction, sortType = "string") {
221
- const comparator = sortType === "date" ? sortByDate(direction) : sortType === "number" ? sortByNumber(direction) : sortType === "boolean" ? sortByBoolean(direction) : sortByString(direction);
76
+ function sortItems(items, key, direction, sortType = "string") {
77
+ const comparator = "date" === sortType ? sortByDate(direction) : "number" === sortType ? sortByNumber(direction) : "boolean" === sortType ? sortByBoolean(direction) : sortByString(direction);
222
78
  return [
223
79
  ...items
224
80
  ].sort((a, b)=>{
@@ -227,10 +83,5 @@ import { SortDirections } from "../7.js";
227
83
  return comparator(aVal, bVal);
228
84
  });
229
85
  }
230
-
231
- // Re-export sort directions from constants for convenience.
232
-
233
-
234
-
235
- export { getNextSortConfig, getOppositeSortDirection, sortByBoolean, sortByDate, sortByNumber, sortByString, sortItems, toggleSortDirection };
236
86
  export { SortDirections } from "../7.js";
87
+ export { getNextSortConfig, getOppositeSortDirection, sortByBoolean, sortByDate, sortByNumber, sortByString, sortItems, toggleSortDirection };
package/dist/u.js CHANGED
@@ -1,88 +1,35 @@
1
1
  /*!
2
- @versini/ui-datagrid v4.2.12
2
+ @versini/ui-datagrid v4.2.13
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
6
6
  import clsx from "clsx";
7
7
  import { useContext, useEffect, useLayoutEffect, useRef } from "react";
8
8
  import { DataGridContext } from "./8.js";
9
-
10
-
11
-
12
- /**
13
- * Get the CSS class for a DataGrid body element. Uses display:contents so the
14
- * body doesn't interfere with the grid flow. Rows will use subgrid when columns
15
- * are provided, or define their own grid otherwise.
16
- *
17
- * @param className - Additional class name to merge
18
- *
19
- */ function getBodyClass(className) {
9
+ function getBodyClass(className) {
20
10
  return clsx("contents", className);
21
11
  }
22
-
23
-
24
-
25
-
26
- /**
27
- * Snap a CSS pixel value to the nearest device pixel.
28
- *
29
- * `getBoundingClientRect()` can produce sub-pixel widths that fluctuate
30
- * slightly across renders (font rasterization, fractional transforms, zoom).
31
- * For sticky header/footer alignment we don't need infinite precision — we need
32
- * stability.
33
- *
34
- * By quantizing to the device pixel grid we reduce "width jitter" that would
35
- * otherwise cause repeated state updates and re-renders.
36
- *
37
- * @internal
38
- *
39
- */ function quantizeWidthToDevicePixels(width, devicePixelRatio = 1) {
40
- // Guard against invalid DPR values.
12
+ function quantizeWidthToDevicePixels(width, devicePixelRatio = 1) {
41
13
  const dpr = Number.isFinite(devicePixelRatio) && devicePixelRatio > 0 ? devicePixelRatio : 1;
42
- /**
43
- * NOTE: `window.devicePixelRatio` can be < 1 in some zoom/scaling scenarios.
44
- * We intentionally accept any DPR > 0 rather than clamping to 1 so that we
45
- * still snap to the real device pixel grid.
46
- */ const quantum = 1 / dpr;
14
+ const quantum = 1 / dpr;
47
15
  const snapped = Math.round(width / quantum) * quantum;
48
- // Clamp floating error (e.g. 33.50000000004).
49
16
  return Number(snapped.toFixed(4));
50
17
  }
51
- /**
52
- * Hook to measure column widths from the first body row's cells. This is needed
53
- * because sticky header/footer are absolutely positioned and can't use CSS
54
- * subgrid. We measure the body cells (which ARE in the grid flow) and report
55
- * the widths so header/footer can use the same pixel values.
56
- *
57
- * @param bodyRef - Ref to the body element containing the rows
58
- * @param contentDependency - Dependency that changes when content changes (children or renderedContent)
59
- *
60
- */ function useColumnMeasurement(bodyRef, contentDependency, noData = false) {
18
+ function useColumnMeasurement(bodyRef, contentDependency, noData = false) {
61
19
  const ctx = useContext(DataGridContext);
62
20
  const prevWidthsRef = useRef([]);
63
21
  const observerRef = useRef(null);
64
22
  const needsMeasurement = Boolean(ctx.columns && (ctx.stickyHeader || ctx.stickyFooter));
65
- /**
66
- * Re-query the current first row's cells, report any changed widths, and
67
- * return the cells. Held in a ref so the persistent ResizeObserver always runs
68
- * the latest logic without being recreated as the window slides.
69
- */ const measureRef = useRef(()=>[]);
23
+ const measureRef = useRef(()=>[]);
70
24
  measureRef.current = ()=>{
71
25
  const element = bodyRef.current;
72
- if (noData || !element || !needsMeasurement || !ctx.setMeasuredColumnWidths) {
73
- return [];
74
- }
26
+ if (noData || !element || !needsMeasurement || !ctx.setMeasuredColumnWidths) return [];
75
27
  const firstRow = element.querySelector('[role="row"]');
76
28
  const cells = firstRow ? Array.from(firstRow.querySelectorAll('[role="cell"], [role="columnheader"], [role="gridcell"]')) : [];
77
- if (cells.length === 0) {
78
- return [];
79
- }
80
- const dpr = typeof window !== "undefined" ? window.devicePixelRatio ?? 1 : 1;
29
+ if (0 === cells.length) return [];
30
+ const dpr = "u" > typeof window ? window.devicePixelRatio ?? 1 : 1;
81
31
  const widths = cells.map((cell)=>quantizeWidthToDevicePixels(cell.getBoundingClientRect().width, dpr));
82
- /**
83
- * Only update state if widths have actually changed to prevent infinite
84
- * loops.
85
- */ const prevWidths = prevWidthsRef.current;
32
+ const prevWidths = prevWidthsRef.current;
86
33
  const hasChanged = widths.length !== prevWidths.length || widths.some((w, i)=>w !== prevWidths[i]);
87
34
  if (hasChanged) {
88
35
  prevWidthsRef.current = widths;
@@ -90,30 +37,15 @@ import { DataGridContext } from "./8.js";
90
37
  }
91
38
  return cells;
92
39
  };
93
- /**
94
- * Keep a single ResizeObserver for the hook's lifetime and re-point it at the
95
- * current first row's cells whenever the rendered content changes (e.g. a
96
- * virtualized window sliding). The cells are the observed targets because the
97
- * body is `display: contents` (it has no box of its own); re-pointing the same
98
- * observer avoids tearing one down and allocating a new one on every scroll
99
- * shift.
100
- */ // biome-ignore lint/correctness/useExhaustiveDependencies: measureRef is stable; contentDependency re-points the observer when the rendered rows change
101
40
  useLayoutEffect(()=>{
102
- if (!needsMeasurement) {
103
- observerRef.current?.disconnect();
104
- return;
105
- }
106
- if (!observerRef.current) {
107
- observerRef.current = new ResizeObserver(()=>{
108
- measureRef.current();
109
- });
110
- }
41
+ if (!needsMeasurement) return void observerRef.current?.disconnect();
42
+ if (!observerRef.current) observerRef.current = new ResizeObserver(()=>{
43
+ measureRef.current();
44
+ });
111
45
  const observer = observerRef.current;
112
46
  observer.disconnect();
113
47
  const cells = measureRef.current();
114
- for (const cell of cells){
115
- observer.observe(cell);
116
- }
48
+ for (const cell of cells)observer.observe(cell);
117
49
  }, [
118
50
  ctx.columns,
119
51
  ctx.stickyHeader,
@@ -123,13 +55,9 @@ import { DataGridContext } from "./8.js";
123
55
  needsMeasurement,
124
56
  noData
125
57
  ]);
126
- // Disconnect on unmount.
127
- useEffect(()=>{
128
- return ()=>{
58
+ useEffect(()=>()=>{
129
59
  observerRef.current?.disconnect();
130
60
  observerRef.current = null;
131
- };
132
- }, []);
61
+ }, []);
133
62
  }
134
-
135
63
  export { getBodyClass, useColumnMeasurement };
package/dist/y.js CHANGED
@@ -1,34 +1,24 @@
1
1
  /*!
2
- @versini/ui-datagrid v4.2.12
2
+ @versini/ui-datagrid v4.2.13
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
6
6
  import clsx from "clsx";
7
7
  import { BlurEffects, CellWrapper } from "./7.js";
8
-
9
-
10
-
11
-
12
- /**
13
- * Theme mode helpers - reused across many functions.
14
- */ const isDark = (m)=>m === "dark";
15
- const isLight = (m)=>m === "light";
16
- const isSys = (m)=>m === "system";
17
- const isAlt = (m)=>m === "alt-system";
8
+ const isDark = (m)=>"dark" === m;
9
+ const isLight = (m)=>"light" === m;
10
+ const isSys = (m)=>"system" === m;
11
+ const isAlt = (m)=>"alt-system" === m;
18
12
  const isDarkish = (m)=>isDark(m) || isSys(m);
19
13
  const isLightish = (m)=>isLight(m) || isAlt(m);
20
14
  const hasBlurEffect = (b)=>Boolean(b && b !== BlurEffects.NONE);
21
15
  const isHeaderCell = (c)=>c === CellWrapper.HEADER;
22
16
  const isFooterCell = (c)=>c === CellWrapper.FOOTER;
23
- /**
24
- * Text color classes - reused in multiple functions.
25
- */ const TXT_LIGHT = "text-copy-light";
17
+ const TXT_LIGHT = "text-copy-light";
26
18
  const TXT_DARK = "text-copy-dark";
27
19
  const TXT_SYS = "text-copy-light dark:text-copy-dark";
28
20
  const TXT_ALT = "text-copy-dark dark:text-copy-light";
29
- /**
30
- * Text color classes based on theme mode.
31
- */ const getTextColorClasses = ({ mode })=>clsx({
21
+ const getTextColorClasses = ({ mode })=>clsx({
32
22
  [TXT_LIGHT]: isDark(mode),
33
23
  [TXT_DARK]: isLight(mode),
34
24
  [TXT_SYS]: isSys(mode),
@@ -39,82 +29,41 @@ const getTextColorClassesForHeaderFooter = ({ mode, hasBlur })=>clsx({
39
29
  [TXT_SYS]: isSys(mode) && hasBlur,
40
30
  "text-copy-dark dark:text-copy-dark": (isSys(mode) || isAlt(mode)) && !hasBlur
41
31
  });
42
- /**
43
- * Surface background classes (main container backgrounds).
44
- */ const getSurfaceBackgroundClasses = ({ mode })=>clsx({
32
+ const getSurfaceBackgroundClasses = ({ mode })=>clsx({
45
33
  "bg-surface-darker": isDarkish(mode),
46
34
  "bg-surface-light": isLightish(mode),
47
35
  "dark:bg-surface-light": isSys(mode),
48
36
  "dark:bg-surface-darker": isAlt(mode)
49
37
  });
50
- /**
51
- * Header/footer background classes (with optional blur transparency).
52
- */ const getHeaderFooterBackgroundClasses = ({ hasBlur, sticky })=>clsx({
38
+ const getHeaderFooterBackgroundClasses = ({ hasBlur, sticky })=>clsx({
53
39
  "bg-surface-medium/50 dark:bg-surface-medium/50": hasBlur && sticky,
54
40
  "bg-surface-medium-light dark:bg-surface-medium-light": !hasBlur
55
41
  });
56
- /**
57
- * Border color classes for rows.
58
- */ const getBorderClasses = ({ mode })=>clsx({
42
+ const getBorderClasses = ({ mode })=>clsx({
59
43
  "border-table-dark": isDarkish(mode),
60
44
  "border-table-light": isLightish(mode),
61
45
  "dark:border-table-light": isSys(mode),
62
46
  "dark:border-table-dark": isAlt(mode)
63
47
  });
64
- /**
65
- * Hover classes for body rows.
66
- *
67
- * The hover lifts both the background and the text color so the highlighted row
68
- * reads as a single, cohesive change (mirroring the light-mode behavior where
69
- * the font color shifts too).
70
- *
71
- * The shade is tuned per surface so the lift stays proportional:
72
- * - Dark surfaces (slate-900 base) only step up to `table-dark-hover`
73
- * (slate-700) instead of the much brighter `surface-medium` (slate-500),
74
- * which felt harsh against very dark tables, and brighten the text to
75
- * `copy-lighter` (white).
76
- * - Light surfaces (slate-300 base) keep the established `surface-medium`
77
- * (slate-500) background with `copy-light` (slate-200) text.
78
- *
79
- * Pairing matches `getBorderClasses`/`getSurfaceBackgroundClasses` so the hover
80
- * always tracks the active surface, including the OS-driven `dark:` flips that
81
- * `system` and `alt-system` perform.
82
- *
83
- */ const getRowHoverClasses = ({ mode })=>clsx(/**
84
- * Smooth the hover so quick mouse sweeps fade rather than flash. Animating
85
- * the row's background- and (inherited) text-color is enough; cells stay
86
- * transparent and follow the row's transitioning color.
87
- */ "transition-colors duration-300 ease-in-out motion-reduce:transition-none", {
48
+ const getRowHoverClasses = ({ mode })=>clsx("transition-colors duration-300 ease-in-out motion-reduce:transition-none", {
88
49
  "hover:bg-table-dark-hover hover:text-copy-lighter": isDarkish(mode),
89
50
  "hover:bg-surface-medium hover:text-copy-light": isLightish(mode),
90
51
  "dark:hover:bg-surface-medium dark:hover:text-copy-light": isSys(mode),
91
52
  "dark:hover:bg-table-dark-hover dark:hover:text-copy-lighter": isAlt(mode)
92
53
  });
93
- /**
94
- * Blur effect classes for sticky elements.
95
- */ const getBlurClasses = ({ blurEffect })=>clsx({
54
+ const getBlurClasses = ({ blurEffect })=>clsx({
96
55
  "backdrop-blur-sm": blurEffect === BlurEffects.SMALL,
97
56
  "backdrop-blur-md": blurEffect === BlurEffects.MEDIUM,
98
57
  "backdrop-blur-lg": blurEffect === BlurEffects.LARGE
99
58
  });
100
- /**
101
- * Loading text classes for loading state. Rendered as a high-contrast pill with
102
- * a fixed dark background and light text so the message stays legible against
103
- * the blurred content behind it regardless of the grid mode.
104
- */ const getLoadingTextClasses = ()=>"px-5 py-2 rounded-full shadow-lg text-sm font-semibold bg-surface-darker text-copy-light";
105
- /**
106
- * Overlay classes for loading state. Uses z-30/z-40 to layer above the sticky
107
- * header/footer (z-20), which sit later in the DOM within the same stacking
108
- * context and would otherwise paint on top of an equal-z overlay.
109
- */ const getOverlayClasses = ()=>({
59
+ const getLoadingTextClasses = ()=>"px-5 py-2 rounded-full shadow-lg text-sm font-semibold bg-surface-darker text-copy-light";
60
+ const getOverlayClasses = ()=>({
110
61
  inner: "relative",
111
62
  overlay: clsx("absolute inset-0 z-30 cursor-not-allowed rounded-lg", "backdrop-blur-xs bg-white/30 dark:bg-black/30"),
112
63
  loadingWrapper: clsx("absolute z-40 top-0 left-0 right-0 h-[min(100%,100vh)]", "flex items-center justify-center", "pointer-events-none"),
113
64
  loadingText: getLoadingTextClasses()
114
65
  });
115
- /**
116
- * Generates classes for the main DataGrid wrapper and grid.
117
- */ const getDataGridClasses = ({ mode, className, wrapperClassName, stickyHeader, stickyFooter, loading })=>{
66
+ const getDataGridClasses = ({ mode, className, wrapperClassName, stickyHeader, stickyFooter, loading })=>{
118
67
  const overlayClasses = loading ? getOverlayClasses() : null;
119
68
  const hasSticky = stickyHeader || stickyFooter;
120
69
  return {
@@ -136,20 +85,16 @@ const getTextColorClassesForHeaderFooter = ({ mode, hasBlur })=>clsx({
136
85
  }))
137
86
  };
138
87
  };
139
- /**
140
- * Generates classes for the DataGridHeader wrapper.
141
- */ const getHeaderClasses = ({ className, stickyHeader, mode, blurEffect })=>{
88
+ const getHeaderClasses = ({ className, stickyHeader, mode, blurEffect })=>{
142
89
  const hasBlur = hasBlurEffect(blurEffect);
143
90
  const textClasses = getTextColorClassesForHeaderFooter({
144
91
  mode,
145
92
  hasBlur
146
93
  });
147
- if (!stickyHeader) {
148
- return clsx("contents", getHeaderFooterBackgroundClasses({
149
- hasBlur,
150
- sticky: false
151
- }), textClasses, className);
152
- }
94
+ if (!stickyHeader) return clsx("contents", getHeaderFooterBackgroundClasses({
95
+ hasBlur,
96
+ sticky: false
97
+ }), textClasses, className);
153
98
  return clsx("flex flex-col border-b border-table-medium shadow-md", "absolute left-0 right-0 z-20 top-0 rounded-t-lg", getHeaderFooterBackgroundClasses({
154
99
  hasBlur,
155
100
  sticky: true
@@ -157,26 +102,20 @@ const getTextColorClassesForHeaderFooter = ({ mode, hasBlur })=>clsx({
157
102
  blurEffect
158
103
  }), className);
159
104
  };
160
- /**
161
- * Generates classes for the caption element inside DataGridHeader.
162
- */ const getCaptionClasses = ({ captionClassName, mode, hasBlur, stickyHeader })=>clsx("py-2 text-sm text-center font-bold col-span-full", getTextColorClassesForHeaderFooter({
105
+ const getCaptionClasses = ({ captionClassName, mode, hasBlur, stickyHeader })=>clsx("py-2 text-sm text-center font-bold col-span-full", getTextColorClassesForHeaderFooter({
163
106
  mode,
164
107
  hasBlur
165
108
  }), !stickyHeader && getHeaderFooterBackgroundClasses({
166
109
  hasBlur,
167
110
  sticky: false
168
111
  }), captionClassName);
169
- /**
170
- * Generates classes for the DataGridFooter.
171
- */ const getFooterClasses = ({ className, stickyFooter, mode, blurEffect })=>{
112
+ const getFooterClasses = ({ className, stickyFooter, mode, blurEffect })=>{
172
113
  const hasBlur = hasBlurEffect(blurEffect);
173
114
  const textClasses = getTextColorClassesForHeaderFooter({
174
115
  mode,
175
116
  hasBlur
176
117
  });
177
- if (!stickyFooter) {
178
- return clsx("contents", textClasses, className);
179
- }
118
+ if (!stickyFooter) return clsx("contents", textClasses, className);
180
119
  return clsx("flex flex-col border-t border-table-medium", "absolute left-0 right-0 z-20 bottom-0 rounded-b-lg", "shadow-[0_-10px_15px_-3px_rgba(0,0,0,0.1)]", getHeaderFooterBackgroundClasses({
181
120
  hasBlur,
182
121
  sticky: true
@@ -185,37 +124,30 @@ const getTextColorClassesForHeaderFooter = ({ mode, hasBlur })=>clsx({
185
124
  }), textClasses, className);
186
125
  };
187
126
  const ROW_LAYOUT = "group grid items-center";
188
- /**
189
- * Generates classes for DataGridRow.
190
- */ const getRowClasses = ({ mode, className, cellWrapper, isLastRow, stickyHeader, stickyFooter })=>{
127
+ const getRowClasses = ({ mode, className, cellWrapper, isLastRow, stickyHeader, stickyFooter })=>{
191
128
  if (isHeaderCell(cellWrapper) || isFooterCell(cellWrapper)) {
192
129
  const isHeader = isHeaderCell(cellWrapper);
193
130
  const parentUsesContents = isHeader ? !stickyHeader : !stickyFooter;
194
- if (parentUsesContents) {
195
- return clsx(ROW_LAYOUT, getHeaderFooterBackgroundClasses({
196
- hasBlur: false,
197
- sticky: false
198
- }), isHeader ? "border-b border-table-medium shadow-md" : "border-t border-table-medium", className);
199
- }
131
+ if (parentUsesContents) return clsx(ROW_LAYOUT, getHeaderFooterBackgroundClasses({
132
+ hasBlur: false,
133
+ sticky: false
134
+ }), isHeader ? "border-b border-table-medium shadow-md" : "border-t border-table-medium", className);
200
135
  return clsx(ROW_LAYOUT, className);
201
136
  }
202
- const borderClasses = isLastRow !== undefined ? isLastRow ? "border-b border-b-transparent dark:border-b-transparent" : "border-b" : "border-b last:border-0";
137
+ const borderClasses = void 0 !== isLastRow ? isLastRow ? "border-b border-b-transparent dark:border-b-transparent" : "border-b" : "border-b last:border-0";
203
138
  return clsx(ROW_LAYOUT, borderClasses, getRowHoverClasses({
204
139
  mode
205
140
  }), getBorderClasses({
206
141
  mode
207
142
  }), className);
208
143
  };
209
- /**
210
- * Generates classes for DataGridCell.
211
- */ const getCellClasses = ({ cellWrapper, className, compact, align, mode, borderLeft, borderRight })=>{
212
- return clsx({
144
+ const getCellClasses = ({ cellWrapper, className, compact, align, mode, borderLeft, borderRight })=>clsx({
213
145
  "px-2 py-1": compact,
214
146
  "px-4 py-3": !compact
215
147
  }, {
216
- "text-left justify-start": align === "left" || !align,
217
- "text-center justify-center": align === "center",
218
- "text-right justify-end": align === "right"
148
+ "text-left justify-start": "left" === align || !align,
149
+ "text-center justify-center": "center" === align,
150
+ "text-right justify-end": "right" === align
219
151
  }, {
220
152
  "font-bold": isHeaderCell(cellWrapper) || isFooterCell(cellWrapper)
221
153
  }, "first:group-data-active:relative", "first:group-data-active:before:absolute first:group-data-active:before:left-0 first:group-data-active:before:top-0 first:group-data-active:before:bottom-0 first:group-data-active:before:w-1", "first:group-data-active:self-stretch first:group-data-active:flex first:group-data-active:items-center", {
@@ -234,10 +166,5 @@ const ROW_LAYOUT = "group grid items-center";
234
166
  "border-r border-r-table-dark dark:border-r-table-light": borderRight && isSys(mode),
235
167
  "border-r border-r-table-light dark:border-r-table-dark": borderRight && isAlt(mode)
236
168
  }, className);
237
- };
238
- /**
239
- * Returns the appropriate ARIA role for the cell based on the cell wrapper
240
- * type.
241
- */ const getCellRole = (cellWrapper)=>isHeaderCell(cellWrapper) ? "columnheader" : "gridcell";
242
-
169
+ const getCellRole = (cellWrapper)=>isHeaderCell(cellWrapper) ? "columnheader" : "gridcell";
243
170
  export { getCaptionClasses, getCellClasses, getCellRole, getDataGridClasses, getFooterClasses, getHeaderClasses, getRowClasses, getTextColorClassesForHeaderFooter };