@toolbox-web/grid 0.4.1 → 0.4.2

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 (157) hide show
  1. package/README.md +10 -13
  2. package/all.js +1101 -1048
  3. package/all.js.map +1 -1
  4. package/index.js +245 -137
  5. package/index.js.map +1 -1
  6. package/lib/core/grid.d.ts +10 -0
  7. package/lib/core/grid.d.ts.map +1 -1
  8. package/lib/core/internal/config-manager.d.ts +1 -0
  9. package/lib/core/internal/config-manager.d.ts.map +1 -1
  10. package/lib/core/internal/keyboard.d.ts.map +1 -1
  11. package/lib/core/internal/utils.d.ts +1 -0
  12. package/lib/core/internal/utils.d.ts.map +1 -1
  13. package/lib/core/plugin/base-plugin.d.ts +57 -1
  14. package/lib/core/plugin/base-plugin.d.ts.map +1 -1
  15. package/lib/core/plugin/expander-column.d.ts +51 -0
  16. package/lib/core/plugin/expander-column.d.ts.map +1 -0
  17. package/lib/core/plugin/types.d.ts +117 -1
  18. package/lib/core/plugin/types.d.ts.map +1 -1
  19. package/lib/core/types.d.ts +4 -2
  20. package/lib/core/types.d.ts.map +1 -1
  21. package/lib/plugins/clipboard/ClipboardPlugin.d.ts +5 -4
  22. package/lib/plugins/clipboard/ClipboardPlugin.d.ts.map +1 -1
  23. package/lib/plugins/clipboard/index.d.ts +1 -1
  24. package/lib/plugins/clipboard/index.d.ts.map +1 -1
  25. package/lib/plugins/clipboard/index.js +282 -188
  26. package/lib/plugins/clipboard/index.js.map +1 -1
  27. package/lib/plugins/clipboard/types.d.ts +72 -2
  28. package/lib/plugins/clipboard/types.d.ts.map +1 -1
  29. package/lib/plugins/column-virtualization/ColumnVirtualizationPlugin.d.ts +0 -1
  30. package/lib/plugins/column-virtualization/ColumnVirtualizationPlugin.d.ts.map +1 -1
  31. package/lib/plugins/column-virtualization/index.js +102 -26
  32. package/lib/plugins/column-virtualization/index.js.map +1 -1
  33. package/lib/plugins/context-menu/ContextMenuPlugin.d.ts +0 -1
  34. package/lib/plugins/context-menu/ContextMenuPlugin.d.ts.map +1 -1
  35. package/lib/plugins/context-menu/index.js +154 -78
  36. package/lib/plugins/context-menu/index.js.map +1 -1
  37. package/lib/plugins/editing/EditingPlugin.d.ts +1 -7
  38. package/lib/plugins/editing/EditingPlugin.d.ts.map +1 -1
  39. package/lib/plugins/editing/index.js +200 -136
  40. package/lib/plugins/editing/index.js.map +1 -1
  41. package/lib/plugins/export/ExportPlugin.d.ts +0 -1
  42. package/lib/plugins/export/ExportPlugin.d.ts.map +1 -1
  43. package/lib/plugins/export/index.js +175 -99
  44. package/lib/plugins/export/index.js.map +1 -1
  45. package/lib/plugins/filtering/FilteringPlugin.d.ts +5 -2
  46. package/lib/plugins/filtering/FilteringPlugin.d.ts.map +1 -1
  47. package/lib/plugins/filtering/index.js +129 -43
  48. package/lib/plugins/filtering/index.js.map +1 -1
  49. package/lib/plugins/grouping-columns/GroupingColumnsPlugin.d.ts +1 -2
  50. package/lib/plugins/grouping-columns/GroupingColumnsPlugin.d.ts.map +1 -1
  51. package/lib/plugins/grouping-columns/grouping-columns.d.ts +1 -1
  52. package/lib/plugins/grouping-columns/grouping-columns.d.ts.map +1 -1
  53. package/lib/plugins/grouping-columns/index.js +144 -66
  54. package/lib/plugins/grouping-columns/index.js.map +1 -1
  55. package/lib/plugins/grouping-rows/GroupingRowsPlugin.d.ts +14 -2
  56. package/lib/plugins/grouping-rows/GroupingRowsPlugin.d.ts.map +1 -1
  57. package/lib/plugins/grouping-rows/index.js +230 -138
  58. package/lib/plugins/grouping-rows/index.js.map +1 -1
  59. package/lib/plugins/master-detail/MasterDetailPlugin.d.ts +13 -11
  60. package/lib/plugins/master-detail/MasterDetailPlugin.d.ts.map +1 -1
  61. package/lib/plugins/master-detail/index.js +265 -196
  62. package/lib/plugins/master-detail/index.js.map +1 -1
  63. package/lib/plugins/master-detail/types.d.ts +0 -10
  64. package/lib/plugins/master-detail/types.d.ts.map +1 -1
  65. package/lib/plugins/multi-sort/MultiSortPlugin.d.ts +1 -2
  66. package/lib/plugins/multi-sort/MultiSortPlugin.d.ts.map +1 -1
  67. package/lib/plugins/multi-sort/index.js +105 -31
  68. package/lib/plugins/multi-sort/index.js.map +1 -1
  69. package/lib/plugins/pinned-columns/PinnedColumnsPlugin.d.ts +0 -1
  70. package/lib/plugins/pinned-columns/PinnedColumnsPlugin.d.ts.map +1 -1
  71. package/lib/plugins/pinned-columns/index.js +128 -52
  72. package/lib/plugins/pinned-columns/index.js.map +1 -1
  73. package/lib/plugins/pinned-rows/PinnedRowsPlugin.d.ts +1 -2
  74. package/lib/plugins/pinned-rows/PinnedRowsPlugin.d.ts.map +1 -1
  75. package/lib/plugins/pinned-rows/index.js +162 -88
  76. package/lib/plugins/pinned-rows/index.js.map +1 -1
  77. package/lib/plugins/pivot/PivotPlugin.d.ts +26 -4
  78. package/lib/plugins/pivot/PivotPlugin.d.ts.map +1 -1
  79. package/lib/plugins/pivot/index.js +398 -310
  80. package/lib/plugins/pivot/index.js.map +1 -1
  81. package/lib/plugins/pivot/pivot-rows.d.ts +2 -1
  82. package/lib/plugins/pivot/pivot-rows.d.ts.map +1 -1
  83. package/lib/plugins/reorder/ReorderPlugin.d.ts +13 -10
  84. package/lib/plugins/reorder/ReorderPlugin.d.ts.map +1 -1
  85. package/lib/plugins/reorder/index.js +288 -226
  86. package/lib/plugins/reorder/index.js.map +1 -1
  87. package/lib/plugins/selection/SelectionPlugin.d.ts +21 -3
  88. package/lib/plugins/selection/SelectionPlugin.d.ts.map +1 -1
  89. package/lib/plugins/selection/index.d.ts +2 -2
  90. package/lib/plugins/selection/index.d.ts.map +1 -1
  91. package/lib/plugins/selection/index.js +276 -145
  92. package/lib/plugins/selection/index.js.map +1 -1
  93. package/lib/plugins/selection/types.d.ts +24 -0
  94. package/lib/plugins/selection/types.d.ts.map +1 -1
  95. package/lib/plugins/server-side/ServerSidePlugin.d.ts +0 -1
  96. package/lib/plugins/server-side/ServerSidePlugin.d.ts.map +1 -1
  97. package/lib/plugins/server-side/index.js +83 -7
  98. package/lib/plugins/server-side/index.js.map +1 -1
  99. package/lib/plugins/tree/TreePlugin.d.ts +5 -1
  100. package/lib/plugins/tree/TreePlugin.d.ts.map +1 -1
  101. package/lib/plugins/tree/index.js +197 -112
  102. package/lib/plugins/tree/index.js.map +1 -1
  103. package/lib/plugins/tree/types.d.ts +0 -10
  104. package/lib/plugins/tree/types.d.ts.map +1 -1
  105. package/lib/plugins/undo-redo/UndoRedoPlugin.d.ts +0 -1
  106. package/lib/plugins/undo-redo/UndoRedoPlugin.d.ts.map +1 -1
  107. package/lib/plugins/undo-redo/index.js +93 -17
  108. package/lib/plugins/undo-redo/index.js.map +1 -1
  109. package/lib/plugins/visibility/VisibilityPlugin.d.ts +7 -4
  110. package/lib/plugins/visibility/VisibilityPlugin.d.ts.map +1 -1
  111. package/lib/plugins/visibility/index.js +144 -65
  112. package/lib/plugins/visibility/index.js.map +1 -1
  113. package/package.json +1 -1
  114. package/umd/grid.all.umd.js +17 -19
  115. package/umd/grid.all.umd.js.map +1 -1
  116. package/umd/grid.umd.js +7 -7
  117. package/umd/grid.umd.js.map +1 -1
  118. package/umd/plugins/clipboard.umd.js +5 -7
  119. package/umd/plugins/clipboard.umd.js.map +1 -1
  120. package/umd/plugins/column-virtualization.umd.js +1 -1
  121. package/umd/plugins/column-virtualization.umd.js.map +1 -1
  122. package/umd/plugins/context-menu.umd.js +1 -1
  123. package/umd/plugins/context-menu.umd.js.map +1 -1
  124. package/umd/plugins/editing.umd.js +1 -1
  125. package/umd/plugins/editing.umd.js.map +1 -1
  126. package/umd/plugins/export.umd.js +1 -1
  127. package/umd/plugins/export.umd.js.map +1 -1
  128. package/umd/plugins/filtering.umd.js +1 -1
  129. package/umd/plugins/filtering.umd.js.map +1 -1
  130. package/umd/plugins/grouping-columns.umd.js +1 -1
  131. package/umd/plugins/grouping-columns.umd.js.map +1 -1
  132. package/umd/plugins/grouping-rows.umd.js +1 -1
  133. package/umd/plugins/grouping-rows.umd.js.map +1 -1
  134. package/umd/plugins/master-detail.umd.js +1 -1
  135. package/umd/plugins/master-detail.umd.js.map +1 -1
  136. package/umd/plugins/multi-sort.umd.js +1 -1
  137. package/umd/plugins/multi-sort.umd.js.map +1 -1
  138. package/umd/plugins/pinned-columns.umd.js +1 -1
  139. package/umd/plugins/pinned-columns.umd.js.map +1 -1
  140. package/umd/plugins/pinned-rows.umd.js +1 -1
  141. package/umd/plugins/pinned-rows.umd.js.map +1 -1
  142. package/umd/plugins/pivot.umd.js +1 -1
  143. package/umd/plugins/pivot.umd.js.map +1 -1
  144. package/umd/plugins/reorder.umd.js +1 -1
  145. package/umd/plugins/reorder.umd.js.map +1 -1
  146. package/umd/plugins/selection.umd.js +1 -1
  147. package/umd/plugins/selection.umd.js.map +1 -1
  148. package/umd/plugins/server-side.umd.js +1 -1
  149. package/umd/plugins/server-side.umd.js.map +1 -1
  150. package/umd/plugins/tree.umd.js +1 -1
  151. package/umd/plugins/tree.umd.js.map +1 -1
  152. package/umd/plugins/undo-redo.umd.js +1 -1
  153. package/umd/plugins/undo-redo.umd.js.map +1 -1
  154. package/umd/plugins/visibility.umd.js +1 -1
  155. package/umd/plugins/visibility.umd.js.map +1 -1
  156. package/lib/core/internal/editing.d.ts +0 -76
  157. package/lib/core/internal/editing.d.ts.map +0 -1
