@glideappsfinal/glide-data-grid 6.0.9 → 6.0.11

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 (173) hide show
  1. package/build.sh +3 -1
  2. package/dist/cjs/data-editor/data-editor.js +40 -7
  3. package/dist/cjs/data-editor/data-editor.js.map +1 -1
  4. package/dist/cjs/internal/data-editor-container/data-grid-container.css +1 -0
  5. package/dist/cjs/internal/data-editor-container/data-grid-container.js +25 -30
  6. package/dist/cjs/internal/data-grid/data-grid.js +7 -8
  7. package/dist/cjs/internal/data-grid/data-grid.js.map +1 -1
  8. package/dist/cjs/internal/data-grid/render/data-grid-lib.js +25 -7
  9. package/dist/cjs/internal/data-grid/render/data-grid-lib.js.map +1 -1
  10. package/dist/cjs/internal/data-grid/render/data-grid-render.header.js +32 -7
  11. package/dist/cjs/internal/data-grid/render/data-grid-render.header.js.map +1 -1
  12. package/dist/cjs/internal/data-grid/render/data-grid-render.js +14 -6
  13. package/dist/cjs/internal/data-grid/render/data-grid-render.js.map +1 -1
  14. package/dist/cjs/internal/data-grid-overlay-editor/data-grid-overlay-editor-style.css +1 -0
  15. package/dist/cjs/internal/data-grid-overlay-editor/data-grid-overlay-editor-style.js +19 -75
  16. package/dist/cjs/internal/data-grid-overlay-editor/private/bubbles-overlay-editor-style.css +1 -0
  17. package/dist/cjs/internal/data-grid-overlay-editor/private/bubbles-overlay-editor-style.js +5 -32
  18. package/dist/cjs/internal/data-grid-overlay-editor/private/drilldown-overlay-editor.css +1 -0
  19. package/dist/cjs/internal/data-grid-overlay-editor/private/drilldown-overlay-editor.js +15 -45
  20. package/dist/cjs/internal/data-grid-overlay-editor/private/image-overlay-editor-style.css +1 -0
  21. package/dist/cjs/internal/data-grid-overlay-editor/private/image-overlay-editor-style.js +5 -54
  22. package/dist/cjs/internal/data-grid-overlay-editor/private/markdown-overlay-editor-style.css +1 -0
  23. package/dist/cjs/internal/data-grid-overlay-editor/private/markdown-overlay-editor-style.js +9 -74
  24. package/dist/cjs/internal/data-grid-overlay-editor/private/number-overlay-editor-style.css +1 -0
  25. package/dist/cjs/internal/data-grid-overlay-editor/private/number-overlay-editor-style.js +5 -13
  26. package/dist/cjs/internal/data-grid-overlay-editor/private/uri-overlay-editor-style.css +1 -0
  27. package/dist/cjs/internal/data-grid-overlay-editor/private/uri-overlay-editor-style.js +5 -51
  28. package/dist/cjs/internal/data-grid-search/data-grid-search-style.css +1 -0
  29. package/dist/cjs/internal/data-grid-search/data-grid-search-style.js +5 -94
  30. package/dist/cjs/internal/growing-entry/growing-entry-style.css +3 -0
  31. package/dist/cjs/internal/growing-entry/growing-entry-style.js +15 -58
  32. package/dist/cjs/internal/markdown-div/private/markdown-container.css +1 -0
  33. package/dist/cjs/internal/markdown-div/private/markdown-container.js +5 -17
  34. package/dist/cjs/internal/scrolling-data-grid/infinite-scroller.css +1 -0
  35. package/dist/cjs/internal/scrolling-data-grid/infinite-scroller.js +233 -231
  36. package/dist/dts/cells/boolean-cell.d.ts +0 -1
  37. package/dist/dts/cells/bubble-cell.d.ts +0 -1
  38. package/dist/dts/cells/cell-types.d.ts +0 -1
  39. package/dist/dts/cells/drilldown-cell.d.ts +0 -1
  40. package/dist/dts/cells/image-cell.d.ts +0 -1
  41. package/dist/dts/cells/index.d.ts +0 -1
  42. package/dist/dts/cells/loading-cell.d.ts +0 -1
  43. package/dist/dts/cells/markdown-cell.d.ts +0 -1
  44. package/dist/dts/cells/marker-cell.d.ts +0 -1
  45. package/dist/dts/cells/new-row-cell.d.ts +0 -1
  46. package/dist/dts/cells/number-cell.d.ts +0 -1
  47. package/dist/dts/cells/protected-cell.d.ts +0 -1
  48. package/dist/dts/cells/row-id-cell.d.ts +0 -1
  49. package/dist/dts/cells/text-cell.d.ts +0 -1
  50. package/dist/dts/cells/uri-cell.d.ts +0 -1
  51. package/dist/dts/common/browser-detect.d.ts +0 -1
  52. package/dist/dts/common/image-window-loader.d.ts +0 -1
  53. package/dist/dts/common/is-hotkey.d.ts +0 -1
  54. package/dist/dts/common/math.d.ts +0 -1
  55. package/dist/dts/common/render-state-provider.d.ts +0 -1
  56. package/dist/dts/common/resize-detector.d.ts +0 -1
  57. package/dist/dts/common/styles.d.ts +0 -1
  58. package/dist/dts/common/support.d.ts +0 -1
  59. package/dist/dts/common/utils.d.ts +0 -1
  60. package/dist/dts/data-editor/copy-paste.d.ts +0 -1
  61. package/dist/dts/data-editor/data-editor-fns.d.ts +0 -1
  62. package/dist/dts/data-editor/data-editor-keybindings.d.ts +0 -1
  63. package/dist/dts/data-editor/data-editor.d.ts +0 -1
  64. package/dist/dts/data-editor/data-editor.d.ts.map +1 -1
  65. package/dist/dts/data-editor/group-rename.d.ts +0 -1
  66. package/dist/dts/data-editor/row-grouping-api.d.ts +0 -1
  67. package/dist/dts/data-editor/row-grouping.d.ts +0 -1
  68. package/dist/dts/data-editor/use-autoscroll.d.ts +0 -1
  69. package/dist/dts/data-editor/use-cells-for-selection.d.ts +0 -1
  70. package/dist/dts/data-editor/use-column-sizer.d.ts +0 -1
  71. package/dist/dts/data-editor/use-initial-scroll-offset.d.ts +0 -1
  72. package/dist/dts/data-editor/use-rem-adjuster.d.ts +0 -1
  73. package/dist/dts/data-editor/visible-region.d.ts +0 -1
  74. package/dist/dts/data-editor-all.d.ts +0 -1
  75. package/dist/dts/index.d.ts +0 -1
  76. package/dist/dts/internal/click-outside-container/click-outside-container.d.ts +0 -1
  77. package/dist/dts/internal/data-editor-container/data-grid-container.d.ts +0 -1
  78. package/dist/dts/internal/data-grid/animation-manager.d.ts +0 -1
  79. package/dist/dts/internal/data-grid/cell-set.d.ts +0 -1
  80. package/dist/dts/internal/data-grid/color-parser.d.ts +0 -1
  81. package/dist/dts/internal/data-grid/data-grid-sprites.d.ts +0 -1
  82. package/dist/dts/internal/data-grid/data-grid-types.d.ts +0 -1
  83. package/dist/dts/internal/data-grid/data-grid.d.ts +0 -1
  84. package/dist/dts/internal/data-grid/data-grid.d.ts.map +1 -1
  85. package/dist/dts/internal/data-grid/event-args.d.ts +1 -2
  86. package/dist/dts/internal/data-grid/event-args.d.ts.map +1 -1
  87. package/dist/dts/internal/data-grid/image-window-loader-interface.d.ts +0 -1
  88. package/dist/dts/internal/data-grid/render/data-grid-lib.d.ts +1 -2
  89. package/dist/dts/internal/data-grid/render/data-grid-lib.d.ts.map +1 -1
  90. package/dist/dts/internal/data-grid/render/data-grid-render.blit.d.ts +0 -1
  91. package/dist/dts/internal/data-grid/render/data-grid-render.cells.d.ts +0 -1
  92. package/dist/dts/internal/data-grid/render/data-grid-render.d.ts +0 -1
  93. package/dist/dts/internal/data-grid/render/data-grid-render.d.ts.map +1 -1
  94. package/dist/dts/internal/data-grid/render/data-grid-render.header.d.ts +0 -1
  95. package/dist/dts/internal/data-grid/render/data-grid-render.header.d.ts.map +1 -1
  96. package/dist/dts/internal/data-grid/render/data-grid-render.lines.d.ts +0 -1
  97. package/dist/dts/internal/data-grid/render/data-grid-render.walk.d.ts +0 -1
  98. package/dist/dts/internal/data-grid/render/data-grid.render.rings.d.ts +0 -1
  99. package/dist/dts/internal/data-grid/render/draw-checkbox.d.ts +0 -1
  100. package/dist/dts/internal/data-grid/render/draw-edit-hover-indicator.d.ts +0 -1
  101. package/dist/dts/internal/data-grid/render/draw-grid-arg.d.ts +0 -1
  102. package/dist/dts/internal/data-grid/sprites.d.ts +0 -1
  103. package/dist/dts/internal/data-grid/use-animation-queue.d.ts +0 -1
  104. package/dist/dts/internal/data-grid/use-selection-behavior.d.ts +0 -1
  105. package/dist/dts/internal/data-grid-dnd/data-grid-dnd.d.ts +0 -1
  106. package/dist/dts/internal/data-grid-overlay-editor/data-grid-overlay-editor-style.d.ts +0 -1
  107. package/dist/dts/internal/data-grid-overlay-editor/data-grid-overlay-editor.d.ts +0 -1
  108. package/dist/dts/internal/data-grid-overlay-editor/private/bubbles-overlay-editor-style.d.ts +0 -1
  109. package/dist/dts/internal/data-grid-overlay-editor/private/bubbles-overlay-editor.d.ts +0 -1
  110. package/dist/dts/internal/data-grid-overlay-editor/private/drilldown-overlay-editor.d.ts +0 -1
  111. package/dist/dts/internal/data-grid-overlay-editor/private/image-overlay-editor-style.d.ts +0 -1
  112. package/dist/dts/internal/data-grid-overlay-editor/private/image-overlay-editor.d.ts +0 -1
  113. package/dist/dts/internal/data-grid-overlay-editor/private/markdown-overlay-editor-style.d.ts +0 -1
  114. package/dist/dts/internal/data-grid-overlay-editor/private/markdown-overlay-editor.d.ts +0 -1
  115. package/dist/dts/internal/data-grid-overlay-editor/private/number-overlay-editor-style.d.ts +0 -1
  116. package/dist/dts/internal/data-grid-overlay-editor/private/number-overlay-editor.d.ts +0 -1
  117. package/dist/dts/internal/data-grid-overlay-editor/private/uri-overlay-editor-style.d.ts +0 -1
  118. package/dist/dts/internal/data-grid-overlay-editor/private/uri-overlay-editor.d.ts +0 -1
  119. package/dist/dts/internal/data-grid-overlay-editor/use-stay-on-screen.d.ts +0 -1
  120. package/dist/dts/internal/data-grid-search/data-grid-search-style.d.ts +0 -1
  121. package/dist/dts/internal/data-grid-search/data-grid-search.d.ts +0 -1
  122. package/dist/dts/internal/growing-entry/growing-entry-style.d.ts +0 -1
  123. package/dist/dts/internal/growing-entry/growing-entry.d.ts +0 -1
  124. package/dist/dts/internal/markdown-div/markdown-div.d.ts +0 -1
  125. package/dist/dts/internal/markdown-div/private/markdown-container.d.ts +0 -1
  126. package/dist/dts/internal/scrolling-data-grid/infinite-scroller.d.ts +0 -1
  127. package/dist/dts/internal/scrolling-data-grid/scrolling-data-grid.d.ts +0 -1
  128. package/dist/dts/internal/scrolling-data-grid/use-kinetic-scroll.d.ts +0 -1
  129. package/dist/esm/data-editor/data-editor.js +40 -7
  130. package/dist/esm/data-editor/data-editor.js.map +1 -1
  131. package/dist/esm/internal/data-editor-container/data-grid-container.css +1 -0
  132. package/dist/esm/internal/data-editor-container/data-grid-container.js +25 -30
  133. package/dist/esm/internal/data-grid/data-grid.js +7 -8
  134. package/dist/esm/internal/data-grid/data-grid.js.map +1 -1
  135. package/dist/esm/internal/data-grid/render/data-grid-lib.js +25 -7
  136. package/dist/esm/internal/data-grid/render/data-grid-lib.js.map +1 -1
  137. package/dist/esm/internal/data-grid/render/data-grid-render.header.js +32 -7
  138. package/dist/esm/internal/data-grid/render/data-grid-render.header.js.map +1 -1
  139. package/dist/esm/internal/data-grid/render/data-grid-render.js +14 -6
  140. package/dist/esm/internal/data-grid/render/data-grid-render.js.map +1 -1
  141. package/dist/esm/internal/data-grid-overlay-editor/data-grid-overlay-editor-style.css +1 -0
  142. package/dist/esm/internal/data-grid-overlay-editor/data-grid-overlay-editor-style.js +19 -75
  143. package/dist/esm/internal/data-grid-overlay-editor/private/bubbles-overlay-editor-style.css +1 -0
  144. package/dist/esm/internal/data-grid-overlay-editor/private/bubbles-overlay-editor-style.js +5 -32
  145. package/dist/esm/internal/data-grid-overlay-editor/private/drilldown-overlay-editor.css +1 -0
  146. package/dist/esm/internal/data-grid-overlay-editor/private/drilldown-overlay-editor.js +15 -45
  147. package/dist/esm/internal/data-grid-overlay-editor/private/image-overlay-editor-style.css +1 -0
  148. package/dist/esm/internal/data-grid-overlay-editor/private/image-overlay-editor-style.js +5 -54
  149. package/dist/esm/internal/data-grid-overlay-editor/private/markdown-overlay-editor-style.css +1 -0
  150. package/dist/esm/internal/data-grid-overlay-editor/private/markdown-overlay-editor-style.js +9 -74
  151. package/dist/esm/internal/data-grid-overlay-editor/private/number-overlay-editor-style.css +1 -0
  152. package/dist/esm/internal/data-grid-overlay-editor/private/number-overlay-editor-style.js +5 -13
  153. package/dist/esm/internal/data-grid-overlay-editor/private/uri-overlay-editor-style.css +1 -0
  154. package/dist/esm/internal/data-grid-overlay-editor/private/uri-overlay-editor-style.js +5 -51
  155. package/dist/esm/internal/data-grid-search/data-grid-search-style.css +1 -0
  156. package/dist/esm/internal/data-grid-search/data-grid-search-style.js +5 -94
  157. package/dist/esm/internal/growing-entry/growing-entry-style.css +3 -0
  158. package/dist/esm/internal/growing-entry/growing-entry-style.js +15 -58
  159. package/dist/esm/internal/markdown-div/private/markdown-container.css +1 -0
  160. package/dist/esm/internal/markdown-div/private/markdown-container.js +5 -17
  161. package/dist/esm/internal/scrolling-data-grid/infinite-scroller.css +1 -0
  162. package/dist/esm/internal/scrolling-data-grid/infinite-scroller.js +233 -231
  163. package/dist/index.css +12 -0
  164. package/package.json +1 -1
  165. package/src/data-editor/data-editor.tsx +50 -7
  166. package/src/docs/examples/custom-group-header.stories.tsx +41 -11
  167. package/src/internal/data-grid/data-grid.tsx +8 -9
  168. package/src/internal/data-grid/event-args.ts +1 -1
  169. package/src/internal/data-grid/render/data-grid-lib.ts +24 -6
  170. package/src/internal/data-grid/render/data-grid-render.header.ts +34 -5
  171. package/src/internal/data-grid/render/data-grid-render.ts +13 -6
  172. package/test/data-editor.test.tsx +21 -13
  173. package/test/data-grid.test.tsx +14 -2
