@toolbox-web/grid 0.0.3 → 0.0.5

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 (63) hide show
  1. package/all.d.ts +50 -6
  2. package/all.js +101 -98
  3. package/all.js.map +1 -1
  4. package/index.d.ts +54 -0
  5. package/index.js +793 -692
  6. package/index.js.map +1 -1
  7. package/lib/plugins/clipboard/index.js +55 -35
  8. package/lib/plugins/clipboard/index.js.map +1 -1
  9. package/lib/plugins/column-virtualization/index.js +49 -29
  10. package/lib/plugins/column-virtualization/index.js.map +1 -1
  11. package/lib/plugins/context-menu/index.js +35 -15
  12. package/lib/plugins/context-menu/index.js.map +1 -1
  13. package/lib/plugins/export/index.js +52 -32
  14. package/lib/plugins/export/index.js.map +1 -1
  15. package/lib/plugins/filtering/index.js +116 -99
  16. package/lib/plugins/filtering/index.js.map +1 -1
  17. package/lib/plugins/grouping-columns/index.js +42 -22
  18. package/lib/plugins/grouping-columns/index.js.map +1 -1
  19. package/lib/plugins/grouping-rows/index.js +20 -0
  20. package/lib/plugins/grouping-rows/index.js.map +1 -1
  21. package/lib/plugins/master-detail/index.js +50 -27
  22. package/lib/plugins/master-detail/index.js.map +1 -1
  23. package/lib/plugins/multi-sort/index.js +25 -5
  24. package/lib/plugins/multi-sort/index.js.map +1 -1
  25. package/lib/plugins/pinned-columns/index.js +20 -0
  26. package/lib/plugins/pinned-columns/index.js.map +1 -1
  27. package/lib/plugins/pinned-rows/index.js +20 -0
  28. package/lib/plugins/pinned-rows/index.js.map +1 -1
  29. package/lib/plugins/pivot/index.js +20 -0
  30. package/lib/plugins/pivot/index.js.map +1 -1
  31. package/lib/plugins/reorder/index.js +56 -33
  32. package/lib/plugins/reorder/index.js.map +1 -1
  33. package/lib/plugins/selection/index.js +138 -100
  34. package/lib/plugins/selection/index.js.map +1 -1
  35. package/lib/plugins/server-side/index.js +20 -0
  36. package/lib/plugins/server-side/index.js.map +1 -1
  37. package/lib/plugins/tree/index.js +76 -53
  38. package/lib/plugins/tree/index.js.map +1 -1
  39. package/lib/plugins/undo-redo/index.js +20 -0
  40. package/lib/plugins/undo-redo/index.js.map +1 -1
  41. package/lib/plugins/visibility/index.js +20 -0
  42. package/lib/plugins/visibility/index.js.map +1 -1
  43. package/package.json +4 -1
  44. package/themes/dg-theme-contrast.css +43 -43
  45. package/themes/dg-theme-large.css +54 -54
  46. package/themes/dg-theme-standard.css +19 -19
  47. package/themes/dg-theme-vibrant.css +16 -16
  48. package/umd/grid.all.umd.js +24 -24
  49. package/umd/grid.all.umd.js.map +1 -1
  50. package/umd/grid.umd.js +14 -14
  51. package/umd/grid.umd.js.map +1 -1
  52. package/umd/plugins/filtering.umd.js +3 -3
  53. package/umd/plugins/filtering.umd.js.map +1 -1
  54. package/umd/plugins/master-detail.umd.js +2 -2
  55. package/umd/plugins/master-detail.umd.js.map +1 -1
  56. package/umd/plugins/multi-sort.umd.js.map +1 -1
  57. package/umd/plugins/reorder.umd.js +1 -1
  58. package/umd/plugins/reorder.umd.js.map +1 -1
  59. package/umd/plugins/selection.umd.js +2 -2
  60. package/umd/plugins/selection.umd.js.map +1 -1
  61. package/umd/plugins/tree.umd.js +2 -2
  62. package/umd/plugins/tree.umd.js.map +1 -1
  63. package/umd/plugins/visibility.umd.js.map +1 -1
