@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 m = /{{\s*([^}]+)\s*}}/g, f = "__DG_EMPTY__", R = /^[\w$. '?+\-*/%:()!<>=,&|]+$/, x = /__(proto|defineGetter|defineSetter)|constructor|window|globalThis|global|process|Function|import|eval|Reflect|Proxy|Error|arguments|document|location|cookie|localStorage|sessionStorage|indexedDB|fetch|XMLHttpRequest|WebSocket|Worker|SharedWorker|ServiceWorker|opener|parent|top|frames|self|this\b/, b = /* @__PURE__ */ new Set([
1
+ const R = /{{\s*([^}]+)\s*}}/g, u = "__DG_EMPTY__", b = /^[\w$. '?+\-*/%:()!<>=,&|]+$/, E = /__(proto|defineGetter|defineSetter)|constructor|window|globalThis|global|process|Function|import|eval|Reflect|Proxy|Error|arguments|document|location|cookie|localStorage|sessionStorage|indexedDB|fetch|XMLHttpRequest|WebSocket|Worker|SharedWorker|ServiceWorker|opener|parent|top|frames|self|this\b/, v = /* @__PURE__ */ new Set([
2
2
  "script",
3
3
  "iframe",
4
4
  "object",
@@ -23,76 +23,76 @@ const m = /{{\s*([^}]+)\s*}}/g, f = "__DG_EMPTY__", R = /^[\w$. '?+\-*/%:()!<>=,
23
23
  "plaintext",
24
24
  "xmp",
25
25
  "listing"
26
- ]), w = /^on\w+$/i, E = /* @__PURE__ */ new Set(["href", "src", "action", "formaction", "data", "srcdoc", "xlink:href", "poster", "srcset"]), v = /^\s*(javascript|vbscript|data|blob):/i;
27
- function y(i) {
28
- if (!i || typeof i != "string") return "";
29
- if (i.indexOf("<") === -1) return i;
26
+ ]), h = /^on\w+$/i, y = /* @__PURE__ */ new Set(["href", "src", "action", "formaction", "data", "srcdoc", "xlink:href", "poster", "srcset"]), C = /^\s*(javascript|vbscript|data|blob):/i;
27
+ function _(n) {
28
+ if (!n || typeof n != "string") return "";
29
+ if (n.indexOf("<") === -1) return n;
30
30
  const e = document.createElement("template");
31
- return e.innerHTML = i, C(e.content), e.innerHTML;
31
+ return e.innerHTML = n, A(e.content), e.innerHTML;
32
32
  }
