@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
package/all.js CHANGED
@@ -1,35 +1,32 @@
1
- import { BaseGridPlugin as x, DEFAULT_GRID_ICONS as ze, runAggregator as ce, e as $e, s as We, PLUGIN_QUERIES as H, getAggregator as ue, getValueAggregator as je, a as Ue, c as V, g as Ze } from "./index.js";
2
- import { DEFAULT_ANIMATION_CONFIG as Jn, DGEvents as Qn, DataGridElement as ei, FitModeEnum as ti, GridCSSVars as ni, GridClasses as ii, GridDataAttrs as oi, DataGridElement as ri, GridSelectors as si, PluginEvents as li, PluginManager as ai, RenderPhase as di, builtInSort as ci, defaultComparator as ui } from "./index.js";
3
- function Xe(s, e, t, n) {
4
- if (n.processCell)
5
- return n.processCell(s, e, t);
6
- if (s == null) return "";
7
- if (s instanceof Date) return s.toISOString();
8
- if (typeof s == "object") return JSON.stringify(s);
9
- const i = String(s), o = n.delimiter ?? " ", r = n.newline ?? `
10
- `;
11
- return n.quoteStrings || i.includes(o) || i.includes(r) || i.includes('"') ? `"${i.replace(/"/g, '""')}"` : i;
1
+ import { BaseGridPlugin as x, DEFAULT_GRID_ICONS as $e, runAggregator as de, e as je, s as Ue, PLUGIN_QUERIES as He, getAggregator as ce, getValueAggregator as Xe, a as Ze, c as V, g as Ye } from "./index.js";
2
+ import { DEFAULT_ANIMATION_CONFIG as oi, DGEvents as ri, DataGridElement as si, FitModeEnum as li, GridCSSVars as ai, GridClasses as di, GridDataAttrs as ci, DataGridElement as ui, GridSelectors as hi, PluginEvents as fi, PluginManager as gi, RenderPhase as pi, builtInSort as mi, defaultComparator as wi } from "./index.js";
3
+ const Oe = "__tbw_expander", Je = 32;
4
+ function ie(s) {
5
+ return s.field === Oe;
12
6
  }
13
- function B(s) {
14
- const { rows: e, columns: t, selectedIndices: n, config: i } = s, o = i.delimiter ?? " ", r = i.newline ?? `
15
- `, l = t.filter((h) => !h.hidden && !h.field.startsWith("__")), a = [];
16
- if (i.includeHeaders) {
17
- const h = l.map((u) => {
18
- const f = u.header || u.field;
19
- return f.includes(o) || f.includes(r) || f.includes('"') ? `"${f.replace(/"/g, '""')}"` : f;
20
- });
21
- a.push(h.join(o));
22
- }
23
- const c = [...n instanceof Set ? [...n] : n].sort((h, u) => h - u);
24
- for (const h of c) {
25
- const u = e[h];
26
- if (!u) continue;
27
- const f = l.map(
28
- (g) => Xe(u[g.field], g.field, u, i)
29
- );
30
- a.push(f.join(o));
31
- }
32
- return a.join(r);
7
+ function _(s) {
8
+ return s.meta?.utility === !0;
9
+ }
10
+ function Qe(s) {
11
+ return s.find(ie);
12
+ }
13
+ function et(s) {
14
+ return {
15
+ field: Oe,
16
+ header: "",
17
+ // No header text - visually merges with next column
18
+ width: Je,
19
+ resizable: !1,
20
+ sortable: !1,
21
+ meta: {
22
+ lockPosition: !0,
23
+ suppressMovable: !0,
24
+ expanderColumn: !0,
25
+ expanderPlugin: s,
26
+ utility: !0
27
+ // Marks this as a utility column (excluded from selection, clipboard, etc.)
28
+ }
29
+ };
33
30
  }
34
31
  async function z(s) {
35
32
  try {
@@ -41,7 +38,7 @@ async function z(s) {
41
38
  return document.body.removeChild(e), t;
42
39
  }
43
40
  }
44
- function he(s, e) {
41
+ function ue(s, e) {
45
42
  const t = e.delimiter ?? " ", n = e.newline ?? `
46
43
  `, i = s.replace(/\r\n/g, `
47
44
  `).replace(/\r/g, `
@@ -49,28 +46,49 @@ function he(s, e) {
49
46
  let r = [], l = "", a = !1;
50
47
  for (let d = 0; d < i.length; d++) {
51
48
  const c = i[d];
52
- c === '"' && !a ? a = !0 : c === '"' && a ? i[d + 1] === '"' ? (l += '"', d++) : a = !1 : c === t && !a ? (r.push(l), l = "") : c === n && !a ? (r.push(l), l = "", (r.length > 1 || r.some((h) => h.trim() !== "")) && o.push(r), r = []) : l += c;
49
+ c === '"' && !a ? a = !0 : c === '"' && a ? i[d + 1] === '"' ? (l += '"', d++) : a = !1 : c === t && !a ? (r.push(l), l = "") : c === n && !a ? (r.push(l), l = "", (r.length > 1 || r.some((u) => u.trim() !== "")) && o.push(r), r = []) : l += c;
53
50
  }
54
51
  return r.push(l), (r.length > 1 || r.some((d) => d.trim() !== "")) && o.push(r), o;
55
52
  }
56
- async function fe() {
53
+ async function tt() {
57
54
  try {
58
55
  return await navigator.clipboard.readText();
59
56
  } catch {
60
57
  return "";
61
58
  }
62
59
  }
63
- class Tn extends x {
60
+ function nt(s, e) {
61
+ const { rows: t, target: n, fields: i } = s;
62
+ if (!n) return;
63
+ const o = e.rows, l = (e.effectiveConfig.columns ?? []).map((c) => c.field), a = [...o], d = n.bounds ? n.bounds.endRow : 1 / 0;
64
+ t.forEach((c, u) => {
65
+ const h = n.row + u;
66
+ if (!(h > d)) {
67
+ if (n.bounds) {
68
+ if (h >= a.length)
69
+ return;
70
+ } else for (; h >= a.length; ) {
71
+ const f = {};
72
+ l.forEach((g) => f[g] = ""), a.push(f);
73
+ }
74
+ a[h] = { ...a[h] }, c.forEach((f, g) => {
75
+ const p = i[g];
76
+ p && (a[h][p] = f);
77
+ });
78
+ }
79
+ }), e.rows = a;
80
+ }
81
+ class qn extends x {
64
82
  /**
65
- * Plugin dependencies - ClipboardPlugin requires SelectionPlugin to know what to copy.
83
+ * Plugin dependencies - ClipboardPlugin works best with SelectionPlugin.
66
84
  *
67
- * The SelectionPlugin must be loaded BEFORE this plugin in the plugins array.
85
+ * Without SelectionPlugin: copies entire grid, pastes at row 0 col 0.
86
+ * With SelectionPlugin: copies/pastes based on selection.
68
87
  */
69
88
  static dependencies = [
70
- { name: "selection", required: !0, reason: "ClipboardPlugin needs selection to determine what cells to copy" }
89
+ { name: "selection", required: !1, reason: "Enables copy/paste of selected cells instead of entire grid" }
71
90
  ];
72
91
  name = "clipboard";
73
- version = "1.0.0";
74
92
  get defaultConfig() {
75
93
  return {
76
94
  includeHeaders: !1,
@@ -85,65 +103,107 @@ class Tn extends x {
85
103
  lastCopied = null;
86
104
  // #endregion
87
105
  // #region Lifecycle
106
+ attach(e) {
107
+ super.attach(e), e.addEventListener(
108
+ "paste",
109
+ (t) => this.#t(t),
110
+ { signal: this.disconnectSignal }
111
+ );
112
+ }
88
113
  detach() {
89
114
  this.lastCopied = null;
90
115
  }
91
116
  // #endregion
92
117
  // #region Event Handlers
93
118
  onKeyDown(e) {
94
- const t = (e.ctrlKey || e.metaKey) && e.key === "c", n = (e.ctrlKey || e.metaKey) && e.key === "v";
95
- return t ? (this.#e(e.target), !0) : n ? (this.#t(), !0) : !1;
119
+ return (e.ctrlKey || e.metaKey) && e.key === "c" ? (this.#e(e.target), !0) : !1;
96
120
  }
97
121
  // #endregion
98
122
  // #region Private Methods
99
123
  /**
100
- * Handle copy operation
124
+ * Handle copy operation.
125
+ *
126
+ * Everything is treated as a range:
127
+ * - With selection: copies the selected range
128
+ * - Row mode: range spanning all columns for selected rows
129
+ * - No selection plugin: entire grid as a range
130
+ * - No selection: try to get focused cell from DOM as 1x1 range
101
131
  */
102
132
  #e(e) {
103
- const t = this.#r(), n = t?.getSelectedRows() ?? [], i = n.length > 0, o = t?.getRanges() ?? [], r = o.length > 0, l = t?.getSelectedCell() != null;
104
- let a, d, c;
105
- if (i && t)
106
- a = B({
107
- rows: this.rows,
108
- columns: [...this.columns],
109
- selectedIndices: n,
110
- config: this.config
111
- }), d = n.length, c = this.columns.filter((h) => !h.hidden && !h.field.startsWith("__")).length;
112
- else if (r && t) {
113
- const h = o[o.length - 1], u = this.#i({
114
- startRow: h.from.row,
115
- startCol: h.from.col,
116
- endRow: h.to.row,
117
- endCol: h.to.col
118
- });
119
- a = u.text, d = u.rowCount, c = u.columnCount;
120
- } else if (l && t) {
121
- const h = t.getSelectedCell(), u = this.#n(h.row, h.col);
122
- if (!u) return;
123
- a = u.text, d = 1, c = 1;
124
- } else {
125
- const h = this.#s(e);
126
- if (!h) return;
127
- a = h.text, d = 1, c = 1;
133
+ const t = this.#n(), n = t?.getSelection(), i = this.columns.length - 1, o = this.rows.length - 1;
134
+ let r;
135
+ if (n && n.ranges.length > 0) {
136
+ const { mode: a, ranges: d } = n, c = d[d.length - 1];
137
+ a === "row" ? r = {
138
+ startRow: c.from.row,
139
+ startCol: 0,
140
+ endRow: c.to.row,
141
+ endCol: i
142
+ } : r = {
143
+ startRow: c.from.row,
144
+ startCol: c.from.col,
145
+ endRow: c.to.row,
146
+ endCol: c.to.col
147
+ };
148
+ } else if (!t)
149
+ r = { startRow: 0, startCol: 0, endRow: o, endCol: i };
150
+ else {
151
+ const a = this.#s(e);
152
+ if (!a) return;
153
+ r = { startRow: a.row, startCol: a.col, endRow: a.row, endCol: a.col };
128
154
  }
129
- z(a).then(() => {
130
- this.lastCopied = { text: a, timestamp: Date.now() }, this.emit("copy", { text: a, rowCount: d, columnCount: c });
155
+ const l = this.#i(r);
156
+ z(l.text).then(() => {
157
+ this.lastCopied = { text: l.text, timestamp: Date.now() }, this.emit("copy", {
158
+ text: l.text,
159
+ rowCount: l.rowCount,
160
+ columnCount: l.columnCount
161
+ });
131
162
  });
132
163
  }
133
164
  /**
134
- * Handle paste operation
165
+ * Handle native paste event (preferred method - works in iframes).
166
+ * Uses synchronous clipboardData from the native paste event.
167
+ *
168
+ * Flow:
169
+ * 1. Parse clipboard text
170
+ * 2. Build target/fields info from selection
171
+ * 3. Emit 'paste' event (for listeners)
172
+ * 4. Call paste handler (if configured) to apply data to grid
173
+ *
174
+ * Selection behavior:
175
+ * - Single cell: paste starts at cell, expands freely
176
+ * - Range/row: paste is clipped to fit within selection bounds
177
+ * - No selection: paste starts at row 0, col 0
178
+ */
179
+ #t(e) {
180
+ const t = e.clipboardData?.getData("text/plain");
181
+ if (!t) return;
182
+ e.preventDefault();
183
+ const n = ue(t, this.config), o = this.#n()?.getSelection(), r = o?.ranges?.[0], l = r?.from.row ?? 0, a = r?.from.col ?? 0, c = r && (o?.mode === "range" || o?.mode === "row") && (r.from.row !== r.to.row || r.from.col !== r.to.col) ? { endRow: r.to.row, endCol: r.to.col } : null, u = c?.endCol ?? this.columns.length - 1, h = this.columns[a], f = h ? { row: l, col: a, field: h.field, bounds: c } : null, g = [], p = n[0]?.length ?? 0;
184
+ for (let m = 0; m < p && a + m <= u; m++) {
185
+ const w = this.columns[a + m];
186
+ w && !w.hidden && g.push(w.field);
187
+ }
188
+ const b = { rows: n, text: t, target: f, fields: g };
189
+ this.emit("paste", b), this.#r(b);
190
+ }
191
+ /**
192
+ * Apply the paste handler to update grid data.
193
+ *
194
+ * Uses the configured `pasteHandler`, or the default handler if not specified.
195
+ * Set `pasteHandler: null` in config to disable auto-paste.
135
196
  */
136
- #t() {
137
- fe().then((e) => {
138
- if (!e) return;
139
- const t = he(e, this.config);
140
- this.emit("paste", { rows: t, text: e });
141
- });
197
+ #r(e) {
198
+ if (!this.grid) return;
199
+ const { pasteHandler: t } = this.config;
200
+ if (t === null) return;
201
+ (t ?? nt)(e, this.grid);
142
202
  }
143
203
  /**
144
204
  * Get the selection plugin instance if available.
145
205
  */
146
- #r() {
206
+ #n() {
147
207
  try {
148
208
  const e = this.grid?.getPluginByName("selection");
149
209
  if (e)
@@ -151,71 +211,45 @@ class Tn extends x {
151
211
  } catch {
152
212
  }
153
213
  }
154
- /**
155
- * Build text for a single cell by row/col index.
156
- */
157
- #n(e, t) {
158
- const n = this.rows[e];
159
- if (!n) return null;
160
- const i = this.columns[t];
161
- if (!i) return null;
162
- const o = n[i.field], r = i.header || i.field;
163
- let l;
164
- if (this.config.includeHeaders) {
165
- const a = o == null ? "" : String(o);
166
- l = `${r}: ${a}`;
167
- } else
168
- l = o == null ? "" : String(o);
169
- return { text: l };
170
- }
171
214
  /**
172
215
  * Build text for a rectangular range of cells.
216
+ * Utility columns (like expander columns) are automatically excluded.
173
217
  */
174
218
  #i(e) {
175
- const { startRow: t, startCol: n, endRow: i, endCol: o } = e, r = Math.min(t, i), l = Math.max(t, i), a = Math.min(n, o), d = Math.max(n, o), c = this.config.delimiter ?? " ", h = this.config.newline ?? `
176
- `, u = [], f = this.columns.slice(a, d + 1);
219
+ const { startRow: t, startCol: n, endRow: i, endCol: o } = e, r = Math.min(t, i), l = Math.max(t, i), a = Math.min(n, o), d = Math.max(n, o), c = this.config.delimiter ?? " ", u = this.config.newline ?? `
220
+ `, h = [], f = this.columns.slice(a, d + 1).filter((g) => !_(g));
177
221
  if (this.config.includeHeaders) {
178
222
  const g = f.map((p) => p.header || p.field);
179
- u.push(g.join(c));
223
+ h.push(g.join(c));
180
224
  }
181
225
  for (let g = r; g <= l; g++) {
182
226
  const p = this.rows[g];
183
227
  if (!p) continue;
184
- const w = f.map((m) => {
185
- const v = p[m.field];
186
- return v == null ? "" : v instanceof Date ? v.toISOString() : String(v);
228
+ const b = f.map((m) => {
229
+ const w = p[m.field];
230
+ return w == null ? "" : w instanceof Date ? w.toISOString() : String(w);
187
231
  });
188
- u.push(w.join(c));
232
+ h.push(b.join(c));
189
233
  }
190
234
  return {
191
- text: u.join(h),
235
+ text: h.join(u),
192
236
  rowCount: l - r + 1,
193
237
  columnCount: d - a + 1
194
238
  };
195
239
  }
196
240
  /**
197
- * Build text for a single focused cell from DOM.
198
- * Used when selection plugin is not available or no rows are selected.
241
+ * Get focused cell coordinates from DOM.
242
+ * Used as fallback when SelectionPlugin has no selection.
199
243
  */
200
244
  #s(e) {
201
245
  const t = e.closest("[data-field-cache]");
202
246
  if (!t) return null;
203
- const n = t.dataset.fieldCache;
204
- if (!n) return null;
205
- const i = t.dataset.row;
206
- if (!i) return null;
247
+ const n = t.dataset.fieldCache, i = t.dataset.row;
248
+ if (!n || !i) return null;
207
249
  const o = parseInt(i, 10);
208
250
  if (isNaN(o)) return null;
209
- const r = this.rows[o];
210
- if (!r) return null;
211
- const l = r[n], d = this.columns.find((h) => h.field === n)?.header || n;
212
- let c;
213
- if (this.config.includeHeaders) {
214
- const h = l == null ? "" : String(l);
215
- c = `${d}: ${h}`;
216
- } else
217
- c = l == null ? "" : String(l);
218
- return { text: c, field: n, value: l };
251
+ const r = this.columns.findIndex((l) => l.field === n);
252
+ return r === -1 ? null : { row: o, col: r };
219
253
  }
220
254
  // #endregion
221
255
  // #region Public API
@@ -224,13 +258,19 @@ class Tn extends x {
224
258
  * @returns The copied text
225
259
  */
226
260
  async copy() {
227
- const t = this.#r()?.getSelectedRows() ?? [], n = B({
228
- rows: this.rows,
229
- columns: [...this.columns],
230
- selectedIndices: t,
231
- config: this.config
232
- });
233
- return await z(n), this.lastCopied = { text: n, timestamp: Date.now() }, n;
261
+ const t = this.#n()?.getSelection(), n = this.columns.length - 1;
262
+ let i = { startRow: 0, startCol: 0, endRow: this.rows.length - 1, endCol: n };
263
+ if (t && t.ranges.length > 0) {
264
+ const r = t.ranges[t.ranges.length - 1];
265
+ t.mode === "row" ? i = { startRow: r.from.row, startCol: 0, endRow: r.to.row, endCol: n } : i = {
266
+ startRow: r.from.row,
267
+ startCol: r.from.col,
268
+ endRow: r.to.row,
269
+ endCol: r.to.col
270
+ };
271
+ }
272
+ const o = this.#i(i);
273
+ return await z(o.text), this.lastCopied = { text: o.text, timestamp: Date.now() }, o.text;
234
274
  }
235
275
  /**
236
276
  * Copy specific rows by index to clipboard.
@@ -238,21 +278,22 @@ class Tn extends x {
238
278
  * @returns The copied text
239
279
  */
240
280
  async copyRows(e) {
241
- const t = B({
242
- rows: this.rows,
243
- columns: [...this.columns],
244
- selectedIndices: e,
245
- config: this.config
246
- });
247
- return await z(t), this.lastCopied = { text: t, timestamp: Date.now() }, t;
281
+ if (e.length === 0) return "";
282
+ const t = [...e].sort((r, l) => r - l), n = this.columns.length - 1, i = {
283
+ startRow: t[0],
284
+ startCol: 0,
285
+ endRow: t[t.length - 1],
286
+ endCol: n
287
+ }, o = this.#i(i);
288
+ return await z(o.text), this.lastCopied = { text: o.text, timestamp: Date.now() }, o.text;
248
289
  }
249
290
  /**
250
291
  * Read and parse clipboard content.
251
292
  * @returns Parsed 2D array of cell values, or null if clipboard is empty
252
293
  */
253
294
  async paste() {
254
- const e = await fe();
255
- return e ? he(e, this.config) : null;
295
+ const e = await tt();
296
+ return e ? ue(e, this.config) : null;
256
297
  }
257
298
  /**
258
299
  * Get the last copied text and timestamp.
@@ -263,33 +304,33 @@ class Tn extends x {
263
304
  }
264
305
  // #endregion
265
306
  }
266
- const ge = 100;
267
- function re(s) {
307
+ const he = 100;
308
+ function oe(s) {
268
309
  if (s == null)
269
- return ge;
310
+ return he;
270
311
  if (typeof s == "number")
271
312
  return s;
272
313
  const e = parseFloat(s);
273
- return isNaN(e) ? ge : e;
314
+ return isNaN(e) ? he : e;
274
315
  }
275
- function pe(s) {
276
- return s.map((e) => re(e.width));
316
+ function fe(s) {
317
+ return s.map((e) => oe(e.width));
277
318
  }
278
- function me(s) {
319
+ function ge(s) {
279
320
  const e = [];
280
321
  let t = 0;
281
322
  for (const n of s)
282
- e.push(t), t += re(n.width);
323
+ e.push(t), t += oe(n.width);
283
324
  return e;
284
325
  }
285
- function we(s) {
286
- return s.reduce((e, t) => e + re(t.width), 0);
326
+ function pe(s) {
327
+ return s.reduce((e, t) => e + oe(t.width), 0);
287
328
  }
288
- function Ye(s, e, t, n, i) {
329
+ function it(s, e, t, n, i) {
289
330
  const o = t.length;
290
331
  if (o === 0)
291
332
  return { startCol: 0, endCol: 0, visibleColumns: [] };
292
- let r = Je(s, t, n);
333
+ let r = ot(s, t, n);
293
334
  r = Math.max(0, r - i);
294
335
  const l = s + e;
295
336
  let a = r;
@@ -306,7 +347,7 @@ function Ye(s, e, t, n, i) {
306
347
  d.push(c);
307
348
  return { startCol: r, endCol: a, visibleColumns: d };
308
349
  }
309
- function Je(s, e, t) {
350
+ function ot(s, e, t) {
310
351
  let n = 0, i = e.length - 1;
311
352
  for (; n < i; ) {
312
353
  const o = Math.floor((n + i) / 2);
@@ -314,12 +355,11 @@ function Je(s, e, t) {
314
355
  }
315
356
  return n;
316
357
  }
317
- function Qe(s, e, t) {
358
+ function rt(s, e, t) {
318
359
  return t ? s > e : !1;
319
360
  }
320
- class In extends x {
361
+ class Nn extends x {
321
362
  name = "columnVirtualization";
322
- version = "1.0.0";
323
363
  get defaultConfig() {
324
364
  return {
325
365
  autoEnable: !0,
@@ -340,7 +380,7 @@ class In extends x {
340
380
  attach(e) {
341
381
  super.attach(e);
342
382
  const t = this.columns;
343
- this.columnWidths = pe(t), this.columnOffsets = me(t), this.totalWidth = we(t), this.endCol = t.length - 1;
383
+ this.columnWidths = fe(t), this.columnOffsets = ge(t), this.totalWidth = pe(t), this.endCol = t.length - 1;
344
384
  }
345
385
  detach() {
346
386
  this.columnWidths = [], this.columnOffsets = [], this.isVirtualized = !1, this.startCol = 0, this.endCol = 0, this.scrollLeft = 0, this.totalWidth = 0;
@@ -348,10 +388,10 @@ class In extends x {
348
388
  // #endregion
349
389
  // #region Hooks
350
390
  processColumns(e) {
351
- const t = Qe(e.length, this.config.threshold ?? 30, this.config.autoEnable ?? !0);
352
- if (this.isVirtualized = t ?? !1, this.columnWidths = pe(e), this.columnOffsets = me(e), this.totalWidth = we(e), !t)
391
+ const t = rt(e.length, this.config.threshold ?? 30, this.config.autoEnable ?? !0);
392
+ if (this.isVirtualized = t ?? !1, this.columnWidths = fe(e), this.columnOffsets = ge(e), this.totalWidth = pe(e), !t)
353
393
  return this.startCol = 0, this.endCol = e.length - 1, [...e];
354
- const n = this.grid.clientWidth || 800, i = Ye(
394
+ const n = this.grid.clientWidth || 800, i = it(
355
395
  this.scrollLeft,
356
396
  n,
357
397
  this.columnOffsets,
@@ -411,14 +451,14 @@ class In extends x {
411
451
  }
412
452
  // #endregion
413
453
  }
414
- const $ = ".tbw-context-menu{position:fixed;background:light-dark(#f5f5f5,#2a2a2a);color:light-dark(#222,#eee);border:1px solid light-dark(#d0d0d4,#454545);border-radius:4px;box-shadow:0 2px 10px #00000026;min-width:160px;padding:4px 0;z-index:10000;font-size:13px;font-family:system-ui,sans-serif}.tbw-context-menu-item{display:flex;align-items:center;padding:6px 12px;cursor:pointer;gap:8px}.tbw-context-menu-item:hover:not(.disabled){background:light-dark(#e8e8e8,#3a3a3a)}.tbw-context-menu-item.disabled{opacity:.5;cursor:default}.tbw-context-menu-item.danger{color:light-dark(#c00,#f66)}.tbw-context-menu-icon{width:16px;text-align:center}.tbw-context-menu-label{flex:1}.tbw-context-menu-shortcut{color:light-dark(#888,#888);font-size:11px}.tbw-context-menu-arrow{font-size:10px;color:light-dark(#888,#888)}.tbw-context-menu-separator{height:1px;background:light-dark(#d0d0d4,#454545);margin:4px 0}";
415
- function te(s, e) {
454
+ const W = ".tbw-context-menu{position:fixed;background:light-dark(#f5f5f5,#2a2a2a);color:light-dark(#222,#eee);border:1px solid light-dark(#d0d0d4,#454545);border-radius:4px;box-shadow:0 2px 10px #00000026;min-width:160px;padding:4px 0;z-index:10000;font-size:13px;font-family:system-ui,sans-serif}.tbw-context-menu-item{display:flex;align-items:center;padding:6px 12px;cursor:pointer;gap:8px}.tbw-context-menu-item:hover:not(.disabled){background:light-dark(#e8e8e8,#3a3a3a)}.tbw-context-menu-item.disabled{opacity:.5;cursor:default}.tbw-context-menu-item.danger{color:light-dark(#c00,#f66)}.tbw-context-menu-icon{width:16px;text-align:center}.tbw-context-menu-label{flex:1}.tbw-context-menu-shortcut{color:light-dark(#888,#888);font-size:11px}.tbw-context-menu-arrow{font-size:10px;color:light-dark(#888,#888)}.tbw-context-menu-separator{height:1px;background:light-dark(#d0d0d4,#454545);margin:4px 0}";
455
+ function ee(s, e) {
416
456
  return (typeof s == "function" ? s(e) : s).filter((n) => !(n.hidden === !0 || typeof n.hidden == "function" && n.hidden(e)));
417
457
  }
418
- function et(s, e) {
458
+ function st(s, e) {
419
459
  return s.disabled === !0 ? !0 : typeof s.disabled == "function" ? s.disabled(e) : !1;
420
460
  }
421
- function ne(s, e, t, n = ze.submenuArrow) {
461
+ function te(s, e, t, n = $e.submenuArrow) {
422
462
  const i = document.createElement("div");
423
463
  i.className = "tbw-context-menu", i.setAttribute("role", "menu");
424
464
  for (const o of s) {
@@ -429,7 +469,7 @@ function ne(s, e, t, n = ze.submenuArrow) {
429
469
  }
430
470
  const r = document.createElement("div");
431
471
  r.className = "tbw-context-menu-item", o.cssClass && r.classList.add(o.cssClass), r.setAttribute("role", "menuitem"), r.setAttribute("data-id", o.id);
432
- const l = et(o, e);
472
+ const l = st(o, e);
433
473
  if (l && (r.classList.add("disabled"), r.setAttribute("aria-disabled", "true")), o.icon) {
434
474
  const d = document.createElement("span");
435
475
  d.className = "tbw-context-menu-icon", d.innerHTML = o.icon, r.appendChild(d);
@@ -443,8 +483,8 @@ function ne(s, e, t, n = ze.submenuArrow) {
443
483
  const d = document.createElement("span");
444
484
  d.className = "tbw-context-menu-arrow", typeof n == "string" ? d.innerHTML = n : n instanceof HTMLElement && d.appendChild(n.cloneNode(!0)), r.appendChild(d), r.addEventListener("mouseenter", () => {
445
485
  if (r.querySelector(".tbw-context-menu") || !o.subMenu) return;
446
- const h = te(o.subMenu, e), u = ne(h, e, t, n);
447
- u.classList.add("tbw-context-submenu"), u.style.position = "absolute", u.style.left = "100%", u.style.top = "0", r.style.position = "relative", r.appendChild(u);
486
+ const u = ee(o.subMenu, e), h = te(u, e, t, n);
487
+ h.classList.add("tbw-context-submenu"), h.style.position = "absolute", h.style.left = "100%", h.style.top = "0", r.style.position = "relative", r.appendChild(h);
448
488
  }), r.addEventListener("mouseleave", () => {
449
489
  const c = r.querySelector(".tbw-context-menu");
450
490
  c && c.remove();
@@ -456,13 +496,13 @@ function ne(s, e, t, n = ze.submenuArrow) {
456
496
  }
457
497
  return i;
458
498
  }
459
- function be(s, e, t) {
499
+ function me(s, e, t) {
460
500
  s.style.position = "fixed", s.style.left = `${e}px`, s.style.top = `${t}px`, s.style.visibility = "hidden", s.style.zIndex = "10000";
461
501
  const n = s.getBoundingClientRect(), i = window.innerWidth, o = window.innerHeight;
462
502
  let r = e, l = t;
463
503
  e + n.width > i && (r = e - n.width), t + n.height > o && (l = t - n.height), r = Math.max(0, r), l = Math.max(0, l), s.style.left = `${r}px`, s.style.top = `${l}px`, s.style.visibility = "visible";
464
504
  }
465
- let L = null, T = null, k = null, W = 0;
505
+ let T = null, I = null, k = null, $ = 0;
466
506
  const j = [
467
507
  {
468
508
  id: "copy",
@@ -481,9 +521,8 @@ const j = [
481
521
  }
482
522
  }
483
523
  ];
484
- class Fn extends x {
524
+ class Hn extends x {
485
525
  name = "contextMenu";
486
- version = "1.0.0";
487
526
  get defaultConfig() {
488
527
  return {
489
528
  items: j
@@ -497,7 +536,7 @@ class Fn extends x {
497
536
  // #endregion
498
537
  // #region Lifecycle
499
538
  attach(e) {
500
- super.attach(e), this.installGlobalHandlers(), W++;
539
+ super.attach(e), this.installGlobalHandlers(), $++;
501
540
  }
502
541
  detach() {
503
542
  this.menuElement && (this.menuElement.remove(), this.menuElement = null), this.isOpen = !1, this.params = null, this.uninstallGlobalHandlers();
@@ -505,18 +544,18 @@ class Fn extends x {
505
544
  // #endregion
506
545
  // #region Private Methods
507
546
  installGlobalHandlers() {
508
- !k && typeof document < "u" && typeof $ == "string" && $ && (k = document.createElement("style"), k.id = "tbw-context-menu-styles", k.textContent = $, document.head.appendChild(k)), L || (L = () => {
547
+ !k && typeof document < "u" && typeof W == "string" && W && (k = document.createElement("style"), k.id = "tbw-context-menu-styles", k.textContent = W, document.head.appendChild(k)), T || (T = () => {
509
548
  document.querySelectorAll(".tbw-context-menu").forEach((t) => t.remove());
510
- }, document.addEventListener("click", L)), T || (T = (e) => {
549
+ }, document.addEventListener("click", T)), I || (I = (e) => {
511
550
  e.key === "Escape" && document.querySelectorAll(".tbw-context-menu").forEach((n) => n.remove());
512
- }, document.addEventListener("keydown", T));
551
+ }, document.addEventListener("keydown", I));
513
552
  }
514
553
  /**
515
554
  * Clean up global handlers when the last instance detaches.
516
555
  * Uses reference counting to ensure handlers persist while any grid uses the plugin.
517
556
  */
518
557
  uninstallGlobalHandlers() {
519
- W--, !(W > 0) && (L && (document.removeEventListener("click", L), L = null), T && (document.removeEventListener("keydown", T), T = null), k && (k.remove(), k = null));
558
+ $--, !($ > 0) && (T && (document.removeEventListener("click", T), T = null), I && (document.removeEventListener("keydown", I), I = null), k && (k.remove(), k = null));
520
559
  }
521
560
  // #endregion
522
561
  // #region Hooks
@@ -530,25 +569,25 @@ class Fn extends x {
530
569
  const o = i.target, r = o.closest("[data-row][data-col]"), l = o.closest(".header-cell");
531
570
  let a;
532
571
  if (r) {
533
- const c = parseInt(r.getAttribute("data-row") ?? "-1", 10), h = parseInt(r.getAttribute("data-col") ?? "-1", 10), u = this.columns[h], f = this.rows[c];
572
+ const c = parseInt(r.getAttribute("data-row") ?? "-1", 10), u = parseInt(r.getAttribute("data-col") ?? "-1", 10), h = this.columns[u], f = this.rows[c];
534
573
  a = {
535
574
  row: f,
536
575
  rowIndex: c,
537
- column: u,
538
- columnIndex: h,
539
- field: u?.field ?? "",
540
- value: f?.[u?.field] ?? null,
576
+ column: h,
577
+ columnIndex: u,
578
+ field: h?.field ?? "",
579
+ value: f?.[h?.field] ?? null,
541
580
  isHeader: !1,
542
581
  event: i
543
582
  };
544
583
  } else if (l) {
545
- const c = parseInt(l.getAttribute("data-col") ?? "-1", 10), h = this.columns[c];
584
+ const c = parseInt(l.getAttribute("data-col") ?? "-1", 10), u = this.columns[c];
546
585
  a = {
547
586
  row: null,
548
587
  rowIndex: -1,
549
- column: h,
588
+ column: u,
550
589
  columnIndex: c,
551
- field: h?.field ?? "",
590
+ field: u?.field ?? "",
552
591
  value: null,
553
592
  isHeader: !0,
554
593
  event: i
@@ -556,15 +595,15 @@ class Fn extends x {
556
595
  } else
557
596
  return;
558
597
  this.params = a, this.position = { x: i.clientX, y: i.clientY };
559
- const d = te(this.config.items ?? j, a);
560
- d.length && (this.menuElement && this.menuElement.remove(), this.menuElement = ne(
598
+ const d = ee(this.config.items ?? j, a);
599
+ d.length && (this.menuElement && this.menuElement.remove(), this.menuElement = te(
561
600
  d,
562
601
  a,
563
602
  (c) => {
564
603
  c.action && c.action(a), this.menuElement?.remove(), this.menuElement = null, this.isOpen = !1;
565
604
  },
566
605
  this.gridIcons.submenuArrow
567
- ), document.body.appendChild(this.menuElement), be(this.menuElement, i.clientX, i.clientY), this.isOpen = !0, this.emit("context-menu-open", { params: a, items: d }));
606
+ ), document.body.appendChild(this.menuElement), me(this.menuElement, i.clientX, i.clientY), this.isOpen = !0, this.emit("context-menu-open", { params: a, items: d }));
568
607
  }));
569
608
  }
570
609
  // #endregion
@@ -585,15 +624,15 @@ class Fn extends x {
585
624
  value: n.value ?? null,
586
625
  isHeader: n.isHeader ?? !1,
587
626
  event: n.event ?? new MouseEvent("contextmenu")
588
- }, o = te(this.config.items ?? j, i);
589
- this.menuElement && this.menuElement.remove(), this.menuElement = ne(
627
+ }, o = ee(this.config.items ?? j, i);
628
+ this.menuElement && this.menuElement.remove(), this.menuElement = te(
590
629
  o,
591
630
  i,
592
631
  (r) => {
593
632
  r.action && r.action(i), this.menuElement?.remove(), this.menuElement = null, this.isOpen = !1;
594
633
  },
595
634
  this.gridIcons.submenuArrow
596
- ), document.body.appendChild(this.menuElement), be(this.menuElement, e, t), this.isOpen = !0;
635
+ ), document.body.appendChild(this.menuElement), me(this.menuElement, e, t), this.isOpen = !0;
597
636
  }
598
637
  /**
599
638
  * Hide the context menu.
@@ -611,7 +650,7 @@ class Fn extends x {
611
650
  // #endregion
612
651
  // Styles are injected globally via installGlobalHandlers() since menu renders in document.body
613
652
  }
614
- function tt(s) {
653
+ function lt(s) {
615
654
  switch (s.type) {
616
655
  case "number":
617
656
  return (e) => {
@@ -665,30 +704,30 @@ function tt(s) {
665
704
  }
666
705
  }
667
706
  const U = 'input,select,textarea,[contenteditable="true"],[contenteditable=""],[tabindex]:not([tabindex="-1"])';
668
- function I(s) {
707
+ function P(s) {
669
708
  return !(typeof s != "string" || s === "__proto__" || s === "constructor" || s === "prototype");
670
709
  }
671
- function Mn(s) {
710
+ function On(s) {
672
711
  return (s.__editingCellCount ?? 0) > 0;
673
712
  }
674
- function nt(s) {
713
+ function at(s) {
675
714
  const e = (s.__editingCellCount ?? 0) + 1;
676
715
  s.__editingCellCount = e, s.setAttribute("data-has-editing", "");
677
716
  }
678
- function it(s) {
717
+ function dt(s) {
679
718
  s.__editingCellCount = 0, s.removeAttribute("data-has-editing");
680
719
  }
681
- function ot(s, e, t) {
720
+ function K(s, e) {
721
+ return s instanceof HTMLInputElement ? s.type === "checkbox" ? s.checked : s.type === "number" ? s.value === "" ? null : Number(s.value) : s.type === "date" ? s.valueAsDate : s.value : e?.type === "number" && s.value !== "" ? Number(s.value) : s.value;
722
+ }
723
+ function ct(s, e, t) {
682
724
  const n = s.querySelector("input,textarea,select");
683
- if (!n) return;
684
- const i = () => n instanceof HTMLInputElement ? n.type === "checkbox" ? n.checked : n.type === "number" ? n.value === "" ? null : Number(n.value) : n.type === "date" ? n.valueAsDate : n.value : e.type === "number" && n.value !== "" ? Number(n.value) : n.value;
685
- n.addEventListener("blur", () => {
686
- t(i());
687
- }), n instanceof HTMLInputElement && n.type === "checkbox" ? n.addEventListener("change", () => t(n.checked)) : n instanceof HTMLSelectElement && n.addEventListener("change", () => t(i()));
725
+ n && (n.addEventListener("blur", () => {
726
+ t(K(n, e));
727
+ }), n instanceof HTMLInputElement && n.type === "checkbox" ? n.addEventListener("change", () => t(n.checked)) : n instanceof HTMLSelectElement && n.addEventListener("change", () => t(K(n, e))));
688
728
  }
689
- class Pn extends x {
729
+ class Gn extends x {
690
730
  name = "editing";
691
- version = "1.0.0";
692
731
  get defaultConfig() {
693
732
  return {
694
733
  editOn: "click"
@@ -740,15 +779,6 @@ class Pn extends x {
740
779
  this.#e = -1, this.#t = -1, this.#r.clear(), this.#n.clear(), this.#i.clear(), super.detach();
741
780
  }
742
781
  // #endregion
743
- // #region Config Augmentation (processColumns hook)
744
- /**
745
- * Augment columns with editing metadata.
746
- * This enables the grid to recognize editable columns without core knowledge.
747
- */
748
- processColumns(e) {
749
- return e;
750
- }
751
- // #endregion
752
782
  // #region Event Handlers (event distribution)
753
783
  /**
754
784
  * Handle cell clicks - start editing if configured for click mode.
@@ -776,7 +806,7 @@ class Pn extends x {
776
806
  const o = t._visibleColumns[i], r = t._rows[n];
777
807
  if (o?.editable && o.type === "boolean" && r) {
778
808
  const l = o.field;
779
- if (I(l)) {
809
+ if (P(l)) {
780
810
  const d = !r[l];
781
811
  return this.#a(n, o, d, r), e.preventDefault(), this.requestRender(), !0;
782
812
  }
@@ -951,10 +981,10 @@ class Pn extends x {
951
981
  if (isNaN(d)) return;
952
982
  const c = n._visibleColumns[d];
953
983
  if (!c) return;
954
- const h = a.querySelector("input,textarea,select");
955
- if (h) {
956
- let u;
957
- h instanceof HTMLInputElement && h.type === "checkbox" ? u = h.checked : (u = h.value, c.type === "number" && u !== "" && (u = Number(u))), o[c.field] !== u && this.#a(e, c, u, o);
984
+ const u = a.querySelector("input,textarea,select");
985
+ if (u) {
986
+ const h = K(u, c);
987
+ o[c.field] !== h && this.#a(e, c, h, o);
958
988
  }
959
989
  }), t && i && o)
960
990
  Object.keys(i).forEach((l) => {
@@ -974,7 +1004,7 @@ class Pn extends x {
974
1004
  for (const l of this.#i)
975
1005
  l.startsWith(`${e}:`) && this.#i.delete(l);
976
1006
  r && (r.querySelectorAll(".cell.editing").forEach((l) => {
977
- l.classList.remove("editing"), it(l.parentElement);
1007
+ l.classList.remove("editing"), dt(l.parentElement);
978
1008
  }), this.requestRender()), this.#s = !0, r || (this.#u(n), this.#s = !1);
979
1009
  }
980
1010
  /**
@@ -982,65 +1012,68 @@ class Pn extends x {
982
1012
  */
983
1013
  #a(e, t, n, i) {
984
1014
  const o = t.field;
985
- if (!I(o) || i[o] === n) return;
986
- i[o] = n;
1015
+ if (!P(o)) return;
1016
+ const r = i[o];
1017
+ if (r === n) return;
987
1018
  const l = !this.#n.has(e);
988
- this.#n.add(e), this.#l();
989
- const d = this.grid.findRenderedRowElement?.(e);
990
- d && d.classList.add("changed"), this.emit("cell-commit", {
1019
+ if (this.emitCancelable("cell-commit", {
991
1020
  row: i,
992
1021
  field: o,
1022
+ oldValue: r,
993
1023
  value: n,
994
1024
  rowIndex: e,
995
1025
  changedRows: this.changedRows,
996
1026
  changedRowIndices: this.changedRowIndices,
997
1027
  firstTimeForRow: l
998
- });
1028
+ })) return;
1029
+ i[o] = n, this.#n.add(e), this.#l();
1030
+ const c = this.grid.findRenderedRowElement?.(e);
1031
+ c && c.classList.add("changed");
999
1032
  }
1000
1033
  /**
1001
1034
  * Inject an editor into a cell.
1002
1035
  */
1003
1036
  #d(e, t, n, i, o, r) {
1004
1037
  if (!n.editable || o.classList.contains("editing")) return;
1005
- const l = I(n.field) ? e[n.field] : void 0;
1038
+ const l = P(n.field) ? e[n.field] : void 0;
1006
1039
  o.classList.add("editing"), this.#i.add(`${t}:${i}`);
1007
1040
  const a = o.parentElement;
1008
- a && nt(a);
1041
+ a && at(a);
1009
1042
  let d = !1;
1010
1043
  const c = (m) => {
1011
1044
  d || this.#e === -1 || this.#a(t, n, m, e);
1012
- }, h = () => {
1013
- d = !0, I(n.field) && (e[n.field] = l);
1014
- }, u = document.createElement("div");
1015
- u.className = "tbw-editor-host", o.innerHTML = "", o.appendChild(u), u.addEventListener("keydown", (m) => {
1016
- m.key === "Enter" && (m.stopPropagation(), m.preventDefault(), d = !0, this.#o(t, !1)), m.key === "Escape" && (m.stopPropagation(), m.preventDefault(), h(), this.#o(t, !0));
1045
+ }, u = () => {
1046
+ d = !0, P(n.field) && (e[n.field] = l);
1047
+ }, h = document.createElement("div");
1048
+ h.className = "tbw-editor-host", o.innerHTML = "", o.appendChild(h), h.addEventListener("keydown", (m) => {
1049
+ m.key === "Enter" && (m.stopPropagation(), m.preventDefault(), d = !0, this.#o(t, !1)), m.key === "Escape" && (m.stopPropagation(), m.preventDefault(), u(), this.#o(t, !0));
1017
1050
  });
1018
- const f = n, g = f.__editorTemplate, p = f.editor || (g ? "template" : tt(n)), w = l;
1051
+ const f = n, g = f.__editorTemplate, p = f.editor || (g ? "template" : lt(n)), b = l;
1019
1052
  if (p === "template" && g)
1020
- this.#f(u, f, e, l, c, h, r, t);
1053
+ this.#f(h, f, e, l, c, u, r, t);
1021
1054
  else if (typeof p == "string") {
1022
1055
  const m = document.createElement(p);
1023
- m.value = w, m.addEventListener("change", () => c(m.value)), u.appendChild(m), r || queueMicrotask(() => {
1024
- u.querySelector(U)?.focus({ preventScroll: !0 });
1056
+ m.value = b, m.addEventListener("change", () => c(m.value)), h.appendChild(m), r || queueMicrotask(() => {
1057
+ h.querySelector(U)?.focus({ preventScroll: !0 });
1025
1058
  });
1026
1059
  } else if (typeof p == "function") {
1027
- const m = { row: e, value: w, field: n.field, column: n, commit: c, cancel: h }, v = p(m);
1028
- typeof v == "string" ? (u.innerHTML = v, ot(u, n, c)) : v instanceof Node && u.appendChild(v), r || queueMicrotask(() => {
1029
- u.querySelector(U)?.focus({ preventScroll: !0 });
1060
+ const m = { row: e, value: b, field: n.field, column: n, commit: c, cancel: u }, w = p(m);
1061
+ typeof w == "string" ? (h.innerHTML = w, ct(h, n, c)) : w instanceof Node && h.appendChild(w), r || queueMicrotask(() => {
1062
+ h.querySelector(U)?.focus({ preventScroll: !0 });
1030
1063
  });
1031
1064
  } else if (p && typeof p == "object") {
1032
- const m = this.grid, v = document.createElement("div");
1033
- v.setAttribute("data-external-editor", ""), v.setAttribute("data-field", n.field), u.appendChild(v);
1034
- const A = { row: e, value: w, field: n.field, column: n, commit: c, cancel: h };
1065
+ const m = this.grid, w = document.createElement("div");
1066
+ w.setAttribute("data-external-editor", ""), w.setAttribute("data-field", n.field), h.appendChild(w);
1067
+ const A = { row: e, value: b, field: n.field, column: n, commit: c, cancel: u };
1035
1068
  if (p.mount)
1036
1069
  try {
1037
- p.mount({ placeholder: v, context: A, spec: p });
1070
+ p.mount({ placeholder: w, context: A, spec: p });
1038
1071
  } catch (q) {
1039
1072
  console.warn(`[tbw-grid] External editor mount error for column '${n.field}':`, q);
1040
1073
  }
1041
1074
  else
1042
1075
  m.dispatchEvent(
1043
- new CustomEvent("mount-external-editor", { detail: { placeholder: v, spec: p, context: A } })
1076
+ new CustomEvent("mount-external-editor", { detail: { placeholder: w, spec: p, context: A } })
1044
1077
  );
1045
1078
  }
1046
1079
  }
@@ -1050,8 +1083,8 @@ class Pn extends x {
1050
1083
  #f(e, t, n, i, o, r, l, a) {
1051
1084
  const d = t.__editorTemplate;
1052
1085
  if (!d) return;
1053
- const c = d.cloneNode(!0), h = t.__compiledEditor;
1054
- h ? c.innerHTML = h({
1086
+ const c = d.cloneNode(!0), u = t.__compiledEditor;
1087
+ u ? c.innerHTML = u({
1055
1088
  row: n,
1056
1089
  value: i,
1057
1090
  field: t.field,
@@ -1060,30 +1093,23 @@ class Pn extends x {
1060
1093
  cancel: r
1061
1094
  }) : c.querySelectorAll("*").forEach((f) => {
1062
1095
  f.childNodes.length === 1 && f.firstChild?.nodeType === Node.TEXT_NODE && (f.textContent = f.textContent?.replace(/{{\s*value\s*}}/g, i == null ? "" : String(i)).replace(/{{\s*row\.([a-zA-Z0-9_]+)\s*}}/g, (g, p) => {
1063
- if (!I(p)) return "";
1064
- const w = n[p];
1065
- return w == null ? "" : String(w);
1096
+ if (!P(p)) return "";
1097
+ const b = n[p];
1098
+ return b == null ? "" : String(b);
1066
1099
  }) || "");
1067
1100
  });
1068
- const u = c.querySelector(
1101
+ const h = c.querySelector(
1069
1102
  "input,textarea,select"
1070
1103
  );
1071
- if (u) {
1072
- u instanceof HTMLInputElement && u.type === "checkbox" ? u.checked = !!i : u.value = String(i ?? "");
1104
+ if (h) {
1105
+ h instanceof HTMLInputElement && h.type === "checkbox" ? h.checked = !!i : h.value = String(i ?? "");
1073
1106
  let f = !1;
1074
- u.addEventListener("blur", () => {
1075
- if (f) return;
1076
- const g = u instanceof HTMLInputElement && u.type === "checkbox" ? u.checked : u.value;
1077
- o(g);
1078
- }), u.addEventListener("keydown", (g) => {
1107
+ h.addEventListener("blur", () => {
1108
+ f || o(K(h, t));
1109
+ }), h.addEventListener("keydown", (g) => {
1079
1110
  const p = g;
1080
- if (p.key === "Enter") {
1081
- p.stopPropagation(), p.preventDefault(), f = !0;
1082
- const w = u instanceof HTMLInputElement && u.type === "checkbox" ? u.checked : u.value;
1083
- o(w), this.#o(a, !1);
1084
- }
1085
- p.key === "Escape" && (p.stopPropagation(), p.preventDefault(), r(), this.#o(a, !0));
1086
- }), u instanceof HTMLInputElement && u.type === "checkbox" && u.addEventListener("change", () => o(u.checked)), l || setTimeout(() => u.focus({ preventScroll: !0 }), 0);
1111
+ p.key === "Enter" && (p.stopPropagation(), p.preventDefault(), f = !0, o(K(h, t)), this.#o(a, !1)), p.key === "Escape" && (p.stopPropagation(), p.preventDefault(), r(), this.#o(a, !0));
1112
+ }), h instanceof HTMLInputElement && h.type === "checkbox" && h.addEventListener("change", () => o(h.checked)), l || setTimeout(() => h.focus({ preventScroll: !0 }), 0);
1087
1113
  }
1088
1114
  e.appendChild(c);
1089
1115
  }
@@ -1107,7 +1133,7 @@ class Pn extends x {
1107
1133
  }
1108
1134
  // #endregion
1109
1135
  }
1110
- function ve(s, e = !0) {
1136
+ function we(s, e = !0) {
1111
1137
  if (s == null) return "";
1112
1138
  if (s instanceof Date) return s.toISOString();
1113
1139
  if (typeof s == "object") return JSON.stringify(s);
@@ -1115,37 +1141,37 @@ function ve(s, e = !0) {
1115
1141
  return e && (t.includes(",") || t.includes('"') || t.includes(`
1116
1142
  `) || t.includes("\r")) ? `"${t.replace(/"/g, '""')}"` : t;
1117
1143
  }
1118
- function rt(s, e, t, n = {}) {
1144
+ function ut(s, e, t, n = {}) {
1119
1145
  const i = n.delimiter ?? ",", o = n.newline ?? `
1120
1146
  `, r = [], l = n.bom ? "\uFEFF" : "";
1121
1147
  if (t.includeHeaders !== !1) {
1122
1148
  const a = e.map((d) => {
1123
- const c = d.header || d.field, h = t.processHeader ? t.processHeader(c, d.field) : c;
1124
- return ve(h);
1149
+ const c = d.header || d.field, u = t.processHeader ? t.processHeader(c, d.field) : c;
1150
+ return we(u);
1125
1151
  });
1126
1152
  r.push(a.join(i));
1127
1153
  }
1128
1154
  for (const a of s) {
1129
1155
  const d = e.map((c) => {
1130
- let h = a[c.field];
1131
- return t.processCell && (h = t.processCell(h, c.field, a)), ve(h);
1156
+ let u = a[c.field];
1157
+ return t.processCell && (u = t.processCell(u, c.field, a)), we(u);
1132
1158
  });
1133
1159
  r.push(d.join(i));
1134
1160
  }
1135
1161
  return l + r.join(o);
1136
1162
  }
1137
- function se(s, e) {
1163
+ function re(s, e) {
1138
1164
  const t = URL.createObjectURL(s), n = document.createElement("a");
1139
1165
  n.href = t, n.download = e, n.style.display = "none", document.body.appendChild(n), n.click(), document.body.removeChild(n), URL.revokeObjectURL(t);
1140
1166
  }
1141
- function st(s, e) {
1167
+ function ht(s, e) {
1142
1168
  const t = new Blob([s], { type: "text/csv;charset=utf-8;" });
1143
- se(t, e);
1169
+ re(t, e);
1144
1170
  }
1145
- function ye(s) {
1171
+ function be(s) {
1146
1172
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
1147
1173
  }
1148
- function lt(s, e, t) {
1174
+ function ft(s, e, t) {
1149
1175
  let n = `<?xml version="1.0" encoding="UTF-8"?>
1150
1176
  <?mso-application progid="Excel.Sheet"?>
1151
1177
  <Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
@@ -1157,7 +1183,7 @@ function lt(s, e, t) {
1157
1183
  <Row>`;
1158
1184
  for (const i of e) {
1159
1185
  const o = i.header || i.field, r = t.processHeader ? t.processHeader(o, i.field) : o;
1160
- n += `<Cell><Data ss:Type="String">${ye(r)}</Data></Cell>`;
1186
+ n += `<Cell><Data ss:Type="String">${be(r)}</Data></Cell>`;
1161
1187
  }
1162
1188
  n += "</Row>";
1163
1189
  }
@@ -1168,7 +1194,7 @@ function lt(s, e, t) {
1168
1194
  let r = i[o.field];
1169
1195
  t.processCell && (r = t.processCell(r, o.field, i));
1170
1196
  let l = "String", a = "";
1171
- r == null ? a = "" : typeof r == "number" && !isNaN(r) ? (l = "Number", a = String(r)) : r instanceof Date ? (l = "DateTime", a = r.toISOString()) : a = ye(String(r)), n += `<Cell><Data ss:Type="${l}">${a}</Data></Cell>`;
1197
+ r == null ? a = "" : typeof r == "number" && !isNaN(r) ? (l = "Number", a = String(r)) : r instanceof Date ? (l = "DateTime", a = r.toISOString()) : a = be(String(r)), n += `<Cell><Data ss:Type="${l}">${a}</Data></Cell>`;
1172
1198
  }
1173
1199
  n += "</Row>";
1174
1200
  }
@@ -1177,15 +1203,14 @@ function lt(s, e, t) {
1177
1203
  </Worksheet>
1178
1204
  </Workbook>`, n;
1179
1205
  }
1180
- function at(s, e) {
1206
+ function gt(s, e) {
1181
1207
  const t = e.endsWith(".xls") ? e : `${e}.xls`, n = new Blob([s], {
1182
1208
  type: "application/vnd.ms-excel;charset=utf-8;"
1183
1209
  });
1184
- se(n, t);
1210
+ re(n, t);
1185
1211
  }
1186
- class qn extends x {
1212
+ class Bn extends x {
1187
1213
  name = "export";
1188
- version = "1.0.0";
1189
1214
  get defaultConfig() {
1190
1215
  return {
1191
1216
  fileName: "export",
@@ -1217,34 +1242,34 @@ class qn extends x {
1217
1242
  let r = [...this.rows];
1218
1243
  if (n.onlySelected) {
1219
1244
  const a = this.getSelectionState();
1220
- a?.selected?.size && (r = [...a.selected].sort((c, h) => c - h).map((c) => this.rows[c]).filter(Boolean));
1245
+ a?.selected?.size && (r = [...a.selected].sort((c, u) => c - u).map((c) => this.rows[c]).filter(Boolean));
1221
1246
  }
1222
1247
  t?.rowIndices && (r = t.rowIndices.map((a) => this.rows[a]).filter(Boolean)), this.isExportingFlag = !0;
1223
1248
  let l = i.fileName;
1224
1249
  try {
1225
1250
  switch (e) {
1226
1251
  case "csv": {
1227
- const a = rt(r, o, i, { bom: !0 });
1228
- l = l.endsWith(".csv") ? l : `${l}.csv`, st(a, l);
1252
+ const a = ut(r, o, i, { bom: !0 });
1253
+ l = l.endsWith(".csv") ? l : `${l}.csv`, ht(a, l);
1229
1254
  break;
1230
1255
  }
1231
1256
  case "excel": {
1232
- const a = lt(r, o, i);
1233
- l = l.endsWith(".xls") ? l : `${l}.xls`, at(a, l);
1257
+ const a = ft(r, o, i);
1258
+ l = l.endsWith(".xls") ? l : `${l}.xls`, gt(a, l);
1234
1259
  break;
1235
1260
  }
1236
1261
  case "json": {
1237
- const a = r.map((h) => {
1238
- const u = {};
1262
+ const a = r.map((u) => {
1263
+ const h = {};
1239
1264
  for (const f of o) {
1240
- let g = h[f.field];
1241
- i.processCell && (g = i.processCell(g, f.field, h)), u[f.field] = g;
1265
+ let g = u[f.field];
1266
+ i.processCell && (g = i.processCell(g, f.field, u)), h[f.field] = g;
1242
1267
  }
1243
- return u;
1268
+ return h;
1244
1269
  }), d = JSON.stringify(a, null, 2);
1245
1270
  l = l.endsWith(".json") ? l : `${l}.json`;
1246
1271
  const c = new Blob([d], { type: "application/json" });
1247
- se(c, l);
1272
+ re(c, l);
1248
1273
  break;
1249
1274
  }
1250
1275
  }
@@ -1304,7 +1329,7 @@ class qn extends x {
1304
1329
  }
1305
1330
  // #endregion
1306
1331
  }
1307
- function dt(s) {
1332
+ function pt(s) {
1308
1333
  const { totalRows: e, viewportHeight: t, scrollTop: n, rowHeight: i, overscan: o } = s, r = Math.ceil(t / i);
1309
1334
  let l = Math.floor(n / i) - o;
1310
1335
  l < 0 && (l = 0);
@@ -1316,10 +1341,10 @@ function dt(s) {
1316
1341
  totalHeight: e * i
1317
1342
  };
1318
1343
  }
1319
- function ct(s, e) {
1344
+ function mt(s, e) {
1320
1345
  return s <= e;
1321
1346
  }
1322
- function ut(s, e, t = !1) {
1347
+ function wt(s, e, t = !1) {
1323
1348
  const n = s[e.field];
1324
1349
  if (e.operator === "blank")
1325
1350
  return n == null || n === "";
@@ -1361,10 +1386,10 @@ function ut(s, e, t = !1) {
1361
1386
  return !0;
1362
1387
  }
1363
1388
  }
1364
- function ht(s, e, t = !1) {
1365
- return e.length ? s.filter((n) => e.every((i) => ut(n, i, t))) : s;
1389
+ function bt(s, e, t = !1) {
1390
+ return e.length ? s.filter((n) => e.every((i) => wt(n, i, t))) : s;
1366
1391
  }
1367
- function ft(s) {
1392
+ function vt(s) {
1368
1393
  return JSON.stringify(
1369
1394
  s.map((e) => ({
1370
1395
  field: e.field,
@@ -1374,7 +1399,7 @@ function ft(s) {
1374
1399
  }))
1375
1400
  );
1376
1401
  }
1377
- function xe(s, e) {
1402
+ function ve(s, e) {
1378
1403
  const t = /* @__PURE__ */ new Set();
1379
1404
  for (const n of s) {
1380
1405
  const i = n[e];
@@ -1382,10 +1407,10 @@ function xe(s, e) {
1382
1407
  }
1383
1408
  return [...t].sort((n, i) => typeof n == "number" && typeof i == "number" ? n - i : String(n).localeCompare(String(i)));
1384
1409
  }
1385
- const gt = ':host .tbw-quick-filter-input{flex:1;max-width:300px;height:28px;padding:0 8px;border:1px solid var(--tbw-color-border);border-radius:var(--tbw-border-radius);background:var(--tbw-color-bg);color:var(--tbw-color-fg);font-size:13px}:host .tbw-quick-filter-input:focus{outline:none;border-color:var(--tbw-color-accent)}:host .header-cell.filtered:before{content:"";position:absolute;top:4px;right:4px;width:6px;height:6px;background:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));border-radius:50%}:host .tbw-filter-btn{display:inline-flex;align-items:center;justify-content:center;background:transparent;border:none;cursor:pointer;padding:2px;margin-left:4px;opacity:.4;transition:opacity .15s;color:inherit;vertical-align:middle}:host .tbw-filter-btn:hover,:host .tbw-filter-btn.active{opacity:1}:host .tbw-filter-btn.active{color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6))}', pt = ".tbw-filter-panel{position:fixed;background:var(--tbw-filter-panel-bg, var(--tbw-color-panel-bg, light-dark(#eeeeee, #222222)));color:var(--tbw-filter-panel-fg, var(--tbw-color-fg, light-dark(#222222, #eeeeee)));border:1px solid var(--tbw-filter-panel-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));border-radius:var(--tbw-filter-panel-radius, var(--tbw-border-radius, 4px));box-shadow:0 4px 16px var(--tbw-filter-panel-shadow, var(--tbw-color-shadow, light-dark(rgba(0, 0, 0, .1), rgba(0, 0, 0, .3))));padding:12px;z-index:10000;min-width:200px;max-width:280px;max-height:350px;display:flex;flex-direction:column;font-family:var(--tbw-font-family, system-ui, sans-serif);font-size:var(--tbw-font-size, 13px)}.tbw-filter-search{margin-bottom:8px}.tbw-filter-search-input{width:100%;padding:6px 10px;background:var(--tbw-filter-input-bg, var(--tbw-color-bg, transparent));color:inherit;border:1px solid var(--tbw-filter-input-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));border-radius:var(--tbw-filter-input-radius, 4px);font-size:inherit;box-sizing:border-box}.tbw-filter-search-input:focus{outline:none;border-color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));box-shadow:0 0 0 2px rgba(from var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6)) r g b / 15%)}.tbw-filter-actions{display:flex;padding:4px 2px;margin-bottom:8px;border-bottom:1px solid var(--tbw-filter-divider, var(--tbw-color-border, light-dark(#d0d0d4, #454545)))}.tbw-filter-action-btn{background:transparent;border:none;color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));cursor:pointer;font-size:12px;padding:2px 0}.tbw-filter-action-btn:hover{text-decoration:underline}.tbw-filter-values{flex:1;overflow-y:auto;margin-bottom:8px;max-height:180px;position:relative}.tbw-filter-values-spacer{width:1px}.tbw-filter-values-content{position:absolute;top:0;left:0;right:0}.tbw-filter-value-item{display:flex;align-items:center;gap:8px;padding:4px 2px;cursor:pointer;border-radius:3px}.tbw-filter-value-item:hover{background:var(--tbw-filter-hover, var(--tbw-color-row-hover, light-dark(#f0f6ff, #1c1c1c)))}.tbw-filter-checkbox{margin:0;cursor:pointer;accent-color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6))}.tbw-filter-no-match{color:var(--tbw-filter-muted, var(--tbw-color-fg-muted, light-dark(#555555, #aaaaaa)));padding:8px 0;text-align:center;font-style:italic}.tbw-filter-buttons{display:flex;gap:8px;padding-top:8px;border-top:1px solid var(--tbw-filter-divider, var(--tbw-color-border, light-dark(#d0d0d4, #454545)))}.tbw-filter-apply-btn{flex:1;padding:6px 12px;background:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));color:var(--tbw-filter-accent-fg, var(--tbw-color-accent-fg, light-dark(#ffffff, #000000)));border:none;border-radius:4px;cursor:pointer;font-size:13px}.tbw-filter-apply-btn:hover{filter:brightness(.9)}.tbw-filter-clear-btn{flex:1;padding:6px 12px;background:transparent;color:var(--tbw-filter-muted, var(--tbw-color-fg-muted, light-dark(#555555, #aaaaaa)));border:1px solid var(--tbw-filter-input-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));border-radius:4px;cursor:pointer;font-size:13px}.tbw-filter-clear-btn:hover{background:var(--tbw-filter-hover, var(--tbw-color-row-hover, light-dark(#f0f6ff, #1c1c1c)))}";
1386
- class _ extends x {
1410
+ const yt = ':host .tbw-quick-filter-input{flex:1;max-width:300px;height:28px;padding:0 8px;border:1px solid var(--tbw-color-border);border-radius:var(--tbw-border-radius);background:var(--tbw-color-bg);color:var(--tbw-color-fg);font-size:13px}:host .tbw-quick-filter-input:focus{outline:none;border-color:var(--tbw-color-accent)}:host .header-cell.filtered:before{content:"";position:absolute;top:4px;right:4px;width:6px;height:6px;background:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));border-radius:50%}:host .tbw-filter-btn{display:inline-flex;align-items:center;justify-content:center;background:transparent;border:none;cursor:pointer;padding:2px;margin-left:4px;opacity:.4;transition:opacity .15s;color:inherit;vertical-align:middle}:host .tbw-filter-btn:hover,:host .tbw-filter-btn.active{opacity:1}:host .tbw-filter-btn.active{color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6))}', xt = ".tbw-filter-panel{position:fixed;background:var(--tbw-filter-panel-bg, var(--tbw-color-panel-bg, light-dark(#eeeeee, #222222)));color:var(--tbw-filter-panel-fg, var(--tbw-color-fg, light-dark(#222222, #eeeeee)));border:1px solid var(--tbw-filter-panel-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));border-radius:var(--tbw-filter-panel-radius, var(--tbw-border-radius, 4px));box-shadow:0 4px 16px var(--tbw-filter-panel-shadow, var(--tbw-color-shadow, light-dark(rgba(0, 0, 0, .1), rgba(0, 0, 0, .3))));padding:12px;z-index:10000;min-width:200px;max-width:280px;max-height:350px;display:flex;flex-direction:column;font-family:var(--tbw-font-family, system-ui, sans-serif);font-size:var(--tbw-font-size, 13px)}.tbw-filter-search{margin-bottom:8px}.tbw-filter-search-input{width:100%;padding:6px 10px;background:var(--tbw-filter-input-bg, var(--tbw-color-bg, transparent));color:inherit;border:1px solid var(--tbw-filter-input-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));border-radius:var(--tbw-filter-input-radius, 4px);font-size:inherit;box-sizing:border-box}.tbw-filter-search-input:focus{outline:none;border-color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));box-shadow:0 0 0 2px rgba(from var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6)) r g b / 15%)}.tbw-filter-actions{display:flex;padding:4px 2px;margin-bottom:8px;border-bottom:1px solid var(--tbw-filter-divider, var(--tbw-color-border, light-dark(#d0d0d4, #454545)))}.tbw-filter-action-btn{background:transparent;border:none;color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));cursor:pointer;font-size:12px;padding:2px 0}.tbw-filter-action-btn:hover{text-decoration:underline}.tbw-filter-values{flex:1;overflow-y:auto;margin-bottom:8px;max-height:180px;position:relative}.tbw-filter-values-spacer{width:1px}.tbw-filter-values-content{position:absolute;top:0;left:0;right:0}.tbw-filter-value-item{display:flex;align-items:center;gap:8px;padding:4px 2px;cursor:pointer;border-radius:3px}.tbw-filter-value-item:hover{background:var(--tbw-filter-hover, var(--tbw-color-row-hover, light-dark(#f0f6ff, #1c1c1c)))}.tbw-filter-checkbox{margin:0;cursor:pointer;accent-color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6))}.tbw-filter-no-match{color:var(--tbw-filter-muted, var(--tbw-color-fg-muted, light-dark(#555555, #aaaaaa)));padding:8px 0;text-align:center;font-style:italic}.tbw-filter-buttons{display:flex;gap:8px;padding-top:8px;border-top:1px solid var(--tbw-filter-divider, var(--tbw-color-border, light-dark(#d0d0d4, #454545)))}.tbw-filter-apply-btn{flex:1;padding:6px 12px;background:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));color:var(--tbw-filter-accent-fg, var(--tbw-color-accent-fg, light-dark(#ffffff, #000000)));border:none;border-radius:4px;cursor:pointer;font-size:13px}.tbw-filter-apply-btn:hover{filter:brightness(.9)}.tbw-filter-clear-btn{flex:1;padding:6px 12px;background:transparent;color:var(--tbw-filter-muted, var(--tbw-color-fg-muted, light-dark(#555555, #aaaaaa)));border:1px solid var(--tbw-filter-input-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));border-radius:4px;cursor:pointer;font-size:13px}.tbw-filter-clear-btn:hover{background:var(--tbw-filter-hover, var(--tbw-color-row-hover, light-dark(#f0f6ff, #1c1c1c)))}";
1411
+ class L extends x {
1387
1412
  name = "filtering";
1388
- version = "1.0.0";
1413
+ styles = yt;
1389
1414
  get defaultConfig() {
1390
1415
  return {
1391
1416
  debounceMs: 300,
@@ -1410,6 +1435,12 @@ class _ extends x {
1410
1435
  static LIST_OVERSCAN = 3;
1411
1436
  static LIST_BYPASS_THRESHOLD = 50;
1412
1437
  // Don't virtualize if < 50 items
1438
+ /**
1439
+ * Sync excludedValues map from a filter model (for set filters).
1440
+ */
1441
+ syncExcludedValues(e, t) {
1442
+ t ? t.type === "set" && t.operator === "notIn" && Array.isArray(t.value) ? this.excludedValues.set(e, new Set(t.value)) : t.type === "set" && this.excludedValues.delete(e) : this.excludedValues.delete(e);
1443
+ }
1413
1444
  // #endregion
1414
1445
  // #region Lifecycle
1415
1446
  attach(e) {
@@ -1425,10 +1456,10 @@ class _ extends x {
1425
1456
  if (!t.length) return [...e];
1426
1457
  if (this.config.filterHandler)
1427
1458
  return this.cachedResult ? this.cachedResult : [...e];
1428
- const n = ft(t);
1459
+ const n = vt(t);
1429
1460
  if (this.cacheKey === n && this.cachedResult)
1430
1461
  return this.cachedResult;
1431
- const i = ht([...e], t, this.config.caseSensitive);
1462
+ const i = bt([...e], t, this.config.caseSensitive);
1432
1463
  return this.cachedResult = i, this.cacheKey = n, i;
1433
1464
  }
1434
1465
  afterRender() {
@@ -1461,7 +1492,13 @@ class _ extends x {
1461
1492
  * Pass null to remove the filter.
1462
1493
  */
1463
1494
  setFilter(e, t) {
1464
- t === null ? (this.filters.delete(e), this.excludedValues.delete(e)) : (this.filters.set(e, { ...t, field: e }), t.type === "set" && t.operator === "notIn" && Array.isArray(t.value) ? this.excludedValues.set(e, new Set(t.value)) : t.type === "set" && this.excludedValues.delete(e)), this.cachedResult = null, this.cacheKey = null, this.emit("filter-change", {
1495
+ if (t === null)
1496
+ this.filters.delete(e), this.syncExcludedValues(e, null);
1497
+ else {
1498
+ const n = { ...t, field: e };
1499
+ this.filters.set(e, n), this.syncExcludedValues(e, n);
1500
+ }
1501
+ this.cachedResult = null, this.cacheKey = null, this.emit("filter-change", {
1465
1502
  filters: [...this.filters.values()],
1466
1503
  filteredRowCount: 0
1467
1504
  // Will be accurate after processRows
@@ -1491,7 +1528,7 @@ class _ extends x {
1491
1528
  setFilterModel(e) {
1492
1529
  this.filters.clear(), this.excludedValues.clear();
1493
1530
  for (const t of e)
1494
- this.filters.set(t.field, t), t.type === "set" && t.operator === "notIn" && Array.isArray(t.value) && this.excludedValues.set(t.field, new Set(t.value));
1531
+ this.filters.set(t.field, t), this.syncExcludedValues(t.field, t);
1495
1532
  this.cachedResult = null, this.cacheKey = null, this.emit("filter-change", {
1496
1533
  filters: [...this.filters.values()],
1497
1534
  filteredRowCount: 0
@@ -1532,7 +1569,7 @@ class _ extends x {
1532
1569
  * Uses sourceRows to include all values regardless of current filter.
1533
1570
  */
1534
1571
  getUniqueValues(e) {
1535
- return xe(this.sourceRows, e);
1572
+ return ve(this.sourceRows, e);
1536
1573
  }
1537
1574
  // #endregion
1538
1575
  // #region Private Methods
@@ -1546,7 +1583,7 @@ class _ extends x {
1546
1583
  return;
1547
1584
  }
1548
1585
  const e = document.createElement("style");
1549
- e.id = "tbw-filter-panel-styles", e.textContent = pt, document.head.appendChild(e), this.globalStylesInjected = !0;
1586
+ e.id = "tbw-filter-panel-styles", e.textContent = xt, document.head.appendChild(e), this.globalStylesInjected = !0;
1550
1587
  }
1551
1588
  /**
1552
1589
  * Toggle the filter panel for a field
@@ -1564,7 +1601,7 @@ class _ extends x {
1564
1601
  });
1565
1602
  return;
1566
1603
  }
1567
- const o = xe(this.sourceRows, e);
1604
+ const o = ve(this.sourceRows, e);
1568
1605
  this.renderPanelContent(e, t, i, o), document.body.appendChild(i), this.positionPanel(i, n), this.setupPanelCloseHandler(i, n);
1569
1606
  }
1570
1607
  /**
@@ -1582,8 +1619,8 @@ class _ extends x {
1582
1619
  applySetFilter: (d) => {
1583
1620
  this.applySetFilter(e, d), this.closeFilterPanel();
1584
1621
  },
1585
- applyTextFilter: (d, c, h) => {
1586
- this.applyTextFilter(e, d, c, h), this.closeFilterPanel();
1622
+ applyTextFilter: (d, c, u) => {
1623
+ this.applyTextFilter(e, d, c, u), this.closeFilterPanel();
1587
1624
  },
1588
1625
  clearFilter: () => {
1589
1626
  this.clearFieldFilter(e), this.closeFilterPanel();
@@ -1637,17 +1674,17 @@ class _ extends x {
1637
1674
  d.className = "tbw-filter-value-item", d.style.padding = "0", d.style.margin = "0";
1638
1675
  const c = document.createElement("input");
1639
1676
  c.type = "checkbox", c.className = "tbw-filter-checkbox";
1640
- const h = document.createElement("span");
1641
- h.textContent = "Select All", d.appendChild(c), d.appendChild(h), a.appendChild(d);
1642
- const u = () => {
1643
- const b = [...w.values()], R = b.every((C) => C), E = b.every((C) => !C);
1677
+ const u = document.createElement("span");
1678
+ u.textContent = "Select All", d.appendChild(c), d.appendChild(u), a.appendChild(d);
1679
+ const h = () => {
1680
+ const v = [...b.values()], R = v.every((C) => C), E = v.every((C) => !C);
1644
1681
  c.checked = R, c.indeterminate = !R && !E;
1645
1682
  };
1646
1683
  c.addEventListener("change", () => {
1647
- const b = c.checked;
1648
- for (const R of w.keys())
1649
- w.set(R, b);
1650
- u(), A();
1684
+ const v = c.checked;
1685
+ for (const R of b.keys())
1686
+ b.set(R, v);
1687
+ h(), A();
1651
1688
  }), e.appendChild(a);
1652
1689
  const f = document.createElement("div");
1653
1690
  f.className = "tbw-filter-values";
@@ -1655,44 +1692,44 @@ class _ extends x {
1655
1692
  g.className = "tbw-filter-values-spacer", f.appendChild(g);
1656
1693
  const p = document.createElement("div");
1657
1694
  p.className = "tbw-filter-values-content", f.appendChild(p);
1658
- const w = /* @__PURE__ */ new Map();
1659
- n.forEach((b) => {
1660
- const R = b == null ? "__null__" : String(b);
1661
- w.set(R, !i.has(b));
1662
- }), u();
1695
+ const b = /* @__PURE__ */ new Map();
1696
+ n.forEach((v) => {
1697
+ const R = v == null ? "__null__" : String(v);
1698
+ b.set(R, !i.has(v));
1699
+ }), h();
1663
1700
  let m = [];
1664
- const v = (b, R) => {
1665
- const E = b == null ? "(Blank)" : String(b), C = b == null ? "__null__" : String(b), y = document.createElement("label");
1666
- y.className = "tbw-filter-value-item", y.style.position = "absolute", y.style.top = `${R * _.LIST_ITEM_HEIGHT}px`, y.style.left = "0", y.style.right = "0", y.style.height = `${_.LIST_ITEM_HEIGHT}px`, y.style.boxSizing = "border-box";
1701
+ const w = (v, R) => {
1702
+ const E = v == null ? "(Blank)" : String(v), C = v == null ? "__null__" : String(v), y = document.createElement("label");
1703
+ y.className = "tbw-filter-value-item", y.style.position = "absolute", y.style.top = `${R * L.LIST_ITEM_HEIGHT}px`, y.style.left = "0", y.style.right = "0", y.style.height = `${L.LIST_ITEM_HEIGHT}px`, y.style.boxSizing = "border-box";
1667
1704
  const S = document.createElement("input");
1668
- S.type = "checkbox", S.className = "tbw-filter-checkbox", S.checked = w.get(C) ?? !0, S.dataset.value = C, S.addEventListener("change", () => {
1669
- w.set(C, S.checked), u();
1705
+ S.type = "checkbox", S.className = "tbw-filter-checkbox", S.checked = b.get(C) ?? !0, S.dataset.value = C, S.addEventListener("change", () => {
1706
+ b.set(C, S.checked), h();
1670
1707
  });
1671
- const de = document.createElement("span");
1672
- return de.textContent = E, y.appendChild(S), y.appendChild(de), y;
1708
+ const ae = document.createElement("span");
1709
+ return ae.textContent = E, y.appendChild(S), y.appendChild(ae), y;
1673
1710
  }, A = () => {
1674
- const b = m.length, R = f.clientHeight, E = f.scrollTop;
1675
- if (g.style.height = `${b * _.LIST_ITEM_HEIGHT}px`, ct(b, _.LIST_BYPASS_THRESHOLD / 3)) {
1711
+ const v = m.length, R = f.clientHeight, E = f.scrollTop;
1712
+ if (g.style.height = `${v * L.LIST_ITEM_HEIGHT}px`, mt(v, L.LIST_BYPASS_THRESHOLD / 3)) {
1676
1713
  p.innerHTML = "", p.style.transform = "translateY(0px)", m.forEach((y, S) => {
1677
- p.appendChild(v(y, S));
1714
+ p.appendChild(w(y, S));
1678
1715
  });
1679
1716
  return;
1680
1717
  }
1681
- const C = dt({
1682
- totalRows: b,
1718
+ const C = pt({
1719
+ totalRows: v,
1683
1720
  viewportHeight: R,
1684
1721
  scrollTop: E,
1685
- rowHeight: _.LIST_ITEM_HEIGHT,
1686
- overscan: _.LIST_OVERSCAN
1722
+ rowHeight: L.LIST_ITEM_HEIGHT,
1723
+ overscan: L.LIST_OVERSCAN
1687
1724
  });
1688
1725
  p.style.transform = `translateY(${C.offsetY}px)`, p.innerHTML = "";
1689
1726
  for (let y = C.start; y < C.end; y++)
1690
- p.appendChild(v(m[y], y - C.start));
1691
- }, q = (b) => {
1692
- const R = b.toLowerCase();
1727
+ p.appendChild(w(m[y], y - C.start));
1728
+ }, q = (v) => {
1729
+ const R = v.toLowerCase();
1693
1730
  if (m = n.filter((E) => {
1694
1731
  const C = E == null ? "(Blank)" : String(E);
1695
- return !b || C.toLowerCase().includes(R);
1732
+ return !v || C.toLowerCase().includes(R);
1696
1733
  }), m.length === 0) {
1697
1734
  g.style.height = "0px", p.innerHTML = "";
1698
1735
  const E = document.createElement("div");
@@ -1708,31 +1745,31 @@ class _ extends x {
1708
1745
  },
1709
1746
  { passive: !0 }
1710
1747
  ), q(l.value), e.appendChild(f);
1711
- let ae;
1748
+ let le;
1712
1749
  l.addEventListener("input", () => {
1713
- clearTimeout(ae), ae = setTimeout(() => {
1750
+ clearTimeout(le), le = setTimeout(() => {
1714
1751
  this.searchText.set(o, l.value), q(l.value);
1715
1752
  }, this.config.debounceMs ?? 150);
1716
1753
  });
1717
1754
  const N = document.createElement("div");
1718
1755
  N.className = "tbw-filter-buttons";
1719
- const K = document.createElement("button");
1720
- K.className = "tbw-filter-apply-btn", K.textContent = "Apply", K.addEventListener("click", () => {
1721
- const b = [];
1722
- for (const [R, E] of w)
1756
+ const H = document.createElement("button");
1757
+ H.className = "tbw-filter-apply-btn", H.textContent = "Apply", H.addEventListener("click", () => {
1758
+ const v = [];
1759
+ for (const [R, E] of b)
1723
1760
  if (!E)
1724
1761
  if (R === "__null__")
1725
- b.push(null);
1762
+ v.push(null);
1726
1763
  else {
1727
1764
  const C = n.find((y) => String(y) === R);
1728
- b.push(C !== void 0 ? C : R);
1765
+ v.push(C !== void 0 ? C : R);
1729
1766
  }
1730
- t.applySetFilter(b);
1731
- }), N.appendChild(K);
1732
- const D = document.createElement("button");
1733
- D.className = "tbw-filter-clear-btn", D.textContent = "Clear Filter", D.addEventListener("click", () => {
1767
+ t.applySetFilter(v);
1768
+ }), N.appendChild(H);
1769
+ const O = document.createElement("button");
1770
+ O.className = "tbw-filter-clear-btn", O.textContent = "Clear Filter", O.addEventListener("click", () => {
1734
1771
  t.clearFilter();
1735
- }), N.appendChild(D), e.appendChild(N);
1772
+ }), N.appendChild(O), e.appendChild(N);
1736
1773
  }
1737
1774
  /**
1738
1775
  * Apply a set filter (exclude values)
@@ -1815,11 +1852,8 @@ class _ extends x {
1815
1852
  this.filters.set(e, n), this.cachedResult = null, this.cacheKey = null;
1816
1853
  }
1817
1854
  // #endregion
1818
- // #region Styles
1819
- styles = gt;
1820
- // #endregion
1821
1855
  }
1822
- function mt(s) {
1856
+ function ye(s) {
1823
1857
  if (!s.length) return [];
1824
1858
  const e = /* @__PURE__ */ new Map(), t = [], n = (r, l) => {
1825
1859
  if (!l.length) return;
@@ -1854,7 +1888,7 @@ function mt(s) {
1854
1888
  }, e.set(d, c), t.push(c)), c.columns.push(r);
1855
1889
  }), i.length && n(o, i), t.length === 1 && t[0].implicit && t[0].columns.length === s.length ? [] : t;
1856
1890
  }
1857
- function wt(s, e, t) {
1891
+ function Ct(s, e, t) {
1858
1892
  if (!e.length || !s) return;
1859
1893
  const n = /* @__PURE__ */ new Map();
1860
1894
  for (const o of e)
@@ -1870,23 +1904,25 @@ function wt(s, e, t) {
1870
1904
  l && l.classList.add("group-end");
1871
1905
  }
1872
1906
  }
1873
- function bt(s, e) {
1907
+ function Rt(s, e) {
1874
1908
  if (s.length === 0) return null;
1875
1909
  const t = document.createElement("div");
1876
1910
  t.className = "header-group-row", t.setAttribute("role", "row");
1877
1911
  for (const n of s) {
1878
- const i = n.firstIndex != null ? n.firstIndex : e.findIndex((a) => n.columns.includes(a)), o = String(n.id).startsWith("__implicit__"), r = o ? "" : n.label || n.id, l = document.createElement("div");
1879
- l.className = "cell header-group-cell", o && l.classList.add("implicit-group"), l.setAttribute("data-group", String(n.id)), l.style.gridColumn = `${i + 1} / span ${n.columns.length}`, l.textContent = r, t.appendChild(l);
1912
+ const i = n.columns[0], o = i ? e.findIndex((d) => d.field === i.field) : -1;
1913
+ if (o === -1) continue;
1914
+ const r = String(n.id).startsWith("__implicit__"), l = r ? "" : n.label || n.id, a = document.createElement("div");
1915
+ a.className = "cell header-group-cell", r && a.classList.add("implicit-group"), a.setAttribute("data-group", String(n.id)), a.style.gridColumn = `${o + 1} / span ${n.columns.length}`, a.textContent = l, t.appendChild(a);
1880
1916
  }
1881
1917
  return t;
1882
1918
  }
1883
- function vt(s) {
1919
+ function Et(s) {
1884
1920
  return s.some((e) => e.group != null);
1885
1921
  }
1886
- const yt = ".header-group-row{display:grid;grid-auto-flow:column;background:var(--tbw-grouping-columns-header-bg, var(--tbw-color-header-bg));border-bottom:1px solid var(--tbw-grouping-columns-border, var(--tbw-color-border))}.header-group-cell{display:flex;align-items:center;justify-content:center;padding:4px 8px;font-weight:600;font-size:.9em;text-transform:uppercase;letter-spacing:.5px;border-right:1px solid var(--tbw-grouping-columns-border, var(--tbw-color-border))}.header-group-cell:last-child{border-right:none}.header-row .cell.grouped{border-top:none}.header-row .cell.group-end{border-right:2px solid var(--tbw-grouping-columns-separator, var(--tbw-color-border-strong))}.header-row .cell.group-end:last-child{border-right:none}.header-group-row.no-borders{border-bottom:none}.header-group-row.no-borders .header-group-cell{border-right:none}.header-row.no-group-borders .cell.group-end{border-right:1px solid var(--tbw-color-border)}";
1887
- class Nn extends x {
1922
+ const St = ".header-group-row{display:grid;grid-auto-flow:column;background:var(--tbw-grouping-columns-header-bg, var(--tbw-color-header-bg));border-bottom:1px solid var(--tbw-grouping-columns-border, var(--tbw-color-border))}.header-group-cell{display:flex;align-items:center;justify-content:center;padding:4px 8px;font-weight:600;font-size:.9em;text-transform:uppercase;letter-spacing:.5px;border-right:1px solid var(--tbw-grouping-columns-border, var(--tbw-color-border))}.header-group-cell:last-child{border-right:none}.header-row .cell.grouped{border-top:none}.header-row .cell.group-end{border-right:2px solid var(--tbw-grouping-columns-separator, var(--tbw-color-border-strong))}.header-row .cell.group-end:last-child{border-right:none}.header-group-row.no-borders{border-bottom:none}.header-group-row.no-borders .header-group-cell{border-right:none}.header-row.no-group-borders .cell.group-end{border-right:1px solid var(--tbw-color-border)}";
1923
+ class Vn extends x {
1888
1924
  name = "groupingColumns";
1889
- version = "1.0.0";
1925
+ styles = St;
1890
1926
  get defaultConfig() {
1891
1927
  return {
1892
1928
  showGroupBorders: !0
@@ -1910,7 +1946,7 @@ class Nn extends x {
1910
1946
  if (t?.columnGroups && Array.isArray(t.columnGroups) && t.columnGroups.length > 0)
1911
1947
  return !0;
1912
1948
  const n = t?.columns;
1913
- return Array.isArray(n) ? vt(n) : !1;
1949
+ return Array.isArray(n) ? Et(n) : !1;
1914
1950
  }
1915
1951
  // #endregion
1916
1952
  // #region Hooks
@@ -1928,27 +1964,29 @@ class Nn extends x {
1928
1964
  });
1929
1965
  } else
1930
1966
  n = [...e];
1931
- const i = mt(n);
1967
+ const i = ye(n);
1932
1968
  return i.length === 0 ? (this.isActive = !1, this.groups = [], n) : (this.isActive = !0, this.groups = i, n);
1933
1969
  }
1934
1970
  afterRender() {
1935
- if (!this.isActive || this.groups.length === 0) {
1936
- const r = this.shadowRoot?.querySelector(".header")?.querySelector(".header-group-row");
1937
- r && r.remove();
1971
+ if (!this.isActive) {
1972
+ const a = this.shadowRoot?.querySelector(".header")?.querySelector(".header-group-row");
1973
+ a && a.remove();
1938
1974
  return;
1939
1975
  }
1940
1976
  const e = this.shadowRoot?.querySelector(".header");
1941
1977
  if (!e) return;
1942
1978
  const t = e.querySelector(".header-group-row");
1943
1979
  t && t.remove();
1944
- const n = bt(this.groups, this.columns);
1945
- if (n) {
1946
- n.classList.toggle("no-borders", !this.config.showGroupBorders);
1947
- const o = e.querySelector(".header-row");
1948
- o ? e.insertBefore(n, o) : e.appendChild(n);
1980
+ const n = this.columns, i = ye(n);
1981
+ if (i.length === 0) return;
1982
+ const o = Rt(i, n);
1983
+ if (o) {
1984
+ o.classList.toggle("no-borders", !this.config.showGroupBorders);
1985
+ const l = e.querySelector(".header-row");
1986
+ l ? e.insertBefore(o, l) : e.appendChild(o);
1949
1987
  }
1950
- const i = e.querySelector(".header-row");
1951
- i && (i.classList.toggle("no-group-borders", !this.config.showGroupBorders), wt(i, this.groups, this.columns));
1988
+ const r = e.querySelector(".header-row");
1989
+ r && (r.classList.toggle("no-group-borders", !this.config.showGroupBorders), Ct(r, i));
1952
1990
  }
1953
1991
  // #endregion
1954
1992
  // #region Public API
@@ -1982,11 +2020,8 @@ class Nn extends x {
1982
2020
  this.requestRender();
1983
2021
  }
1984
2022
  // #endregion
1985
- // #region Styles
1986
- styles = yt;
1987
- // #endregion
1988
2023
  }
1989
- function xt({ rows: s, config: e, expanded: t }) {
2024
+ function kt({ rows: s, config: e, expanded: t }) {
1990
2025
  const n = e.groupOn;
1991
2026
  if (typeof n != "function")
1992
2027
  return [];
@@ -1995,10 +2030,10 @@ function xt({ rows: s, config: e, expanded: t }) {
1995
2030
  let a = n(l);
1996
2031
  a == null || a === !1 ? a = ["__ungrouped__"] : Array.isArray(a) || (a = [a]);
1997
2032
  let d = i;
1998
- a.forEach((c, h) => {
1999
- const u = c == null ? "∅" : String(c), f = d.key === "__root__" ? u : d.key + "||" + u;
2000
- let g = d.children.get(u);
2001
- g || (g = { key: f, value: c, depth: h, rows: [], children: /* @__PURE__ */ new Map(), parent: d }, d.children.set(u, g)), d = g;
2033
+ a.forEach((c, u) => {
2034
+ const h = c == null ? "∅" : String(c), f = d.key === "__root__" ? h : d.key + "||" + h;
2035
+ let g = d.children.get(h);
2036
+ g || (g = { key: f, value: c, depth: u, rows: [], children: /* @__PURE__ */ new Map(), parent: d }, d.children.set(h, g)), d = g;
2002
2037
  }), d.rows.push(l);
2003
2038
  }), i.children.size === 1 && i.children.has("__ungrouped__") && i.children.get("__ungrouped__").rows.length === s.length)
2004
2039
  return [];
@@ -2019,26 +2054,26 @@ function xt({ rows: s, config: e, expanded: t }) {
2019
2054
  };
2020
2055
  return r(i), o;
2021
2056
  }
2022
- function Ct(s, e) {
2057
+ function At(s, e) {
2023
2058
  const t = new Set(s);
2024
2059
  return t.has(e) ? t.delete(e) : t.add(e), t;
2025
2060
  }
2026
- function Rt(s) {
2061
+ function _t(s) {
2027
2062
  const e = /* @__PURE__ */ new Set();
2028
2063
  for (const t of s)
2029
2064
  t.kind === "group" && e.add(t.key);
2030
2065
  return e;
2031
2066
  }
2032
- function Et() {
2067
+ function Lt() {
2033
2068
  return /* @__PURE__ */ new Set();
2034
2069
  }
2035
- function St(s) {
2070
+ function Tt(s) {
2036
2071
  return s.kind !== "group" ? 0 : s.rows.length;
2037
2072
  }
2038
- const kt = '.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;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}}';
2039
- class Kn extends x {
2073
+ const It = '.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;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}}';
2074
+ class zn extends x {
2040
2075
  name = "groupingRows";
2041
- version = "1.0.0";
2076
+ styles = It;
2042
2077
  get defaultConfig() {
2043
2078
  return {
2044
2079
  defaultExpanded: !1,
@@ -2056,15 +2091,12 @@ class Kn extends x {
2056
2091
  keysToAnimate = /* @__PURE__ */ new Set();
2057
2092
  // #endregion
2058
2093
  // #region Animation
2094
+ /**
2095
+ * Get expand/collapse animation style from plugin config.
2096
+ * Uses base class isAnimationEnabled to respect grid-level settings.
2097
+ */
2059
2098
  get animationStyle() {
2060
- const t = this.grid.effectiveConfig?.animation?.mode ?? "reduced-motion";
2061
- if (t === !1 || t === "off") return !1;
2062
- if (t !== !0 && t !== "on") {
2063
- const n = this.shadowRoot?.host;
2064
- if (n && getComputedStyle(n).getPropertyValue("--tbw-animation-enabled").trim() === "0")
2065
- return !1;
2066
- }
2067
- return this.config.animation ?? "slide";
2099
+ return this.isAnimationEnabled ? this.config.animation ?? "slide" : !1;
2068
2100
  }
2069
2101
  // #endregion
2070
2102
  // #region Lifecycle
@@ -2084,7 +2116,7 @@ class Kn extends x {
2084
2116
  const t = this.config;
2085
2117
  if (typeof t.groupOn != "function")
2086
2118
  return this.isActive = !1, this.flattenedRows = [], [...e];
2087
- const n = xt({
2119
+ const n = kt({
2088
2120
  rows: [...e],
2089
2121
  config: t,
2090
2122
  expanded: this.expandedKeys
@@ -2105,7 +2137,7 @@ class Kn extends x {
2105
2137
  __groupDepth: o.depth,
2106
2138
  __groupRows: o.rows,
2107
2139
  __groupExpanded: o.expanded,
2108
- __groupRowCount: St(o)
2140
+ __groupRowCount: Tt(o)
2109
2141
  } : o.row);
2110
2142
  }
2111
2143
  onCellClick(e) {
@@ -2113,6 +2145,12 @@ class Kn extends x {
2113
2145
  if (t?.__isGroupRow && e.originalEvent.target?.closest(".group-toggle"))
2114
2146
  return this.toggle(t.__groupKey), !0;
2115
2147
  }
2148
+ onKeyDown(e) {
2149
+ if (e.key !== " ") return;
2150
+ const t = this.grid._focusRow, n = this.rows[t];
2151
+ if (n?.__isGroupRow)
2152
+ return e.preventDefault(), this.toggle(n.__groupKey), this.requestRenderWithFocus(), !0;
2153
+ }
2116
2154
  /**
2117
2155
  * Render a row. Returns true if we handled the row (group row), false otherwise.
2118
2156
  */
@@ -2132,12 +2170,12 @@ class Kn extends x {
2132
2170
  toggleExpand: l
2133
2171
  });
2134
2172
  if (a)
2135
- return t.className = "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;
2173
+ 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;
2136
2174
  }
2137
2175
  const o = () => {
2138
2176
  this.toggle(e.__groupKey);
2139
2177
  };
2140
- 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) * (i.indentWidth ?? 20)}px`, t.innerHTML = "", i.fullWidth !== !1 ? this.renderFullWidthGroupRow(e, t, o) : this.renderPerColumnGroupRow(e, t, o), !0;
2178
+ 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) * (i.indentWidth ?? 20)}px`, t.innerHTML = "", i.fullWidth !== !1 ? this.renderFullWidthGroupRow(e, t, o) : this.renderPerColumnGroupRow(e, t, o), !0;
2141
2179
  }
2142
2180
  afterRender() {
2143
2181
  const e = this.animationStyle;
@@ -2153,52 +2191,63 @@ class Kn extends x {
2153
2191
  }
2154
2192
  // #endregion
2155
2193
  // #region Private Rendering Helpers
2194
+ /**
2195
+ * Create a toggle button for expanding/collapsing a group.
2196
+ */
2197
+ createToggleButton(e, t) {
2198
+ const n = document.createElement("button");
2199
+ return n.type = "button", n.className = `group-toggle${e ? " expanded" : ""}`, n.setAttribute("aria-label", e ? "Collapse group" : "Expand group"), this.setIcon(n, this.resolveIcon(e ? "collapse" : "expand")), n.addEventListener("click", (i) => {
2200
+ i.stopPropagation(), t();
2201
+ }), n;
2202
+ }
2203
+ /**
2204
+ * Get the formatted label text for a group.
2205
+ */
2206
+ getGroupLabelText(e, t, n) {
2207
+ const i = this.config;
2208
+ return i.formatLabel ? i.formatLabel(e, t, n) : String(e);
2209
+ }
2156
2210
  renderFullWidthGroupRow(e, t, n) {
2157
2211
  const i = this.config, o = document.createElement("div");
2158
- o.className = "cell group-full", o.style.gridColumn = "1 / -1", o.setAttribute("role", "gridcell");
2159
- const r = document.createElement("button");
2160
- r.type = "button", r.className = `group-toggle${e.__groupExpanded ? " expanded" : ""}`, r.setAttribute("aria-label", e.__groupExpanded ? "Collapse group" : "Expand group"), this.setIcon(r, this.resolveIcon(e.__groupExpanded ? "collapse" : "expand")), r.addEventListener("click", (d) => {
2161
- d.stopPropagation(), n();
2162
- }), o.appendChild(r);
2163
- const l = document.createElement("span");
2164
- l.className = "group-label";
2165
- const a = i.formatLabel ? i.formatLabel(e.__groupValue, e.__groupDepth || 0, e.__groupKey) : String(e.__groupValue);
2166
- if (l.textContent = a, o.appendChild(l), i.showRowCount !== !1) {
2167
- const d = document.createElement("span");
2168
- d.className = "group-count", d.textContent = `(${e.__groupRowCount ?? e.__groupRows?.length ?? 0})`, o.appendChild(d);
2212
+ o.className = "cell group-full", o.style.gridColumn = "1 / -1", o.setAttribute("role", "gridcell"), o.setAttribute("data-col", "0"), o.appendChild(this.createToggleButton(e.__groupExpanded, n));
2213
+ const r = document.createElement("span");
2214
+ if (r.className = "group-label", r.textContent = this.getGroupLabelText(e.__groupValue, e.__groupDepth || 0, e.__groupKey), o.appendChild(r), i.showRowCount !== !1) {
2215
+ const l = document.createElement("span");
2216
+ l.className = "group-count", l.textContent = `(${e.__groupRowCount ?? e.__groupRows?.length ?? 0})`, o.appendChild(l);
2169
2217
  }
2170
2218
  t.appendChild(o);
2171
2219
  }
2172
2220
  renderPerColumnGroupRow(e, t, n) {
2173
2221
  const i = this.config, o = i.aggregators ?? {}, r = this.columns, l = e.__groupRows ?? [], d = this.shadowRoot?.querySelector(".body")?.style.gridTemplateColumns || "";
2174
- d && (t.style.display = "grid", t.style.gridTemplateColumns = d), r.forEach((c, h) => {
2175
- const u = document.createElement("div");
2176
- if (u.className = "cell group-cell", u.setAttribute("data-col", String(h)), u.setAttribute("role", "gridcell"), h === 0) {
2177
- const f = document.createElement("button");
2178
- f.type = "button", f.className = `group-toggle${e.__groupExpanded ? " expanded" : ""}`, f.setAttribute("aria-label", e.__groupExpanded ? "Collapse group" : "Expand group"), this.setIcon(f, this.resolveIcon(e.__groupExpanded ? "collapse" : "expand")), f.addEventListener("click", (w) => {
2179
- w.stopPropagation(), n();
2180
- }), u.appendChild(f);
2181
- const g = document.createElement("span"), p = o[c.field];
2182
- if (p) {
2183
- const w = ce(p, l, c.field, c);
2184
- g.textContent = w != null ? String(w) : String(e.__groupValue);
2185
- } else {
2186
- const w = i.formatLabel ? i.formatLabel(e.__groupValue, e.__groupDepth || 0, e.__groupKey) : String(e.__groupValue);
2187
- g.textContent = w;
2188
- }
2189
- if (u.appendChild(g), i.showRowCount !== !1) {
2190
- const w = document.createElement("span");
2191
- w.className = "group-count", w.textContent = ` (${l.length})`, u.appendChild(w);
2192
- }
2222
+ d && (t.style.display = "grid", t.style.gridTemplateColumns = d);
2223
+ let c = !1;
2224
+ r.forEach((u, h) => {
2225
+ const f = document.createElement("div");
2226
+ if (f.className = "cell group-cell", f.setAttribute("data-col", String(h)), f.setAttribute("role", "gridcell"), ie(u)) {
2227
+ f.setAttribute("data-field", u.field), t.appendChild(f);
2228
+ return;
2229
+ }
2230
+ if (c) {
2231
+ const g = o[u.field];
2232
+ if (g) {
2233
+ const p = de(g, l, u.field, u);
2234
+ f.textContent = p != null ? String(p) : "";
2235
+ } else
2236
+ f.textContent = "";
2193
2237
  } else {
2194
- const f = o[c.field];
2195
- if (f) {
2196
- const g = ce(f, l, c.field, c);
2197
- u.textContent = g != null ? String(g) : "";
2238
+ c = !0, f.appendChild(this.createToggleButton(e.__groupExpanded, n));
2239
+ const g = document.createElement("span"), p = o[u.field];
2240
+ if (p) {
2241
+ const b = de(p, l, u.field, u);
2242
+ g.textContent = b != null ? String(b) : String(e.__groupValue);
2198
2243
  } else
2199
- u.textContent = "";
2244
+ g.textContent = this.getGroupLabelText(e.__groupValue, e.__groupDepth || 0, e.__groupKey);
2245
+ if (f.appendChild(g), i.showRowCount !== !1) {
2246
+ const b = document.createElement("span");
2247
+ b.className = "group-count", b.textContent = ` (${l.length})`, f.appendChild(b);
2248
+ }
2200
2249
  }
2201
- t.appendChild(u);
2250
+ t.appendChild(f);
2202
2251
  });
2203
2252
  }
2204
2253
  // #endregion
@@ -2207,20 +2256,20 @@ class Kn extends x {
2207
2256
  * Expand all groups.
2208
2257
  */
2209
2258
  expandAll() {
2210
- this.expandedKeys = Rt(this.flattenedRows), this.requestRender();
2259
+ this.expandedKeys = _t(this.flattenedRows), this.requestRender();
2211
2260
  }
2212
2261
  /**
2213
2262
  * Collapse all groups.
2214
2263
  */
2215
2264
  collapseAll() {
2216
- this.expandedKeys = Et(), this.requestRender();
2265
+ this.expandedKeys = Lt(), this.requestRender();
2217
2266
  }
2218
2267
  /**
2219
2268
  * Toggle expansion of a specific group.
2220
2269
  * @param key - The group key to toggle
2221
2270
  */
2222
2271
  toggle(e) {
2223
- this.expandedKeys = Ct(this.expandedKeys, e);
2272
+ this.expandedKeys = At(this.expandedKeys, e);
2224
2273
  const t = this.flattenedRows.find((n) => n.kind === "group" && n.key === e);
2225
2274
  this.emit("group-toggle", {
2226
2275
  key: e,
@@ -2310,26 +2359,23 @@ class Kn extends x {
2310
2359
  this.config.groupOn = e, this.requestRender();
2311
2360
  }
2312
2361
  // #endregion
2313
- // #region Styles
2314
- styles = kt;
2315
- // #endregion
2316
2362
  }
2317
- function Z(s, e) {
2363
+ function xe(s, e) {
2318
2364
  const t = new Set(s);
2319
2365
  return t.has(e) ? t.delete(e) : t.add(e), t;
2320
2366
  }
2321
- function At(s, e) {
2367
+ function Ft(s, e) {
2322
2368
  const t = new Set(s);
2323
2369
  return t.add(e), t;
2324
2370
  }
2325
- function _t(s, e) {
2371
+ function Mt(s, e) {
2326
2372
  const t = new Set(s);
2327
2373
  return t.delete(e), t;
2328
2374
  }
2329
- function Lt(s, e) {
2375
+ function Pt(s, e) {
2330
2376
  return s.has(e);
2331
2377
  }
2332
- function Tt(s, e, t, n) {
2378
+ function Dt(s, e, t, n) {
2333
2379
  const i = document.createElement("div");
2334
2380
  i.className = "master-detail-row", i.setAttribute("data-detail-for", String(e)), i.setAttribute("role", "row");
2335
2381
  const o = document.createElement("div");
@@ -2337,10 +2383,10 @@ function Tt(s, e, t, n) {
2337
2383
  const r = t(s, e);
2338
2384
  return typeof r == "string" ? o.innerHTML = r : r instanceof HTMLElement && o.appendChild(r), i.appendChild(o), i;
2339
2385
  }
2340
- const It = ".master-detail-cell-wrapper{display:flex;align-items:center;gap:4px}.master-detail-toggle{cursor:pointer;opacity:.7;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}}";
2341
- class Dn extends x {
2386
+ const Kt = ".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;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}}";
2387
+ class Ge extends x {
2342
2388
  name = "masterDetail";
2343
- version = "1.0.0";
2389
+ styles = Kt;
2344
2390
  get defaultConfig() {
2345
2391
  return {
2346
2392
  detailHeight: "auto",
@@ -2388,50 +2434,29 @@ class Dn extends x {
2388
2434
  if (!t) return;
2389
2435
  const n = e;
2390
2436
  if (n.__frameworkAdapter?.parseDetailElement) {
2391
- const h = n.__frameworkAdapter.parseDetailElement(t);
2392
- if (h) {
2393
- this.config = { ...this.config, detailRenderer: h };
2437
+ const u = n.__frameworkAdapter.parseDetailElement(t);
2438
+ if (u) {
2439
+ this.config = { ...this.config, detailRenderer: u };
2394
2440
  return;
2395
2441
  }
2396
2442
  }
2397
2443
  const i = t.getAttribute("animation"), o = t.getAttribute("show-expand-column"), r = t.getAttribute("expand-on-row-click"), l = t.getAttribute("collapse-on-click-outside"), a = t.getAttribute("height"), d = {};
2398
2444
  i !== null && (d.animation = i === "false" ? !1 : i), o !== null && (d.showExpandColumn = o !== "false"), r !== null && (d.expandOnRowClick = r === "true"), l !== null && (d.collapseOnClickOutside = l === "true"), a !== null && (d.detailHeight = a === "auto" ? "auto" : parseInt(a, 10));
2399
2445
  const c = t.innerHTML.trim();
2400
- c && !this.config.detailRenderer && (d.detailRenderer = (h, u) => {
2401
- const f = $e(c, { value: h, row: h });
2402
- return We(f);
2446
+ c && !this.config.detailRenderer && (d.detailRenderer = (u, h) => {
2447
+ const f = je(c, { value: u, row: u });
2448
+ return Ue(f);
2403
2449
  }), Object.keys(d).length > 0 && (this.config = { ...this.config, ...d });
2404
2450
  }
2405
2451
  // #endregion
2406
2452
  // #region Animation Helpers
2407
- /**
2408
- * Check if animations are enabled at the grid level.
2409
- * Respects gridConfig.animation.mode and CSS variable.
2410
- */
2411
- get isAnimationEnabled() {
2412
- const t = this.grid.effectiveConfig?.animation?.mode ?? "reduced-motion";
2413
- if (t === !1 || t === "off") return !1;
2414
- if (t === !0 || t === "on") return !0;
2415
- const n = this.shadowRoot?.host;
2416
- return n ? getComputedStyle(n).getPropertyValue("--tbw-animation-enabled").trim() !== "0" : !0;
2417
- }
2418
2453
  /**
2419
2454
  * Get expand/collapse animation style from plugin config.
2455
+ * Uses base class isAnimationEnabled to respect grid-level settings.
2420
2456
  */
2421
2457
  get animationStyle() {
2422
2458
  return this.isAnimationEnabled ? this.config.animation ?? "slide" : !1;
2423
2459
  }
2424
- /**
2425
- * Get animation duration from CSS variable (set by grid).
2426
- */
2427
- get animationDuration() {
2428
- const e = this.shadowRoot?.host;
2429
- if (e) {
2430
- const t = getComputedStyle(e).getPropertyValue("--tbw-animation-duration").trim(), n = parseInt(t, 10);
2431
- if (!isNaN(n)) return n;
2432
- }
2433
- return 200;
2434
- }
2435
2460
  /**
2436
2461
  * Apply expand animation to a detail element.
2437
2462
  */
@@ -2462,6 +2487,25 @@ class Dn extends x {
2462
2487
  // #region Internal State
2463
2488
  expandedRows = /* @__PURE__ */ new Set();
2464
2489
  detailElements = /* @__PURE__ */ new Map();
2490
+ /** Default height for detail rows when not configured */
2491
+ static DEFAULT_DETAIL_HEIGHT = 150;
2492
+ /**
2493
+ * Get the estimated height for a detail row.
2494
+ */
2495
+ getDetailHeight(e) {
2496
+ const t = this.detailElements.get(e);
2497
+ return t ? t.offsetHeight : typeof this.config?.detailHeight == "number" ? this.config.detailHeight : Ge.DEFAULT_DETAIL_HEIGHT;
2498
+ }
2499
+ /**
2500
+ * Toggle a row's detail and emit event.
2501
+ */
2502
+ toggleAndEmit(e, t) {
2503
+ this.expandedRows = xe(this.expandedRows, e), this.emit("detail-expand", {
2504
+ rowIndex: t,
2505
+ row: e,
2506
+ expanded: this.expandedRows.has(e)
2507
+ }), this.requestRender();
2508
+ }
2465
2509
  // #endregion
2466
2510
  // #region Lifecycle
2467
2511
  detach() {
@@ -2470,49 +2514,36 @@ class Dn extends x {
2470
2514
  // #endregion
2471
2515
  // #region Hooks
2472
2516
  processColumns(e) {
2473
- if (!this.config.detailRenderer)
2517
+ if (!this.config.detailRenderer || this.config.showExpandColumn === !1)
2474
2518
  return [...e];
2475
2519
  const t = [...e];
2476
- if (t.length > 0) {
2477
- const n = { ...t[0] }, i = n.viewRenderer;
2478
- if (i?.__masterDetailWrapped)
2479
- return t;
2480
- const o = (r) => {
2481
- const { value: l, row: a } = r, d = this.expandedRows.has(a), c = document.createElement("span");
2482
- c.className = "master-detail-cell-wrapper";
2483
- const h = document.createElement("span");
2484
- h.className = `master-detail-toggle${d ? " expanded" : ""}`, this.setIcon(h, this.resolveIcon(d ? "collapse" : "expand")), h.setAttribute("role", "button"), h.setAttribute("tabindex", "0"), h.setAttribute("aria-expanded", String(d)), h.setAttribute("aria-label", d ? "Collapse details" : "Expand details"), c.appendChild(h);
2485
- const u = document.createElement("span");
2486
- if (i) {
2487
- const f = i(r);
2488
- f instanceof Node ? u.appendChild(f) : u.textContent = String(f ?? l ?? "");
2489
- } else
2490
- u.textContent = String(l ?? "");
2491
- return c.appendChild(u), c;
2492
- };
2493
- o.__masterDetailWrapped = !0, n.viewRenderer = o, t[0] = n;
2494
- }
2495
- return t;
2520
+ if (Qe(t))
2521
+ return t;
2522
+ const i = et(this.name);
2523
+ return i.viewRenderer = (o) => {
2524
+ const { row: r } = o, l = this.expandedRows.has(r), a = document.createElement("span");
2525
+ a.className = "master-detail-expander expander-cell";
2526
+ const d = document.createElement("span");
2527
+ return d.className = `master-detail-toggle${l ? " expanded" : ""}`, this.setIcon(d, this.resolveIcon(l ? "collapse" : "expand")), d.setAttribute("role", "button"), d.setAttribute("tabindex", "0"), d.setAttribute("aria-expanded", String(l)), d.setAttribute("aria-label", l ? "Collapse details" : "Expand details"), a.appendChild(d), a;
2528
+ }, [i, ...t];
2496
2529
  }
2497
2530
  onRowClick(e) {
2498
2531
  if (!(!this.config.expandOnRowClick || !this.config.detailRenderer))
2499
- return this.expandedRows = Z(this.expandedRows, e.row), this.emit("detail-expand", {
2500
- rowIndex: e.rowIndex,
2501
- row: e.row,
2502
- expanded: this.expandedRows.has(e.row)
2503
- }), this.requestRender(), !1;
2532
+ return this.toggleAndEmit(e.row, e.rowIndex), !1;
2504
2533
  }
2505
2534
  onCellClick(e) {
2506
- if (e.originalEvent?.target?.classList.contains("master-detail-toggle")) {
2507
- const n = e.row, i = e.rowIndex;
2508
- return this.expandedRows = Z(this.expandedRows, n), this.emit("detail-expand", {
2509
- rowIndex: i,
2510
- row: n,
2511
- expanded: this.expandedRows.has(n)
2512
- }), this.requestRender(), !0;
2513
- }
2535
+ if (e.originalEvent?.target?.classList.contains("master-detail-toggle"))
2536
+ return this.toggleAndEmit(e.row, e.rowIndex), !0;
2514
2537
  this.expandedRows.size > 0 && queueMicrotask(() => this.#e());
2515
2538
  }
2539
+ onKeyDown(e) {
2540
+ if (e.key !== " ") return;
2541
+ const t = this.grid._focusCol, n = this.grid._focusRow, i = this.columns[t];
2542
+ if (!i || !ie(i)) return;
2543
+ const o = this.rows[n];
2544
+ if (o)
2545
+ return e.preventDefault(), this.toggleAndEmit(o, n), this.requestRenderWithFocus(), !0;
2546
+ }
2516
2547
  afterRender() {
2517
2548
  this.#e();
2518
2549
  }
@@ -2549,7 +2580,7 @@ class Dn extends x {
2549
2580
  d.previousElementSibling !== l && l.after(d);
2550
2581
  continue;
2551
2582
  }
2552
- const c = Tt(a, r, this.config.detailRenderer, i);
2583
+ const c = Dt(a, r, this.config.detailRenderer, i);
2553
2584
  typeof this.config.detailHeight == "number" && (c.style.height = `${this.config.detailHeight}px`), l.after(c), this.detailElements.set(a, c), this.animateExpand(c);
2554
2585
  }
2555
2586
  }
@@ -2559,15 +2590,8 @@ class Dn extends x {
2559
2590
  */
2560
2591
  getExtraHeight() {
2561
2592
  let e = 0;
2562
- for (const t of this.expandedRows) {
2563
- const n = this.detailElements.get(t);
2564
- if (n)
2565
- e += n.offsetHeight;
2566
- else {
2567
- const i = this.config?.detailHeight;
2568
- e += typeof i == "number" ? i : 150;
2569
- }
2570
- }
2593
+ for (const t of this.expandedRows)
2594
+ e += this.getDetailHeight(t);
2571
2595
  return e;
2572
2596
  }
2573
2597
  /**
@@ -2578,15 +2602,7 @@ class Dn extends x {
2578
2602
  let t = 0;
2579
2603
  for (const n of this.expandedRows) {
2580
2604
  const i = this.rows.indexOf(n);
2581
- if (i >= 0 && i < e) {
2582
- const o = this.detailElements.get(n);
2583
- if (o)
2584
- t += o.offsetHeight;
2585
- else {
2586
- const r = this.config?.detailHeight;
2587
- t += typeof r == "number" ? r : 150;
2588
- }
2589
- }
2605
+ i >= 0 && i < e && (t += this.getDetailHeight(n));
2590
2606
  }
2591
2607
  return t;
2592
2608
  }
@@ -2604,8 +2620,8 @@ class Dn extends x {
2604
2620
  i.sort((l, a) => l.index - a.index);
2605
2621
  let o = e, r = 0;
2606
2622
  for (const { index: l, row: a } of i) {
2607
- const d = l * n + r, h = this.detailElements.get(a)?.offsetHeight ?? (typeof this.config?.detailHeight == "number" ? this.config.detailHeight : 150), u = d + n + h;
2608
- r += h, !(l >= e) && u > t && l < o && (o = l);
2623
+ const d = l * n + r, c = this.getDetailHeight(a), u = d + n + c;
2624
+ r += c, !(l >= e) && u > t && l < o && (o = l);
2609
2625
  }
2610
2626
  return o;
2611
2627
  }
@@ -2617,7 +2633,7 @@ class Dn extends x {
2617
2633
  */
2618
2634
  expand(e) {
2619
2635
  const t = this.rows[e];
2620
- t && (this.expandedRows = At(this.expandedRows, t), this.requestRender());
2636
+ t && (this.expandedRows = Ft(this.expandedRows, t), this.requestRender());
2621
2637
  }
2622
2638
  /**
2623
2639
  * Collapse the detail row at the given index.
@@ -2625,7 +2641,7 @@ class Dn extends x {
2625
2641
  */
2626
2642
  collapse(e) {
2627
2643
  const t = this.rows[e];
2628
- t && (this.expandedRows = _t(this.expandedRows, t), this.requestRender());
2644
+ t && (this.expandedRows = Mt(this.expandedRows, t), this.requestRender());
2629
2645
  }
2630
2646
  /**
2631
2647
  * Toggle the detail row at the given index.
@@ -2633,7 +2649,7 @@ class Dn extends x {
2633
2649
  */
2634
2650
  toggle(e) {
2635
2651
  const t = this.rows[e];
2636
- t && (this.expandedRows = Z(this.expandedRows, t), this.requestRender());
2652
+ t && (this.expandedRows = xe(this.expandedRows, t), this.requestRender());
2637
2653
  }
2638
2654
  /**
2639
2655
  * Check if the detail row at the given index is expanded.
@@ -2642,7 +2658,7 @@ class Dn extends x {
2642
2658
  */
2643
2659
  isExpanded(e) {
2644
2660
  const t = this.rows[e];
2645
- return t ? Lt(this.expandedRows, t) : !1;
2661
+ return t ? Pt(this.expandedRows, t) : !1;
2646
2662
  }
2647
2663
  /**
2648
2664
  * Expand all detail rows.
@@ -2694,24 +2710,21 @@ class Dn extends x {
2694
2710
  }
2695
2711
  }
2696
2712
  // #endregion
2697
- // #region Styles
2698
- styles = It;
2699
- // #endregion
2700
2713
  }
2701
- function Ft(s, e, t) {
2714
+ function qt(s, e, t) {
2702
2715
  return e.length ? [...s].sort((n, i) => {
2703
2716
  for (const o of e) {
2704
- const l = t.find((h) => h.field === o.field)?.sortComparator ?? Mt, a = n[o.field], d = i[o.field], c = l(a, d, n, i);
2717
+ const l = t.find((u) => u.field === o.field)?.sortComparator ?? Nt, a = n[o.field], d = i[o.field], c = l(a, d, n, i);
2705
2718
  if (c !== 0)
2706
2719
  return o.direction === "asc" ? c : -c;
2707
2720
  }
2708
2721
  return 0;
2709
2722
  }) : [...s];
2710
2723
  }
2711
- function Mt(s, e) {
2724
+ function Nt(s, e) {
2712
2725
  return s == null && e == null ? 0 : s == null ? 1 : e == null ? -1 : typeof s == "number" && typeof e == "number" ? s - e : s instanceof Date && e instanceof Date ? s.getTime() - e.getTime() : typeof s == "boolean" && typeof e == "boolean" ? s === e ? 0 : s ? -1 : 1 : String(s).localeCompare(String(e));
2713
2726
  }
2714
- function Pt(s, e, t, n) {
2727
+ function Ht(s, e, t, n) {
2715
2728
  const i = s.find((o) => o.field === e);
2716
2729
  return t ? i ? i.direction === "asc" ? s.map((o) => o.field === e ? { ...o, direction: "desc" } : o) : s.filter((o) => o.field !== e) : s.length < n ? [...s, { field: e, direction: "asc" }] : s : i?.direction === "asc" ? [{ field: e, direction: "desc" }] : i?.direction === "desc" ? [] : [{ field: e, direction: "asc" }];
2717
2730
  }
@@ -2722,10 +2735,10 @@ function Ce(s, e) {
2722
2735
  function Re(s, e) {
2723
2736
  return s.find((t) => t.field === e)?.direction;
2724
2737
  }
2725
- const qt = '.header-cell[data-sort=asc]:after{content:"↑";margin-left:4px;opacity:.8}.header-cell[data-sort=desc]:after{content:"↓";margin-left:4px;opacity:.8}.sort-indicator{margin-left:4px;opacity:.8}.sort-index{font-size:10px;background:var(--tbw-multi-sort-badge-bg, var(--tbw-color-panel-bg));color:var(--tbw-multi-sort-badge-color, var(--tbw-color-fg));border-radius:50%;width:14px;height:14px;display:inline-flex;align-items:center;justify-content:center;margin-left:2px;font-weight:600}';
2726
- class Hn extends x {
2738
+ const Ot = '.header-cell[data-sort=asc]:after{content:"↑";margin-left:4px;opacity:.8}.header-cell[data-sort=desc]:after{content:"↓";margin-left:4px;opacity:.8}.sort-indicator{margin-left:4px;opacity:.8}.sort-index{font-size:10px;background:var(--tbw-multi-sort-badge-bg, var(--tbw-color-panel-bg));color:var(--tbw-multi-sort-badge-color, var(--tbw-color-fg));border-radius:50%;width:14px;height:14px;display:inline-flex;align-items:center;justify-content:center;margin-left:2px;font-weight:600}';
2739
+ class Wn extends x {
2727
2740
  name = "multiSort";
2728
- version = "1.0.0";
2741
+ styles = Ot;
2729
2742
  get defaultConfig() {
2730
2743
  return {
2731
2744
  maxSortColumns: 3,
@@ -2742,12 +2755,12 @@ class Hn extends x {
2742
2755
  // #endregion
2743
2756
  // #region Hooks
2744
2757
  processRows(e) {
2745
- return this.sortModel.length === 0 ? [...e] : Ft([...e], this.sortModel, [...this.columns]);
2758
+ return this.sortModel.length === 0 ? [...e] : qt([...e], this.sortModel, [...this.columns]);
2746
2759
  }
2747
2760
  onHeaderClick(e) {
2748
2761
  if (!this.columns.find((o) => o.field === e.field)?.sortable) return !1;
2749
2762
  const n = e.originalEvent.shiftKey, i = this.config.maxSortColumns ?? 3;
2750
- return this.sortModel = Pt(this.sortModel, e.field, n, i), this.emit("sort-change", { sortModel: [...this.sortModel] }), this.requestRender(), !0;
2763
+ return this.sortModel = Ht(this.sortModel, e.field, n, i), this.emit("sort-change", { sortModel: [...this.sortModel] }), this.requestRender(), !0;
2751
2764
  }
2752
2765
  afterRender() {
2753
2766
  const e = this.shadowRoot;
@@ -2761,7 +2774,7 @@ class Hn extends x {
2761
2774
  i.querySelector('[part~="sort-indicator"], .sort-indicator')?.remove(), i.setAttribute("data-sort", l);
2762
2775
  const c = document.createElement("span");
2763
2776
  c.className = "sort-indicator", this.setIcon(c, this.resolveIcon(l === "asc" ? "sortAsc" : "sortDesc"));
2764
- const h = i.querySelector(".tbw-filter-btn"), u = i.querySelector(".resize-handle"), f = h ?? u;
2777
+ const u = i.querySelector(".tbw-filter-btn"), h = i.querySelector(".resize-handle"), f = u ?? h;
2765
2778
  if (f ? i.insertBefore(c, f) : i.appendChild(c), t && this.sortModel.length > 1 && r !== void 0) {
2766
2779
  const g = document.createElement("span");
2767
2780
  g.className = "sort-index", g.textContent = String(r), c.nextSibling ? i.insertBefore(g, c.nextSibling) : i.appendChild(g);
@@ -2838,14 +2851,11 @@ class Hn extends x {
2838
2851
  n !== -1 ? this.sortModel[n] = i : this.sortModel.splice(t.sort.priority, 0, i);
2839
2852
  }
2840
2853
  // #endregion
2841
- // #region Styles
2842
- styles = qt;
2843
- // #endregion
2844
2854
  }
2845
- function Nt(s) {
2855
+ function Gt(s) {
2846
2856
  return s.filter((e) => e.sticky === "left");
2847
2857
  }
2848
- function Kt(s) {
2858
+ function Bt(s) {
2849
2859
  return s.filter((e) => e.sticky === "right");
2850
2860
  }
2851
2861
  function X(s) {
@@ -2884,9 +2894,8 @@ function Se(s) {
2884
2894
  n.classList.remove("sticky-left", "sticky-right"), n.style.position = "", n.style.left = "", n.style.right = "";
2885
2895
  });
2886
2896
  }
2887
- class On extends x {
2897
+ class $n extends x {
2888
2898
  name = "pinnedColumns";
2889
- version = "1.0.0";
2890
2899
  get defaultConfig() {
2891
2900
  return {};
2892
2901
  }
@@ -2930,7 +2939,7 @@ class On extends x {
2930
2939
  */
2931
2940
  onPluginQuery(e) {
2932
2941
  switch (e.type) {
2933
- case H.CAN_MOVE_COLUMN: {
2942
+ case He.CAN_MOVE_COLUMN: {
2934
2943
  const t = e.context, n = t.sticky;
2935
2944
  if (n === "left" || n === "right")
2936
2945
  return !1;
@@ -2955,14 +2964,14 @@ class On extends x {
2955
2964
  */
2956
2965
  getLeftPinnedColumns() {
2957
2966
  const e = [...this.columns];
2958
- return Nt(e);
2967
+ return Gt(e);
2959
2968
  }
2960
2969
  /**
2961
2970
  * Get columns pinned to the right.
2962
2971
  */
2963
2972
  getRightPinnedColumns() {
2964
2973
  const e = [...this.columns];
2965
- return Kt(e);
2974
+ return Bt(e);
2966
2975
  }
2967
2976
  /**
2968
2977
  * Clear all sticky positioning.
@@ -2996,10 +3005,10 @@ class On extends x {
2996
3005
  }
2997
3006
  // #endregion
2998
3007
  }
2999
- function Dt(s) {
3008
+ function Vt(s) {
3000
3009
  return typeof s == "object" && s !== null && "aggFunc" in s;
3001
3010
  }
3002
- function Y(s, e) {
3011
+ function Z(s, e) {
3003
3012
  const t = document.createElement("div");
3004
3013
  t.className = "tbw-pinned-rows", t.setAttribute("role", "presentation"), t.setAttribute("aria-live", "polite");
3005
3014
  const n = document.createElement("div");
@@ -3021,7 +3030,7 @@ function Y(s, e) {
3021
3030
  }
3022
3031
  if (s.customPanels)
3023
3032
  for (const r of s.customPanels) {
3024
- const l = Ht(r, e);
3033
+ const l = zt(r, e);
3025
3034
  switch (r.position) {
3026
3035
  case "left":
3027
3036
  n.appendChild(l);
@@ -3054,23 +3063,23 @@ function Ae(s, e, t, n) {
3054
3063
  let a, d;
3055
3064
  const c = i.aggregators?.[r.field];
3056
3065
  if (c)
3057
- if (Dt(c)) {
3058
- const h = ue(c.aggFunc);
3059
- h && (a = h(n, r.field, r)), d = c.formatter;
3066
+ if (Vt(c)) {
3067
+ const u = ce(c.aggFunc);
3068
+ u && (a = u(n, r.field, r)), d = c.formatter;
3060
3069
  } else {
3061
- const h = ue(c);
3062
- h && (a = h(n, r.field, r));
3070
+ const u = ce(c);
3071
+ u && (a = u(n, r.field, r));
3063
3072
  }
3064
3073
  else if (i.cells && Object.prototype.hasOwnProperty.call(i.cells, r.field)) {
3065
- const h = i.cells[r.field];
3066
- typeof h == "function" ? a = h(n, r.field, r) : a = h;
3074
+ const u = i.cells[r.field];
3075
+ typeof u == "function" ? a = u(n, r.field, r) : a = u;
3067
3076
  }
3068
3077
  a != null ? l.textContent = d ? d(a, r.field, r) : String(a) : l.textContent = "", o.appendChild(l);
3069
3078
  }
3070
3079
  s.appendChild(o);
3071
3080
  }
3072
3081
  }
3073
- function Ht(s, e) {
3082
+ function zt(s, e) {
3074
3083
  const t = document.createElement("div");
3075
3084
  t.className = "tbw-status-panel tbw-status-panel-custom", t.id = `status-panel-${s.id}`;
3076
3085
  const n = s.render(e);
@@ -3086,10 +3095,10 @@ function _e(s, e, t, n, i) {
3086
3095
  grid: t
3087
3096
  };
3088
3097
  }
3089
- const Ot = ".tbw-footer{flex-shrink:0;z-index:var(--tbw-z-layer-pinned-rows, 20);background:var(--tbw-color-panel-bg)}.tbw-pinned-rows{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;background:var(--tbw-pinned-rows-bg, var(--tbw-color-panel-bg));border-top:1px solid var(--tbw-pinned-rows-border, var(--tbw-color-border));font-size:12px;color:var(--tbw-pinned-rows-color, var(--tbw-color-fg-muted));min-height:32px;box-sizing:border-box;min-width:fit-content}.tbw-pinned-rows-left,.tbw-pinned-rows-center,.tbw-pinned-rows-right{display:flex;align-items:center;gap:16px}.tbw-pinned-rows-left{justify-content:flex-start}.tbw-pinned-rows-center{justify-content:center;flex:1}.tbw-pinned-rows-right{justify-content:flex-end}.tbw-status-panel{white-space:nowrap}.tbw-aggregation-rows{min-width:fit-content;background:var(--tbw-aggregation-bg, var(--tbw-color-header-bg))}.tbw-aggregation-rows-top{border-bottom:1px solid var(--tbw-aggregation-border, var(--tbw-color-border))}.tbw-aggregation-rows-bottom{border-top:1px solid var(--tbw-aggregation-border, var(--tbw-color-border))}.tbw-aggregation-row{display:grid;grid-template-columns:var(--tbw-column-template);font-size:var(--tbw-aggregation-font-size, .8em);font-weight:var(--tbw-aggregation-font-weight, 600)}.tbw-aggregation-cell{padding:var(--tbw-cell-padding, 2px 8px);min-height:var(--tbw-row-height, 28px);display:flex;align-items:center;border-right:1px solid var(--tbw-color-border-cell)}.tbw-aggregation-cell:last-child{border-right:0}.tbw-aggregation-cell-full{grid-column:1 / -1;border-right:0}";
3090
- class Gn extends x {
3098
+ const Wt = ".tbw-footer{flex-shrink:0;z-index:var(--tbw-z-layer-pinned-rows, 20);background:var(--tbw-color-panel-bg)}.tbw-pinned-rows{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;background:var(--tbw-pinned-rows-bg, var(--tbw-color-panel-bg));border-top:1px solid var(--tbw-pinned-rows-border, var(--tbw-color-border));font-size:12px;color:var(--tbw-pinned-rows-color, var(--tbw-color-fg-muted));min-height:32px;box-sizing:border-box;min-width:fit-content}.tbw-pinned-rows-left,.tbw-pinned-rows-center,.tbw-pinned-rows-right{display:flex;align-items:center;gap:16px}.tbw-pinned-rows-left{justify-content:flex-start}.tbw-pinned-rows-center{justify-content:center;flex:1}.tbw-pinned-rows-right{justify-content:flex-end}.tbw-status-panel{white-space:nowrap}.tbw-aggregation-rows{min-width:fit-content;background:var(--tbw-aggregation-bg, var(--tbw-color-header-bg))}.tbw-aggregation-rows-top{border-bottom:1px solid var(--tbw-aggregation-border, var(--tbw-color-border))}.tbw-aggregation-rows-bottom{border-top:1px solid var(--tbw-aggregation-border, var(--tbw-color-border))}.tbw-aggregation-row{display:grid;grid-template-columns:var(--tbw-column-template);font-size:var(--tbw-aggregation-font-size, .8em);font-weight:var(--tbw-aggregation-font-weight, 600)}.tbw-aggregation-cell{padding:var(--tbw-cell-padding, 2px 8px);min-height:var(--tbw-row-height, 28px);display:flex;align-items:center;border-right:1px solid var(--tbw-color-border-cell)}.tbw-aggregation-cell:last-child{border-right:0}.tbw-aggregation-cell-full{grid-column:1 / -1;border-right:0}";
3099
+ class jn extends x {
3091
3100
  name = "pinnedRows";
3092
- version = "1.0.0";
3101
+ styles = Wt;
3093
3102
  get defaultConfig() {
3094
3103
  return {
3095
3104
  position: "bottom",
@@ -3122,12 +3131,12 @@ class Gn extends x {
3122
3131
  this.grid,
3123
3132
  n,
3124
3133
  i
3125
- ), r = this.config.aggregationRows || [], l = r.filter((u) => u.position === "top"), a = r.filter((u) => u.position !== "top");
3134
+ ), r = this.config.aggregationRows || [], l = r.filter((h) => h.position === "top"), a = r.filter((h) => h.position !== "top");
3126
3135
  if (l.length > 0) {
3127
3136
  if (!this.topAggregationContainer) {
3128
3137
  this.topAggregationContainer = ke("top");
3129
- const u = e.querySelector(".header");
3130
- u && u.nextSibling ? t.insertBefore(this.topAggregationContainer, u.nextSibling) : t.appendChild(this.topAggregationContainer);
3138
+ const h = e.querySelector(".header");
3139
+ h && h.nextSibling ? t.insertBefore(this.topAggregationContainer, h.nextSibling) : t.appendChild(this.topAggregationContainer);
3131
3140
  }
3132
3141
  Ae(
3133
3142
  this.topAggregationContainer,
@@ -3136,21 +3145,21 @@ class Gn extends x {
3136
3145
  this.rows
3137
3146
  );
3138
3147
  } else this.topAggregationContainer && (this.topAggregationContainer.remove(), this.topAggregationContainer = null);
3139
- const d = this.config.showRowCount !== !1 || this.config.showSelectedCount && o.selectedRows > 0 || this.config.showFilteredCount && o.filteredRows !== o.totalRows || this.config.customPanels && this.config.customPanels.length > 0, c = d && this.config.position !== "top", h = a.length > 0 || c;
3148
+ const d = this.config.showRowCount !== !1 || this.config.showSelectedCount && o.selectedRows > 0 || this.config.showFilteredCount && o.filteredRows !== o.totalRows || this.config.customPanels && this.config.customPanels.length > 0, c = d && this.config.position !== "top", u = a.length > 0 || c;
3140
3149
  if (d && this.config.position === "top")
3141
3150
  if (!this.infoBarElement)
3142
- this.infoBarElement = Y(this.config, o), t.insertBefore(this.infoBarElement, t.firstChild);
3151
+ this.infoBarElement = Z(this.config, o), t.insertBefore(this.infoBarElement, t.firstChild);
3143
3152
  else {
3144
- const u = Y(this.config, o);
3145
- this.infoBarElement.replaceWith(u), this.infoBarElement = u;
3153
+ const h = Z(this.config, o);
3154
+ this.infoBarElement.replaceWith(h), this.infoBarElement = h;
3146
3155
  }
3147
3156
  else this.config.position === "top" && this.infoBarElement && (this.infoBarElement.remove(), this.infoBarElement = null);
3148
- h ? (this.footerWrapper || (this.footerWrapper = document.createElement("div"), this.footerWrapper.className = "tbw-footer", t.appendChild(this.footerWrapper)), this.footerWrapper.innerHTML = "", a.length > 0 && (this.bottomAggregationContainer || (this.bottomAggregationContainer = ke("bottom")), this.footerWrapper.appendChild(this.bottomAggregationContainer), Ae(
3157
+ u ? (this.footerWrapper || (this.footerWrapper = document.createElement("div"), this.footerWrapper.className = "tbw-footer", t.appendChild(this.footerWrapper)), this.footerWrapper.innerHTML = "", a.length > 0 && (this.bottomAggregationContainer || (this.bottomAggregationContainer = ke("bottom")), this.footerWrapper.appendChild(this.bottomAggregationContainer), Ae(
3149
3158
  this.bottomAggregationContainer,
3150
3159
  a,
3151
3160
  this.visibleColumns,
3152
3161
  this.rows
3153
- )), c && (this.infoBarElement = Y(this.config, o), this.footerWrapper.appendChild(this.infoBarElement))) : this.cleanupFooter();
3162
+ )), c && (this.infoBarElement = Z(this.config, o), this.footerWrapper.appendChild(this.infoBarElement))) : this.cleanupFooter();
3154
3163
  }
3155
3164
  // #endregion
3156
3165
  // #region Private Methods
@@ -3225,20 +3234,17 @@ class Gn extends x {
3225
3234
  this.config.aggregationRows && (this.config.aggregationRows = this.config.aggregationRows.filter((t) => t.id !== e), this.requestRender());
3226
3235
  }
3227
3236
  // #endregion
3228
- // #region Styles
3229
- styles = Ot;
3230
- // #endregion
3231
3237
  }
3232
- const Gt = je;
3233
- function Vt(s) {
3238
+ const $t = Xe;
3239
+ function jt(s) {
3234
3240
  const e = [];
3235
3241
  return !s.rowGroupFields?.length && !s.columnGroupFields?.length && e.push("At least one row or column group field is required"), s.valueFields?.length || e.push("At least one value field is required"), e;
3236
3242
  }
3237
- function le(s, e) {
3243
+ function se(s, e) {
3238
3244
  return [...s, e].join("|");
3239
3245
  }
3240
- function Bt(s, e) {
3241
- const t = e.rowGroupFields ?? [], n = e.columnGroupFields ?? [], i = e.valueFields ?? [], o = zt(s, n), r = Ge(
3246
+ function Ut(s, e) {
3247
+ const t = e.rowGroupFields ?? [], n = e.columnGroupFields ?? [], i = e.valueFields ?? [], o = Xt(s, n), r = Be(
3242
3248
  s,
3243
3249
  t,
3244
3250
  n,
@@ -3248,7 +3254,7 @@ function Bt(s, e) {
3248
3254
  // starting depth
3249
3255
  ""
3250
3256
  // parent key prefix
3251
- ), l = Wt(r, o, i), a = Object.values(l).reduce((d, c) => d + c, 0);
3257
+ ), l = Yt(r, o, i), a = Object.values(l).reduce((d, c) => d + c, 0);
3252
3258
  return {
3253
3259
  rows: r,
3254
3260
  columnKeys: o,
@@ -3256,7 +3262,7 @@ function Bt(s, e) {
3256
3262
  grandTotal: a
3257
3263
  };
3258
3264
  }
3259
- function zt(s, e) {
3265
+ function Xt(s, e) {
3260
3266
  if (e.length === 0) return ["value"];
3261
3267
  const t = /* @__PURE__ */ new Set();
3262
3268
  for (const n of s) {
@@ -3265,7 +3271,7 @@ function zt(s, e) {
3265
3271
  }
3266
3272
  return [...t].sort();
3267
3273
  }
3268
- function $t(s, e) {
3274
+ function Zt(s, e) {
3269
3275
  const t = /* @__PURE__ */ new Map();
3270
3276
  for (const n of s) {
3271
3277
  const i = String(n[e] ?? ""), o = t.get(i);
@@ -3273,25 +3279,25 @@ function $t(s, e) {
3273
3279
  }
3274
3280
  return t;
3275
3281
  }
3276
- function Ge(s, e, t, n, i, o, r) {
3282
+ function Be(s, e, t, n, i, o, r) {
3277
3283
  const l = [];
3278
3284
  if (e.length === 0) {
3279
- const u = Le(s, t, n, i), f = Te(u);
3285
+ const h = Le(s, t, n, i), f = Te(h);
3280
3286
  return l.push({
3281
3287
  rowKey: r || "all",
3282
3288
  rowLabel: r || "All",
3283
3289
  depth: o,
3284
- values: u,
3290
+ values: h,
3285
3291
  total: f,
3286
3292
  isGroup: !1,
3287
3293
  rowCount: s.length
3288
3294
  }), l;
3289
3295
  }
3290
- const a = e[0], d = e.slice(1), c = d.length > 0, h = $t(s, a);
3291
- for (const [u, f] of h) {
3292
- const g = r ? `${r}|${u}` : u, p = Le(f, t, n, i), w = Te(p);
3296
+ const a = e[0], d = e.slice(1), c = d.length > 0, u = Zt(s, a);
3297
+ for (const [h, f] of u) {
3298
+ const g = r ? `${r}|${h}` : h, p = Le(f, t, n, i), b = Te(p);
3293
3299
  let m;
3294
- c && (m = Ge(
3300
+ c && (m = Be(
3295
3301
  f,
3296
3302
  d,
3297
3303
  t,
@@ -3301,10 +3307,10 @@ function Ge(s, e, t, n, i, o, r) {
3301
3307
  g
3302
3308
  )), l.push({
3303
3309
  rowKey: g,
3304
- rowLabel: u || "(blank)",
3310
+ rowLabel: h || "(blank)",
3305
3311
  depth: o,
3306
3312
  values: p,
3307
- total: w,
3313
+ total: b,
3308
3314
  isGroup: c,
3309
3315
  children: m,
3310
3316
  rowCount: f.length
@@ -3316,8 +3322,8 @@ function Le(s, e, t, n) {
3316
3322
  const i = {};
3317
3323
  for (const o of t)
3318
3324
  for (const r of n) {
3319
- const a = (e.length > 0 ? s.filter((u) => e.map((f) => String(u[f] ?? "")).join("|") === o) : s).map((u) => Number(u[r.field]) || 0), d = Gt(r.aggFunc), c = a.length > 0 ? d(a) : null, h = le([o], r.field);
3320
- i[h] = c;
3325
+ const a = (e.length > 0 ? s.filter((h) => e.map((f) => String(h[f] ?? "")).join("|") === o) : s).map((h) => Number(h[r.field]) || 0), d = $t(r.aggFunc), c = a.length > 0 ? d(a) : null, u = se([o], r.field);
3326
+ i[u] = c;
3321
3327
  }
3322
3328
  return i;
3323
3329
  }
@@ -3327,21 +3333,21 @@ function Te(s) {
3327
3333
  e += t ?? 0;
3328
3334
  return e;
3329
3335
  }
3330
- function Wt(s, e, t) {
3336
+ function Yt(s, e, t) {
3331
3337
  const n = {};
3332
3338
  function i(o) {
3333
3339
  for (const r of o)
3334
3340
  if (!r.isGroup || !r.children?.length)
3335
3341
  for (const l of e)
3336
3342
  for (const a of t) {
3337
- const d = le([l], a.field);
3343
+ const d = se([l], a.field);
3338
3344
  n[d] = (n[d] ?? 0) + (r.values[d] ?? 0);
3339
3345
  }
3340
3346
  else r.children && i(r.children);
3341
3347
  }
3342
3348
  return i(s), n;
3343
3349
  }
3344
- function jt(s, e, t = !0) {
3350
+ function Jt(s, e, t = !0) {
3345
3351
  const n = [];
3346
3352
  function i(o) {
3347
3353
  n.push(o);
@@ -3354,7 +3360,7 @@ function jt(s, e, t = !0) {
3354
3360
  i(o);
3355
3361
  return n;
3356
3362
  }
3357
- function J(s) {
3363
+ function Qt(s) {
3358
3364
  const e = [];
3359
3365
  function t(n) {
3360
3366
  if (n.isGroup && e.push(n.rowKey), n.children)
@@ -3365,14 +3371,14 @@ function J(s) {
3365
3371
  t(n);
3366
3372
  return e;
3367
3373
  }
3368
- const Ut = ["sum", "avg", "count", "min", "max", "first", "last"];
3369
- function Zt(s, e, t, n) {
3374
+ const en = ["sum", "avg", "count", "min", "max", "first", "last"];
3375
+ function tn(s, e, t, n) {
3370
3376
  const i = new AbortController(), o = { config: e, callbacks: n, signal: i.signal }, r = document.createElement("div");
3371
- return r.className = "tbw-pivot-panel", r.appendChild(F("Options", () => en(t, o))), r.appendChild(F("Row Groups", () => Ie("rowGroups", o))), r.appendChild(F("Column Groups", () => Ie("columnGroups", o))), r.appendChild(F("Values", () => Yt(o))), r.appendChild(F("Available Fields", () => Qt(o))), s.appendChild(r), () => {
3377
+ return r.className = "tbw-pivot-panel", r.appendChild(D("Options", () => ln(t, o))), r.appendChild(D("Row Groups", () => Ie("rowGroups", o))), r.appendChild(D("Column Groups", () => Ie("columnGroups", o))), r.appendChild(D("Values", () => on(o))), r.appendChild(D("Available Fields", () => sn(o))), s.appendChild(r), () => {
3372
3378
  i.abort(), r.remove();
3373
3379
  };
3374
3380
  }
3375
- function F(s, e) {
3381
+ function D(s, e) {
3376
3382
  const t = document.createElement("div");
3377
3383
  t.className = "tbw-pivot-section";
3378
3384
  const n = document.createElement("div");
@@ -3389,7 +3395,7 @@ function Ie(s, e) {
3389
3395
  l.className = "tbw-pivot-placeholder", l.textContent = "Drag fields here or click to add", o.appendChild(l);
3390
3396
  } else
3391
3397
  for (const l of r)
3392
- o.appendChild(Xt(l, s, e));
3398
+ o.appendChild(nn(l, s, e));
3393
3399
  return o.addEventListener(
3394
3400
  "dragover",
3395
3401
  (l) => {
@@ -3412,7 +3418,7 @@ function Ie(s, e) {
3412
3418
  { signal: i }
3413
3419
  ), o;
3414
3420
  }
3415
- function Xt(s, e, t) {
3421
+ function nn(s, e, t) {
3416
3422
  const { callbacks: n, signal: i } = t, o = document.createElement("div");
3417
3423
  o.className = "tbw-pivot-field-chip", o.draggable = !0;
3418
3424
  const r = n.getAvailableFields().find((d) => d.field === s), l = document.createElement("span");
@@ -3438,7 +3444,7 @@ function Xt(s, e, t) {
3438
3444
  { signal: i }
3439
3445
  ), o;
3440
3446
  }
3441
- function Yt(s) {
3447
+ function on(s) {
3442
3448
  const { config: e, callbacks: t, signal: n } = s, i = document.createElement("div");
3443
3449
  i.className = "tbw-pivot-drop-zone tbw-pivot-values-zone", i.setAttribute("data-zone", "values");
3444
3450
  const o = e.valueFields ?? [];
@@ -3447,7 +3453,7 @@ function Yt(s) {
3447
3453
  r.className = "tbw-pivot-placeholder", r.textContent = "Drag numeric fields here for aggregation", i.appendChild(r);
3448
3454
  } else
3449
3455
  for (const r of o)
3450
- i.appendChild(Jt(r, s));
3456
+ i.appendChild(rn(r, s));
3451
3457
  return i.addEventListener(
3452
3458
  "dragover",
3453
3459
  (r) => {
@@ -3470,7 +3476,7 @@ function Yt(s) {
3470
3476
  { signal: n }
3471
3477
  ), i;
3472
3478
  }
3473
- function Jt(s, e) {
3479
+ function rn(s, e) {
3474
3480
  const { callbacks: t, signal: n } = e, i = document.createElement("div");
3475
3481
  i.className = "tbw-pivot-field-chip tbw-pivot-value-chip";
3476
3482
  const o = t.getAvailableFields().find((c) => c.field === s.field), r = document.createElement("div");
@@ -3479,9 +3485,9 @@ function Jt(s, e) {
3479
3485
  l.className = "tbw-pivot-chip-label", l.textContent = o?.header ?? s.field;
3480
3486
  const a = document.createElement("select");
3481
3487
  a.className = "tbw-pivot-agg-select", a.title = "Aggregation function";
3482
- for (const c of Ut) {
3483
- const h = document.createElement("option");
3484
- h.value = c, h.textContent = c.toUpperCase(), h.selected = c === s.aggFunc, a.appendChild(h);
3488
+ for (const c of en) {
3489
+ const u = document.createElement("option");
3490
+ u.value = c, u.textContent = c.toUpperCase(), u.selected = c === s.aggFunc, a.appendChild(u);
3485
3491
  }
3486
3492
  a.addEventListener(
3487
3493
  "change",
@@ -3499,7 +3505,7 @@ function Jt(s, e) {
3499
3505
  { signal: n }
3500
3506
  ), r.appendChild(l), r.appendChild(a), i.appendChild(r), i.appendChild(d), i;
3501
3507
  }
3502
- function Qt(s) {
3508
+ function sn(s) {
3503
3509
  const { config: e, callbacks: t, signal: n } = s, i = document.createElement("div");
3504
3510
  i.className = "tbw-pivot-available-fields";
3505
3511
  const o = t.getAvailableFields(), r = /* @__PURE__ */ new Set([
@@ -3529,10 +3535,10 @@ function Qt(s) {
3529
3535
  }
3530
3536
  return i;
3531
3537
  }
3532
- function en(s, e) {
3538
+ function ln(s, e) {
3533
3539
  const { config: t, callbacks: n, signal: i } = e, o = document.createElement("div");
3534
3540
  return o.className = "tbw-pivot-options", o.appendChild(
3535
- Q(
3541
+ Y(
3536
3542
  "Enable Pivot View",
3537
3543
  s,
3538
3544
  (r) => {
@@ -3541,7 +3547,7 @@ function en(s, e) {
3541
3547
  i
3542
3548
  )
3543
3549
  ), o.appendChild(
3544
- Q(
3550
+ Y(
3545
3551
  "Show Row Totals",
3546
3552
  t.showTotals ?? !0,
3547
3553
  (r) => {
@@ -3550,7 +3556,7 @@ function en(s, e) {
3550
3556
  i
3551
3557
  )
3552
3558
  ), o.appendChild(
3553
- Q(
3559
+ Y(
3554
3560
  "Show Grand Total",
3555
3561
  t.showGrandTotal ?? !0,
3556
3562
  (r) => {
@@ -3560,7 +3566,7 @@ function en(s, e) {
3560
3566
  )
3561
3567
  ), o;
3562
3568
  }
3563
- function Q(s, e, t, n) {
3569
+ function Y(s, e, t, n) {
3564
3570
  const i = document.createElement("label");
3565
3571
  i.className = "tbw-pivot-checkbox";
3566
3572
  const o = document.createElement("input");
@@ -3568,15 +3574,15 @@ function Q(s, e, t, n) {
3568
3574
  const r = document.createElement("span");
3569
3575
  return r.textContent = s, i.appendChild(o), i.appendChild(r), i;
3570
3576
  }
3571
- function tn(s, e, t) {
3572
- return e.className = "pivot-group-row", e.setAttribute("data-pivot-depth", String(s.__pivotDepth ?? 0)), e.setAttribute("data-pivot-key", String(s.__pivotRowKey ?? "")), e.setAttribute("role", "row"), e.innerHTML = "", t.columns.forEach((n, i) => {
3577
+ function an(s, e, t) {
3578
+ return e.className = "data-grid-row pivot-group-row", e.setAttribute("data-pivot-depth", String(s.__pivotDepth ?? 0)), e.setAttribute("data-pivot-key", String(s.__pivotRowKey ?? "")), e.setAttribute("role", "row"), e.innerHTML = "", t.columns.forEach((n, i) => {
3573
3579
  const o = document.createElement("div");
3574
- if (o.className = "cell", o.setAttribute("data-col", String(i)), o.setAttribute("role", "gridcell"), i === 0) {
3580
+ if (o.className = "cell", o.setAttribute("data-col", String(i)), o.setAttribute("data-row", String(t.rowIndex)), o.setAttribute("role", "gridcell"), i === 0) {
3575
3581
  const r = Number(s.__pivotIndent) || 0;
3576
3582
  o.style.paddingLeft = `${r}px`;
3577
3583
  const l = String(s.__pivotRowKey), a = document.createElement("button");
3578
- a.type = "button", a.className = "pivot-toggle", a.setAttribute("aria-label", s.__pivotExpanded ? "Collapse group" : "Expand group"), t.setIcon(a, t.resolveIcon(s.__pivotExpanded ? "collapse" : "expand")), a.addEventListener("click", (h) => {
3579
- h.stopPropagation(), t.onToggle(l);
3584
+ a.type = "button", a.className = "pivot-toggle", a.setAttribute("aria-label", s.__pivotExpanded ? "Collapse group" : "Expand group"), t.setIcon(a, t.resolveIcon(s.__pivotExpanded ? "collapse" : "expand")), a.addEventListener("click", (u) => {
3585
+ u.stopPropagation(), t.onToggle(l);
3580
3586
  }), o.appendChild(a);
3581
3587
  const d = document.createElement("span");
3582
3588
  d.className = "pivot-label", d.textContent = String(s.__pivotLabel ?? ""), o.appendChild(d);
@@ -3589,22 +3595,22 @@ function tn(s, e, t) {
3589
3595
  e.appendChild(o);
3590
3596
  }), !0;
3591
3597
  }
3592
- function nn(s, e, t) {
3593
- return e.className = "pivot-leaf-row", e.setAttribute("data-pivot-depth", String(s.__pivotDepth ?? 0)), e.setAttribute("data-pivot-key", String(s.__pivotRowKey ?? "")), e.innerHTML = "", t.forEach((n, i) => {
3594
- const o = document.createElement("div");
3595
- if (o.className = "cell", o.setAttribute("data-col", String(i)), o.setAttribute("role", "gridcell"), i === 0) {
3596
- const r = Number(s.__pivotIndent) || 0;
3597
- o.style.paddingLeft = `${r + 20}px`;
3598
- const l = document.createElement("span");
3599
- l.className = "pivot-label", l.textContent = String(s.__pivotLabel ?? ""), o.appendChild(l);
3598
+ function dn(s, e, t, n) {
3599
+ return e.className = "data-grid-row pivot-leaf-row", e.setAttribute("data-pivot-depth", String(s.__pivotDepth ?? 0)), e.setAttribute("data-pivot-key", String(s.__pivotRowKey ?? "")), e.innerHTML = "", t.forEach((i, o) => {
3600
+ const r = document.createElement("div");
3601
+ if (r.className = "cell", r.setAttribute("data-col", String(o)), r.setAttribute("data-row", String(n)), r.setAttribute("role", "gridcell"), o === 0) {
3602
+ const l = Number(s.__pivotIndent) || 0;
3603
+ r.style.paddingLeft = `${l + 20}px`;
3604
+ const a = document.createElement("span");
3605
+ a.className = "pivot-label", a.textContent = String(s.__pivotLabel ?? ""), r.appendChild(a);
3600
3606
  } else {
3601
- const r = s[n.field];
3602
- o.textContent = r != null ? String(r) : "";
3607
+ const l = s[i.field];
3608
+ r.textContent = l != null ? String(l) : "";
3603
3609
  }
3604
- e.appendChild(o);
3610
+ e.appendChild(r);
3605
3611
  }), !0;
3606
3612
  }
3607
- function on(s, e, t) {
3613
+ function cn(s, e, t) {
3608
3614
  return e.className = "pivot-grand-total-row", e.setAttribute("role", "presentation"), e.innerHTML = "", t.forEach((n, i) => {
3609
3615
  const o = document.createElement("div");
3610
3616
  if (o.className = "cell", o.setAttribute("data-col", String(i)), i === 0) {
@@ -3617,10 +3623,10 @@ function on(s, e, t) {
3617
3623
  e.appendChild(o);
3618
3624
  }), !0;
3619
3625
  }
3620
- const rn = '.pivot-group-row{display:grid;grid-template-columns:var(--tbw-column-template);font-weight:600;background:var(--tbw-pivot-group-bg, var(--tbw-color-row-alt));min-height:var(--tbw-row-height);border-bottom:var(--tbw-row-divider)}.pivot-group-row:hover{background:var(--tbw-pivot-group-hover, var(--tbw-color-row-hover))}.pivot-leaf-row{display:grid;grid-template-columns:var(--tbw-column-template);background:var(--tbw-pivot-leaf-bg, var(--tbw-color-bg));min-height:var(--tbw-row-height);border-bottom:var(--tbw-row-divider)}.pivot-grand-total-row{display:grid;grid-template-columns:var(--tbw-column-template);font-weight:700;background:var(--tbw-pivot-grand-total-bg, var(--tbw-color-header-bg));min-height:var(--tbw-row-height);border-top:2px solid var(--tbw-color-border-strong)}.pivot-grand-total-row>.cell{display:flex;align-items:center;padding:var(--tbw-cell-padding);border-right:1px solid var(--tbw-color-border-cell);overflow:hidden;min-width:0}.pivot-grand-total-row>.cell:last-child{border-right:0}.pivot-grand-total-footer{position:sticky;bottom:0;z-index:var(--tbw-z-layer-pinned-rows, 20);background:var(--tbw-pivot-grand-total-bg, var(--tbw-color-header-bg));min-width:fit-content}.pivot-group-row>.cell,.pivot-leaf-row>.cell{display:flex;align-items:center;padding:var(--tbw-cell-padding);border-right:1px solid var(--tbw-color-border-cell);overflow:hidden;min-width:0}.pivot-group-row>.cell:last-child,.pivot-leaf-row>.cell:last-child{border-right:0}.pivot-toggle{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;margin-right:6px;border:none;background:transparent;cursor:pointer;color:var(--tbw-pivot-toggle-color, var(--tbw-color-fg-muted));border-radius:var(--tbw-border-radius);transition:background .15s,color .15s}.pivot-toggle:hover{background:var(--tbw-pivot-toggle-hover-bg, var(--tbw-color-row-hover));color:var(--tbw-pivot-toggle-hover-color, var(--tbw-color-fg))}.pivot-toggle:focus{outline:var(--tbw-focus-outline);outline-offset:var(--tbw-focus-outline-offset)}.pivot-label{font-weight:inherit}.pivot-count{color:var(--tbw-pivot-count-color, var(--tbw-color-fg-muted));font-size:.9em;font-weight:400}.pivot-total-row{font-weight:700;border-top:2px solid var(--tbw-pivot-border, var(--tbw-color-border-strong))}[data-pivot-depth="1"]{--tbw-pivot-depth: 1}[data-pivot-depth="2"]{--tbw-pivot-depth: 2}[data-pivot-depth="3"]{--tbw-pivot-depth: 3}[data-pivot-depth="4"]{--tbw-pivot-depth: 4}.tbw-pivot-panel{display:flex;flex-direction:column;gap:12px;padding:12px;height:100%;overflow-y:auto;font-size:13px}.tbw-pivot-section{border:1px solid var(--tbw-pivot-border, var(--tbw-color-border));border-radius:var(--tbw-border-radius);background:var(--tbw-pivot-section-bg, var(--tbw-color-bg))}.tbw-pivot-section-header{padding:8px 12px;font-weight:600;background:var(--tbw-pivot-header-bg, var(--tbw-color-header-bg));border-bottom:1px solid var(--tbw-pivot-border, var(--tbw-color-border));border-radius:var(--tbw-border-radius) var(--tbw-border-radius) 0 0}.tbw-pivot-section-content{padding:8px}.tbw-pivot-toggle-wrapper{display:flex;align-items:center}.tbw-pivot-toggle-label{display:flex;align-items:center;gap:8px;cursor:pointer}.tbw-pivot-toggle-label input{width:16px;height:16px;cursor:pointer}.tbw-pivot-drop-zone{min-height:60px;padding:8px;border:2px dashed var(--tbw-pivot-drop-border, var(--tbw-color-border));border-radius:var(--tbw-border-radius);background:var(--tbw-pivot-drop-bg, var(--tbw-color-row-alt));display:flex;flex-wrap:wrap;gap:6px;align-content:flex-start;transition:all .15s ease}.tbw-pivot-drop-zone.drag-over{border-color:var(--tbw-color-accent);background:var(--tbw-pivot-drop-active, var(--tbw-focus-background))}.tbw-pivot-placeholder{color:var(--tbw-color-fg-muted);font-style:italic;padding:8px;text-align:center;width:100%}.tbw-pivot-field-chip{display:inline-flex;align-items:center;gap:6px;padding:4px 8px;background:var(--tbw-pivot-chip-bg, var(--tbw-color-header-bg));border:1px solid var(--tbw-pivot-chip-border, var(--tbw-color-border));border-radius:var(--tbw-border-radius);cursor:grab;font-size:12px;transition:all .15s ease}.tbw-pivot-field-chip:hover{background:var(--tbw-pivot-chip-hover, var(--tbw-color-row-hover));border-color:var(--tbw-color-accent)}.tbw-pivot-field-chip.available{background:var(--tbw-color-bg)}.tbw-pivot-field-chip.dragging{opacity:.5;cursor:grabbing}.tbw-pivot-chip-label{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:120px}.tbw-pivot-chip-remove{display:flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:none;background:transparent;color:var(--tbw-color-fg-muted);font-size:14px;font-weight:700;cursor:pointer;border-radius:50%;transition:all .15s ease}.tbw-pivot-chip-remove:hover{background:var(--tbw-pivot-chip-remove-hover-bg, var(--tbw-color-accent));color:var(--tbw-pivot-chip-remove-hover-fg, var(--tbw-color-accent-fg))}.tbw-pivot-value-chip{padding:4px 8px}.tbw-pivot-value-label-wrapper{display:flex;align-items:center;gap:8px;flex:1;min-width:0}.tbw-pivot-agg-select{padding:2px 4px;font-size:11px;border:1px solid var(--tbw-color-border);border-radius:var(--tbw-border-radius);background:var(--tbw-color-bg);cursor:pointer}.tbw-pivot-available-fields{display:flex;flex-wrap:wrap;gap:6px;min-height:40px}.tbw-pivot-options{display:flex;flex-direction:column;gap:8px}.tbw-pivot-checkbox{display:flex;align-items:center;gap:8px;cursor:pointer}.tbw-pivot-checkbox input{width:14px;height:14px;cursor:pointer}.pivot-group-row.tbw-pivot-slide-in,.pivot-leaf-row.tbw-pivot-slide-in{animation:tbw-pivot-slide-in var(--tbw-animation-duration, .2s) var(--tbw-animation-easing, ease-out) forwards}@keyframes tbw-pivot-slide-in{0%{opacity:0;transform:translate(-8px)}to{opacity:1;transform:translate(0)}}.pivot-group-row.tbw-pivot-fade-in,.pivot-leaf-row.tbw-pivot-fade-in{animation:tbw-pivot-fade-in var(--tbw-animation-duration, .2s) var(--tbw-animation-easing, ease-out) forwards}@keyframes tbw-pivot-fade-in{0%{opacity:0}to{opacity:1}}';
3621
- class M extends x {
3626
+ const un = '.pivot-group-row{display:grid;grid-template-columns:var(--tbw-column-template);font-weight:600;background:var(--tbw-pivot-group-bg, var(--tbw-color-row-alt));min-height:var(--tbw-row-height);border-bottom:var(--tbw-row-divider)}.pivot-group-row:hover{background:var(--tbw-pivot-group-hover, var(--tbw-color-row-hover))}.pivot-leaf-row{display:grid;grid-template-columns:var(--tbw-column-template);background:var(--tbw-pivot-leaf-bg, var(--tbw-color-bg));min-height:var(--tbw-row-height);border-bottom:var(--tbw-row-divider)}.pivot-grand-total-row{display:grid;grid-template-columns:var(--tbw-column-template);font-weight:700;background:var(--tbw-pivot-grand-total-bg, var(--tbw-color-header-bg));min-height:var(--tbw-row-height);border-top:2px solid var(--tbw-color-border-strong)}.pivot-grand-total-row>.cell{display:flex;align-items:center;padding:var(--tbw-cell-padding);border-right:1px solid var(--tbw-color-border-cell);overflow:hidden;min-width:0}.pivot-grand-total-row>.cell:last-child{border-right:0}.pivot-grand-total-footer{position:sticky;bottom:0;z-index:var(--tbw-z-layer-pinned-rows, 20);background:var(--tbw-pivot-grand-total-bg, var(--tbw-color-header-bg));min-width:fit-content}.pivot-group-row>.cell,.pivot-leaf-row>.cell{display:flex;align-items:center;padding:var(--tbw-cell-padding);border-right:1px solid var(--tbw-color-border-cell);overflow:hidden;min-width:0}.pivot-group-row>.cell:last-child,.pivot-leaf-row>.cell:last-child{border-right:0}.pivot-toggle{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;margin-right:6px;border:none;background:transparent;cursor:pointer;color:var(--tbw-pivot-toggle-color, var(--tbw-color-fg-muted));border-radius:var(--tbw-border-radius);transition:background .15s,color .15s}.pivot-toggle:hover{background:var(--tbw-pivot-toggle-hover-bg, var(--tbw-color-row-hover));color:var(--tbw-pivot-toggle-hover-color, var(--tbw-color-fg))}.pivot-toggle:focus{outline:var(--tbw-focus-outline);outline-offset:var(--tbw-focus-outline-offset)}.pivot-label{font-weight:inherit}.pivot-count{color:var(--tbw-pivot-count-color, var(--tbw-color-fg-muted));font-size:.9em;font-weight:400}.pivot-total-row{font-weight:700;border-top:2px solid var(--tbw-pivot-border, var(--tbw-color-border-strong))}[data-pivot-depth="1"]{--tbw-pivot-depth: 1}[data-pivot-depth="2"]{--tbw-pivot-depth: 2}[data-pivot-depth="3"]{--tbw-pivot-depth: 3}[data-pivot-depth="4"]{--tbw-pivot-depth: 4}.tbw-pivot-panel{display:flex;flex-direction:column;gap:12px;padding:12px;height:100%;overflow-y:auto;font-size:13px}.tbw-pivot-section{border:1px solid var(--tbw-pivot-border, var(--tbw-color-border));border-radius:var(--tbw-border-radius);background:var(--tbw-pivot-section-bg, var(--tbw-color-bg))}.tbw-pivot-section-header{padding:8px 12px;font-weight:600;background:var(--tbw-pivot-header-bg, var(--tbw-color-header-bg));border-bottom:1px solid var(--tbw-pivot-border, var(--tbw-color-border));border-radius:var(--tbw-border-radius) var(--tbw-border-radius) 0 0}.tbw-pivot-section-content{padding:8px}.tbw-pivot-toggle-wrapper{display:flex;align-items:center}.tbw-pivot-toggle-label{display:flex;align-items:center;gap:8px;cursor:pointer}.tbw-pivot-toggle-label input{width:16px;height:16px;cursor:pointer}.tbw-pivot-drop-zone{min-height:60px;padding:8px;border:2px dashed var(--tbw-pivot-drop-border, var(--tbw-color-border));border-radius:var(--tbw-border-radius);background:var(--tbw-pivot-drop-bg, var(--tbw-color-row-alt));display:flex;flex-wrap:wrap;gap:6px;align-content:flex-start;transition:all .15s ease}.tbw-pivot-drop-zone.drag-over{border-color:var(--tbw-color-accent);background:var(--tbw-pivot-drop-active, var(--tbw-focus-background))}.tbw-pivot-placeholder{color:var(--tbw-color-fg-muted);font-style:italic;padding:8px;text-align:center;width:100%}.tbw-pivot-field-chip{display:inline-flex;align-items:center;gap:6px;padding:4px 8px;background:var(--tbw-pivot-chip-bg, var(--tbw-color-header-bg));border:1px solid var(--tbw-pivot-chip-border, var(--tbw-color-border));border-radius:var(--tbw-border-radius);cursor:grab;font-size:12px;transition:all .15s ease}.tbw-pivot-field-chip:hover{background:var(--tbw-pivot-chip-hover, var(--tbw-color-row-hover));border-color:var(--tbw-color-accent)}.tbw-pivot-field-chip.available{background:var(--tbw-color-bg)}.tbw-pivot-field-chip.dragging{opacity:.5;cursor:grabbing}.tbw-pivot-chip-label{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:120px}.tbw-pivot-chip-remove{display:flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:none;background:transparent;color:var(--tbw-color-fg-muted);font-size:14px;font-weight:700;cursor:pointer;border-radius:50%;transition:all .15s ease}.tbw-pivot-chip-remove:hover{background:var(--tbw-pivot-chip-remove-hover-bg, var(--tbw-color-accent));color:var(--tbw-pivot-chip-remove-hover-fg, var(--tbw-color-accent-fg))}.tbw-pivot-value-chip{padding:4px 8px}.tbw-pivot-value-label-wrapper{display:flex;align-items:center;gap:8px;flex:1;min-width:0}.tbw-pivot-agg-select{padding:2px 4px;font-size:11px;border:1px solid var(--tbw-color-border);border-radius:var(--tbw-border-radius);background:var(--tbw-color-bg);cursor:pointer}.tbw-pivot-available-fields{display:flex;flex-wrap:wrap;gap:6px;min-height:40px}.tbw-pivot-options{display:flex;flex-direction:column;gap:8px}.tbw-pivot-checkbox{display:flex;align-items:center;gap:8px;cursor:pointer}.tbw-pivot-checkbox input{width:14px;height:14px;cursor:pointer}.pivot-group-row.tbw-pivot-slide-in,.pivot-leaf-row.tbw-pivot-slide-in{animation:tbw-pivot-slide-in var(--tbw-animation-duration, .2s) var(--tbw-animation-easing, ease-out) forwards}@keyframes tbw-pivot-slide-in{0%{opacity:0;transform:translate(-8px)}to{opacity:1;transform:translate(0)}}.pivot-group-row.tbw-pivot-fade-in,.pivot-leaf-row.tbw-pivot-fade-in{animation:tbw-pivot-fade-in var(--tbw-animation-duration, .2s) var(--tbw-animation-easing, ease-out) forwards}@keyframes tbw-pivot-fade-in{0%{opacity:0}to{opacity:1}}';
3627
+ class F extends x {
3622
3628
  name = "pivot";
3623
- version = "1.0.0";
3629
+ styles = un;
3624
3630
  /** Tool panel ID for shell integration */
3625
3631
  static PANEL_ID = "pivot";
3626
3632
  get defaultConfig() {
@@ -3651,17 +3657,11 @@ class M extends x {
3651
3657
  return (this.config.valueFields?.length ?? 0) > 0;
3652
3658
  }
3653
3659
  /**
3654
- * Get animation style respecting grid-level animation mode.
3660
+ * Get expand/collapse animation style from plugin config.
3661
+ * Uses base class isAnimationEnabled to respect grid-level settings.
3655
3662
  */
3656
3663
  get animationStyle() {
3657
- const t = this.grid.effectiveConfig?.animation?.mode ?? "reduced-motion";
3658
- if (t === !1 || t === "off") return !1;
3659
- if (t !== !0 && t !== "on") {
3660
- const n = this.shadowRoot?.host;
3661
- if (n && getComputedStyle(n).getPropertyValue("--tbw-animation-enabled").trim() === "0")
3662
- return !1;
3663
- }
3664
- return this.config.animation ?? "slide";
3664
+ return this.isAnimationEnabled ? this.config.animation ?? "slide" : !1;
3665
3665
  }
3666
3666
  // #endregion
3667
3667
  // #region Lifecycle
@@ -3673,7 +3673,7 @@ class M extends x {
3673
3673
  getToolPanel() {
3674
3674
  if ((this.config?.showToolPanel ?? this.userConfig?.showToolPanel ?? !0) !== !1)
3675
3675
  return {
3676
- id: M.PANEL_ID,
3676
+ id: F.PANEL_ID,
3677
3677
  title: "Pivot",
3678
3678
  icon: "⊞",
3679
3679
  tooltip: "Configure pivot table",
@@ -3686,20 +3686,11 @@ class M extends x {
3686
3686
  processRows(e) {
3687
3687
  if (!this.hasInitialized && this.config.active !== !1 && this.hasValidPivotConfig() && (this.hasInitialized = !0, this.isActive = !0), !this.isActive)
3688
3688
  return [...e];
3689
- const t = Vt(this.config);
3689
+ const t = jt(this.config);
3690
3690
  if (t.length > 0)
3691
3691
  return this.warn(`Config errors: ${t.join(", ")}`), [...e];
3692
- if (this.buildFieldHeaderMap(), this.defaultExpanded = this.config.defaultExpanded ?? !0, this.expandedKeys.size === 0 && this.defaultExpanded && this.pivotResult) {
3693
- const r = J(this.pivotResult.rows);
3694
- for (const l of r)
3695
- this.expandedKeys.add(l);
3696
- }
3697
- if (this.pivotResult = Bt(e, this.config), this.expandedKeys.size === 0 && this.defaultExpanded) {
3698
- const r = J(this.pivotResult.rows);
3699
- for (const l of r)
3700
- this.expandedKeys.add(l);
3701
- }
3702
- const n = this.config.indentWidth ?? 20, i = jt(
3692
+ this.buildFieldHeaderMap(), this.defaultExpanded = this.config.defaultExpanded ?? !0, this.expandedKeys.size === 0 && this.defaultExpanded && this.pivotResult && this.expandAllKeys(), this.pivotResult = Ut(e, this.config), this.expandedKeys.size === 0 && this.defaultExpanded && this.expandAllKeys();
3693
+ const n = this.config.indentWidth ?? 20, i = Jt(
3703
3694
  this.pivotResult.rows,
3704
3695
  this.expandedKeys,
3705
3696
  this.defaultExpanded
@@ -3734,7 +3725,7 @@ class M extends x {
3734
3725
  });
3735
3726
  for (const i of this.pivotResult.columnKeys)
3736
3727
  for (const o of this.config.valueFields ?? []) {
3737
- const r = le([i], o.field), l = o.header || this.fieldHeaderMap.get(o.field) || o.field;
3728
+ const r = se([i], o.field), l = o.header || this.fieldHeaderMap.get(o.field) || o.field;
3738
3729
  t.push({
3739
3730
  field: r,
3740
3731
  header: `${i} - ${l} (${o.aggFunc})`,
@@ -3749,14 +3740,15 @@ class M extends x {
3749
3740
  type: "number"
3750
3741
  }), t;
3751
3742
  }
3752
- renderRow(e, t) {
3753
- const n = e;
3754
- return n.__pivotRowKey && n.__pivotHasChildren ? tn(n, t, {
3743
+ renderRow(e, t, n) {
3744
+ const i = e;
3745
+ return i.__pivotRowKey && i.__pivotHasChildren ? an(i, t, {
3755
3746
  columns: this.gridColumns,
3756
- onToggle: (i) => this.toggle(i),
3757
- resolveIcon: (i) => this.resolveIcon(i),
3758
- setIcon: (i, o) => this.setIcon(i, o)
3759
- }) : n.__pivotRowKey !== void 0 && this.isActive ? nn(n, t, this.gridColumns) : (this.cleanupPivotStyling(t), !1);
3747
+ rowIndex: n,
3748
+ onToggle: (o) => this.toggle(o),
3749
+ resolveIcon: (o) => this.resolveIcon(o),
3750
+ setIcon: (o, r) => this.setIcon(o, r)
3751
+ }) : i.__pivotRowKey !== void 0 && this.isActive ? dn(i, t, this.gridColumns, n) : (this.cleanupPivotStyling(t), !1);
3760
3752
  }
3761
3753
  /**
3762
3754
  * Remove pivot-specific classes, attributes, and inline styles from a row element.
@@ -3766,6 +3758,12 @@ class M extends x {
3766
3758
  cleanupPivotStyling(e) {
3767
3759
  (e.classList.contains("pivot-group-row") || e.classList.contains("pivot-leaf-row") || e.classList.contains("pivot-grand-total-row")) && (e.classList.remove("pivot-group-row", "pivot-leaf-row", "pivot-grand-total-row"), e.classList.add("data-grid-row"), e.removeAttribute("data-pivot-depth"), e.innerHTML = "");
3768
3760
  }
3761
+ onKeyDown(e) {
3762
+ if (e.key !== " " || !this.isActive) return;
3763
+ const t = this.grid._focusRow, n = this.rows[t];
3764
+ if (!(!n?.__pivotIsGroup || !n.__pivotHasChildren))
3765
+ return e.preventDefault(), this.toggle(n.__pivotRowKey), this.requestRenderWithFocus(), !0;
3766
+ }
3769
3767
  afterRender() {
3770
3768
  this.isActive && this.config.showGrandTotal && this.pivotResult ? this.renderGrandTotalFooter() : this.cleanupGrandTotalFooter();
3771
3769
  const e = this.animationStyle;
@@ -3796,7 +3794,7 @@ class M extends x {
3796
3794
  __pivotTotal: this.pivotResult.grandTotal,
3797
3795
  ...this.pivotResult.totals
3798
3796
  };
3799
- on(n, this.grandTotalFooter, this.gridColumns);
3797
+ cn(n, this.grandTotalFooter, this.gridColumns);
3800
3798
  }
3801
3799
  /**
3802
3800
  * Remove the grand total footer element.
@@ -3816,16 +3814,20 @@ class M extends x {
3816
3814
  this.expandedKeys.delete(e), this.requestRender();
3817
3815
  }
3818
3816
  expandAll() {
3819
- if (this.pivotResult) {
3820
- const e = J(this.pivotResult.rows);
3821
- for (const t of e)
3822
- this.expandedKeys.add(t);
3823
- this.requestRender();
3824
- }
3817
+ this.expandAllKeys(), this.requestRender();
3825
3818
  }
3826
3819
  collapseAll() {
3827
3820
  this.expandedKeys.clear(), this.requestRender();
3828
3821
  }
3822
+ /**
3823
+ * Add all group keys from the current pivot result to expandedKeys.
3824
+ */
3825
+ expandAllKeys() {
3826
+ if (!this.pivotResult) return;
3827
+ const e = Qt(this.pivotResult.rows);
3828
+ for (const t of e)
3829
+ this.expandedKeys.add(t);
3830
+ }
3829
3831
  isExpanded(e) {
3830
3832
  return this.expandedKeys.has(e);
3831
3833
  }
@@ -3857,23 +3859,42 @@ class M extends x {
3857
3859
  }
3858
3860
  // #endregion
3859
3861
  // #region Tool Panel API
3862
+ /**
3863
+ * Show the pivot tool panel.
3864
+ * Opens the tool panel and ensures this section is expanded.
3865
+ */
3860
3866
  showPanel() {
3861
- this.grid.openToolPanel(M.PANEL_ID);
3867
+ this.grid.openToolPanel(), this.grid.expandedToolPanelSections.includes(F.PANEL_ID) || this.grid.toggleToolPanelSection(F.PANEL_ID);
3862
3868
  }
3869
+ /**
3870
+ * Hide the tool panel.
3871
+ */
3863
3872
  hidePanel() {
3864
3873
  this.grid.closeToolPanel();
3865
3874
  }
3875
+ /**
3876
+ * Toggle the pivot tool panel section.
3877
+ */
3866
3878
  togglePanel() {
3867
- this.grid.toggleToolPanel(M.PANEL_ID);
3879
+ this.grid.isToolPanelOpen || this.grid.openToolPanel(), this.grid.toggleToolPanelSection(F.PANEL_ID);
3868
3880
  }
3881
+ /**
3882
+ * Check if the pivot panel section is currently expanded.
3883
+ */
3869
3884
  isPanelVisible() {
3870
- return this.grid.activeToolPanel === M.PANEL_ID;
3885
+ return this.grid.isToolPanelOpen && this.grid.expandedToolPanelSections.includes(F.PANEL_ID);
3871
3886
  }
3872
3887
  // #endregion
3873
3888
  // #region Private Helpers
3874
3889
  get gridColumns() {
3875
3890
  return this.grid.columns ?? [];
3876
3891
  }
3892
+ /**
3893
+ * Refresh pivot and update tool panel if active.
3894
+ */
3895
+ refreshIfActive() {
3896
+ this.isActive && this.refresh(), this.refreshPanel();
3897
+ }
3877
3898
  buildFieldHeaderMap() {
3878
3899
  const e = this.getAvailableFields();
3879
3900
  this.fieldHeaderMap.clear();
@@ -3884,12 +3905,11 @@ class M extends x {
3884
3905
  return this.originalColumns.length > 0 ? this.originalColumns : this.captureOriginalColumns();
3885
3906
  }
3886
3907
  captureOriginalColumns() {
3887
- const e = this.grid;
3888
3908
  try {
3889
- const t = e.getAllColumns?.() ?? e.columns ?? [];
3890
- return this.originalColumns = t.filter((n) => !n.field.startsWith("__pivot")).map((n) => ({
3891
- field: n.field,
3892
- header: n.header ?? n.field
3909
+ const e = this.grid.getAllColumns?.() ?? this.grid.columns ?? [];
3910
+ return this.originalColumns = e.filter((t) => !t.field.startsWith("__pivot")).map((t) => ({
3911
+ field: t.field,
3912
+ header: t.header ?? t.field
3893
3913
  })), this.originalColumns;
3894
3914
  } catch {
3895
3915
  return [];
@@ -3911,7 +3931,7 @@ class M extends x {
3911
3931
  },
3912
3932
  getAvailableFields: () => this.getAvailableFields()
3913
3933
  };
3914
- return Zt(e, this.config, this.isActive, t);
3934
+ return tn(e, this.config, this.isActive, t);
3915
3935
  }
3916
3936
  refreshPanel() {
3917
3937
  this.panelContainer && (this.panelContainer.innerHTML = "", this.renderPanel(this.panelContainer));
@@ -3924,43 +3944,40 @@ class M extends x {
3924
3944
  const n = this.config.columnGroupFields ?? [];
3925
3945
  n.includes(e) || (this.config.columnGroupFields = [...n, e]);
3926
3946
  }
3927
- this.removeFromOtherZones(e, t), this.isActive && this.refresh(), this.refreshPanel();
3947
+ this.removeFromOtherZones(e, t), this.refreshIfActive();
3928
3948
  }
3929
3949
  removeFieldFromZone(e, t) {
3930
- t === "rowGroups" ? this.config.rowGroupFields = (this.config.rowGroupFields ?? []).filter((n) => n !== e) : this.config.columnGroupFields = (this.config.columnGroupFields ?? []).filter((n) => n !== e), this.isActive && this.refresh(), this.refreshPanel();
3950
+ t === "rowGroups" ? this.config.rowGroupFields = (this.config.rowGroupFields ?? []).filter((n) => n !== e) : this.config.columnGroupFields = (this.config.columnGroupFields ?? []).filter((n) => n !== e), this.refreshIfActive();
3931
3951
  }
3932
3952
  removeFromOtherZones(e, t) {
3933
3953
  t !== "rowGroups" && (this.config.rowGroupFields = (this.config.rowGroupFields ?? []).filter((n) => n !== e)), t !== "columnGroups" && (this.config.columnGroupFields = (this.config.columnGroupFields ?? []).filter((n) => n !== e)), t !== "values" && (this.config.valueFields = (this.config.valueFields ?? []).filter((n) => n.field !== e));
3934
3954
  }
3935
3955
  addValueField(e, t) {
3936
3956
  const n = this.config.valueFields ?? [];
3937
- n.some((i) => i.field === e) || (this.config.valueFields = [...n, { field: e, aggFunc: t }]), this.removeFromOtherZones(e, "values"), this.isActive && this.refresh(), this.refreshPanel();
3957
+ n.some((i) => i.field === e) || (this.config.valueFields = [...n, { field: e, aggFunc: t }]), this.removeFromOtherZones(e, "values"), this.refreshIfActive();
3938
3958
  }
3939
3959
  removeValueField(e) {
3940
- this.config.valueFields = (this.config.valueFields ?? []).filter((t) => t.field !== e), this.isActive && this.refresh(), this.refreshPanel();
3960
+ this.config.valueFields = (this.config.valueFields ?? []).filter((t) => t.field !== e), this.refreshIfActive();
3941
3961
  }
3942
3962
  updateValueAggFunc(e, t) {
3943
3963
  const n = this.config.valueFields ?? [], i = n.findIndex((o) => o.field === e);
3944
3964
  i >= 0 && (n[i] = { ...n[i], aggFunc: t }, this.config.valueFields = [...n]), this.isActive && this.refresh();
3945
3965
  }
3946
3966
  // #endregion
3947
- // #region Styles
3948
- styles = rn;
3949
- // #endregion
3950
3967
  }
3951
- function Fe(s) {
3968
+ function hn(s) {
3952
3969
  const e = s.meta ?? {};
3953
3970
  return e.lockPosition !== !0 && e.suppressMovable !== !0;
3954
3971
  }
3955
- function Me(s, e, t) {
3972
+ function Fe(s, e, t) {
3956
3973
  if (e === t || e < 0 || e >= s.length || t < 0 || t > s.length) return s;
3957
3974
  const n = [...s], [i] = n.splice(e, 1);
3958
3975
  return n.splice(t, 0, i), n;
3959
3976
  }
3960
- const sn = '.header-row>.cell[draggable=true]{cursor:grab;position:relative}.header-row>.cell.dragging{opacity:.5;cursor:grabbing}.header-row>.cell.drop-before:before{content:"";position:absolute;left:0;top:0;bottom:0;width:2px;background:var(--tbw-reorder-indicator, var(--tbw-color-accent));z-index:1}.header-row>.cell.drop-after:after{content:"";position:absolute;right:0;top:0;bottom:0;width:2px;background:var(--tbw-reorder-indicator, var(--tbw-color-accent));z-index:1}.cell.flip-animating{transition:transform var(--tbw-animation-duration, .2s) ease-out;will-change:transform;z-index:1}@keyframes reorder-fade-in{0%{opacity:0}to{opacity:1}}.cell.fade-animating{animation:reorder-fade-in var(--tbw-animation-duration, .2s) ease-out backwards}';
3961
- class Vn extends x {
3977
+ const fn = '.header-row>.cell[draggable=true]{cursor:grab;position:relative}.header-row>.cell.dragging{opacity:.5;cursor:grabbing}.header-row>.cell.drop-before:before{content:"";position:absolute;left:0;top:0;bottom:0;width:2px;background:var(--tbw-reorder-indicator, var(--tbw-color-accent));z-index:1}.header-row>.cell.drop-after:after{content:"";position:absolute;right:0;top:0;bottom:0;width:2px;background:var(--tbw-reorder-indicator, var(--tbw-color-accent));z-index:1}.cell.flip-animating{transition:transform var(--tbw-animation-duration, .2s) ease-out;will-change:transform;z-index:1}@keyframes reorder-fade-in{0%{opacity:0}to{opacity:1}}.cell.fade-animating{animation:reorder-fade-in var(--tbw-animation-duration, .2s) ease-out backwards}';
3978
+ class Un extends x {
3962
3979
  name = "reorder";
3963
- version = "1.0.0";
3980
+ styles = fn;
3964
3981
  get defaultConfig() {
3965
3982
  return {
3966
3983
  animation: "flip"
@@ -3969,40 +3986,40 @@ class Vn extends x {
3969
3986
  }
3970
3987
  /**
3971
3988
  * Resolve animation type from plugin config.
3972
- * Respects grid-level animation.mode (disabled = no animation).
3989
+ * Uses base class isAnimationEnabled to respect grid-level settings.
3973
3990
  */
3974
3991
  get animationType() {
3975
3992
  return this.isAnimationEnabled ? this.config.animation !== void 0 ? this.config.animation : this.config.viewTransition === !1 ? !1 : (this.config.viewTransition === !0, "flip") : !1;
3976
3993
  }
3977
3994
  /**
3978
- * Check if animations are enabled at the grid level.
3979
- * Respects gridConfig.animation.mode and CSS variable.
3980
- */
3981
- get isAnimationEnabled() {
3982
- const t = this.grid.effectiveConfig?.animation?.mode ?? "reduced-motion";
3983
- if (t === !1 || t === "off") return !1;
3984
- if (t === !0 || t === "on") return !0;
3985
- const n = this.shadowRoot?.host;
3986
- return n ? getComputedStyle(n).getPropertyValue("--tbw-animation-enabled").trim() !== "0" : !0;
3987
- }
3988
- /**
3989
- * Get animation duration from CSS variable (set by grid config).
3995
+ * Get animation duration, allowing plugin config override.
3996
+ * Uses base class animationDuration for default.
3990
3997
  */
3991
3998
  get animationDuration() {
3992
- if (this.config.animationDuration !== void 0)
3993
- return this.config.animationDuration;
3994
- const e = this.shadowRoot?.host;
3995
- if (e) {
3996
- const t = getComputedStyle(e).getPropertyValue("--tbw-animation-duration").trim(), n = parseInt(t, 10);
3997
- if (!isNaN(n)) return n;
3998
- }
3999
- return 200;
3999
+ return this.config.animationDuration !== void 0 ? this.config.animationDuration : super.animationDuration;
4000
4000
  }
4001
4001
  // #region Internal State
4002
4002
  isDragging = !1;
4003
4003
  draggedField = null;
4004
4004
  draggedIndex = null;
4005
4005
  dropIndex = null;
4006
+ /**
4007
+ * Check if a column can be moved, considering both column config and plugin queries.
4008
+ */
4009
+ canMoveColumnWithPlugins(e) {
4010
+ return !e || !hn(e) ? !1 : !this.grid.queryPlugins({
4011
+ type: He.CAN_MOVE_COLUMN,
4012
+ context: e
4013
+ }).includes(!1);
4014
+ }
4015
+ /**
4016
+ * Clear all drag-related classes from header cells.
4017
+ */
4018
+ clearDragClasses() {
4019
+ this.shadowRoot?.querySelectorAll(".header-row > .cell").forEach((e) => {
4020
+ e.classList.remove("dragging", "drop-target", "drop-before", "drop-after");
4021
+ });
4022
+ }
4006
4023
  // #endregion
4007
4024
  // #region Lifecycle
4008
4025
  attach(e) {
@@ -4026,39 +4043,34 @@ class Vn extends x {
4026
4043
  e.querySelectorAll(".header-row > .cell").forEach((n) => {
4027
4044
  const i = n, o = i.getAttribute("data-field");
4028
4045
  if (!o) return;
4029
- const r = this.columns.find((c) => c.field === o), d = !this.grid.queryPlugins({
4030
- type: H.CAN_MOVE_COLUMN,
4031
- context: r
4032
- }).includes(!1);
4033
- if (!r || !Fe(r) || !d) {
4046
+ const r = this.columns.find((l) => l.field === o);
4047
+ if (!this.canMoveColumnWithPlugins(r)) {
4034
4048
  i.draggable = !1;
4035
4049
  return;
4036
4050
  }
4037
- i.draggable = !0, !i.getAttribute("data-dragstart-bound") && (i.setAttribute("data-dragstart-bound", "true"), i.addEventListener("dragstart", (c) => {
4038
- const u = this.getColumnOrder().indexOf(o);
4039
- this.isDragging = !0, this.draggedField = o, this.draggedIndex = u, c.dataTransfer && (c.dataTransfer.effectAllowed = "move", c.dataTransfer.setData("text/plain", o)), i.classList.add("dragging");
4051
+ i.draggable = !0, !i.getAttribute("data-dragstart-bound") && (i.setAttribute("data-dragstart-bound", "true"), i.addEventListener("dragstart", (l) => {
4052
+ const d = this.getColumnOrder().indexOf(o);
4053
+ this.isDragging = !0, this.draggedField = o, this.draggedIndex = d, l.dataTransfer && (l.dataTransfer.effectAllowed = "move", l.dataTransfer.setData("text/plain", o)), i.classList.add("dragging");
4040
4054
  }), i.addEventListener("dragend", () => {
4041
- this.isDragging = !1, this.draggedField = null, this.draggedIndex = null, this.dropIndex = null, e.querySelectorAll(".header-row > .cell").forEach((c) => {
4042
- c.classList.remove("dragging", "drop-target", "drop-before", "drop-after");
4043
- });
4044
- }), i.addEventListener("dragover", (c) => {
4045
- if (c.preventDefault(), !this.isDragging || this.draggedField === o) return;
4046
- const h = i.getBoundingClientRect(), u = h.left + h.width / 2, g = this.getColumnOrder().indexOf(o);
4047
- this.dropIndex = c.clientX < u ? g : g + 1, i.classList.add("drop-target"), i.classList.toggle("drop-before", c.clientX < u), i.classList.toggle("drop-after", c.clientX >= u);
4055
+ this.isDragging = !1, this.draggedField = null, this.draggedIndex = null, this.dropIndex = null, this.clearDragClasses();
4056
+ }), i.addEventListener("dragover", (l) => {
4057
+ if (l.preventDefault(), !this.isDragging || this.draggedField === o) return;
4058
+ const a = i.getBoundingClientRect(), d = a.left + a.width / 2, u = this.getColumnOrder().indexOf(o);
4059
+ this.dropIndex = l.clientX < d ? u : u + 1, i.classList.add("drop-target"), i.classList.toggle("drop-before", l.clientX < d), i.classList.toggle("drop-after", l.clientX >= d);
4048
4060
  }), i.addEventListener("dragleave", () => {
4049
4061
  i.classList.remove("drop-target", "drop-before", "drop-after");
4050
- }), i.addEventListener("drop", (c) => {
4051
- c.preventDefault();
4052
- const h = this.draggedField, u = this.draggedIndex, f = this.dropIndex;
4053
- if (!this.isDragging || h === null || u === null || f === null)
4062
+ }), i.addEventListener("drop", (l) => {
4063
+ l.preventDefault();
4064
+ const a = this.draggedField, d = this.draggedIndex, c = this.dropIndex;
4065
+ if (!this.isDragging || a === null || d === null || c === null)
4054
4066
  return;
4055
- const g = f > u ? f - 1 : f, p = this.getColumnOrder(), w = Me(p, u, g), m = {
4056
- field: h,
4057
- fromIndex: u,
4058
- toIndex: g,
4059
- columnOrder: w
4067
+ const u = c > d ? c - 1 : c, h = this.getColumnOrder(), f = Fe(h, d, u), g = {
4068
+ field: a,
4069
+ fromIndex: d,
4070
+ toIndex: u,
4071
+ columnOrder: f
4060
4072
  };
4061
- this.updateColumnOrder(w), this.emit("column-move", m);
4073
+ this.updateColumnOrder(f), this.emitCancelable("column-move", g) && this.updateColumnOrder(h);
4062
4074
  }));
4063
4075
  });
4064
4076
  }
@@ -4071,22 +4083,14 @@ class Vn extends x {
4071
4083
  const t = this.grid, n = t._focusCol, i = t._visibleColumns;
4072
4084
  if (n < 0 || n >= i.length) return;
4073
4085
  const o = i[n];
4074
- if (!o || !Fe(o)) return;
4075
- const r = this.grid;
4076
- if (r.queryPlugins({
4077
- type: H.CAN_MOVE_COLUMN,
4078
- context: o
4079
- }).includes(!1)) return;
4080
- const a = this.getColumnOrder(), d = a.indexOf(o.field);
4081
- if (d === -1) return;
4082
- const c = e.key === "ArrowLeft" ? d - 1 : d + 1;
4083
- if (c < 0 || c >= a.length) return;
4084
- const h = i.find((u) => u.field === a[c]);
4085
- if (!(h && r.queryPlugins({
4086
- type: H.CAN_MOVE_COLUMN,
4087
- context: h
4088
- }).includes(!1)))
4089
- return this.moveColumn(o.field, c), t._focusCol = c, Ue(this.grid), e.preventDefault(), e.stopPropagation(), !0;
4086
+ if (!this.canMoveColumnWithPlugins(o)) return;
4087
+ const r = this.getColumnOrder(), l = r.indexOf(o.field);
4088
+ if (l === -1) return;
4089
+ const a = e.key === "ArrowLeft" ? l - 1 : l + 1;
4090
+ if (a < 0 || a >= r.length) return;
4091
+ const d = i.find((c) => c.field === r[a]);
4092
+ if (this.canMoveColumnWithPlugins(d))
4093
+ return this.moveColumn(o.field, a), t._focusCol = a, Ze(this.grid), e.preventDefault(), e.stopPropagation(), !0;
4090
4094
  }
4091
4095
  // #endregion
4092
4096
  // #region Public API
@@ -4105,13 +4109,13 @@ class Vn extends x {
4105
4109
  moveColumn(e, t) {
4106
4110
  const n = this.getColumnOrder(), i = n.indexOf(e);
4107
4111
  if (i === -1) return;
4108
- const o = Me(n, i, t);
4109
- this.updateColumnOrder(o), this.emit("column-move", {
4112
+ const o = Fe(n, i, t);
4113
+ this.updateColumnOrder(o), this.emitCancelable("column-move", {
4110
4114
  field: e,
4111
4115
  fromIndex: i,
4112
4116
  toIndex: t,
4113
4117
  columnOrder: o
4114
- });
4118
+ }) && this.updateColumnOrder(n);
4115
4119
  }
4116
4120
  /**
4117
4121
  * Set a specific column order.
@@ -4214,21 +4218,47 @@ class Vn extends x {
4214
4218
  * Update column order with configured animation.
4215
4219
  */
4216
4220
  updateColumnOrder(e) {
4217
- const t = this.grid, n = this.animationType;
4218
- if (n === "flip" && this.shadowRoot) {
4219
- const i = this.captureHeaderPositions();
4220
- t.setColumnOrder(e), requestAnimationFrame(() => {
4221
- this.shadowRoot?.host?.offsetHeight, this.animateFLIP(i);
4221
+ const t = this.animationType;
4222
+ if (t === "flip" && this.shadowRoot) {
4223
+ const n = this.captureHeaderPositions();
4224
+ this.grid.setColumnOrder(e), requestAnimationFrame(() => {
4225
+ this.shadowRoot?.host?.offsetHeight, this.animateFLIP(n);
4222
4226
  });
4223
- } else n === "fade" ? this.animateFade(() => t.setColumnOrder(e)) : t.setColumnOrder(e);
4224
- t.requestStateChange?.();
4227
+ } else t === "fade" ? this.animateFade(() => this.grid.setColumnOrder(e)) : this.grid.setColumnOrder(e);
4228
+ this.grid.requestStateChange?.();
4225
4229
  }
4226
4230
  // #endregion
4227
- // #region Styles
4228
- styles = sn;
4229
- // #endregion
4230
4231
  }
4231
- function G(s) {
4232
+ function Xn(s, e, t, n) {
4233
+ const i = new Set(s.selected);
4234
+ let o = s.anchor;
4235
+ if (t === "single")
4236
+ i.clear(), i.add(e), o = e;
4237
+ else if (t === "multiple") {
4238
+ const r = n.ctrlKey || n.metaKey;
4239
+ if (n.shiftKey && s.anchor !== null) {
4240
+ const l = Math.min(s.anchor, e), a = Math.max(s.anchor, e);
4241
+ for (let d = l; d <= a; d++)
4242
+ i.add(d);
4243
+ } else r ? (i.has(e) ? i.delete(e) : i.add(e), o = e) : (i.clear(), i.add(e), o = e);
4244
+ }
4245
+ return { selected: i, lastSelected: e, anchor: o };
4246
+ }
4247
+ function Zn(s) {
4248
+ const e = /* @__PURE__ */ new Set();
4249
+ for (let t = 0; t < s; t++)
4250
+ e.add(t);
4251
+ return e;
4252
+ }
4253
+ function Yn(s, e) {
4254
+ const t = [], n = [];
4255
+ for (const i of e)
4256
+ s.has(i) || t.push(i);
4257
+ for (const i of s)
4258
+ e.has(i) || n.push(i);
4259
+ return { added: t, removed: n };
4260
+ }
4261
+ function B(s) {
4232
4262
  return {
4233
4263
  startRow: Math.min(s.startRow, s.endRow),
4234
4264
  startCol: Math.min(s.startCol, s.endCol),
@@ -4236,38 +4266,38 @@ function G(s) {
4236
4266
  endCol: Math.max(s.startCol, s.endCol)
4237
4267
  };
4238
4268
  }
4239
- function ln(s) {
4240
- const e = G(s);
4269
+ function gn(s) {
4270
+ const e = B(s);
4241
4271
  return {
4242
4272
  from: { row: e.startRow, col: e.startCol },
4243
4273
  to: { row: e.endRow, col: e.endCol }
4244
4274
  };
4245
4275
  }
4246
- function ie(s) {
4247
- return s.map(ln);
4276
+ function Ve(s) {
4277
+ return s.map(gn);
4248
4278
  }
4249
- function an(s, e, t) {
4250
- const n = G(t);
4279
+ function pn(s, e, t) {
4280
+ const n = B(t);
4251
4281
  return s >= n.startRow && s <= n.endRow && e >= n.startCol && e <= n.endCol;
4252
4282
  }
4253
- function Pe(s, e, t) {
4254
- return t.some((n) => an(s, e, n));
4283
+ function Me(s, e, t) {
4284
+ return t.some((n) => pn(s, e, n));
4255
4285
  }
4256
- function dn(s) {
4257
- const e = [], t = G(s);
4286
+ function mn(s) {
4287
+ const e = [], t = B(s);
4258
4288
  for (let n = t.startRow; n <= t.endRow; n++)
4259
4289
  for (let i = t.startCol; i <= t.endCol; i++)
4260
4290
  e.push({ row: n, col: i });
4261
4291
  return e;
4262
4292
  }
4263
- function cn(s) {
4293
+ function wn(s) {
4264
4294
  const e = /* @__PURE__ */ new Map();
4265
4295
  for (const t of s)
4266
- for (const n of dn(t))
4296
+ for (const n of mn(t))
4267
4297
  e.set(`${n.row},${n.col}`, n);
4268
4298
  return [...e.values()];
4269
4299
  }
4270
- function ee(s, e) {
4300
+ function J(s, e) {
4271
4301
  return {
4272
4302
  startRow: s.row,
4273
4303
  startCol: s.col,
@@ -4275,8 +4305,8 @@ function ee(s, e) {
4275
4305
  endCol: e.col
4276
4306
  };
4277
4307
  }
4278
- const un = ':host .selecting .data-grid-row>.cell{user-select:none}:host .data-grid-row.row-focus{background-color:var(--tbw-focus-background, rgba(from var(--tbw-color-accent) r g b / 12%))}:host([data-selection-mode="row"]) .cell-focus{outline:none}:host .data-grid-row>.cell.selected{background-color:var(--tbw-range-selection-bg)}:host .data-grid-row>.cell.selected.top{border-top:2px solid var(--tbw-range-border-color)}:host .data-grid-row>.cell.selected.bottom{border-bottom:2px solid var(--tbw-range-border-color)}:host .data-grid-row>.cell.selected.first{border-left:2px solid var(--tbw-range-border-color)}:host .data-grid-row>.cell.selected.last{border-right:2px solid var(--tbw-range-border-color)}:host .tbw-selection-summary{font-size:13px;color:var(--tbw-color-fg-muted);white-space:nowrap}';
4279
- function hn(s, e, t) {
4308
+ const bn = ':host .selecting .data-grid-row>.cell{user-select:none}:host([data-has-focus]) .data-grid-row.row-focus{background-color:var(--tbw-focus-background, rgba(from var(--tbw-color-accent) r g b / 12%))}:host([data-selection-mode="row"]) .cell-focus{outline:none}:host .data-grid-row>.cell.selected{background-color:var(--tbw-range-selection-bg)}:host .data-grid-row>.cell.selected.top{border-top:2px solid var(--tbw-range-border-color)}:host .data-grid-row>.cell.selected.bottom{border-bottom:2px solid var(--tbw-range-border-color)}:host .data-grid-row>.cell.selected.first{border-left:2px solid var(--tbw-range-border-color)}:host .data-grid-row>.cell.selected.last{border-right:2px solid var(--tbw-range-border-color)}:host .tbw-selection-summary{font-size:13px;color:var(--tbw-color-fg-muted);white-space:nowrap}';
4309
+ function vn(s, e, t) {
4280
4310
  if (s === "cell" && e.selectedCell)
4281
4311
  return {
4282
4312
  mode: s,
@@ -4294,11 +4324,11 @@ function hn(s, e, t) {
4294
4324
  }));
4295
4325
  return { mode: s, ranges: n };
4296
4326
  }
4297
- return s === "range" && e.ranges.length > 0 ? { mode: s, ranges: ie(e.ranges) } : { mode: s, ranges: [] };
4327
+ return s === "range" && e.ranges.length > 0 ? { mode: s, ranges: Ve(e.ranges) } : { mode: s, ranges: [] };
4298
4328
  }
4299
- class Bn extends x {
4329
+ class Jn extends x {
4300
4330
  name = "selection";
4301
- version = "1.0.0";
4331
+ styles = bn;
4302
4332
  get defaultConfig() {
4303
4333
  return {
4304
4334
  mode: "cell"
@@ -4326,32 +4356,34 @@ class Bn extends x {
4326
4356
  // #endregion
4327
4357
  // #region Event Handlers
4328
4358
  onCellClick(e) {
4329
- const { rowIndex: t, colIndex: n, originalEvent: i } = e, { mode: o } = this.config;
4359
+ const { rowIndex: t, colIndex: n, originalEvent: i } = e, { mode: o } = this.config, r = this.columns[n], l = r && _(r);
4330
4360
  if (o === "cell")
4331
- return this.selectedCell = { row: t, col: n }, this.emit("selection-change", this.#t()), this.requestAfterRender(), !1;
4361
+ return l || (this.selectedCell = { row: t, col: n }, this.emit("selection-change", this.#t()), this.requestAfterRender()), !1;
4332
4362
  if (o === "row")
4333
4363
  return this.selected.clear(), this.selected.add(t), this.lastSelected = t, this.emit("selection-change", this.#t()), this.requestAfterRender(), !1;
4334
4364
  if (o === "range") {
4335
- const r = i.shiftKey, l = i.ctrlKey || i.metaKey;
4336
- if (r && this.cellAnchor) {
4337
- const a = ee(this.cellAnchor, { row: t, col: n });
4338
- l ? this.ranges.length > 0 ? this.ranges[this.ranges.length - 1] = a : this.ranges.push(a) : this.ranges = [a], this.activeRange = a;
4339
- } else if (l) {
4340
- const a = {
4365
+ if (l)
4366
+ return !1;
4367
+ const a = i.shiftKey, d = i.ctrlKey || i.metaKey;
4368
+ if (a && this.cellAnchor) {
4369
+ const c = J(this.cellAnchor, { row: t, col: n });
4370
+ d ? this.ranges.length > 0 ? this.ranges[this.ranges.length - 1] = c : this.ranges.push(c) : this.ranges = [c], this.activeRange = c;
4371
+ } else if (d) {
4372
+ const c = {
4341
4373
  startRow: t,
4342
4374
  startCol: n,
4343
4375
  endRow: t,
4344
4376
  endCol: n
4345
4377
  };
4346
- this.ranges.push(a), this.activeRange = a, this.cellAnchor = { row: t, col: n };
4378
+ this.ranges.push(c), this.activeRange = c, this.cellAnchor = { row: t, col: n };
4347
4379
  } else {
4348
- const a = {
4380
+ const c = {
4349
4381
  startRow: t,
4350
4382
  startCol: n,
4351
4383
  endRow: t,
4352
4384
  endCol: n
4353
4385
  };
4354
- this.ranges = [a], this.activeRange = a, this.cellAnchor = { row: t, col: n };
4386
+ this.ranges = [c], this.activeRange = c, this.cellAnchor = { row: t, col: n };
4355
4387
  }
4356
4388
  return this.emit("selection-change", this.#t()), this.requestAfterRender(), !1;
4357
4389
  }
@@ -4388,23 +4420,31 @@ class Bn extends x {
4388
4420
  return !1;
4389
4421
  }
4390
4422
  onCellMouseDown(e) {
4391
- if (this.config.mode !== "range" || e.rowIndex === void 0 || e.colIndex === void 0 || e.rowIndex < 0 || e.originalEvent.shiftKey && this.cellAnchor)
4423
+ if (this.config.mode !== "range" || e.rowIndex === void 0 || e.colIndex === void 0 || e.rowIndex < 0) return;
4424
+ const t = this.columns[e.colIndex];
4425
+ if (t && _(t) || e.originalEvent.shiftKey && this.cellAnchor)
4392
4426
  return;
4393
4427
  this.isDragging = !0;
4394
- const t = e.rowIndex, n = e.colIndex;
4395
- this.cellAnchor = { row: t, col: n }, e.originalEvent.ctrlKey || e.originalEvent.metaKey || (this.ranges = []);
4396
- const o = {
4397
- startRow: t,
4398
- startCol: n,
4399
- endRow: t,
4400
- endCol: n
4428
+ const n = e.rowIndex, i = e.colIndex;
4429
+ this.cellAnchor = { row: n, col: i }, e.originalEvent.ctrlKey || e.originalEvent.metaKey || (this.ranges = []);
4430
+ const r = {
4431
+ startRow: n,
4432
+ startCol: i,
4433
+ endRow: n,
4434
+ endCol: i
4401
4435
  };
4402
- return this.ranges.push(o), this.activeRange = o, this.emit("selection-change", this.#t()), this.requestAfterRender(), !0;
4436
+ return this.ranges.push(r), this.activeRange = r, this.emit("selection-change", this.#t()), this.requestAfterRender(), !0;
4403
4437
  }
4404
4438
  onCellMouseMove(e) {
4405
4439
  if (this.config.mode !== "range" || !this.isDragging || !this.cellAnchor || e.rowIndex === void 0 || e.colIndex === void 0 || e.rowIndex < 0) return;
4406
- const t = ee(this.cellAnchor, { row: e.rowIndex, col: e.colIndex });
4407
- return this.ranges.length > 0 ? this.ranges[this.ranges.length - 1] = t : this.ranges.push(t), this.activeRange = t, this.emit("selection-change", this.#t()), this.requestAfterRender(), !0;
4440
+ let t = e.colIndex;
4441
+ const n = this.columns[t];
4442
+ if (n && _(n)) {
4443
+ const o = this.columns.findIndex((r) => !_(r));
4444
+ o >= 0 && (t = o);
4445
+ }
4446
+ const i = J(this.cellAnchor, { row: e.rowIndex, col: t });
4447
+ return this.ranges.length > 0 ? this.ranges[this.ranges.length - 1] = i : this.ranges.push(i), this.activeRange = i, this.emit("selection-change", this.#t()), this.requestAfterRender(), !0;
4408
4448
  }
4409
4449
  onCellMouseUp(e) {
4410
4450
  if (this.config.mode === "range" && this.isDragging)
@@ -4425,14 +4465,23 @@ class Bn extends x {
4425
4465
  if (i.forEach((o) => {
4426
4466
  o.classList.remove("selected", "row-focus");
4427
4467
  }), t === "row" && (V(e), i.forEach((o) => {
4428
- const r = o.querySelector(".cell[data-row]"), l = Ze(r);
4468
+ const r = o.querySelector(".cell[data-row]"), l = Ye(r);
4429
4469
  l >= 0 && this.selected.has(l) && o.classList.add("selected", "row-focus");
4430
4470
  })), t === "range" && this.ranges.length > 0) {
4431
4471
  V(e);
4432
- const o = this.activeRange ? G(this.activeRange) : null;
4433
- e.querySelectorAll(".cell[data-row][data-col]").forEach((l) => {
4434
- const a = parseInt(l.getAttribute("data-row") ?? "-1", 10), d = parseInt(l.getAttribute("data-col") ?? "-1", 10);
4435
- a >= 0 && d >= 0 && Pe(a, d, this.ranges) && (l.classList.add("selected"), o && (a === o.startRow && l.classList.add("top"), a === o.endRow && l.classList.add("bottom"), d === o.startCol && l.classList.add("first"), d === o.endCol && l.classList.add("last")));
4472
+ const o = this.activeRange ? B(this.activeRange) : null, r = this.columns.findIndex((a) => !_(a));
4473
+ this.columns.length - 1, e.querySelectorAll(".cell[data-row][data-col]").forEach((a) => {
4474
+ const d = parseInt(a.getAttribute("data-row") ?? "-1", 10), c = parseInt(a.getAttribute("data-col") ?? "-1", 10);
4475
+ if (d >= 0 && c >= 0) {
4476
+ const u = this.columns[c];
4477
+ if (u && _(u))
4478
+ return;
4479
+ if (Me(d, c, this.ranges) && (a.classList.add("selected"), o)) {
4480
+ d === o.startRow && a.classList.add("top"), d === o.endRow && a.classList.add("bottom");
4481
+ const f = Math.max(o.startCol, r);
4482
+ c === f && a.classList.add("first"), c === o.endCol && a.classList.add("last");
4483
+ }
4484
+ }
4436
4485
  });
4437
4486
  }
4438
4487
  t === "cell" && this.selectedCell && V(e);
@@ -4446,7 +4495,7 @@ class Bn extends x {
4446
4495
  this.pendingKeyboardUpdate = null;
4447
4496
  const o = this.grid._focusRow, r = this.grid._focusCol;
4448
4497
  if (i && this.cellAnchor) {
4449
- const l = ee(this.cellAnchor, { row: o, col: r });
4498
+ const l = J(this.cellAnchor, { row: o, col: r });
4450
4499
  this.ranges = [l], this.activeRange = l;
4451
4500
  } else i || (this.ranges = [], this.activeRange = null, this.cellAnchor = { row: o, col: r });
4452
4501
  this.emit("selection-change", this.#t());
@@ -4462,35 +4511,62 @@ class Bn extends x {
4462
4511
  }
4463
4512
  // #endregion
4464
4513
  // #region Public API
4514
+ /**
4515
+ * Get the current selection as a unified result.
4516
+ * Works for all selection modes and always returns ranges.
4517
+ *
4518
+ * @example
4519
+ * ```ts
4520
+ * const selection = plugin.getSelection();
4521
+ * if (selection.ranges.length > 0) {
4522
+ * const { from, to } = selection.ranges[0];
4523
+ * // For cell mode: from === to (single cell)
4524
+ * // For row mode: from.col = 0, to.col = lastCol (full row)
4525
+ * // For range mode: rectangular selection
4526
+ * }
4527
+ * ```
4528
+ */
4529
+ getSelection() {
4530
+ return {
4531
+ mode: this.config.mode,
4532
+ ranges: this.#t().ranges,
4533
+ anchor: this.cellAnchor
4534
+ };
4535
+ }
4465
4536
  /**
4466
4537
  * Get the selected cell (cell mode only).
4538
+ * @deprecated Use `getSelection()` instead for a unified API across all modes.
4467
4539
  */
4468
4540
  getSelectedCell() {
4469
- return this.selectedCell;
4541
+ const { mode: e, ranges: t } = this.getSelection();
4542
+ return e === "cell" && t.length > 0 ? t[0].from : null;
4470
4543
  }
4471
4544
  /**
4472
4545
  * Get all selected row indices (row mode).
4546
+ * @deprecated Use `getSelection().ranges` instead - each range represents a full row.
4473
4547
  */
4474
4548
  getSelectedRows() {
4475
- return [...this.selected];
4549
+ const { mode: e, ranges: t } = this.getSelection();
4550
+ return e === "row" ? t.map((n) => n.from.row) : [];
4476
4551
  }
4477
4552
  /**
4478
4553
  * Get all selected cell ranges in public format.
4554
+ * @deprecated Use `getSelection().ranges` instead.
4479
4555
  */
4480
4556
  getRanges() {
4481
- return ie(this.ranges);
4557
+ return this.getSelection().ranges;
4482
4558
  }
4483
4559
  /**
4484
4560
  * Get all selected cells across all ranges.
4485
4561
  */
4486
4562
  getSelectedCells() {
4487
- return cn(this.ranges);
4563
+ return wn(this.ranges);
4488
4564
  }
4489
4565
  /**
4490
4566
  * Check if a specific cell is in range selection.
4491
4567
  */
4492
4568
  isCellSelected(e, t) {
4493
- return Pe(e, t, this.ranges);
4569
+ return Me(e, t, this.ranges);
4494
4570
  }
4495
4571
  /**
4496
4572
  * Clear all selection.
@@ -4509,13 +4585,13 @@ class Bn extends x {
4509
4585
  endCol: t.to.col
4510
4586
  })), this.activeRange = this.ranges.length > 0 ? this.ranges[this.ranges.length - 1] : null, this.emit("selection-change", {
4511
4587
  mode: this.config.mode,
4512
- ranges: ie(this.ranges)
4588
+ ranges: Ve(this.ranges)
4513
4589
  }), this.requestAfterRender();
4514
4590
  }
4515
4591
  // #endregion
4516
4592
  // #region Private Helpers
4517
4593
  #t() {
4518
- return hn(
4594
+ return vn(
4519
4595
  this.config.mode,
4520
4596
  {
4521
4597
  selectedCell: this.selectedCell,
@@ -4526,56 +4602,24 @@ class Bn extends x {
4526
4602
  );
4527
4603
  }
4528
4604
  // #endregion
4529
- // #region Styles
4530
- styles = un;
4531
- // #endregion
4532
- }
4533
- function zn(s, e, t, n) {
4534
- const i = new Set(s.selected);
4535
- let o = s.anchor;
4536
- if (t === "single")
4537
- i.clear(), i.add(e), o = e;
4538
- else if (t === "multiple") {
4539
- const r = n.ctrlKey || n.metaKey;
4540
- if (n.shiftKey && s.anchor !== null) {
4541
- const l = Math.min(s.anchor, e), a = Math.max(s.anchor, e);
4542
- for (let d = l; d <= a; d++)
4543
- i.add(d);
4544
- } else r ? (i.has(e) ? i.delete(e) : i.add(e), o = e) : (i.clear(), i.add(e), o = e);
4545
- }
4546
- return { selected: i, lastSelected: e, anchor: o };
4547
- }
4548
- function $n(s) {
4549
- const e = /* @__PURE__ */ new Set();
4550
- for (let t = 0; t < s; t++)
4551
- e.add(t);
4552
- return e;
4553
4605
  }
4554
- function Wn(s, e) {
4555
- const t = [], n = [];
4556
- for (const i of e)
4557
- s.has(i) || t.push(i);
4558
- for (const i of s)
4559
- e.has(i) || n.push(i);
4560
- return { added: t, removed: n };
4561
- }
4562
- function O(s, e) {
4606
+ function G(s, e) {
4563
4607
  return Math.floor(s / e);
4564
4608
  }
4565
- function fn(s, e) {
4609
+ function yn(s, e) {
4566
4610
  return {
4567
4611
  start: s * e,
4568
4612
  end: (s + 1) * e
4569
4613
  };
4570
4614
  }
4571
- function gn(s, e, t) {
4572
- const n = O(s, t), i = O(e - 1, t), o = [];
4615
+ function xn(s, e, t) {
4616
+ const n = G(s, t), i = G(e - 1, t), o = [];
4573
4617
  for (let r = n; r <= i; r++)
4574
4618
  o.push(r);
4575
4619
  return o;
4576
4620
  }
4577
- async function qe(s, e, t, n) {
4578
- const i = fn(e, t);
4621
+ async function Pe(s, e, t, n) {
4622
+ const i = yn(e, t);
4579
4623
  return s.getRows({
4580
4624
  startRow: i.start,
4581
4625
  endRow: i.end,
@@ -4583,16 +4627,15 @@ async function qe(s, e, t, n) {
4583
4627
  filterModel: n.filterModel
4584
4628
  });
4585
4629
  }
4586
- function pn(s, e, t) {
4587
- const n = O(s, e), i = t.get(n);
4630
+ function Cn(s, e, t) {
4631
+ const n = G(s, e), i = t.get(n);
4588
4632
  if (!i) return;
4589
4633
  const o = s % e;
4590
4634
  return i[o];
4591
4635
  }
4592
- const mn = 100;
4593
- class jn extends x {
4636
+ const Rn = 100;
4637
+ class Qn extends x {
4594
4638
  name = "serverSide";
4595
- version = "1.0.0";
4596
4639
  get defaultConfig() {
4597
4640
  return {
4598
4641
  pageSize: 100,
@@ -4619,12 +4662,12 @@ class jn extends x {
4619
4662
  */
4620
4663
  loadRequiredBlocks() {
4621
4664
  if (!this.dataSource) return;
4622
- const e = this.grid, t = this.config.cacheBlockSize ?? 100, n = { startRow: e._virtualization.start, endRow: e._virtualization.end }, i = gn(n.startRow, n.endRow, t);
4665
+ const e = this.grid, t = this.config.cacheBlockSize ?? 100, n = { startRow: e._virtualization.start, endRow: e._virtualization.end }, i = xn(n.startRow, n.endRow, t);
4623
4666
  for (const o of i)
4624
4667
  if (!(this.loadedBlocks.has(o) || this.loadingBlocks.has(o))) {
4625
4668
  if (this.loadingBlocks.size >= (this.config.maxConcurrentRequests ?? 2))
4626
4669
  break;
4627
- this.loadingBlocks.add(o), qe(this.dataSource, o, t, {}).then((r) => {
4670
+ this.loadingBlocks.add(o), Pe(this.dataSource, o, t, {}).then((r) => {
4628
4671
  this.loadedBlocks.set(o, r.rows), this.totalRowCount = r.totalRowCount, this.loadingBlocks.delete(o), this.requestRender(), this.loadRequiredBlocks();
4629
4672
  }).catch(() => {
4630
4673
  this.loadingBlocks.delete(o);
@@ -4637,7 +4680,7 @@ class jn extends x {
4637
4680
  if (!this.dataSource) return [...e];
4638
4681
  const t = [];
4639
4682
  for (let n = 0; n < this.totalRowCount; n++) {
4640
- const i = pn(n, this.config.cacheBlockSize ?? 100, this.loadedBlocks);
4683
+ const i = Cn(n, this.config.cacheBlockSize ?? 100, this.loadedBlocks);
4641
4684
  t.push(i ?? { __loading: !0, __index: n });
4642
4685
  }
4643
4686
  return t;
@@ -4645,7 +4688,7 @@ class jn extends x {
4645
4688
  onScroll(e) {
4646
4689
  this.dataSource && (this.loadRequiredBlocks(), this.scrollDebounceTimer && clearTimeout(this.scrollDebounceTimer), this.scrollDebounceTimer = setTimeout(() => {
4647
4690
  this.loadRequiredBlocks();
4648
- }, mn));
4691
+ }, Rn));
4649
4692
  }
4650
4693
  // #endregion
4651
4694
  // #region Public API
@@ -4656,7 +4699,7 @@ class jn extends x {
4656
4699
  setDataSource(e) {
4657
4700
  this.dataSource = e, this.loadedBlocks.clear(), this.loadingBlocks.clear();
4658
4701
  const t = this.config.cacheBlockSize ?? 100;
4659
- qe(e, 0, t, {}).then((n) => {
4702
+ Pe(e, 0, t, {}).then((n) => {
4660
4703
  this.loadedBlocks.set(0, n.rows), this.totalRowCount = n.totalRowCount, this.requestRender();
4661
4704
  });
4662
4705
  }
@@ -4683,7 +4726,7 @@ class jn extends x {
4683
4726
  * @param rowIndex - Row index to check
4684
4727
  */
4685
4728
  isRowLoaded(e) {
4686
- const t = this.config.cacheBlockSize ?? 100, n = O(e, t);
4729
+ const t = this.config.cacheBlockSize ?? 100, n = G(e, t);
4687
4730
  return this.loadedBlocks.has(n);
4688
4731
  }
4689
4732
  /**
@@ -4694,52 +4737,52 @@ class jn extends x {
4694
4737
  }
4695
4738
  // #endregion
4696
4739
  }
4697
- function Ve(s, e, t) {
4740
+ function ze(s, e, t) {
4698
4741
  return s.id !== void 0 ? String(s.id) : t ? `${t}-${e}` : String(e);
4699
4742
  }
4700
- function Ne(s, e) {
4743
+ function Q(s, e) {
4701
4744
  const t = new Set(s);
4702
4745
  return t.has(e) ? t.delete(e) : t.add(e), t;
4703
4746
  }
4704
- function oe(s, e, t = null, n = 0) {
4747
+ function ne(s, e, t = null, n = 0) {
4705
4748
  const i = e.childrenField ?? "children", o = /* @__PURE__ */ new Set();
4706
4749
  for (let r = 0; r < s.length; r++) {
4707
- const l = s[r], a = Ve(l, r, t), d = l[i];
4750
+ const l = s[r], a = ze(l, r, t), d = l[i];
4708
4751
  if (Array.isArray(d) && d.length > 0) {
4709
4752
  o.add(a);
4710
- const c = oe(d, e, a, n + 1);
4711
- for (const h of c) o.add(h);
4753
+ const c = ne(d, e, a, n + 1);
4754
+ for (const u of c) o.add(u);
4712
4755
  }
4713
4756
  }
4714
4757
  return o;
4715
4758
  }
4716
- function wn() {
4759
+ function En() {
4717
4760
  return /* @__PURE__ */ new Set();
4718
4761
  }
4719
- function Be(s, e, t, n = null, i = 0) {
4762
+ function We(s, e, t, n = null, i = 0) {
4720
4763
  const o = t.childrenField ?? "children";
4721
4764
  for (let r = 0; r < s.length; r++) {
4722
- const l = s[r], a = Ve(l, r, n);
4765
+ const l = s[r], a = ze(l, r, n);
4723
4766
  if (a === e)
4724
4767
  return [a];
4725
4768
  const d = l[o];
4726
4769
  if (Array.isArray(d) && d.length > 0) {
4727
- const c = Be(d, e, t, a, i + 1);
4770
+ const c = We(d, e, t, a, i + 1);
4728
4771
  if (c)
4729
4772
  return [a, ...c];
4730
4773
  }
4731
4774
  }
4732
4775
  return null;
4733
4776
  }
4734
- function bn(s, e, t, n) {
4735
- const i = Be(s, e, t);
4777
+ function Sn(s, e, t, n) {
4778
+ const i = We(s, e, t);
4736
4779
  if (!i) return n;
4737
4780
  const o = new Set(n);
4738
4781
  for (let r = 0; r < i.length - 1; r++)
4739
4782
  o.add(i[r]);
4740
4783
  return o;
4741
4784
  }
4742
- function Ke(s, e = "children") {
4785
+ function De(s, e = "children") {
4743
4786
  if (!Array.isArray(s) || s.length === 0) return !1;
4744
4787
  for (const t of s) {
4745
4788
  if (!t) continue;
@@ -4749,7 +4792,7 @@ function Ke(s, e = "children") {
4749
4792
  }
4750
4793
  return !1;
4751
4794
  }
4752
- function vn(s) {
4795
+ function kn(s) {
4753
4796
  if (!Array.isArray(s) || s.length === 0) return null;
4754
4797
  const e = ["children", "items", "nodes", "subRows", "nested"];
4755
4798
  for (const t of s)
@@ -4761,35 +4804,34 @@ function vn(s) {
4761
4804
  }
4762
4805
  return null;
4763
4806
  }
4764
- function yn(s, e = "children", t = 0) {
4807
+ function An(s, e = "children", t = 0) {
4765
4808
  if (!Array.isArray(s) || s.length === 0) return t;
4766
4809
  let n = t;
4767
4810
  for (const i of s) {
4768
4811
  if (!i) continue;
4769
4812
  const o = i[e];
4770
4813
  if (Array.isArray(o) && o.length > 0) {
4771
- const r = yn(o, e, t + 1);
4814
+ const r = An(o, e, t + 1);
4772
4815
  r > n && (n = r);
4773
4816
  }
4774
4817
  }
4775
4818
  return n;
4776
4819
  }
4777
- function xn(s, e = "children") {
4820
+ function _n(s, e = "children") {
4778
4821
  if (!Array.isArray(s)) return 0;
4779
4822
  let t = 0;
4780
4823
  for (const n of s) {
4781
4824
  if (!n) continue;
4782
4825
  t++;
4783
4826
  const i = n[e];
4784
- Array.isArray(i) && (t += xn(i, e));
4827
+ Array.isArray(i) && (t += _n(i, e));
4785
4828
  }
4786
4829
  return t;
4787
4830
  }
4788
- const Cn = ".tree-cell{display:flex;align-items:center;padding-left:calc(var(--tree-depth, 0) * var(--tbw-tree-indent, 20px))}.tree-toggle{cursor:pointer;user-select:none;display:inline-flex;align-items:center;justify-content:center;margin-right:4px}.tree-toggle:hover{color:var(--tbw-tree-accent, var(--tbw-color-accent))}.tree-spacer{width:14px;display:inline-block}.data-grid-row.tbw-tree-slide-in{animation:tbw-tree-slide-in var(--tbw-animation-duration, .2s) var(--tbw-animation-easing, ease-out) forwards}@keyframes tbw-tree-slide-in{0%{opacity:0;transform:translate(-8px)}to{opacity:1;transform:translate(0)}}.data-grid-row.tbw-tree-fade-in{animation:tbw-tree-fade-in var(--tbw-animation-duration, .2s) var(--tbw-animation-easing, ease-out) forwards}@keyframes tbw-tree-fade-in{0%{opacity:0}to{opacity:1}}";
4789
- class Un extends x {
4831
+ const Ln = ".cell[data-field=__tbw_expander]{border-right:none!important;padding:0;display:flex;align-items:center;justify-content:flex-start}.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)}.tree-expander{display:flex;align-items:center;justify-content:flex-start;width:100%;height:100%;box-sizing:border-box}.tree-toggle{cursor:pointer;user-select:none;display:inline-flex;align-items:center;justify-content:center}.tree-toggle:hover{color:var(--tbw-tree-accent, var(--tbw-color-accent))}.tree-spacer{width:14px;display:inline-block}.data-grid-row.tbw-tree-slide-in{animation:tbw-tree-slide-in var(--tbw-animation-duration, .2s) var(--tbw-animation-easing, ease-out) forwards}@keyframes tbw-tree-slide-in{0%{opacity:0;transform:translate(-8px)}to{opacity:1;transform:translate(0)}}.data-grid-row.tbw-tree-fade-in{animation:tbw-tree-fade-in var(--tbw-animation-duration, .2s) var(--tbw-animation-easing, ease-out) forwards}@keyframes tbw-tree-fade-in{0%{opacity:0}to{opacity:1}}";
4832
+ class ei extends x {
4790
4833
  name = "tree";
4791
- version = "1.0.0";
4792
- styles = Cn;
4834
+ styles = Ln;
4793
4835
  get defaultConfig() {
4794
4836
  return {
4795
4837
  childrenField: "children",
@@ -4813,31 +4855,28 @@ class Un extends x {
4813
4855
  }
4814
4856
  // #endregion
4815
4857
  // #region Animation
4858
+ /**
4859
+ * Get expand/collapse animation style from plugin config.
4860
+ * Uses base class isAnimationEnabled to respect grid-level settings.
4861
+ */
4816
4862
  get animationStyle() {
4817
- const t = this.grid.effectiveConfig?.animation?.mode ?? "reduced-motion";
4818
- if (t === !1 || t === "off") return !1;
4819
- if (t !== !0 && t !== "on") {
4820
- const n = this.shadowRoot?.host;
4821
- if (n && getComputedStyle(n).getPropertyValue("--tbw-animation-enabled").trim() === "0")
4822
- return !1;
4823
- }
4824
- return this.config.animation ?? "slide";
4863
+ return this.isAnimationEnabled ? this.config.animation ?? "slide" : !1;
4825
4864
  }
4826
4865
  // #endregion
4827
4866
  // #region Auto-Detection
4828
4867
  detect(e) {
4829
4868
  if (!this.config.autoDetect) return !1;
4830
- const t = e, n = this.config.childrenField ?? vn(t) ?? "children";
4831
- return Ke(t, n);
4869
+ const t = e, n = this.config.childrenField ?? kn(t) ?? "children";
4870
+ return De(t, n);
4832
4871
  }
4833
4872
  // #endregion
4834
4873
  // #region Data Processing
4835
4874
  processRows(e) {
4836
4875
  const t = this.config.childrenField ?? "children", n = e;
4837
- if (!Ke(n, t))
4876
+ if (!De(n, t))
4838
4877
  return this.flattenedRows = [], this.rowKeyMap.clear(), this.previousVisibleKeys.clear(), [...e];
4839
4878
  let i = this.withStableKeys(n);
4840
- this.sortState && (i = this.sortTree(i, this.sortState.field, this.sortState.direction)), this.config.defaultExpanded && !this.initialExpansionDone && (this.expandedKeys = oe(i, this.config), this.initialExpansionDone = !0), this.flattenedRows = this.flattenTree(i, this.expandedKeys), this.rowKeyMap.clear(), this.keysToAnimate.clear();
4879
+ this.sortState && (i = this.sortTree(i, this.sortState.field, this.sortState.direction)), this.config.defaultExpanded && !this.initialExpansionDone && (this.expandedKeys = ne(i, this.config), this.initialExpansionDone = !0), this.flattenedRows = this.flattenTree(i, this.expandedKeys), this.rowKeyMap.clear(), this.keysToAnimate.clear();
4841
4880
  const o = /* @__PURE__ */ new Set();
4842
4881
  for (const r of this.flattenedRows)
4843
4882
  this.rowKeyMap.set(r.key, r), o.add(r.key), !this.previousVisibleKeys.has(r.key) && r.depth > 0 && this.keysToAnimate.add(r.key);
@@ -4865,15 +4904,15 @@ class Un extends x {
4865
4904
  flattenTree(e, t, n = 0) {
4866
4905
  const i = this.config.childrenField ?? "children", o = [];
4867
4906
  for (const r of e) {
4868
- const a = r.__stableKey ?? String(r.id ?? "?"), d = r[i], c = Array.isArray(d) && d.length > 0, h = t.has(a);
4907
+ const a = r.__stableKey ?? String(r.id ?? "?"), d = r[i], c = Array.isArray(d) && d.length > 0, u = t.has(a);
4869
4908
  o.push({
4870
4909
  key: a,
4871
4910
  data: r,
4872
4911
  depth: n,
4873
4912
  hasChildren: c,
4874
- isExpanded: h,
4913
+ isExpanded: u,
4875
4914
  parentKey: n > 0 && a.substring(0, a.lastIndexOf("-")) || null
4876
- }), c && h && o.push(...this.flattenTree(d, t, n + 1));
4915
+ }), c && u && o.push(...this.flattenTree(d, t, n + 1));
4877
4916
  }
4878
4917
  return o;
4879
4918
  }
@@ -4892,40 +4931,52 @@ class Un extends x {
4892
4931
  if (this.flattenedRows.length === 0) return [...e];
4893
4932
  const t = [...e];
4894
4933
  if (t.length === 0) return t;
4895
- const n = { ...t[0] }, i = n.viewRenderer;
4896
- if (i?.__treeWrapped) return t;
4897
- const o = () => this.config, r = this.setIcon.bind(this), l = this.resolveIcon.bind(this), a = (d) => {
4898
- const { value: c, row: h } = d, { indentWidth: u = 20, showExpandIcons: f = !0 } = o(), g = h, p = document.createElement("span");
4899
- if (p.className = "tree-cell", p.style.setProperty("--tree-depth", String(g.__treeDepth ?? 0)), p.style.setProperty("--tbw-tree-indent", `${u}px`), g.__treeHasChildren && f) {
4900
- const m = document.createElement("span");
4901
- m.className = `tree-toggle${g.__treeExpanded ? " expanded" : ""}`, r(m, l(g.__treeExpanded ? "collapse" : "expand")), m.setAttribute("data-tree-key", String(g.__treeKey ?? "")), p.appendChild(m);
4902
- } else if (f) {
4903
- const m = document.createElement("span");
4904
- m.className = "tree-spacer", p.appendChild(m);
4905
- }
4906
- const w = document.createElement("span");
4907
- if (i) {
4908
- const m = i(d);
4909
- m instanceof Node ? w.appendChild(m) : w.textContent = String(m ?? c ?? "");
4934
+ const n = t[0], i = n.viewRenderer, o = () => this.config, r = this.setIcon.bind(this), l = this.resolveIcon.bind(this), a = (d) => {
4935
+ const { row: c, value: u } = d, { indentWidth: h = 20, showExpandIcons: f = !0 } = o(), g = c, p = g.__treeDepth ?? 0, b = document.createElement("span");
4936
+ if (b.className = "tree-cell-wrapper", b.style.paddingLeft = `${Number(p) * h}px`, f)
4937
+ if (g.__treeHasChildren) {
4938
+ const w = document.createElement("span");
4939
+ w.className = `tree-toggle${g.__treeExpanded ? " expanded" : ""}`, r(w, l(g.__treeExpanded ? "collapse" : "expand")), w.setAttribute("data-tree-key", String(g.__treeKey ?? "")), b.appendChild(w);
4940
+ } else {
4941
+ const w = document.createElement("span");
4942
+ w.className = "tree-spacer", b.appendChild(w);
4943
+ }
4944
+ const m = document.createElement("span");
4945
+ if (m.className = "tree-content", i) {
4946
+ const w = i(d);
4947
+ w instanceof Node ? m.appendChild(w) : typeof w == "string" && (m.innerHTML = w);
4910
4948
  } else
4911
- w.textContent = String(c ?? "");
4912
- return p.appendChild(w), p;
4949
+ m.textContent = u != null ? String(u) : "";
4950
+ return b.appendChild(m), b;
4913
4951
  };
4914
- return a.__treeWrapped = !0, n.viewRenderer = a, t[0] = n, t;
4952
+ return t[0] = { ...n, viewRenderer: a }, t;
4915
4953
  }
4916
4954
  // #endregion
4917
4955
  // #region Event Handlers
4918
4956
  onCellClick(e) {
4919
4957
  const t = e.originalEvent?.target;
4920
4958
  if (!t?.classList.contains("tree-toggle")) return !1;
4921
- const n = t.getAttribute("data-tree-key"), i = n ? this.rowKeyMap.get(n) : null;
4922
- return i ? (this.expandedKeys = Ne(this.expandedKeys, n), this.emit("tree-expand", {
4959
+ const n = t.getAttribute("data-tree-key");
4960
+ if (!n) return !1;
4961
+ const i = this.rowKeyMap.get(n);
4962
+ return i ? (this.expandedKeys = Q(this.expandedKeys, n), this.emit("tree-expand", {
4923
4963
  key: n,
4924
4964
  row: i.data,
4925
4965
  expanded: this.expandedKeys.has(n),
4926
4966
  depth: i.depth
4927
4967
  }), this.requestRender(), !0) : !1;
4928
4968
  }
4969
+ onKeyDown(e) {
4970
+ if (e.key !== " ") return;
4971
+ const t = this.grid._focusRow, n = this.flattenedRows[t];
4972
+ if (n?.hasChildren)
4973
+ return e.preventDefault(), this.expandedKeys = Q(this.expandedKeys, n.key), this.emit("tree-expand", {
4974
+ key: n.key,
4975
+ row: n.data,
4976
+ expanded: this.expandedKeys.has(n.key),
4977
+ depth: n.depth
4978
+ }), this.requestRenderWithFocus(), !0;
4979
+ }
4929
4980
  onHeaderClick(e) {
4930
4981
  if (this.flattenedRows.length === 0 || !e.column.sortable) return !1;
4931
4982
  const { field: t } = e.column;
@@ -4954,13 +5005,13 @@ class Un extends x {
4954
5005
  this.expandedKeys.delete(e), this.requestRender();
4955
5006
  }
4956
5007
  toggle(e) {
4957
- this.expandedKeys = Ne(this.expandedKeys, e), this.requestRender();
5008
+ this.expandedKeys = Q(this.expandedKeys, e), this.requestRender();
4958
5009
  }
4959
5010
  expandAll() {
4960
- this.expandedKeys = oe(this.rows, this.config), this.requestRender();
5011
+ this.expandedKeys = ne(this.rows, this.config), this.requestRender();
4961
5012
  }
4962
5013
  collapseAll() {
4963
- this.expandedKeys = wn(), this.requestRender();
5014
+ this.expandedKeys = En(), this.requestRender();
4964
5015
  }
4965
5016
  isExpanded(e) {
4966
5017
  return this.expandedKeys.has(e);
@@ -4975,11 +5026,11 @@ class Un extends x {
4975
5026
  return this.rowKeyMap.get(e)?.data;
4976
5027
  }
4977
5028
  expandToKey(e) {
4978
- this.expandedKeys = bn(this.rows, e, this.config, this.expandedKeys), this.requestRender();
5029
+ this.expandedKeys = Sn(this.rows, e, this.config, this.expandedKeys), this.requestRender();
4979
5030
  }
4980
5031
  // #endregion
4981
5032
  }
4982
- function Rn(s, e, t) {
5033
+ function Tn(s, e, t) {
4983
5034
  const n = [...s.undoStack, e];
4984
5035
  for (; n.length > t; )
4985
5036
  n.shift();
@@ -4989,7 +5040,7 @@ function Rn(s, e, t) {
4989
5040
  // Clear redo on new action
4990
5041
  };
4991
5042
  }
4992
- function De(s) {
5043
+ function Ke(s) {
4993
5044
  if (s.undoStack.length === 0)
4994
5045
  return { newState: s, action: null };
4995
5046
  const e = [...s.undoStack], t = e.pop();
@@ -5001,7 +5052,7 @@ function De(s) {
5001
5052
  action: t
5002
5053
  } : { newState: s, action: null };
5003
5054
  }
5004
- function He(s) {
5055
+ function qe(s) {
5005
5056
  if (s.redoStack.length === 0)
5006
5057
  return { newState: s, action: null };
5007
5058
  const e = [...s.redoStack], t = e.pop();
@@ -5013,16 +5064,16 @@ function He(s) {
5013
5064
  action: t
5014
5065
  } : { newState: s, action: null };
5015
5066
  }
5016
- function En(s) {
5067
+ function In(s) {
5017
5068
  return s.undoStack.length > 0;
5018
5069
  }
5019
- function Sn(s) {
5070
+ function Fn(s) {
5020
5071
  return s.redoStack.length > 0;
5021
5072
  }
5022
- function kn() {
5073
+ function Mn() {
5023
5074
  return { undoStack: [], redoStack: [] };
5024
5075
  }
5025
- function An(s, e, t, n) {
5076
+ function Pn(s, e, t, n) {
5026
5077
  return {
5027
5078
  type: "cell-edit",
5028
5079
  rowIndex: s,
@@ -5032,7 +5083,7 @@ function An(s, e, t, n) {
5032
5083
  timestamp: Date.now()
5033
5084
  };
5034
5085
  }
5035
- class Zn extends x {
5086
+ class ti extends x {
5036
5087
  /**
5037
5088
  * Plugin dependencies - UndoRedoPlugin requires EditingPlugin to track edits.
5038
5089
  *
@@ -5042,7 +5093,6 @@ class Zn extends x {
5042
5093
  { name: "editing", required: !0, reason: "UndoRedoPlugin tracks cell edit history" }
5043
5094
  ];
5044
5095
  name = "undoRedo";
5045
- version = "1.0.0";
5046
5096
  get defaultConfig() {
5047
5097
  return {
5048
5098
  maxHistorySize: 100
@@ -5065,7 +5115,7 @@ class Zn extends x {
5065
5115
  onKeyDown(e) {
5066
5116
  const t = (e.ctrlKey || e.metaKey) && e.key === "z" && !e.shiftKey, n = (e.ctrlKey || e.metaKey) && (e.key === "y" || e.key === "z" && e.shiftKey);
5067
5117
  if (t) {
5068
- const i = De({ undoStack: this.undoStack, redoStack: this.redoStack });
5118
+ const i = Ke({ undoStack: this.undoStack, redoStack: this.redoStack });
5069
5119
  if (i.action) {
5070
5120
  const o = this.rows;
5071
5121
  o[i.action.rowIndex] && (o[i.action.rowIndex][i.action.field] = i.action.oldValue), this.undoStack = i.newState.undoStack, this.redoStack = i.newState.redoStack, this.emit("undo", {
@@ -5076,7 +5126,7 @@ class Zn extends x {
5076
5126
  return !0;
5077
5127
  }
5078
5128
  if (n) {
5079
- const i = He({ undoStack: this.undoStack, redoStack: this.redoStack });
5129
+ const i = qe({ undoStack: this.undoStack, redoStack: this.redoStack });
5080
5130
  if (i.action) {
5081
5131
  const o = this.rows;
5082
5132
  o[i.action.rowIndex] && (o[i.action.rowIndex][i.action.field] = i.action.newValue), this.undoStack = i.newState.undoStack, this.redoStack = i.newState.redoStack, this.emit("redo", {
@@ -5099,7 +5149,7 @@ class Zn extends x {
5099
5149
  * @param newValue - The value after the edit
5100
5150
  */
5101
5151
  recordEdit(e, t, n, i) {
5102
- const o = An(e, t, n, i), r = Rn(
5152
+ const o = Pn(e, t, n, i), r = Tn(
5103
5153
  { undoStack: this.undoStack, redoStack: this.redoStack },
5104
5154
  o,
5105
5155
  this.config.maxHistorySize ?? 100
@@ -5112,7 +5162,7 @@ class Zn extends x {
5112
5162
  * @returns The undone action, or null if nothing to undo
5113
5163
  */
5114
5164
  undo() {
5115
- const e = De({ undoStack: this.undoStack, redoStack: this.redoStack });
5165
+ const e = Ke({ undoStack: this.undoStack, redoStack: this.redoStack });
5116
5166
  if (e.action) {
5117
5167
  const t = this.rows;
5118
5168
  t[e.action.rowIndex] && (t[e.action.rowIndex][e.action.field] = e.action.oldValue), this.undoStack = e.newState.undoStack, this.redoStack = e.newState.redoStack, this.requestRender();
@@ -5125,7 +5175,7 @@ class Zn extends x {
5125
5175
  * @returns The redone action, or null if nothing to redo
5126
5176
  */
5127
5177
  redo() {
5128
- const e = He({ undoStack: this.undoStack, redoStack: this.redoStack });
5178
+ const e = qe({ undoStack: this.undoStack, redoStack: this.redoStack });
5129
5179
  if (e.action) {
5130
5180
  const t = this.rows;
5131
5181
  t[e.action.rowIndex] && (t[e.action.rowIndex][e.action.field] = e.action.newValue), this.undoStack = e.newState.undoStack, this.redoStack = e.newState.redoStack, this.requestRender();
@@ -5136,19 +5186,19 @@ class Zn extends x {
5136
5186
  * Check if there are any actions that can be undone.
5137
5187
  */
5138
5188
  canUndo() {
5139
- return En({ undoStack: this.undoStack, redoStack: this.redoStack });
5189
+ return In({ undoStack: this.undoStack, redoStack: this.redoStack });
5140
5190
  }
5141
5191
  /**
5142
5192
  * Check if there are any actions that can be redone.
5143
5193
  */
5144
5194
  canRedo() {
5145
- return Sn({ undoStack: this.undoStack, redoStack: this.redoStack });
5195
+ return Fn({ undoStack: this.undoStack, redoStack: this.redoStack });
5146
5196
  }
5147
5197
  /**
5148
5198
  * Clear all undo/redo history.
5149
5199
  */
5150
5200
  clearHistory() {
5151
- const e = kn();
5201
+ const e = Mn();
5152
5202
  this.undoStack = e.undoStack, this.redoStack = e.redoStack;
5153
5203
  }
5154
5204
  /**
@@ -5165,12 +5215,12 @@ class Zn extends x {
5165
5215
  }
5166
5216
  // #endregion
5167
5217
  }
5168
- const _n = '.tbw-visibility-content{display:flex;flex-direction:column;height:100%}.tbw-visibility-list{flex:1;overflow-y:auto;padding:8px}.tbw-visibility-row{display:flex;align-items:center;gap:8px;padding:6px 4px;cursor:pointer;font-size:13px;border-radius:var(--tbw-border-radius, 4px);position:relative}.tbw-visibility-row:hover{background:var(--tbw-visibility-hover, var(--tbw-color-row-hover, #f3f4f6))}.tbw-visibility-row input[type=checkbox]{cursor:pointer}.tbw-visibility-row.locked span{color:var(--tbw-color-fg-muted, #888)}.tbw-visibility-handle{cursor:grab;color:var(--tbw-color-fg-muted, #888);font-size:10px;letter-spacing:-2px;user-select:none;flex-shrink:0}.tbw-visibility-row.reorderable:hover .tbw-visibility-handle{color:var(--tbw-color-fg, #1f2937)}.tbw-visibility-label{display:flex;align-items:center;gap:8px;flex:1;cursor:pointer}.tbw-visibility-row.dragging{opacity:.5;cursor:grabbing}.tbw-visibility-row.drop-before:before{content:"";position:absolute;left:0;right:0;top:0;height:2px;background:var(--tbw-reorder-indicator, var(--tbw-color-accent, #3b82f6))}.tbw-visibility-row.drop-after:after{content:"";position:absolute;left:0;right:0;bottom:0;height:2px;background:var(--tbw-reorder-indicator, var(--tbw-color-accent, #3b82f6))}.tbw-visibility-show-all{margin:8px;padding:8px 12px;border:1px solid var(--tbw-visibility-border, var(--tbw-color-border, #e5e7eb));border-radius:var(--tbw-border-radius, 4px);background:var(--tbw-visibility-btn-bg, var(--tbw-color-header-bg, #f9fafb));color:var(--tbw-color-fg, #1f2937);cursor:pointer;font-size:13px}.tbw-visibility-show-all:hover{background:var(--tbw-visibility-hover, var(--tbw-color-row-hover, #f3f4f6))}';
5169
- function Oe(s) {
5218
+ const Dn = '.tbw-visibility-content{display:flex;flex-direction:column;height:100%}.tbw-visibility-list{flex:1;overflow-y:auto;padding:8px}.tbw-visibility-row{display:flex;align-items:center;gap:8px;padding:6px 4px;cursor:pointer;font-size:13px;border-radius:var(--tbw-border-radius, 4px);position:relative}.tbw-visibility-row:hover{background:var(--tbw-visibility-hover, var(--tbw-color-row-hover, #f3f4f6))}.tbw-visibility-row input[type=checkbox]{cursor:pointer}.tbw-visibility-row.locked span{color:var(--tbw-color-fg-muted, #888)}.tbw-visibility-handle{cursor:grab;color:var(--tbw-color-fg-muted, #888);font-size:10px;letter-spacing:-2px;user-select:none;flex-shrink:0}.tbw-visibility-row.reorderable:hover .tbw-visibility-handle{color:var(--tbw-color-fg, #1f2937)}.tbw-visibility-label{display:flex;align-items:center;gap:8px;flex:1;cursor:pointer}.tbw-visibility-row.dragging{opacity:.5;cursor:grabbing}.tbw-visibility-row.drop-before:before{content:"";position:absolute;left:0;right:0;top:0;height:2px;background:var(--tbw-reorder-indicator, var(--tbw-color-accent, #3b82f6))}.tbw-visibility-row.drop-after:after{content:"";position:absolute;left:0;right:0;bottom:0;height:2px;background:var(--tbw-reorder-indicator, var(--tbw-color-accent, #3b82f6))}.tbw-visibility-show-all{margin:8px;padding:8px 12px;border:1px solid var(--tbw-visibility-border, var(--tbw-color-border, #e5e7eb));border-radius:var(--tbw-border-radius, 4px);background:var(--tbw-visibility-btn-bg, var(--tbw-color-header-bg, #f9fafb));color:var(--tbw-color-fg, #1f2937);cursor:pointer;font-size:13px}.tbw-visibility-show-all:hover{background:var(--tbw-visibility-hover, var(--tbw-color-row-hover, #f3f4f6))}';
5219
+ function Ne(s) {
5170
5220
  const e = s.meta ?? {};
5171
5221
  return e.lockPosition !== !0 && e.suppressMovable !== !0;
5172
5222
  }
5173
- class P extends x {
5223
+ class M extends x {
5174
5224
  /**
5175
5225
  * Plugin dependencies - VisibilityPlugin optionally uses ReorderPlugin for drag-drop reordering.
5176
5226
  *
@@ -5180,9 +5230,9 @@ class P extends x {
5180
5230
  { name: "reorder", required: !1, reason: "Enables drag-to-reorder columns in visibility panel" }
5181
5231
  ];
5182
5232
  name = "visibility";
5183
- version = "1.0.0";
5184
5233
  /** Tool panel ID for shell integration */
5185
5234
  static PANEL_ID = "columns";
5235
+ styles = Dn;
5186
5236
  get defaultConfig() {
5187
5237
  return {
5188
5238
  allowHideAll: !1
@@ -5195,6 +5245,12 @@ class P extends x {
5195
5245
  draggedField = null;
5196
5246
  draggedIndex = null;
5197
5247
  dropIndex = null;
5248
+ /** Clear drag-related classes from all rows in a list. */
5249
+ clearDragClasses(e) {
5250
+ e.querySelectorAll(".tbw-visibility-row").forEach((t) => {
5251
+ t.classList.remove("dragging", "drop-target", "drop-before", "drop-after");
5252
+ });
5253
+ }
5198
5254
  // #endregion
5199
5255
  // #region Lifecycle
5200
5256
  detach() {
@@ -5207,7 +5263,7 @@ class P extends x {
5207
5263
  */
5208
5264
  getToolPanel() {
5209
5265
  return {
5210
- id: P.PANEL_ID,
5266
+ id: M.PANEL_ID,
5211
5267
  title: "Columns",
5212
5268
  icon: "☰",
5213
5269
  tooltip: "Column visibility",
@@ -5220,9 +5276,10 @@ class P extends x {
5220
5276
  // #region Public API
5221
5277
  /**
5222
5278
  * Show the visibility sidebar panel.
5279
+ * Opens the tool panel and ensures this section is expanded.
5223
5280
  */
5224
5281
  show() {
5225
- this.grid.openToolPanel(P.PANEL_ID);
5282
+ this.grid.openToolPanel(), this.grid.expandedToolPanelSections.includes(M.PANEL_ID) || this.grid.toggleToolPanelSection(M.PANEL_ID);
5226
5283
  }
5227
5284
  /**
5228
5285
  * Hide the visibility sidebar panel.
@@ -5231,10 +5288,10 @@ class P extends x {
5231
5288
  this.grid.closeToolPanel();
5232
5289
  }
5233
5290
  /**
5234
- * Toggle the visibility sidebar panel.
5291
+ * Toggle the visibility sidebar panel section.
5235
5292
  */
5236
5293
  toggle() {
5237
- this.grid.toggleToolPanel(P.PANEL_ID);
5294
+ this.grid.isToolPanelOpen || this.grid.openToolPanel(), this.grid.toggleToolPanelSection(M.PANEL_ID);
5238
5295
  }
5239
5296
  /**
5240
5297
  * Check if a specific column is visible.
@@ -5259,14 +5316,14 @@ class P extends x {
5259
5316
  * @returns Array of visible field names
5260
5317
  */
5261
5318
  getVisibleColumns() {
5262
- return this.grid.getAllColumns().filter((t) => t.visible).map((t) => t.field);
5319
+ return this.grid.getAllColumns().filter((e) => e.visible).map((e) => e.field);
5263
5320
  }
5264
5321
  /**
5265
5322
  * Get list of all hidden column fields.
5266
5323
  * @returns Array of hidden field names
5267
5324
  */
5268
5325
  getHiddenColumns() {
5269
- return this.grid.getAllColumns().filter((t) => !t.visible).map((t) => t.field);
5326
+ return this.grid.getAllColumns().filter((e) => !e.visible).map((e) => e.field);
5270
5327
  }
5271
5328
  /**
5272
5329
  * Show all columns.
@@ -5289,7 +5346,7 @@ class P extends x {
5289
5346
  * @param field - The field name of the column to show
5290
5347
  */
5291
5348
  showColumn(e) {
5292
- this.grid.setColumnVisible(e, !0);
5349
+ this.setColumnVisible(e, !0);
5293
5350
  }
5294
5351
  /**
5295
5352
  * Hide a specific column.
@@ -5297,7 +5354,7 @@ class P extends x {
5297
5354
  * @param field - The field name of the column to hide
5298
5355
  */
5299
5356
  hideColumn(e) {
5300
- this.grid.setColumnVisible(e, !1);
5357
+ this.setColumnVisible(e, !1);
5301
5358
  }
5302
5359
  /**
5303
5360
  * Get all columns with their visibility status.
@@ -5309,10 +5366,10 @@ class P extends x {
5309
5366
  }
5310
5367
  /**
5311
5368
  * Check if the sidebar panel is currently open.
5312
- * @returns True if the panel is open
5369
+ * @returns True if the panel section is expanded
5313
5370
  */
5314
5371
  isPanelVisible() {
5315
- return this.grid.activeToolPanel === P.PANEL_ID;
5372
+ return this.grid.isToolPanelOpen && this.grid.expandedToolPanelSections.includes(M.PANEL_ID);
5316
5373
  }
5317
5374
  // #endregion
5318
5375
  // #region Private Methods
@@ -5321,15 +5378,15 @@ class P extends x {
5321
5378
  * Returns a cleanup function.
5322
5379
  */
5323
5380
  renderPanelContent(e) {
5324
- const t = this.grid, n = document.createElement("div");
5325
- n.className = "tbw-visibility-content";
5326
- const i = document.createElement("div");
5327
- i.className = "tbw-visibility-list", n.appendChild(i);
5328
- const o = document.createElement("button");
5329
- return o.className = "tbw-visibility-show-all", o.textContent = "Show All", o.addEventListener("click", () => {
5330
- t.showAllColumns(), this.rebuildToggles(i);
5331
- }), n.appendChild(o), this.columnListElement = i, this.rebuildToggles(i), e.appendChild(n), () => {
5332
- this.columnListElement = null, n.remove();
5381
+ const t = document.createElement("div");
5382
+ t.className = "tbw-visibility-content";
5383
+ const n = document.createElement("div");
5384
+ n.className = "tbw-visibility-list", t.appendChild(n);
5385
+ const i = document.createElement("button");
5386
+ return i.className = "tbw-visibility-show-all", i.textContent = "Show All", i.addEventListener("click", () => {
5387
+ this.grid.showAllColumns(), this.rebuildToggles(n);
5388
+ }), t.appendChild(i), this.columnListElement = n, this.rebuildToggles(n), e.appendChild(t), () => {
5389
+ this.columnListElement = null, t.remove();
5333
5390
  };
5334
5391
  }
5335
5392
  /**
@@ -5344,24 +5401,24 @@ class P extends x {
5344
5401
  * When a reorder plugin is present, adds drag handles for reordering.
5345
5402
  */
5346
5403
  rebuildToggles(e) {
5347
- const t = this.grid, n = this.hasReorderPlugin();
5404
+ const t = this.hasReorderPlugin();
5348
5405
  e.innerHTML = "";
5349
- const i = t.getAllColumns();
5350
- for (let o = 0; o < i.length; o++) {
5351
- const r = i[o], l = r.header || r.field, a = document.createElement("div");
5352
- a.className = r.lockVisible ? "tbw-visibility-row locked" : "tbw-visibility-row", a.setAttribute("data-field", r.field), a.setAttribute("data-index", String(o)), n && Oe(r) && (a.draggable = !0, a.classList.add("reorderable"), this.setupDragListeners(a, r.field, o, e));
5353
- const d = document.createElement("label");
5354
- d.className = "tbw-visibility-label";
5355
- const c = document.createElement("input");
5356
- c.type = "checkbox", c.checked = r.visible, c.disabled = r.lockVisible ?? !1, c.addEventListener("change", () => {
5357
- t.toggleColumnVisibility(r.field), setTimeout(() => this.rebuildToggles(e), 0);
5406
+ const n = this.grid.getAllColumns().filter((i) => !i.utility);
5407
+ for (let i = 0; i < n.length; i++) {
5408
+ const o = n[i], r = o.header || o.field, l = document.createElement("div");
5409
+ l.className = o.lockVisible ? "tbw-visibility-row locked" : "tbw-visibility-row", l.setAttribute("data-field", o.field), l.setAttribute("data-index", String(i)), t && Ne(o) && (l.draggable = !0, l.classList.add("reorderable"), this.setupDragListeners(l, o.field, i, e));
5410
+ const a = document.createElement("label");
5411
+ a.className = "tbw-visibility-label";
5412
+ const d = document.createElement("input");
5413
+ d.type = "checkbox", d.checked = o.visible, d.disabled = o.lockVisible ?? !1, d.addEventListener("change", () => {
5414
+ this.grid.toggleColumnVisibility(o.field), setTimeout(() => this.rebuildToggles(e), 0);
5358
5415
  });
5359
- const h = document.createElement("span");
5360
- if (h.textContent = l, d.appendChild(c), d.appendChild(h), n && Oe(r)) {
5416
+ const c = document.createElement("span");
5417
+ if (c.textContent = r, a.appendChild(d), a.appendChild(c), t && Ne(o)) {
5361
5418
  const u = document.createElement("span");
5362
- u.className = "tbw-visibility-handle", this.setIcon(u, this.resolveIcon("dragHandle")), u.title = "Drag to reorder", a.appendChild(u);
5419
+ u.className = "tbw-visibility-handle", this.setIcon(u, this.resolveIcon("dragHandle")), u.title = "Drag to reorder", l.appendChild(u);
5363
5420
  }
5364
- a.appendChild(d), e.appendChild(a);
5421
+ l.appendChild(a), e.appendChild(l);
5365
5422
  }
5366
5423
  }
5367
5424
  /**
@@ -5372,9 +5429,7 @@ class P extends x {
5372
5429
  e.addEventListener("dragstart", (o) => {
5373
5430
  this.isDragging = !0, this.draggedField = t, this.draggedIndex = n, o.dataTransfer && (o.dataTransfer.effectAllowed = "move", o.dataTransfer.setData("text/plain", t)), e.classList.add("dragging");
5374
5431
  }), e.addEventListener("dragend", () => {
5375
- this.isDragging = !1, this.draggedField = null, this.draggedIndex = null, this.dropIndex = null, i.querySelectorAll(".tbw-visibility-row").forEach((o) => {
5376
- o.classList.remove("dragging", "drop-target", "drop-before", "drop-after");
5377
- });
5432
+ this.isDragging = !1, this.draggedField = null, this.draggedIndex = null, this.dropIndex = null, this.clearDragClasses(i);
5378
5433
  }), e.addEventListener("dragover", (o) => {
5379
5434
  if (o.preventDefault(), !this.isDragging || this.draggedField === t) return;
5380
5435
  const r = e.getBoundingClientRect(), l = r.top + r.height / 2;
@@ -5402,57 +5457,55 @@ class P extends x {
5402
5457
  });
5403
5458
  }
5404
5459
  // #endregion
5405
- // #region Styles
5406
- styles = _n;
5407
- // #endregion
5408
5460
  }
5409
5461
  export {
5410
5462
  x as BaseGridPlugin,
5411
- Tn as ClipboardPlugin,
5412
- In as ColumnVirtualizationPlugin,
5413
- Fn as ContextMenuPlugin,
5414
- Jn as DEFAULT_ANIMATION_CONFIG,
5415
- ze as DEFAULT_GRID_ICONS,
5416
- Qn as DGEvents,
5417
- ei as DataGridElement,
5418
- Pn as EditingPlugin,
5419
- qn as ExportPlugin,
5463
+ qn as ClipboardPlugin,
5464
+ Nn as ColumnVirtualizationPlugin,
5465
+ Hn as ContextMenuPlugin,
5466
+ oi as DEFAULT_ANIMATION_CONFIG,
5467
+ $e as DEFAULT_GRID_ICONS,
5468
+ ri as DGEvents,
5469
+ si as DataGridElement,
5470
+ Gn as EditingPlugin,
5471
+ Bn as ExportPlugin,
5420
5472
  U as FOCUSABLE_EDITOR_SELECTOR,
5421
- _ as FilteringPlugin,
5422
- ti as FitModeEnum,
5423
- ni as GridCSSVars,
5424
- ii as GridClasses,
5425
- oi as GridDataAttrs,
5426
- ri as GridElement,
5427
- si as GridSelectors,
5428
- Nn as GroupingColumnsPlugin,
5429
- Kn as GroupingRowsPlugin,
5430
- Dn as MasterDetailPlugin,
5431
- Hn as MultiSortPlugin,
5432
- H as PLUGIN_QUERIES,
5433
- On as PinnedColumnsPlugin,
5434
- Gn as PinnedRowsPlugin,
5435
- M as PivotPlugin,
5436
- li as PluginEvents,
5437
- ai as PluginManager,
5438
- di as RenderPhase,
5439
- Vn as ReorderPlugin,
5440
- Bn as SelectionPlugin,
5441
- jn as ServerSidePlugin,
5442
- Un as TreePlugin,
5443
- Zn as UndoRedoPlugin,
5444
- P as VisibilityPlugin,
5445
- ci as builtInSort,
5446
- it as clearEditingState,
5447
- Wn as computeSelectionDiff,
5448
- xn as countNodes,
5449
- ui as defaultComparator,
5450
- tt as defaultEditorFor,
5451
- Ke as detectTreeStructure,
5452
- yn as getMaxDepth,
5453
- zn as handleRowClick,
5454
- Mn as hasEditingCells,
5455
- vn as inferChildrenField,
5456
- $n as selectAll
5473
+ L as FilteringPlugin,
5474
+ li as FitModeEnum,
5475
+ ai as GridCSSVars,
5476
+ di as GridClasses,
5477
+ ci as GridDataAttrs,
5478
+ ui as GridElement,
5479
+ hi as GridSelectors,
5480
+ Vn as GroupingColumnsPlugin,
5481
+ zn as GroupingRowsPlugin,
5482
+ Ge as MasterDetailPlugin,
5483
+ Wn as MultiSortPlugin,
5484
+ He as PLUGIN_QUERIES,
5485
+ $n as PinnedColumnsPlugin,
5486
+ jn as PinnedRowsPlugin,
5487
+ F as PivotPlugin,
5488
+ fi as PluginEvents,
5489
+ gi as PluginManager,
5490
+ pi as RenderPhase,
5491
+ Un as ReorderPlugin,
5492
+ Jn as SelectionPlugin,
5493
+ Qn as ServerSidePlugin,
5494
+ ei as TreePlugin,
5495
+ ti as UndoRedoPlugin,
5496
+ M as VisibilityPlugin,
5497
+ mi as builtInSort,
5498
+ dt as clearEditingState,
5499
+ Yn as computeSelectionDiff,
5500
+ _n as countNodes,
5501
+ wi as defaultComparator,
5502
+ lt as defaultEditorFor,
5503
+ nt as defaultPasteHandler,
5504
+ De as detectTreeStructure,
5505
+ An as getMaxDepth,
5506
+ Xn as handleRowClick,
5507
+ On as hasEditingCells,
5508
+ kn as inferChildrenField,
5509
+ Zn as selectAll
5457
5510
  };
5458
5511
  //# sourceMappingURL=all.js.map