@versini/ui-datagrid 4.2.12 → 4.2.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/7.js CHANGED
@@ -1,36 +1,27 @@
1
1
  /*!
2
- @versini/ui-datagrid v4.2.12
2
+ @versini/ui-datagrid v4.2.14
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
6
- /**
7
- * Sort direction constants for DataGrid sorting.
8
- */ const SortDirections = {
6
+ const SortDirections = {
9
7
  ASC: "asc",
10
8
  DESC: "desc"
11
9
  };
12
- /**
13
- * Blur effect intensity options for sticky header/footer.
14
- */ const BlurEffects = {
10
+ const BlurEffects = {
15
11
  NONE: "none",
16
12
  SMALL: "small",
17
13
  MEDIUM: "medium",
18
14
  LARGE: "large"
19
15
  };
20
- /**
21
- * Theme mode options for DataGrid.
22
- */ const ThemeModes = {
16
+ const ThemeModes = {
23
17
  DARK: "dark",
24
18
  LIGHT: "light",
25
19
  SYSTEM: "system",
26
20
  ALT_SYSTEM: "alt-system"
27
21
  };
28
- /**
29
- * Cell wrapper types for internal context.
30
- */ const CellWrapper = {
22
+ const CellWrapper = {
31
23
  HEADER: "header",
32
24
  BODY: "body",
33
25
  FOOTER: "footer"
34
26
  };
35
-
36
27
  export { BlurEffects, CellWrapper, SortDirections, ThemeModes };
package/dist/8.js CHANGED
@@ -1,14 +1,10 @@
1
1
  /*!
2
- @versini/ui-datagrid v4.2.12
2
+ @versini/ui-datagrid v4.2.14
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
6
6
  import { createContext } from "react";
7
-
8
-
9
-
10
7
  const DataGridContext = createContext({
11
8
  mode: "system"
12
9
  });
13
-
14
10
  export { DataGridContext };
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v4.2.12
2
+ @versini/ui-datagrid v4.2.14
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -8,40 +8,13 @@ import { useCallback, useMemo, useRef, useState } from "react";
8
8
  import { BlurEffects } from "../7.js";
9
9
  import { getDataGridClasses } from "../y.js";
10
10
  import { DataGridContext } from "../8.js";
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
- /* =============================================================================
20
- * DataGrid (main component)
21
- * ========================================================================== */ const DataGrid = ({ className, wrapperClassName, children, mode = "system", compact = false, stickyHeader = false, stickyFooter = false, blurEffect = BlurEffects.NONE, maxHeight, loading = false, columns, ...rest })=>{
22
- /**
23
- * Track registered header/footer components via context registration. Uses
24
- * counter-based tracking to properly handle multiple instances. Components
25
- * register themselves when they mount, regardless of nesting depth. This
26
- * replaces the previous displayName-based child inspection approach.
27
- */ const [headerCount, setHeaderCount] = useState(0);
11
+ const DataGrid = ({ className, wrapperClassName, children, mode = "system", compact = false, stickyHeader = false, stickyFooter = false, blurEffect = BlurEffects.NONE, maxHeight, loading = false, columns, ...rest })=>{
12
+ const [headerCount, setHeaderCount] = useState(0);
28
13
  const [footerCount, setFooterCount] = useState(0);
29
- /**
30
- * Track measured heights of header/footer for dynamic padding. Reported by
31
- * DataGridHeader/Footer via ResizeObserver. This replaces the brittle
32
- * hard-coded Tailwind padding classes.
33
- */ const [headerHeight, setHeaderHeight] = useState(0);
14
+ const [headerHeight, setHeaderHeight] = useState(0);
34
15
  const [footerHeight, setFooterHeight] = useState(0);
35
- /**
36
- * Track measured column widths from the body. Used by sticky header/footer to
37
- * sync column widths since absolutely positioned elements can't use CSS
38
- * subgrid.
39
- */ const [measuredColumnWidths, setMeasuredColumnWidths] = useState([]);
40
- /**
41
- * Registration callbacks with stable references. Called by
42
- * DataGridHeader/DataGridFooter on mount/unmount. Uses increment/decrement to
43
- * handle multiple instances correctly.
44
- */ const registerHeader = useCallback(()=>setHeaderCount((c)=>c + 1), []);
16
+ const [measuredColumnWidths, setMeasuredColumnWidths] = useState([]);
17
+ const registerHeader = useCallback(()=>setHeaderCount((c)=>c + 1), []);
45
18
  const unregisterHeader = useCallback(()=>setHeaderCount((c)=>c - 1), []);
46
19
  const registerFooter = useCallback(()=>setFooterCount((c)=>c + 1), []);
47
20
  const unregisterFooter = useCallback(()=>setFooterCount((c)=>c - 1), []);
@@ -49,45 +22,21 @@ import { DataGridContext } from "../8.js";
49
22
  const hasRegisteredFooter = footerCount > 0;
50
23
  const headerRows = hasRegisteredHeader ? 1 : 0;
51
24
  const footerRows = hasRegisteredFooter ? 1 : 0;
52
- /**
53
- * Only apply sticky behavior if both the prop is true AND the corresponding
54
- * component exists. This prevents adding padding/styles for non-existent
55
- * headers/footers.
56
- */ const effectiveStickyHeader = stickyHeader && hasRegisteredHeader;
25
+ const effectiveStickyHeader = stickyHeader && hasRegisteredHeader;
57
26
  const effectiveStickyFooter = stickyFooter && hasRegisteredFooter;
58
27
  const hasSticky = effectiveStickyHeader || effectiveStickyFooter;
59
- /**
60
- * Whether DataGrid owns a bounded internal scroll container (sticky → the
61
- * scrollableContent area; maxHeight → the wrapper). When it doesn't, a
62
- * virtualized body windows against the page instead (pageScroll).
63
- */ const hasInternalScroller = hasSticky || Boolean(maxHeight);
28
+ const hasInternalScroller = hasSticky || Boolean(maxHeight);
64
29
  const pageScroll = !hasInternalScroller;
65
- /**
66
- * State to hold the caption ID registered by DataGridHeader. Used for
67
- * aria-labelledby on the grid element for accessibility.
68
- */ const [captionId, setCaptionId] = useState(undefined);
30
+ const [captionId, setCaptionId] = useState(void 0);
69
31
  const handleSetCaptionId = useCallback((id)=>{
70
32
  setCaptionId(id);
71
33
  }, []);
72
- /**
73
- * Total row count reported by DataGridInfiniteBody. Drives `aria-rowcount` on
74
- * the grid. Seeded `undefined` so non-infinite grids render no `aria-rowcount`
75
- * (markup stays unchanged).
76
- */ const [rowCount, setRowCount] = useState(undefined);
77
- /**
78
- * Focus sentinel: a virtualizing body moves focus here (the grid element,
79
- * made focusable via tabIndex={-1}) when a focused row recycles out of the
80
- * DOM, so focus never drops to document.body.
81
- */ const gridRef = useRef(null);
34
+ const [rowCount, setRowCount] = useState(void 0);
35
+ const gridRef = useRef(null);
82
36
  const focusGrid = useCallback(()=>{
83
37
  gridRef.current?.focus();
84
38
  }, []);
85
- /**
86
- * The internal scroll container a virtualized body should window against,
87
- * exposed via context. DataGrid owns a bounded scroller only when sticky
88
- * header/footer or maxHeight is set; otherwise the body windows against the
89
- * page (pageScroll).
90
- */ const [scrollContainer, setScrollContainer] = useState(null);
39
+ const [scrollContainer, setScrollContainer] = useState(null);
91
40
  const scrollContainerRef = useCallback((el)=>{
92
41
  setScrollContainer(el);
93
42
  }, []);
@@ -150,48 +99,42 @@ import { DataGridContext } from "../8.js";
150
99
  pageScroll
151
100
  ]);
152
101
  const wrapperStyle = maxHeight ? {
153
- maxHeight: typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight
154
- } : undefined;
155
- /**
156
- * Dynamic padding for scrollable content based on measured header/footer
157
- * heights. This replaces the brittle hard-coded Tailwind padding classes.
158
- */ const scrollableContentStyle = {
102
+ maxHeight: "number" == typeof maxHeight ? `${maxHeight}px` : maxHeight
103
+ } : void 0;
104
+ const scrollableContentStyle = {
159
105
  ...wrapperStyle,
160
- paddingTop: effectiveStickyHeader ? headerHeight : undefined,
161
- paddingBottom: effectiveStickyFooter ? footerHeight : undefined
106
+ paddingTop: effectiveStickyHeader ? headerHeight : void 0,
107
+ paddingBottom: effectiveStickyFooter ? footerHeight : void 0
162
108
  };
163
- /**
164
- * When columns are provided, apply grid-template-columns at the grid level so
165
- * all rows can use subgrid to inherit the same column sizing.
166
- */ const gridStyle = columns ? {
109
+ const gridStyle = columns ? {
167
110
  gridTemplateColumns: columns.join(" ")
168
- } : undefined;
169
- const gridContent = /*#__PURE__*/ jsx("div", {
111
+ } : void 0;
112
+ const gridContent = jsx("div", {
170
113
  ref: gridRef,
171
114
  role: "grid",
172
115
  "aria-labelledby": captionId,
173
116
  "aria-rowcount": rowCount,
174
- tabIndex: rowCount != null ? -1 : undefined,
117
+ tabIndex: null != rowCount ? -1 : void 0,
175
118
  className: classes.grid,
176
119
  style: gridStyle,
177
120
  ...rest,
178
121
  children: children
179
122
  });
180
- const loadingText = typeof loading === "string" ? loading : loading ? "Loading..." : null;
181
- return /*#__PURE__*/ jsx(DataGridContext.Provider, {
123
+ const loadingText = "string" == typeof loading ? loading : loading ? "Loading..." : null;
124
+ return jsx(DataGridContext.Provider, {
182
125
  value: contextValue,
183
- children: /*#__PURE__*/ jsxs("div", {
126
+ children: jsxs("div", {
184
127
  className: classes.inner,
185
128
  children: [
186
- loading && /*#__PURE__*/ jsxs(Fragment, {
129
+ loading && jsxs(Fragment, {
187
130
  children: [
188
- /*#__PURE__*/ jsx("div", {
131
+ jsx("div", {
189
132
  className: classes.overlay,
190
133
  "aria-hidden": "true"
191
134
  }),
192
- /*#__PURE__*/ jsx("div", {
135
+ jsx("div", {
193
136
  className: classes.loadingWrapper,
194
- children: /*#__PURE__*/ jsx("span", {
137
+ children: jsx("span", {
195
138
  className: classes.loadingText,
196
139
  role: "status",
197
140
  children: loadingText
@@ -199,11 +142,11 @@ import { DataGridContext } from "../8.js";
199
142
  })
200
143
  ]
201
144
  }),
202
- /*#__PURE__*/ jsx("div", {
203
- ref: hasInternalScroller && !hasSticky ? scrollContainerRef : undefined,
145
+ jsx("div", {
146
+ ref: hasInternalScroller && !hasSticky ? scrollContainerRef : void 0,
204
147
  className: classes.wrapper,
205
148
  style: wrapperStyle,
206
- children: hasSticky ? /*#__PURE__*/ jsx("div", {
149
+ children: hasSticky ? jsx("div", {
207
150
  ref: scrollContainerRef,
208
151
  className: classes.scrollableContent,
209
152
  style: scrollableContentStyle,
@@ -214,9 +157,5 @@ import { DataGridContext } from "../8.js";
214
157
  })
215
158
  });
216
159
  };
217
-
218
-
219
-
220
-
221
- export { DataGrid };
222
160
  export { DataGridContext } from "../8.js";
161
+ export { DataGrid };
@@ -1,109 +1,49 @@
1
1
  /*!
2
- @versini/ui-datagrid v4.2.12
2
+ @versini/ui-datagrid v4.2.14
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
6
6
  import { jsx } from "react/jsx-runtime";
7
7
  import { useLayoutEffect, useRef, useState } from "react";
8
-
9
-
10
-
11
-
12
8
  const DEFAULT_ANIMATION_DURATION = 300;
13
- /**
14
- * Hook that provides smooth height animations when content changes.
15
- *
16
- * Uses FLIP technique: captures height before render via a persistent ref, then
17
- * animates from old height to new height after the DOM updates.
18
- *
19
- * @param dependency - Value that triggers animation when changed.
20
- * @param options - Configuration options.
21
- *
22
- * @example
23
- * ```tsx
24
- * const items = useMemo(() => data.slice(0, visibleCount), [data, visibleCount]);
25
- * const { ref, style } = useAnimatedHeight(items.length);
26
- *
27
- * return (
28
- * <div ref={ref} style={style}>
29
- * {items.map((item) => <Row key={item.id} {...item} />)}
30
- * </div>
31
- * );
32
- * ```
33
- *
34
- */ function useAnimatedHeight(dependency, options) {
9
+ function useAnimatedHeight(dependency, options) {
35
10
  const { duration = DEFAULT_ANIMATION_DURATION, enabled = true } = options ?? {};
36
11
  const ref = useRef(null);
37
12
  const [animationState, setAnimationState] = useState({
38
13
  height: "auto",
39
14
  isAnimating: false
40
15
  });
41
- /**
42
- * Track the last measured height persistently. This ref is updated AFTER each
43
- * animation completes, so it holds the "before" value when dependency changes.
44
- */ const lastHeightRef = useRef(0);
16
+ const lastHeightRef = useRef(0);
45
17
  const prevDependencyRef = useRef(dependency);
46
18
  const animationFrameRef = useRef(0);
47
19
  const timeoutRef = useRef(null);
48
20
  useLayoutEffect(()=>{
49
- if (!ref.current || !enabled) {
50
- return;
51
- }
52
- /**
53
- * On first render or when not animating, just record the current height.
54
- */ if (lastHeightRef.current === 0) {
21
+ if (!ref.current || !enabled) return;
22
+ if (0 === lastHeightRef.current) {
55
23
  lastHeightRef.current = ref.current.offsetHeight;
56
24
  prevDependencyRef.current = dependency;
57
- // If a prior animation was canceled and the content collapsed to 0,
58
- // clear any locked height so the wrapper can't stay frozen.
59
25
  setAnimationState((state)=>state.isAnimating ? {
60
26
  height: "auto",
61
27
  isAnimating: false
62
28
  } : state);
63
29
  return;
64
30
  }
65
- /**
66
- * If dependency hasn't changed, nothing to animate.
67
- */ if (prevDependencyRef.current === dependency) {
68
- return;
69
- }
31
+ if (prevDependencyRef.current === dependency) return;
70
32
  prevDependencyRef.current = dependency;
71
33
  const previousHeight = lastHeightRef.current;
72
34
  const newHeight = ref.current.scrollHeight;
73
- /**
74
- * Update the stored height for next time.
75
- */ lastHeightRef.current = newHeight;
76
- /**
77
- * If heights are the same or previous was 0, no animation needed. Reset any
78
- * height left locked by a just-canceled animation, so the wrapper can't get
79
- * stuck collapsed with `overflow: hidden` when the dependency keeps changing
80
- * without a height change — e.g. a virtualized body reporting a scroll-driven
81
- * count while its panel stays a fixed `maxHeight`.
82
- */ if (previousHeight === newHeight || previousHeight === 0) {
83
- setAnimationState((state)=>state.isAnimating ? {
84
- height: "auto",
85
- isAnimating: false
86
- } : state);
87
- return;
88
- }
89
- /**
90
- * Cancel any ongoing animation.
91
- */ if (timeoutRef.current) {
92
- clearTimeout(timeoutRef.current);
93
- }
94
- if (animationFrameRef.current) {
95
- cancelAnimationFrame(animationFrameRef.current);
96
- }
97
- /**
98
- * Lock to the previous height immediately.
99
- */ setAnimationState({
35
+ lastHeightRef.current = newHeight;
36
+ if (previousHeight === newHeight || 0 === previousHeight) return void setAnimationState((state)=>state.isAnimating ? {
37
+ height: "auto",
38
+ isAnimating: false
39
+ } : state);
40
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
41
+ if (animationFrameRef.current) cancelAnimationFrame(animationFrameRef.current);
42
+ setAnimationState({
100
43
  height: previousHeight,
101
44
  isAnimating: true
102
45
  });
103
- /**
104
- * Use double RAF to ensure the browser has painted the locked height, then
105
- * transition to the new height.
106
- */ animationFrameRef.current = requestAnimationFrame(()=>{
46
+ animationFrameRef.current = requestAnimationFrame(()=>{
107
47
  animationFrameRef.current = requestAnimationFrame(()=>{
108
48
  setAnimationState({
109
49
  height: newHeight,
@@ -118,12 +58,8 @@ const DEFAULT_ANIMATION_DURATION = 300;
118
58
  });
119
59
  });
120
60
  return ()=>{
121
- if (timeoutRef.current) {
122
- clearTimeout(timeoutRef.current);
123
- }
124
- if (animationFrameRef.current) {
125
- cancelAnimationFrame(animationFrameRef.current);
126
- }
61
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
62
+ if (animationFrameRef.current) cancelAnimationFrame(animationFrameRef.current);
127
63
  };
128
64
  }, [
129
65
  dependency,
@@ -131,9 +67,9 @@ const DEFAULT_ANIMATION_DURATION = 300;
131
67
  enabled
132
68
  ]);
133
69
  const style = enabled ? {
134
- height: animationState.height === "auto" ? "auto" : `${animationState.height}px`,
135
- overflow: animationState.isAnimating ? "hidden" : undefined,
136
- transition: animationState.isAnimating ? `height ${duration}ms ease-out` : undefined
70
+ height: "auto" === animationState.height ? "auto" : `${animationState.height}px`,
71
+ overflow: animationState.isAnimating ? "hidden" : void 0,
72
+ transition: animationState.isAnimating ? `height ${duration}ms ease-out` : void 0
137
73
  } : {};
138
74
  return {
139
75
  ref,
@@ -141,46 +77,16 @@ const DEFAULT_ANIMATION_DURATION = 300;
141
77
  isAnimating: animationState.isAnimating
142
78
  };
143
79
  }
144
-
145
-
146
-
147
- /**
148
- * Wrapper component that animates height changes when content changes.
149
- *
150
- * @example
151
- * ```tsx
152
- * const [visibleCount, setVisibleCount] = useState(0);
153
- *
154
- * return (
155
- * <AnimatedWrapper dependency={visibleCount}>
156
- * <DataGrid maxHeight="400px" stickyHeader>
157
- * <DataGridInfiniteBody
158
- * data={largeData}
159
- * onVisibleCountChange={(count) => setVisibleCount(count)}
160
- * >
161
- * {(row) => (
162
- * <DataGridRow key={row.id}>...</DataGridRow>
163
- * )}
164
- * </DataGridInfiniteBody>
165
- * </DataGrid>
166
- * </AnimatedWrapper>
167
- * );
168
- * ```
169
- *
170
- */ const AnimatedWrapper = ({ children, dependency, duration, enabled = true, className })=>{
80
+ const AnimatedWrapper = ({ children, dependency, duration, enabled = true, className })=>{
171
81
  const { ref, style } = useAnimatedHeight(dependency, {
172
82
  duration,
173
83
  enabled
174
84
  });
175
- return /*#__PURE__*/ jsx("div", {
85
+ return jsx("div", {
176
86
  ref: ref,
177
87
  style: style,
178
88
  className: className,
179
89
  children: children
180
90
  });
181
91
  };
182
-
183
-
184
-
185
-
186
92
  export { AnimatedWrapper, useAnimatedHeight };
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v4.2.12
2
+ @versini/ui-datagrid v4.2.14
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -8,39 +8,27 @@ import { useContext, useRef } from "react";
8
8
  import { DataGridContext } from "../8.js";
9
9
  import { getBodyClass, useColumnMeasurement } from "../u.js";
10
10
  import { CellWrapper } from "../7.js";
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
- /* =============================================================================
21
- * DataGridBody
22
- * ========================================================================== */ const DataGridBody = ({ className, children, noData = false, noDataText, ...rest })=>{
11
+ const DataGridBody = ({ className, children, noData = false, noDataText, ...rest })=>{
23
12
  const ctx = useContext(DataGridContext);
24
13
  const bodyRef = useRef(null);
25
- // Measure column widths for sticky header/footer sync.
26
14
  useColumnMeasurement(bodyRef, children, noData);
27
15
  const bodyClass = getBodyClass(className);
28
- return /*#__PURE__*/ jsx(DataGridContext.Provider, {
16
+ return jsx(DataGridContext.Provider, {
29
17
  value: {
30
18
  ...ctx,
31
19
  cellWrapper: CellWrapper.BODY
32
20
  },
33
- children: /*#__PURE__*/ jsx("div", {
21
+ children: jsx("div", {
34
22
  ref: bodyRef,
35
23
  role: "rowgroup",
36
24
  className: bodyClass,
37
25
  ...rest,
38
- children: noData ? /*#__PURE__*/ jsx("div", {
26
+ children: noData ? jsx("div", {
39
27
  role: "row",
40
28
  style: {
41
29
  gridColumn: "1 / -1"
42
30
  },
43
- children: /*#__PURE__*/ jsx("div", {
31
+ children: jsx("div", {
44
32
  role: "gridcell",
45
33
  style: {
46
34
  textAlign: "center",
@@ -52,7 +40,4 @@ import { CellWrapper } from "../7.js";
52
40
  })
53
41
  });
54
42
  };
55
-
56
-
57
-
58
43
  export { DataGridBody };
@@ -1,20 +1,12 @@
1
1
  /*!
2
- @versini/ui-datagrid v4.2.12
2
+ @versini/ui-datagrid v4.2.14
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
6
6
  import { jsx } from "react/jsx-runtime";
7
7
  import { DataGridContext } from "../8.js";
8
8
  import { getCellRole, getCellClasses } from "../y.js";
9
-
10
-
11
-
12
-
13
-
14
- /* =============================================================================
15
- * DataGridCell
16
- * ========================================================================== */ const DataGridCell = ({ className, children, align, borderLeft, borderRight, colSpan, style, ...rest })=>{
17
- return /*#__PURE__*/ jsx(DataGridContext.Consumer, {
9
+ const DataGridCell = ({ className, children, align, borderLeft, borderRight, colSpan, style, ...rest })=>jsx(DataGridContext.Consumer, {
18
10
  children: ({ mode, compact, cellWrapper })=>{
19
11
  const mainClasses = getCellClasses({
20
12
  cellWrapper,
@@ -26,12 +18,11 @@ import { getCellRole, getCellClasses } from "../y.js";
26
18
  borderRight
27
19
  });
28
20
  const role = getCellRole(cellWrapper);
29
- // Apply grid-column span for colSpan > 1.
30
21
  const cellStyle = colSpan && colSpan > 1 ? {
31
22
  ...style,
32
23
  gridColumn: `span ${colSpan}`
33
24
  } : style;
34
- return /*#__PURE__*/ jsx("div", {
25
+ return jsx("div", {
35
26
  role: role,
36
27
  className: mainClasses,
37
28
  style: cellStyle,
@@ -40,8 +31,4 @@ import { getCellRole, getCellClasses } from "../y.js";
40
31
  });
41
32
  }
42
33
  });
43
- };
44
-
45
-
46
-
47
34
  export { DataGridCell };