@toolbox-web/grid 0.4.0 → 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 (161) hide show
  1. package/README.md +10 -13
  2. package/all.js +1124 -1047
  3. package/all.js.map +1 -1
  4. package/index.js +688 -515
  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/internal/validate-config.d.ts +14 -0
  14. package/lib/core/internal/validate-config.d.ts.map +1 -1
  15. package/lib/core/plugin/base-plugin.d.ts +105 -1
  16. package/lib/core/plugin/base-plugin.d.ts.map +1 -1
  17. package/lib/core/plugin/expander-column.d.ts +51 -0
  18. package/lib/core/plugin/expander-column.d.ts.map +1 -0
  19. package/lib/core/plugin/index.d.ts +1 -0
  20. package/lib/core/plugin/index.d.ts.map +1 -1
  21. package/lib/core/plugin/plugin-manager.d.ts +1 -1
  22. package/lib/core/plugin/plugin-manager.d.ts.map +1 -1
  23. package/lib/core/plugin/types.d.ts +117 -1
  24. package/lib/core/plugin/types.d.ts.map +1 -1
  25. package/lib/core/types.d.ts +4 -2
  26. package/lib/core/types.d.ts.map +1 -1
  27. package/lib/plugins/clipboard/ClipboardPlugin.d.ts +9 -2
  28. package/lib/plugins/clipboard/ClipboardPlugin.d.ts.map +1 -1
  29. package/lib/plugins/clipboard/index.d.ts +1 -1
  30. package/lib/plugins/clipboard/index.d.ts.map +1 -1
  31. package/lib/plugins/clipboard/index.js +303 -185
  32. package/lib/plugins/clipboard/index.js.map +1 -1
  33. package/lib/plugins/clipboard/types.d.ts +72 -2
  34. package/lib/plugins/clipboard/types.d.ts.map +1 -1
  35. package/lib/plugins/column-virtualization/ColumnVirtualizationPlugin.d.ts +0 -1
  36. package/lib/plugins/column-virtualization/ColumnVirtualizationPlugin.d.ts.map +1 -1
  37. package/lib/plugins/column-virtualization/index.js +116 -24
  38. package/lib/plugins/column-virtualization/index.js.map +1 -1
  39. package/lib/plugins/context-menu/ContextMenuPlugin.d.ts +0 -1
  40. package/lib/plugins/context-menu/ContextMenuPlugin.d.ts.map +1 -1
  41. package/lib/plugins/context-menu/index.js +164 -72
  42. package/lib/plugins/context-menu/index.js.map +1 -1
  43. package/lib/plugins/editing/EditingPlugin.d.ts +1 -7
  44. package/lib/plugins/editing/EditingPlugin.d.ts.map +1 -1
  45. package/lib/plugins/editing/index.js +213 -133
  46. package/lib/plugins/editing/index.js.map +1 -1
  47. package/lib/plugins/export/ExportPlugin.d.ts +0 -1
  48. package/lib/plugins/export/ExportPlugin.d.ts.map +1 -1
  49. package/lib/plugins/export/index.js +195 -103
  50. package/lib/plugins/export/index.js.map +1 -1
  51. package/lib/plugins/filtering/FilteringPlugin.d.ts +5 -2
  52. package/lib/plugins/filtering/FilteringPlugin.d.ts.map +1 -1
  53. package/lib/plugins/filtering/index.js +145 -43
  54. package/lib/plugins/filtering/index.js.map +1 -1
  55. package/lib/plugins/grouping-columns/GroupingColumnsPlugin.d.ts +1 -2
  56. package/lib/plugins/grouping-columns/GroupingColumnsPlugin.d.ts.map +1 -1
  57. package/lib/plugins/grouping-columns/grouping-columns.d.ts +1 -1
  58. package/lib/plugins/grouping-columns/grouping-columns.d.ts.map +1 -1
  59. package/lib/plugins/grouping-columns/index.js +162 -68
  60. package/lib/plugins/grouping-columns/index.js.map +1 -1
  61. package/lib/plugins/grouping-rows/GroupingRowsPlugin.d.ts +14 -2
  62. package/lib/plugins/grouping-rows/GroupingRowsPlugin.d.ts.map +1 -1
  63. package/lib/plugins/grouping-rows/index.js +246 -138
  64. package/lib/plugins/grouping-rows/index.js.map +1 -1
  65. package/lib/plugins/master-detail/MasterDetailPlugin.d.ts +13 -11
  66. package/lib/plugins/master-detail/MasterDetailPlugin.d.ts.map +1 -1
  67. package/lib/plugins/master-detail/index.js +281 -196
  68. package/lib/plugins/master-detail/index.js.map +1 -1
  69. package/lib/plugins/master-detail/types.d.ts +0 -10
  70. package/lib/plugins/master-detail/types.d.ts.map +1 -1
  71. package/lib/plugins/multi-sort/MultiSortPlugin.d.ts +1 -2
  72. package/lib/plugins/multi-sort/MultiSortPlugin.d.ts.map +1 -1
  73. package/lib/plugins/multi-sort/index.js +121 -31
  74. package/lib/plugins/multi-sort/index.js.map +1 -1
  75. package/lib/plugins/pinned-columns/PinnedColumnsPlugin.d.ts +0 -1
  76. package/lib/plugins/pinned-columns/PinnedColumnsPlugin.d.ts.map +1 -1
  77. package/lib/plugins/pinned-columns/index.js +144 -52
  78. package/lib/plugins/pinned-columns/index.js.map +1 -1
  79. package/lib/plugins/pinned-rows/PinnedRowsPlugin.d.ts +1 -2
  80. package/lib/plugins/pinned-rows/PinnedRowsPlugin.d.ts.map +1 -1
  81. package/lib/plugins/pinned-rows/index.js +178 -88
  82. package/lib/plugins/pinned-rows/index.js.map +1 -1
  83. package/lib/plugins/pivot/PivotPlugin.d.ts +26 -4
  84. package/lib/plugins/pivot/PivotPlugin.d.ts.map +1 -1
  85. package/lib/plugins/pivot/index.js +414 -310
  86. package/lib/plugins/pivot/index.js.map +1 -1
  87. package/lib/plugins/pivot/pivot-rows.d.ts +2 -1
  88. package/lib/plugins/pivot/pivot-rows.d.ts.map +1 -1
  89. package/lib/plugins/reorder/ReorderPlugin.d.ts +13 -10
  90. package/lib/plugins/reorder/ReorderPlugin.d.ts.map +1 -1
  91. package/lib/plugins/reorder/index.js +304 -226
  92. package/lib/plugins/reorder/index.js.map +1 -1
  93. package/lib/plugins/selection/SelectionPlugin.d.ts +21 -3
  94. package/lib/plugins/selection/SelectionPlugin.d.ts.map +1 -1
  95. package/lib/plugins/selection/index.d.ts +2 -2
  96. package/lib/plugins/selection/index.d.ts.map +1 -1
  97. package/lib/plugins/selection/index.js +292 -145
  98. package/lib/plugins/selection/index.js.map +1 -1
  99. package/lib/plugins/selection/types.d.ts +24 -0
  100. package/lib/plugins/selection/types.d.ts.map +1 -1
  101. package/lib/plugins/server-side/ServerSidePlugin.d.ts +0 -1
  102. package/lib/plugins/server-side/ServerSidePlugin.d.ts.map +1 -1
  103. package/lib/plugins/server-side/index.js +95 -3
  104. package/lib/plugins/server-side/index.js.map +1 -1
  105. package/lib/plugins/tree/TreePlugin.d.ts +5 -1
  106. package/lib/plugins/tree/TreePlugin.d.ts.map +1 -1
  107. package/lib/plugins/tree/index.js +213 -112
  108. package/lib/plugins/tree/index.js.map +1 -1
  109. package/lib/plugins/tree/types.d.ts +0 -10
  110. package/lib/plugins/tree/types.d.ts.map +1 -1
  111. package/lib/plugins/undo-redo/UndoRedoPlugin.d.ts +7 -2
  112. package/lib/plugins/undo-redo/UndoRedoPlugin.d.ts.map +1 -1
  113. package/lib/plugins/undo-redo/index.js +112 -12
  114. package/lib/plugins/undo-redo/index.js.map +1 -1
  115. package/lib/plugins/visibility/VisibilityPlugin.d.ts +14 -5
  116. package/lib/plugins/visibility/VisibilityPlugin.d.ts.map +1 -1
  117. package/lib/plugins/visibility/index.js +168 -65
  118. package/lib/plugins/visibility/index.js.map +1 -1
  119. package/package.json +1 -1
  120. package/umd/grid.all.umd.js +21 -17
  121. package/umd/grid.all.umd.js.map +1 -1
  122. package/umd/grid.umd.js +14 -8
  123. package/umd/grid.umd.js.map +1 -1
  124. package/umd/plugins/clipboard.umd.js +5 -7
  125. package/umd/plugins/clipboard.umd.js.map +1 -1
  126. package/umd/plugins/column-virtualization.umd.js +1 -1
  127. package/umd/plugins/column-virtualization.umd.js.map +1 -1
  128. package/umd/plugins/context-menu.umd.js +1 -1
  129. package/umd/plugins/context-menu.umd.js.map +1 -1
  130. package/umd/plugins/editing.umd.js +1 -1
  131. package/umd/plugins/editing.umd.js.map +1 -1
  132. package/umd/plugins/export.umd.js +1 -1
  133. package/umd/plugins/export.umd.js.map +1 -1
  134. package/umd/plugins/filtering.umd.js +1 -1
  135. package/umd/plugins/filtering.umd.js.map +1 -1
  136. package/umd/plugins/grouping-columns.umd.js +1 -1
  137. package/umd/plugins/grouping-columns.umd.js.map +1 -1
  138. package/umd/plugins/grouping-rows.umd.js +1 -1
  139. package/umd/plugins/grouping-rows.umd.js.map +1 -1
  140. package/umd/plugins/master-detail.umd.js +1 -1
  141. package/umd/plugins/master-detail.umd.js.map +1 -1
  142. package/umd/plugins/multi-sort.umd.js +1 -1
  143. package/umd/plugins/multi-sort.umd.js.map +1 -1
  144. package/umd/plugins/pinned-columns.umd.js +1 -1
  145. package/umd/plugins/pinned-columns.umd.js.map +1 -1
  146. package/umd/plugins/pinned-rows.umd.js +1 -1
  147. package/umd/plugins/pinned-rows.umd.js.map +1 -1
  148. package/umd/plugins/pivot.umd.js +1 -1
  149. package/umd/plugins/pivot.umd.js.map +1 -1
  150. package/umd/plugins/reorder.umd.js +1 -1
  151. package/umd/plugins/reorder.umd.js.map +1 -1
  152. package/umd/plugins/selection.umd.js +1 -1
  153. package/umd/plugins/selection.umd.js.map +1 -1
  154. package/umd/plugins/server-side.umd.js +1 -1
  155. package/umd/plugins/server-side.umd.js.map +1 -1
  156. package/umd/plugins/tree.umd.js +1 -1
  157. package/umd/plugins/tree.umd.js.map +1 -1
  158. package/umd/plugins/undo-redo.umd.js +1 -1
  159. package/umd/plugins/undo-redo.umd.js.map +1 -1
  160. package/umd/plugins/visibility.umd.js +1 -1
  161. package/umd/plugins/visibility.umd.js.map +1 -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,20 +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 {
82
+ /**
83
+ * Plugin dependencies - ClipboardPlugin works best with SelectionPlugin.
84
+ *
85
+ * Without SelectionPlugin: copies entire grid, pastes at row 0 col 0.
86
+ * With SelectionPlugin: copies/pastes based on selection.
87
+ */
88
+ static dependencies = [
89
+ { name: "selection", required: !1, reason: "Enables copy/paste of selected cells instead of entire grid" }
90
+ ];
64
91
  name = "clipboard";
65
- version = "1.0.0";
66
92
  get defaultConfig() {
67
93
  return {
68
94
  includeHeaders: !1,
@@ -77,65 +103,107 @@ class Tn extends x {
77
103
  lastCopied = null;
78
104
  // #endregion
79
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
+ }
80
113
  detach() {
81
114
  this.lastCopied = null;
82
115
  }
83
116
  // #endregion
84
117
  // #region Event Handlers
85
118
  onKeyDown(e) {
86
- const t = (e.ctrlKey || e.metaKey) && e.key === "c", n = (e.ctrlKey || e.metaKey) && e.key === "v";
87
- 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;
88
120
  }
89
121
  // #endregion
90
122
  // #region Private Methods
91
123
  /**
92
- * 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
93
131
  */
94
132
  #e(e) {
95
- const t = this.#r(), n = t?.getSelectedRows() ?? [], i = n.length > 0, o = t?.getRanges() ?? [], r = o.length > 0, l = t?.getSelectedCell() != null;
96
- let a, d, c;
97
- if (i && t)
98
- a = B({
99
- rows: this.rows,
100
- columns: [...this.columns],
101
- selectedIndices: n,
102
- config: this.config
103
- }), d = n.length, c = this.columns.filter((h) => !h.hidden && !h.field.startsWith("__")).length;
104
- else if (r && t) {
105
- const h = o[o.length - 1], u = this.#i({
106
- startRow: h.from.row,
107
- startCol: h.from.col,
108
- endRow: h.to.row,
109
- endCol: h.to.col
110
- });
111
- a = u.text, d = u.rowCount, c = u.columnCount;
112
- } else if (l && t) {
113
- const h = t.getSelectedCell(), u = this.#n(h.row, h.col);
114
- if (!u) return;
115
- a = u.text, d = 1, c = 1;
116
- } else {
117
- const h = this.#s(e);
118
- if (!h) return;
119
- 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 };
120
154
  }
121
- z(a).then(() => {
122
- 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
+ });
123
162
  });
124
163
  }
125
164
  /**
126
- * 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
127
178
  */
128
- #t() {
129
- fe().then((e) => {
130
- if (!e) return;
131
- const t = he(e, this.config);
132
- this.emit("paste", { rows: t, text: e });
133
- });
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.
196
+ */
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);
134
202
  }
135
203
  /**
136
204
  * Get the selection plugin instance if available.
137
205
  */
138
- #r() {
206
+ #n() {
139
207
  try {
140
208
  const e = this.grid?.getPluginByName("selection");
141
209
  if (e)
@@ -143,71 +211,45 @@ class Tn extends x {
143
211
  } catch {
144
212
  }
145
213
  }
146
- /**
147
- * Build text for a single cell by row/col index.
148
- */
149
- #n(e, t) {
150
- const n = this.rows[e];
151
- if (!n) return null;
152
- const i = this.columns[t];
153
- if (!i) return null;
154
- const o = n[i.field], r = i.header || i.field;
155
- let l;
156
- if (this.config.includeHeaders) {
157
- const a = o == null ? "" : String(o);
158
- l = `${r}: ${a}`;
159
- } else
160
- l = o == null ? "" : String(o);
161
- return { text: l };
162
- }
163
214
  /**
164
215
  * Build text for a rectangular range of cells.
216
+ * Utility columns (like expander columns) are automatically excluded.
165
217
  */
166
218
  #i(e) {
167
- 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 ?? `
168
- `, 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));
169
221
  if (this.config.includeHeaders) {
170
222
  const g = f.map((p) => p.header || p.field);
171
- u.push(g.join(c));
223
+ h.push(g.join(c));
172
224
  }
173
225
  for (let g = r; g <= l; g++) {
174
226
  const p = this.rows[g];
175
227
  if (!p) continue;
176
- const w = f.map((m) => {
177
- const v = p[m.field];
178
- 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);
179
231
  });
180
- u.push(w.join(c));
232
+ h.push(b.join(c));
181
233
  }
182
234
  return {
183
- text: u.join(h),
235
+ text: h.join(u),
184
236
  rowCount: l - r + 1,
185
237
  columnCount: d - a + 1
186
238
  };
187
239
  }
188
240
  /**
189
- * Build text for a single focused cell from DOM.
190
- * 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.
191
243
  */
192
244
  #s(e) {
193
245
  const t = e.closest("[data-field-cache]");
194
246
  if (!t) return null;
195
- const n = t.dataset.fieldCache;
196
- if (!n) return null;
197
- const i = t.dataset.row;
198
- if (!i) return null;
247
+ const n = t.dataset.fieldCache, i = t.dataset.row;
248
+ if (!n || !i) return null;
199
249
  const o = parseInt(i, 10);
200
250
  if (isNaN(o)) return null;
201
- const r = this.rows[o];
202
- if (!r) return null;
203
- const l = r[n], d = this.columns.find((h) => h.field === n)?.header || n;
204
- let c;
205
- if (this.config.includeHeaders) {
206
- const h = l == null ? "" : String(l);
207
- c = `${d}: ${h}`;
208
- } else
209
- c = l == null ? "" : String(l);
210
- 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 };
211
253
  }
212
254
  // #endregion
213
255
  // #region Public API
@@ -216,13 +258,19 @@ class Tn extends x {
216
258
  * @returns The copied text
217
259
  */
218
260
  async copy() {
219
- const t = this.#r()?.getSelectedRows() ?? [], n = B({
220
- rows: this.rows,
221
- columns: [...this.columns],
222
- selectedIndices: t,
223
- config: this.config
224
- });
225
- 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;
226
274
  }
227
275
  /**
228
276
  * Copy specific rows by index to clipboard.
@@ -230,21 +278,22 @@ class Tn extends x {
230
278
  * @returns The copied text
231
279
  */
232
280
  async copyRows(e) {
233
- const t = B({
234
- rows: this.rows,
235
- columns: [...this.columns],
236
- selectedIndices: e,
237
- config: this.config
238
- });
239
- 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;
240
289
  }
241
290
  /**
242
291
  * Read and parse clipboard content.
243
292
  * @returns Parsed 2D array of cell values, or null if clipboard is empty
244
293
  */
245
294
  async paste() {
246
- const e = await fe();
247
- return e ? he(e, this.config) : null;
295
+ const e = await tt();
296
+ return e ? ue(e, this.config) : null;
248
297
  }