@@ -7,9 +7,10 @@ import {
7
7
  useMockDataGenerator,
8
8
  defaultProps,
9
9
  } from "../../data-editor/stories/utils.js";
10
- import type { DrawGroupHeaderCallback } from "../../internal/data-grid/data-grid-types.js";
10
+ import type { DrawGroupHeaderCallback, GridSelection } from "../../internal/data-grid/data-grid-types.js";
11
11
  import { GridColumnIcon } from "../../internal/data-grid/data-grid-types.js";
12
12
  import { SimpleThemeWrapper } from "../../stories/story-utils.js";
13
+ import { emptyGridSelection } from "../../data-editor/data-editor.js";
13
14
 
14
15
  const COMPOSITE_DESTINATION_OVER = "destination-over";
15
16
  const COMPOSITE_SOURCE_OVER = "source-over";
@@ -66,7 +67,8 @@ export const CustomGroupHeaderDrawing: React.VFC = () => {
66
67
  });
67
68
 
68
69
  const drawGroupHeader: DrawGroupHeaderCallback = React.useCallback(args => {
69
- const { ctx, groupName, level, span, rect, theme, isSelected, isHovered } = args;
70
+ const { ctx, groupName, level, span, rect, theme, isSelected, isHovered, } = args;
71
+ console.log(args);
70
72
 
71
73
  // First draw default to get icons and actions, but we'll draw over the background
72
74
  // Save the context state before default drawing
@@ -96,7 +98,7 @@ export const CustomGroupHeaderDrawing: React.VFC = () => {
96
98
  // Use composite operation to draw background behind existing content
97
99
  ctx.globalCompositeOperation = COMPOSITE_DESTINATION_OVER;
98
100
  ctx.fillStyle = gradient;
99
- ctx.fill();
101
+ // ctx.fill();
100
102
  ctx.globalCompositeOperation = COMPOSITE_SOURCE_OVER;
101
103
 
102
104
  // Draw border
@@ -107,7 +109,7 @@ export const CustomGroupHeaderDrawing: React.VFC = () => {
107
109
 
108
110
  // Draw custom text with shadow effect
109
111
  if (groupName !== "") {
110
- ctx.fillStyle = isSelected ? theme.textHeaderSelected : theme.textHeader;
112
+ // ctx.fillStyle = isSelected ? theme.textHeaderSelected : theme.textHeader;
111
113
  ctx.font = `bold ${14 + level * 2}px ${theme.fontFamily}`;
112
114
  ctx.textAlign = "left";
113
115
  ctx.textBaseline = "middle";
@@ -119,6 +121,7 @@ export const CustomGroupHeaderDrawing: React.VFC = () => {
119
121
  ctx.shadowOffsetY = 1;
120
122
 
121
123
  const padding = 12 + level * 4;
124
+
122
125
  ctx.fillText(groupName, rect.x + padding, rect.y + rect.height / 2);
123
126
 
124
127
  // Reset shadow
@@ -130,7 +133,7 @@ export const CustomGroupHeaderDrawing: React.VFC = () => {
130
133
  // Draw span indicator (number of columns in group)
131
134
  const spanText = `(${span[1] - span[0] + 1} cols)`;
132
135
  ctx.font = `${10}px ${theme.fontFamily}`;
133
- ctx.fillStyle = isSelected ? theme.textHeaderSelected : (theme.textGroupHeader ?? theme.textHeader);
136
+ // ctx.fillStyle = isSelected ? theme.textHeaderSelected : (theme.textGroupHeader ?? theme.textHeader);
134
137
  ctx.globalAlpha = 0.7;
135
138
  const textWidth = ctx.measureText(groupName).width;
136
139
  ctx.fillText(spanText, rect.x + padding + textWidth + 8, rect.y + rect.height / 2);
@@ -138,16 +141,16 @@ export const CustomGroupHeaderDrawing: React.VFC = () => {
138
141
  }
139
142
 
140
143
  // Draw level indicator badge in top-right corner
141
- ctx.fillStyle = isSelected ? theme.accentColor : theme.bgHeader;
144
+ // ctx.fillStyle = isSelected ? theme.accentColor : theme.bgHeader;
142
145
  ctx.beginPath();
143
146
  const badgeSize = 20;
144
147
  const badgePadding = 4;
145
148
  const badgeX = rect.x + rect.width - badgeSize - badgePadding;
146
149
  const badgeY = rect.y + badgePadding;
147
150
  ctx.arc(badgeX + badgeSize / 2, badgeY + badgeSize / 2, badgeSize / 2, 0, Math.PI * 2);
148
- ctx.fill();
151
+ // ctx.fill();
149
152
 
150
- ctx.fillStyle = theme.textHeader;
153
+ // ctx.fillStyle = theme.textHeader;
151
154
  ctx.font = `bold ${10}px ${theme.fontFamily}`;
152
155
  ctx.textAlign = "center";
153
156
  ctx.textBaseline = "middle";
@@ -155,6 +158,8 @@ export const CustomGroupHeaderDrawing: React.VFC = () => {
155
158
 
156
159
  ctx.restore();
157
160
  }, []);
161
+ const [sel, setSel] = React.useState<GridSelection>(emptyGridSelection);
162
+
158
163
 
159
164
  return (
160
165
  <DataEditor
@@ -166,9 +171,34 @@ export const CustomGroupHeaderDrawing: React.VFC = () => {
166
171
  name: g,
167
172
  icon: g === "" ? undefined : GridColumnIcon.HeaderCode,
168
173
  })}
174
+ // freezeColumns={3}
169
175
  groupHeaderHeight={[36, 32, 30, 28]} // Four different heights for four levels
170
- drawGroupHeader={drawGroupHeader}
176
+ // drawGroupHeader={drawGroupHeader}
177
+ drawHeader={(args,draw) => {
178
+ console.log(args);
179
+ draw();
180
+ }}
171
181
  rowMarkers="both"
182
+ gridSelection={sel}
183
+ onGridSelectionChange={(args) => {
184
+ setSel(args)
185
+ console.log('onGridSelectionChange',args);
186
+ }}
187
+ onGroupHeaderClicked={(args) => {
188
+ console.log('onGroupHeaderClicked',args);
189
+ }}
190
+ onMouseMove={(args) => {
191
+ if(args.kind === "group-header") {
192
+
193
+ // console.log('onMouseMove',args);
194
+ }
195
+ }}
196
+ onCellClicked={(args) => {
197
+
198
+
199
+ // console.log('onCellClicked',args);
200
+
201
+ }}
172
202
  />
173
203
  );
174
204
  };
@@ -190,8 +220,8 @@ export const MinimalGroupHeader: React.VFC = () => {
190
220
  });
191
221
 
192
222
  const drawGroupHeader: DrawGroupHeaderCallback = React.useCallback(args => {
193
- const { ctx, rect, theme, isSelected, isHovered } = args;
194
-
223
+ const { ctx, rect, theme, isSelected, isHovered, groupName } = args;
224
+
195
225
  // Call default drawing first
196
226
  ctx.save();
197
227
  // draw();
@@ -9,6 +9,7 @@ import {
9
9
  rectBottomRight,
10
10
  useMappedColumns,
11
11
  } from "./render/data-grid-lib.js";
12
+ import { getGroupLevels, getTotalGroupHeaderHeight } from "./render/data-grid-render.walk.js";
12
13
  import {
13
14
  GridCellKind,
14
15
  type Rectangle,
@@ -445,13 +446,6 @@ const DataGrid: React.ForwardRefRenderFunction<DataGridRef, DataGridProps> = (p,
445
446
  }),
446
447
  [headerIcons]
447
448
  );
448
- const groupHeights = enableGroups
449
- ? (Array.isArray(groupHeaderHeight)
450
- ? groupHeaderHeight.reduce((sum, h) => sum + h, 0)
451
- : groupHeaderHeight)
452
- : 0;
453
- const totalHeaderHeight = headerHeight + groupHeights;
454
-
455
449
  const scrollingStopRef = React.useRef(-1);
456
450
  const enableFirefoxRescaling = (experimental?.enableFirefoxRescaling ?? false) && browserIsFirefox.value;
457
451
  const enableSafariRescaling = (experimental?.enableSafariRescaling ?? false) && browserIsSafari.value;
@@ -469,6 +463,9 @@ const DataGrid: React.ForwardRefRenderFunction<DataGridRef, DataGridProps> = (p,
469
463
  }, [cellYOffset, cellXOffset, translateX, translateY, enableFirefoxRescaling, enableSafariRescaling]);
470
464
 
471
465
  const mappedColumns = useMappedColumns(columns, freezeColumns);
466
+ const groupHeaderLevels = enableGroups ? getGroupLevels(mappedColumns) : 0;
467
+ const totalGroupHeaderHeight = enableGroups ? getTotalGroupHeaderHeight(groupHeaderHeight, mappedColumns) : 0;
468
+ const totalHeaderHeight = headerHeight + totalGroupHeaderHeight;
472
469
  const stickyX = React.useMemo(
473
470
  () => (fixedShadowX ? getStickyWidth(mappedColumns, dragAndDropState) : 0),
474
471
  [mappedColumns, dragAndDropState, fixedShadowX]
@@ -578,7 +575,8 @@ const DataGrid: React.ForwardRefRenderFunction<DataGridRef, DataGridProps> = (p,
578
575
  rowHeight,
579
576
  cellYOffset,
580
577
  translateY,
581
- freezeTrailingRows
578
+ freezeTrailingRows,
579
+ groupHeaderLevels
582
580
  );
583
581
 
584
582
  const shiftKey = ev?.shiftKey === true;
@@ -741,6 +739,7 @@ const DataGrid: React.ForwardRefRenderFunction<DataGridRef, DataGridProps> = (p,
741
739
  enableGroups,
742
740
  headerHeight,
743
741
  groupHeaderHeight,
742
+ groupHeaderLevels,
744
743
  rows,
745
744
  rowHeight,
746
745
  cellYOffset,
@@ -987,7 +986,7 @@ const DataGrid: React.ForwardRefRenderFunction<DataGridRef, DataGridProps> = (p,
987
986
  hCol >= 0 &&
988
987
  hCol < mappedColumns.length &&
989
988
  mappedColumns[hCol].headerRowMarkerDisabled !== true;
990
- const groupHeaderHovered = hCol !== undefined && hRow === -2;
989
+ const groupHeaderHovered = hCol !== undefined && hRow !== undefined && hRow <= -2;
991
990
  let clickableInnerCellHovered = false;
992
991
  let editableBoolHovered = false;
993
992
  let cursorOverride: React.CSSProperties["cursor"] | undefined = drawCursorOverride;
@@ -42,7 +42,7 @@ export const groupHeaderKind = "group-header" as const;
42
42
  /** @category Types */
43
43
  export interface GridMouseGroupHeaderEventArgs extends BaseGridMouseEventArgs, PositionableMouseEventArgs {
44
44
  readonly kind: typeof groupHeaderKind;
45
- readonly location: readonly [number, -2];
45
+ readonly location: Item;
46
46
  readonly bounds: Rectangle;
47
47
  readonly group: string;
48
48
  }
@@ -293,13 +293,31 @@ export function getRowIndexForY(
293
293
  rowHeight: number | ((index: number) => number),
294
294
  cellYOffset: number,
295
295
  translateY: number,
296
- freezeTrailingRows: number
296
+ freezeTrailingRows: number,
297
+ groupHeaderLevels?: number
297
298
  ): number | undefined {
298
- const groupHeights = Array.isArray(groupHeaderHeight)
299
- ? groupHeaderHeight.reduce((sum, h) => sum + h, 0)
300
- : groupHeaderHeight;
299
+ const groupHeightsArray = Array.isArray(groupHeaderHeight) ? groupHeaderHeight : undefined;
300
+ const groupHeaderHeightValue = typeof groupHeaderHeight === "number" ? groupHeaderHeight : undefined;
301
+ const levels = groupHeightsArray?.length ?? (groupHeaderLevels ?? (hasGroups ? 1 : 0));
302
+ const groupHeights = hasGroups
303
+ ? (groupHeightsArray !== undefined
304
+ ? groupHeightsArray.reduce((sum, h) => sum + h, 0)
305
+ : (levels > 0 && groupHeaderHeightValue !== undefined ? groupHeaderHeightValue * levels : 0))
306
+ : 0;
301
307
  const totalHeaderHeight = headerHeight + groupHeights;
302
- if (hasGroups && targetY <= groupHeights) return -2;
308
+ if (hasGroups && levels > 0 && targetY <= groupHeights) {
309
+ if (groupHeightsArray !== undefined) {
310
+ let yOffset = 0;
311
+ for (let level = 0; level < levels; level++) {
312
+ yOffset += groupHeightsArray[level] ?? groupHeightsArray[0] ?? 0;
313
+ if (targetY <= yOffset) return -2 - level;
314
+ }
315
+ return -2 - (levels - 1);
316
+ }
317
+ if (groupHeaderHeightValue === undefined || groupHeaderHeightValue <= 0) return -2;
318
+ const groupLevel = Math.min(levels - 1, Math.max(0, Math.floor(targetY / groupHeaderHeightValue)));
319
+ return -2 - groupLevel;
320
+ }
303
321
  if (targetY <= totalHeaderHeight) return -1;
304
322
 
305
323
  let y = height;
@@ -805,7 +823,7 @@ export function computeBounds(
805
823
  height: 0,
806
824
  };
807
825
 
808
- if (col >= mappedColumns.length || row >= rows || row < -2 || col < 0) {
826
+ if (col >= mappedColumns.length || row >= rows || col < 0) {
809
827
  return result;
810
828
  }
811
829
 
@@ -97,11 +97,15 @@ export function drawGridHeaders(
97
97
  const bgFillStyle = selected ? theme.accentColor : hasSelectedCell ? theme.bgHeaderHasFocus : theme.bgHeader;
98
98
 
99
99
  const y = enableGroups ? totalGroupHeaderHeight : 0;
100
+ const isFirstSelected = selected && selection.columns.first() === c.sourceIndex;
100
101
  const xOffset = c.sourceIndex === 0 ? 0 : 1;
101
102
 
102
103
  if (selected) {
103
104
  ctx.fillStyle = bgFillStyle;
104
105
  ctx.fillRect(x + xOffset, y, c.width - xOffset, headerHeight);
106
+ if (isFirstSelected) {
107
+ ctx.fillRect(x, y, 1, headerHeight);
108
+ }
105
109
  } else if (hasSelectedCell || hover > 0) {
106
110
  ctx.beginPath();
107
111
  ctx.rect(x + xOffset, y, c.width - xOffset, headerHeight);
@@ -227,6 +231,7 @@ function drawGroupHeaderInner(
227
231
  span: readonly [number, number],
228
232
  isSelected: boolean,
229
233
  isHovered: boolean,
234
+ hoverAmount: number,
230
235
  theme: FullTheme,
231
236
  groupTheme: FullTheme,
232
237
  group: GroupDetails,
@@ -243,7 +248,13 @@ function drawGroupHeaderInner(
243
248
 
244
249
  if (fillColor !== theme.bgHeader) {
245
250
  ctx.fillStyle = fillColor;
246
- ctx.fill();
251
+ if (hoverAmount > 0) {
252
+ ctx.globalAlpha = hoverAmount;
253
+ ctx.fillRect(x, y + 1, width, height - 1);
254
+ ctx.globalAlpha = 1;
255
+ } else {
256
+ ctx.fillRect(x, y, width, height);
257
+ }
247
258
  }
248
259
 
249
260
  ctx.fillStyle = groupTheme.textGroupHeader ?? groupTheme.textHeader;
@@ -335,6 +346,15 @@ function drawGroupLevel(
335
346
  const hPosY = hovered?.[1]?.[1];
336
347
  // hRow: -2 is group header, we use -2 - level for multi-level
337
348
  const targetRow = -2 - level;
349
+ const selectionRow = selection?.current?.cell[1];
350
+ const selectionLevel = selectionRow !== undefined && selectionRow <= -2 ? -2 - selectionRow : undefined;
351
+ const selectionSpan =
352
+ selection?.current === undefined || selectionLevel === undefined
353
+ ? undefined
354
+ : ([
355
+ selection.current.range.x,
356
+ selection.current.range.x + selection.current.range.width - 1,
357
+ ] as const);
338
358
 
339
359
  let finalX = 0;
340
360
  walkGroups(effectiveCols, width, translateX, groupHeaderHeight, level, (span, groupName, x, y, w, h) => {
@@ -356,13 +376,20 @@ function drawGroupLevel(
356
376
  const group = getGroupDetails(groupName);
357
377
  const groupTheme =
358
378
  group?.overrideTheme === undefined ? theme : mergeAndRealizeTheme(theme, group.overrideTheme);
359
- const isHovered = hRow === targetRow && hCol !== undefined && hCol >= span[0] && hCol <= span[1];
360
-
361
379
  // Check if all columns in this group span are selected
362
380
  let isSelected = false;
363
381
  if (selection !== undefined) {
364
- isSelected = selection.columns.hasAll([span[0], span[1] + 1]);
382
+ const selectionMatchesLevel = selectionRow !== undefined && targetRow <= selectionRow;
383
+ const spanInSelection =
384
+ selectionSpan !== undefined && span[0] >= selectionSpan[0] && span[1] <= selectionSpan[1];
385
+ isSelected =
386
+ selectionMatchesLevel && spanInSelection && selection.columns.hasAll([span[0], span[1] + 1]);
365
387
  }
388
+ const isHovered = hRow === targetRow && hCol !== undefined && hCol >= span[0] && hCol <= span[1];
389
+ const hoverAmount =
390
+ isSelected || !isHovered
391
+ ? 0
392
+ : (_hoverValues.find(s => s.item[0] === hCol && s.item[1] === targetRow)?.hoverAmount ?? 0);
366
393
 
367
394
  if (drawGroupHeaderCallback !== undefined) {
368
395
  drawGroupHeaderCallback(
@@ -372,7 +399,7 @@ function drawGroupLevel(
372
399
  level,
373
400
  span,
374
401
  theme: groupTheme,
375
- rect: { x, y: y + yOffset, width: w, height: h },
402
+ rect: { x: x + 0.5, y: y + yOffset, width: w, height: h },
376
403
  isSelected,
377
404
  isHovered,
378
405
  spriteManager,
@@ -391,6 +418,7 @@ function drawGroupLevel(
391
418
  span,
392
419
  isSelected,
393
420
  isHovered,
421
+ hoverAmount,
394
422
  theme,
395
423
  groupTheme,
396
424
  group,
@@ -411,6 +439,7 @@ function drawGroupLevel(
411
439
  span,
412
440
  isSelected,
413
441
  isHovered,
442
+ hoverAmount,
414
443
  theme,
415
444
  groupTheme,
416
445
  group,
@@ -50,13 +50,16 @@ function clipHeaderDamage(
50
50
  ? groupHeaderHeight
51
51
  : Array.from({ length: levels }, () => groupHeaderHeight);
52
52
 
53
+ let currentY = 0;
53
54
  for (let level = 0; level < levels; level++) {
55
+ const levelHeight = heights[level] ?? heights[0] ?? 0;
56
+ if (levelHeight <= 0) continue;
54
57
  const targetRow = -2 - level;
55
58
  walkGroups(
56
59
  effectiveColumns,
57
60
  width,
58
61
  translateX,
59
- heights[level] ?? heights[0] ?? 0,
62
+ levelHeight,
60
63
  level,
61
64
  (span, _group, x, y, w, h) => {
62
65
  const hasItemInSpan = damage.hasItemInRectangle({
@@ -66,10 +69,11 @@ function clipHeaderDamage(
66
69
  height: 1,
67
70
  });
68
71
  if (hasItemInSpan) {
69
- ctx.rect(x, y, w, h);
72
+ ctx.rect(x, y + currentY, w, h);
70
73
  }
71
74
  }
72
75
  );
76
+ currentY += levelHeight;
73
77
  }
74
78
 
75
79
  walkColumns(
@@ -394,12 +398,15 @@ export function drawGrid(arg: DrawGridArg, lastArg: DrawGridArg | undefined) {
394
398
  // handle damage updates by directly drawing to the target to avoid large blits
395
399
  if (damage !== undefined) {
396
400
  const viewRegionWidth = effectiveCols[effectiveCols.length - 1].sourceIndex + 1;
401
+ const groupHeaderLevels = enableGroups ? getGroupLevels(mappedColumns) : 0;
402
+ const headerRegionRowStart = -1 - groupHeaderLevels;
403
+ const headerRegionHeight = groupHeaderLevels + 1;
397
404
  const damageInView = damage.hasItemInRegion([
398
405
  {
399
406
  x: cellXOffset,
400
- y: -2,
407
+ y: headerRegionRowStart,
401
408
  width: viewRegionWidth,
402
- height: 2,
409
+ height: headerRegionHeight,
403
410
  },
404
411
  {
405
412
  x: cellXOffset,
@@ -415,9 +422,9 @@ export function drawGrid(arg: DrawGridArg, lastArg: DrawGridArg | undefined) {
415
422
  },
416
423
  {
417
424
  x: 0,
418
- y: -2,
425
+ y: headerRegionRowStart,
419
426
  width: freezeColumns,
420
- height: 2,
427
+ height: headerRegionHeight,
421
428
  },
422
429
  {
423
430
  x: cellXOffset,
@@ -966,10 +966,13 @@ describe("data-editor", () => {
966
966
  });
967
967
 
968
968
  expect(spy).toHaveBeenCalledTimes(1);
969
- expect(spy).toHaveBeenCalledWith({
970
- columns: CompactSelection.fromSingleSelection([0, 11]),
971
- rows: CompactSelection.empty(),
972
- });
969
+ expect(spy).toHaveBeenCalledWith(
970
+ expect.objectContaining({
971
+ columns: CompactSelection.fromSingleSelection([0, 11]),
972
+ rows: CompactSelection.empty(),
973
+ current: expect.objectContaining({ cell: [0, -2] }),
974
+ })
975
+ );
973
976
 
974
977
  spy.mockClear();
975
978
 
@@ -980,10 +983,13 @@ describe("data-editor", () => {
980
983
  });
981
984
 
982
985
  expect(spy).toHaveBeenCalled();
983
- expect(spy).toHaveBeenCalledWith({
984
- columns: CompactSelection.empty(),
985
- rows: CompactSelection.empty(),
986
- });
986
+ expect(spy).toHaveBeenCalledWith(
987
+ expect.objectContaining({
988
+ columns: CompactSelection.empty(),
989
+ rows: CompactSelection.empty(),
990
+ current: undefined,
991
+ })
992
+ );
987
993
 
988
994
  spy.mockClear();
989
995
 
@@ -994,11 +1000,13 @@ describe("data-editor", () => {
994
1000
  });
995
1001
 
996
1002
  expect(spy).toHaveBeenCalled();
997
- expect(spy).toHaveBeenCalledWith({
998
- rows: CompactSelection.empty(),
999
- current: undefined,
1000
- columns: CompactSelection.fromSingleSelection([0, 11]),
1001
- });
1003
+ expect(spy).toHaveBeenCalledWith(
1004
+ expect.objectContaining({
1005
+ rows: CompactSelection.empty(),
1006
+ columns: CompactSelection.fromSingleSelection([0, 11]),
1007
+ current: expect.objectContaining({ cell: [0, -2] }),
1008
+ })
1009
+ );
1002
1010
  });
1003
1011
 
1004
1012
  test("Rename group header shows", async () => {
@@ -305,9 +305,17 @@ describe("data-grid", () => {
305
305
 
306
306
  test("Header hovered when scrolled", () => {
307
307
  const spy = vi.fn();
308
+ const groupedColumns = basicProps.columns.map(col => ({ ...col, group: "A" }));
308
309
 
309
310
  render(
310
- <DataGrid {...basicProps} groupHeaderHeight={32} enableGroups={true} cellYOffset={10} onItemHovered={spy} />
311
+ <DataGrid
312
+ {...basicProps}
313
+ columns={groupedColumns}
314
+ groupHeaderHeight={32}
315
+ enableGroups={true}
316
+ cellYOffset={10}
317
+ onItemHovered={spy}
318
+ />
311
319
  );
312
320
 
313
321
  const el = screen.getByTestId(dataGridCanvasId);
@@ -327,7 +335,11 @@ describe("data-grid", () => {
327
335
  test("Group header hovered", () => {
328
336
  const spy = vi.fn();
329
337
 
330
- render(<DataGrid {...basicProps} onItemHovered={spy} enableGroups={true} groupHeaderHeight={28} />);
338
+ const groupedColumns = basicProps.columns.map(col => ({ ...col, group: "A" }));
339
+ // TODO old test
340
+ //render(<DataGrid {...basicProps} onItemHovered={spy} enableGroups={true} groupHeaderHeight={28} />);
341
+
342
+ render(<DataGrid {...basicProps} columns={groupedColumns} onItemHovered={spy} enableGroups={true} groupHeaderHeight={28} />);
331
343
 
332
344
  const el = screen.getByTestId(dataGridCanvasId);
333
345
  fireEvent.pointerMove(el, {