@@ -1,4 +1,4 @@
1
- const x = {
1
+ const R = {
2
2
  expand: "▶",
3
3
  collapse: "▼",
4
4
  sortAsc: "▲",
@@ -8,7 +8,7 @@ const x = {
8
8
  dragHandle: "⋮⋮",
9
9
  toolPanel: "☰"
10
10
  };
11
- class R {
11
+ class x {
12
12
  /**
13
13
  * Plugin dependencies - declare other plugins this one requires.
14
14
  *
@@ -25,8 +25,11 @@ class R {
25
25
  * ```
26
26
  */
27
27
  static dependencies;
28
- /** Plugin version - override in subclass if needed */
29
- version = "1.0.0";
28
+ /**
29
+ * Plugin version - defaults to grid version for built-in plugins.
30
+ * Third-party plugins can override with their own semver.
31
+ */
32
+ version = typeof __GRID_VERSION__ < "u" ? __GRID_VERSION__ : "dev";
30
33
  /** CSS styles to inject into the grid's shadow DOM */
31
34
  styles;
32
35
  /** Custom cell renderers keyed by type name */
@@ -113,12 +116,28 @@ class R {
113
116
  emit(e, t) {
114
117
  this.grid?.dispatchEvent?.(new CustomEvent(e, { detail: t, bubbles: !0 }));
115
118
  }
119
+ /**
120
+ * Emit a cancelable custom event from the grid.
121
+ * @returns `true` if the event was cancelled (preventDefault called), `false` otherwise
122
+ */
123
+ emitCancelable(e, t) {
124
+ const r = new CustomEvent(e, { detail: t, bubbles: !0, cancelable: !0 });
125
+ return this.grid?.dispatchEvent?.(r), r.defaultPrevented;
126
+ }
116
127
  /**
117
128
  * Request a re-render of the grid.
118
129
  */
119
130
  requestRender() {
120
131
  this.grid?.requestRender?.();
121
132
  }
133
+ /**
134
+ * Request a re-render and restore focus styling afterward.
135
+ * Use this when a plugin action (like expand/collapse) triggers a render
136
+ * but needs to maintain keyboard navigation focus.
137
+ */
138
+ requestRenderWithFocus() {
139
+ this.grid?.requestRenderWithFocus?.();
140
+ }
122
141
  /**
123
142
  * Request a lightweight style update without rebuilding DOM.
124
143
  * Use this instead of requestRender() when only CSS classes need updating.
@@ -152,6 +171,19 @@ class R {
152
171
  get visibleColumns() {
153
172
  return this.grid?._visibleColumns ?? [];
154
173
  }
174
+ /**
175
+ * Get the grid as an HTMLElement for direct DOM operations.
176
+ * Use sparingly - prefer the typed GridElementRef API when possible.
177
+ *
178
+ * @example
179
+ * ```ts
180
+ * const width = this.gridElement.clientWidth;
181
+ * this.gridElement.classList.add('my-plugin-active');
182
+ * ```
183
+ */
184
+ get gridElement() {
185
+ return this.grid;
186
+ }
155
187
  /**
156
188
  * Get the shadow root of the grid.
157
189
  */
@@ -184,8 +216,53 @@ class R {
184
216
  */
185
217
  get gridIcons() {
186
218
  const e = this.grid?.gridConfig?.icons ?? {};
187
- return { ...x, ...e };
219
+ return { ...R, ...e };
220
+ }
221
+ // #region Animation Helpers
222
+ /**
223
+ * Check if animations are enabled at the grid level.
224
+ * Respects gridConfig.animation.mode and the CSS variable set by the grid.
225
+ *
226
+ * Plugins should use this to skip animations when:
227
+ * - Animation mode is 'off' or `false`
228
+ * - User prefers reduced motion and mode is 'reduced-motion' (default)
229
+ *
230
+ * @example
231
+ * ```ts
232
+ * private get animationStyle(): 'slide' | 'fade' | false {
233
+ * if (!this.isAnimationEnabled) return false;
234
+ * return this.config.animation ?? 'slide';
235
+ * }
236
+ * ```
237
+ */
238
+ get isAnimationEnabled() {
239
+ const e = this.grid?.effectiveConfig?.animation?.mode ?? "reduced-motion";
240
+ if (e === !1 || e === "off") return !1;
241
+ if (e === !0 || e === "on") return !0;
242
+ const t = this.shadowRoot?.host;
243
+ return t ? getComputedStyle(t).getPropertyValue("--tbw-animation-enabled").trim() !== "0" : !0;
188
244
  }
245
+ /**
246
+ * Get the animation duration in milliseconds from CSS variable.
247
+ * Falls back to 200ms if not set.
248
+ *
249
+ * Plugins can use this for their animation timing to stay consistent
250
+ * with the grid-level animation.duration setting.
251
+ *
252
+ * @example
253
+ * ```ts
254
+ * element.animate(keyframes, { duration: this.animationDuration });
255
+ * ```
256
+ */
257
+ get animationDuration() {
258
+ const e = this.shadowRoot?.host;
259
+ if (e) {
260
+ const t = getComputedStyle(e).getPropertyValue("--tbw-animation-duration").trim(), r = parseInt(t, 10);
261
+ if (!isNaN(r)) return r;
262
+ }
263
+ return 200;
264
+ }
265
+ // #endregion
189
266
  /**
190
267
  * Resolve an icon value to string or HTMLElement.
191
268
  * Checks plugin config first, then grid-level icons, then defaults.
@@ -215,10 +292,14 @@ class R {
215
292
  }
216
293
  // #endregion
217
294
  }
295
+ const v = "__tbw_expander";
296
+ function C(n) {
297
+ return n.field === v;
298
+ }
218
299
  const m = {
219
- sum: (n, e) => n.reduce((t, i) => t + (Number(i[e]) || 0), 0),
300
+ sum: (n, e) => n.reduce((t, r) => t + (Number(r[e]) || 0), 0),
220
301
  avg: (n, e) => {
221
- const t = n.reduce((i, r) => i + (Number(r[e]) || 0), 0);
302
+ const t = n.reduce((r, o) => r + (Number(o[e]) || 0), 0);
222
303
  return n.length ? t / n.length : 0;
223
304
  },
224
305
  count: (n) => n.length,
@@ -226,104 +307,104 @@ const m = {
226
307
  max: (n, e) => Math.max(...n.map((t) => Number(t[e]) || -1 / 0)),
227
308
  first: (n, e) => n[0]?.[e],
228
309
  last: (n, e) => n[n.length - 1]?.[e]
229
- }, _ = /* @__PURE__ */ new Map(), f = {
310
+ }, w = /* @__PURE__ */ new Map(), c = {
230
311
  /**
231
312
  * Register a custom aggregator function.
232
313
  */
233
314
  register(n, e) {
234
- _.set(n, e);
315
+ w.set(n, e);
235
316
  },
236
317
  /**
237
318
  * Unregister a custom aggregator function.
238
319
  */
239
320
  unregister(n) {
240
- _.delete(n);
321
+ w.delete(n);
241
322
  },
242
323
  /**
243
324
  * Get an aggregator function by reference.
244
325
  */
245
326
  get(n) {
246
327
  if (n !== void 0)
247
- return typeof n == "function" ? n : _.get(n) ?? m[n];
328
+ return typeof n == "function" ? n : w.get(n) ?? m[n];
248
329
  },
249
330
  /**
250
331
  * Run an aggregator on a set of rows.
251
332
  */
252
- run(n, e, t, i) {
253
- const r = this.get(n);
254
- return r ? r(e, t, i) : void 0;
333
+ run(n, e, t, r) {
334
+ const o = this.get(n);
335
+ return o ? o(e, t, r) : void 0;
255
336
  },
256
337
  /**
257
338
  * Check if an aggregator exists.
258
339
  */
259
340
  has(n) {
260
- return _.has(n) || n in m;
341
+ return w.has(n) || n in m;
261
342
  },
262
343
  /**
263
344
  * List all available aggregator names.
264
345
  */
265
346
  list() {
266
- return [...Object.keys(m), ..._.keys()];
347
+ return [...Object.keys(m), ...w.keys()];
267
348
  }
268
349
  };
269
- f.register.bind(f);
270
- f.unregister.bind(f);
271
- f.get.bind(f);
272
- const w = f.run.bind(f);
273
- f.list.bind(f);
274
- function v({ rows: n, config: e, expanded: t }) {
275
- const i = e.groupOn;
276
- if (typeof i != "function")
350
+ c.register.bind(c);
351
+ c.unregister.bind(c);
352
+ c.get.bind(c);
353
+ const y = c.run.bind(c);
354
+ c.list.bind(c);
355
+ function A({ rows: n, config: e, expanded: t }) {
356
+ const r = e.groupOn;
357
+ if (typeof r != "function")
277
358
  return [];
278
- const r = { key: "__root__", value: null, depth: -1, rows: [], children: /* @__PURE__ */ new Map() };
279
- if (n.forEach((s) => {
280
- let d = i(s);
281
- d == null || d === !1 ? d = ["__ungrouped__"] : Array.isArray(d) || (d = [d]);
282
- let a = r;
283
- d.forEach((c, b) => {
284
- const l = c == null ? "∅" : String(c), g = a.key === "__root__" ? l : a.key + "||" + l;
285
- let p = a.children.get(l);
286
- p || (p = { key: g, value: c, depth: b, rows: [], children: /* @__PURE__ */ new Map(), parent: a }, a.children.set(l, p)), a = p;
287
- }), a.rows.push(s);
288
- }), r.children.size === 1 && r.children.has("__ungrouped__") && r.children.get("__ungrouped__").rows.length === n.length)
359
+ const o = { key: "__root__", value: null, depth: -1, rows: [], children: /* @__PURE__ */ new Map() };
360
+ if (n.forEach((i) => {
361
+ let a = r(i);
362
+ a == null || a === !1 ? a = ["__ungrouped__"] : Array.isArray(a) || (a = [a]);
363
+ let d = o;
364
+ a.forEach((h, p) => {
365
+ const f = h == null ? "∅" : String(h), l = d.key === "__root__" ? f : d.key + "||" + f;
366
+ let g = d.children.get(f);
367
+ g || (g = { key: l, value: h, depth: p, rows: [], children: /* @__PURE__ */ new Map(), parent: d }, d.children.set(f, g)), d = g;
368
+ }), d.rows.push(i);
369
+ }), o.children.size === 1 && o.children.has("__ungrouped__") && o.children.get("__ungrouped__").rows.length === n.length)
289
370
  return [];
290
- const o = [], u = (s) => {
291
- if (s === r) {
292
- s.children.forEach((a) => u(a));
371
+ const s = [], u = (i) => {
372
+ if (i === o) {
373
+ i.children.forEach((d) => u(d));
293
374
  return;
294
375
  }
295
- const d = t.has(s.key);
296
- o.push({
376
+ const a = t.has(i.key);
377
+ s.push({
297
378
  kind: "group",
298
- key: s.key,
299
- value: s.value,
300
- depth: s.depth,
301
- rows: s.rows,
302
- expanded: d
303
- }), d && (s.children.size ? s.children.forEach((a) => u(a)) : s.rows.forEach((a) => o.push({ kind: "data", row: a, rowIndex: n.indexOf(a) })));
379
+ key: i.key,
380
+ value: i.value,
381
+ depth: i.depth,
382
+ rows: i.rows,
383
+ expanded: a
384
+ }), a && (i.children.size ? i.children.forEach((d) => u(d)) : i.rows.forEach((d) => s.push({ kind: "data", row: d, rowIndex: n.indexOf(d) })));
304
385
  };
305
- return u(r), o;
386
+ return u(o), s;
306
387
  }
307
- function C(n, e) {
388
+ function k(n, e) {
308
389
  const t = new Set(n);
309
390
  return t.has(e) ? t.delete(e) : t.add(e), t;
310
391
  }
311
- function A(n) {
392
+ function K(n) {
312
393
  const e = /* @__PURE__ */ new Set();
313
394
  for (const t of n)
314
395
  t.kind === "group" && e.add(t.key);
315
396
  return e;
316
397
  }
317
- function k() {
398
+ function S() {
318
399
  return /* @__PURE__ */ new Set();
319
400
  }
320
- function K(n) {
401
+ function E(n) {
321
402
  return n.kind !== "group" ? 0 : n.rows.length;
322
403
  }
323
- const S = '.group-row{display:grid;grid-template-columns:var(--tbw-column-template);background:var(--tbw-grouping-rows-bg, var(--tbw-color-panel-bg));font-weight:500;border-bottom:var(--tbw-row-divider);min-height:var(--tbw-row-height)}.group-row .cell{display:flex;align-items:center;padding:var(--tbw-cell-padding, 2px 8px)}.group-row:hover{background:var(--tbw-grouping-rows-bg-hover, var(--tbw-color-row-hover))}.group-toggle{cursor:pointer;-webkit-user-select:none;user-select:none;display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;margin-right:4px;background:none;border:0;font:inherit}.group-toggle:hover{background:var(--tbw-grouping-rows-toggle-hover, var(--tbw-color-row-hover));border-radius:2px}.group-label{display:inline-flex;align-items:center;gap:8px}.group-count{color:var(--tbw-grouping-rows-count-color, var(--tbw-color-fg-muted));font-size:.85em;font-weight:400}[data-group-depth="0"] .group-label{padding-left:0}[data-group-depth="1"] .group-label{padding-left:20px}[data-group-depth="2"] .group-label{padding-left:40px}[data-group-depth="3"] .group-label{padding-left:60px}[data-group-depth="4"] .group-label{padding-left:80px}.data-grid-row.tbw-group-slide-in{animation:tbw-group-slide-in var(--tbw-animation-duration, .2s) var(--tbw-animation-easing, ease-out) forwards}@keyframes tbw-group-slide-in{0%{opacity:0;transform:translate(-8px)}to{opacity:1;transform:translate(0)}}.data-grid-row.tbw-group-fade-in{animation:tbw-group-fade-in var(--tbw-animation-duration, .2s) var(--tbw-animation-easing, ease-out) forwards}@keyframes tbw-group-fade-in{0%{opacity:0}to{opacity:1}}';
324
- class E extends R {
404
+ const G = '.group-row{display:grid;grid-template-columns:var(--tbw-column-template);background:var(--tbw-grouping-rows-bg, var(--tbw-color-panel-bg));font-weight:500;border-bottom:var(--tbw-row-divider);min-height:var(--tbw-row-height)}.group-row .cell{display:flex;align-items:center;padding:var(--tbw-cell-padding, 2px 8px)}.group-row:hover{background:var(--tbw-grouping-rows-bg-hover, var(--tbw-color-row-hover))}.group-toggle{cursor:pointer;-webkit-user-select:none;user-select:none;display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;margin-right:4px;background:none;border:0;font:inherit}.group-toggle:hover{background:var(--tbw-grouping-rows-toggle-hover, var(--tbw-color-row-hover));border-radius:2px}.group-label{display:inline-flex;align-items:center;gap:8px}.group-count{color:var(--tbw-grouping-rows-count-color, var(--tbw-color-fg-muted));font-size:.85em;font-weight:400}[data-group-depth="0"] .group-label{padding-left:0}[data-group-depth="1"] .group-label{padding-left:20px}[data-group-depth="2"] .group-label{padding-left:40px}[data-group-depth="3"] .group-label{padding-left:60px}[data-group-depth="4"] .group-label{padding-left:80px}.data-grid-row.tbw-group-slide-in{animation:tbw-group-slide-in var(--tbw-animation-duration, .2s) var(--tbw-animation-easing, ease-out) forwards}@keyframes tbw-group-slide-in{0%{opacity:0;transform:translate(-8px)}to{opacity:1;transform:translate(0)}}.data-grid-row.tbw-group-fade-in{animation:tbw-group-fade-in var(--tbw-animation-duration, .2s) var(--tbw-animation-easing, ease-out) forwards}@keyframes tbw-group-fade-in{0%{opacity:0}to{opacity:1}}';
405
+ class T extends x {
325
406
  name = "groupingRows";
326
- version = "1.0.0";
407
+ styles = G;
327
408
  get defaultConfig() {
328
409
  return {
329
410
  defaultExpanded: !1,
@@ -341,15 +422,12 @@ class E extends R {
341
422
  keysToAnimate = /* @__PURE__ */ new Set();
342
423
  // #endregion
343
424
  // #region Animation
425
+ /**
426
+ * Get expand/collapse animation style from plugin config.
427
+ * Uses base class isAnimationEnabled to respect grid-level settings.
428
+ */
344
429
  get animationStyle() {
345
- const t = this.grid.effectiveConfig?.animation?.mode ?? "reduced-motion";
346
- if (t === !1 || t === "off") return !1;
347
- if (t !== !0 && t !== "on") {
348
- const i = this.shadowRoot?.host;
349
- if (i && getComputedStyle(i).getPropertyValue("--tbw-animation-enabled").trim() === "0")
350
- return !1;
351
- }
352
- return this.config.animation ?? "slide";
430
+ return this.isAnimationEnabled ? this.config.animation ?? "slide" : !1;
353
431
  }
354
432
  // #endregion
355
433
  // #region Lifecycle
@@ -369,119 +447,136 @@ class E extends R {
369
447
  const t = this.config;
370
448
  if (typeof t.groupOn != "function")
371
449
  return this.isActive = !1, this.flattenedRows = [], [...e];
372
- const i = v({
450
+ const r = A({
373
451
  rows: [...e],
374
452
  config: t,
375
453
  expanded: this.expandedKeys
376
454
  });
377
- if (i.length === 0)
455
+ if (r.length === 0)
378
456
  return this.isActive = !1, this.flattenedRows = [], [...e];
379
- this.isActive = !0, this.flattenedRows = i, this.keysToAnimate.clear();
380
- const r = /* @__PURE__ */ new Set();
381
- return i.forEach((o, u) => {
382
- if (o.kind === "data") {
383
- const s = `data-${u}`;
384
- r.add(s), this.previousVisibleKeys.has(s) || this.keysToAnimate.add(s);
457
+ this.isActive = !0, this.flattenedRows = r, this.keysToAnimate.clear();
458
+ const o = /* @__PURE__ */ new Set();
459
+ return r.forEach((s, u) => {
460
+ if (s.kind === "data") {
461
+ const i = `data-${u}`;
462
+ o.add(i), this.previousVisibleKeys.has(i) || this.keysToAnimate.add(i);
385
463
  }
386
- }), this.previousVisibleKeys = r, i.map((o) => o.kind === "group" ? {
464
+ }), this.previousVisibleKeys = o, r.map((s) => s.kind === "group" ? {
387
465
  __isGroupRow: !0,
388
- __groupKey: o.key,
389
- __groupValue: o.value,
390
- __groupDepth: o.depth,
391
- __groupRows: o.rows,
392
- __groupExpanded: o.expanded,
393
- __groupRowCount: K(o)
394
- } : o.row);
466
+ __groupKey: s.key,
467
+ __groupValue: s.value,
468
+ __groupDepth: s.depth,
469
+ __groupRows: s.rows,
470
+ __groupExpanded: s.expanded,
471
+ __groupRowCount: E(s)
472
+ } : s.row);
395
473
  }
396
474
  onCellClick(e) {
397
475
  const t = e.row;
398
476
  if (t?.__isGroupRow && e.originalEvent.target?.closest(".group-toggle"))
399
477
  return this.toggle(t.__groupKey), !0;
400
478
  }
479
+ onKeyDown(e) {
480
+ if (e.key !== " ") return;
481
+ const t = this.grid._focusRow, r = this.rows[t];
482
+ if (r?.__isGroupRow)
483
+ return e.preventDefault(), this.toggle(r.__groupKey), this.requestRenderWithFocus(), !0;
484
+ }
401
485
  /**
402
486
  * Render a row. Returns true if we handled the row (group row), false otherwise.
403
487
  */
404
- renderRow(e, t, i) {
488
+ renderRow(e, t, r) {
405
489
  if (!e?.__isGroupRow)
406
490
  return !1;
407
- const r = this.config;
408
- if (r.groupRowRenderer) {
409
- const s = () => {
491
+ const o = this.config;
492
+ if (o.groupRowRenderer) {
493
+ const i = () => {
410
494
  this.toggle(e.__groupKey);
411
- }, d = r.groupRowRenderer({
495
+ }, a = o.groupRowRenderer({
412
496
  key: e.__groupKey,
413
497
  value: e.__groupValue,
414
498
  depth: e.__groupDepth,
415
499
  rows: e.__groupRows,
416
500
  expanded: e.__groupExpanded,
417
- toggleExpand: s
501
+ toggleExpand: i
418
502
  });
419
- if (d)
420
- return t.className = "group-row", t.__isCustomRow = !0, t.setAttribute("data-group-depth", String(e.__groupDepth)), typeof d == "string" ? t.innerHTML = d : (t.innerHTML = "", t.appendChild(d)), !0;
503
+ if (a)
504
+ return t.className = "data-grid-row group-row", t.__isCustomRow = !0, t.setAttribute("data-group-depth", String(e.__groupDepth)), typeof a == "string" ? t.innerHTML = a : (t.innerHTML = "", t.appendChild(a)), !0;
421
505
  }
422
- const o = () => {
506
+ const s = () => {
423
507
  this.toggle(e.__groupKey);
424
508
  };
425
- return t.className = "group-row", t.__isCustomRow = !0, t.setAttribute("data-group-depth", String(e.__groupDepth)), t.setAttribute("role", "row"), t.setAttribute("aria-expanded", String(e.__groupExpanded)), t.style.paddingLeft = `${(e.__groupDepth || 0) * (r.indentWidth ?? 20)}px`, t.innerHTML = "", r.fullWidth !== !1 ? this.renderFullWidthGroupRow(e, t, o) : this.renderPerColumnGroupRow(e, t, o), !0;
509
+ return t.className = "data-grid-row group-row", t.__isCustomRow = !0, t.setAttribute("data-group-depth", String(e.__groupDepth)), t.setAttribute("role", "row"), t.setAttribute("aria-expanded", String(e.__groupExpanded)), t.style.paddingLeft = `${(e.__groupDepth || 0) * (o.indentWidth ?? 20)}px`, t.innerHTML = "", o.fullWidth !== !1 ? this.renderFullWidthGroupRow(e, t, s) : this.renderPerColumnGroupRow(e, t, s), !0;
426
510
  }
427
511
  afterRender() {
428
512
  const e = this.animationStyle;
429
513
  if (e === !1 || this.keysToAnimate.size === 0) return;
430
514
  const t = this.shadowRoot?.querySelector(".rows");
431
515
  if (!t) return;
432
- const i = e === "fade" ? "tbw-group-fade-in" : "tbw-group-slide-in";
433
- for (const r of t.querySelectorAll(".data-grid-row:not(.group-row)")) {
434
- const o = r.querySelector(".cell[data-row]"), u = o ? parseInt(o.getAttribute("data-row") ?? "-1", 10) : -1, d = this.flattenedRows[u]?.kind === "data" ? `data-${u}` : void 0;
435
- d && this.keysToAnimate.has(d) && (r.classList.add(i), r.addEventListener("animationend", () => r.classList.remove(i), { once: !0 }));
516
+ const r = e === "fade" ? "tbw-group-fade-in" : "tbw-group-slide-in";
517
+ for (const o of t.querySelectorAll(".data-grid-row:not(.group-row)")) {
518
+ const s = o.querySelector(".cell[data-row]"), u = s ? parseInt(s.getAttribute("data-row") ?? "-1", 10) : -1, a = this.flattenedRows[u]?.kind === "data" ? `data-${u}` : void 0;
519
+ a && this.keysToAnimate.has(a) && (o.classList.add(r), o.addEventListener("animationend", () => o.classList.remove(r), { once: !0 }));
436
520
  }
437
521
  this.keysToAnimate.clear();
438
522
  }
439
523
  // #endregion
440
524
  // #region Private Rendering Helpers
441
- renderFullWidthGroupRow(e, t, i) {
442
- const r = this.config, o = document.createElement("div");
443
- o.className = "cell group-full", o.style.gridColumn = "1 / -1", o.setAttribute("role", "gridcell");
444
- const u = document.createElement("button");
445
- u.type = "button", u.className = `group-toggle${e.__groupExpanded ? " expanded" : ""}`, u.setAttribute("aria-label", e.__groupExpanded ? "Collapse group" : "Expand group"), this.setIcon(u, this.resolveIcon(e.__groupExpanded ? "collapse" : "expand")), u.addEventListener("click", (a) => {
446
- a.stopPropagation(), i();
447
- }), o.appendChild(u);
448
- const s = document.createElement("span");
449
- s.className = "group-label";
450
- const d = r.formatLabel ? r.formatLabel(e.__groupValue, e.__groupDepth || 0, e.__groupKey) : String(e.__groupValue);
451
- if (s.textContent = d, o.appendChild(s), r.showRowCount !== !1) {
452
- const a = document.createElement("span");
453
- a.className = "group-count", a.textContent = `(${e.__groupRowCount ?? e.__groupRows?.length ?? 0})`, o.appendChild(a);
525
+ /**
526
+ * Create a toggle button for expanding/collapsing a group.
527
+ */
528
+ createToggleButton(e, t) {
529
+ const r = document.createElement("button");
530
+ return r.type = "button", r.className = `group-toggle${e ? " expanded" : ""}`, r.setAttribute("aria-label", e ? "Collapse group" : "Expand group"), this.setIcon(r, this.resolveIcon(e ? "collapse" : "expand")), r.addEventListener("click", (o) => {
531
+ o.stopPropagation(), t();
532
+ }), r;
533
+ }
534
+ /**
535
+ * Get the formatted label text for a group.
536
+ */
537
+ getGroupLabelText(e, t, r) {
538
+ const o = this.config;
539
+ return o.formatLabel ? o.formatLabel(e, t, r) : String(e);
540
+ }
541
+ renderFullWidthGroupRow(e, t, r) {
542
+ const o = this.config, s = document.createElement("div");
543
+ s.className = "cell group-full", s.style.gridColumn = "1 / -1", s.setAttribute("role", "gridcell"), s.setAttribute("data-col", "0"), s.appendChild(this.createToggleButton(e.__groupExpanded, r));
544
+ const u = document.createElement("span");
545
+ if (u.className = "group-label", u.textContent = this.getGroupLabelText(e.__groupValue, e.__groupDepth || 0, e.__groupKey), s.appendChild(u), o.showRowCount !== !1) {
546
+ const i = document.createElement("span");
547
+ i.className = "group-count", i.textContent = `(${e.__groupRowCount ?? e.__groupRows?.length ?? 0})`, s.appendChild(i);
454
548
  }
455
- t.appendChild(o);
549
+ t.appendChild(s);
456
550
  }
457
- renderPerColumnGroupRow(e, t, i) {
458
- const r = this.config, o = r.aggregators ?? {}, u = this.columns, s = e.__groupRows ?? [], a = this.shadowRoot?.querySelector(".body")?.style.gridTemplateColumns || "";
459
- a && (t.style.display = "grid", t.style.gridTemplateColumns = a), u.forEach((c, b) => {
551
+ renderPerColumnGroupRow(e, t, r) {
552
+ const o = this.config, s = o.aggregators ?? {}, u = this.columns, i = e.__groupRows ?? [], d = this.shadowRoot?.querySelector(".body")?.style.gridTemplateColumns || "";
553
+ d && (t.style.display = "grid", t.style.gridTemplateColumns = d);
554
+ let h = !1;
555
+ u.forEach((p, f) => {
460
556
  const l = document.createElement("div");
461
- if (l.className = "cell group-cell", l.setAttribute("data-col", String(b)), l.setAttribute("role", "gridcell"), b === 0) {
462
- const g = document.createElement("button");
463
- g.type = "button", g.className = `group-toggle${e.__groupExpanded ? " expanded" : ""}`, g.setAttribute("aria-label", e.__groupExpanded ? "Collapse group" : "Expand group"), this.setIcon(g, this.resolveIcon(e.__groupExpanded ? "collapse" : "expand")), g.addEventListener("click", (h) => {
464
- h.stopPropagation(), i();
465
- }), l.appendChild(g);
466
- const p = document.createElement("span"), y = o[c.field];
467
- if (y) {
468
- const h = w(y, s, c.field, c);
469
- p.textContent = h != null ? String(h) : String(e.__groupValue);
470
- } else {
471
- const h = r.formatLabel ? r.formatLabel(e.__groupValue, e.__groupDepth || 0, e.__groupKey) : String(e.__groupValue);
472
- p.textContent = h;
473
- }
474
- if (l.appendChild(p), r.showRowCount !== !1) {
475
- const h = document.createElement("span");
476
- h.className = "group-count", h.textContent = ` (${s.length})`, l.appendChild(h);
477
- }
478
- } else {
479
- const g = o[c.field];
557
+ if (l.className = "cell group-cell", l.setAttribute("data-col", String(f)), l.setAttribute("role", "gridcell"), C(p)) {
558
+ l.setAttribute("data-field", p.field), t.appendChild(l);
559
+ return;
560
+ }
561
+ if (h) {
562
+ const g = s[p.field];
480
563
  if (g) {
481
- const p = w(g, s, c.field, c);
482
- l.textContent = p != null ? String(p) : "";
564
+ const b = y(g, i, p.field, p);
565
+ l.textContent = b != null ? String(b) : "";
483
566
  } else
484
567
  l.textContent = "";
568
+ } else {
569
+ h = !0, l.appendChild(this.createToggleButton(e.__groupExpanded, r));
570
+ const g = document.createElement("span"), b = s[p.field];
571
+ if (b) {
572
+ const _ = y(b, i, p.field, p);
573
+ g.textContent = _ != null ? String(_) : String(e.__groupValue);
574
+ } else
575
+ g.textContent = this.getGroupLabelText(e.__groupValue, e.__groupDepth || 0, e.__groupKey);
576
+ if (l.appendChild(g), o.showRowCount !== !1) {
577
+ const _ = document.createElement("span");
578
+ _.className = "group-count", _.textContent = ` (${i.length})`, l.appendChild(_);
579
+ }
485
580
  }
486
581
  t.appendChild(l);
487
582
  });
@@ -492,21 +587,21 @@ class E extends R {
492
587
  * Expand all groups.
493
588
  */
494
589
  expandAll() {
495
- this.expandedKeys = A(this.flattenedRows), this.requestRender();
590
+ this.expandedKeys = K(this.flattenedRows), this.requestRender();
496
591
  }
497
592
  /**
498
593
  * Collapse all groups.
499
594
  */
500
595
  collapseAll() {
501
- this.expandedKeys = k(), this.requestRender();
596
+ this.expandedKeys = S(), this.requestRender();
502
597
  }
503
598
  /**
504
599
  * Toggle expansion of a specific group.
505
600
  * @param key - The group key to toggle
506
601
  */
507
602
  toggle(e) {
508
- this.expandedKeys = C(this.expandedKeys, e);
509
- const t = this.flattenedRows.find((i) => i.kind === "group" && i.key === e);
603
+ this.expandedKeys = k(this.expandedKeys, e);
604
+ const t = this.flattenedRows.find((r) => r.kind === "group" && r.key === e);
510
605
  this.emit("group-toggle", {
511
606
  key: e,
512
607
  expanded: this.expandedKeys.has(e),
@@ -595,11 +690,8 @@ class E extends R {
595
690
  this.config.groupOn = e, this.requestRender();
596
691
  }
597
692
  // #endregion
598
- // #region Styles
599
- styles = S;
600
- // #endregion
601
693
  }
602
694
  export {
603
- E as GroupingRowsPlugin
695
+ T as GroupingRowsPlugin
604
696
  };
605
697
  //# sourceMappingURL=index.js.map