249
298
  /**
250
299
  * Get the last copied text and timestamp.
@@ -255,33 +304,33 @@ class Tn extends x {
255
304
  }
256
305
  // #endregion
257
306
  }
258
- const ge = 100;
259
- function re(s) {
307
+ const he = 100;
308
+ function oe(s) {
260
309
  if (s == null)
261
- return ge;
310
+ return he;
262
311
  if (typeof s == "number")
263
312
  return s;
264
313
  const e = parseFloat(s);
265
- return isNaN(e) ? ge : e;
314
+ return isNaN(e) ? he : e;
266
315
  }
267
- function pe(s) {
268
- return s.map((e) => re(e.width));
316
+ function fe(s) {
317
+ return s.map((e) => oe(e.width));
269
318
  }
270
- function me(s) {
319
+ function ge(s) {
271
320
  const e = [];
272
321
  let t = 0;
273
322
  for (const n of s)
274
- e.push(t), t += re(n.width);
323
+ e.push(t), t += oe(n.width);
275
324
  return e;
276
325
  }
277
- function we(s) {
278
- 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);
279
328
  }
280
- function Ye(s, e, t, n, i) {
329
+ function it(s, e, t, n, i) {
281
330
  const o = t.length;
282
331
  if (o === 0)
283
332
  return { startCol: 0, endCol: 0, visibleColumns: [] };
284
- let r = Je(s, t, n);
333
+ let r = ot(s, t, n);
285
334
  r = Math.max(0, r - i);
286
335
  const l = s + e;
287
336
  let a = r;
@@ -298,7 +347,7 @@ function Ye(s, e, t, n, i) {
298
347
  d.push(c);
299
348
  return { startCol: r, endCol: a, visibleColumns: d };
300
349
  }
301
- function Je(s, e, t) {
350
+ function ot(s, e, t) {
302
351
  let n = 0, i = e.length - 1;
303
352
  for (; n < i; ) {
304
353
  const o = Math.floor((n + i) / 2);
@@ -306,12 +355,11 @@ function Je(s, e, t) {
306
355
  }
307
356
  return n;
308
357
  }
309
- function Qe(s, e, t) {
358
+ function rt(s, e, t) {
310
359
  return t ? s > e : !1;
311
360
  }
312
- class In extends x {
361
+ class Nn extends x {
313
362
  name = "columnVirtualization";
314
- version = "1.0.0";
315
363
  get defaultConfig() {
316
364
  return {
317
365
  autoEnable: !0,
@@ -332,7 +380,7 @@ class In extends x {
332
380
  attach(e) {
333
381
  super.attach(e);
334
382
  const t = this.columns;
335
- 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;
336
384
  }
337
385
  detach() {
338
386
  this.columnWidths = [], this.columnOffsets = [], this.isVirtualized = !1, this.startCol = 0, this.endCol = 0, this.scrollLeft = 0, this.totalWidth = 0;
@@ -340,10 +388,10 @@ class In extends x {
340
388
  // #endregion
341
389
  // #region Hooks
342
390
  processColumns(e) {
343
- const t = Qe(e.length, this.config.threshold ?? 30, this.config.autoEnable ?? !0);
344
- 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)
345
393
  return this.startCol = 0, this.endCol = e.length - 1, [...e];
346
- const n = this.grid.clientWidth || 800, i = Ye(
394
+ const n = this.grid.clientWidth || 800, i = it(
347
395
  this.scrollLeft,
348
396
  n,
349
397
  this.columnOffsets,
@@ -403,14 +451,14 @@ class In extends x {
403
451
  }
404
452
  // #endregion
405
453
  }
406
- 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}";
407
- 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) {
408
456
  return (typeof s == "function" ? s(e) : s).filter((n) => !(n.hidden === !0 || typeof n.hidden == "function" && n.hidden(e)));
409
457
  }
410
- function et(s, e) {
458
+ function st(s, e) {
411
459
  return s.disabled === !0 ? !0 : typeof s.disabled == "function" ? s.disabled(e) : !1;
412
460
  }
413
- function ne(s, e, t, n = ze.submenuArrow) {
461
+ function te(s, e, t, n = $e.submenuArrow) {
414
462
  const i = document.createElement("div");
415
463
  i.className = "tbw-context-menu", i.setAttribute("role", "menu");
416
464
  for (const o of s) {
@@ -421,7 +469,7 @@ function ne(s, e, t, n = ze.submenuArrow) {
421
469
  }
422
470
  const r = document.createElement("div");
423
471
  r.className = "tbw-context-menu-item", o.cssClass && r.classList.add(o.cssClass), r.setAttribute("role", "menuitem"), r.setAttribute("data-id", o.id);
424
- const l = et(o, e);
472
+ const l = st(o, e);
425
473
  if (l && (r.classList.add("disabled"), r.setAttribute("aria-disabled", "true")), o.icon) {
426
474
  const d = document.createElement("span");
427
475
  d.className = "tbw-context-menu-icon", d.innerHTML = o.icon, r.appendChild(d);
@@ -435,8 +483,8 @@ function ne(s, e, t, n = ze.submenuArrow) {
435
483
  const d = document.createElement("span");
436
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", () => {
437
485
  if (r.querySelector(".tbw-context-menu") || !o.subMenu) return;
438
- const h = te(o.subMenu, e), u = ne(h, e, t, n);
439
- 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);
440
488
  }), r.addEventListener("mouseleave", () => {
441
489
  const c = r.querySelector(".tbw-context-menu");
442
490
  c && c.remove();
@@ -448,13 +496,13 @@ function ne(s, e, t, n = ze.submenuArrow) {
448
496
  }
449
497
  return i;
450
498
  }
451
- function be(s, e, t) {
499
+ function me(s, e, t) {
452
500
  s.style.position = "fixed", s.style.left = `${e}px`, s.style.top = `${t}px`, s.style.visibility = "hidden", s.style.zIndex = "10000";
453
501
  const n = s.getBoundingClientRect(), i = window.innerWidth, o = window.innerHeight;
454
502
  let r = e, l = t;
455
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";
456
504
  }
457
- let L = null, T = null, k = null, W = 0;
505
+ let T = null, I = null, k = null, $ = 0;
458
506
  const j = [
459
507
  {
460
508
  id: "copy",
@@ -473,9 +521,8 @@ const j = [
473
521
  }
474
522
  }
475
523
  ];
476
- class Fn extends x {
524
+ class Hn extends x {
477
525
  name = "contextMenu";
478
- version = "1.0.0";
479
526
  get defaultConfig() {
480
527
  return {
481
528
  items: j
@@ -489,7 +536,7 @@ class Fn extends x {
489
536
  // #endregion
490
537
  // #region Lifecycle
491
538
  attach(e) {
492
- super.attach(e), this.installGlobalHandlers(), W++;
539
+ super.attach(e), this.installGlobalHandlers(), $++;
493
540
  }
494
541
  detach() {
495
542
  this.menuElement && (this.menuElement.remove(), this.menuElement = null), this.isOpen = !1, this.params = null, this.uninstallGlobalHandlers();
@@ -497,18 +544,18 @@ class Fn extends x {
497
544
  // #endregion
498
545
  // #region Private Methods
499
546
  installGlobalHandlers() {
500
- !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 = () => {
501
548
  document.querySelectorAll(".tbw-context-menu").forEach((t) => t.remove());
502
- }, document.addEventListener("click", L)), T || (T = (e) => {
549
+ }, document.addEventListener("click", T)), I || (I = (e) => {
503
550
  e.key === "Escape" && document.querySelectorAll(".tbw-context-menu").forEach((n) => n.remove());
504
- }, document.addEventListener("keydown", T));
551
+ }, document.addEventListener("keydown", I));
505
552
  }
506
553
  /**
507
554
  * Clean up global handlers when the last instance detaches.
508
555
  * Uses reference counting to ensure handlers persist while any grid uses the plugin.
509
556
  */
510
557
  uninstallGlobalHandlers() {
511
- 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));
512
559
  }
513
560
  // #endregion
514
561
  // #region Hooks
@@ -522,25 +569,25 @@ class Fn extends x {
522
569
  const o = i.target, r = o.closest("[data-row][data-col]"), l = o.closest(".header-cell");
523
570
  let a;
524
571
  if (r) {
525
- 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];
526
573
  a = {
527
574
  row: f,
528
575
  rowIndex: c,
529
- column: u,
530
- columnIndex: h,
531
- field: u?.field ?? "",
532
- value: f?.[u?.field] ?? null,
576
+ column: h,
577
+ columnIndex: u,
578
+ field: h?.field ?? "",
579
+ value: f?.[h?.field] ?? null,
533
580
  isHeader: !1,
534
581
  event: i
535
582
  };
536
583
  } else if (l) {
537
- 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];
538
585
  a = {
539
586
  row: null,
540
587
  rowIndex: -1,
541
- column: h,
588
+ column: u,
542
589
  columnIndex: c,
543
- field: h?.field ?? "",
590
+ field: u?.field ?? "",
544
591
  value: null,
545
592
  isHeader: !0,
546
593
  event: i
@@ -548,15 +595,15 @@ class Fn extends x {
548
595
  } else
549
596
  return;
550
597
  this.params = a, this.position = { x: i.clientX, y: i.clientY };
551
- const d = te(this.config.items ?? j, a);
552
- 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(
553
600
  d,
554
601
  a,
555
602
  (c) => {
556
603
  c.action && c.action(a), this.menuElement?.remove(), this.menuElement = null, this.isOpen = !1;
557
604
  },
558
605
  this.gridIcons.submenuArrow
559
- ), 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 }));
560
607
  }));
561
608
  }
562
609
  // #endregion
@@ -577,15 +624,15 @@ class Fn extends x {
577
624
  value: n.value ?? null,
578
625
  isHeader: n.isHeader ?? !1,
579
626
  event: n.event ?? new MouseEvent("contextmenu")
580
- }, o = te(this.config.items ?? j, i);
581
- 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(
582
629
  o,
583
630
  i,
584
631
  (r) => {
585
632
  r.action && r.action(i), this.menuElement?.remove(), this.menuElement = null, this.isOpen = !1;
586
633
  },
587
634
  this.gridIcons.submenuArrow
588
- ), 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;
589
636
  }
590
637
  /**
591
638
  * Hide the context menu.
@@ -603,7 +650,7 @@ class Fn extends x {
603
650
  // #endregion
604
651
  // Styles are injected globally via installGlobalHandlers() since menu renders in document.body
605
652
  }
606
- function tt(s) {
653
+ function lt(s) {
607
654
  switch (s.type) {
608
655
  case "number":
609
656
  return (e) => {
@@ -657,30 +704,30 @@ function tt(s) {
657
704
  }
658
705
  }
659
706
  const U = 'input,select,textarea,[contenteditable="true"],[contenteditable=""],[tabindex]:not([tabindex="-1"])';
660
- function I(s) {
707
+ function P(s) {
661
708
  return !(typeof s != "string" || s === "__proto__" || s === "constructor" || s === "prototype");
662
709
  }
663
- function Mn(s) {
710
+ function On(s) {
664
711
  return (s.__editingCellCount ?? 0) > 0;
665
712
  }
666
- function nt(s) {
713
+ function at(s) {
667
714
  const e = (s.__editingCellCount ?? 0) + 1;
668
715
  s.__editingCellCount = e, s.setAttribute("data-has-editing", "");
669
716
  }
670
- function it(s) {
717
+ function dt(s) {
671
718
  s.__editingCellCount = 0, s.removeAttribute("data-has-editing");
672
719
  }
673
- 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) {
674
724
  const n = s.querySelector("input,textarea,select");
675
- if (!n) return;
676
- 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;
677
- n.addEventListener("blur", () => {
678
- t(i());
679
- }), 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))));
680
728
  }
681
- class Pn extends x {
729
+ class Gn extends x {
682
730
  name = "editing";
683
- version = "1.0.0";
684
731
  get defaultConfig() {
685
732
  return {
686
733
  editOn: "click"
@@ -732,15 +779,6 @@ class Pn extends x {
732
779
  this.#e = -1, this.#t = -1, this.#r.clear(), this.#n.clear(), this.#i.clear(), super.detach();
733
780
  }
734
781
  // #endregion
735
- // #region Config Augmentation (processColumns hook)
736
- /**
737
- * Augment columns with editing metadata.
738
- * This enables the grid to recognize editable columns without core knowledge.
739
- */
740
- processColumns(e) {
741
- return e;
742
- }
743
- // #endregion
744
782
  // #region Event Handlers (event distribution)
745
783
  /**
746
784
  * Handle cell clicks - start editing if configured for click mode.
@@ -768,7 +806,7 @@ class Pn extends x {
768
806
  const o = t._visibleColumns[i], r = t._rows[n];
769
807
  if (o?.editable && o.type === "boolean" && r) {
770
808
  const l = o.field;
771
- if (I(l)) {
809
+ if (P(l)) {
772
810
  const d = !r[l];
773
811
  return this.#a(n, o, d, r), e.preventDefault(), this.requestRender(), !0;
774
812
  }
@@ -943,10 +981,10 @@ class Pn extends x {
943
981
  if (isNaN(d)) return;
944
982
  const c = n._visibleColumns[d];
945
983
  if (!c) return;
946
- const h = a.querySelector("input,textarea,select");
947
- if (h) {
948
- let u;
949
- 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);
950
988
  }
951
989
  }), t && i && o)
952
990
  Object.keys(i).forEach((l) => {
@@ -966,7 +1004,7 @@ class Pn extends x {
966
1004
  for (const l of this.#i)
967
1005
  l.startsWith(`${e}:`) && this.#i.delete(l);
968
1006
  r && (r.querySelectorAll(".cell.editing").forEach((l) => {
969
- l.classList.remove("editing"), it(l.parentElement);
1007
+ l.classList.remove("editing"), dt(l.parentElement);
970
1008
  }), this.requestRender()), this.#s = !0, r || (this.#u(n), this.#s = !1);
971
1009
  }
972
1010
  /**
@@ -974,65 +1012,68 @@ class Pn extends x {
974
1012
  */
975
1013
  #a(e, t, n, i) {
976
1014
  const o = t.field;
977
- if (!I(o) || i[o] === n) return;
978
- i[o] = n;
1015
+ if (!P(o)) return;
1016
+ const r = i[o];
1017
+ if (r === n) return;
979
1018
  const l = !this.#n.has(e);
980
- this.#n.add(e), this.#l();
981
- const d = this.grid.findRenderedRowElement?.(e);
982
- d && d.classList.add("changed"), this.emit("cell-commit", {
1019
+ if (this.emitCancelable("cell-commit", {
983
1020
  row: i,
984
1021
  field: o,
1022
+ oldValue: r,
985
1023
  value: n,
986
1024
  rowIndex: e,
987
1025
  changedRows: this.changedRows,
988
1026
  changedRowIndices: this.changedRowIndices,
989
1027
  firstTimeForRow: l
990
- });
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");
991
1032
  }
992
1033
  /**
993
1034
  * Inject an editor into a cell.
994
1035
  */
995
1036
  #d(e, t, n, i, o, r) {
996
1037
  if (!n.editable || o.classList.contains("editing")) return;
997
- const l = I(n.field) ? e[n.field] : void 0;
1038
+ const l = P(n.field) ? e[n.field] : void 0;
998
1039
  o.classList.add("editing"), this.#i.add(`${t}:${i}`);
999
1040
  const a = o.parentElement;
1000
- a && nt(a);
1041
+ a && at(a);
1001
1042
  let d = !1;
1002
1043
  const c = (m) => {
1003
1044
  d || this.#e === -1 || this.#a(t, n, m, e);
1004
- }, h = () => {
1005
- d = !0, I(n.field) && (e[n.field] = l);
1006
- }, u = document.createElement("div");
1007
- u.style.display = "contents", o.innerHTML = "", o.appendChild(u), u.addEventListener("keydown", (m) => {
1008
- 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));
1009
1050
  });
1010
- 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;
1011
1052
  if (p === "template" && g)
1012
- this.#f(u, f, e, l, c, h, r, t);
1053
+ this.#f(h, f, e, l, c, u, r, t);
1013
1054
  else if (typeof p == "string") {
1014
1055
  const m = document.createElement(p);
1015
- m.value = w, m.addEventListener("change", () => c(m.value)), u.appendChild(m), r || queueMicrotask(() => {
1016
- 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 });
1017
1058
  });
1018
1059
  } else if (typeof p == "function") {
1019
- const m = { row: e, value: w, field: n.field, column: n, commit: c, cancel: h }, v = p(m);
1020
- typeof v == "string" ? (u.innerHTML = v, ot(u, n, c)) : v instanceof Node && u.appendChild(v), r || queueMicrotask(() => {
1021
- 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 });
1022
1063
  });
1023
1064
  } else if (p && typeof p == "object") {
1024
- const m = this.grid, v = document.createElement("div");
1025
- v.setAttribute("data-external-editor", ""), v.setAttribute("data-field", n.field), u.appendChild(v);
1026
- 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 };
1027
1068
  if (p.mount)
1028
1069
  try {
1029
- p.mount({ placeholder: v, context: A, spec: p });
1070
+ p.mount({ placeholder: w, context: A, spec: p });
1030
1071
  } catch (q) {
1031
1072
  console.warn(`[tbw-grid] External editor mount error for column '${n.field}':`, q);
1032
1073
  }
1033
1074
  else
1034
1075
  m.dispatchEvent(
1035
- 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 } })
1036
1077
  );
1037
1078
  }
1038
1079
  }