33
- function C(i) {
34
- const e = [], t = i.querySelectorAll("*");
35
- for (const n of t) {
36
- const s = n.tagName.toLowerCase();
37
- if (b.has(s)) {
38
- e.push(n);
33
+ function A(n) {
34
+ const e = [], t = n.querySelectorAll("*");
35
+ for (const i of t) {
36
+ const r = i.tagName.toLowerCase();
37
+ if (v.has(r)) {
38
+ e.push(i);
39
39
  continue;
40
40
  }
41
- if ((s === "svg" || n.namespaceURI === "http://www.w3.org/2000/svg") && Array.from(n.attributes).some(
42
- (o) => w.test(o.name) || o.name === "href" || o.name === "xlink:href"
41
+ if ((r === "svg" || i.namespaceURI === "http://www.w3.org/2000/svg") && Array.from(i.attributes).some(
42
+ (s) => h.test(s.name) || s.name === "href" || s.name === "xlink:href"
43
43
  )) {
44
- e.push(n);
44
+ e.push(i);
45
45
  continue;
46
46
  }
47
- const a = [];
48
- for (const r of n.attributes) {
49
- const o = r.name.toLowerCase();
50
- if (w.test(o)) {
51
- a.push(r.name);
47
+ const l = [];
48
+ for (const o of i.attributes) {
49
+ const s = o.name.toLowerCase();
50
+ if (h.test(s)) {
51
+ l.push(o.name);
52
52
  continue;
53
53
  }
54
- if (E.has(o) && v.test(r.value)) {
55
- a.push(r.name);
54
+ if (y.has(s) && C.test(o.value)) {
55
+ l.push(o.name);
56
56
  continue;
57
57
  }
58
- if (o === "style" && /expression\s*\(|javascript:|behavior\s*:/i.test(r.value)) {
59
- a.push(r.name);
58
+ if (s === "style" && /expression\s*\(|javascript:|behavior\s*:/i.test(o.value)) {
59
+ l.push(o.name);
60
60
  continue;
61
61
  }
62
62
  }
63
- a.forEach((r) => n.removeAttribute(r));
63
+ l.forEach((o) => i.removeAttribute(o));
64
64
  }
65
- e.forEach((n) => n.remove());
65
+ e.forEach((i) => i.remove());
66
66
  }
67
- function S(i, e) {
68
- if (!i || i.indexOf("{{") === -1) return i;
69
- const t = [], n = i.replace(m, (o, l) => {
70
- const d = A(l, e);
71
- return t.push({ expr: l.trim(), result: d }), d;
72
- }), s = D(n), a = t.length && t.every((o) => o.result === "" || o.result === f);
73
- return /Reflect\.|\bProxy\b|ownKeys\(/.test(i) || a ? "" : s;
67
+ function D(n, e) {
68
+ if (!n || n.indexOf("{{") === -1) return n;
69
+ const t = [], i = n.replace(R, (s, a) => {
70
+ const d = S(a, e);
71
+ return t.push({ expr: a.trim(), result: d }), d;
72
+ }), r = L(i), l = t.length && t.every((s) => s.result === "" || s.result === u);
73
+ return /Reflect\.|\bProxy\b|ownKeys\(/.test(n) || l ? "" : r;
74
74
  }
75
- function A(i, e) {
76
- if (i = (i || "").trim(), !i || /\b(Reflect|Proxy|ownKeys)\b/.test(i)) return f;
77
- if (i === "value") return e.value == null ? f : String(e.value);
78
- if (i.startsWith("row.") && !/[()?]/.test(i) && !i.includes(":")) {
79
- const n = i.slice(4), s = e.row ? e.row[n] : void 0;
80
- return s == null ? f : String(s);
81
- }
82
- if (i.length > 80 || !R.test(i) || x.test(i)) return f;
83
- const t = i.match(/\./g);
84
- if (t && t.length > 1) return f;
75
+ function S(n, e) {
76
+ if (n = (n || "").trim(), !n || /\b(Reflect|Proxy|ownKeys)\b/.test(n)) return u;
77
+ if (n === "value") return e.value == null ? u : String(e.value);
78
+ if (n.startsWith("row.") && !/[()?]/.test(n) && !n.includes(":")) {
79
+ const i = n.slice(4), r = e.row ? e.row[i] : void 0;
80
+ return r == null ? u : String(r);
81
+ }
82
+ if (n.length > 80 || !b.test(n) || E.test(n)) return u;
83
+ const t = n.match(/\./g);
84
+ if (t && t.length > 1) return u;
85
85
  try {
86
- const s = new Function("value", "row", `return (${i});`)(e.value, e.row), a = s == null ? "" : String(s);
87
- return /Reflect|Proxy|ownKeys/.test(a) ? f : a || f;
86
+ const r = new Function("value", "row", `return (${n});`)(e.value, e.row), l = r == null ? "" : String(r);
87
+ return /Reflect|Proxy|ownKeys/.test(l) ? u : l || u;
88
88
  } catch {
89
- return f;
89
+ return u;
90
90
  }
91
91
  }
92
- function D(i) {
93
- return i && i.replace(new RegExp(f, "g"), "").replace(/Reflect\.[^<>{}\s]+/g, "").replace(/\bProxy\b/g, "").replace(/ownKeys\([^)]*\)/g, "");
92
+ function L(n) {
93
+ return n && n.replace(new RegExp(u, "g"), "").replace(/Reflect\.[^<>{}\s]+/g, "").replace(/\bProxy\b/g, "").replace(/ownKeys\([^)]*\)/g, "");
94
94
  }
95
- const H = {
95
+ const I = {
96
96
  expand: "▶",
97
97
  collapse: "▼",
98
98
  sortAsc: "▲",
@@ -102,7 +102,7 @@ const H = {
102
102
  dragHandle: "⋮⋮",
103
103
  toolPanel: "☰"
104
104
  };
105
- class _ {
105
+ class T {
106
106
  /**
107
107
  * Plugin dependencies - declare other plugins this one requires.
108
108
  *
@@ -119,8 +119,11 @@ class _ {
119
119
  * ```
120
120
  */
121
121
  static dependencies;
122
- /** Plugin version - override in subclass if needed */
123
- version = "1.0.0";
122
+ /**
123
+ * Plugin version - defaults to grid version for built-in plugins.
124
+ * Third-party plugins can override with their own semver.
125
+ */
126
+ version = typeof __GRID_VERSION__ < "u" ? __GRID_VERSION__ : "dev";
124
127
  /** CSS styles to inject into the grid's shadow DOM */
125
128
  styles;
126
129
  /** Custom cell renderers keyed by type name */
@@ -207,12 +210,28 @@ class _ {
207
210
  emit(e, t) {
208
211
  this.grid?.dispatchEvent?.(new CustomEvent(e, { detail: t, bubbles: !0 }));
209
212
  }
213
+ /**
214
+ * Emit a cancelable custom event from the grid.
215
+ * @returns `true` if the event was cancelled (preventDefault called), `false` otherwise
216
+ */
217
+ emitCancelable(e, t) {
218
+ const i = new CustomEvent(e, { detail: t, bubbles: !0, cancelable: !0 });
219
+ return this.grid?.dispatchEvent?.(i), i.defaultPrevented;
220
+ }
210
221
  /**
211
222
  * Request a re-render of the grid.
212
223
  */
213
224
  requestRender() {
214
225
  this.grid?.requestRender?.();
215
226
  }
227
+ /**
228
+ * Request a re-render and restore focus styling afterward.
229
+ * Use this when a plugin action (like expand/collapse) triggers a render
230
+ * but needs to maintain keyboard navigation focus.
231
+ */
232
+ requestRenderWithFocus() {
233
+ this.grid?.requestRenderWithFocus?.();
234
+ }
216
235
  /**
217
236
  * Request a lightweight style update without rebuilding DOM.
218
237
  * Use this instead of requestRender() when only CSS classes need updating.
@@ -246,6 +265,19 @@ class _ {
246
265
  get visibleColumns() {
247
266
  return this.grid?._visibleColumns ?? [];
248
267
  }
268
+ /**
269
+ * Get the grid as an HTMLElement for direct DOM operations.
270
+ * Use sparingly - prefer the typed GridElementRef API when possible.
271
+ *
272
+ * @example
273
+ * ```ts
274
+ * const width = this.gridElement.clientWidth;
275
+ * this.gridElement.classList.add('my-plugin-active');
276
+ * ```
277
+ */
278
+ get gridElement() {
279
+ return this.grid;
280
+ }
249
281
  /**
250
282
  * Get the shadow root of the grid.
251
283
  */
@@ -278,8 +310,53 @@ class _ {
278
310
  */
279
311
  get gridIcons() {
280
312
  const e = this.grid?.gridConfig?.icons ?? {};
281
- return { ...H, ...e };
313
+ return { ...I, ...e };
282
314
  }
315
+ // #region Animation Helpers
316
+ /**
317
+ * Check if animations are enabled at the grid level.
318
+ * Respects gridConfig.animation.mode and the CSS variable set by the grid.
319
+ *
320
+ * Plugins should use this to skip animations when:
321
+ * - Animation mode is 'off' or `false`
322
+ * - User prefers reduced motion and mode is 'reduced-motion' (default)
323
+ *
324
+ * @example
325
+ * ```ts
326
+ * private get animationStyle(): 'slide' | 'fade' | false {
327
+ * if (!this.isAnimationEnabled) return false;
328
+ * return this.config.animation ?? 'slide';
329
+ * }
330
+ * ```
331
+ */
332
+ get isAnimationEnabled() {
333
+ const e = this.grid?.effectiveConfig?.animation?.mode ?? "reduced-motion";
334
+ if (e === !1 || e === "off") return !1;
335
+ if (e === !0 || e === "on") return !0;
336
+ const t = this.shadowRoot?.host;
337
+ return t ? getComputedStyle(t).getPropertyValue("--tbw-animation-enabled").trim() !== "0" : !0;
338
+ }
339
+ /**
340
+ * Get the animation duration in milliseconds from CSS variable.
341
+ * Falls back to 200ms if not set.
342
+ *
343
+ * Plugins can use this for their animation timing to stay consistent
344
+ * with the grid-level animation.duration setting.
345
+ *
346
+ * @example
347
+ * ```ts
348
+ * element.animate(keyframes, { duration: this.animationDuration });
349
+ * ```
350
+ */
351
+ get animationDuration() {
352
+ const e = this.shadowRoot?.host;
353
+ if (e) {
354
+ const t = getComputedStyle(e).getPropertyValue("--tbw-animation-duration").trim(), i = parseInt(t, 10);
355
+ if (!isNaN(i)) return i;
356
+ }
357
+ return 200;
358
+ }
359
+ // #endregion
283
360
  /**
284
361
  * Resolve an icon value to string or HTMLElement.
285
362
  * Checks plugin config first, then grid-level icons, then defaults.
@@ -309,33 +386,58 @@ class _ {
309
386
  }
310
387
  // #endregion
311
388
  }
312
- function p(i, e) {
313
- const t = new Set(i);
389
+ const p = "__tbw_expander", H = 32;
390
+ function m(n) {
391
+ return n.field === p;
392
+ }
393
+ function k(n) {
394
+ return n.find(m);
395
+ }
396
+ function O(n) {
397
+ return {
398
+ field: p,
399
+ header: "",
400
+ // No header text - visually merges with next column
401
+ width: H,
402
+ resizable: !1,
403
+ sortable: !1,
404
+ meta: {
405
+ lockPosition: !0,
406
+ suppressMovable: !0,
407
+ expanderColumn: !0,
408
+ expanderPlugin: n,
409
+ utility: !0
410
+ // Marks this as a utility column (excluded from selection, clipboard, etc.)
411
+ }
412
+ };
413
+ }
414
+ function g(n, e) {
415
+ const t = new Set(n);
314
416
  return t.has(e) ? t.delete(e) : t.add(e), t;
315
417
  }
316
- function k(i, e) {
317
- const t = new Set(i);
418
+ function N(n, e) {
419
+ const t = new Set(n);
318
420
  return t.add(e), t;
319
421
  }
320
- function L(i, e) {
321
- const t = new Set(i);
422
+ function q(n, e) {
423
+ const t = new Set(n);
322
424
  return t.delete(e), t;
323
425
  }
324
- function T(i, e) {
325
- return i.has(e);
426
+ function P(n, e) {
427
+ return n.has(e);
326
428
  }
327
- function I(i, e, t, n) {
328
- const s = document.createElement("div");
329
- s.className = "master-detail-row", s.setAttribute("data-detail-for", String(e)), s.setAttribute("role", "row");
330
- const a = document.createElement("div");
331
- a.className = "master-detail-cell", a.setAttribute("role", "cell"), a.style.gridColumn = `1 / ${n + 1}`;
332
- const r = t(i, e);
333
- return typeof r == "string" ? a.innerHTML = r : r instanceof HTMLElement && a.appendChild(r), s.appendChild(a), s;
429
+ function M(n, e, t, i) {
430
+ const r = document.createElement("div");
431
+ r.className = "master-detail-row", r.setAttribute("data-detail-for", String(e)), r.setAttribute("role", "row");
432
+ const l = document.createElement("div");
433
+ l.className = "master-detail-cell", l.setAttribute("role", "cell"), l.style.gridColumn = `1 / ${i + 1}`;
434
+ const o = t(n, e);
435
+ return typeof o == "string" ? l.innerHTML = o : o instanceof HTMLElement && l.appendChild(o), r.appendChild(l), r;
334
436
  }
335
- const O = ".master-detail-cell-wrapper{display:flex;align-items:center;gap:4px}.master-detail-toggle{cursor:pointer;opacity:.7;-webkit-user-select:none;user-select:none;display:inline-flex;align-items:center;justify-content:center}.master-detail-toggle:hover{opacity:1}.master-detail-row{grid-column:1 / -1;display:grid;background:var(--tbw-master-detail-bg, var(--tbw-color-row-alt));border-bottom:1px solid var(--tbw-master-detail-border, var(--tbw-color-border));overflow:hidden}.master-detail-cell{padding:16px;overflow:auto}.master-detail-row.tbw-expanding{animation:tbw-detail-expand var(--tbw-animation-duration, .2s) var(--tbw-animation-easing, ease-out) forwards}.master-detail-row.tbw-collapsing{animation:tbw-detail-collapse var(--tbw-animation-duration, .2s) var(--tbw-animation-easing, ease-out) forwards}@keyframes tbw-detail-expand{0%{opacity:0;max-height:0;padding-top:0;padding-bottom:0}to{opacity:1;max-height:500px;padding-top:16px;padding-bottom:16px}}@keyframes tbw-detail-collapse{0%{opacity:1;max-height:500px}to{opacity:0;max-height:0}}";
336
- class q extends _ {
437
+ const F = ".cell[data-field=__tbw_expander]{border-right:none!important;padding:0;display:flex;align-items:center;justify-content:center}.header-row .cell[data-field=__tbw_expander]{visibility:hidden;border:none!important;padding:0;overflow:hidden}.header-row .cell[data-field=__tbw_expander]+.cell{margin-left:-32px;padding-left:calc(var(--tbw-cell-padding, 8px) + 32px)}.master-detail-expander{display:flex;align-items:center;justify-content:center;width:100%;height:100%}.master-detail-toggle{cursor:pointer;opacity:.7;-webkit-user-select:none;user-select:none;display:inline-flex;align-items:center;justify-content:center}.master-detail-toggle:hover{opacity:1}.master-detail-row{grid-column:1 / -1;display:grid;background:var(--tbw-master-detail-bg, var(--tbw-color-row-alt));border-bottom:1px solid var(--tbw-master-detail-border, var(--tbw-color-border));overflow:hidden}.master-detail-cell{padding:16px;overflow:auto}.master-detail-row.tbw-expanding{animation:tbw-detail-expand var(--tbw-animation-duration, .2s) var(--tbw-animation-easing, ease-out) forwards}.master-detail-row.tbw-collapsing{animation:tbw-detail-collapse var(--tbw-animation-duration, .2s) var(--tbw-animation-easing, ease-out) forwards}@keyframes tbw-detail-expand{0%{opacity:0;max-height:0;padding-top:0;padding-bottom:0}to{opacity:1;max-height:500px;padding-top:16px;padding-bottom:16px}}@keyframes tbw-detail-collapse{0%{opacity:1;max-height:500px}to{opacity:0;max-height:0}}";
438
+ class w extends T {
337
439
  name = "masterDetail";
338
- version = "1.0.0";
440
+ styles = F;
339
441
  get defaultConfig() {
340
442
  return {
341
443
  detailHeight: "auto",
@@ -381,52 +483,31 @@ class q extends _ {
381
483
  if (!e || typeof e.querySelector != "function") return;
382
484
  const t = e.querySelector("tbw-grid-detail");
383
485
  if (!t) return;
384
- const n = e;
385
- if (n.__frameworkAdapter?.parseDetailElement) {
386
- const c = n.__frameworkAdapter.parseDetailElement(t);
387
- if (c) {
388
- this.config = { ...this.config, detailRenderer: c };
486
+ const i = e;
487
+ if (i.__frameworkAdapter?.parseDetailElement) {
488
+ const f = i.__frameworkAdapter.parseDetailElement(t);
489
+ if (f) {
490
+ this.config = { ...this.config, detailRenderer: f };
389
491
  return;
390
492
  }
391
493
  }
392
- const s = t.getAttribute("animation"), a = t.getAttribute("show-expand-column"), r = t.getAttribute("expand-on-row-click"), o = t.getAttribute("collapse-on-click-outside"), l = t.getAttribute("height"), d = {};
393
- s !== null && (d.animation = s === "false" ? !1 : s), a !== null && (d.showExpandColumn = a !== "false"), r !== null && (d.expandOnRowClick = r === "true"), o !== null && (d.collapseOnClickOutside = o === "true"), l !== null && (d.detailHeight = l === "auto" ? "auto" : parseInt(l, 10));
394
- const u = t.innerHTML.trim();
395
- u && !this.config.detailRenderer && (d.detailRenderer = (c, h) => {
396
- const g = S(u, { value: c, row: c });
397
- return y(g);
494
+ const r = t.getAttribute("animation"), l = t.getAttribute("show-expand-column"), o = t.getAttribute("expand-on-row-click"), s = t.getAttribute("collapse-on-click-outside"), a = t.getAttribute("height"), d = {};
495
+ r !== null && (d.animation = r === "false" ? !1 : r), l !== null && (d.showExpandColumn = l !== "false"), o !== null && (d.expandOnRowClick = o === "true"), s !== null && (d.collapseOnClickOutside = s === "true"), a !== null && (d.detailHeight = a === "auto" ? "auto" : parseInt(a, 10));
496
+ const c = t.innerHTML.trim();
497
+ c && !this.config.detailRenderer && (d.detailRenderer = (f, G) => {
498
+ const x = D(c, { value: f, row: f });
499
+ return _(x);
398
500
  }), Object.keys(d).length > 0 && (this.config = { ...this.config, ...d });
399
501
  }
400
502
  // #endregion
401
503
  // #region Animation Helpers
402
- /**
403
- * Check if animations are enabled at the grid level.
404
- * Respects gridConfig.animation.mode and CSS variable.
405
- */
406
- get isAnimationEnabled() {
407
- const t = this.grid.effectiveConfig?.animation?.mode ?? "reduced-motion";
408
- if (t === !1 || t === "off") return !1;
409
- if (t === !0 || t === "on") return !0;
410
- const n = this.shadowRoot?.host;
411
- return n ? getComputedStyle(n).getPropertyValue("--tbw-animation-enabled").trim() !== "0" : !0;
412
- }
413
504
  /**
414
505
  * Get expand/collapse animation style from plugin config.
506
+ * Uses base class isAnimationEnabled to respect grid-level settings.
415
507
  */
416
508
  get animationStyle() {
417
509
  return this.isAnimationEnabled ? this.config.animation ?? "slide" : !1;
418
510
  }
419
- /**
420
- * Get animation duration from CSS variable (set by grid).
421
- */
422
- get animationDuration() {
423
- const e = this.shadowRoot?.host;
424
- if (e) {
425
- const t = getComputedStyle(e).getPropertyValue("--tbw-animation-duration").trim(), n = parseInt(t, 10);
426
- if (!isNaN(n)) return n;
427
- }
428
- return 200;
429
- }
430
511
  /**
431
512
  * Apply expand animation to a detail element.
432
513
  */
@@ -448,15 +529,34 @@ class q extends _ {
448
529
  return;
449
530
  }
450
531
  e.classList.add("tbw-collapsing");
451
- const n = () => {
532
+ const i = () => {
452
533
  e.classList.remove("tbw-collapsing"), t();
453
534
  };
454
- e.addEventListener("animationend", n, { once: !0 }), setTimeout(n, this.animationDuration + 50);
535
+ e.addEventListener("animationend", i, { once: !0 }), setTimeout(i, this.animationDuration + 50);
455
536
  }
456
537
  // #endregion
457
538
  // #region Internal State
458
539
  expandedRows = /* @__PURE__ */ new Set();
459
540
  detailElements = /* @__PURE__ */ new Map();
541
+ /** Default height for detail rows when not configured */
542
+ static DEFAULT_DETAIL_HEIGHT = 150;
543
+ /**
544
+ * Get the estimated height for a detail row.
545
+ */
546
+ getDetailHeight(e) {
547
+ const t = this.detailElements.get(e);
548
+ return t ? t.offsetHeight : typeof this.config?.detailHeight == "number" ? this.config.detailHeight : w.DEFAULT_DETAIL_HEIGHT;
549
+ }
550
+ /**
551
+ * Toggle a row's detail and emit event.
552
+ */
553
+ toggleAndEmit(e, t) {
554
+ this.expandedRows = g(this.expandedRows, e), this.emit("detail-expand", {
555
+ rowIndex: t,
556
+ row: e,
557
+ expanded: this.expandedRows.has(e)
558
+ }), this.requestRender();
559
+ }
460
560
  // #endregion
461
561
  // #region Lifecycle
462
562
  detach() {
@@ -465,49 +565,36 @@ class q extends _ {
465
565
  // #endregion
466
566
  // #region Hooks
467
567
  processColumns(e) {
468
- if (!this.config.detailRenderer)
568
+ if (!this.config.detailRenderer || this.config.showExpandColumn === !1)
469
569
  return [...e];
470
570
  const t = [...e];
471
- if (t.length > 0) {
472
- const n = { ...t[0] }, s = n.viewRenderer;
473
- if (s?.__masterDetailWrapped)
474
- return t;
475
- const a = (r) => {
476
- const { value: o, row: l } = r, d = this.expandedRows.has(l), u = document.createElement("span");
477
- u.className = "master-detail-cell-wrapper";
478
- const c = document.createElement("span");
479
- c.className = `master-detail-toggle${d ? " expanded" : ""}`, this.setIcon(c, this.resolveIcon(d ? "collapse" : "expand")), c.setAttribute("role", "button"), c.setAttribute("tabindex", "0"), c.setAttribute("aria-expanded", String(d)), c.setAttribute("aria-label", d ? "Collapse details" : "Expand details"), u.appendChild(c);
480
- const h = document.createElement("span");
481
- if (s) {
482
- const g = s(r);
483
- g instanceof Node ? h.appendChild(g) : h.textContent = String(g ?? o ?? "");
484
- } else
485
- h.textContent = String(o ?? "");
486
- return u.appendChild(h), u;
487
- };
488
- a.__masterDetailWrapped = !0, n.viewRenderer = a, t[0] = n;
489
- }
490
- return t;
571
+ if (k(t))
572
+ return t;
573
+ const r = O(this.name);
574
+ return r.viewRenderer = (l) => {
575
+ const { row: o } = l, s = this.expandedRows.has(o), a = document.createElement("span");
576
+ a.className = "master-detail-expander expander-cell";
577
+ const d = document.createElement("span");
578
+ return d.className = `master-detail-toggle${s ? " expanded" : ""}`, this.setIcon(d, this.resolveIcon(s ? "collapse" : "expand")), d.setAttribute("role", "button"), d.setAttribute("tabindex", "0"), d.setAttribute("aria-expanded", String(s)), d.setAttribute("aria-label", s ? "Collapse details" : "Expand details"), a.appendChild(d), a;
579
+ }, [r, ...t];
491
580
  }
492
581
  onRowClick(e) {
493
582
  if (!(!this.config.expandOnRowClick || !this.config.detailRenderer))
494
- return this.expandedRows = p(this.expandedRows, e.row), this.emit("detail-expand", {
495
- rowIndex: e.rowIndex,
496
- row: e.row,
497
- expanded: this.expandedRows.has(e.row)
498
- }), this.requestRender(), !1;
583
+ return this.toggleAndEmit(e.row, e.rowIndex), !1;
499
584
  }
500
585
  onCellClick(e) {
501
- if (e.originalEvent?.target?.classList.contains("master-detail-toggle")) {
502
- const n = e.row, s = e.rowIndex;
503
- return this.expandedRows = p(this.expandedRows, n), this.emit("detail-expand", {
504
- rowIndex: s,
505
- row: n,
506
- expanded: this.expandedRows.has(n)
507
- }), this.requestRender(), !0;
508
- }
586
+ if (e.originalEvent?.target?.classList.contains("master-detail-toggle"))
587
+ return this.toggleAndEmit(e.row, e.rowIndex), !0;
509
588
  this.expandedRows.size > 0 && queueMicrotask(() => this.#e());
510
589
  }
590
+ onKeyDown(e) {
591
+ if (e.key !== " ") return;
592
+ const t = this.grid._focusCol, i = this.grid._focusRow, r = this.columns[t];
593
+ if (!r || !m(r)) return;
594
+ const l = this.rows[i];
595
+ if (l)
596
+ return e.preventDefault(), this.toggleAndEmit(l, i), this.requestRenderWithFocus(), !0;
597
+ }
511
598
  afterRender() {
512
599
  this.#e();
513
600
  }
@@ -526,26 +613,26 @@ class q extends _ {
526
613
  if (!this.config.detailRenderer) return;
527
614
  const e = this.shadowRoot?.querySelector(".rows");
528
615
  if (!e) return;
529
- const t = /* @__PURE__ */ new Map(), n = e.querySelectorAll(".data-grid-row"), s = this.columns.length;
530
- for (const r of n) {
531
- const o = r.querySelector(".cell[data-row]"), l = o ? parseInt(o.getAttribute("data-row") ?? "-1", 10) : -1;
532
- l >= 0 && t.set(l, r);
616
+ const t = /* @__PURE__ */ new Map(), i = e.querySelectorAll(".data-grid-row"), r = this.columns.length;
617
+ for (const o of i) {
618
+ const s = o.querySelector(".cell[data-row]"), a = s ? parseInt(s.getAttribute("data-row") ?? "-1", 10) : -1;
619
+ a >= 0 && t.set(a, o);
533
620
  }
534
- const a = e.querySelectorAll(".master-detail-row");
535
- for (const r of a) {
536
- const o = parseInt(r.getAttribute("data-detail-for") ?? "-1", 10), l = o >= 0 ? this.rows[o] : void 0, d = l && this.expandedRows.has(l), u = t.has(o);
537
- (!d || !u) && (r.remove(), l && this.detailElements.delete(l));
621
+ const l = e.querySelectorAll(".master-detail-row");
622
+ for (const o of l) {
623
+ const s = parseInt(o.getAttribute("data-detail-for") ?? "-1", 10), a = s >= 0 ? this.rows[s] : void 0, d = a && this.expandedRows.has(a), c = t.has(s);
624
+ (!d || !c) && (o.remove(), a && this.detailElements.delete(a));
538
625
  }
539
- for (const [r, o] of t) {
540
- const l = this.rows[r];
541
- if (!l || !this.expandedRows.has(l)) continue;
542
- const d = this.detailElements.get(l);
626
+ for (const [o, s] of t) {
627
+ const a = this.rows[o];
628
+ if (!a || !this.expandedRows.has(a)) continue;
629
+ const d = this.detailElements.get(a);
543
630
  if (d) {
544
- d.previousElementSibling !== o && o.after(d);
631
+ d.previousElementSibling !== s && s.after(d);
545
632
  continue;
546
633
  }
547
- const u = I(l, r, this.config.detailRenderer, s);
548
- typeof this.config.detailHeight == "number" && (u.style.height = `${this.config.detailHeight}px`), o.after(u), this.detailElements.set(l, u), this.animateExpand(u);
634
+ const c = M(a, o, this.config.detailRenderer, r);
635
+ typeof this.config.detailHeight == "number" && (c.style.height = `${this.config.detailHeight}px`), s.after(c), this.detailElements.set(a, c), this.animateExpand(c);
549
636
  }
550
637
  }
551
638
  /**
@@ -554,15 +641,8 @@ class q extends _ {
554
641
  */
555
642
  getExtraHeight() {
556
643
  let e = 0;
557
- for (const t of this.expandedRows) {
558
- const n = this.detailElements.get(t);
559
- if (n)
560
- e += n.offsetHeight;
561
- else {
562
- const s = this.config?.detailHeight;
563
- e += typeof s == "number" ? s : 150;
564
- }
565
- }
644
+ for (const t of this.expandedRows)
645
+ e += this.getDetailHeight(t);
566
646
  return e;
567
647
  }
568
648
  /**
@@ -571,17 +651,9 @@ class q extends _ {
571
651
  */
572
652
  getExtraHeightBefore(e) {
573
653
  let t = 0;
574
- for (const n of this.expandedRows) {
575
- const s = this.rows.indexOf(n);
576
- if (s >= 0 && s < e) {
577
- const a = this.detailElements.get(n);
578
- if (a)
579
- t += a.offsetHeight;
580
- else {
581
- const r = this.config?.detailHeight;
582
- t += typeof r == "number" ? r : 150;
583
- }
584
- }
654
+ for (const i of this.expandedRows) {
655
+ const r = this.rows.indexOf(i);
656
+ r >= 0 && r < e && (t += this.getDetailHeight(i));
585
657
  }
586
658
  return t;
587
659
  }
@@ -589,20 +661,20 @@ class q extends _ {
589
661
  * Adjust the virtualization start index to keep expanded row visible while its detail is visible.
590
662
  * This ensures the detail scrolls smoothly out of view instead of disappearing abruptly.
591
663
  */
592
- adjustVirtualStart(e, t, n) {
664
+ adjustVirtualStart(e, t, i) {
593
665
  if (this.expandedRows.size === 0) return e;
594
- const s = [];
595
- for (const o of this.expandedRows) {
596
- const l = this.rows.indexOf(o);
597
- l >= 0 && s.push({ index: l, row: o });
666
+ const r = [];
667
+ for (const s of this.expandedRows) {
668
+ const a = this.rows.indexOf(s);
669
+ a >= 0 && r.push({ index: a, row: s });
598
670
  }
599
- s.sort((o, l) => o.index - l.index);
600
- let a = e, r = 0;
601
- for (const { index: o, row: l } of s) {
602
- const d = o * n + r, c = this.detailElements.get(l)?.offsetHeight ?? (typeof this.config?.detailHeight == "number" ? this.config.detailHeight : 150), h = d + n + c;
603
- r += c, !(o >= e) && h > t && o < a && (a = o);
671
+ r.sort((s, a) => s.index - a.index);
672
+ let l = e, o = 0;
673
+ for (const { index: s, row: a } of r) {
674
+ const d = s * i + o, c = this.getDetailHeight(a), f = d + i + c;
675
+ o += c, !(s >= e) && f > t && s < l && (l = s);
604
676
  }
605
- return a;
677
+ return l;
606
678
  }
607
679
  // #endregion
608
680
  // #region Public API
@@ -612,7 +684,7 @@ class q extends _ {
612
684
  */
613
685
  expand(e) {
614
686
  const t = this.rows[e];
615
- t && (this.expandedRows = k(this.expandedRows, t), this.requestRender());
687
+ t && (this.expandedRows = N(this.expandedRows, t), this.requestRender());
616
688
  }
617
689
  /**
618
690
  * Collapse the detail row at the given index.
@@ -620,7 +692,7 @@ class q extends _ {
620
692
  */
621
693
  collapse(e) {
622
694
  const t = this.rows[e];
623
- t && (this.expandedRows = L(this.expandedRows, t), this.requestRender());
695
+ t && (this.expandedRows = q(this.expandedRows, t), this.requestRender());
624
696
  }
625
697
  /**
626
698
  * Toggle the detail row at the given index.
@@ -628,7 +700,7 @@ class q extends _ {
628
700
  */
629
701
  toggle(e) {
630
702
  const t = this.rows[e];
631
- t && (this.expandedRows = p(this.expandedRows, t), this.requestRender());
703
+ t && (this.expandedRows = g(this.expandedRows, t), this.requestRender());
632
704
  }
633
705
  /**
634
706
  * Check if the detail row at the given index is expanded.
@@ -637,7 +709,7 @@ class q extends _ {
637
709
  */
638
710
  isExpanded(e) {
639
711
  const t = this.rows[e];
640
- return t ? T(this.expandedRows, t) : !1;
712
+ return t ? P(this.expandedRows, t) : !1;
641
713
  }
642
714
  /**
643
715
  * Expand all detail rows.
@@ -660,8 +732,8 @@ class q extends _ {
660
732
  getExpandedRows() {
661
733
  const e = [];
662
734
  for (const t of this.expandedRows) {
663
- const n = this.rows.indexOf(t);
664
- n >= 0 && e.push(n);
735
+ const i = this.rows.indexOf(t);
736
+ i >= 0 && e.push(i);
665
737
  }
666
738
  return e;
667
739
  }
@@ -689,11 +761,8 @@ class q extends _ {
689
761
  }
690
762
  }
691
763
  // #endregion
692
- // #region Styles
693
- styles = O;
694
- // #endregion
695
764
  }
696
765
  export {
697
- q as MasterDetailPlugin
766
+ w as MasterDetailPlugin
698
767
  };
699
768
  //# sourceMappingURL=index.js.map