package/all.d.ts CHANGED
@@ -171,6 +171,24 @@ export declare abstract class BaseGridPlugin<TConfig = unknown> {
171
171
  * Get the shadow root of the grid.
172
172
  */
173
173
  protected get shadowRoot(): ShadowRoot | null;
174
+ /**
175
+ * Get the disconnect signal for event listener cleanup.
176
+ * This signal is aborted when the grid disconnects from the DOM.
177
+ * Use this when adding event listeners that should be cleaned up automatically.
178
+ *
179
+ * Best for:
180
+ * - Document/window-level listeners added in attach()
181
+ * - Listeners on the grid element itself
182
+ * - Any listener that should persist across renders
183
+ *
184
+ * Not needed for:
185
+ * - Listeners on elements created in afterRender() (removed with element)
186
+ *
187
+ * @example
188
+ * element.addEventListener('click', handler, { signal: this.disconnectSignal });
189
+ * document.addEventListener('keydown', handler, { signal: this.disconnectSignal });
190
+ */
191
+ protected get disconnectSignal(): AbortSignal;
174
192
  /**
175
193
  * Log a warning message.
176
194
  */
@@ -252,6 +270,22 @@ export declare abstract class BaseGridPlugin<TConfig = unknown> {
252
270
  * ```
253
271
  */
254
272
  afterRender?(): void;
273
+ /**
274
+ * Called after scroll-triggered row rendering completes.
275
+ * This is a lightweight hook for applying visual state to recycled DOM elements.
276
+ * Use this instead of afterRender when you need to reapply styling during scroll.
277
+ *
278
+ * Performance note: This is called frequently during scroll. Keep implementation fast.
279
+ *
280
+ * @example
281
+ * ```ts
282
+ * onScrollRender(): void {
283
+ * // Reapply selection state to visible cells
284
+ * this.applySelectionToVisibleCells();
285
+ * }
286
+ * ```
287
+ */
288
+ onScrollRender?(): void;
255
289
  /**
256
290
  * Render a custom row, bypassing the default row rendering.
257
291
  * Use this for special row types like group headers, detail rows, or footers.
@@ -1155,6 +1189,14 @@ declare class DataGridElement<T = any> extends HTMLElement implements InternalGr
1155
1189
  get editOn(): string | undefined;
1156
1190
  set editOn(value: string | undefined);
1157
1191
  get effectiveConfig(): GridConfig<T>;
1192
+ /**
1193
+ * Get the disconnect signal for event listener cleanup.
1194
+ * This signal is aborted when the grid disconnects from the DOM.
1195
+ * Plugins and internal code can use this for automatic listener cleanup.
1196
+ * @example
1197
+ * element.addEventListener('click', handler, { signal: this.grid.disconnectSignal });
1198
+ */
1199
+ get disconnectSignal(): AbortSignal;
1158
1200
  constructor();
1159
1201
  /**
1160
1202
  * Get a plugin instance by its class.
@@ -1569,7 +1611,7 @@ export declare class FilteringPlugin extends BaseGridPlugin<FilterConfig> {
1569
1611
  private panelElement;
1570
1612
  private searchText;
1571
1613
  private excludedValues;
1572
- private documentClickHandler;
1614
+ private panelAbortController;
1573
1615
  private globalStylesInjected;
1574
1616
  private static readonly LIST_ITEM_HEIGHT;
1575
1617
  private static readonly LIST_OVERSCAN;
@@ -1636,10 +1678,6 @@ export declare class FilteringPlugin extends BaseGridPlugin<FilterConfig> {
1636
1678
  * Close the filter panel
1637
1679
  */
1638
1680
  private closeFilterPanel;
1639
- /**
1640
- * Remove the document click handler
1641
- */
1642
- private removeDocumentClickHandler;
1643
1681
  /**
1644
1682
  * Position the panel below the button
1645
1683
  */
@@ -1911,6 +1949,8 @@ declare interface GridElement_2 {
1911
1949
  rows: any[];
1912
1950
  columns: ColumnConfig[];
1913
1951
  gridConfig: any;
1952
+ /** AbortSignal that is aborted when the grid disconnects from the DOM */
1953
+ disconnectSignal: AbortSignal;
1914
1954
  requestRender(): void;
1915
1955
  requestAfterRender(): void;
1916
1956
  forceLayout(): Promise<void>;
@@ -2806,7 +2846,6 @@ export declare class ReorderPlugin extends BaseGridPlugin<ReorderConfig> {
2806
2846
  private draggedField;
2807
2847
  private draggedIndex;
2808
2848
  private dropIndex;
2809
- private boundReorderRequestHandler;
2810
2849
  attach(grid: GridElement_2): void;
2811
2850
  detach(): void;
2812
2851
  afterRender(): void;
@@ -2955,6 +2994,11 @@ export declare class SelectionPlugin extends BaseGridPlugin<SelectionConfig> {
2955
2994
  onCellMouseMove(event: CellMouseEvent): boolean | void;
2956
2995
  onCellMouseUp(_event: CellMouseEvent): boolean | void;
2957
2996
  afterRender(): void;
2997
+ /**
2998
+ * Called after scroll-triggered row rendering.
2999
+ * Reapplies selection classes to recycled DOM elements.
3000
+ */
3001
+ onScrollRender(): void;
2958
3002
  /**
2959
3003
  * Get the selected cell (cell mode only).
2960
3004
  */
package/all.js CHANGED
@@ -1,5 +1,5 @@
1
- import { BaseGridPlugin as C, runAggregator as X, getAggregator as xe } from "./index.js";
2
- import { DGEvents as Pt, DataGridElement as Dt, FitModeEnum as Bt, GridCSSVars as Ht, GridClasses as Ot, GridDataAttrs as Wt, DataGridElement as Kt, GridSelectors as Vt, PluginEvents as Gt, SelectionPlugin as zt, TreePlugin as $t } from "./index.js";
1
+ import { BaseGridPlugin as y, runAggregator as X, getAggregator as xe } from "./index.js";
2
+ import { DGEvents as Pt, DataGridElement as Dt, FitModeEnum as Bt, GridCSSVars as Ot, GridClasses as Ht, GridDataAttrs as Wt, DataGridElement as Kt, GridSelectors as Vt, PluginEvents as Gt, SelectionPlugin as zt, TreePlugin as $t } from "./index.js";
3
3
  function ve(i, e, t, n) {
4
4
  if (n.processCell)
5
5
  return n.processCell(i, e, t);
@@ -60,7 +60,7 @@ async function Q() {
60
60
  return "";
61
61
  }
62
62
  }
63
- class vt extends C {
63
+ class vt extends y {
64
64
  name = "clipboard";
65
65
  version = "1.0.0";
66
66
  get defaultConfig() {
@@ -277,11 +277,11 @@ function te(i) {
277
277
  function ne(i) {
278
278
  return i.reduce((e, t) => e + G(t.width), 0);
279
279
  }
280
- function Ce(i, e, t, n, o) {
280
+ function ye(i, e, t, n, o) {
281
281
  const r = t.length;
282
282
  if (r === 0)
283
283
  return { startCol: 0, endCol: 0, visibleColumns: [] };
284
- let s = ye(i, t, n);
284
+ let s = Ce(i, t, n);
285
285
  s = Math.max(0, s - o);
286
286
  const l = i + e;
287
287
  let a = s;
@@ -298,7 +298,7 @@ function Ce(i, e, t, n, o) {
298
298
  c.push(d);
299
299
  return { startCol: s, endCol: a, visibleColumns: c };
300
300
  }
301
- function ye(i, e, t) {
301
+ function Ce(i, e, t) {
302
302
  let n = 0, o = e.length - 1;
303
303
  for (; n < o; ) {
304
304
  const r = Math.floor((n + o) / 2);
@@ -309,7 +309,7 @@ function ye(i, e, t) {
309
309
  function Se(i, e, t) {
310
310
  return t ? i > e : !1;
311
311
  }
312
- class Ct extends C {
312
+ class yt extends y {
313
313
  name = "columnVirtualization";
314
314
  version = "1.0.0";
315
315
  get defaultConfig() {
@@ -342,7 +342,7 @@ class Ct extends C {
342
342
  const t = this.config.enabled && Se(e.length, this.config.threshold ?? 30, this.config.autoEnable ?? !0);
343
343
  if (this.isVirtualized = t ?? !1, this.columnWidths = ee(e), this.columnOffsets = te(e), this.totalWidth = ne(e), !t)
344
344
  return this.startCol = 0, this.endCol = e.length - 1, [...e];
345
- const n = this.grid.clientWidth || 800, o = Ce(
345
+ const n = this.grid.clientWidth || 800, o = ye(
346
346
  this.scrollLeft,
347
347
  n,
348
348
  this.columnOffsets,
@@ -520,7 +520,7 @@ const ke = `
520
520
  }
521
521
  }
