@versini/ui-datagrid 0.2.2 → 0.2.3

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,10 +1,10 @@
1
1
  /*!
2
- @versini/ui-datagrid v0.2.2
2
+ @versini/ui-datagrid v0.2.3
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
6
6
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
- import { Children, isValidElement, useCallback, useMemo, useState } from "react";
7
+ import { useCallback, useMemo, useState } from "react";
8
8
  import { BlurEffects } from "../DataGridConstants/DataGridConstants.js";
9
9
  import { DataGridContext } from "./DataGridContext.js";
10
10
  import { getDataGridClasses } from "./utilities.js";
@@ -25,54 +25,44 @@ import { getDataGridClasses } from "./utilities.js";
25
25
 
26
26
 
27
27
 
28
- /**
29
- * Helper to check component type by displayName.
30
- * This allows tree-shaking since we don't need to import the actual component.
31
- */ const isComponentType = (child, displayName)=>{
32
- if (!/*#__PURE__*/ isValidElement(child)) {
33
- return false;
34
- }
35
- const type = child.type;
36
- return type?.displayName === displayName;
37
- };
38
28
  /* =============================================================================
39
29
  * DataGrid (main component)
40
30
  * ========================================================================== */ const DataGrid = ({ className, wrapperClassName, children, mode = "system", compact = false, stickyHeader = false, stickyFooter = false, blurEffect = BlurEffects.NONE, maxHeight, disabled = false, columns, ...rest })=>{
41
31
  /**
42
- * Auto-detect if DataGridHeader and DataGridFooter children exist.
43
- * This prevents applying sticky styles when the component doesn't exist.
44
- * Uses displayName comparison to enable tree-shaking.
45
- */ const hasHeader = useMemo(()=>{
46
- return Children.toArray(children).some((child)=>isComponentType(child, "DataGridHeader"));
47
- }, [
48
- children
49
- ]);
50
- const hasFooter = useMemo(()=>{
51
- return Children.toArray(children).some((child)=>isComponentType(child, "DataGridFooter"));
52
- }, [
53
- children
54
- ]);
32
+ * Track registered header/footer components via context registration.
33
+ * Uses counter-based tracking to properly handle multiple instances.
34
+ * Components register themselves when they mount, regardless of nesting depth.
35
+ * This replaces the previous displayName-based child inspection approach.
36
+ */ const [headerCount, setHeaderCount] = useState(0);
37
+ const [footerCount, setFooterCount] = useState(0);
38
+ /**
39
+ * Registration callbacks with stable references.
40
+ * Called by DataGridHeader/DataGridFooter on mount/unmount.
41
+ * Uses increment/decrement to handle multiple instances correctly.
42
+ */ const registerHeader = useCallback(()=>setHeaderCount((c)=>c + 1), []);
43
+ const unregisterHeader = useCallback(()=>setHeaderCount((c)=>c - 1), []);
44
+ const registerFooter = useCallback(()=>setFooterCount((c)=>c + 1), []);
45
+ const unregisterFooter = useCallback(()=>setFooterCount((c)=>c - 1), []);
46
+ const hasRegisteredHeader = headerCount > 0;
47
+ const hasRegisteredFooter = footerCount > 0;
55
48
  /**
56
49
  * Only apply sticky behavior if both the prop is true AND the
57
50
  * corresponding component exists. This prevents adding padding/styles
58
51
  * for non-existent headers/footers.
59
- */ const effectiveStickyHeader = stickyHeader && hasHeader;
60
- const effectiveStickyFooter = stickyFooter && hasFooter;
61
- /**
62
- * Auto-detect if any DataGridHeader child has a caption prop.
63
- * This eliminates the need for a separate hasCaption prop.
64
- */ const hasCaption = useMemo(()=>{
65
- return Children.toArray(children).some((child)=>isComponentType(child, "DataGridHeader") && /*#__PURE__*/ isValidElement(child) && Boolean(child.props.caption));
66
- }, [
67
- children
68
- ]);
52
+ */ const effectiveStickyHeader = stickyHeader && hasRegisteredHeader;
53
+ const effectiveStickyFooter = stickyFooter && hasRegisteredFooter;
69
54
  /**
70
55
  * State to hold the caption ID registered by DataGridHeader.
71
56
  * Used for aria-labelledby on the grid element for accessibility.
57
+ * Also used to determine if a caption exists (for padding calculations).
72
58
  */ const [captionId, setCaptionId] = useState(undefined);
73
59
  const handleSetCaptionId = useCallback((id)=>{
74
60
  setCaptionId(id);
75
61
  }, []);
62
+ /**
63
+ * Determine if caption exists based on registered captionId.
64
+ * This replaces the previous child inspection approach.
65
+ */ const hasCaption = Boolean(captionId);
76
66
  const classes = useMemo(()=>getDataGridClasses({
77
67
  mode,
78
68
  className,
@@ -99,7 +89,11 @@ import { getDataGridClasses } from "./utilities.js";
99
89
  stickyFooter: effectiveStickyFooter,
100
90
  blurEffect,
101
91
  columns,
102
- setCaptionId: handleSetCaptionId
92
+ setCaptionId: handleSetCaptionId,
93
+ registerHeader,
94
+ unregisterHeader,
95
+ registerFooter,
96
+ unregisterFooter
103
97
  }), [
104
98
  mode,
105
99
  compact,
@@ -107,7 +101,11 @@ import { getDataGridClasses } from "./utilities.js";
107
101
  effectiveStickyFooter,
108
102
  blurEffect,
109
103
  columns,
110
- handleSetCaptionId
104
+ handleSetCaptionId,
105
+ registerHeader,
106
+ unregisterHeader,
107
+ registerFooter,
108
+ unregisterFooter
111
109
  ]);
112
110
  const wrapperStyle = maxHeight ? {
113
111
  maxHeight: typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v0.2.2
2
+ @versini/ui-datagrid v0.2.3
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v0.2.2
2
+ @versini/ui-datagrid v0.2.3
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v0.2.2
2
+ @versini/ui-datagrid v0.2.3
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v0.2.2
2
+ @versini/ui-datagrid v0.2.3
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v0.2.2
2
+ @versini/ui-datagrid v0.2.3
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v0.2.2
2
+ @versini/ui-datagrid v0.2.3
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v0.2.2
2
+ @versini/ui-datagrid v0.2.3
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v0.2.2
2
+ @versini/ui-datagrid v0.2.3
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v0.2.2
2
+ @versini/ui-datagrid v0.2.3
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v0.2.2
2
+ @versini/ui-datagrid v0.2.3
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v0.2.2
2
+ @versini/ui-datagrid v0.2.3
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v0.2.2
2
+ @versini/ui-datagrid v0.2.3
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v0.2.2
2
+ @versini/ui-datagrid v0.2.3
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v0.2.2
2
+ @versini/ui-datagrid v0.2.3
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,10 +1,11 @@
1
1
  /*!
2
- @versini/ui-datagrid v0.2.2
2
+ @versini/ui-datagrid v0.2.3
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
6
6
  import { jsx } from "react/jsx-runtime";
7
7
  import clsx from "clsx";
8
+ import { useEffect } from "react";
8
9
  import { getHeaderFooterBackgroundClasses, getStickyBlurClasses } from "../common/utilities.js";
9
10
  import { DataGridContext } from "../DataGrid/DataGridContext.js";
10
11
  import { BlurEffects, CellWrapper } from "../DataGridConstants/DataGridConstants.js";
@@ -13,6 +14,8 @@ import { BlurEffects, CellWrapper } from "../DataGridConstants/DataGridConstants
13
14
 
14
15
  ;// CONCATENATED MODULE: external "clsx"
15
16
 
17
+ ;// CONCATENATED MODULE: external "react"
18
+
16
19
  ;// CONCATENATED MODULE: external "../common/utilities.js"
17
20
 
18
21
  ;// CONCATENATED MODULE: external "../DataGrid/DataGridContext.js"
@@ -25,6 +28,7 @@ import { BlurEffects, CellWrapper } from "../DataGridConstants/DataGridConstants
25
28
 
26
29
 
27
30
 
31
+
28
32
  /**
29
33
  * Generates classes for the DataGridFooter.
30
34
  *
@@ -60,28 +64,49 @@ import { BlurEffects, CellWrapper } from "../DataGridConstants/DataGridConstants
60
64
  * DataGridFooter
61
65
  * ========================================================================== */ const DataGridFooter = ({ className, children, ...rest })=>{
62
66
  return /*#__PURE__*/ jsx(DataGridContext.Consumer, {
63
- children: ({ mode, stickyFooter, blurEffect, columns })=>/*#__PURE__*/ jsx(DataGridContext.Consumer, {
64
- children: (ctx)=>/*#__PURE__*/ jsx(DataGridContext.Provider, {
65
- value: {
66
- ...ctx,
67
- cellWrapper: CellWrapper.FOOTER
68
- },
69
- children: /*#__PURE__*/ jsx("div", {
70
- role: "rowgroup",
71
- className: getFooterClasses({
72
- className,
73
- stickyFooter,
74
- mode,
75
- blurEffect,
76
- hasColumns: Boolean(columns)
77
- }),
78
- ...rest,
79
- children: children
80
- })
81
- })
67
+ children: (ctx)=>/*#__PURE__*/ jsx(DataGridFooterInner, {
68
+ className: className,
69
+ ctx: ctx,
70
+ ...rest,
71
+ children: children
82
72
  })
83
73
  });
84
74
  };
85
75
  DataGridFooter.displayName = "DataGridFooter";
76
+ /**
77
+ * Inner component to handle the useEffect for registering footer.
78
+ * Separated to avoid hooks inside Consumer render prop.
79
+ */ const DataGridFooterInner = ({ className, ctx, children, ...rest })=>{
80
+ const hasColumns = Boolean(ctx.columns);
81
+ // Register this footer with the parent DataGrid on mount.
82
+ // This enables sticky footer behavior regardless of nesting depth.
83
+ useEffect(()=>{
84
+ ctx.registerFooter?.();
85
+ return ()=>{
86
+ ctx.unregisterFooter?.();
87
+ };
88
+ }, [
89
+ ctx.registerFooter,
90
+ ctx.unregisterFooter
91
+ ]);
92
+ return /*#__PURE__*/ jsx(DataGridContext.Provider, {
93
+ value: {
94
+ ...ctx,
95
+ cellWrapper: CellWrapper.FOOTER
96
+ },
97
+ children: /*#__PURE__*/ jsx("div", {
98
+ role: "rowgroup",
99
+ className: getFooterClasses({
100
+ className,
101
+ stickyFooter: ctx.stickyFooter,
102
+ mode: ctx.mode,
103
+ blurEffect: ctx.blurEffect,
104
+ hasColumns
105
+ }),
106
+ ...rest,
107
+ children: children
108
+ })
109
+ });
110
+ };
86
111
 
87
112
  export { DataGridFooter, getFooterClasses };
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v0.2.2
2
+ @versini/ui-datagrid v0.2.3
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v0.2.2
2
+ @versini/ui-datagrid v0.2.3
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -90,10 +90,21 @@ import { BlurEffects, CellWrapper } from "../DataGridConstants/DataGridConstants
90
90
  };
91
91
  DataGridHeader.displayName = "DataGridHeader";
92
92
  /**
93
- * Inner component to handle the useEffect for registering captionId.
93
+ * Inner component to handle the useEffect for registering captionId and header.
94
94
  * Separated to avoid hooks inside Consumer render prop.
95
95
  */ const DataGridHeaderInner = ({ caption, captionClassName, captionId, className, ctx, children, ...rest })=>{
96
96
  const hasColumns = Boolean(ctx.columns);
97
+ // Register this header with the parent DataGrid on mount.
98
+ // This enables sticky header behavior regardless of nesting depth.
99
+ useEffect(()=>{
100
+ ctx.registerHeader?.();
101
+ return ()=>{
102
+ ctx.unregisterHeader?.();
103
+ };
104
+ }, [
105
+ ctx.registerHeader,
106
+ ctx.unregisterHeader
107
+ ]);
97
108
  // Register the caption ID with the parent DataGrid for aria-labelledby
98
109
  useEffect(()=>{
99
110
  if (caption && ctx.setCaptionId) {
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v0.2.2
2
+ @versini/ui-datagrid v0.2.3
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v0.2.2
2
+ @versini/ui-datagrid v0.2.3
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v0.2.2
2
+ @versini/ui-datagrid v0.2.3
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v0.2.2
2
+ @versini/ui-datagrid v0.2.3
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v0.2.2
2
+ @versini/ui-datagrid v0.2.3
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v0.2.2
2
+ @versini/ui-datagrid v0.2.3
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v0.2.2
2
+ @versini/ui-datagrid v0.2.3
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v0.2.2
2
+ @versini/ui-datagrid v0.2.3
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v0.2.2
2
+ @versini/ui-datagrid v0.2.3
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@versini/ui-datagrid",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "license": "MIT",
5
5
  "author": "Arno Versini",
6
6
  "publishConfig": {
@@ -94,5 +94,5 @@
94
94
  "sideEffects": [
95
95
  "**/*.css"
96
96
  ],
97
- "gitHead": "f23e7cccc6798893b412edd01aec4d767ec94c9f"
97
+ "gitHead": "e82cbf23cd8790099a81e5520e7d6a2c7df51ec9"
98
98
  }