@@ -1042,8 +1083,8 @@ class Pn extends x {
1042
1083
  #f(e, t, n, i, o, r, l, a) {
1043
1084
  const d = t.__editorTemplate;
1044
1085
  if (!d) return;
1045
- const c = d.cloneNode(!0), h = t.__compiledEditor;
1046
- h ? c.innerHTML = h({
1086
+ const c = d.cloneNode(!0), u = t.__compiledEditor;
1087
+ u ? c.innerHTML = u({
1047
1088
  row: n,
1048
1089
  value: i,
1049
1090
  field: t.field,
@@ -1052,30 +1093,23 @@ class Pn extends x {
1052
1093
  cancel: r
1053
1094
  }) : c.querySelectorAll("*").forEach((f) => {
1054
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) => {
1055
- if (!I(p)) return "";
1056
- const w = n[p];
1057
- return w == null ? "" : String(w);
1096
+ if (!P(p)) return "";
1097
+ const b = n[p];
1098
+ return b == null ? "" : String(b);
1058
1099
  }) || "");
1059
1100
  });
1060
- const u = c.querySelector(
1101
+ const h = c.querySelector(
1061
1102
  "input,textarea,select"
1062
1103
  );
1063
- if (u) {
1064
- 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 ?? "");
1065
1106
  let f = !1;
1066
- u.addEventListener("blur", () => {
1067
- if (f) return;
1068
- const g = u instanceof HTMLInputElement && u.type === "checkbox" ? u.checked : u.value;
1069
- o(g);
1070
- }), u.addEventListener("keydown", (g) => {
1107
+ h.addEventListener("blur", () => {
1108
+ f || o(K(h, t));
1109
+ }), h.addEventListener("keydown", (g) => {
1071
1110
  const p = g;
1072
- if (p.key === "Enter") {
1073
- p.stopPropagation(), p.preventDefault(), f = !0;
1074
- const w = u instanceof HTMLInputElement && u.type === "checkbox" ? u.checked : u.value;
1075
- o(w), this.#o(a, !1);
1076
- }
1077
- p.key === "Escape" && (p.stopPropagation(), p.preventDefault(), r(), this.#o(a, !0));
1078
- }), 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);
1079
1113
  }
1080
1114
  e.appendChild(c);
1081
1115
  }
@@ -1099,7 +1133,7 @@ class Pn extends x {
1099
1133
  }
1100
1134
  // #endregion
1101
1135
  }
1102
- function ve(s, e = !0) {
1136
+ function we(s, e = !0) {
1103
1137
  if (s == null) return "";
1104
1138
  if (s instanceof Date) return s.toISOString();
1105
1139
  if (typeof s == "object") return JSON.stringify(s);
@@ -1107,37 +1141,37 @@ function ve(s, e = !0) {
1107
1141
  return e && (t.includes(",") || t.includes('"') || t.includes(`
1108
1142
  `) || t.includes("\r")) ? `"${t.replace(/"/g, '""')}"` : t;
1109
1143
  }
1110
- function rt(s, e, t, n = {}) {
1144
+ function ut(s, e, t, n = {}) {
1111
1145
  const i = n.delimiter ?? ",", o = n.newline ?? `
1112
1146
  `, r = [], l = n.bom ? "\uFEFF" : "";
1113
1147
  if (t.includeHeaders !== !1) {
1114
1148
  const a = e.map((d) => {
1115
- const c = d.header || d.field, h = t.processHeader ? t.processHeader(c, d.field) : c;
1116
- return ve(h);
1149
+ const c = d.header || d.field, u = t.processHeader ? t.processHeader(c, d.field) : c;
1150
+ return we(u);
1117
1151
  });
1118
1152
  r.push(a.join(i));
1119
1153
  }
1120
1154
  for (const a of s) {
1121
1155
  const d = e.map((c) => {
1122
- let h = a[c.field];
1123
- 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);
1124
1158
  });
1125
1159
  r.push(d.join(i));
1126
1160
  }
1127
1161
  return l + r.join(o);
1128
1162
  }
1129
- function se(s, e) {
1163
+ function re(s, e) {
1130
1164
  const t = URL.createObjectURL(s), n = document.createElement("a");
1131
1165
  n.href = t, n.download = e, n.style.display = "none", document.body.appendChild(n), n.click(), document.body.removeChild(n), URL.revokeObjectURL(t);
1132
1166
  }
1133
- function st(s, e) {
1167
+ function ht(s, e) {
1134
1168
  const t = new Blob([s], { type: "text/csv;charset=utf-8;" });
1135
- se(t, e);
1169
+ re(t, e);
1136
1170
  }
1137
- function ye(s) {
1171
+ function be(s) {
1138
1172
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
1139
1173
  }
1140
- function lt(s, e, t) {
1174
+ function ft(s, e, t) {
1141
1175
  let n = `<?xml version="1.0" encoding="UTF-8"?>
1142
1176
  <?mso-application progid="Excel.Sheet"?>
1143
1177
  <Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
@@ -1149,7 +1183,7 @@ function lt(s, e, t) {
1149
1183
  <Row>`;
1150
1184
  for (const i of e) {
1151
1185
  const o = i.header || i.field, r = t.processHeader ? t.processHeader(o, i.field) : o;
1152
- n += `<Cell><Data ss:Type="String">${ye(r)}</Data></Cell>`;
1186
+ n += `<Cell><Data ss:Type="String">${be(r)}</Data></Cell>`;
1153
1187
  }
1154
1188
  n += "</Row>";
1155
1189
  }
@@ -1160,7 +1194,7 @@ function lt(s, e, t) {
1160
1194
  let r = i[o.field];
1161
1195
  t.processCell && (r = t.processCell(r, o.field, i));
1162
1196
  let l = "String", a = "";
1163
- 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>`;
1164
1198
  }
1165
1199
  n += "</Row>";
1166
1200
  }
@@ -1169,15 +1203,14 @@ function lt(s, e, t) {
1169
1203
  </Worksheet>
1170
1204
  </Workbook>`, n;
1171
1205
  }
1172
- function at(s, e) {
1206
+ function gt(s, e) {
1173
1207
  const t = e.endsWith(".xls") ? e : `${e}.xls`, n = new Blob([s], {
1174
1208
  type: "application/vnd.ms-excel;charset=utf-8;"
1175
1209
  });
1176
- se(n, t);
1210
+ re(n, t);
1177
1211
  }
1178
- class qn extends x {
1212
+ class Bn extends x {
1179
1213
  name = "export";
1180
- version = "1.0.0";
1181
1214
  get defaultConfig() {
1182
1215
  return {
1183
1216
  fileName: "export",
@@ -1209,34 +1242,34 @@ class qn extends x {
1209
1242
  let r = [...this.rows];
1210
1243
  if (n.onlySelected) {
1211
1244
  const a = this.getSelectionState();
1212
- 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));
1213
1246
  }
1214
1247
  t?.rowIndices && (r = t.rowIndices.map((a) => this.rows[a]).filter(Boolean)), this.isExportingFlag = !0;
1215
1248
  let l = i.fileName;
1216
1249
  try {
1217
1250
  switch (e) {
1218
1251
  case "csv": {
1219
- const a = rt(r, o, i, { bom: !0 });
1220
- 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);
1221
1254
  break;
1222
1255
  }
1223
1256
  case "excel": {
1224
- const a = lt(r, o, i);
1225
- 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);
1226
1259
  break;
1227
1260
  }
1228
1261
  case "json": {
1229
- const a = r.map((h) => {
1230
- const u = {};
1262
+ const a = r.map((u) => {
1263
+ const h = {};
1231
1264
  for (const f of o) {
1232
- let g = h[f.field];
1233
- 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;
1234
1267
  }
1235
- return u;
1268
+ return h;
1236
1269
  }), d = JSON.stringify(a, null, 2);
1237
1270
  l = l.endsWith(".json") ? l : `${l}.json`;
1238
1271
  const c = new Blob([d], { type: "application/json" });
1239
- se(c, l);
1272
+ re(c, l);
1240
1273
  break;
1241
1274
  }
1242
1275
  }
@@ -1296,7 +1329,7 @@ class qn extends x {
1296
1329
  }
1297
1330
  // #endregion
1298
1331
  }
1299
- function dt(s) {
1332
+ function pt(s) {
1300
1333
  const { totalRows: e, viewportHeight: t, scrollTop: n, rowHeight: i, overscan: o } = s, r = Math.ceil(t / i);
1301
1334
  let l = Math.floor(n / i) - o;
1302
1335
  l < 0 && (l = 0);
@@ -1308,10 +1341,10 @@ function dt(s) {
1308
1341
  totalHeight: e * i
1309
1342
  };
1310
1343
  }
1311
- function ct(s, e) {
1344
+ function mt(s, e) {
1312
1345
  return s <= e;
1313
1346
  }
1314
- function ut(s, e, t = !1) {
1347
+ function wt(s, e, t = !1) {
1315
1348
  const n = s[e.field];
1316
1349
  if (e.operator === "blank")
1317
1350
  return n == null || n === "";
@@ -1353,10 +1386,10 @@ function ut(s, e, t = !1) {
1353
1386
  return !0;
1354
1387
  }
1355
1388
  }
1356
- function ht(s, e, t = !1) {
1357
- 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;
1358
1391
  }
1359
- function ft(s) {
1392
+ function vt(s) {
1360
1393
  return JSON.stringify(
1361
1394
  s.map((e) => ({
1362
1395
  field: e.field,
@@ -1366,7 +1399,7 @@ function ft(s) {
1366
1399
  }))
1367
1400
  );
1368
1401
  }
1369
- function xe(s, e) {
1402
+ function ve(s, e) {
1370
1403
  const t = /* @__PURE__ */ new Set();
1371
1404
  for (const n of s) {
1372
1405
  const i = n[e];
@@ -1374,10 +1407,10 @@ function xe(s, e) {
1374
1407
  }
1375
1408
  return [...t].sort((n, i) => typeof n == "number" && typeof i == "number" ? n - i : String(n).localeCompare(String(i)));
1376
1409
  }
1377
- 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)))}";
1378
- 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 {
1379
1412
  name = "filtering";
1380
- version = "1.0.0";
1413
+ styles = yt;
1381
1414
  get defaultConfig() {
1382
1415
  return {
1383
1416
  debounceMs: 300,
@@ -1402,6 +1435,12 @@ class _ extends x {
1402
1435
  static LIST_OVERSCAN = 3;
1403
1436
  static LIST_BYPASS_THRESHOLD = 50;
1404
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
+ }
1405
1444
  // #endregion
1406
1445
  // #region Lifecycle
1407
1446
  attach(e) {
@@ -1417,10 +1456,10 @@ class _ extends x {
1417
1456
  if (!t.length) return [...e];
1418
1457
  if (this.config.filterHandler)
1419
1458
  return this.cachedResult ? this.cachedResult : [...e];
1420
- const n = ft(t);
1459
+ const n = vt(t);
1421
1460
  if (this.cacheKey === n && this.cachedResult)
1422
1461
  return this.cachedResult;
1423
- const i = ht([...e], t, this.config.caseSensitive);
1462
+ const i = bt([...e], t, this.config.caseSensitive);
1424
1463
  return this.cachedResult = i, this.cacheKey = n, i;
1425
1464
  }
1426
1465
  afterRender() {
@@ -1453,7 +1492,13 @@ class _ extends x {
1453
1492
  * Pass null to remove the filter.
1454
1493
  */
1455
1494
  setFilter(e, t) {
1456
- 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", {
1457
1502
  filters: [...this.filters.values()],
1458
1503
  filteredRowCount: 0
1459
1504
  // Will be accurate after processRows
@@ -1483,7 +1528,7 @@ class _ extends x {
1483
1528
  setFilterModel(e) {
1484
1529
  this.filters.clear(), this.excludedValues.clear();
1485
1530
  for (const t of e)
1486
- 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);
1487
1532
  this.cachedResult = null, this.cacheKey = null, this.emit("filter-change", {
1488
1533
  filters: [...this.filters.values()],
1489
1534
  filteredRowCount: 0
@@ -1524,7 +1569,7 @@ class _ extends x {
1524
1569
  * Uses sourceRows to include all values regardless of current filter.
1525
1570
  */
1526
1571
  getUniqueValues(e) {
1527
- return xe(this.sourceRows, e);
1572
+ return ve(this.sourceRows, e);
1528
1573
  }
1529
1574
  // #endregion
1530
1575
  // #region Private Methods
@@ -1538,7 +1583,7 @@ class _ extends x {
1538
1583
  return;
1539
1584
  }
1540
1585
  const e = document.createElement("style");
1541
- 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;
1542
1587
  }
1543
1588
  /**
1544
1589
  * Toggle the filter panel for a field
@@ -1556,7 +1601,7 @@ class _ extends x {
1556
1601
  });
1557
1602
  return;
1558
1603
  }
1559
- const o = xe(this.sourceRows, e);
1604
+ const o = ve(this.sourceRows, e);
1560
1605
  this.renderPanelContent(e, t, i, o), document.body.appendChild(i), this.positionPanel(i, n), this.setupPanelCloseHandler(i, n);
1561
1606
  }
1562
1607
  /**
@@ -1574,8 +1619,8 @@ class _ extends x {
1574
1619
  applySetFilter: (d) => {
1575
1620
  this.applySetFilter(e, d), this.closeFilterPanel();
1576
1621
  },
1577
- applyTextFilter: (d, c, h) => {
1578
- this.applyTextFilter(e, d, c, h), this.closeFilterPanel();
1622
+ applyTextFilter: (d, c, u) => {
1623
+ this.applyTextFilter(e, d, c, u), this.closeFilterPanel();
1579
1624
  },
1580
1625
  clearFilter: () => {
1581
1626
  this.clearFieldFilter(e), this.closeFilterPanel();
@@ -1629,17 +1674,17 @@ class _ extends x {
1629
1674
  d.className = "tbw-filter-value-item", d.style.padding = "0", d.style.margin = "0";
1630
1675
  const c = document.createElement("input");
1631
1676
  c.type = "checkbox", c.className = "tbw-filter-checkbox";
1632
- const h = document.createElement("span");
1633
- h.textContent = "Select All", d.appendChild(c), d.appendChild(h), a.appendChild(d);
1634
- const u = () => {
1635
- 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);
1636
1681
  c.checked = R, c.indeterminate = !R && !E;
1637
1682
  };
1638
1683
  c.addEventListener("change", () => {
1639
- const b = c.checked;
1640
- for (const R of w.keys())
1641
- w.set(R, b);
1642
- u(), A();
1684
+ const v = c.checked;
1685
+ for (const R of b.keys())
1686
+ b.set(R, v);
1687
+ h(), A();
1643
1688
  }), e.appendChild(a);
1644
1689
  const f = document.createElement("div");
1645
1690
  f.className = "tbw-filter-values";
@@ -1647,44 +1692,44 @@ class _ extends x {
1647
1692
  g.className = "tbw-filter-values-spacer", f.appendChild(g);
1648
1693
  const p = document.createElement("div");
1649
1694
  p.className = "tbw-filter-values-content", f.appendChild(p);
1650
- const w = /* @__PURE__ */ new Map();
1651
- n.forEach((b) => {
1652
- const R = b == null ? "__null__" : String(b);
1653
- w.set(R, !i.has(b));
1654
- }), 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();
1655
1700
  let m = [];
1656
- const v = (b, R) => {
1657
- const E = b == null ? "(Blank)" : String(b), C = b == null ? "__null__" : String(b), y = document.createElement("label");
1658
- 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";
1659
1704
  const S = document.createElement("input");
1660
- S.type = "checkbox", S.className = "tbw-filter-checkbox", S.checked = w.get(C) ?? !0, S.dataset.value = C, S.addEventListener("change", () => {
1661
- 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();
1662
1707
  });
1663
- const de = document.createElement("span");
1664
- 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;
1665
1710
  }, A = () => {
1666
- const b = m.length, R = f.clientHeight, E = f.scrollTop;
1667
- 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)) {
1668
1713
  p.innerHTML = "", p.style.transform = "translateY(0px)", m.forEach((y, S) => {
1669
- p.appendChild(v(y, S));
1714
+ p.appendChild(w(y, S));
1670
1715
  });
1671
1716
  return;
1672
1717
  }
1673
- const C = dt({
1674
- totalRows: b,
1718
+ const C = pt({
1719
+ totalRows: v,
1675
1720
  viewportHeight: R,
1676
1721
  scrollTop: E,
1677
- rowHeight: _.LIST_ITEM_HEIGHT,
1678
- overscan: _.LIST_OVERSCAN
1722
+ rowHeight: L.LIST_ITEM_HEIGHT,
1723
+ overscan: L.LIST_OVERSCAN
1679
1724
  });
1680
1725
  p.style.transform = `translateY(${C.offsetY}px)`, p.innerHTML = "";
1681
1726
  for (let y = C.start; y < C.end; y++)
1682
- p.appendChild(v(m[y], y - C.start));
1683
- }, q = (b) => {
1684
- const R = b.toLowerCase();
1727
+ p.appendChild(w(m[y], y - C.start));
1728
+ }, q = (v) => {
1729
+ const R = v.toLowerCase();
1685
1730
  if (m = n.filter((E) => {
1686
1731
  const C = E == null ? "(Blank)" : String(E);
1687
- return !b || C.toLowerCase().includes(R);
1732
+ return !v || C.toLowerCase().includes(R);
1688
1733
  }), m.length === 0) {
1689
1734
  g.style.height = "0px", p.innerHTML = "";
1690
1735
  const E = document.createElement("div");
@@ -1700,31 +1745,31 @@ class _ extends x {
1700
1745
  },
1701
1746
  { passive: !0 }
1702
1747
  ), q(l.value), e.appendChild(f);
1703
- let ae;
1748
+ let le;
1704
1749
  l.addEventListener("input", () => {
1705
- clearTimeout(ae), ae = setTimeout(() => {
1750
+ clearTimeout(le), le = setTimeout(() => {
1706
1751
  this.searchText.set(o, l.value), q(l.value);
1707
1752
  }, this.config.debounceMs ?? 150);
1708
1753
  });
1709
- const K = document.createElement("div");
1710
- K.className = "tbw-filter-buttons";
1711
- const N = document.createElement("button");
1712
- N.className = "tbw-filter-apply-btn", N.textContent = "Apply", N.addEventListener("click", () => {
1713
- const b = [];
1714
- for (const [R, E] of w)
1754
+ const N = document.createElement("div");
1755
+ N.className = "tbw-filter-buttons";
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)
1715
1760
  if (!E)
1716
1761
  if (R === "__null__")
1717
- b.push(null);
1762
+ v.push(null);
1718
1763
  else {
1719
1764
  const C = n.find((y) => String(y) === R);
1720
- b.push(C !== void 0 ? C : R);
1765
+ v.push(C !== void 0 ? C : R);
1721
1766
  }
1722
- t.applySetFilter(b);
1723
- }), K.appendChild(N);
1724
- const D = document.createElement("button");
1725
- 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", () => {
1726
1771
  t.clearFilter();
1727
- }), K.appendChild(D), e.appendChild(K);
1772
+ }), N.appendChild(O), e.appendChild(N);
1728
1773
  }
1729
1774
  /**
1730
1775
  * Apply a set filter (exclude values)
@@ -1807,11 +1852,8 @@ class _ extends x {
1807
1852
  this.filters.set(e, n), this.cachedResult = null, this.cacheKey = null;
1808
1853
  }
1809
1854
  // #endregion
1810
- // #region Styles
1811
- styles = gt;
1812
- // #endregion
1813
1855
  }
1814
- function mt(s) {
1856
+ function ye(s) {
1815
1857
  if (!s.length) return [];
1816
1858
  const e = /* @__PURE__ */ new Map(), t = [], n = (r, l) => {
1817
1859
  if (!l.length) return;
@@ -1846,7 +1888,7 @@ function mt(s) {
1846
1888
  }, e.set(d, c), t.push(c)), c.columns.push(r);
1847
1889
  }), i.length && n(o, i), t.length === 1 && t[0].implicit && t[0].columns.length === s.length ? [] : t;
1848
1890
  }
1849
- function wt(s, e, t) {
1891
+ function Ct(s, e, t) {
1850
1892
  if (!e.length || !s) return;
1851
1893
  const n = /* @__PURE__ */ new Map();
1852
1894
  for (const o of e)
@@ -1862,23 +1904,25 @@ function wt(s, e, t) {
1862
1904
  l && l.classList.add("group-end");
1863
1905
  }
1864
1906
  }
1865
- function bt(s, e) {
1907
+ function Rt(s, e) {
1866
1908
  if (s.length === 0) return null;
1867
1909
  const t = document.createElement("div");
1868
1910
  t.className = "header-group-row", t.setAttribute("role", "row");
1869
1911
  for (const n of s) {
1870
- 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");
1871
- 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);
1872
1916
  }
1873
1917
  return t;
1874
1918
  }
1875
- function vt(s) {
1919
+ function Et(s) {
1876
1920
  return s.some((e) => e.group != null);
1877
1921
  }
1878
- 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)}";
1879
- class Kn 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 {
1880
1924
  name = "groupingColumns";
1881
- version = "1.0.0";
1925
+ styles = St;
1882
1926
  get defaultConfig() {
1883
1927
  return {
1884
1928
  showGroupBorders: !0
@@ -1902,7 +1946,7 @@ class Kn extends x {
1902
1946
  if (t?.columnGroups && Array.isArray(t.columnGroups) && t.columnGroups.length > 0)
1903
1947
  return !0;
1904
1948
  const n = t?.columns;
1905
- return Array.isArray(n) ? vt(n) : !1;
1949
+ return Array.isArray(n) ? Et(n) : !1;
1906
1950
  }
1907
1951
  // #endregion
1908
1952
  // #region Hooks
@@ -1920,27 +1964,29 @@ class Kn extends x {
1920
1964
  });
1921
1965
  } else
1922
1966
  n = [...e];
1923
- const i = mt(n);
1967
+ const i = ye(n);
1924
1968
  return i.length === 0 ? (this.isActive = !1, this.groups = [], n) : (this.isActive = !0, this.groups = i, n);
1925
1969
  }
1926
1970
  afterRender() {
1927
- if (!this.isActive || this.groups.length === 0) {
1928
- const r = this.shadowRoot?.querySelector(".header")?.querySelector(".header-group-row");
1929
- r && r.remove();
1971
+ if (!this.isActive) {
1972
+ const a = this.shadowRoot?.querySelector(".header")?.querySelector(".header-group-row");
1973
+ a && a.remove();
1930
1974
  return;
1931
1975
  }
1932
1976
  const e = this.shadowRoot?.querySelector(".header");
1933
1977
  if (!e) return;
1934
1978
  const t = e.querySelector(".header-group-row");
1935
1979
  t && t.remove();
1936
- const n = bt(this.groups, this.columns);
1937
- if (n) {
1938
- n.classList.toggle("no-borders", !this.config.showGroupBorders);
1939
- const o = e.querySelector(".header-row");
1940
- 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);
1941
1987
  }
1942
- const i = e.querySelector(".header-row");
1943
- 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));
1944
1990
  }
1945
1991
  // #endregion
1946
1992
  // #region Public API
@@ -1974,11 +2020,8 @@ class Kn extends x {
1974
2020
  this.requestRender();
1975
2021
  }
1976
2022
  // #endregion
1977
- // #region Styles
1978
- styles = yt;
1979
- // #endregion
1980
2023
  }
1981
- function xt({ rows: s, config: e, expanded: t }) {
2024
+ function kt({ rows: s, config: e, expanded: t }) {
1982
2025
  const n = e.groupOn;
1983
2026
  if (typeof n != "function")
1984
2027
  return [];
@@ -1987,10 +2030,10 @@ function xt({ rows: s, config: e, expanded: t }) {
1987
2030
  let a = n(l);
1988
2031
  a == null || a === !1 ? a = ["__ungrouped__"] : Array.isArray(a) || (a = [a]);
1989
2032
  let d = i;
1990
- a.forEach((c, h) => {
1991
- const u = c == null ? "∅" : String(c), f = d.key === "__root__" ? u : d.key + "||" + u;
1992
- let g = d.children.get(u);
1993
- 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;
1994
2037
  }), d.rows.push(l);
1995
2038
  }), i.children.size === 1 && i.children.has("__ungrouped__") && i.children.get("__ungrouped__").rows.length === s.length)
1996
2039
  return [];
@@ -2011,26 +2054,26 @@ function xt({ rows: s, config: e, expanded: t }) {
2011
2054
  };
2012
2055
  return r(i), o;
2013
2056
  }
2014
- function Ct(s, e) {
2057
+ function At(s, e) {
2015
2058
  const t = new Set(s);
2016
2059
  return t.has(e) ? t.delete(e) : t.add(e), t;
2017
2060
  }
2018
- function Rt(s) {
2061
+ function _t(s) {
2019
2062
  const e = /* @__PURE__ */ new Set();
2020
2063
  for (const t of s)
2021
2064
  t.kind === "group" && e.add(t.key);
2022
2065
  return e;
2023
2066
  }
2024
- function Et() {
2067
+ function Lt() {
2025
2068
  return /* @__PURE__ */ new Set();
2026
2069
  }
2027
- function St(s) {
2070
+ function Tt(s) {
2028
2071
  return s.kind !== "group" ? 0 : s.rows.length;
2029
2072
  }
2030
- 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}}';
2031
- class Nn 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 {
2032
2075
  name = "groupingRows";
2033
- version = "1.0.0";
2076
+ styles = It;
2034
2077
  get defaultConfig() {
2035
2078
  return {
2036
2079
  defaultExpanded: !1,
@@ -2048,15 +2091,12 @@ class Nn extends x {
2048
2091
  keysToAnimate = /* @__PURE__ */ new Set();
2049
2092
  // #endregion
2050
2093
  // #region Animation
2094
+ /**
2095
+ * Get expand/collapse animation style from plugin config.
2096
+ * Uses base class isAnimationEnabled to respect grid-level settings.
2097
+ */
2051
2098
  get animationStyle() {
2052
- const t = this.grid.effectiveConfig?.animation?.mode ?? "reduced-motion";
2053
- if (t === !1 || t === "off") return !1;
2054
- if (t !== !0 && t !== "on") {
2055
- const n = this.shadowRoot?.host;
2056
- if (n && getComputedStyle(n).getPropertyValue("--tbw-animation-enabled").trim() === "0")
2057
- return !1;
2058
- }
2059
- return this.config.animation ?? "slide";
2099
+ return this.isAnimationEnabled ? this.config.animation ?? "slide" : !1;
2060
2100
  }
2061
2101
  // #endregion
2062
2102
  // #region Lifecycle
@@ -2076,7 +2116,7 @@ class Nn extends x {
2076
2116
  const t = this.config;
2077
2117
  if (typeof t.groupOn != "function")
2078
2118
  return this.isActive = !1, this.flattenedRows = [], [...e];
2079
- const n = xt({
2119
+ const n = kt({
2080
2120
  rows: [...e],
2081
2121
  config: t,
2082
2122
  expanded: this.expandedKeys
@@ -2097,7 +2137,7 @@ class Nn extends x {
2097
2137
  __groupDepth: o.depth,
2098
2138
  __groupRows: o.rows,
2099
2139
  __groupExpanded: o.expanded,
2100
- __groupRowCount: St(o)
2140
+ __groupRowCount: Tt(o)
2101
2141
  } : o.row);
2102
2142
  }
2103
2143
  onCellClick(e) {
@@ -2105,6 +2145,12 @@ class Nn extends x {
2105
2145
  if (t?.__isGroupRow && e.originalEvent.target?.closest(".group-toggle"))
2106
2146
  return this.toggle(t.__groupKey), !0;
2107
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
+ }
2108
2154
  /**
2109
2155
  * Render a row. Returns true if we handled the row (group row), false otherwise.
2110
2156
  */
@@ -2124,12 +2170,12 @@ class Nn extends x {
2124
2170
  toggleExpand: l
2125
2171
  });
2126
2172
  if (a)
2127
- 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;
2128
2174
  }
2129
2175
  const o = () => {
2130
2176
  this.toggle(e.__groupKey);
2131
2177
  };
2132
- 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;
2133
2179
  }
2134
2180
  afterRender() {
2135
2181
  const e = this.animationStyle;
@@ -2145,52 +2191,63 @@ class Nn extends x {
2145
2191
  }
2146
2192
  // #endregion
2147
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
+ }
2148
2210
  renderFullWidthGroupRow(e, t, n) {
2149
2211
  const i = this.config, o = document.createElement("div");
2150
- o.className = "cell group-full", o.style.gridColumn = "1 / -1", o.setAttribute("role", "gridcell");
2151
- const r = document.createElement("button");
2152
- 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) => {
2153
- d.stopPropagation(), n();
2154
- }), o.appendChild(r);
2155
- const l = document.createElement("span");
2156
- l.className = "group-label";
2157
- const a = i.formatLabel ? i.formatLabel(e.__groupValue, e.__groupDepth || 0, e.__groupKey) : String(e.__groupValue);
2158
- if (l.textContent = a, o.appendChild(l), i.showRowCount !== !1) {
2159
- const d = document.createElement("span");
2160
- 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);
2161
2217
  }
2162
2218
  t.appendChild(o);
2163
2219
  }
2164
2220
  renderPerColumnGroupRow(e, t, n) {
2165
2221
  const i = this.config, o = i.aggregators ?? {}, r = this.columns, l = e.__groupRows ?? [], d = this.shadowRoot?.querySelector(".body")?.style.gridTemplateColumns || "";
2166
- d && (t.style.display = "grid", t.style.gridTemplateColumns = d), r.forEach((c, h) => {
2167
- const u = document.createElement("div");
2168
- if (u.className = "cell group-cell", u.setAttribute("data-col", String(h)), u.setAttribute("role", "gridcell"), h === 0) {
2169
- const f = document.createElement("button");
2170
- 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) => {
2171
- w.stopPropagation(), n();
2172
- }), u.appendChild(f);
2173
- const g = document.createElement("span"), p = o[c.field];
2174
- if (p) {
2175
- const w = ce(p, l, c.field, c);
2176
- g.textContent = w != null ? String(w) : String(e.__groupValue);
2177
- } else {
2178
- const w = i.formatLabel ? i.formatLabel(e.__groupValue, e.__groupDepth || 0, e.__groupKey) : String(e.__groupValue);
2179
- g.textContent = w;
2180
- }
2181
- if (u.appendChild(g), i.showRowCount !== !1) {
2182
- const w = document.createElement("span");
2183
- w.className = "group-count", w.textContent = ` (${l.length})`, u.appendChild(w);
2184
- }
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 = "";
2185
2237
  } else {
2186
- const f = o[c.field];
2187
- if (f) {
2188
- const g = ce(f, l, c.field, c);
2189
- 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);
2190
2243
  } else
2191
- 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
+ }
2192
2249
  }
2193
- t.appendChild(u);
2250
+ t.appendChild(f);
2194
2251
  });
2195
2252
  }
2196
2253
  // #endregion
@@ -2199,20 +2256,20 @@ class Nn extends x {
2199
2256
  * Expand all groups.
2200
2257
  */
2201
2258
  expandAll() {
2202
- this.expandedKeys = Rt(this.flattenedRows), this.requestRender();
2259
+ this.expandedKeys = _t(this.flattenedRows), this.requestRender();
2203
2260
  }
2204
2261
  /**
2205
2262
  * Collapse all groups.
2206
2263
  */
2207
2264
  collapseAll() {
2208
- this.expandedKeys = Et(), this.requestRender();
2265
+ this.expandedKeys = Lt(), this.requestRender();
2209
2266
  }
2210
2267
  /**
2211
2268
  * Toggle expansion of a specific group.
2212
2269
  * @param key - The group key to toggle
2213
2270
  */
2214
2271
  toggle(e) {
2215
- this.expandedKeys = Ct(this.expandedKeys, e);
2272
+ this.expandedKeys = At(this.expandedKeys, e);
2216
2273
  const t = this.flattenedRows.find((n) => n.kind === "group" && n.key === e);
2217
2274
  this.emit("group-toggle", {
2218
2275
  key: e,
@@ -2302,26 +2359,23 @@ class Nn extends x {
2302
2359
  this.config.groupOn = e, this.requestRender();
2303
2360
  }
2304
2361
  // #endregion
2305
- // #region Styles
2306
- styles = kt;
2307
- // #endregion
2308
2362
  }
2309
- function Z(s, e) {
2363
+ function xe(s, e) {
2310
2364
  const t = new Set(s);
2311
2365
  return t.has(e) ? t.delete(e) : t.add(e), t;
2312
2366
  }
2313
- function At(s, e) {
2367
+ function Ft(s, e) {
2314
2368
  const t = new Set(s);
2315
2369
  return t.add(e), t;
2316
2370
  }
2317
- function _t(s, e) {
2371
+ function Mt(s, e) {
2318
2372
  const t = new Set(s);
2319
2373
  return t.delete(e), t;
2320
2374
  }
2321
- function Lt(s, e) {
2375
+ function Pt(s, e) {
2322
2376
  return s.has(e);
2323
2377
  }
2324
- function Tt(s, e, t, n) {
2378
+ function Dt(s, e, t, n) {
2325
2379
  const i = document.createElement("div");
2326
2380
  i.className = "master-detail-row", i.setAttribute("data-detail-for", String(e)), i.setAttribute("role", "row");
2327
2381
  const o = document.createElement("div");
@@ -2329,10 +2383,10 @@ function Tt(s, e, t, n) {
2329
2383
  const r = t(s, e);
2330
2384
  return typeof r == "string" ? o.innerHTML = r : r instanceof HTMLElement && o.appendChild(r), i.appendChild(o), i;
2331
2385
  }
2332
- 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}}";
2333
- 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 {
2334
2388
  name = "masterDetail";
2335
- version = "1.0.0";
2389
+ styles = Kt;
2336
2390
  get defaultConfig() {
2337
2391
  return {
2338
2392
  detailHeight: "auto",
@@ -2380,50 +2434,29 @@ class Dn extends x {
2380
2434
  if (!t) return;
2381
2435
  const n = e;
2382
2436
  if (n.__frameworkAdapter?.parseDetailElement) {
2383
- const h = n.__frameworkAdapter.parseDetailElement(t);
2384
- if (h) {
2385
- this.config = { ...this.config, detailRenderer: h };
2437
+ const u = n.__frameworkAdapter.parseDetailElement(t);
2438
+ if (u) {
2439
+ this.config = { ...this.config, detailRenderer: u };
2386
2440
  return;
2387
2441
  }
2388
2442
  }
2389
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 = {};
2390
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));
2391
2445
  const c = t.innerHTML.trim();
2392
- c && !this.config.detailRenderer && (d.detailRenderer = (h, u) => {
2393
- const f = $e(c, { value: h, row: h });
2394
- 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);
2395
2449
  }), Object.keys(d).length > 0 && (this.config = { ...this.config, ...d });
2396
2450
  }
2397
2451
  // #endregion
2398
2452
  // #region Animation Helpers
2399
- /**
2400
- * Check if animations are enabled at the grid level.
2401
- * Respects gridConfig.animation.mode and CSS variable.
2402
- */
2403
- get isAnimationEnabled() {
2404
- const t = this.grid.effectiveConfig?.animation?.mode ?? "reduced-motion";
2405
- if (t === !1 || t === "off") return !1;
2406
- if (t === !0 || t === "on") return !0;
2407
- const n = this.shadowRoot?.host;
2408
- return n ? getComputedStyle(n).getPropertyValue("--tbw-animation-enabled").trim() !== "0" : !0;
2409
- }
2410
2453
  /**
2411
2454
  * Get expand/collapse animation style from plugin config.
2455
+ * Uses base class isAnimationEnabled to respect grid-level settings.
2412
2456
  */
2413
2457
  get animationStyle() {
2414
2458
  return this.isAnimationEnabled ? this.config.animation ?? "slide" : !1;
2415
2459
  }
2416
- /**
2417
- * Get animation duration from CSS variable (set by grid).
2418
- */
2419
- get animationDuration() {
2420
- const e = this.shadowRoot?.host;
2421
- if (e) {
2422
- const t = getComputedStyle(e).getPropertyValue("--tbw-animation-duration").trim(), n = parseInt(t, 10);
2423
- if (!isNaN(n)) return n;
2424
- }
2425
- return 200;
2426
- }
2427
2460
  /**
2428
2461
  * Apply expand animation to a detail element.
2429
2462
  */
@@ -2454,6 +2487,25 @@ class Dn extends x {
2454
2487
  // #region Internal State
2455
2488
  expandedRows = /* @__PURE__ */ new Set();
2456
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
+ }
2457
2509
  // #endregion
2458
2510
  // #region Lifecycle
2459
2511
  detach() {
@@ -2462,49 +2514,36 @@ class Dn extends x {
2462
2514
  // #endregion
2463
2515
  // #region Hooks
2464
2516
  processColumns(e) {
2465
- if (!this.config.detailRenderer)
2517
+ if (!this.config.detailRenderer || this.config.showExpandColumn === !1)
2466
2518
  return [...e];
2467
2519
  const t = [...e];
2468
- if (t.length > 0) {
2469
- const n = { ...t[0] }, i = n.viewRenderer;
2470
- if (i?.__masterDetailWrapped)
2471
- return t;
2472
- const o = (r) => {
2473
- const { value: l, row: a } = r, d = this.expandedRows.has(a), c = document.createElement("span");
2474
- c.className = "master-detail-cell-wrapper";
2475
- const h = document.createElement("span");
2476
- 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);
2477
- const u = document.createElement("span");
2478
- if (i) {
2479
- const f = i(r);
2480
- f instanceof Node ? u.appendChild(f) : u.textContent = String(f ?? l ?? "");
2481
- } else
2482
- u.textContent = String(l ?? "");
2483
- return c.appendChild(u), c;
2484
- };
2485
- o.__masterDetailWrapped = !0, n.viewRenderer = o, t[0] = n;
2486
- }
2487
- 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];
2488
2529
  }
2489
2530
  onRowClick(e) {
2490
2531
  if (!(!this.config.expandOnRowClick || !this.config.detailRenderer))
2491
- return this.expandedRows = Z(this.expandedRows, e.row), this.emit("detail-expand", {
2492
- rowIndex: e.rowIndex,
2493
- row: e.row,
2494
- expanded: this.expandedRows.has(e.row)
2495
- }), this.requestRender(), !1;
2532
+ return this.toggleAndEmit(e.row, e.rowIndex), !1;
2496
2533
  }
2497
2534
  onCellClick(e) {
2498
- if (e.originalEvent?.target?.classList.contains("master-detail-toggle")) {
2499
- const n = e.row, i = e.rowIndex;
2500
- return this.expandedRows = Z(this.expandedRows, n), this.emit("detail-expand", {
2501
- rowIndex: i,
2502
- row: n,
2503
- expanded: this.expandedRows.has(n)
2504
- }), this.requestRender(), !0;
2505
- }
2535
+ if (e.originalEvent?.target?.classList.contains("master-detail-toggle"))
2536
+ return this.toggleAndEmit(e.row, e.rowIndex), !0;
2506
2537
  this.expandedRows.size > 0 && queueMicrotask(() => this.#e());
2507
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
+ }
2508
2547
  afterRender() {
2509
2548
  this.#e();
2510
2549
  }
@@ -2541,7 +2580,7 @@ class Dn extends x {
2541
2580
  d.previousElementSibling !== l && l.after(d);
2542
2581
  continue;
2543
2582
  }
2544
- const c = Tt(a, r, this.config.detailRenderer, i);
2583
+ const c = Dt(a, r, this.config.detailRenderer, i);
2545
2584
  typeof this.config.detailHeight == "number" && (c.style.height = `${this.config.detailHeight}px`), l.after(c), this.detailElements.set(a, c), this.animateExpand(c);
2546
2585
  }
2547
2586
  }
@@ -2551,15 +2590,8 @@ class Dn extends x {
2551
2590
  */
2552
2591
  getExtraHeight() {
2553
2592
  let e = 0;
2554
- for (const t of this.expandedRows) {
2555
- const n = this.detailElements.get(t);
2556
- if (n)
2557
- e += n.offsetHeight;
2558
- else {
2559
- const i = this.config?.detailHeight;
2560
- e += typeof i == "number" ? i : 150;
2561
- }
2562
- }
2593
+ for (const t of this.expandedRows)
2594
+ e += this.getDetailHeight(t);
2563
2595
  return e;
2564
2596
  }
2565
2597
  /**
@@ -2570,15 +2602,7 @@ class Dn extends x {
2570
2602
  let t = 0;
2571
2603
  for (const n of this.expandedRows) {
2572
2604
  const i = this.rows.indexOf(n);
2573
- if (i >= 0 && i < e) {
2574
- const o = this.detailElements.get(n);
2575
- if (o)
2576
- t += o.offsetHeight;
2577
- else {
2578
- const r = this.config?.detailHeight;
2579
- t += typeof r == "number" ? r : 150;
2580
- }
2581
- }
2605
+ i >= 0 && i < e && (t += this.getDetailHeight(n));
2582
2606
  }
2583
2607
  return t;
2584
2608
  }
@@ -2596,8 +2620,8 @@ class Dn extends x {
2596
2620
  i.sort((l, a) => l.index - a.index);
2597
2621
  let o = e, r = 0;
2598
2622
  for (const { index: l, row: a } of i) {
2599
- const d = l * n + r, h = this.detailElements.get(a)?.offsetHeight ?? (typeof this.config?.detailHeight == "number" ? this.config.detailHeight : 150), u = d + n + h;
2600
- 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);
2601
2625
  }
2602
2626
  return o;
2603
2627
  }
@@ -2609,7 +2633,7 @@ class Dn extends x {
2609
2633
  */
2610
2634
  expand(e) {
2611
2635
  const t = this.rows[e];
2612
- t && (this.expandedRows = At(this.expandedRows, t), this.requestRender());
2636
+ t && (this.expandedRows = Ft(this.expandedRows, t), this.requestRender());
2613
2637
  }
2614
2638
  /**
2615
2639
  * Collapse the detail row at the given index.
@@ -2617,7 +2641,7 @@ class Dn extends x {
2617
2641
  */
2618
2642
  collapse(e) {
2619
2643
  const t = this.rows[e];
2620
- t && (this.expandedRows = _t(this.expandedRows, t), this.requestRender());
2644
+ t && (this.expandedRows = Mt(this.expandedRows, t), this.requestRender());
2621
2645
  }
2622
2646
  /**
2623
2647
  * Toggle the detail row at the given index.
@@ -2625,7 +2649,7 @@ class Dn extends x {
2625
2649
  */
2626
2650
  toggle(e) {
2627
2651
  const t = this.rows[e];
2628
- t && (this.expandedRows = Z(this.expandedRows, t), this.requestRender());
2652
+ t && (this.expandedRows = xe(this.expandedRows, t), this.requestRender());
2629
2653
  }
2630
2654
  /**
2631
2655
  * Check if the detail row at the given index is expanded.
@@ -2634,7 +2658,7 @@ class Dn extends x {
2634
2658
  */
2635
2659
  isExpanded(e) {
2636
2660
  const t = this.rows[e];
2637
- return t ? Lt(this.expandedRows, t) : !1;
2661
+ return t ? Pt(this.expandedRows, t) : !1;
2638
2662
  }
2639
2663
  /**
2640
2664
  * Expand all detail rows.
@@ -2686,24 +2710,21 @@ class Dn extends x {
2686
2710
  }
2687
2711
  }
2688
2712
  // #endregion
2689
- // #region Styles
2690
- styles = It;
2691
- // #endregion
2692
2713
  }
2693
- function Ft(s, e, t) {
2714
+ function qt(s, e, t) {
2694
2715
  return e.length ? [...s].sort((n, i) => {
2695
2716
  for (const o of e) {
2696
- 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);
2697
2718
  if (c !== 0)
2698
2719
  return o.direction === "asc" ? c : -c;
2699
2720
  }
2700
2721
  return 0;
2701
2722
  }) : [...s];
2702
2723
  }
2703
- function Mt(s, e) {
2724
+ function Nt(s, e) {
2704
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));
2705
2726
  }
2706
- function Pt(s, e, t, n) {
2727
+ function Ht(s, e, t, n) {
2707
2728
  const i = s.find((o) => o.field === e);
2708
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" }];
2709
2730
  }
@@ -2714,10 +2735,10 @@ function Ce(s, e) {
2714
2735
  function Re(s, e) {
2715
2736
  return s.find((t) => t.field === e)?.direction;
2716
2737
  }
2717
- 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}';
2718
- 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 {
2719
2740
  name = "multiSort";
2720
- version = "1.0.0";
2741
+ styles = Ot;
2721
2742
  get defaultConfig() {
2722
2743
  return {
2723
2744
  maxSortColumns: 3,
@@ -2734,12 +2755,12 @@ class Hn extends x {
2734
2755
  // #endregion
2735
2756
  // #region Hooks
2736
2757
  processRows(e) {
2737
- 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]);
2738
2759
  }
2739
2760
  onHeaderClick(e) {
2740
2761
  if (!this.columns.find((o) => o.field === e.field)?.sortable) return !1;
2741
2762
  const n = e.originalEvent.shiftKey, i = this.config.maxSortColumns ?? 3;
2742
- 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;
2743
2764
  }
2744
2765
  afterRender() {
2745
2766
  const e = this.shadowRoot;
@@ -2753,7 +2774,7 @@ class Hn extends x {
2753
2774
  i.querySelector('[part~="sort-indicator"], .sort-indicator')?.remove(), i.setAttribute("data-sort", l);
2754
2775
  const c = document.createElement("span");
2755
2776
  c.className = "sort-indicator", this.setIcon(c, this.resolveIcon(l === "asc" ? "sortAsc" : "sortDesc"));
2756
- 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;
2757
2778
  if (f ? i.insertBefore(c, f) : i.appendChild(c), t && this.sortModel.length > 1 && r !== void 0) {
2758
2779
  const g = document.createElement("span");
2759
2780
  g.className = "sort-index", g.textContent = String(r), c.nextSibling ? i.insertBefore(g, c.nextSibling) : i.appendChild(g);
@@ -2830,14 +2851,11 @@ class Hn extends x {
2830
2851
  n !== -1 ? this.sortModel[n] = i : this.sortModel.splice(t.sort.priority, 0, i);
2831
2852
  }
2832
2853
  // #endregion
2833
- // #region Styles
2834
- styles = qt;
2835
- // #endregion
2836
2854
  }
2837
- function Kt(s) {
2855
+ function Gt(s) {
2838
2856
  return s.filter((e) => e.sticky === "left");
2839
2857
  }
2840
- function Nt(s) {
2858
+ function Bt(s) {
2841
2859
  return s.filter((e) => e.sticky === "right");
2842
2860
  }
2843
2861
  function X(s) {
@@ -2876,9 +2894,8 @@ function Se(s) {
2876
2894
  n.classList.remove("sticky-left", "sticky-right"), n.style.position = "", n.style.left = "", n.style.right = "";
2877
2895
  });
2878
2896
  }
2879
- class On extends x {
2897
+ class $n extends x {
2880
2898
  name = "pinnedColumns";
2881
- version = "1.0.0";
2882
2899
  get defaultConfig() {
2883
2900
  return {};
2884
2901
  }
@@ -2922,7 +2939,7 @@ class On extends x {
2922
2939
  */
2923
2940
  onPluginQuery(e) {
2924
2941
  switch (e.type) {
2925
- case H.CAN_MOVE_COLUMN: {
2942
+ case He.CAN_MOVE_COLUMN: {
2926
2943
  const t = e.context, n = t.sticky;
2927
2944
  if (n === "left" || n === "right")
2928
2945
  return !1;
@@ -2947,14 +2964,14 @@ class On extends x {
2947
2964
  */
2948
2965
  getLeftPinnedColumns() {
2949
2966
  const e = [...this.columns];
2950
- return Kt(e);
2967
+ return Gt(e);
2951
2968
  }
2952
2969
  /**
2953
2970
  * Get columns pinned to the right.
2954
2971
  */
2955
2972
  getRightPinnedColumns() {
2956
2973
  const e = [...this.columns];
2957
- return Nt(e);
2974
+ return Bt(e);
2958
2975
  }
2959
2976
  /**
2960
2977
  * Clear all sticky positioning.
@@ -2988,10 +3005,10 @@ class On extends x {
2988
3005
  }
2989
3006
  // #endregion
2990
3007
  }
2991
- function Dt(s) {
3008
+ function Vt(s) {
2992
3009
  return typeof s == "object" && s !== null && "aggFunc" in s;
2993
3010
  }
2994
- function Y(s, e) {
3011
+ function Z(s, e) {
2995
3012
  const t = document.createElement("div");
2996
3013
  t.className = "tbw-pinned-rows", t.setAttribute("role", "presentation"), t.setAttribute("aria-live", "polite");
2997
3014
  const n = document.createElement("div");
@@ -3013,7 +3030,7 @@ function Y(s, e) {
3013
3030
  }
3014
3031
  if (s.customPanels)
3015
3032
  for (const r of s.customPanels) {
3016
- const l = Ht(r, e);
3033
+ const l = zt(r, e);
3017
3034
  switch (r.position) {
3018
3035
  case "left":
3019
3036
  n.appendChild(l);
@@ -3046,23 +3063,23 @@ function Ae(s, e, t, n) {
3046
3063
  let a, d;
3047
3064
  const c = i.aggregators?.[r.field];
3048
3065
  if (c)
3049
- if (Dt(c)) {
3050
- const h = ue(c.aggFunc);
3051
- 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;
3052
3069
  } else {
3053
- const h = ue(c);
3054
- h && (a = h(n, r.field, r));
3070
+ const u = ce(c);
3071
+ u && (a = u(n, r.field, r));
3055
3072
  }
3056
3073
  else if (i.cells && Object.prototype.hasOwnProperty.call(i.cells, r.field)) {
3057
- const h = i.cells[r.field];
3058
- 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;
3059
3076
  }
3060
3077
  a != null ? l.textContent = d ? d(a, r.field, r) : String(a) : l.textContent = "", o.appendChild(l);
3061
3078
  }
3062
3079
  s.appendChild(o);
3063
3080
  }
3064
3081
  }
3065
- function Ht(s, e) {
3082
+ function zt(s, e) {
3066
3083
  const t = document.createElement("div");
3067
3084
  t.className = "tbw-status-panel tbw-status-panel-custom", t.id = `status-panel-${s.id}`;
3068
3085
  const n = s.render(e);
@@ -3078,10 +3095,10 @@ function _e(s, e, t, n, i) {
3078
3095
  grid: t
3079
3096
  };
3080
3097
  }
3081
- 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}";
3082
- 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 {
3083
3100
  name = "pinnedRows";
3084
- version = "1.0.0";
3101
+ styles = Wt;
3085
3102
  get defaultConfig() {
3086
3103
  return {
3087
3104
  position: "bottom",
@@ -3114,12 +3131,12 @@ class Gn extends x {
3114
3131
  this.grid,
3115
3132
  n,
3116
3133
  i
3117
- ), 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");
3118
3135
  if (l.length > 0) {
3119
3136
  if (!this.topAggregationContainer) {
3120
3137
  this.topAggregationContainer = ke("top");
3121
- const u = e.querySelector(".header");
3122
- 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);
3123
3140
  }
3124
3141
  Ae(
3125
3142
  this.topAggregationContainer,
@@ -3128,21 +3145,21 @@ class Gn extends x {
3128
3145
  this.rows
3129
3146
  );
3130
3147
  } else this.topAggregationContainer && (this.topAggregationContainer.remove(), this.topAggregationContainer = null);
3131
- 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;
3132
3149
  if (d && this.config.position === "top")
3133
3150
  if (!this.infoBarElement)
3134
- 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);
3135
3152
  else {
3136
- const u = Y(this.config, o);
3137
- this.infoBarElement.replaceWith(u), this.infoBarElement = u;
3153
+ const h = Z(this.config, o);
3154
+ this.infoBarElement.replaceWith(h), this.infoBarElement = h;
3138
3155
  }
3139
3156
  else this.config.position === "top" && this.infoBarElement && (this.infoBarElement.remove(), this.infoBarElement = null);
3140
- 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(
3141
3158
  this.bottomAggregationContainer,
3142
3159
  a,
3143
3160
  this.visibleColumns,
3144
3161
  this.rows
3145
- )), 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();
3146
3163
  }
3147
3164
  // #endregion
3148
3165
  // #region Private Methods
@@ -3217,20 +3234,17 @@ class Gn extends x {
3217
3234
  this.config.aggregationRows && (this.config.aggregationRows = this.config.aggregationRows.filter((t) => t.id !== e), this.requestRender());
3218
3235
  }
3219
3236
  // #endregion
3220
- // #region Styles
3221
- styles = Ot;
3222
- // #endregion
3223
3237
  }
3224
- const Gt = je;
3225
- function Vt(s) {
3238
+ const $t = Xe;
3239
+ function jt(s) {
3226
3240
  const e = [];
3227
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;
3228
3242
  }
3229
- function le(s, e) {
3243
+ function se(s, e) {
3230
3244
  return [...s, e].join("|");
3231
3245
  }
3232
- function Bt(s, e) {
3233
- 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(
3234
3248
  s,
3235
3249
  t,
3236
3250
  n,
@@ -3240,7 +3254,7 @@ function Bt(s, e) {
3240
3254
  // starting depth
3241
3255
  ""
3242
3256
  // parent key prefix
3243
- ), 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);
3244
3258
  return {
3245
3259
  rows: r,
3246
3260
  columnKeys: o,
@@ -3248,7 +3262,7 @@ function Bt(s, e) {
3248
3262
  grandTotal: a
3249
3263
  };
3250
3264
  }
3251
- function zt(s, e) {
3265
+ function Xt(s, e) {
3252
3266
  if (e.length === 0) return ["value"];
3253
3267
  const t = /* @__PURE__ */ new Set();
3254
3268
  for (const n of s) {
@@ -3257,7 +3271,7 @@ function zt(s, e) {
3257
3271
  }
3258
3272
  return [...t].sort();
3259
3273
  }
3260
- function $t(s, e) {
3274
+ function Zt(s, e) {
3261
3275
  const t = /* @__PURE__ */ new Map();
3262
3276
  for (const n of s) {
3263
3277
  const i = String(n[e] ?? ""), o = t.get(i);
@@ -3265,25 +3279,25 @@ function $t(s, e) {
3265
3279
  }
3266
3280
  return t;
3267
3281
  }
3268
- function Ge(s, e, t, n, i, o, r) {
3282
+ function Be(s, e, t, n, i, o, r) {
3269
3283
  const l = [];
3270
3284
  if (e.length === 0) {
3271
- const u = Le(s, t, n, i), f = Te(u);
3285
+ const h = Le(s, t, n, i), f = Te(h);
3272
3286
  return l.push({
3273
3287
  rowKey: r || "all",
3274
3288
  rowLabel: r || "All",
3275
3289
  depth: o,
3276
- values: u,
3290
+ values: h,
3277
3291
  total: f,
3278
3292
  isGroup: !1,
3279
3293
  rowCount: s.length
3280
3294
  }), l;
3281
3295
  }
3282
- const a = e[0], d = e.slice(1), c = d.length > 0, h = $t(s, a);
3283
- for (const [u, f] of h) {
3284
- 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);
3285
3299
  let m;
3286
- c && (m = Ge(
3300
+ c && (m = Be(
3287
3301
  f,
3288
3302
  d,
3289
3303
  t,
@@ -3293,10 +3307,10 @@ function Ge(s, e, t, n, i, o, r) {
3293
3307
  g
3294
3308
  )), l.push({
3295
3309
  rowKey: g,
3296
- rowLabel: u || "(blank)",
3310
+ rowLabel: h || "(blank)",
3297
3311
  depth: o,
3298
3312
  values: p,
3299
- total: w,
3313
+ total: b,
3300
3314
  isGroup: c,
3301
3315
  children: m,
3302
3316
  rowCount: f.length
@@ -3308,8 +3322,8 @@ function Le(s, e, t, n) {
3308
3322
  const i = {};
3309
3323
  for (const o of t)
3310
3324
  for (const r of n) {
3311
- 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);
3312
- 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;
3313
3327
  }
3314
3328
  return i;
3315
3329
  }
@@ -3319,21 +3333,21 @@ function Te(s) {
3319
3333
  e += t ?? 0;
3320
3334
  return e;
3321
3335
  }
3322
- function Wt(s, e, t) {
3336
+ function Yt(s, e, t) {
3323
3337
  const n = {};
3324
3338
  function i(o) {
3325
3339
  for (const r of o)
3326
3340
  if (!r.isGroup || !r.children?.length)
3327
3341
  for (const l of e)
3328
3342
  for (const a of t) {
3329
- const d = le([l], a.field);
3343
+ const d = se([l], a.field);
3330
3344
  n[d] = (n[d] ?? 0) + (r.values[d] ?? 0);
3331
3345
  }
3332
3346
  else r.children && i(r.children);
3333
3347
  }
3334
3348
  return i(s), n;
3335
3349
  }
3336
- function jt(s, e, t = !0) {
3350
+ function Jt(s, e, t = !0) {
3337
3351
  const n = [];
3338
3352
  function i(o) {
3339
3353
  n.push(o);
@@ -3346,7 +3360,7 @@ function jt(s, e, t = !0) {
3346
3360
  i(o);
3347
3361
  return n;
3348
3362
  }
3349
- function J(s) {
3363
+ function Qt(s) {
3350
3364
  const e = [];
3351
3365
  function t(n) {
3352
3366
  if (n.isGroup && e.push(n.rowKey), n.children)
@@ -3357,14 +3371,14 @@ function J(s) {
3357
3371
  t(n);
3358
3372
  return e;
3359
3373
  }
3360
- const Ut = ["sum", "avg", "count", "min", "max", "first", "last"];
3361
- function Zt(s, e, t, n) {
3374
+ const en = ["sum", "avg", "count", "min", "max", "first", "last"];
3375
+ function tn(s, e, t, n) {
3362
3376
  const i = new AbortController(), o = { config: e, callbacks: n, signal: i.signal }, r = document.createElement("div");
3363
- 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), () => {
3364
3378
  i.abort(), r.remove();
3365
3379
  };
3366
3380
  }
3367
- function F(s, e) {
3381
+ function D(s, e) {
3368
3382
  const t = document.createElement("div");
3369
3383
  t.className = "tbw-pivot-section";
3370
3384
  const n = document.createElement("div");
@@ -3381,7 +3395,7 @@ function Ie(s, e) {
3381
3395
  l.className = "tbw-pivot-placeholder", l.textContent = "Drag fields here or click to add", o.appendChild(l);
3382
3396
  } else
3383
3397
  for (const l of r)
3384
- o.appendChild(Xt(l, s, e));
3398
+ o.appendChild(nn(l, s, e));
3385
3399
  return o.addEventListener(
3386
3400
  "dragover",
3387
3401
  (l) => {
@@ -3404,7 +3418,7 @@ function Ie(s, e) {
3404
3418
  { signal: i }
3405
3419
  ), o;
3406
3420
  }
3407
- function Xt(s, e, t) {
3421
+ function nn(s, e, t) {
3408
3422
  const { callbacks: n, signal: i } = t, o = document.createElement("div");
3409
3423
  o.className = "tbw-pivot-field-chip", o.draggable = !0;
3410
3424
  const r = n.getAvailableFields().find((d) => d.field === s), l = document.createElement("span");
@@ -3430,7 +3444,7 @@ function Xt(s, e, t) {
3430
3444
  { signal: i }
3431
3445
  ), o;
3432
3446
  }
3433
- function Yt(s) {
3447
+ function on(s) {
3434
3448
  const { config: e, callbacks: t, signal: n } = s, i = document.createElement("div");
3435
3449
  i.className = "tbw-pivot-drop-zone tbw-pivot-values-zone", i.setAttribute("data-zone", "values");
3436
3450
  const o = e.valueFields ?? [];
@@ -3439,7 +3453,7 @@ function Yt(s) {
3439
3453
  r.className = "tbw-pivot-placeholder", r.textContent = "Drag numeric fields here for aggregation", i.appendChild(r);
3440
3454
  } else
3441
3455
  for (const r of o)
3442
- i.appendChild(Jt(r, s));
3456
+ i.appendChild(rn(r, s));
3443
3457
  return i.addEventListener(
3444
3458
  "dragover",
3445
3459
  (r) => {
@@ -3462,7 +3476,7 @@ function Yt(s) {
3462
3476
  { signal: n }
3463
3477
  ), i;
3464
3478
  }
3465
- function Jt(s, e) {
3479
+ function rn(s, e) {
3466
3480
  const { callbacks: t, signal: n } = e, i = document.createElement("div");
3467
3481
  i.className = "tbw-pivot-field-chip tbw-pivot-value-chip";
3468
3482
  const o = t.getAvailableFields().find((c) => c.field === s.field), r = document.createElement("div");
@@ -3471,9 +3485,9 @@ function Jt(s, e) {
3471
3485
  l.className = "tbw-pivot-chip-label", l.textContent = o?.header ?? s.field;
3472
3486
  const a = document.createElement("select");
3473
3487
  a.className = "tbw-pivot-agg-select", a.title = "Aggregation function";
3474
- for (const c of Ut) {
3475
- const h = document.createElement("option");
3476
- 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);
3477
3491
  }
3478
3492
  a.addEventListener(
3479
3493
  "change",
@@ -3491,7 +3505,7 @@ function Jt(s, e) {
3491
3505
  { signal: n }
3492
3506
  ), r.appendChild(l), r.appendChild(a), i.appendChild(r), i.appendChild(d), i;
3493
3507
  }
3494
- function Qt(s) {
3508
+ function sn(s) {
3495
3509
  const { config: e, callbacks: t, signal: n } = s, i = document.createElement("div");
3496
3510
  i.className = "tbw-pivot-available-fields";
3497
3511
  const o = t.getAvailableFields(), r = /* @__PURE__ */ new Set([
@@ -3521,10 +3535,10 @@ function Qt(s) {
3521
3535
  }
3522
3536
  return i;
3523
3537
  }
3524
- function en(s, e) {
3538
+ function ln(s, e) {
3525
3539
  const { config: t, callbacks: n, signal: i } = e, o = document.createElement("div");
3526
3540
  return o.className = "tbw-pivot-options", o.appendChild(
3527
- Q(
3541
+ Y(
3528
3542
  "Enable Pivot View",
3529
3543
  s,
3530
3544
  (r) => {
@@ -3533,7 +3547,7 @@ function en(s, e) {
3533
3547
  i
3534
3548
  )
3535
3549
  ), o.appendChild(
3536
- Q(
3550
+ Y(
3537
3551
  "Show Row Totals",
3538
3552
  t.showTotals ?? !0,
3539
3553
  (r) => {
@@ -3542,7 +3556,7 @@ function en(s, e) {
3542
3556
  i
3543
3557
  )
3544
3558
  ), o.appendChild(
3545
- Q(
3559
+ Y(
3546
3560
  "Show Grand Total",
3547
3561
  t.showGrandTotal ?? !0,
3548
3562
  (r) => {
@@ -3552,7 +3566,7 @@ function en(s, e) {
3552
3566
  )
3553
3567
  ), o;
3554
3568
  }
3555
- function Q(s, e, t, n) {
3569
+ function Y(s, e, t, n) {
3556
3570
  const i = document.createElement("label");
3557
3571
  i.className = "tbw-pivot-checkbox";
3558
3572
  const o = document.createElement("input");
@@ -3560,15 +3574,15 @@ function Q(s, e, t, n) {
3560
3574
  const r = document.createElement("span");
3561
3575
  return r.textContent = s, i.appendChild(o), i.appendChild(r), i;
3562
3576
  }
3563
- function tn(s, e, t) {
3564
- 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) => {
3565
3579
  const o = document.createElement("div");
3566
- 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) {
3567
3581
  const r = Number(s.__pivotIndent) || 0;
3568
3582
  o.style.paddingLeft = `${r}px`;
3569
3583
  const l = String(s.__pivotRowKey), a = document.createElement("button");
3570
- 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) => {
3571
- 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);
3572
3586
  }), o.appendChild(a);
3573
3587
  const d = document.createElement("span");
3574
3588
  d.className = "pivot-label", d.textContent = String(s.__pivotLabel ?? ""), o.appendChild(d);
@@ -3581,22 +3595,22 @@ function tn(s, e, t) {
3581
3595
  e.appendChild(o);
3582
3596
  }), !0;
3583
3597
  }
3584
- function nn(s, e, t) {
3585
- 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) => {
3586
- const o = document.createElement("div");
3587
- if (o.className = "cell", o.setAttribute("data-col", String(i)), o.setAttribute("role", "gridcell"), i === 0) {
3588
- const r = Number(s.__pivotIndent) || 0;
3589
- o.style.paddingLeft = `${r + 20}px`;
3590
- const l = document.createElement("span");
3591
- 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);
3592
3606
  } else {
3593
- const r = s[n.field];
3594
- o.textContent = r != null ? String(r) : "";
3607
+ const l = s[i.field];
3608
+ r.textContent = l != null ? String(l) : "";
3595
3609
  }
3596
- e.appendChild(o);
3610
+ e.appendChild(r);
3597
3611
  }), !0;
3598
3612
  }
3599
- function on(s, e, t) {
3613
+ function cn(s, e, t) {
3600
3614
  return e.className = "pivot-grand-total-row", e.setAttribute("role", "presentation"), e.innerHTML = "", t.forEach((n, i) => {
3601
3615
  const o = document.createElement("div");
3602
3616
  if (o.className = "cell", o.setAttribute("data-col", String(i)), i === 0) {
@@ -3609,10 +3623,10 @@ function on(s, e, t) {
3609
3623
  e.appendChild(o);
3610
3624
  }), !0;
3611
3625
  }
3612
- 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}}';
3613
- 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 {
3614
3628
  name = "pivot";
3615
- version = "1.0.0";
3629
+ styles = un;
3616
3630
  /** Tool panel ID for shell integration */
3617
3631
  static PANEL_ID = "pivot";
3618
3632
  get defaultConfig() {
@@ -3643,17 +3657,11 @@ class M extends x {
3643
3657
  return (this.config.valueFields?.length ?? 0) > 0;
3644
3658
  }
3645
3659
  /**
3646
- * 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.
3647
3662
  */
3648
3663
  get animationStyle() {
3649
- const t = this.grid.effectiveConfig?.animation?.mode ?? "reduced-motion";
3650
- if (t === !1 || t === "off") return !1;
3651
- if (t !== !0 && t !== "on") {
3652
- const n = this.shadowRoot?.host;
3653
- if (n && getComputedStyle(n).getPropertyValue("--tbw-animation-enabled").trim() === "0")
3654
- return !1;
3655
- }
3656
- return this.config.animation ?? "slide";
3664
+ return this.isAnimationEnabled ? this.config.animation ?? "slide" : !1;
3657
3665
  }
3658
3666
  // #endregion
3659
3667
  // #region Lifecycle
@@ -3665,7 +3673,7 @@ class M extends x {
3665
3673
  getToolPanel() {
3666
3674
  if ((this.config?.showToolPanel ?? this.userConfig?.showToolPanel ?? !0) !== !1)
3667
3675
  return {
3668
- id: M.PANEL_ID,
3676
+ id: F.PANEL_ID,
3669
3677
  title: "Pivot",
3670
3678
  icon: "⊞",
3671
3679
  tooltip: "Configure pivot table",
@@ -3678,20 +3686,11 @@ class M extends x {
3678
3686
  processRows(e) {
3679
3687
  if (!this.hasInitialized && this.config.active !== !1 && this.hasValidPivotConfig() && (this.hasInitialized = !0, this.isActive = !0), !this.isActive)
3680
3688
  return [...e];
3681
- const t = Vt(this.config);
3689
+ const t = jt(this.config);
3682
3690
  if (t.length > 0)
3683
3691
  return this.warn(`Config errors: ${t.join(", ")}`), [...e];
3684
- if (this.buildFieldHeaderMap(), this.defaultExpanded = this.config.defaultExpanded ?? !0, this.expandedKeys.size === 0 && this.defaultExpanded && this.pivotResult) {
3685
- const r = J(this.pivotResult.rows);
3686
- for (const l of r)
3687
- this.expandedKeys.add(l);
3688
- }
3689
- if (this.pivotResult = Bt(e, this.config), this.expandedKeys.size === 0 && this.defaultExpanded) {
3690
- const r = J(this.pivotResult.rows);
3691
- for (const l of r)
3692
- this.expandedKeys.add(l);
3693
- }
3694
- 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(
3695
3694
  this.pivotResult.rows,
3696
3695
  this.expandedKeys,
3697
3696
  this.defaultExpanded
@@ -3726,7 +3725,7 @@ class M extends x {
3726
3725
  });
3727
3726
  for (const i of this.pivotResult.columnKeys)
3728
3727
  for (const o of this.config.valueFields ?? []) {
3729
- 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;
3730
3729
  t.push({
3731
3730
  field: r,
3732
3731
  header: `${i} - ${l} (${o.aggFunc})`,
@@ -3741,14 +3740,15 @@ class M extends x {
3741
3740
  type: "number"
3742
3741
  }), t;
3743
3742
  }
3744
- renderRow(e, t) {
3745
- const n = e;
3746
- 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, {
3747
3746
  columns: this.gridColumns,
3748
- onToggle: (i) => this.toggle(i),
3749
- resolveIcon: (i) => this.resolveIcon(i),
3750
- setIcon: (i, o) => this.setIcon(i, o)
3751
- }) : 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);
3752
3752
  }
3753
3753
  /**
3754
3754
  * Remove pivot-specific classes, attributes, and inline styles from a row element.
@@ -3758,6 +3758,12 @@ class M extends x {
3758
3758
  cleanupPivotStyling(e) {
3759
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 = "");
3760
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
+ }
3761
3767
  afterRender() {
3762
3768
  this.isActive && this.config.showGrandTotal && this.pivotResult ? this.renderGrandTotalFooter() : this.cleanupGrandTotalFooter();
3763
3769
  const e = this.animationStyle;
@@ -3788,7 +3794,7 @@ class M extends x {
3788
3794
  __pivotTotal: this.pivotResult.grandTotal,
3789
3795
  ...this.pivotResult.totals
3790
3796
  };
3791
- on(n, this.grandTotalFooter, this.gridColumns);
3797
+ cn(n, this.grandTotalFooter, this.gridColumns);
3792
3798
  }
3793
3799
  /**
3794
3800
  * Remove the grand total footer element.
@@ -3808,16 +3814,20 @@ class M extends x {
3808
3814
  this.expandedKeys.delete(e), this.requestRender();
3809
3815
  }
3810
3816
  expandAll() {
3811
- if (this.pivotResult) {
3812
- const e = J(this.pivotResult.rows);
3813
- for (const t of e)
3814
- this.expandedKeys.add(t);
3815
- this.requestRender();
3816
- }
3817
+ this.expandAllKeys(), this.requestRender();
3817
3818
  }
3818
3819
  collapseAll() {
3819
3820
  this.expandedKeys.clear(), this.requestRender();
3820
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
+ }
3821
3831
  isExpanded(e) {
3822
3832
  return this.expandedKeys.has(e);
3823
3833
  }
@@ -3849,23 +3859,42 @@ class M extends x {
3849
3859
  }
3850
3860
  // #endregion
3851
3861
  // #region Tool Panel API
3862
+ /**
3863
+ * Show the pivot tool panel.
3864
+ * Opens the tool panel and ensures this section is expanded.
3865
+ */
3852
3866
  showPanel() {
3853
- this.grid.openToolPanel(M.PANEL_ID);
3867
+ this.grid.openToolPanel(), this.grid.expandedToolPanelSections.includes(F.PANEL_ID) || this.grid.toggleToolPanelSection(F.PANEL_ID);
3854
3868
  }
3869
+ /**
3870
+ * Hide the tool panel.
3871
+ */
3855
3872
  hidePanel() {
3856
3873
  this.grid.closeToolPanel();
3857
3874
  }
3875
+ /**
3876
+ * Toggle the pivot tool panel section.
3877
+ */
3858
3878
  togglePanel() {
3859
- this.grid.toggleToolPanel(M.PANEL_ID);
3879
+ this.grid.isToolPanelOpen || this.grid.openToolPanel(), this.grid.toggleToolPanelSection(F.PANEL_ID);
3860
3880
  }
3881
+ /**
3882
+ * Check if the pivot panel section is currently expanded.
3883
+ */
3861
3884
  isPanelVisible() {
3862
- return this.grid.activeToolPanel === M.PANEL_ID;
3885
+ return this.grid.isToolPanelOpen && this.grid.expandedToolPanelSections.includes(F.PANEL_ID);
3863
3886
  }
3864
3887
  // #endregion
3865
3888
  // #region Private Helpers
3866
3889
  get gridColumns() {
3867
3890
  return this.grid.columns ?? [];
3868
3891
  }
3892
+ /**
3893
+ * Refresh pivot and update tool panel if active.
3894
+ */
3895
+ refreshIfActive() {
3896
+ this.isActive && this.refresh(), this.refreshPanel();
3897
+ }
3869
3898
  buildFieldHeaderMap() {
3870
3899
  const e = this.getAvailableFields();
3871
3900
  this.fieldHeaderMap.clear();
@@ -3876,12 +3905,11 @@ class M extends x {
3876
3905
  return this.originalColumns.length > 0 ? this.originalColumns : this.captureOriginalColumns();
3877
3906
  }
3878
3907
  captureOriginalColumns() {
3879
- const e = this.grid;
3880
3908
  try {
3881
- const t = e.getAllColumns?.() ?? e.columns ?? [];
3882
- return this.originalColumns = t.filter((n) => !n.field.startsWith("__pivot")).map((n) => ({
3883
- field: n.field,
3884
- 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
3885
3913
  })), this.originalColumns;
3886
3914
  } catch {
3887
3915
  return [];
@@ -3903,7 +3931,7 @@ class M extends x {
3903
3931
  },
3904
3932
  getAvailableFields: () => this.getAvailableFields()
3905
3933
  };
3906
- return Zt(e, this.config, this.isActive, t);
3934
+ return tn(e, this.config, this.isActive, t);
3907
3935
  }
3908
3936
  refreshPanel() {
3909
3937
  this.panelContainer && (this.panelContainer.innerHTML = "", this.renderPanel(this.panelContainer));
@@ -3916,43 +3944,40 @@ class M extends x {
3916
3944
  const n = this.config.columnGroupFields ?? [];
3917
3945
  n.includes(e) || (this.config.columnGroupFields = [...n, e]);
3918
3946
  }
3919
- this.removeFromOtherZones(e, t), this.isActive && this.refresh(), this.refreshPanel();
3947
+ this.removeFromOtherZones(e, t), this.refreshIfActive();
3920
3948
  }
3921
3949
  removeFieldFromZone(e, t) {
3922
- 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();
3923
3951
  }
3924
3952
  removeFromOtherZones(e, t) {
3925
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));
3926
3954
  }
3927
3955
  addValueField(e, t) {
3928
3956
  const n = this.config.valueFields ?? [];
3929
- 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();
3930
3958
  }
3931
3959
  removeValueField(e) {
3932
- 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();
3933
3961
  }
3934
3962
  updateValueAggFunc(e, t) {
3935
3963
  const n = this.config.valueFields ?? [], i = n.findIndex((o) => o.field === e);
3936
3964
  i >= 0 && (n[i] = { ...n[i], aggFunc: t }, this.config.valueFields = [...n]), this.isActive && this.refresh();
3937
3965
  }
3938
3966
  // #endregion
3939
- // #region Styles
3940
- styles = rn;
3941
- // #endregion
3942
3967
  }
3943
- function Fe(s) {
3968
+ function hn(s) {
3944
3969
  const e = s.meta ?? {};
3945
3970
  return e.lockPosition !== !0 && e.suppressMovable !== !0;
3946
3971
  }
3947
- function Me(s, e, t) {
3972
+ function Fe(s, e, t) {
3948
3973
  if (e === t || e < 0 || e >= s.length || t < 0 || t > s.length) return s;
3949
3974
  const n = [...s], [i] = n.splice(e, 1);
3950
3975
  return n.splice(t, 0, i), n;
3951
3976
  }
3952
- 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}';
3953
- 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 {
3954
3979
  name = "reorder";
3955
- version = "1.0.0";
3980
+ styles = fn;
3956
3981
  get defaultConfig() {
3957
3982
  return {
3958
3983
  animation: "flip"
@@ -3961,40 +3986,40 @@ class Vn extends x {
3961
3986
  }
3962
3987
  /**
3963
3988
  * Resolve animation type from plugin config.
3964
- * Respects grid-level animation.mode (disabled = no animation).
3989
+ * Uses base class isAnimationEnabled to respect grid-level settings.
3965
3990
  */
3966
3991
  get animationType() {
3967
3992
  return this.isAnimationEnabled ? this.config.animation !== void 0 ? this.config.animation : this.config.viewTransition === !1 ? !1 : (this.config.viewTransition === !0, "flip") : !1;
3968
3993
  }
3969
3994
  /**
3970
- * Check if animations are enabled at the grid level.
3971
- * Respects gridConfig.animation.mode and CSS variable.
3972
- */
3973
- get isAnimationEnabled() {
3974
- const t = this.grid.effectiveConfig?.animation?.mode ?? "reduced-motion";
3975
- if (t === !1 || t === "off") return !1;
3976
- if (t === !0 || t === "on") return !0;
3977
- const n = this.shadowRoot?.host;
3978
- return n ? getComputedStyle(n).getPropertyValue("--tbw-animation-enabled").trim() !== "0" : !0;
3979
- }
3980
- /**
3981
- * 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.
3982
3997
  */
3983
3998
  get animationDuration() {
3984
- if (this.config.animationDuration !== void 0)
3985
- return this.config.animationDuration;
3986
- const e = this.shadowRoot?.host;
3987
- if (e) {
3988
- const t = getComputedStyle(e).getPropertyValue("--tbw-animation-duration").trim(), n = parseInt(t, 10);
3989
- if (!isNaN(n)) return n;
3990
- }
3991
- return 200;
3999
+ return this.config.animationDuration !== void 0 ? this.config.animationDuration : super.animationDuration;
3992
4000
  }
3993
4001
  // #region Internal State
3994
4002
  isDragging = !1;
3995
4003
  draggedField = null;
3996
4004
  draggedIndex = null;
3997
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
+ }
3998
4023
  // #endregion
3999
4024
  // #region Lifecycle
4000
4025
  attach(e) {
@@ -4018,39 +4043,34 @@ class Vn extends x {
4018
4043
  e.querySelectorAll(".header-row > .cell").forEach((n) => {
4019
4044
  const i = n, o = i.getAttribute("data-field");
4020
4045
  if (!o) return;
4021
- const r = this.columns.find((c) => c.field === o), d = !this.grid.queryPlugins({
4022
- type: H.CAN_MOVE_COLUMN,
4023
- context: r
4024
- }).includes(!1);
4025
- if (!r || !Fe(r) || !d) {
4046
+ const r = this.columns.find((l) => l.field === o);
4047
+ if (!this.canMoveColumnWithPlugins(r)) {
4026
4048
  i.draggable = !1;
4027
4049
  return;
4028
4050
  }
4029
- i.draggable = !0, !i.getAttribute("data-dragstart-bound") && (i.setAttribute("data-dragstart-bound", "true"), i.addEventListener("dragstart", (c) => {
4030
- const u = this.getColumnOrder().indexOf(o);
4031
- 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");
4032
4054
  }), i.addEventListener("dragend", () => {
4033
- this.isDragging = !1, this.draggedField = null, this.draggedIndex = null, this.dropIndex = null, e.querySelectorAll(".header-row > .cell").forEach((c) => {
4034
- c.classList.remove("dragging", "drop-target", "drop-before", "drop-after");
4035
- });
4036
- }), i.addEventListener("dragover", (c) => {
4037
- if (c.preventDefault(), !this.isDragging || this.draggedField === o) return;
4038
- const h = i.getBoundingClientRect(), u = h.left + h.width / 2, g = this.getColumnOrder().indexOf(o);
4039
- 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);
4040
4060
  }), i.addEventListener("dragleave", () => {
4041
4061
  i.classList.remove("drop-target", "drop-before", "drop-after");
4042
- }), i.addEventListener("drop", (c) => {
4043
- c.preventDefault();
4044
- const h = this.draggedField, u = this.draggedIndex, f = this.dropIndex;
4045
- 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)
4046
4066
  return;
4047
- const g = f > u ? f - 1 : f, p = this.getColumnOrder(), w = Me(p, u, g), m = {
4048
- field: h,
4049
- fromIndex: u,
4050
- toIndex: g,
4051
- 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
4052
4072
  };
4053
- this.updateColumnOrder(w), this.emit("column-move", m);
4073
+ this.updateColumnOrder(f), this.emitCancelable("column-move", g) && this.updateColumnOrder(h);
4054
4074
  }));
4055
4075
  });
4056
4076
  }
@@ -4063,22 +4083,14 @@ class Vn extends x {
4063
4083
  const t = this.grid, n = t._focusCol, i = t._visibleColumns;
4064
4084
  if (n < 0 || n >= i.length) return;
4065
4085
  const o = i[n];
4066
- if (!o || !Fe(o)) return;
4067
- const r = this.grid;
4068
- if (r.queryPlugins({
4069
- type: H.CAN_MOVE_COLUMN,
4070
- context: o
4071
- }).includes(!1)) return;
4072
- const a = this.getColumnOrder(), d = a.indexOf(o.field);
4073
- if (d === -1) return;
4074
- const c = e.key === "ArrowLeft" ? d - 1 : d + 1;
4075
- if (c < 0 || c >= a.length) return;
4076
- const h = i.find((u) => u.field === a[c]);
4077
- if (!(h && r.queryPlugins({
4078
- type: H.CAN_MOVE_COLUMN,
4079
- context: h
4080
- }).includes(!1)))
4081
- 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;
4082
4094
  }
4083
4095
  // #endregion
4084
4096
  // #region Public API
@@ -4097,13 +4109,13 @@ class Vn extends x {
4097
4109
  moveColumn(e, t) {
4098
4110
  const n = this.getColumnOrder(), i = n.indexOf(e);
4099
4111
  if (i === -1) return;
4100
- const o = Me(n, i, t);
4101
- this.updateColumnOrder(o), this.emit("column-move", {
4112
+ const o = Fe(n, i, t);
4113
+ this.updateColumnOrder(o), this.emitCancelable("column-move", {
4102
4114
  field: e,
4103
4115
  fromIndex: i,
4104
4116
  toIndex: t,
4105
4117
  columnOrder: o
4106
- });
4118
+ }) && this.updateColumnOrder(n);
4107
4119
  }
4108
4120
  /**
4109
4121
  * Set a specific column order.
@@ -4206,21 +4218,47 @@ class Vn extends x {
4206
4218
  * Update column order with configured animation.
4207
4219
  */
4208
4220
  updateColumnOrder(e) {
4209
- const t = this.grid, n = this.animationType;
4210
- if (n === "flip" && this.shadowRoot) {
4211
- const i = this.captureHeaderPositions();
4212
- t.setColumnOrder(e), requestAnimationFrame(() => {
4213
- 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);
4214
4226
  });
4215
- } else n === "fade" ? this.animateFade(() => t.setColumnOrder(e)) : t.setColumnOrder(e);
4216
- t.requestStateChange?.();
4227
+ } else t === "fade" ? this.animateFade(() => this.grid.setColumnOrder(e)) : this.grid.setColumnOrder(e);
4228
+ this.grid.requestStateChange?.();
4217
4229
  }
4218
4230
  // #endregion
4219
- // #region Styles
4220
- styles = sn;
4221
- // #endregion
4222
4231
  }
4223
- 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) {
4224
4262
  return {
4225
4263
  startRow: Math.min(s.startRow, s.endRow),
4226
4264
  startCol: Math.min(s.startCol, s.endCol),
@@ -4228,38 +4266,38 @@ function G(s) {
4228
4266
  endCol: Math.max(s.startCol, s.endCol)
4229
4267
  };
4230
4268
  }
4231
- function ln(s) {
4232
- const e = G(s);
4269
+ function gn(s) {
4270
+ const e = B(s);
4233
4271
  return {
4234
4272
  from: { row: e.startRow, col: e.startCol },
4235
4273
  to: { row: e.endRow, col: e.endCol }
4236
4274
  };
4237
4275
  }
4238
- function ie(s) {
4239
- return s.map(ln);
4276
+ function Ve(s) {
4277
+ return s.map(gn);
4240
4278
  }
4241
- function an(s, e, t) {
4242
- const n = G(t);
4279
+ function pn(s, e, t) {
4280
+ const n = B(t);
4243
4281
  return s >= n.startRow && s <= n.endRow && e >= n.startCol && e <= n.endCol;
4244
4282
  }
4245
- function Pe(s, e, t) {
4246
- return t.some((n) => an(s, e, n));
4283
+ function Me(s, e, t) {
4284
+ return t.some((n) => pn(s, e, n));
4247
4285
  }
4248
- function dn(s) {
4249
- const e = [], t = G(s);
4286
+ function mn(s) {
4287
+ const e = [], t = B(s);
4250
4288
  for (let n = t.startRow; n <= t.endRow; n++)
4251
4289
  for (let i = t.startCol; i <= t.endCol; i++)
4252
4290
  e.push({ row: n, col: i });
4253
4291
  return e;
4254
4292
  }
4255
- function cn(s) {
4293
+ function wn(s) {
4256
4294
  const e = /* @__PURE__ */ new Map();
4257
4295
  for (const t of s)
4258
- for (const n of dn(t))
4296
+ for (const n of mn(t))
4259
4297
  e.set(`${n.row},${n.col}`, n);
4260
4298
  return [...e.values()];
4261
4299
  }
4262
- function ee(s, e) {
4300
+ function J(s, e) {
4263
4301
  return {
4264
4302
  startRow: s.row,
4265
4303
  startCol: s.col,
@@ -4267,8 +4305,8 @@ function ee(s, e) {
4267
4305
  endCol: e.col
4268
4306
  };
4269
4307
  }
4270
- 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}';
4271
- 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) {
4272
4310
  if (s === "cell" && e.selectedCell)
4273
4311
  return {
4274
4312
  mode: s,
@@ -4286,11 +4324,11 @@ function hn(s, e, t) {
4286
4324
  }));
4287
4325
  return { mode: s, ranges: n };
4288
4326
  }
4289
- 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: [] };
4290
4328
  }
4291
- class Bn extends x {
4329
+ class Jn extends x {
4292
4330
  name = "selection";
4293
- version = "1.0.0";
4331
+ styles = bn;
4294
4332
  get defaultConfig() {
4295
4333
  return {
4296
4334
  mode: "cell"
@@ -4318,32 +4356,34 @@ class Bn extends x {
4318
4356
  // #endregion
4319
4357
  // #region Event Handlers
4320
4358
  onCellClick(e) {
4321
- 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);
4322
4360
  if (o === "cell")
4323
- 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;
4324
4362
  if (o === "row")
4325
4363
  return this.selected.clear(), this.selected.add(t), this.lastSelected = t, this.emit("selection-change", this.#t()), this.requestAfterRender(), !1;
4326
4364
  if (o === "range") {
4327
- const r = i.shiftKey, l = i.ctrlKey || i.metaKey;
4328
- if (r && this.cellAnchor) {
4329
- const a = ee(this.cellAnchor, { row: t, col: n });
4330
- l ? this.ranges.length > 0 ? this.ranges[this.ranges.length - 1] = a : this.ranges.push(a) : this.ranges = [a], this.activeRange = a;
4331
- } else if (l) {
4332
- 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 = {
4333
4373
  startRow: t,
4334
4374
  startCol: n,
4335
4375
  endRow: t,
4336
4376
  endCol: n
4337
4377
  };
4338
- 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 };
4339
4379
  } else {
4340
- const a = {
4380
+ const c = {
4341
4381
  startRow: t,
4342
4382
  startCol: n,
4343
4383
  endRow: t,
4344
4384
  endCol: n
4345
4385
  };
4346
- 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 };
4347
4387
  }
4348
4388
  return this.emit("selection-change", this.#t()), this.requestAfterRender(), !1;
4349
4389
  }
@@ -4380,23 +4420,31 @@ class Bn extends x {
4380
4420
  return !1;
4381
4421
  }
4382
4422
  onCellMouseDown(e) {
4383
- 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)
4384
4426
  return;
4385
4427
  this.isDragging = !0;
4386
- const t = e.rowIndex, n = e.colIndex;
4387
- this.cellAnchor = { row: t, col: n }, e.originalEvent.ctrlKey || e.originalEvent.metaKey || (this.ranges = []);
4388
- const o = {
4389
- startRow: t,
4390
- startCol: n,
4391
- endRow: t,
4392
- 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
4393
4435
  };
4394
- 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;
4395
4437
  }
4396
4438
  onCellMouseMove(e) {
4397
4439
  if (this.config.mode !== "range" || !this.isDragging || !this.cellAnchor || e.rowIndex === void 0 || e.colIndex === void 0 || e.rowIndex < 0) return;
4398
- const t = ee(this.cellAnchor, { row: e.rowIndex, col: e.colIndex });
4399
- 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;
4400
4448
  }
4401
4449
  onCellMouseUp(e) {
4402
4450
  if (this.config.mode === "range" && this.isDragging)
@@ -4417,14 +4465,23 @@ class Bn extends x {
4417
4465
  if (i.forEach((o) => {
4418
4466
  o.classList.remove("selected", "row-focus");
4419
4467
  }), t === "row" && (V(e), i.forEach((o) => {
4420
- const r = o.querySelector(".cell[data-row]"), l = Ze(r);
4468
+ const r = o.querySelector(".cell[data-row]"), l = Ye(r);
4421
4469
  l >= 0 && this.selected.has(l) && o.classList.add("selected", "row-focus");
4422
4470
  })), t === "range" && this.ranges.length > 0) {
4423
4471
  V(e);
4424
- const o = this.activeRange ? G(this.activeRange) : null;
4425
- e.querySelectorAll(".cell[data-row][data-col]").forEach((l) => {
4426
- const a = parseInt(l.getAttribute("data-row") ?? "-1", 10), d = parseInt(l.getAttribute("data-col") ?? "-1", 10);
4427
- 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
+ }
4428
4485
  });
4429
4486
  }
4430
4487
  t === "cell" && this.selectedCell && V(e);
@@ -4438,7 +4495,7 @@ class Bn extends x {
4438
4495
  this.pendingKeyboardUpdate = null;
4439
4496
  const o = this.grid._focusRow, r = this.grid._focusCol;
4440
4497
  if (i && this.cellAnchor) {
4441
- const l = ee(this.cellAnchor, { row: o, col: r });
4498
+ const l = J(this.cellAnchor, { row: o, col: r });
4442
4499
  this.ranges = [l], this.activeRange = l;
4443
4500
  } else i || (this.ranges = [], this.activeRange = null, this.cellAnchor = { row: o, col: r });
4444
4501
  this.emit("selection-change", this.#t());
@@ -4454,35 +4511,62 @@ class Bn extends x {
4454
4511
  }
4455
4512
  // #endregion
4456
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
+ }
4457
4536
  /**
4458
4537
  * Get the selected cell (cell mode only).
4538
+ * @deprecated Use `getSelection()` instead for a unified API across all modes.
4459
4539
  */
4460
4540
  getSelectedCell() {
4461
- return this.selectedCell;
4541
+ const { mode: e, ranges: t } = this.getSelection();
4542
+ return e === "cell" && t.length > 0 ? t[0].from : null;
4462
4543
  }
4463
4544
  /**
4464
4545
  * Get all selected row indices (row mode).
4546
+ * @deprecated Use `getSelection().ranges` instead - each range represents a full row.
4465
4547
  */
4466
4548
  getSelectedRows() {
4467
- return [...this.selected];
4549
+ const { mode: e, ranges: t } = this.getSelection();
4550
+ return e === "row" ? t.map((n) => n.from.row) : [];
4468
4551
  }
4469
4552
  /**
4470
4553
  * Get all selected cell ranges in public format.
4554
+ * @deprecated Use `getSelection().ranges` instead.
4471
4555
  */
4472
4556
  getRanges() {
4473
- return ie(this.ranges);
4557
+ return this.getSelection().ranges;
4474
4558
  }
4475
4559
  /**
4476
4560
  * Get all selected cells across all ranges.
4477
4561
  */
4478
4562
  getSelectedCells() {
4479
- return cn(this.ranges);
4563
+ return wn(this.ranges);
4480
4564
  }
4481
4565
  /**
4482
4566
  * Check if a specific cell is in range selection.
4483
4567
  */
4484
4568
  isCellSelected(e, t) {
4485
- return Pe(e, t, this.ranges);
4569
+ return Me(e, t, this.ranges);
4486
4570
  }
4487
4571
  /**
4488
4572
  * Clear all selection.
@@ -4501,13 +4585,13 @@ class Bn extends x {
4501
4585
  endCol: t.to.col
4502
4586
  })), this.activeRange = this.ranges.length > 0 ? this.ranges[this.ranges.length - 1] : null, this.emit("selection-change", {
4503
4587
  mode: this.config.mode,
4504
- ranges: ie(this.ranges)
4588
+ ranges: Ve(this.ranges)
4505
4589
  }), this.requestAfterRender();
4506
4590
  }
4507
4591
  // #endregion
4508
4592
  // #region Private Helpers
4509
4593
  #t() {
4510
- return hn(
4594
+ return vn(
4511
4595
  this.config.mode,
4512
4596
  {
4513
4597
  selectedCell: this.selectedCell,
@@ -4518,56 +4602,24 @@ class Bn extends x {
4518
4602
  );
4519
4603
  }
4520
4604
  // #endregion
4521
- // #region Styles
4522
- styles = un;
4523
- // #endregion
4524
4605
  }
4525
- function zn(s, e, t, n) {
4526
- const i = new Set(s.selected);
4527
- let o = s.anchor;
4528
- if (t === "single")
4529
- i.clear(), i.add(e), o = e;
4530
- else if (t === "multiple") {
4531
- const r = n.ctrlKey || n.metaKey;
4532
- if (n.shiftKey && s.anchor !== null) {
4533
- const l = Math.min(s.anchor, e), a = Math.max(s.anchor, e);
4534
- for (let d = l; d <= a; d++)
4535
- i.add(d);
4536
- } else r ? (i.has(e) ? i.delete(e) : i.add(e), o = e) : (i.clear(), i.add(e), o = e);
4537
- }
4538
- return { selected: i, lastSelected: e, anchor: o };
4539
- }
4540
- function $n(s) {
4541
- const e = /* @__PURE__ */ new Set();
4542
- for (let t = 0; t < s; t++)
4543
- e.add(t);
4544
- return e;
4545
- }
4546
- function Wn(s, e) {
4547
- const t = [], n = [];
4548
- for (const i of e)
4549
- s.has(i) || t.push(i);
4550
- for (const i of s)
4551
- e.has(i) || n.push(i);
4552
- return { added: t, removed: n };
4553
- }
4554
- function O(s, e) {
4606
+ function G(s, e) {
4555
4607
  return Math.floor(s / e);
4556
4608
  }
4557
- function fn(s, e) {
4609
+ function yn(s, e) {
4558
4610
  return {
4559
4611
  start: s * e,
4560
4612
  end: (s + 1) * e
4561
4613
  };
4562
4614
  }
4563
- function gn(s, e, t) {
4564
- 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 = [];
4565
4617
  for (let r = n; r <= i; r++)
4566
4618
  o.push(r);
4567
4619
  return o;
4568
4620
  }
4569
- async function qe(s, e, t, n) {
4570
- const i = fn(e, t);
4621
+ async function Pe(s, e, t, n) {
4622
+ const i = yn(e, t);
4571
4623
  return s.getRows({
4572
4624
  startRow: i.start,
4573
4625
  endRow: i.end,
@@ -4575,16 +4627,15 @@ async function qe(s, e, t, n) {
4575
4627
  filterModel: n.filterModel
4576
4628
  });
4577
4629
  }
4578
- function pn(s, e, t) {
4579
- 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);
4580
4632
  if (!i) return;
4581
4633
  const o = s % e;
4582
4634
  return i[o];
4583
4635
  }
4584
- const mn = 100;
4585
- class jn extends x {
4636
+ const Rn = 100;
4637
+ class Qn extends x {
4586
4638
  name = "serverSide";
4587
- version = "1.0.0";
4588
4639
  get defaultConfig() {
4589
4640
  return {
4590
4641
  pageSize: 100,
@@ -4611,12 +4662,12 @@ class jn extends x {
4611
4662
  */
4612
4663
  loadRequiredBlocks() {
4613
4664
  if (!this.dataSource) return;
4614
- 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);
4615
4666
  for (const o of i)
4616
4667
  if (!(this.loadedBlocks.has(o) || this.loadingBlocks.has(o))) {
4617
4668
  if (this.loadingBlocks.size >= (this.config.maxConcurrentRequests ?? 2))
4618
4669
  break;
4619
- this.loadingBlocks.add(o), qe(this.dataSource, o, t, {}).then((r) => {
4670
+ this.loadingBlocks.add(o), Pe(this.dataSource, o, t, {}).then((r) => {
4620
4671
  this.loadedBlocks.set(o, r.rows), this.totalRowCount = r.totalRowCount, this.loadingBlocks.delete(o), this.requestRender(), this.loadRequiredBlocks();
4621
4672
  }).catch(() => {
4622
4673
  this.loadingBlocks.delete(o);
@@ -4629,7 +4680,7 @@ class jn extends x {
4629
4680
  if (!this.dataSource) return [...e];
4630
4681
  const t = [];
4631
4682
  for (let n = 0; n < this.totalRowCount; n++) {
4632
- const i = pn(n, this.config.cacheBlockSize ?? 100, this.loadedBlocks);
4683
+ const i = Cn(n, this.config.cacheBlockSize ?? 100, this.loadedBlocks);
4633
4684
  t.push(i ?? { __loading: !0, __index: n });
4634
4685
  }
4635
4686
  return t;
@@ -4637,7 +4688,7 @@ class jn extends x {
4637
4688
  onScroll(e) {
4638
4689
  this.dataSource && (this.loadRequiredBlocks(), this.scrollDebounceTimer && clearTimeout(this.scrollDebounceTimer), this.scrollDebounceTimer = setTimeout(() => {
4639
4690
  this.loadRequiredBlocks();
4640
- }, mn));
4691
+ }, Rn));
4641
4692
  }
4642
4693
  // #endregion
4643
4694
  // #region Public API
@@ -4648,7 +4699,7 @@ class jn extends x {
4648
4699
  setDataSource(e) {
4649
4700
  this.dataSource = e, this.loadedBlocks.clear(), this.loadingBlocks.clear();
4650
4701
  const t = this.config.cacheBlockSize ?? 100;
4651
- qe(e, 0, t, {}).then((n) => {
4702
+ Pe(e, 0, t, {}).then((n) => {
4652
4703
  this.loadedBlocks.set(0, n.rows), this.totalRowCount = n.totalRowCount, this.requestRender();
4653
4704
  });
4654
4705
  }
@@ -4675,7 +4726,7 @@ class jn extends x {
4675
4726
  * @param rowIndex - Row index to check
4676
4727
  */
4677
4728
  isRowLoaded(e) {
4678
- const t = this.config.cacheBlockSize ?? 100, n = O(e, t);
4729
+ const t = this.config.cacheBlockSize ?? 100, n = G(e, t);
4679
4730
  return this.loadedBlocks.has(n);
4680
4731
  }
4681
4732
  /**
@@ -4686,52 +4737,52 @@ class jn extends x {
4686
4737
  }
4687
4738
  // #endregion
4688
4739
  }
4689
- function Ve(s, e, t) {
4740
+ function ze(s, e, t) {
4690
4741
  return s.id !== void 0 ? String(s.id) : t ? `${t}-${e}` : String(e);
4691
4742
  }
4692
- function Ke(s, e) {
4743
+ function Q(s, e) {
4693
4744
  const t = new Set(s);
4694
4745
  return t.has(e) ? t.delete(e) : t.add(e), t;
4695
4746
  }
4696
- function oe(s, e, t = null, n = 0) {
4747
+ function ne(s, e, t = null, n = 0) {
4697
4748
  const i = e.childrenField ?? "children", o = /* @__PURE__ */ new Set();
4698
4749
  for (let r = 0; r < s.length; r++) {
4699
- 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];
4700
4751
  if (Array.isArray(d) && d.length > 0) {
4701
4752
  o.add(a);
4702
- const c = oe(d, e, a, n + 1);
4703
- 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);
4704
4755
  }
4705
4756
  }
4706
4757
  return o;
4707
4758
  }
4708
- function wn() {
4759
+ function En() {
4709
4760
  return /* @__PURE__ */ new Set();
4710
4761
  }
4711
- function Be(s, e, t, n = null, i = 0) {
4762
+ function We(s, e, t, n = null, i = 0) {
4712
4763
  const o = t.childrenField ?? "children";
4713
4764
  for (let r = 0; r < s.length; r++) {
4714
- const l = s[r], a = Ve(l, r, n);
4765
+ const l = s[r], a = ze(l, r, n);
4715
4766
  if (a === e)
4716
4767
  return [a];
4717
4768
  const d = l[o];
4718
4769
  if (Array.isArray(d) && d.length > 0) {
4719
- const c = Be(d, e, t, a, i + 1);
4770
+ const c = We(d, e, t, a, i + 1);
4720
4771
  if (c)
4721
4772
  return [a, ...c];
4722
4773
  }
4723
4774
  }
4724
4775
  return null;
4725
4776
  }
4726
- function bn(s, e, t, n) {
4727
- const i = Be(s, e, t);
4777
+ function Sn(s, e, t, n) {
4778
+ const i = We(s, e, t);
4728
4779
  if (!i) return n;
4729
4780
  const o = new Set(n);
4730
4781
  for (let r = 0; r < i.length - 1; r++)
4731
4782
  o.add(i[r]);
4732
4783
  return o;
4733
4784
  }
4734
- function Ne(s, e = "children") {
4785
+ function De(s, e = "children") {
4735
4786
  if (!Array.isArray(s) || s.length === 0) return !1;
4736
4787
  for (const t of s) {
4737
4788
  if (!t) continue;
@@ -4741,7 +4792,7 @@ function Ne(s, e = "children") {
4741
4792
  }
4742
4793
  return !1;
4743
4794
  }
4744
- function vn(s) {
4795
+ function kn(s) {
4745
4796
  if (!Array.isArray(s) || s.length === 0) return null;
4746
4797
  const e = ["children", "items", "nodes", "subRows", "nested"];
4747
4798
  for (const t of s)
@@ -4753,35 +4804,34 @@ function vn(s) {
4753
4804
  }
4754
4805
  return null;
4755
4806
  }
4756
- function yn(s, e = "children", t = 0) {
4807
+ function An(s, e = "children", t = 0) {
4757
4808
  if (!Array.isArray(s) || s.length === 0) return t;
4758
4809
  let n = t;
4759
4810
  for (const i of s) {
4760
4811
  if (!i) continue;
4761
4812
  const o = i[e];
4762
4813
  if (Array.isArray(o) && o.length > 0) {
4763
- const r = yn(o, e, t + 1);
4814
+ const r = An(o, e, t + 1);
4764
4815
  r > n && (n = r);
4765
4816
  }
4766
4817
  }
4767
4818
  return n;
4768
4819
  }
4769
- function xn(s, e = "children") {
4820
+ function _n(s, e = "children") {
4770
4821
  if (!Array.isArray(s)) return 0;
4771
4822
  let t = 0;
4772
4823
  for (const n of s) {
4773
4824
  if (!n) continue;
4774
4825
  t++;
4775
4826
  const i = n[e];
4776
- Array.isArray(i) && (t += xn(i, e));
4827
+ Array.isArray(i) && (t += _n(i, e));
4777
4828
  }
4778
4829
  return t;
4779
4830
  }
4780
- 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}}";
4781
- 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 {
4782
4833
  name = "tree";
4783
- version = "1.0.0";
4784
- styles = Cn;
4834
+ styles = Ln;
4785
4835
  get defaultConfig() {
4786
4836
  return {
4787
4837
  childrenField: "children",
@@ -4805,31 +4855,28 @@ class Un extends x {
4805
4855
  }
4806
4856
  // #endregion
4807
4857
  // #region Animation
4858
+ /**
4859
+ * Get expand/collapse animation style from plugin config.
4860
+ * Uses base class isAnimationEnabled to respect grid-level settings.
4861
+ */
4808
4862
  get animationStyle() {
4809
- const t = this.grid.effectiveConfig?.animation?.mode ?? "reduced-motion";
4810
- if (t === !1 || t === "off") return !1;
4811
- if (t !== !0 && t !== "on") {
4812
- const n = this.shadowRoot?.host;
4813
- if (n && getComputedStyle(n).getPropertyValue("--tbw-animation-enabled").trim() === "0")
4814
- return !1;
4815
- }
4816
- return this.config.animation ?? "slide";
4863
+ return this.isAnimationEnabled ? this.config.animation ?? "slide" : !1;
4817
4864
  }
4818
4865
  // #endregion
4819
4866
  // #region Auto-Detection
4820
4867
  detect(e) {
4821
4868
  if (!this.config.autoDetect) return !1;
4822
- const t = e, n = this.config.childrenField ?? vn(t) ?? "children";
4823
- return Ne(t, n);
4869
+ const t = e, n = this.config.childrenField ?? kn(t) ?? "children";
4870
+ return De(t, n);
4824
4871
  }
4825
4872
  // #endregion
4826
4873
  // #region Data Processing
4827
4874
  processRows(e) {
4828
4875
  const t = this.config.childrenField ?? "children", n = e;
4829
- if (!Ne(n, t))
4876
+ if (!De(n, t))
4830
4877
  return this.flattenedRows = [], this.rowKeyMap.clear(), this.previousVisibleKeys.clear(), [...e];
4831
4878
  let i = this.withStableKeys(n);
4832
- 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();
4833
4880
  const o = /* @__PURE__ */ new Set();
4834
4881
  for (const r of this.flattenedRows)
4835
4882
  this.rowKeyMap.set(r.key, r), o.add(r.key), !this.previousVisibleKeys.has(r.key) && r.depth > 0 && this.keysToAnimate.add(r.key);
@@ -4857,15 +4904,15 @@ class Un extends x {
4857
4904
  flattenTree(e, t, n = 0) {
4858
4905
  const i = this.config.childrenField ?? "children", o = [];
4859
4906
  for (const r of e) {
4860
- 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);
4861
4908
  o.push({
4862
4909
  key: a,
4863
4910
  data: r,
4864
4911
  depth: n,
4865
4912
  hasChildren: c,
4866
- isExpanded: h,
4913
+ isExpanded: u,
4867
4914
  parentKey: n > 0 && a.substring(0, a.lastIndexOf("-")) || null
4868
- }), c && h && o.push(...this.flattenTree(d, t, n + 1));
4915
+ }), c && u && o.push(...this.flattenTree(d, t, n + 1));
4869
4916
  }
4870
4917
  return o;
4871
4918
  }
@@ -4884,40 +4931,52 @@ class Un extends x {
4884
4931
  if (this.flattenedRows.length === 0) return [...e];
4885
4932
  const t = [...e];
4886
4933
  if (t.length === 0) return t;
4887
- const n = { ...t[0] }, i = n.viewRenderer;
4888
- if (i?.__treeWrapped) return t;
4889
- const o = () => this.config, r = this.setIcon.bind(this), l = this.resolveIcon.bind(this), a = (d) => {
4890
- const { value: c, row: h } = d, { indentWidth: u = 20, showExpandIcons: f = !0 } = o(), g = h, p = document.createElement("span");
4891
- 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) {
4892
- const m = document.createElement("span");
4893
- 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);
4894
- } else if (f) {
4895
- const m = document.createElement("span");
4896
- m.className = "tree-spacer", p.appendChild(m);
4897
- }
4898
- const w = document.createElement("span");
4899
- if (i) {
4900
- const m = i(d);
4901
- 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);
4902
4948
  } else
4903
- w.textContent = String(c ?? "");
4904
- return p.appendChild(w), p;
4949
+ m.textContent = u != null ? String(u) : "";
4950
+ return b.appendChild(m), b;
4905
4951
  };
4906
- return a.__treeWrapped = !0, n.viewRenderer = a, t[0] = n, t;
4952
+ return t[0] = { ...n, viewRenderer: a }, t;
4907
4953
  }
4908
4954
  // #endregion
4909
4955
  // #region Event Handlers
4910
4956
  onCellClick(e) {
4911
4957
  const t = e.originalEvent?.target;
4912
4958
  if (!t?.classList.contains("tree-toggle")) return !1;
4913
- const n = t.getAttribute("data-tree-key"), i = n ? this.rowKeyMap.get(n) : null;
4914
- return i ? (this.expandedKeys = Ke(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", {
4915
4963
  key: n,
4916
4964
  row: i.data,
4917
4965
  expanded: this.expandedKeys.has(n),
4918
4966
  depth: i.depth
4919
4967
  }), this.requestRender(), !0) : !1;
4920
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
+ }
4921
4980
  onHeaderClick(e) {
4922
4981
  if (this.flattenedRows.length === 0 || !e.column.sortable) return !1;
4923
4982
  const { field: t } = e.column;
@@ -4946,13 +5005,13 @@ class Un extends x {
4946
5005
  this.expandedKeys.delete(e), this.requestRender();
4947
5006
  }
4948
5007
  toggle(e) {
4949
- this.expandedKeys = Ke(this.expandedKeys, e), this.requestRender();
5008
+ this.expandedKeys = Q(this.expandedKeys, e), this.requestRender();
4950
5009
  }
4951
5010
  expandAll() {
4952
- this.expandedKeys = oe(this.rows, this.config), this.requestRender();
5011
+ this.expandedKeys = ne(this.rows, this.config), this.requestRender();
4953
5012
  }
4954
5013
  collapseAll() {
4955
- this.expandedKeys = wn(), this.requestRender();
5014
+ this.expandedKeys = En(), this.requestRender();
4956
5015
  }
4957
5016
  isExpanded(e) {
4958
5017
  return this.expandedKeys.has(e);
@@ -4967,11 +5026,11 @@ class Un extends x {
4967
5026
  return this.rowKeyMap.get(e)?.data;
4968
5027
  }
4969
5028
  expandToKey(e) {
4970
- 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();
4971
5030
  }
4972
5031
  // #endregion
4973
5032
  }
4974
- function Rn(s, e, t) {
5033
+ function Tn(s, e, t) {
4975
5034
  const n = [...s.undoStack, e];
4976
5035
  for (; n.length > t; )
4977
5036
  n.shift();
@@ -4981,7 +5040,7 @@ function Rn(s, e, t) {
4981
5040
  // Clear redo on new action
4982
5041
  };
4983
5042
  }
4984
- function De(s) {
5043
+ function Ke(s) {
4985
5044
  if (s.undoStack.length === 0)
4986
5045
  return { newState: s, action: null };
4987
5046
  const e = [...s.undoStack], t = e.pop();
@@ -4993,7 +5052,7 @@ function De(s) {
4993
5052
  action: t
4994
5053
  } : { newState: s, action: null };
4995
5054
  }
4996
- function He(s) {
5055
+ function qe(s) {
4997
5056
  if (s.redoStack.length === 0)
4998
5057
  return { newState: s, action: null };
4999
5058
  const e = [...s.redoStack], t = e.pop();
@@ -5005,16 +5064,16 @@ function He(s) {
5005
5064
  action: t
5006
5065
  } : { newState: s, action: null };
5007
5066
  }
5008
- function En(s) {
5067
+ function In(s) {
5009
5068
  return s.undoStack.length > 0;
5010
5069
  }
5011
- function Sn(s) {
5070
+ function Fn(s) {
5012
5071
  return s.redoStack.length > 0;
5013
5072
  }
5014
- function kn() {
5073
+ function Mn() {
5015
5074
  return { undoStack: [], redoStack: [] };
5016
5075
  }
5017
- function An(s, e, t, n) {
5076
+ function Pn(s, e, t, n) {
5018
5077
  return {
5019
5078
  type: "cell-edit",
5020
5079
  rowIndex: s,
@@ -5024,9 +5083,16 @@ function An(s, e, t, n) {
5024
5083
  timestamp: Date.now()
5025
5084
  };
5026
5085
  }
5027
- class Zn extends x {
5086
+ class ti extends x {
5087
+ /**
5088
+ * Plugin dependencies - UndoRedoPlugin requires EditingPlugin to track edits.
5089
+ *
5090
+ * The EditingPlugin must be loaded BEFORE this plugin in the plugins array.
5091
+ */
5092
+ static dependencies = [
5093
+ { name: "editing", required: !0, reason: "UndoRedoPlugin tracks cell edit history" }
5094
+ ];
5028
5095
  name = "undoRedo";
5029
- version = "1.0.0";
5030
5096
  get defaultConfig() {
5031
5097
  return {
5032
5098
  maxHistorySize: 100
@@ -5049,7 +5115,7 @@ class Zn extends x {
5049
5115
  onKeyDown(e) {
5050
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);
5051
5117
  if (t) {
5052
- const i = De({ undoStack: this.undoStack, redoStack: this.redoStack });
5118
+ const i = Ke({ undoStack: this.undoStack, redoStack: this.redoStack });
5053
5119
  if (i.action) {
5054
5120
  const o = this.rows;
5055
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", {
@@ -5060,7 +5126,7 @@ class Zn extends x {
5060
5126
  return !0;
5061
5127
  }
5062
5128
  if (n) {
5063
- const i = He({ undoStack: this.undoStack, redoStack: this.redoStack });
5129
+ const i = qe({ undoStack: this.undoStack, redoStack: this.redoStack });
5064
5130
  if (i.action) {
5065
5131
  const o = this.rows;
5066
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", {
@@ -5083,7 +5149,7 @@ class Zn extends x {
5083
5149
  * @param newValue - The value after the edit
5084
5150
  */
5085
5151
  recordEdit(e, t, n, i) {
5086
- const o = An(e, t, n, i), r = Rn(
5152
+ const o = Pn(e, t, n, i), r = Tn(
5087
5153
  { undoStack: this.undoStack, redoStack: this.redoStack },
5088
5154
  o,
5089
5155
  this.config.maxHistorySize ?? 100
@@ -5096,7 +5162,7 @@ class Zn extends x {
5096
5162
  * @returns The undone action, or null if nothing to undo
5097
5163
  */
5098
5164
  undo() {
5099
- const e = De({ undoStack: this.undoStack, redoStack: this.redoStack });
5165
+ const e = Ke({ undoStack: this.undoStack, redoStack: this.redoStack });
5100
5166
  if (e.action) {
5101
5167
  const t = this.rows;
5102
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();
@@ -5109,7 +5175,7 @@ class Zn extends x {
5109
5175
  * @returns The redone action, or null if nothing to redo
5110
5176
  */
5111
5177
  redo() {
5112
- const e = He({ undoStack: this.undoStack, redoStack: this.redoStack });
5178
+ const e = qe({ undoStack: this.undoStack, redoStack: this.redoStack });
5113
5179
  if (e.action) {
5114
5180
  const t = this.rows;
5115
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();
@@ -5120,19 +5186,19 @@ class Zn extends x {
5120
5186
  * Check if there are any actions that can be undone.
5121
5187
  */
5122
5188
  canUndo() {
5123
- return En({ undoStack: this.undoStack, redoStack: this.redoStack });
5189
+ return In({ undoStack: this.undoStack, redoStack: this.redoStack });
5124
5190
  }
5125
5191
  /**
5126
5192
  * Check if there are any actions that can be redone.
5127
5193
  */
5128
5194
  canRedo() {
5129
- return Sn({ undoStack: this.undoStack, redoStack: this.redoStack });
5195
+ return Fn({ undoStack: this.undoStack, redoStack: this.redoStack });
5130
5196
  }
5131
5197
  /**
5132
5198
  * Clear all undo/redo history.
5133
5199
  */
5134
5200
  clearHistory() {
5135
- const e = kn();
5201
+ const e = Mn();
5136
5202
  this.undoStack = e.undoStack, this.redoStack = e.redoStack;
5137
5203
  }
5138
5204
  /**
@@ -5149,16 +5215,24 @@ class Zn extends x {
5149
5215
  }
5150
5216
  // #endregion
5151
5217
  }
5152
- 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))}';
5153
- 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) {
5154
5220
  const e = s.meta ?? {};
5155
5221
  return e.lockPosition !== !0 && e.suppressMovable !== !0;
5156
5222
  }
5157
- class P extends x {
5223
+ class M extends x {
5224
+ /**
5225
+ * Plugin dependencies - VisibilityPlugin optionally uses ReorderPlugin for drag-drop reordering.
5226
+ *
5227
+ * When ReorderPlugin is present, columns in the visibility panel become draggable.
5228
+ */
5229
+ static dependencies = [
5230
+ { name: "reorder", required: !1, reason: "Enables drag-to-reorder columns in visibility panel" }
5231
+ ];
5158
5232
  name = "visibility";
5159
- version = "1.0.0";
5160
5233
  /** Tool panel ID for shell integration */
5161
5234
  static PANEL_ID = "columns";
5235
+ styles = Dn;
5162
5236
  get defaultConfig() {
5163
5237
  return {
5164
5238
  allowHideAll: !1
@@ -5171,6 +5245,12 @@ class P extends x {
5171
5245
  draggedField = null;
5172
5246
  draggedIndex = null;
5173
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
+ }
5174
5254
  // #endregion
5175
5255
  // #region Lifecycle
5176
5256
  detach() {
@@ -5183,7 +5263,7 @@ class P extends x {
5183
5263
  */
5184
5264
  getToolPanel() {
5185
5265
  return {
5186
- id: P.PANEL_ID,
5266
+ id: M.PANEL_ID,
5187
5267
  title: "Columns",
5188
5268
  icon: "☰",
5189
5269
  tooltip: "Column visibility",
@@ -5196,9 +5276,10 @@ class P extends x {
5196
5276
  // #region Public API
5197
5277
  /**
5198
5278
  * Show the visibility sidebar panel.
5279
+ * Opens the tool panel and ensures this section is expanded.
5199
5280
  */
5200
5281
  show() {
5201
- this.grid.openToolPanel(P.PANEL_ID);
5282
+ this.grid.openToolPanel(), this.grid.expandedToolPanelSections.includes(M.PANEL_ID) || this.grid.toggleToolPanelSection(M.PANEL_ID);
5202
5283
  }
5203
5284
  /**
5204
5285
  * Hide the visibility sidebar panel.
@@ -5207,10 +5288,10 @@ class P extends x {
5207
5288
  this.grid.closeToolPanel();
5208
5289
  }
5209
5290
  /**
5210
- * Toggle the visibility sidebar panel.
5291
+ * Toggle the visibility sidebar panel section.
5211
5292
  */
5212
5293
  toggle() {
5213
- this.grid.toggleToolPanel(P.PANEL_ID);
5294
+ this.grid.isToolPanelOpen || this.grid.openToolPanel(), this.grid.toggleToolPanelSection(M.PANEL_ID);
5214
5295
  }
5215
5296
  /**
5216
5297
  * Check if a specific column is visible.
@@ -5235,14 +5316,14 @@ class P extends x {
5235
5316
  * @returns Array of visible field names
5236
5317
  */
5237
5318
  getVisibleColumns() {
5238
- 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);
5239
5320
  }
5240
5321
  /**
5241
5322
  * Get list of all hidden column fields.
5242
5323
  * @returns Array of hidden field names
5243
5324
  */
5244
5325
  getHiddenColumns() {
5245
- 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);
5246
5327
  }
5247
5328
  /**
5248
5329
  * Show all columns.
@@ -5265,7 +5346,7 @@ class P extends x {
5265
5346
  * @param field - The field name of the column to show
5266
5347
  */
5267
5348
  showColumn(e) {
5268
- this.grid.setColumnVisible(e, !0);
5349
+ this.setColumnVisible(e, !0);
5269
5350
  }
5270
5351
  /**
5271
5352
  * Hide a specific column.
@@ -5273,7 +5354,7 @@ class P extends x {
5273
5354
  * @param field - The field name of the column to hide
5274
5355
  */
5275
5356
  hideColumn(e) {
5276
- this.grid.setColumnVisible(e, !1);
5357
+ this.setColumnVisible(e, !1);
5277
5358
  }
5278
5359
  /**
5279
5360
  * Get all columns with their visibility status.
@@ -5285,10 +5366,10 @@ class P extends x {
5285
5366
  }
5286
5367
  /**
5287
5368
  * Check if the sidebar panel is currently open.
5288
- * @returns True if the panel is open
5369
+ * @returns True if the panel section is expanded
5289
5370
  */
5290
5371
  isPanelVisible() {
5291
- return this.grid.activeToolPanel === P.PANEL_ID;
5372
+ return this.grid.isToolPanelOpen && this.grid.expandedToolPanelSections.includes(M.PANEL_ID);
5292
5373
  }
5293
5374
  // #endregion
5294
5375
  // #region Private Methods
@@ -5297,15 +5378,15 @@ class P extends x {
5297
5378
  * Returns a cleanup function.
5298
5379
  */
5299
5380
  renderPanelContent(e) {
5300
- const t = this.grid, n = document.createElement("div");
5301
- n.className = "tbw-visibility-content";
5302
- const i = document.createElement("div");
5303
- i.className = "tbw-visibility-list", n.appendChild(i);
5304
- const o = document.createElement("button");
5305
- return o.className = "tbw-visibility-show-all", o.textContent = "Show All", o.addEventListener("click", () => {
5306
- t.showAllColumns(), this.rebuildToggles(i);
5307
- }), n.appendChild(o), this.columnListElement = i, this.rebuildToggles(i), e.appendChild(n), () => {
5308
- 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();
5309
5390
  };
5310
5391
  }
5311
5392
  /**
@@ -5320,24 +5401,24 @@ class P extends x {
5320
5401
  * When a reorder plugin is present, adds drag handles for reordering.
5321
5402
  */
5322
5403
  rebuildToggles(e) {
5323
- const t = this.grid, n = this.hasReorderPlugin();
5404
+ const t = this.hasReorderPlugin();
5324
5405
  e.innerHTML = "";
5325
- const i = t.getAllColumns();
5326
- for (let o = 0; o < i.length; o++) {
5327
- const r = i[o], l = r.header || r.field, a = document.createElement("div");
5328
- 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));
5329
- const d = document.createElement("label");
5330
- d.className = "tbw-visibility-label";
5331
- const c = document.createElement("input");
5332
- c.type = "checkbox", c.checked = r.visible, c.disabled = r.lockVisible ?? !1, c.addEventListener("change", () => {
5333
- 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);
5334
5415
  });
5335
- const h = document.createElement("span");
5336
- 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)) {
5337
5418
  const u = document.createElement("span");
5338
- 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);
5339
5420
  }
5340
- a.appendChild(d), e.appendChild(a);
5421
+ l.appendChild(a), e.appendChild(l);
5341
5422
  }
5342
5423
  }
5343
5424
  /**
@@ -5348,9 +5429,7 @@ class P extends x {
5348
5429
  e.addEventListener("dragstart", (o) => {
5349
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");
5350
5431
  }), e.addEventListener("dragend", () => {
5351
- this.isDragging = !1, this.draggedField = null, this.draggedIndex = null, this.dropIndex = null, i.querySelectorAll(".tbw-visibility-row").forEach((o) => {
5352
- o.classList.remove("dragging", "drop-target", "drop-before", "drop-after");
5353
- });
5432
+ this.isDragging = !1, this.draggedField = null, this.draggedIndex = null, this.dropIndex = null, this.clearDragClasses(i);
5354
5433
  }), e.addEventListener("dragover", (o) => {
5355
5434
  if (o.preventDefault(), !this.isDragging || this.draggedField === t) return;
5356
5435
  const r = e.getBoundingClientRect(), l = r.top + r.height / 2;
@@ -5378,57 +5457,55 @@ class P extends x {
5378
5457
  });
5379
5458
  }
5380
5459
  // #endregion
5381
- // #region Styles
5382
- styles = _n;
5383
- // #endregion
5384
5460
  }
5385
5461
  export {
5386
5462
  x as BaseGridPlugin,
5387
- Tn as ClipboardPlugin,
5388
- In as ColumnVirtualizationPlugin,
5389
- Fn as ContextMenuPlugin,
5390
- Jn as DEFAULT_ANIMATION_CONFIG,
5391
- ze as DEFAULT_GRID_ICONS,
5392
- Qn as DGEvents,
5393
- ei as DataGridElement,
5394
- Pn as EditingPlugin,
5395
- 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,
5396
5472
  U as FOCUSABLE_EDITOR_SELECTOR,
5397
- _ as FilteringPlugin,
5398
- ti as FitModeEnum,
5399
- ni as GridCSSVars,
5400
- ii as GridClasses,
5401
- oi as GridDataAttrs,
5402
- ri as GridElement,
5403
- si as GridSelectors,
5404
- Kn as GroupingColumnsPlugin,
5405
- Nn as GroupingRowsPlugin,
5406
- Dn as MasterDetailPlugin,
5407
- Hn as MultiSortPlugin,
5408
- H as PLUGIN_QUERIES,
5409
- On as PinnedColumnsPlugin,
5410
- Gn as PinnedRowsPlugin,
5411
- M as PivotPlugin,
5412
- li as PluginEvents,
5413
- ai as PluginManager,
5414
- di as RenderPhase,
5415
- Vn as ReorderPlugin,
5416
- Bn as SelectionPlugin,
5417
- jn as ServerSidePlugin,
5418
- Un as TreePlugin,
5419
- Zn as UndoRedoPlugin,
5420
- P as VisibilityPlugin,
5421
- ci as builtInSort,
5422
- it as clearEditingState,
5423
- Wn as computeSelectionDiff,
5424
- xn as countNodes,
5425
- ui as defaultComparator,
5426
- tt as defaultEditorFor,
5427
- Ne as detectTreeStructure,
5428
- yn as getMaxDepth,
5429
- zn as handleRowClick,
5430
- Mn as hasEditingCells,
5431
- vn as inferChildrenField,
5432
- $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
5433
5510
  };
5434
5511
  //# sourceMappingURL=all.js.map