522
522
  ];
523
- class yt extends C {
523
+ class Ct extends y {
524
524
  name = "contextMenu";
525
525
  version = "1.0.0";
526
526
  get defaultConfig() {
@@ -707,7 +707,7 @@ function Ie(i, e) {
707
707
  });
708
708
  z(n, t);
709
709
  }
710
- class St extends C {
710
+ class St extends y {
711
711
  name = "export";
712
712
  version = "1.0.0";
713
713
  get defaultConfig() {
@@ -1046,7 +1046,7 @@ const Ne = `
1046
1046
  background: var(--tbw-filter-hover, var(--tbw-color-row-hover, light-dark(#f0f6ff, #1c1c1c)));
1047
1047
  }
1048
1048
  `;
1049
- class E extends C {
1049
+ class E extends y {
1050
1050
  name = "filtering";
1051
1051
  version = "1.0.0";
1052
1052
  get defaultConfig() {
@@ -1066,7 +1066,8 @@ class E extends C {
1066
1066
  panelElement = null;
1067
1067
  searchText = /* @__PURE__ */ new Map();
1068
1068
  excludedValues = /* @__PURE__ */ new Map();
1069
- documentClickHandler = null;
1069
+ panelAbortController = null;
1070
+ // For panel-scoped listeners
1070
1071
  globalStylesInjected = !1;
1071
1072
  // Virtualization constants for filter value list
1072
1073
  static LIST_ITEM_HEIGHT = 28;
@@ -1078,7 +1079,7 @@ class E extends C {
1078
1079
  super.attach(e), this.injectGlobalStyles();
1079
1080
  }
1080
1081
  detach() {
1081
- this.filters.clear(), this.cachedResult = null, this.cacheKey = null, this.openPanelField = null, this.panelElement && (this.panelElement.remove(), this.panelElement = null), this.searchText.clear(), this.excludedValues.clear(), this.removeDocumentClickHandler();
1082
+ this.filters.clear(), this.cachedResult = null, this.cacheKey = null, this.openPanelField = null, this.panelElement && (this.panelElement.remove(), this.panelElement = null), this.searchText.clear(), this.excludedValues.clear(), this.panelAbortController?.abort(), this.panelAbortController = null;
1082
1083
  }
1083
1084
  // ===== Hooks =====
1084
1085
  processRows(e) {
@@ -1225,11 +1226,11 @@ class E extends C {
1225
1226
  uniqueValues: r,
1226
1227
  excludedValues: s,
1227
1228
  searchText: l,
1228
- applySetFilter: (u) => {
1229
- this.applySetFilter(e, u), this.closeFilterPanel();
1229
+ applySetFilter: (d) => {
1230
+ this.applySetFilter(e, d), this.closeFilterPanel();
1230
1231
  },
1231
- applyTextFilter: (u, h, f) => {
1232
- this.applyTextFilter(e, u, h, f), this.closeFilterPanel();
1232
+ applyTextFilter: (d, u, h) => {
1233
+ this.applyTextFilter(e, d, u, h), this.closeFilterPanel();
1233
1234
  },
1234
1235
  clearFilter: () => {
1235
1236
  this.clearFieldFilter(e), this.closeFilterPanel();
@@ -1237,25 +1238,21 @@ class E extends C {
1237
1238
  closePanel: () => this.closeFilterPanel()
1238
1239
  };
1239
1240
  let c = !1;
1240
- this.config.filterPanelRenderer && (this.config.filterPanelRenderer(o, a), c = o.children.length > 0), c || this.renderDefaultFilterPanel(o, a, r, s), document.body.appendChild(o), this.positionPanel(o, n);
1241
- const d = (u) => {
1242
- !o.contains(u.target) && u.target !== n && this.closeFilterPanel();
1243
- };
1244
- this.documentClickHandler = d, setTimeout(() => {
1245
- document.addEventListener("click", d);
1241
+ this.config.filterPanelRenderer && (this.config.filterPanelRenderer(o, a), c = o.children.length > 0), c || this.renderDefaultFilterPanel(o, a, r, s), document.body.appendChild(o), this.positionPanel(o, n), this.panelAbortController = new AbortController(), setTimeout(() => {
1242
+ document.addEventListener(
1243
+ "click",
1244
+ (d) => {
1245
+ !o.contains(d.target) && d.target !== n && this.closeFilterPanel();
1246
+ },
1247
+ { signal: this.panelAbortController?.signal }
1248
+ );
1246
1249
  }, 0);
1247
1250
  }
1248
1251
  /**
1249
1252
  * Close the filter panel
1250
1253
  */
1251
1254
  closeFilterPanel() {
1252
- this.panelElement && (this.panelElement.remove(), this.panelElement = null), this.openPanelField = null, this.removeDocumentClickHandler();
1253
- }
1254
- /**
1255
- * Remove the document click handler
1256
- */
1257
- removeDocumentClickHandler() {
1258
- this.documentClickHandler && (document.removeEventListener("click", this.documentClickHandler), this.documentClickHandler = null);
1255
+ this.panelElement && (this.panelElement.remove(), this.panelElement = null), this.openPanelField = null, this.panelAbortController?.abort(), this.panelAbortController = null;
1259
1256
  }
1260
1257
  /**
1261
1258
  * Position the panel below the button
@@ -1284,8 +1281,8 @@ class E extends C {
1284
1281
  const u = document.createElement("span");
1285
1282
  u.textContent = "Select All", c.appendChild(d), c.appendChild(u), a.appendChild(c);
1286
1283
  const h = () => {
1287
- const p = [...b.values()], v = p.every((x) => x), y = p.every((x) => !x);
1288
- d.checked = v, d.indeterminate = !v && !y;
1284
+ const p = [...b.values()], v = p.every((x) => x), C = p.every((x) => !x);
1285
+ d.checked = v, d.indeterminate = !v && !C;
1289
1286
  };
1290
1287
  d.addEventListener("change", () => {
1291
1288
  const p = d.checked;
@@ -1306,16 +1303,16 @@ class E extends C {
1306
1303
  }), h();
1307
1304
  let S = [];
1308
1305
  const R = (p, v) => {
1309
- const y = p == null ? "(Blank)" : String(p), x = p == null ? "__null__" : String(p), w = document.createElement("label");
1306
+ const C = p == null ? "(Blank)" : String(p), x = p == null ? "__null__" : String(p), w = document.createElement("label");
1310
1307
  w.className = "tbw-filter-value-item", w.style.position = "absolute", w.style.top = `${v * E.LIST_ITEM_HEIGHT}px`, w.style.left = "0", w.style.right = "0", w.style.height = `${E.LIST_ITEM_HEIGHT}px`, w.style.boxSizing = "border-box";
1311
1308
  const k = document.createElement("input");
1312
1309
  k.type = "checkbox", k.className = "tbw-filter-checkbox", k.checked = b.get(x) ?? !0, k.dataset.value = x, k.addEventListener("change", () => {
1313
1310
  b.set(x, k.checked), h();
1314
1311
  });
1315
1312
  const Y = document.createElement("span");
1316
- return Y.textContent = y, w.appendChild(k), w.appendChild(Y), w;
1313
+ return Y.textContent = C, w.appendChild(k), w.appendChild(Y), w;
1317
1314
  }, q = () => {
1318
- const p = S.length, v = f.clientHeight, y = f.scrollTop;
1315
+ const p = S.length, v = f.clientHeight, C = f.scrollTop;
1319
1316
  if (g.style.height = `${p * E.LIST_ITEM_HEIGHT}px`, Le(p, E.LIST_BYPASS_THRESHOLD / 3)) {
1320
1317
  m.innerHTML = "", m.style.transform = "translateY(0px)", S.forEach((w, k) => {
1321
1318
  m.appendChild(R(w, k));
@@ -1325,7 +1322,7 @@ class E extends C {
1325
1322
  const x = Te({
1326
1323
  totalRows: p,
1327
1324
  viewportHeight: v,
1328
- scrollTop: y,
1325
+ scrollTop: C,
1329
1326
  rowHeight: E.LIST_ITEM_HEIGHT,
1330
1327
  overscan: E.LIST_OVERSCAN
1331
1328
  });
@@ -1334,13 +1331,13 @@ class E extends C {
1334
1331
  m.appendChild(R(S[w], w - x.start));
1335
1332
  }, j = (p) => {
1336
1333
  const v = p.toLowerCase();
1337
- if (S = n.filter((y) => {
1338
- const x = y == null ? "(Blank)" : String(y);
1334
+ if (S = n.filter((C) => {
1335
+ const x = C == null ? "(Blank)" : String(C);
1339
1336
  return !p || x.toLowerCase().includes(v);
1340
1337
  }), S.length === 0) {
1341
1338
  g.style.height = "0px", m.innerHTML = "";
1342
- const y = document.createElement("div");
1343
- y.className = "tbw-filter-no-match", y.textContent = "No matching values", m.appendChild(y);
1339
+ const C = document.createElement("div");
1340
+ C.className = "tbw-filter-no-match", C.textContent = "No matching values", m.appendChild(C);
1344
1341
  return;
1345
1342
  }
1346
1343
  q();
@@ -1363,8 +1360,8 @@ class E extends C {
1363
1360
  const T = document.createElement("button");
1364
1361
  T.className = "tbw-filter-apply-btn", T.textContent = "Apply", T.addEventListener("click", () => {
1365
1362
  const p = [];
1366
- for (const [v, y] of b)
1367
- if (!y)
1363
+ for (const [v, C] of b)
1364
+ if (!C)
1368
1365
  if (v === "__null__")
1369
1366
  p.push(null);
1370
1367
  else {
@@ -1536,10 +1533,10 @@ function Be(i, e) {
1536
1533
  }
1537
1534
  return t;
1538
1535
  }
1539
- function He(i) {
1536
+ function Oe(i) {
1540
1537
  return i.some((e) => e.group != null);
1541
1538
  }
1542
- class Rt extends C {
1539
+ class Rt extends y {
1543
1540
  name = "groupingColumns";
1544
1541
  version = "1.0.0";
1545
1542
  get defaultConfig() {
@@ -1561,7 +1558,7 @@ class Rt extends C {
1561
1558
  */
1562
1559
  static detect(e, t) {
1563
1560
  const n = t?.columns;
1564
- return Array.isArray(n) ? He(n) : !1;
1561
+ return Array.isArray(n) ? Oe(n) : !1;
1565
1562
  }
1566
1563
  // ===== Hooks =====
1567
1564
  processColumns(e) {
@@ -1648,7 +1645,7 @@ class Rt extends C {
1648
1645
  }
1649
1646
  `;
1650
1647
  }
1651
- function Oe({ rows: i, config: e, expanded: t }) {
1648
+ function He({ rows: i, config: e, expanded: t }) {
1652
1649
  const n = e.groupOn;
1653
1650
  if (!e.enabled || typeof n != "function")
1654
1651
  return [];
@@ -1697,7 +1694,7 @@ function Ve() {
1697
1694
  function Ge(i) {
1698
1695
  return i.kind !== "group" ? 0 : i.rows.length;
1699
1696
  }
1700
- class kt extends C {
1697
+ class kt extends y {
1701
1698
  name = "groupingRows";
1702
1699
  version = "1.0.0";
1703
1700
  get defaultConfig() {
@@ -1729,7 +1726,7 @@ class kt extends C {
1729
1726
  const t = this.config;
1730
1727
  if (!t.enabled || typeof t.groupOn != "function")
1731
1728
  return this.isActive = !1, this.flattenedRows = [], [...e];
1732
- const n = Oe({
1729
+ const n = He({
1733
1730
  rows: e,
1734
1731
  config: t,
1735
1732
  expanded: this.expandedKeys
@@ -1976,7 +1973,7 @@ class kt extends C {
1976
1973
  [data-group-depth="4"] .group-label { padding-left: 80px; }
1977
1974
  `;
1978
1975
  }
1979
- function H(i, e) {
1976
+ function O(i, e) {
1980
1977
  const t = new Set(i);
1981
1978
  return t.has(e) ? t.delete(e) : t.add(e), t;
1982
1979
  }
@@ -1999,7 +1996,7 @@ function Ue(i, e, t, n) {
1999
1996
  const s = t(i, e);
2000
1997
  return typeof s == "string" ? r.innerHTML = s : s instanceof HTMLElement && r.appendChild(s), o.appendChild(r), o;
2001
1998
  }
2002
- class Et extends C {
1999
+ class Et extends y {
2003
2000
  name = "masterDetail";
2004
2001
  version = "1.0.0";
2005
2002
  get defaultConfig() {
@@ -2025,33 +2022,36 @@ class Et extends C {
2025
2022
  const t = [...e];
2026
2023
  if (t.length > 0) {
2027
2024
  const n = { ...t[0] }, o = n.viewRenderer;
2028
- n.viewRenderer = (r) => {
2029
- const { value: s, row: l } = r, a = this.expandedRows.has(l), c = document.createElement("span");
2030
- c.className = "master-detail-cell-wrapper";
2031
- const d = document.createElement("span");
2032
- d.className = "master-detail-toggle", d.textContent = a ? "▼" : "▶", d.setAttribute("aria-expanded", String(a)), d.setAttribute("aria-label", a ? "Collapse details" : "Expand details"), d.addEventListener("click", (h) => {
2033
- h.stopPropagation();
2034
- const f = this.rows.indexOf(l);
2035
- this.expandedRows = H(this.expandedRows, l), this.emit("detail-expand", {
2036
- rowIndex: f,
2037
- row: l,
2038
- expanded: this.expandedRows.has(l)
2039
- }), this.requestRender();
2040
- }), c.appendChild(d);
2025
+ if (o?.__masterDetailWrapped)
2026
+ return t;
2027
+ const r = (s) => {
2028
+ const { value: l, row: a } = s, c = this.expandedRows.has(a), d = document.createElement("span");
2029
+ d.className = "master-detail-cell-wrapper";
2041
2030
  const u = document.createElement("span");
2031
+ u.className = "master-detail-toggle", u.textContent = c ? "▼" : "▶", u.setAttribute("aria-expanded", String(c)), u.setAttribute("aria-label", c ? "Collapse details" : "Expand details"), u.addEventListener("click", (f) => {
2032
+ f.stopPropagation();
2033
+ const g = this.rows.indexOf(a);
2034
+ this.expandedRows = O(this.expandedRows, a), this.emit("detail-expand", {
2035
+ rowIndex: g,
2036
+ row: a,
2037
+ expanded: this.expandedRows.has(a)
2038
+ }), this.requestRender();
2039
+ }), d.appendChild(u);
2040
+ const h = document.createElement("span");
2042
2041
  if (o) {
2043
- const h = o(r);
2044
- h instanceof Node ? u.appendChild(h) : u.textContent = String(h ?? s ?? "");
2042
+ const f = o(s);
2043
+ f instanceof Node ? h.appendChild(f) : h.textContent = String(f ?? l ?? "");
2045
2044
  } else
2046
- u.textContent = String(s ?? "");
2047
- return c.appendChild(u), c;
2048
- }, t[0] = n;
2045
+ h.textContent = String(l ?? "");
2046
+ return d.appendChild(h), d;
2047
+ };
2048
+ r.__masterDetailWrapped = !0, n.viewRenderer = r, t[0] = n;
2049
2049
  }
2050
2050
  return t;
2051
2051
  }
2052
2052
  onRowClick(e) {
2053
2053
  if (!(!this.config.expandOnRowClick || !this.config.detailRenderer))
2054
- return this.expandedRows = H(this.expandedRows, e.row), this.emit("detail-expand", {
2054
+ return this.expandedRows = O(this.expandedRows, e.row), this.emit("detail-expand", {
2055
2055
  rowIndex: e.rowIndex,
2056
2056
  row: e.row,
2057
2057
  expanded: this.expandedRows.has(e.row)
@@ -2095,7 +2095,7 @@ class Et extends C {
2095
2095
  */
2096
2096
  toggle(e) {
2097
2097
  const t = this.rows[e];
2098
- t && (this.expandedRows = H(this.expandedRows, t), this.requestRender());
2098
+ t && (this.expandedRows = O(this.expandedRows, t), this.requestRender());
2099
2099
  }
2100
2100
  /**
2101
2101
  * Check if the detail row at the given index is expanded.
@@ -2193,7 +2193,7 @@ function le(i, e) {
2193
2193
  function ae(i, e) {
2194
2194
  return i.find((t) => t.field === e)?.direction;
2195
2195
  }
2196
- class At extends C {
2196
+ class At extends y {
2197
2197
  name = "multiSort";
2198
2198
  version = "1.0.0";
2199
2199
  get defaultConfig() {
@@ -2335,7 +2335,7 @@ function Qe(i) {
2335
2335
  function Ze(i) {
2336
2336
  return i.filter((e) => e.sticky === "right");
2337
2337
  }
2338
- function O(i) {
2338
+ function H(i) {
2339
2339
  return i.some((e) => e.sticky === "left" || e.sticky === "right");
2340
2340
  }
2341
2341
  function de(i, e) {
@@ -2371,7 +2371,7 @@ function ce(i) {
2371
2371
  n.classList.remove("sticky-left", "sticky-right"), n.style.left = "", n.style.right = "";
2372
2372
  });
2373
2373
  }
2374
- class _t extends C {
2374
+ class _t extends y {
2375
2375
  name = "pinnedColumns";
2376
2376
  version = "1.0.0";
2377
2377
  get defaultConfig() {
@@ -2393,17 +2393,17 @@ class _t extends C {
2393
2393
  */
2394
2394
  static detect(e, t) {
2395
2395
  const n = t?.columns;
2396
- return Array.isArray(n) ? O(n) : !1;
2396
+ return Array.isArray(n) ? H(n) : !1;
2397
2397
  }
2398
2398
  // ===== Hooks =====
2399
2399
  processColumns(e) {
2400
- return this.config.enabled ? (this.isApplied = O([...e]), [...e]) : (this.isApplied = !1, [...e]);
2400
+ return this.config.enabled ? (this.isApplied = H([...e]), [...e]) : (this.isApplied = !1, [...e]);
2401
2401
  }
2402
2402
  afterRender() {
2403
2403
  if (!this.config.enabled || !this.isApplied)
2404
2404
  return;
2405
2405
  const e = this.grid, t = [...this.columns];
2406
- if (!O(t)) {
2406
+ if (!H(t)) {
2407
2407
  ce(e), this.isApplied = !1;
2408
2408
  return;
2409
2409
  }
@@ -2522,7 +2522,7 @@ function fe(i, e, t, n, o) {
2522
2522
  grid: t
2523
2523
  };
2524
2524
  }
2525
- class It extends C {
2525
+ class It extends y {
2526
2526
  name = "pinnedRows";
2527
2527
  version = "1.0.0";
2528
2528
  get defaultConfig() {
@@ -2829,7 +2829,7 @@ function at(i) {
2829
2829
  t(n);
2830
2830
  return e;
2831
2831
  }
2832
- class Tt extends C {
2832
+ class Tt extends y {
2833
2833
  name = "pivot";
2834
2834
  version = "1.0.0";
2835
2835
  get defaultConfig() {
@@ -2950,15 +2950,18 @@ class Tt extends C {
2950
2950
  `;
2951
2951
  }
2952
2952
  function dt(i) {
2953
- const e = i.meta ?? {}, t = e.sticky;
2954
- return t === "left" || t === "right" ? !1 : e.lockPosition !== !0 && e.suppressMovable !== !0;
2953
+ const e = i.sticky;
2954
+ if (e === "left" || e === "right")
2955
+ return !1;
2956
+ const t = i.meta ?? {}, n = t.sticky;
2957
+ return n === "left" || n === "right" ? !1 : t.lockPosition !== !0 && t.suppressMovable !== !0;
2955
2958
  }
2956
2959
  function ge(i, e, t) {
2957
2960
  if (e === t || e < 0 || e >= i.length || t < 0 || t > i.length) return i;
2958
2961
  const n = [...i], [o] = n.splice(e, 1);
2959
2962
  return n.splice(t, 0, o), n;
2960
2963
  }
2961
- class Lt extends C {
2964
+ class Lt extends y {
2962
2965
  name = "reorder";
2963
2966
  version = "1.0.0";
2964
2967
  get defaultConfig() {
@@ -2973,19 +2976,19 @@ class Lt extends C {
2973
2976
  draggedField = null;
2974
2977
  draggedIndex = null;
2975
2978
  dropIndex = null;
2976
- boundReorderRequestHandler = null;
2977
2979
  // ===== Lifecycle =====
2978
2980
  attach(e) {
2979
- super.attach(e), this.boundReorderRequestHandler = (t) => {
2980
- const n = t.detail;
2981
- n?.field && typeof n.toIndex == "number" && this.moveColumn(n.field, n.toIndex);
2982
- }, e.addEventListener("column-reorder-request", this.boundReorderRequestHandler);
2981
+ super.attach(e), e.addEventListener(
2982
+ "column-reorder-request",
2983
+ (t) => {
2984
+ const n = t.detail;
2985
+ n?.field && typeof n.toIndex == "number" && this.moveColumn(n.field, n.toIndex);
2986
+ },
2987
+ { signal: this.disconnectSignal }
2988
+ );
2983
2989
  }
2984
2990
  detach() {
2985
- this.boundReorderRequestHandler && this.grid && (this.grid.removeEventListener(
2986
- "column-reorder-request",
2987
- this.boundReorderRequestHandler
2988
- ), this.boundReorderRequestHandler = null), this.isDragging = !1, this.draggedField = null, this.draggedIndex = null, this.dropIndex = null;
2991
+ this.isDragging = !1, this.draggedField = null, this.draggedIndex = null, this.dropIndex = null;
2989
2992
  }
2990
2993
  // ===== Hooks =====
2991
2994
  // Note: No processColumns hook needed - we directly update the grid's column order
@@ -3130,7 +3133,7 @@ function ht(i, e, t) {
3130
3133
  return o[r];
3131
3134
  }
3132
3135
  const ft = 100;
3133
- class Mt extends C {
3136
+ class Mt extends y {
3134
3137
  name = "serverSide";
3135
3138
  version = "1.0.0";
3136
3139
  get defaultConfig() {
@@ -3283,7 +3286,7 @@ function wt(i, e, t, n) {
3283
3286
  timestamp: Date.now()
3284
3287
  };
3285
3288
  }
3286
- class qt extends C {
3289
+ class qt extends y {
3287
3290
  name = "undoRedo";
3288
3291
  version = "1.0.0";
3289
3292
  get defaultConfig() {
@@ -3413,7 +3416,7 @@ function we(i) {
3413
3416
  const e = i.meta ?? {};
3414
3417
  return e.lockPosition !== !0 && e.suppressMovable !== !0;
3415
3418
  }
3416
- class _ extends C {
3419
+ class _ extends y {
3417
3420
  name = "visibility";
3418
3421
  version = "1.0.0";
3419
3422
  /** Tool panel ID for shell integration */
@@ -3730,17 +3733,17 @@ class _ extends C {
3730
3733
  `;
3731
3734
  }
3732
3735
  export {
3733
- C as BaseGridPlugin,
3736
+ y as BaseGridPlugin,
3734
3737
  vt as ClipboardPlugin,
3735
- Ct as ColumnVirtualizationPlugin,
3736
- yt as ContextMenuPlugin,
3738
+ yt as ColumnVirtualizationPlugin,
3739
+ Ct as ContextMenuPlugin,
3737
3740
  Pt as DGEvents,
3738
3741
  Dt as DataGridElement,
3739
3742
  St as ExportPlugin,
3740
3743
  E as FilteringPlugin,
3741
3744
  Bt as FitModeEnum,
3742
- Ht as GridCSSVars,
3743
- Ot as GridClasses,
3745
+ Ot as GridCSSVars,
3746
+ Ht as GridClasses,
3744
3747
  Wt as GridDataAttrs,
3745
3748
  Kt as GridElement,
3746
3749
  Vt as GridSelectors,