@toolbox-web/grid 0.0.1

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 (87) hide show
  1. package/all.d.ts +3518 -0
  2. package/all.js +3762 -0
  3. package/all.js.map +1 -0
  4. package/index.d.ts +2367 -0
  5. package/index.js +3105 -0
  6. package/index.js.map +1 -0
  7. package/lib/plugins/clipboard/index.js +365 -0
  8. package/lib/plugins/clipboard/index.js.map +1 -0
  9. package/lib/plugins/column-virtualization/index.js +255 -0
  10. package/lib/plugins/column-virtualization/index.js.map +1 -0
  11. package/lib/plugins/context-menu/index.js +341 -0
  12. package/lib/plugins/context-menu/index.js.map +1 -0
  13. package/lib/plugins/export/index.js +305 -0
  14. package/lib/plugins/export/index.js.map +1 -0
  15. package/lib/plugins/filtering/index.js +759 -0
  16. package/lib/plugins/filtering/index.js.map +1 -0
  17. package/lib/plugins/grouping-columns/index.js +283 -0
  18. package/lib/plugins/grouping-columns/index.js.map +1 -0
  19. package/lib/plugins/grouping-rows/index.js +494 -0
  20. package/lib/plugins/grouping-rows/index.js.map +1 -0
  21. package/lib/plugins/master-detail/index.js +303 -0
  22. package/lib/plugins/master-detail/index.js.map +1 -0
  23. package/lib/plugins/multi-sort/index.js +270 -0
  24. package/lib/plugins/multi-sort/index.js.map +1 -0
  25. package/lib/plugins/pinned-columns/index.js +221 -0
  26. package/lib/plugins/pinned-columns/index.js.map +1 -0
  27. package/lib/plugins/pinned-rows/index.js +459 -0
  28. package/lib/plugins/pinned-rows/index.js.map +1 -0
  29. package/lib/plugins/pivot/index.js +326 -0
  30. package/lib/plugins/pivot/index.js.map +1 -0
  31. package/lib/plugins/reorder/index.js +260 -0
  32. package/lib/plugins/reorder/index.js.map +1 -0
  33. package/lib/plugins/selection/index.js +426 -0
  34. package/lib/plugins/selection/index.js.map +1 -0
  35. package/lib/plugins/server-side/index.js +241 -0
  36. package/lib/plugins/server-side/index.js.map +1 -0
  37. package/lib/plugins/tree/index.js +383 -0
  38. package/lib/plugins/tree/index.js.map +1 -0
  39. package/lib/plugins/undo-redo/index.js +289 -0
  40. package/lib/plugins/undo-redo/index.js.map +1 -0
  41. package/lib/plugins/visibility/index.js +430 -0
  42. package/lib/plugins/visibility/index.js.map +1 -0
  43. package/package.json +53 -0
  44. package/themes/dg-theme-contrast.css +43 -0
  45. package/themes/dg-theme-large.css +54 -0
  46. package/themes/dg-theme-standard.css +19 -0
  47. package/themes/dg-theme-vibrant.css +16 -0
  48. package/umd/grid.all.umd.js +660 -0
  49. package/umd/grid.all.umd.js.map +1 -0
  50. package/umd/grid.umd.js +105 -0
  51. package/umd/grid.umd.js.map +1 -0
  52. package/umd/plugins/clipboard.umd.js +9 -0
  53. package/umd/plugins/clipboard.umd.js.map +1 -0
  54. package/umd/plugins/column-virtualization.umd.js +2 -0
  55. package/umd/plugins/column-virtualization.umd.js.map +1 -0
  56. package/umd/plugins/context-menu.umd.js +53 -0
  57. package/umd/plugins/context-menu.umd.js.map +1 -0
  58. package/umd/plugins/export.umd.js +14 -0
  59. package/umd/plugins/export.umd.js.map +1 -0
  60. package/umd/plugins/filtering.umd.js +175 -0
  61. package/umd/plugins/filtering.umd.js.map +1 -0
  62. package/umd/plugins/grouping-columns.umd.js +29 -0
  63. package/umd/plugins/grouping-columns.umd.js.map +1 -0
  64. package/umd/plugins/grouping-rows.umd.js +40 -0
  65. package/umd/plugins/grouping-rows.umd.js.map +1 -0
  66. package/umd/plugins/master-detail.umd.js +27 -0
  67. package/umd/plugins/master-detail.umd.js.map +1 -0
  68. package/umd/plugins/multi-sort.umd.js +26 -0
  69. package/umd/plugins/multi-sort.umd.js.map +1 -0
  70. package/umd/plugins/pinned-columns.umd.js +2 -0
  71. package/umd/plugins/pinned-columns.umd.js.map +1 -0
  72. package/umd/plugins/pinned-rows.umd.js +73 -0
  73. package/umd/plugins/pinned-rows.umd.js.map +1 -0
  74. package/umd/plugins/pivot.umd.js +8 -0
  75. package/umd/plugins/pivot.umd.js.map +1 -0
  76. package/umd/plugins/reorder.umd.js +31 -0
  77. package/umd/plugins/reorder.umd.js.map +1 -0
  78. package/umd/plugins/selection.umd.js +34 -0
  79. package/umd/plugins/selection.umd.js.map +1 -0
  80. package/umd/plugins/server-side.umd.js +2 -0
  81. package/umd/plugins/server-side.umd.js.map +1 -0
  82. package/umd/plugins/tree.umd.js +11 -0
  83. package/umd/plugins/tree.umd.js.map +1 -0
  84. package/umd/plugins/undo-redo.umd.js +2 -0
  85. package/umd/plugins/undo-redo.umd.js.map +1 -0
  86. package/umd/plugins/visibility.umd.js +94 -0
  87. package/umd/plugins/visibility.umd.js.map +1 -0
package/index.js ADDED
@@ -0,0 +1,3105 @@
1
+ const we = ":root{color-scheme:light dark}:host{--tbw-color-bg: transparent;--tbw-color-panel-bg: light-dark(#eeeeee, #222222);--tbw-color-fg: light-dark(#222222, #eeeeee);--tbw-color-fg-muted: light-dark(#555555, #aaaaaa);--tbw-color-accent: light-dark(#3b82f6, #3b82f6);--tbw-color-accent-fg: light-dark(#ffffff, #000000);--tbw-color-success: light-dark(hsl(122, 39%, 40%), hsl(122, 39%, 49%));--tbw-color-selection: light-dark(#fff7d6, #333333);--tbw-color-row-alt: var(--tbw-color-bg);--tbw-color-row-hover: light-dark(#f0f6ff, #1c1c1c);--tbw-color-header-bg: color-mix(in hsl, var(--tbw-color-panel-bg) 85%, var(--tbw-color-fg));--tbw-color-header-fg: color-mix(in hsl, var(--tbw-color-fg) 75%, var(--tbw-color-panel-bg));--tbw-color-border: light-dark(#d0d0d4, #454545);--tbw-color-border-strong: light-dark(#777777, #adacac);--tbw-color-border-cell: var(--tbw-color-border);--tbw-color-border-header: var(--tbw-color-border);--tbw-color-shadow: light-dark(rgba(0, 0, 0, .1), rgba(0, 0, 0, .3));--tbw-font-family: inherit;--tbw-font-size: inherit;--tbw-font-size-header: var(--tbw-font-size);--tbw-font-weight-header: bold;--tbw-cell-padding-header: 2px 8px;--tbw-cell-padding: 2px 8px;--tbw-cell-padding-input: 2px 6px;--tbw-row-height: 28px;--tbw-header-height: 30px;--tbw-border-radius: 4px;--tbw-border-input: 1px solid var(--tbw-color-border-strong);--tbw-border-header: 1px solid var(--tbw-color-border-header);--tbw-row-divider: 1px solid var(--tbw-color-border-cell);--tbw-row-hover-outline: 0;--tbw-color-active-row-bg: var(--tbw-color-selection);--tbw-active-row-outline: 0;--tbw-focus-outline: 2px solid var(--tbw-color-accent);--tbw-focus-outline-offset: -2px;--tbw-focus-background: rgba(from var(--tbw-color-accent) r g b / 12%);--tbw-range-border-color: var(--tbw-color-success);--tbw-range-selection-bg: rgba(from var(--tbw-range-border-color) r g b / 12%);--tbw-resize-handle-width: 4px;--tbw-resize-handle-color: transparent;--tbw-resize-handle-color-hover: var(--tbw-color-accent);--tbw-resize-handle-border-radius: 0;--tbw-scrollbar-thumb: var(--tbw-color-border-strong);--tbw-scrollbar-track: var(--tbw-color-bg);--tbw-transition-duration: .12s;--tbw-transition-ease: ease;--tbw-editing-bg: var(--tbw-color-selection);--tbw-editing-border: var(--tbw-border-input, 1px solid var(--tbw-color-border-strong));--tbw-padding-editing-input: var(--tbw-cell-padding-input, 2px 6px);--tbw-font-size-editor: inherit;--tbw-sort-indicator-color: var(--tbw-color-fg-muted);--tbw-sort-indicator-active-color: var(--tbw-color-accent);--tbw-header-text-transform: none;--tbw-header-letter-spacing: normal;--tbw-color-header-separator: var(--tbw-color-border-cell);--tbw-checkbox-size: 16px;--tbw-density-scale: 1}:host{position:relative;display:block;width:100%;height:100%;min-height:0;contain:content;font-family:var(--tbw-font-family);font-size:var(--tbw-font-size);background:var(--tbw-color-bg);color:var(--tbw-color-fg);border:1px solid var(--tbw-color-border);border-radius:var(--tbw-border-radius);overflow:clip;outline:none}:host,:host *{box-sizing:border-box}:host .header{display:block;flex-shrink:0;z-index:var(--tbw-z-layer-header, 30);background:var(--tbw-color-header-bg);overflow:visible}:host .header-group-row{display:grid;grid-template-columns:var(--tbw-column-template);background:var(--tbw-color-header-bg);z-index:var(--tbw-z-layer-header, 30)}:host .header-group-cell{display:flex;align-items:center;justify-content:flex-start;padding:var(--tbw-cell-padding-header, 2px 8px);color:var(--tbw-color-header-group-fg, var(--tbw-color-header-fg));font-weight:var(--tbw-font-weight-header-group, var(--tbw-font-weight-header));justify-content:var(--tbw-align-header-group, var(--tbw-align-header, flex-start))}:host .header-row{display:grid;grid-template-columns:var(--tbw-column-template);color:var(--tbw-color-header-fg);font-size:var(--tbw-font-size-header);min-height:var(--tbw-header-height);border-bottom:var(--tbw-border-header);z-index:var(--tbw-z-layer-header, 30)}:host .header-row>.cell{display:flex;align-items:center;gap:4px;padding:var(--tbw-cell-padding-header, 2px 8px);background-color:var(--tbw-color-header-bg);font-weight:var(--tbw-font-weight-header);border-right:1px solid var(--tbw-color-border-cell);overflow:hidden;min-width:0}:host .header-row>.cell>span:first-child{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host .header-row>.cell>span[part~=sort-indicator]{flex-shrink:0}:host .header-row>.cell:last-child{border-right:0}:host .header-group-cell,:host .header-row>.cell.grouped.group-end{border-right:2px solid var(--tbw-color-border)}:host .tbw-grid-root{display:flex;flex-direction:column;height:100%}:host .rows-body-wrapper{flex:1;min-height:0;display:flex;flex-direction:row;width:100%;min-width:fit-content}:host .rows-body{flex:1;min-width:0;min-height:0;display:flex;flex-direction:column;overflow:visible}:host .rows-container{display:flex;flex-direction:row;flex:1;min-height:0;overflow:visible}:host .rows-viewport{flex:1;min-width:0;position:relative;display:block;overflow:clip}:host .faux-vscroll{position:sticky;inset-inline-end:0;flex-shrink:0;width:auto;overflow-y:auto;overflow-x:hidden;z-index:var(--tbw-z-layer-header, 30)}:host .faux-vscroll-spacer{width:1px}:host .rows-viewport .rows{position:absolute;top:0;left:0;min-width:100%;will-change:transform;z-index:var(--tbw-z-layer-rows, 1)}:host .data-grid-row{display:grid;grid-template-columns:var(--tbw-column-template);contain:layout style}:host .data-grid-row:has(.editing){background:var(--tbw-editing-bg)}:host .selecting .data-grid-row>.cell{user-select:none}:host .data-grid-row>.cell{display:flex;align-items:center;padding:var(--tbw-cell-padding, 2px 8px);border-bottom:var(--tbw-row-divider);min-height:var(--tbw-row-height);border-right:1px solid var(--tbw-color-border-cell);overflow:hidden;min-width:0}:host .data-grid-row>.cell>*{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host .data-grid-row>.cell:last-child{border-right:0}:host .data-grid-row>.cell[data-type=boolean]{justify-content:center}:host .data-grid-row>.cell[data-type=boolean] input[type=checkbox]{margin:0;width:var(--tbw-checkbox-size);height:var(--tbw-checkbox-size)}:host .data-grid-row>.cell.editing{overflow:hidden;padding:0}:host .data-grid-row>.cell.editing input:not([type=checkbox]),:host .data-grid-row>.cell.editing select,:host .data-grid-row>.cell.editing textarea{width:100%;height:100%;max-width:100%;flex:1 1 auto;min-width:0;border:var(--tbw-editing-border);padding:var(--tbw-padding-editing-input);font-size:var(--tbw-font-size-editor)}:host .data-grid-row:nth-child(2n){background:var(--tbw-color-row-alt)}:host .data-grid-row:hover{background:var(--tbw-color-row-hover)}:host .sortable{cursor:pointer;user-select:none}:host .resize-handle{position:absolute;top:0;right:calc(var(--tbw-resize-handle-width) / -2);width:var(--tbw-resize-handle-width);height:100%;cursor:e-resize;user-select:none;touch-action:none;z-index:20;background:var(--tbw-resize-handle-color);transition:background .12s ease;border-radius:var(--tbw-resize-handle-border-radius)}:host .resize-handle:hover{background:var(--tbw-resize-handle-color-hover)}:host .cell-focus,:host .row-focus{outline:var(--tbw-focus-outline);outline-offset:var(--tbw-focus-outline-offset)}:host .group-row{display:grid;grid-template-columns:var(--tbw-column-template);background:var(--tbw-color-row-alt);font-weight:500;border-bottom:var(--tbw-row-divider);min-height:var(--tbw-row-height)}:host .group-row .cell{display:flex;align-items:center;padding:var(--tbw-cell-padding, 2px 8px)}:host .group-row .group-toggle{background:none;border:0;cursor:pointer;padding:0 4px 0 0;font:inherit}:host .group-row .group-count{margin-left:4px;opacity:.7}:host .sticky-left,:host .sticky-right{position:sticky;z-index:25}:host .header-row>.cell.sticky-left,:host .header-row>.cell.sticky-right{background:var(--tbw-color-header-bg);z-index:35}:host .data-grid-row>.cell.sticky-left,:host .data-grid-row>.cell.sticky-right{background:var(--tbw-color-panel-bg)}:host .sticky-left{box-shadow:1px 0 0 var(--tbw-color-border)}:host .sticky-right{box-shadow:-1px 0 0 var(--tbw-color-border)}.grid-container{position:relative;width:100%;height:100%}.grid-placeholder{padding:2rem;text-align:center;color:var(--tbw-color-fg);opacity:.6}:host{--tbw-shell-header-height: 44px;--tbw-shell-header-bg: var(--tbw-color-panel-bg);--tbw-shell-header-border: var(--tbw-color-border);--tbw-shell-title-font-size: 14px;--tbw-shell-title-font-weight: 600;--tbw-tool-panel-width: 280px;--tbw-tool-panel-bg: var(--tbw-color-panel-bg);--tbw-tool-panel-border: var(--tbw-color-border);--tbw-tool-panel-header-height: 40px;--tbw-tool-panel-transition: .2s ease-out;--tbw-toolbar-button-size: 32px;--tbw-toolbar-button-gap: 4px}:host .tbw-grid-root.has-shell{display:flex;flex-direction:column;height:100%}:host .tbw-shell-header{display:flex;align-items:center;gap:8px;min-height:var(--tbw-shell-header-height);padding:0 8px;background:var(--tbw-shell-header-bg);border-bottom:1px solid var(--tbw-shell-header-border);flex-shrink:0}:host .tbw-shell-title{font-size:var(--tbw-shell-title-font-size);font-weight:var(--tbw-shell-title-font-weight);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}:host .tbw-shell-content{flex:1;display:flex;align-items:center;gap:12px;min-width:0;overflow:hidden}:host .tbw-shell-toolbar{display:flex;align-items:center;gap:var(--tbw-toolbar-button-gap);flex-shrink:0}:host .tbw-toolbar-btn{display:inline-flex;align-items:center;justify-content:center;width:var(--tbw-toolbar-button-size);height:var(--tbw-toolbar-button-size);padding:0;border:1px solid transparent;border-radius:var(--tbw-border-radius);background:transparent;color:var(--tbw-color-fg);cursor:pointer;font-size:16px;transition:background var(--tbw-transition-duration) var(--tbw-transition-ease),border-color var(--tbw-transition-duration) var(--tbw-transition-ease)}:host .tbw-toolbar-btn:hover{background:var(--tbw-color-row-hover)}:host .tbw-toolbar-btn:focus-visible{outline:var(--tbw-focus-outline);outline-offset:var(--tbw-focus-outline-offset)}:host .tbw-toolbar-btn.active{background:var(--tbw-focus-background);border-color:var(--tbw-color-accent)}:host .tbw-toolbar-btn:disabled{opacity:.5;cursor:not-allowed}:host .tbw-toolbar-separator{width:1px;height:20px;background:var(--tbw-color-border);margin:0 4px}:host .tbw-shell-body{display:flex;flex:1;min-height:0;overflow:visible}:host .tbw-grid-content{flex:1;min-width:0;min-height:0;display:flex;flex-direction:row;overflow:hidden}:host .tbw-scroll-area{flex:1;min-width:0;min-height:0;display:flex;flex-direction:column;overflow-x:auto;overflow-y:hidden}:host .tbw-tool-panel{width:0;overflow:hidden;background:var(--tbw-tool-panel-bg);border-left:1px solid var(--tbw-tool-panel-border);transition:width var(--tbw-tool-panel-transition);display:flex;flex-direction:column;flex-shrink:0}:host .tbw-tool-panel[data-position=left]{border-left:none;border-right:1px solid var(--tbw-tool-panel-border);order:-1}:host .tbw-tool-panel.open{width:var(--tbw-tool-panel-width)}:host .tbw-tool-panel-header{display:flex;align-items:center;justify-content:space-between;min-height:var(--tbw-tool-panel-header-height);padding:0 12px;border-bottom:1px solid var(--tbw-tool-panel-border);flex-shrink:0}:host .tbw-tool-panel-title{font-weight:600;font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}:host .tbw-tool-panel-close{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;border:none;border-radius:var(--tbw-border-radius);background:transparent;color:var(--tbw-color-fg-muted);cursor:pointer;font-size:14px}:host .tbw-tool-panel-close:hover{background:var(--tbw-color-row-hover);color:var(--tbw-color-fg)}:host .tbw-tool-panel-content{flex:1;overflow:auto;padding:12px}: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 .tbw-selection-summary{font-size:13px;color:var(--tbw-color-fg-muted);white-space:nowrap}";
2
+ function be(o) {
3
+ const e = /* @__PURE__ */ new Map();
4
+ return o.sortState && e.set(o.sortState.field, {
5
+ direction: o.sortState.direction === 1 ? "asc" : "desc",
6
+ priority: 0
7
+ }), e;
8
+ }
9
+ function ae(o, e) {
10
+ const t = o._columns, n = be(o);
11
+ return {
12
+ columns: t.map((i, s) => {
13
+ const r = {
14
+ field: i.field,
15
+ order: s,
16
+ visible: !0
17
+ // If it's in _columns, it's visible (hidden columns are filtered out)
18
+ }, l = i;
19
+ l.__renderedWidth !== void 0 ? r.width = l.__renderedWidth : i.width !== void 0 && (r.width = typeof i.width == "string" ? parseFloat(i.width) : i.width);
20
+ const a = n.get(i.field);
21
+ a && (r.sort = a);
22
+ for (const h of e)
23
+ if (h.getColumnState) {
24
+ const u = h.getColumnState(i.field);
25
+ u && Object.assign(r, u);
26
+ }
27
+ return r;
28
+ })
29
+ };
30
+ }
31
+ function ge(o, e, t, n) {
32
+ if (!e.columns || e.columns.length === 0) return;
33
+ const i = new Map(e.columns.map((l) => [l.field, l])), s = t.map((l) => {
34
+ const a = i.get(l.field);
35
+ if (!a) return l;
36
+ const h = { ...l };
37
+ return a.width !== void 0 && (h.width = a.width, h.__renderedWidth = a.width), a.visible !== void 0 && (h.hidden = !a.visible), h;
38
+ });
39
+ s.sort((l, a) => {
40
+ const h = i.get(l.field)?.order ?? 1 / 0, u = i.get(a.field)?.order ?? 1 / 0;
41
+ return h - u;
42
+ }), o._columns = s;
43
+ const r = e.columns.filter((l) => l.sort !== void 0).sort((l, a) => (l.sort?.priority ?? 0) - (a.sort?.priority ?? 0));
44
+ if (r.length > 0) {
45
+ const l = r[0];
46
+ l.sort && (o.sortState = {
47
+ field: l.field,
48
+ direction: l.sort.direction === "asc" ? 1 : -1
49
+ });
50
+ } else
51
+ o.sortState = null;
52
+ for (const l of n)
53
+ if (l.applyColumnState)
54
+ for (const a of e.columns)
55
+ l.applyColumnState(a.field, a);
56
+ }
57
+ function me(o, e, t) {
58
+ let n = null;
59
+ return () => {
60
+ n !== null && clearTimeout(n), n = setTimeout(() => {
61
+ n = null;
62
+ const i = ae(o, e());
63
+ t(i);
64
+ }, 100);
65
+ };
66
+ }
67
+ const O = {
68
+ STRETCH: "stretch",
69
+ FIXED: "fixed"
70
+ };
71
+ function ve(o) {
72
+ return o == null ? "string" : typeof o == "number" ? "number" : typeof o == "boolean" ? "boolean" : o instanceof Date || typeof o == "string" && /\d{4}-\d{2}-\d{2}/.test(o) && !isNaN(Date.parse(o)) ? "date" : "string";
73
+ }
74
+ function ce(o, e) {
75
+ if (e && e.length) {
76
+ const s = {};
77
+ return e.forEach((r) => {
78
+ r.type && (s[r.field] = r.type);
79
+ }), { columns: e, typeMap: s };
80
+ }
81
+ const t = o[0] || {}, n = Object.keys(t).map((s) => {
82
+ const r = t[s], l = ve(r);
83
+ return { field: s, header: s.charAt(0).toUpperCase() + s.slice(1), type: l };
84
+ }), i = {};
85
+ return n.forEach((s) => {
86
+ i[s.field] = s.type || "string";
87
+ }), { columns: n, typeMap: i };
88
+ }
89
+ const Ce = /{{\s*([^}]+)\s*}}/g, C = "__DG_EMPTY__", ye = /^[\w$. '?+\-*/%:()!<>=,&|]+$/, Ee = /__(proto|defineGetter|defineSetter)|constructor|window|globalThis|global|process|Function|import|eval|Reflect|Proxy|Error|arguments|document|location|cookie|localStorage|sessionStorage|indexedDB|fetch|XMLHttpRequest|WebSocket|Worker|SharedWorker|ServiceWorker|opener|parent|top|frames|self|this\b/, Re = /* @__PURE__ */ new Set([
90
+ "script",
91
+ "iframe",
92
+ "object",
93
+ "embed",
94
+ "form",
95
+ "input",
96
+ "button",
97
+ "textarea",
98
+ "select",
99
+ "link",
100
+ "meta",
101
+ "base",
102
+ "style",
103
+ "template",
104
+ "slot",
105
+ "portal",
106
+ "frame",
107
+ "frameset",
108
+ "applet",
109
+ "noscript",
110
+ "noembed",
111
+ "plaintext",
112
+ "xmp",
113
+ "listing"
114
+ ]), U = /^on\w+$/i, _e = /* @__PURE__ */ new Set(["href", "src", "action", "formaction", "data", "srcdoc", "xlink:href", "poster", "srcset"]), Ae = /^\s*(javascript|vbscript|data|blob):/i;
115
+ function N(o) {
116
+ if (!o || typeof o != "string") return "";
117
+ if (o.indexOf("<") === -1) return o;
118
+ const e = document.createElement("template");
119
+ return e.innerHTML = o, Se(e.content), e.innerHTML;
120
+ }
121
+ function Se(o) {
122
+ const e = [], t = o.querySelectorAll("*");
123
+ for (const n of t) {
124
+ const i = n.tagName.toLowerCase();
125
+ if (Re.has(i)) {
126
+ e.push(n);
127
+ continue;
128
+ }
129
+ if ((i === "svg" || n.namespaceURI === "http://www.w3.org/2000/svg") && Array.from(n.attributes).some(
130
+ (l) => U.test(l.name) || l.name === "href" || l.name === "xlink:href"
131
+ )) {
132
+ e.push(n);
133
+ continue;
134
+ }
135
+ const s = [];
136
+ for (const r of n.attributes) {
137
+ const l = r.name.toLowerCase();
138
+ if (U.test(l)) {
139
+ s.push(r.name);
140
+ continue;
141
+ }
142
+ if (_e.has(l) && Ae.test(r.value)) {
143
+ s.push(r.name);
144
+ continue;
145
+ }
146
+ if (l === "style" && /expression\s*\(|javascript:|behavior\s*:/i.test(r.value)) {
147
+ s.push(r.name);
148
+ continue;
149
+ }
150
+ }
151
+ s.forEach((r) => n.removeAttribute(r));
152
+ }
153
+ e.forEach((n) => n.remove());
154
+ }
155
+ function de(o, e) {
156
+ if (!o || o.indexOf("{{") === -1) return o;
157
+ const t = [], n = o.replace(Ce, (l, a) => {
158
+ const h = xe(a, e);
159
+ return t.push({ expr: a.trim(), result: h }), h;
160
+ }), i = Te(n), s = t.length && t.every((l) => l.result === "" || l.result === C);
161
+ return /Reflect\.|\bProxy\b|ownKeys\(/.test(o) || s ? "" : i;
162
+ }
163
+ function xe(o, e) {
164
+ if (o = (o || "").trim(), !o || /\b(Reflect|Proxy|ownKeys)\b/.test(o)) return C;
165
+ if (o === "value") return e.value == null ? C : String(e.value);
166
+ if (o.startsWith("row.") && !/[()?]/.test(o) && !o.includes(":")) {
167
+ const n = o.slice(4), i = e.row ? e.row[n] : void 0;
168
+ return i == null ? C : String(i);
169
+ }
170
+ if (o.length > 80 || !ye.test(o) || Ee.test(o)) return C;
171
+ const t = o.match(/\./g);
172
+ if (t && t.length > 1) return C;
173
+ try {
174
+ const i = new Function("value", "row", `return (${o});`)(e.value, e.row), s = i == null ? "" : String(i);
175
+ return /Reflect|Proxy|ownKeys/.test(s) ? C : s || C;
176
+ } catch {
177
+ return C;
178
+ }
179
+ }
180
+ function Te(o) {
181
+ return o && o.replace(new RegExp(C, "g"), "").replace(/Reflect\.[^<>{}\s]+/g, "").replace(/\bProxy\b/g, "").replace(/ownKeys\([^)]*\)/g, "");
182
+ }
183
+ function Le(o) {
184
+ if (/Reflect|Proxy|ownKeys/.test(o.textContent || "")) {
185
+ if (Array.from(o.childNodes).forEach((e) => {
186
+ e.nodeType === Node.TEXT_NODE && /Reflect|Proxy|ownKeys/.test(e.textContent || "") && (e.textContent = "");
187
+ }), /Reflect|Proxy|ownKeys/.test(o.textContent || "")) {
188
+ if (/Reflect|Proxy|ownKeys/.test(o.textContent || ""))
189
+ for (; o.firstChild; ) o.removeChild(o.firstChild);
190
+ o.textContent = (o.textContent || "").replace(/Reflect|Proxy|ownKeys/g, "");
191
+ }
192
+ (o.textContent || "").trim().length === 0 && (o.textContent = "");
193
+ }
194
+ }
195
+ function X(o) {
196
+ const e = /Reflect\.|\bProxy\b|ownKeys\(/.test(o), t = (n) => e ? "" : de(o, n);
197
+ return t.__blocked = e, t;
198
+ }
199
+ function ke(o) {
200
+ return Array.from(o.querySelectorAll("tbw-grid-column")).map((t) => {
201
+ const n = t.getAttribute("field") || "";
202
+ if (!n) return null;
203
+ const i = t.getAttribute("type") || void 0, r = i && (/* @__PURE__ */ new Set(["number", "string", "date", "boolean", "select", "typeahead"])).has(i) ? i : void 0, l = t.getAttribute("header") || void 0, a = t.hasAttribute("sortable"), h = t.hasAttribute("editable"), u = { field: n, type: r, header: l, sortable: a, editable: h };
204
+ t.hasAttribute("resizable") && (u.resizable = !0), t.hasAttribute("sizable") && (u.resizable = !0);
205
+ const w = t.getAttribute("options");
206
+ w && (u.options = w.split(",").map((f) => {
207
+ const [b, y] = f.includes(":") ? f.split(":") : [f.trim(), f.trim()];
208
+ return { value: b.trim(), label: y?.trim() || b.trim() };
209
+ }));
210
+ const c = t.querySelector("tbw-grid-column-view"), d = t.querySelector("tbw-grid-column-editor"), p = t.querySelector("tbw-grid-column-header");
211
+ return c && (u.__viewTemplate = c), d && (u.__editorTemplate = d), p && (u.__headerTemplate = p), u;
212
+ }).filter((t) => !!t);
213
+ }
214
+ function Pe(o, e) {
215
+ if ((!o || !o.length) && (!e || !e.length)) return [];
216
+ if (!o || !o.length) return e || [];
217
+ if (!e || !e.length) return o;
218
+ const t = {};
219
+ e.forEach((i) => t[i.field] = i);
220
+ const n = o.map((i) => {
221
+ const s = t[i.field];
222
+ if (!s) return i;
223
+ const r = { ...i };
224
+ return s.header && !r.header && (r.header = s.header), s.type && !r.type && (r.type = s.type), r.sortable = i.sortable || s.sortable, (i.resizable === !0 || s.resizable === !0) && (r.resizable = !0), r.editable = i.editable || s.editable, s.__viewTemplate && (r.__viewTemplate = s.__viewTemplate), s.__editorTemplate && (r.__editorTemplate = s.__editorTemplate), s.__headerTemplate && (r.__headerTemplate = s.__headerTemplate), delete t[i.field], r;
225
+ });
226
+ return Object.keys(t).forEach((i) => n.push(t[i])), n;
227
+ }
228
+ function B(o, e) {
229
+ try {
230
+ o.part?.add?.(e);
231
+ } catch {
232
+ }
233
+ const t = o.getAttribute("part");
234
+ t ? t.split(/\s+/).includes(e) || o.setAttribute("part", t + " " + e) : o.setAttribute("part", e);
235
+ }
236
+ function Oe(o) {
237
+ o.__lightDomColumnsCache || (o.__originalColumnNodes = Array.from(
238
+ o.querySelectorAll("tbw-grid-column")
239
+ ), o.__lightDomColumnsCache = o.__originalColumnNodes.length ? ke(o) : []);
240
+ const e = o.__lightDomColumnsCache, t = Pe(o._columns, e);
241
+ t.forEach((i) => {
242
+ i.__viewTemplate && !i.__compiledView && (i.__compiledView = X(i.__viewTemplate.innerHTML)), i.__editorTemplate && !i.__compiledEditor && (i.__compiledEditor = X(i.__editorTemplate.innerHTML));
243
+ });
244
+ const { columns: n } = ce(o._rows, t);
245
+ o._columns = n;
246
+ }
247
+ function Me(o) {
248
+ const e = o.effectiveConfig?.fitMode || o.fitMode || O.STRETCH;
249
+ if (e !== O.STRETCH && e !== O.FIXED || o.__didInitialAutoSize || !o.isConnected) return;
250
+ const t = o.headerRowEl?.children || [];
251
+ if (!t.length) return;
252
+ let n = !1;
253
+ o.visibleColumns.forEach((i, s) => {
254
+ if (i.width) return;
255
+ const r = t[s];
256
+ let l = r ? r.scrollWidth : 0;
257
+ for (const a of o.rowPool) {
258
+ const h = a.children[s];
259
+ if (h) {
260
+ const u = h.scrollWidth;
261
+ u > l && (l = u);
262
+ }
263
+ }
264
+ l > 0 && (i.width = l + 2, i.__autoSized = !0, n = !0);
265
+ }), n && he(o), o.__didInitialAutoSize = !0;
266
+ }
267
+ function he(o) {
268
+ (o.effectiveConfig?.fitMode || o.fitMode || O.STRETCH) === O.STRETCH ? o.gridTemplate = o.visibleColumns.map((t) => {
269
+ if (t.width) return `${t.width}px`;
270
+ const n = t.minWidth;
271
+ return n != null ? `minmax(${n}px, 1fr)` : "1fr";
272
+ }).join(" ").trim() : o.gridTemplate = o.visibleColumns.map((t) => t.width ? `${t.width}px` : "max-content").join(" "), o.style.setProperty("--tbw-column-template", o.gridTemplate);
273
+ }
274
+ function De(o) {
275
+ switch (o.type) {
276
+ case "number":
277
+ return (e) => {
278
+ const t = document.createElement("input");
279
+ return t.type = "number", t.value = e.value ?? "", t.addEventListener("blur", () => e.commit(t.value === "" ? null : Number(t.value))), t.addEventListener("keydown", (n) => {
280
+ n.key === "Enter" && e.commit(t.value === "" ? null : Number(t.value)), n.key === "Escape" && e.cancel();
281
+ }), t.focus(), t;
282
+ };
283
+ case "boolean":
284
+ return (e) => {
285
+ const t = document.createElement("input");
286
+ return t.type = "checkbox", t.checked = !!e.value, t.addEventListener("change", () => e.commit(t.checked)), t.focus(), t;
287
+ };
288
+ case "date":
289
+ return (e) => {
290
+ const t = document.createElement("input");
291
+ return t.type = "date", e.value instanceof Date && (t.valueAsDate = e.value), t.addEventListener("change", () => e.commit(t.valueAsDate)), t.addEventListener("keydown", (n) => {
292
+ n.key === "Escape" && e.cancel();
293
+ }), t.focus(), t;
294
+ };
295
+ case "select":
296
+ case "typeahead":
297
+ return (e) => {
298
+ const t = document.createElement("select");
299
+ e.column.multi && (t.multiple = !0), (typeof e.column.options == "function" ? e.column.options() : e.column.options || []).forEach((s) => {
300
+ const r = document.createElement("option");
301
+ r.value = String(s.value), r.textContent = s.label, (e.column.multi && Array.isArray(e.value) && e.value.includes(s.value) || !e.column.multi && e.value === s.value) && (r.selected = !0), t.appendChild(r);
302
+ });
303
+ const i = () => {
304
+ if (e.column.multi) {
305
+ const s = [];
306
+ Array.from(t.selectedOptions).forEach((r) => {
307
+ s.push(r.value);
308
+ }), e.commit(s);
309
+ } else
310
+ e.commit(t.value);
311
+ };
312
+ return t.addEventListener("change", i), t.addEventListener("blur", i), t.addEventListener("keydown", (s) => {
313
+ s.key === "Escape" && e.cancel();
314
+ }), t.focus(), t;
315
+ };
316
+ default:
317
+ return (e) => {
318
+ const t = document.createElement("input");
319
+ return t.type = "text", t.value = e.value ?? "", t.addEventListener("blur", () => e.commit(t.value)), t.addEventListener("keydown", (n) => {
320
+ n.key === "Enter" && e.commit(t.value), n.key === "Escape" && e.cancel();
321
+ }), t.focus(), t;
322
+ };
323
+ }
324
+ }
325
+ function He(o, e) {
326
+ if (o.dispatchKeyDown?.(e))
327
+ return;
328
+ const t = o._rows.length - 1, n = o.visibleColumns.length - 1, i = o.activeEditRows !== void 0 && o.activeEditRows !== -1, r = o.visibleColumns[o.focusCol]?.type, l = e.composedPath ? e.composedPath() : [], a = l && l.length ? l[0] : e.target, h = (u) => {
329
+ if (!u) return !1;
330
+ const w = u.tagName;
331
+ return !!(w === "INPUT" || w === "SELECT" || w === "TEXTAREA" || u.isContentEditable);
332
+ };
333
+ if (!(h(a) && (e.key === "Home" || e.key === "End")) && !(h(a) && (e.key === "ArrowUp" || e.key === "ArrowDown") && a.tagName === "INPUT" && a.type === "number") && !(i && (r === "select" || r === "typeahead") && (e.key === "ArrowDown" || e.key === "ArrowUp"))) {
334
+ switch (e.key) {
335
+ case "Tab": {
336
+ e.preventDefault(), !e.shiftKey ? o.focusCol < n ? o.focusCol += 1 : (typeof o.commitActiveRowEdit == "function" && o.commitActiveRowEdit(), o.focusRow < t && (o.focusRow += 1, o.focusCol = 0)) : o.focusCol > 0 ? o.focusCol -= 1 : o.focusRow > 0 && (typeof o.commitActiveRowEdit == "function" && o.activeEditRows === o.focusRow && o.commitActiveRowEdit(), o.focusRow -= 1, o.focusCol = n), M(o);
337
+ return;
338
+ }
339
+ case "ArrowDown":
340
+ i && typeof o.commitActiveRowEdit == "function" && o.commitActiveRowEdit(), o.focusRow = Math.min(t, o.focusRow + 1), e.preventDefault();
341
+ break;
342
+ case "ArrowUp":
343
+ i && typeof o.commitActiveRowEdit == "function" && o.commitActiveRowEdit(), o.focusRow = Math.max(0, o.focusRow - 1), e.preventDefault();
344
+ break;
345
+ case "ArrowRight":
346
+ o.focusCol = Math.min(n, o.focusCol + 1), e.preventDefault();
347
+ break;
348
+ case "ArrowLeft":
349
+ o.focusCol = Math.max(0, o.focusCol - 1), e.preventDefault();
350
+ break;
351
+ case "Home":
352
+ o.focusCol = 0, e.preventDefault();
353
+ break;
354
+ case "End":
355
+ o.focusCol = n, e.preventDefault();
356
+ break;
357
+ case "PageDown":
358
+ o.focusRow = Math.min(t, o.focusRow + 20), e.preventDefault();
359
+ break;
360
+ case "PageUp":
361
+ o.focusRow = Math.max(0, o.focusRow - 20), e.preventDefault();
362
+ break;
363
+ case "Enter":
364
+ return typeof o.beginBulkEdit == "function" ? o.beginBulkEdit(o.focusRow) : o.dispatchEvent(
365
+ new CustomEvent("activate-cell", { detail: { row: o.focusRow, col: o.focusCol } })
366
+ ), M(o);
367
+ default:
368
+ return;
369
+ }
370
+ M(o);
371
+ }
372
+ }
373
+ function M(o) {
374
+ if (o.virtualization?.enabled) {
375
+ const { rowHeight: i } = o.virtualization, s = o, r = o.focusRow * i;
376
+ r < s.scrollTop ? s.scrollTop = r : r + i > s.scrollTop + s.clientHeight && (s.scrollTop = r - s.clientHeight + i);
377
+ }
378
+ o.refreshVirtualWindow(!1), Array.from(o.bodyEl.querySelectorAll(".cell-focus")).forEach((i) => i.classList.remove("cell-focus")), Array.from(o.bodyEl.querySelectorAll('[aria-selected="true"]')).forEach((i) => {
379
+ i.setAttribute("aria-selected", "false");
380
+ });
381
+ const e = o.focusRow, t = o.virtualization.start ?? 0, n = o.virtualization.end ?? o._rows.length;
382
+ if (e >= t && e < n) {
383
+ const s = o.bodyEl.querySelectorAll(".data-grid-row")[e - t]?.children[o.focusCol];
384
+ if (s) {
385
+ if (s.classList.add("cell-focus"), s.setAttribute("aria-selected", "true"), o.activeEditRows !== void 0 && o.activeEditRows !== -1 && s.classList.contains("editing")) {
386
+ const r = s.querySelector(
387
+ 'input,select,textarea,[contenteditable="true"],[contenteditable=""],[tabindex]:not([tabindex="-1"])'
388
+ );
389
+ if (r && document.activeElement !== r)
390
+ try {
391
+ r.focus();
392
+ } catch {
393
+ }
394
+ } else if (!s.contains(document.activeElement)) {
395
+ s.hasAttribute("tabindex") || s.setAttribute("tabindex", "-1");
396
+ try {
397
+ s.focus({ preventScroll: !0 });
398
+ } catch {
399
+ }
400
+ }
401
+ }
402
+ }
403
+ }
404
+ const ze = "__cellDisplayCache", Ne = "__cellCacheEpoch";
405
+ function j(o) {
406
+ o[ze] = void 0, o[Ne] = void 0, o.__hasSpecialColumns = void 0;
407
+ }
408
+ function qe(o, e, t, n, i) {
409
+ const s = Math.max(0, t - e), r = o.bodyEl, l = o.visibleColumns, a = l.length;
410
+ let h = o.__cachedHeaderRowCount;
411
+ for (h === void 0 && (h = o.shadowRoot?.querySelector(".header-group-row") ? 2 : 1, o.__cachedHeaderRowCount = h); o.rowPool.length < s; ) {
412
+ const w = document.createElement("div");
413
+ w.className = "data-grid-row", w.setAttribute("role", "row"), w.addEventListener("click", (c) => Z(o, c, w, !1)), w.addEventListener("dblclick", (c) => Z(o, c, w, !0)), o.rowPool.push(w);
414
+ }
415
+ if (o.rowPool.length > s) {
416
+ for (let w = s; w < o.rowPool.length; w++) {
417
+ const c = o.rowPool[w];
418
+ c.parentNode === r && c.remove();
419
+ }
420
+ o.rowPool.length = s;
421
+ }
422
+ const u = i && o.__hasRenderRowPlugins !== !1;
423
+ for (let w = 0; w < s; w++) {
424
+ const c = e + w, d = o._rows[c], p = o.rowPool[w];
425
+ if (p.setAttribute("aria-rowindex", String(c + h + 1)), u && i(d, p, c)) {
426
+ p.__epoch = n, p.__rowDataRef = d, p.parentNode !== r && r.appendChild(p);
427
+ continue;
428
+ }
429
+ const f = p.__epoch, b = p.__rowDataRef, y = p.children.length, T = f === n && y === a, L = b !== d;
430
+ let _ = !1;
431
+ if (T && L) {
432
+ for (let E = 0; E < a; E++)
433
+ if (l[E].externalView && !p.querySelector(`.cell[data-col="${E}"] [data-external-view]`)) {
434
+ _ = !0;
435
+ break;
436
+ }
437
+ }
438
+ !T || _ ? (p.__isCustomRow && (p.className = "data-grid-row", p.setAttribute("role", "row"), p.__isCustomRow = !1), F(o, p, d, c), p.__epoch = n, p.__rowDataRef = d) : L ? (Y(o, p, d, c), p.__rowDataRef = d) : Y(o, p, d, c);
439
+ const g = o._changedRowIndices.has(c), m = p.classList.contains("changed");
440
+ g !== m && p.classList.toggle("changed", g), p.parentNode !== r && r.appendChild(p);
441
+ }
442
+ }
443
+ function Y(o, e, t, n) {
444
+ const i = e.children, s = o.visibleColumns, r = s.length, l = i.length, a = r < l ? r : l;
445
+ let h = o.__hasSpecialColumns;
446
+ if (h === void 0) {
447
+ h = !1;
448
+ for (let w = 0; w < r; w++) {
449
+ const c = s[w];
450
+ if (c.__viewTemplate || c.__compiledView || c.viewRenderer || c.externalView || c.format || c.type === "date" || c.type === "boolean") {
451
+ h = !0;
452
+ break;
453
+ }
454
+ }
455
+ o.__hasSpecialColumns = h;
456
+ }
457
+ const u = String(n);
458
+ if (!h) {
459
+ for (let w = 0; w < a; w++) {
460
+ const c = i[w], d = t[s[w].field];
461
+ c.textContent = d == null ? "" : String(d), c.getAttribute("data-row") !== u && c.setAttribute("data-row", u);
462
+ }
463
+ return;
464
+ }
465
+ for (let w = 0; w < a; w++)
466
+ if (s[w].externalView && !i[w].querySelector("[data-external-view]")) {
467
+ F(o, e, t, n);
468
+ return;
469
+ }
470
+ for (let w = 0; w < a; w++) {
471
+ const c = s[w], d = i[w];
472
+ if (d.getAttribute("data-row") !== u && d.setAttribute("data-row", u), d.classList.contains("editing") || c.__viewTemplate || c.__compiledView || c.viewRenderer || c.externalView)
473
+ continue;
474
+ const p = t[c.field];
475
+ let f;
476
+ if (c.format)
477
+ try {
478
+ const b = c.format(p, t);
479
+ f = b == null ? "" : String(b);
480
+ } catch {
481
+ f = p == null ? "" : String(p);
482
+ }
483
+ else if (c.type === "date")
484
+ if (p == null || p === "")
485
+ f = "";
486
+ else if (p instanceof Date)
487
+ f = isNaN(p.getTime()) ? "" : p.toLocaleDateString();
488
+ else {
489
+ const b = new Date(p);
490
+ f = isNaN(b.getTime()) ? "" : b.toLocaleDateString();
491
+ }
492
+ else c.type === "boolean" ? (f = p ? "🗹" : "☐", d.setAttribute("aria-checked", String(!!p))) : f = p == null ? "" : String(p);
493
+ d.textContent = f;
494
+ }
495
+ }
496
+ function F(o, e, t, n) {
497
+ e.innerHTML = "";
498
+ const i = o.visibleColumns, s = i.length, r = o.focusRow, l = o.focusCol, a = o.effectiveConfig?.editOn || o.editOn, h = o, u = document.createDocumentFragment();
499
+ for (let w = 0; w < s; w++) {
500
+ const c = i[w], d = document.createElement("div");
501
+ d.className = "cell", B(d, "cell"), c.type !== "boolean" && d.setAttribute("role", "gridcell"), d.setAttribute("data-col", String(w)), d.setAttribute("data-row", String(n)), d.setAttribute("aria-colindex", String(w + 1)), c.type && d.setAttribute("data-type", c.type);
502
+ const p = c.sticky;
503
+ p === "left" ? d.classList.add("sticky-left") : p === "right" && d.classList.add("sticky-right");
504
+ let f = t[c.field];
505
+ const b = c.format;
506
+ if (b)
507
+ try {
508
+ f = b(f, t);
509
+ } catch {
510
+ }
511
+ const y = c.__compiledView, S = c.__viewTemplate, T = c.viewRenderer, L = c.externalView;
512
+ let _ = !1;
513
+ if (T) {
514
+ const g = T({ row: t, value: f, field: c.field, column: c });
515
+ typeof g == "string" ? (d.innerHTML = N(g), _ = !0) : g ? d.appendChild(g) : d.textContent = f == null ? "" : String(f);
516
+ } else if (L) {
517
+ const g = L, m = document.createElement("div");
518
+ m.setAttribute("data-external-view", ""), m.setAttribute("data-field", c.field), d.appendChild(m);
519
+ const E = { row: t, value: f, field: c.field, column: c };
520
+ if (g.mount)
521
+ try {
522
+ g.mount({ placeholder: m, context: E, spec: g });
523
+ } catch {
524
+ }
525
+ else
526
+ queueMicrotask(() => {
527
+ try {
528
+ h.dispatchEvent(
529
+ new CustomEvent("mount-external-view", {
530
+ bubbles: !0,
531
+ composed: !0,
532
+ detail: { placeholder: m, spec: g, context: E }
533
+ })
534
+ );
535
+ } catch {
536
+ }
537
+ });
538
+ m.setAttribute("data-mounted", "");
539
+ } else if (y) {
540
+ const g = y({ row: t, value: f, field: c.field, column: c }), m = y.__blocked;
541
+ d.innerHTML = m ? "" : N(g), _ = !0, m && (d.textContent = "", d.setAttribute("data-blocked-template", ""));
542
+ } else if (S) {
543
+ const g = S.innerHTML;
544
+ /Reflect\.|\bProxy\b|ownKeys\(/.test(g) ? (d.textContent = "", d.setAttribute("data-blocked-template", "")) : (d.innerHTML = N(de(g, { row: t, value: f })), _ = !0);
545
+ } else if (c.type === "date")
546
+ if (f == null || f === "")
547
+ d.textContent = "";
548
+ else {
549
+ let g = null;
550
+ if (f instanceof Date) g = f;
551
+ else if (typeof f == "number" || typeof f == "string") {
552
+ const m = new Date(f);
553
+ isNaN(m.getTime()) || (g = m);
554
+ }
555
+ d.textContent = g ? g.toLocaleDateString() : "";
556
+ }
557
+ else if (c.type === "boolean") {
558
+ const g = !!f;
559
+ d.innerHTML = g ? "&#x1F5F9;" : "&#9744;", d.setAttribute("role", "checkbox"), d.setAttribute("aria-checked", String(g)), d.setAttribute("aria-label", String(g));
560
+ } else
561
+ d.textContent = f == null ? "" : String(f);
562
+ if (_) {
563
+ Le(d);
564
+ const g = d.textContent || "";
565
+ /Proxy|Reflect\.ownKeys/.test(g) && (d.textContent = g.replace(/Proxy|Reflect\.ownKeys/g, "").trim(), /Proxy|Reflect\.ownKeys/.test(d.textContent || "") && (d.textContent = ""));
566
+ }
567
+ d.hasAttribute("data-blocked-template") && (d.textContent || "").trim().length && (d.textContent = ""), c.editable ? (d.tabIndex = 0, d.addEventListener("mousedown", () => {
568
+ o.focusRow = n, o.focusCol = w, M(o);
569
+ }), a === "click" ? d.addEventListener("click", (g) => {
570
+ d.classList.contains("editing") || (g.stopPropagation(), o.focusRow = n, o.focusCol = w, x(o, t, n, c, d));
571
+ }) : d.addEventListener("dblclick", (g) => {
572
+ g.stopPropagation(), A(o, n, t);
573
+ const m = o.findRenderedRowElement?.(n);
574
+ if (m) {
575
+ const E = m.children;
576
+ for (let k = 0; k < E.length; k++) {
577
+ const D = o.visibleColumns[k];
578
+ D && D.editable && x(o, t, n, D, E[k]);
579
+ }
580
+ }
581
+ }), d.addEventListener("keydown", (g) => {
582
+ if ((c.type === "select" || c.type === "typeahead") && !d.classList.contains("editing") && g.key === "Enter") {
583
+ g.preventDefault(), o.activeEditRows !== n && A(o, n, t), x(o, t, n, c, d), setTimeout(() => {
584
+ const m = d.querySelector("select");
585
+ try {
586
+ m?.showPicker?.();
587
+ } catch {
588
+ }
589
+ m?.focus();
590
+ }, 0);
591
+ return;
592
+ }
593
+ if (c.type === "boolean" && g.key === " " && !d.classList.contains("editing")) {
594
+ g.preventDefault(), o.activeEditRows !== n && A(o, n, t);
595
+ const m = !t[c.field];
596
+ $(o, n, c, m, t), d.innerHTML = m ? "&#x1F5F9;" : "&#9744;", d.setAttribute("aria-label", String(!!m));
597
+ return;
598
+ }
599
+ if (g.key === "Enter" && !d.classList.contains("editing")) {
600
+ g.preventDefault(), o.focusRow = n, o.focusCol = w, typeof o.beginBulkEdit == "function" ? o.beginBulkEdit(n) : x(o, t, n, c, d);
601
+ return;
602
+ }
603
+ if (g.key === "F2" && !d.classList.contains("editing")) {
604
+ g.preventDefault(), x(o, t, n, c, d);
605
+ return;
606
+ }
607
+ })) : c.type === "boolean" && (d.hasAttribute("tabindex") || (d.tabIndex = 0), d.addEventListener("keydown", (g) => {
608
+ if (g.key === " ") {
609
+ g.preventDefault();
610
+ const m = !t[c.field];
611
+ o.activeEditRows !== n && A(o, n, t), $(o, n, c, m, t), d.innerHTML = m ? "&#x1F5F9;" : "&#9744;", d.setAttribute("role", "checkbox"), d.setAttribute("aria-checked", String(!!m)), d.setAttribute("aria-label", String(!!m));
612
+ }
613
+ })), r === n && l === w ? d.setAttribute("aria-selected", "true") : d.setAttribute("aria-selected", "false"), u.appendChild(d);
614
+ }
615
+ e.appendChild(u);
616
+ }
617
+ function Z(o, e, t, n) {
618
+ if (e.target?.closest(".resize-handle")) return;
619
+ const i = t.querySelector(".cell[data-row]");
620
+ if (!i) return;
621
+ const s = Number(i.getAttribute("data-row"));
622
+ if (isNaN(s)) return;
623
+ const r = o._rows[s];
624
+ if (!r) return;
625
+ const l = e.target?.closest(".cell[data-col]");
626
+ if (l) {
627
+ const h = Number(l.getAttribute("data-col"));
628
+ if (!isNaN(h)) {
629
+ if (o.dispatchCellClick?.(e, s, h, l))
630
+ return;
631
+ o.focusRow = s, o.focusCol = h, M(o);
632
+ }
633
+ }
634
+ if (t.querySelector(".cell.editing")) {
635
+ const h = t.querySelectorAll(".cell.editing");
636
+ if (!n) return;
637
+ h.forEach((u) => u.classList.remove("editing"));
638
+ }
639
+ const a = o.effectiveConfig?.editOn || o.editOn || "doubleClick";
640
+ if (a === "click" || a === "doubleClick" && n) A(o, s, r);
641
+ else return;
642
+ Array.from(t.children).forEach((h, u) => {
643
+ const w = o.visibleColumns[u];
644
+ w && w.editable && x(o, r, s, w, h);
645
+ }), l && queueMicrotask(() => {
646
+ const h = t.querySelector(`.cell[data-col="${o.focusCol}"]`);
647
+ if (h?.classList.contains("editing")) {
648
+ const u = h.querySelector(
649
+ 'input,select,textarea,[contenteditable="true"],[contenteditable=""],[tabindex]:not([tabindex="-1"])'
650
+ );
651
+ try {
652
+ u?.focus();
653
+ } catch {
654
+ }
655
+ }
656
+ });
657
+ }
658
+ function A(o, e, t) {
659
+ o.activeEditRows !== e && (o.rowEditSnapshots.set(e, { ...t }), o.activeEditRows = e);
660
+ }
661
+ function Ie(o, e, t) {
662
+ if (o.activeEditRows !== e) return;
663
+ const n = o.rowEditSnapshots.get(e), i = o._rows[e];
664
+ if (t && n && i)
665
+ Object.keys(n).forEach((r) => i[r] = n[r]), o._changedRowIndices.delete(e);
666
+ else if (!t) {
667
+ const r = o._changedRowIndices.has(e);
668
+ o.dispatchEvent(
669
+ new CustomEvent("row-commit", {
670
+ detail: {
671
+ rowIndex: e,
672
+ row: i,
673
+ changed: r,
674
+ changedRows: o.changedRows,
675
+ changedRowIndices: o.changedRowIndices
676
+ }
677
+ })
678
+ );
679
+ }
680
+ o.rowEditSnapshots.delete(e), o.activeEditRows = -1;
681
+ const s = o.findRenderedRowElement?.(e);
682
+ s && (F(o, s, o._rows[e], e), o._changedRowIndices.has(e) ? s.classList.add("changed") : s.classList.remove("changed")), t && queueMicrotask(() => {
683
+ try {
684
+ o.focus();
685
+ const r = o.focusRow, l = o.focusCol, a = o.findRenderedRowElement?.(r);
686
+ if (a) {
687
+ Array.from(o.bodyEl.querySelectorAll(".cell-focus")).forEach(
688
+ (u) => u.classList.remove("cell-focus")
689
+ );
690
+ const h = a.querySelector(`.cell[data-row="${r}"][data-col="${l}"]`);
691
+ h && h.classList.add("cell-focus");
692
+ }
693
+ } catch {
694
+ }
695
+ });
696
+ }
697
+ function $(o, e, t, n, i) {
698
+ const s = t.field;
699
+ if (i[s] === n) return;
700
+ i[s] = n;
701
+ const l = !o._changedRowIndices.has(e);
702
+ o._changedRowIndices.add(e);
703
+ const a = o.findRenderedRowElement?.(e);
704
+ a && a.classList.add("changed"), o.dispatchEvent(
705
+ new CustomEvent("cell-commit", {
706
+ detail: {
707
+ row: i,
708
+ field: s,
709
+ value: n,
710
+ rowIndex: e,
711
+ changedRows: o.changedRows,
712
+ changedRowIndices: o.changedRowIndices,
713
+ firstTimeForRow: l
714
+ }
715
+ })
716
+ );
717
+ }
718
+ function x(o, e, t, n, i) {
719
+ if (!n.editable || (o.activeEditRows !== t && A(o, t, e), i.classList.contains("editing"))) return;
720
+ const s = e[n.field];
721
+ i.classList.add("editing");
722
+ const r = (c) => {
723
+ $(o, t, n, c, e);
724
+ }, l = () => {
725
+ e[n.field] = s;
726
+ const c = i.querySelector("input,textarea,select");
727
+ c && (typeof HTMLInputElement < "u" && c instanceof HTMLInputElement && c.type === "checkbox" ? c.checked = !!s : "value" in c && (c.value = s ?? ""));
728
+ }, a = document.createElement("div");
729
+ a.style.display = "contents", i.innerHTML = "", i.appendChild(a);
730
+ const h = n.__editorTemplate, u = n.editor || (h ? "template" : De(n)), w = s;
731
+ if (u === "template" && h) {
732
+ const c = h.cloneNode(!0), d = n.__compiledEditor;
733
+ d ? c.innerHTML = d({ row: e, value: s, field: n.field, column: n }) : c.querySelectorAll("*").forEach((f) => {
734
+ f.childNodes.length === 1 && f.firstChild?.nodeType === Node.TEXT_NODE && (f.textContent = f.textContent?.replace(/{{\s*value\s*}}/g, s == null ? "" : String(s)).replace(/{{\s*row\.([a-zA-Z0-9_]+)\s*}}/g, (b, y) => {
735
+ const S = e[y];
736
+ return S == null ? "" : String(S);
737
+ }) || "");
738
+ });
739
+ const p = c.querySelector("input,textarea,select");
740
+ if (p) {
741
+ const f = typeof HTMLInputElement < "u";
742
+ f && p instanceof HTMLInputElement && p.type === "checkbox" ? p.checked = !!s : "value" in p && (p.value = s ?? ""), p.addEventListener("blur", () => {
743
+ const b = f && p instanceof HTMLInputElement && p.type === "checkbox" ? p.checked : p.value;
744
+ r(b);
745
+ }), p.addEventListener("keydown", (b) => {
746
+ if (b.key === "Enter") {
747
+ const y = f && p instanceof HTMLInputElement && p.type === "checkbox" ? p.checked : p.value;
748
+ r(y);
749
+ }
750
+ b.key === "Escape" && l();
751
+ }), f && p instanceof HTMLInputElement && p.type === "checkbox" && p.addEventListener("change", () => {
752
+ const b = p.checked;
753
+ r(b);
754
+ }), setTimeout(() => p.focus(), 0);
755
+ }
756
+ a.appendChild(c);
757
+ } else if (typeof u == "string") {
758
+ const c = document.createElement(u);
759
+ c.value = w, c.addEventListener("change", () => r(c.value)), a.appendChild(c);
760
+ } else if (typeof u == "function") {
761
+ const c = u({ row: e, value: w, field: n.field, column: n, commit: r, cancel: l });
762
+ typeof c == "string" ? a.innerHTML = c : a.appendChild(c);
763
+ } else if (u && typeof u == "object") {
764
+ const c = document.createElement("div");
765
+ c.setAttribute("data-external-editor", ""), c.setAttribute("data-field", n.field), a.appendChild(c);
766
+ const d = { row: e, value: w, field: n.field, column: n, commit: r, cancel: l };
767
+ if (u.mount)
768
+ try {
769
+ u.mount({ placeholder: c, context: d, spec: u });
770
+ } catch {
771
+ }
772
+ else
773
+ o.dispatchEvent(
774
+ new CustomEvent("mount-external-editor", { detail: { placeholder: c, spec: u, context: d } })
775
+ );
776
+ }
777
+ }
778
+ function J(o, e) {
779
+ !o.sortState || o.sortState.field !== e.field ? (o.sortState || (o.__originalOrder = o._rows.slice()), Q(o, e, 1)) : o.sortState.direction === 1 ? Q(o, e, -1) : (o.sortState = null, o.__rowRenderEpoch++, o.rowPool.forEach((n) => n.__epoch = -1), o._rows = o.__originalOrder.slice(), V(o), o.headerRowEl?.querySelectorAll('[role="columnheader"].sortable')?.forEach((n) => {
780
+ n.getAttribute("aria-sort") ? (n.getAttribute("aria-sort") === "ascending" || n.getAttribute("aria-sort") === "descending") && (o.sortState || n.setAttribute("aria-sort", "none")) : n.setAttribute("aria-sort", "none");
781
+ }), o.refreshVirtualWindow(!0), o.dispatchEvent(
782
+ new CustomEvent("sort-change", { detail: { field: e.field, direction: 0 } })
783
+ ), o.requestStateChange?.());
784
+ }
785
+ function Q(o, e, t) {
786
+ o.sortState = { field: e.field, direction: t };
787
+ const n = e.sortComparator || ((i, s) => i == null && s == null ? 0 : i == null ? -1 : s == null || i > s ? 1 : i < s ? -1 : 0);
788
+ o._rows.sort((i, s) => n(i[e.field], s[e.field], i, s) * t), o.__rowRenderEpoch++, o.rowPool.forEach((i) => i.__epoch = -1), V(o), o.refreshVirtualWindow(!0), o.dispatchEvent(
789
+ new CustomEvent("sort-change", { detail: { field: e.field, direction: t } })
790
+ ), o.requestStateChange?.();
791
+ }
792
+ function V(o) {
793
+ o.headerRowEl = o.findHeaderRow();
794
+ const e = o.headerRowEl;
795
+ e.innerHTML = "", e.setAttribute("role", "row"), e.setAttribute("aria-rowindex", "1"), o.visibleColumns.forEach((t, n) => {
796
+ const i = document.createElement("div");
797
+ i.className = "cell", B(i, "header-cell"), i.setAttribute("role", "columnheader"), i.setAttribute("aria-colindex", String(n + 1)), i.setAttribute("data-field", t.field), i.setAttribute("data-col", String(n)), t.sticky === "left" ? i.classList.add("sticky-left") : t.sticky === "right" && i.classList.add("sticky-right");
798
+ const s = t.__headerTemplate;
799
+ if (s) Array.from(s.childNodes).forEach((r) => i.appendChild(r.cloneNode(!0)));
800
+ else {
801
+ const r = t.header || t.field, l = document.createElement("span");
802
+ l.textContent = r, i.appendChild(l);
803
+ }
804
+ if (t.sortable) {
805
+ i.classList.add("sortable"), i.tabIndex = 0;
806
+ const r = document.createElement("span");
807
+ B(r, "sort-indicator"), r.style.opacity = "0.6";
808
+ const l = o.sortState?.field === t.field ? o.sortState.direction : 0;
809
+ r.textContent = l === 1 ? "▲" : l === -1 ? "▼" : "⇅", i.appendChild(r), i.setAttribute("aria-sort", l === 0 ? "none" : l === 1 ? "ascending" : "descending"), i.addEventListener("click", (a) => {
810
+ o.resizeController?.isResizing || o.dispatchHeaderClick?.(a, n, i) || J(o, t);
811
+ }), i.addEventListener("keydown", (a) => {
812
+ if (a.key === "Enter" || a.key === " ") {
813
+ if (a.preventDefault(), o.dispatchHeaderClick?.(a, n, i)) return;
814
+ J(o, t);
815
+ }
816
+ });
817
+ }
818
+ if (t.resizable) {
819
+ t.sticky || (i.style.position = "relative");
820
+ const r = document.createElement("div");
821
+ r.className = "resize-handle", r.setAttribute("aria-hidden", "true"), r.addEventListener("mousedown", (l) => {
822
+ l.stopPropagation(), l.preventDefault(), o.resizeController.start(l, n, i);
823
+ }), i.appendChild(r);
824
+ }
825
+ e.appendChild(i);
826
+ });
827
+ try {
828
+ const t = o.shadowRoot;
829
+ t && t.querySelectorAll(".header-group-row .cell").forEach((i) => {
830
+ i.getAttribute("data-group") && i.classList.add("grouped");
831
+ });
832
+ } catch {
833
+ }
834
+ e.querySelectorAll(".cell.sortable").forEach((t) => {
835
+ t.getAttribute("aria-sort") || t.setAttribute("aria-sort", "none");
836
+ });
837
+ }
838
+ function Be(o) {
839
+ let e = null, t = null, n = null, i = null;
840
+ const s = (a) => {
841
+ if (!e) return;
842
+ const h = a.clientX - e.startX, u = Math.max(40, e.startWidth + h), w = o.visibleColumns[e.colIndex];
843
+ w.width = u, w.__userResized = !0, w.__renderedWidth = u, t == null && (t = requestAnimationFrame(() => {
844
+ t = null, o.updateTemplate?.();
845
+ })), o.dispatchEvent(
846
+ new CustomEvent("column-resize", { detail: { field: w.field, width: u } })
847
+ );
848
+ };
849
+ let r = !1;
850
+ const l = () => {
851
+ const a = e !== null;
852
+ a && (r = !0, requestAnimationFrame(() => {
853
+ r = !1;
854
+ })), window.removeEventListener("mousemove", s), window.removeEventListener("mouseup", l), n !== null && (document.documentElement.style.cursor = n, n = null), i !== null && (document.body.style.userSelect = i, i = null), e = null, a && o.requestStateChange && o.requestStateChange();
855
+ };
856
+ return {
857
+ get isResizing() {
858
+ return e !== null || r;
859
+ },
860
+ start(a, h, u) {
861
+ a.preventDefault();
862
+ const w = u.getBoundingClientRect();
863
+ e = { startX: a.clientX, colIndex: h, startWidth: w.width }, window.addEventListener("mousemove", s), window.addEventListener("mouseup", l), n === null && (n = document.documentElement.style.cursor), document.documentElement.style.cursor = "e-resize", i === null && (i = document.body.style.userSelect), document.body.style.userSelect = "none";
864
+ },
865
+ dispose() {
866
+ l();
867
+ }
868
+ };
869
+ }
870
+ function $e() {
871
+ return {
872
+ toolPanels: /* @__PURE__ */ new Map(),
873
+ headerContents: /* @__PURE__ */ new Map(),
874
+ toolbarButtons: /* @__PURE__ */ new Map(),
875
+ lightDomButtons: [],
876
+ lightDomHeaderContent: [],
877
+ activePanel: null,
878
+ headerContentCleanups: /* @__PURE__ */ new Map(),
879
+ activePanelCleanup: null,
880
+ toolbarButtonCleanups: /* @__PURE__ */ new Map()
881
+ };
882
+ }
883
+ function Ke(o, e) {
884
+ return !!(o?.header?.title || o?.header?.toolbarButtons?.length || e.toolPanels.size > 0 || e.headerContents.size > 0 || e.toolbarButtons.size > 0 || e.lightDomButtons.length > 0 || e.lightDomHeaderContent.length > 0);
885
+ }
886
+ function We(o, e) {
887
+ const t = o?.header?.title ?? "", n = !!t, i = o?.header?.toolbarButtons ?? [], s = i.length > 0, r = e.toolbarButtons.size > 0, l = e.lightDomButtons.length > 0, a = e.toolPanels.size > 0, u = (s || r || l) && a, w = [...i].sort((f, b) => (f.order ?? 100) - (b.order ?? 100)), c = [...e.toolbarButtons.values()].sort((f, b) => (f.order ?? 100) - (b.order ?? 100)), d = [...e.toolPanels.values()].sort((f, b) => (f.order ?? 100) - (b.order ?? 100));
888
+ let p = "";
889
+ for (const f of w)
890
+ f.icon && f.action && (p += `<button class="tbw-toolbar-btn" data-btn="${f.id}" title="${f.label}" aria-label="${f.label}"${f.disabled ? " disabled" : ""}>${f.icon}</button>`);
891
+ for (const f of c)
892
+ f.icon && f.action && (p += `<button class="tbw-toolbar-btn" data-btn="${f.id}" title="${f.label}" aria-label="${f.label}"${f.disabled ? " disabled" : ""}>${f.icon}</button>`);
893
+ for (const f of w)
894
+ (f.element || f.render) && (p += `<div class="tbw-toolbar-btn-slot" data-btn-slot="${f.id}"></div>`);
895
+ for (const f of c)
896
+ (f.element || f.render) && (p += `<div class="tbw-toolbar-btn-slot" data-btn-slot="${f.id}"></div>`);
897
+ l && (p += '<slot name="toolbar"></slot>'), u && (p += '<div class="tbw-toolbar-separator"></div>');
898
+ for (const f of d) {
899
+ const b = e.activePanel === f.id;
900
+ p += `<button class="tbw-toolbar-btn${b ? " active" : ""}" data-panel="${f.id}" title="${f.tooltip ?? f.title}" aria-label="${f.tooltip ?? f.title}" aria-pressed="${b}" aria-controls="tbw-panel-${f.id}">${f.icon}</button>`;
901
+ }
902
+ return `
903
+ <div class="tbw-shell-header" part="shell-header" role="banner">
904
+ ${n ? `<div class="tbw-shell-title">${t}</div>` : ""}
905
+ <div class="tbw-shell-content" part="shell-content" role="region" aria-label="Grid information">
906
+ <slot name="header-content"></slot>
907
+ </div>
908
+ <div class="tbw-shell-toolbar" part="shell-toolbar" role="toolbar" aria-label="Grid tools">
909
+ ${p}
910
+ </div>
911
+ </div>
912
+ `;
913
+ }
914
+ function Fe(o, e, t) {
915
+ const n = o?.toolPanel?.position ?? "right", i = e.toolPanels.size > 0, s = e.activePanel !== null, r = e.activePanel ? e.toolPanels.get(e.activePanel) : null, l = i ? `
916
+ <aside class="tbw-tool-panel${s ? " open" : ""}" part="tool-panel" data-position="${n}" role="complementary" aria-label="${r?.title ?? "Tool panel"}" id="tbw-panel-${e.activePanel ?? "closed"}">
917
+ <div class="tbw-tool-panel-header">
918
+ <span class="tbw-tool-panel-title">${r?.title ?? ""}</span>
919
+ <button class="tbw-tool-panel-close" aria-label="Close panel">✕</button>
920
+ </div>
921
+ <div class="tbw-tool-panel-content" role="region"></div>
922
+ </aside>
923
+ ` : "";
924
+ return n === "left" ? `
925
+ <div class="tbw-shell-body">
926
+ ${l}
927
+ <div class="tbw-grid-content">
928
+ ${t}
929
+ </div>
930
+ </div>
931
+ ` : `
932
+ <div class="tbw-shell-body">
933
+ <div class="tbw-grid-content">
934
+ ${t}
935
+ </div>
936
+ ${l}
937
+ </div>
938
+ `;
939
+ }
940
+ function ee(o, e) {
941
+ const t = o.querySelector("tbw-grid-header");
942
+ if (!t) return;
943
+ t.style.display = "none";
944
+ const n = t.querySelectorAll("tbw-grid-header-content");
945
+ e.lightDomHeaderContent = Array.from(n), e.lightDomHeaderContent.forEach((s, r) => {
946
+ s.setAttribute("slot", "header-content");
947
+ });
948
+ const i = t.querySelectorAll("tbw-grid-tool-button");
949
+ e.lightDomButtons = Array.from(i), e.lightDomButtons.sort((s, r) => {
950
+ const l = parseInt(s.getAttribute("order") ?? "100", 10), a = parseInt(r.getAttribute("order") ?? "100", 10);
951
+ return l - a;
952
+ }), e.lightDomButtons.forEach((s) => {
953
+ s.setAttribute("slot", "toolbar");
954
+ });
955
+ }
956
+ function Ve(o, e, t, n) {
957
+ const i = o.querySelector(".tbw-shell-toolbar");
958
+ i && i.addEventListener("click", (r) => {
959
+ const l = r.target, a = l.closest("[data-panel]");
960
+ if (a) {
961
+ const u = a.getAttribute("data-panel");
962
+ u && n.onPanelToggle(u);
963
+ return;
964
+ }
965
+ const h = l.closest("[data-btn]");
966
+ if (h) {
967
+ const u = h.getAttribute("data-btn");
968
+ u && n.onToolbarButtonClick(u);
969
+ }
970
+ });
971
+ const s = o.querySelector(".tbw-tool-panel-close");
972
+ s && s.addEventListener("click", () => {
973
+ n.onPanelClose();
974
+ });
975
+ }
976
+ function Ge(o, e, t) {
977
+ const n = [...e?.header?.toolbarButtons ?? [], ...t.toolbarButtons.values()];
978
+ for (const i of n) {
979
+ const s = o.querySelector(`[data-btn-slot="${i.id}"]`);
980
+ if (!s) continue;
981
+ const r = t.toolbarButtonCleanups.get(i.id);
982
+ if (r && (r(), t.toolbarButtonCleanups.delete(i.id)), i.element)
983
+ s.appendChild(i.element);
984
+ else if (i.render) {
985
+ const l = i.render(s);
986
+ l && t.toolbarButtonCleanups.set(i.id, l);
987
+ }
988
+ }
989
+ }
990
+ function te(o, e) {
991
+ const t = o.querySelector(".tbw-shell-content");
992
+ if (!t) return;
993
+ const n = [...e.headerContents.values()].sort((s, r) => (s.order ?? 100) - (r.order ?? 100)), i = t.querySelector('slot[name="header-content"]');
994
+ for (const s of n) {
995
+ const r = e.headerContentCleanups.get(s.id);
996
+ r && (r(), e.headerContentCleanups.delete(s.id));
997
+ let l = t.querySelector(`[data-header-content="${s.id}"]`);
998
+ l || (l = document.createElement("div"), l.setAttribute("data-header-content", s.id), i ? t.insertBefore(l, i) : t.appendChild(l));
999
+ const a = s.render(l);
1000
+ a && e.headerContentCleanups.set(s.id, a);
1001
+ }
1002
+ }
1003
+ function Ue(o, e) {
1004
+ if (!e.activePanel) return;
1005
+ const t = e.toolPanels.get(e.activePanel);
1006
+ if (!t) return;
1007
+ const n = o.querySelector(".tbw-tool-panel-content");
1008
+ if (!n) return;
1009
+ e.activePanelCleanup && (e.activePanelCleanup(), e.activePanelCleanup = null), n.innerHTML = "";
1010
+ const i = t.render(n);
1011
+ i && (e.activePanelCleanup = i);
1012
+ }
1013
+ function oe(o, e) {
1014
+ o.querySelectorAll("[data-panel]").forEach((n) => {
1015
+ const s = n.getAttribute("data-panel") === e.activePanel;
1016
+ n.classList.toggle("active", s), n.setAttribute("aria-pressed", String(s));
1017
+ });
1018
+ }
1019
+ function ne(o, e) {
1020
+ const t = o.querySelector(".tbw-tool-panel");
1021
+ if (!t) return;
1022
+ const n = e.activePanel !== null;
1023
+ if (t.classList.toggle("open", n), n && e.activePanel) {
1024
+ const i = e.toolPanels.get(e.activePanel), s = t.querySelector(".tbw-tool-panel-title");
1025
+ s && (s.textContent = i?.title ?? ""), t.setAttribute("aria-label", `${i?.title ?? "Tool"} panel`), t.id = `tbw-panel-${e.activePanel}`;
1026
+ }
1027
+ }
1028
+ function Xe(o, e) {
1029
+ const t = [];
1030
+ for (const n of o?.header?.toolbarButtons ?? [])
1031
+ t.push({
1032
+ id: n.id,
1033
+ label: n.label,
1034
+ disabled: n.disabled ?? !1,
1035
+ source: "config"
1036
+ });
1037
+ for (const n of e.toolbarButtons.values())
1038
+ t.push({
1039
+ id: n.id,
1040
+ label: n.label,
1041
+ disabled: n.disabled ?? !1,
1042
+ source: "config"
1043
+ });
1044
+ for (let n = 0; n < e.lightDomButtons.length; n++) {
1045
+ const s = e.lightDomButtons[n].querySelector("button");
1046
+ t.push({
1047
+ id: `light-dom-${n}`,
1048
+ label: s?.getAttribute("title") ?? s?.getAttribute("aria-label") ?? "",
1049
+ disabled: s?.disabled ?? !1,
1050
+ source: "light-dom"
1051
+ });
1052
+ }
1053
+ for (const n of e.toolPanels.values())
1054
+ t.push({
1055
+ id: `panel-toggle-${n.id}`,
1056
+ label: n.tooltip ?? n.title,
1057
+ disabled: !1,
1058
+ source: "panel-toggle",
1059
+ panelId: n.id
1060
+ });
1061
+ return t;
1062
+ }
1063
+ function je(o) {
1064
+ for (const e of o.headerContentCleanups.values())
1065
+ e();
1066
+ o.headerContentCleanups.clear(), o.activePanelCleanup && (o.activePanelCleanup(), o.activePanelCleanup = null);
1067
+ for (const e of o.toolbarButtonCleanups.values())
1068
+ e();
1069
+ o.toolbarButtonCleanups.clear(), o.activePanel && o.toolPanels.get(o.activePanel)?.onClose?.(), o.toolPanels.clear(), o.headerContents.clear(), o.toolbarButtons.clear(), o.lightDomButtons = [], o.lightDomHeaderContent = [], o.activePanel = null;
1070
+ }
1071
+ class Ye {
1072
+ constructor(e) {
1073
+ this.grid = e;
1074
+ }
1075
+ /** Plugin instances in order of attachment */
1076
+ plugins = [];
1077
+ /** Map from plugin class to instance for fast lookup */
1078
+ pluginMap = /* @__PURE__ */ new Map();
1079
+ /** Cell renderers registered by plugins */
1080
+ cellRenderers = /* @__PURE__ */ new Map();
1081
+ /** Header renderers registered by plugins */
1082
+ headerRenderers = /* @__PURE__ */ new Map();
1083
+ /** Cell editors registered by plugins */
1084
+ cellEditors = /* @__PURE__ */ new Map();
1085
+ /**
1086
+ * Attach all plugins from the config.
1087
+ */
1088
+ attachAll(e) {
1089
+ for (const t of e)
1090
+ this.attach(t);
1091
+ }
1092
+ /**
1093
+ * Attach a plugin to this grid.
1094
+ */
1095
+ attach(e) {
1096
+ if (this.pluginMap.set(e.constructor, e), this.plugins.push(e), e.cellRenderers)
1097
+ for (const [t, n] of Object.entries(e.cellRenderers))
1098
+ this.cellRenderers.set(t, n);
1099
+ if (e.headerRenderers)
1100
+ for (const [t, n] of Object.entries(e.headerRenderers))
1101
+ this.headerRenderers.set(t, n);
1102
+ if (e.cellEditors)
1103
+ for (const [t, n] of Object.entries(e.cellEditors))
1104
+ this.cellEditors.set(t, n);
1105
+ e.attach(this.grid);
1106
+ }
1107
+ /**
1108
+ * Detach all plugins and clean up.
1109
+ */
1110
+ detachAll() {
1111
+ for (let e = this.plugins.length - 1; e >= 0; e--)
1112
+ this.plugins[e].detach();
1113
+ this.plugins = [], this.pluginMap.clear(), this.cellRenderers.clear(), this.headerRenderers.clear(), this.cellEditors.clear();
1114
+ }
1115
+ /**
1116
+ * Get a plugin instance by its class.
1117
+ */
1118
+ getPlugin(e) {
1119
+ return this.pluginMap.get(e);
1120
+ }
1121
+ /**
1122
+ * Get a plugin instance by its name.
1123
+ */
1124
+ getPluginByName(e) {
1125
+ return this.plugins.find((t) => t.name === e);
1126
+ }
1127
+ /**
1128
+ * Check if a plugin is attached.
1129
+ */
1130
+ hasPlugin(e) {
1131
+ return this.pluginMap.has(e);
1132
+ }
1133
+ /**
1134
+ * Get all attached plugins.
1135
+ */
1136
+ getAll() {
1137
+ return this.plugins;
1138
+ }
1139
+ /**
1140
+ * Get a cell renderer by type name.
1141
+ */
1142
+ getCellRenderer(e) {
1143
+ return this.cellRenderers.get(e);
1144
+ }
1145
+ /**
1146
+ * Get a header renderer by type name.
1147
+ */
1148
+ getHeaderRenderer(e) {
1149
+ return this.headerRenderers.get(e);
1150
+ }
1151
+ /**
1152
+ * Get a cell editor by type name.
1153
+ */
1154
+ getCellEditor(e) {
1155
+ return this.cellEditors.get(e);
1156
+ }
1157
+ /**
1158
+ * Get all CSS styles from all plugins.
1159
+ */
1160
+ getAllStyles() {
1161
+ return this.plugins.filter((e) => e.styles).map((e) => e.styles).join(`
1162
+ `);
1163
+ }
1164
+ // ===== Hook execution methods =====
1165
+ /**
1166
+ * Execute processRows hook on all plugins.
1167
+ */
1168
+ processRows(e) {
1169
+ let t = [...e];
1170
+ for (const n of this.plugins)
1171
+ n.processRows && (t = n.processRows(t));
1172
+ return t;
1173
+ }
1174
+ /**
1175
+ * Execute processColumns hook on all plugins.
1176
+ */
1177
+ processColumns(e) {
1178
+ let t = [...e];
1179
+ for (const n of this.plugins)
1180
+ n.processColumns && (t = n.processColumns(t));
1181
+ return t;
1182
+ }
1183
+ /**
1184
+ * Execute beforeRender hook on all plugins.
1185
+ */
1186
+ beforeRender() {
1187
+ for (const e of this.plugins)
1188
+ e.beforeRender?.();
1189
+ }
1190
+ /**
1191
+ * Execute afterRender hook on all plugins.
1192
+ */
1193
+ afterRender() {
1194
+ for (const e of this.plugins)
1195
+ e.afterRender?.();
1196
+ }
1197
+ /**
1198
+ * Execute renderRow hook on all plugins.
1199
+ * Returns true if any plugin handled the row.
1200
+ */
1201
+ renderRow(e, t, n) {
1202
+ for (const i of this.plugins)
1203
+ if (i.renderRow?.(e, t, n))
1204
+ return !0;
1205
+ return !1;
1206
+ }
1207
+ /**
1208
+ * Execute onKeyDown hook on all plugins.
1209
+ * Returns true if any plugin handled the event.
1210
+ */
1211
+ onKeyDown(e) {
1212
+ for (const t of this.plugins)
1213
+ if (t.onKeyDown?.(e))
1214
+ return !0;
1215
+ return !1;
1216
+ }
1217
+ /**
1218
+ * Execute onCellClick hook on all plugins.
1219
+ * Returns true if any plugin handled the event.
1220
+ */
1221
+ onCellClick(e) {
1222
+ for (const t of this.plugins)
1223
+ if (t.onCellClick?.(e))
1224
+ return !0;
1225
+ return !1;
1226
+ }
1227
+ /**
1228
+ * Execute onRowClick hook on all plugins.
1229
+ * Returns true if any plugin handled the event.
1230
+ */
1231
+ onRowClick(e) {
1232
+ for (const t of this.plugins)
1233
+ if (t.onRowClick?.(e))
1234
+ return !0;
1235
+ return !1;
1236
+ }
1237
+ /**
1238
+ * Execute onHeaderClick hook on all plugins.
1239
+ * Returns true if any plugin handled the event.
1240
+ */
1241
+ onHeaderClick(e) {
1242
+ for (const t of this.plugins)
1243
+ if (t.onHeaderClick?.(e))
1244
+ return !0;
1245
+ return !1;
1246
+ }
1247
+ /**
1248
+ * Execute onScroll hook on all plugins.
1249
+ */
1250
+ onScroll(e) {
1251
+ for (const t of this.plugins)
1252
+ t.onScroll?.(e);
1253
+ }
1254
+ /**
1255
+ * Execute onCellMouseDown hook on all plugins.
1256
+ * Returns true if any plugin handled the event.
1257
+ */
1258
+ onCellMouseDown(e) {
1259
+ for (const t of this.plugins)
1260
+ if (t.onCellMouseDown?.(e))
1261
+ return !0;
1262
+ return !1;
1263
+ }
1264
+ /**
1265
+ * Execute onCellMouseMove hook on all plugins.
1266
+ * Returns true if any plugin handled the event.
1267
+ */
1268
+ onCellMouseMove(e) {
1269
+ for (const t of this.plugins)
1270
+ if (t.onCellMouseMove?.(e))
1271
+ return !0;
1272
+ return !1;
1273
+ }
1274
+ /**
1275
+ * Execute onCellMouseUp hook on all plugins.
1276
+ * Returns true if any plugin handled the event.
1277
+ */
1278
+ onCellMouseUp(e) {
1279
+ for (const t of this.plugins)
1280
+ if (t.onCellMouseUp?.(e))
1281
+ return !0;
1282
+ return !1;
1283
+ }
1284
+ /**
1285
+ * Collect context menu items from all plugins.
1286
+ */
1287
+ getContextMenuItems(e) {
1288
+ const t = [];
1289
+ for (const n of this.plugins) {
1290
+ const i = n.getContextMenuItems?.(e);
1291
+ i && t.push(...i);
1292
+ }
1293
+ return t;
1294
+ }
1295
+ // ===== Shell Integration Hooks =====
1296
+ /**
1297
+ * Collect tool panels from all plugins.
1298
+ * Returns panels sorted by order (ascending).
1299
+ */
1300
+ getToolPanels() {
1301
+ const e = [];
1302
+ for (const t of this.plugins) {
1303
+ const n = t.getToolPanel?.();
1304
+ n && e.push({ plugin: t, panel: n });
1305
+ }
1306
+ return e.sort((t, n) => (t.panel.order ?? 0) - (n.panel.order ?? 0));
1307
+ }
1308
+ /**
1309
+ * Collect header contents from all plugins.
1310
+ * Returns contents sorted by order (ascending).
1311
+ */
1312
+ getHeaderContents() {
1313
+ const e = [];
1314
+ for (const t of this.plugins) {
1315
+ const n = t.getHeaderContent?.();
1316
+ n && e.push({ plugin: t, content: n });
1317
+ }
1318
+ return e.sort((t, n) => (t.content.order ?? 0) - (n.content.order ?? 0));
1319
+ }
1320
+ }
1321
+ class q extends HTMLElement {
1322
+ // TODO: Rename to 'data-grid' when migration is complete
1323
+ static tagName = "tbw-grid";
1324
+ #t;
1325
+ #S = !1;
1326
+ // ---------------- Ready Promise ----------------
1327
+ #D;
1328
+ #H;
1329
+ // ================== INPUT PROPERTIES ==================
1330
+ // These backing fields store raw user input. They are merged into
1331
+ // #effectiveConfig by #mergeEffectiveConfig(). Never read directly
1332
+ // for rendering logic - always use effectiveConfig or derived state.
1333
+ #s = [];
1334
+ #r;
1335
+ #b;
1336
+ #v;
1337
+ #C;
1338
+ // ================== SINGLE SOURCE OF TRUTH ==================
1339
+ // All input sources converge here. This is the canonical config
1340
+ // that all rendering and logic should read from.
1341
+ #n = {};
1342
+ #h = !1;
1343
+ #x = 0;
1344
+ #y = null;
1345
+ #E = !1;
1346
+ // Cached flag for plugin scroll handlers
1347
+ #T;
1348
+ // Cached hook to avoid closures
1349
+ #u;
1350
+ #f;
1351
+ #R = !1;
1352
+ #p;
1353
+ #w;
1354
+ // ---------------- Plugin System ----------------
1355
+ #o;
1356
+ // ---------------- Column State ----------------
1357
+ #L;
1358
+ #c;
1359
+ // ---------------- Shell State ----------------
1360
+ #e = $e();
1361
+ #l = !1;
1362
+ // ================== DERIVED STATE ==================
1363
+ // _rows: result of applying plugin processRows hooks
1364
+ _rows = [];
1365
+ // _columns is a getter/setter that operates on effectiveConfig.columns
1366
+ // This ensures effectiveConfig.columns is the single source of truth for columns
1367
+ // _columns always contains ALL columns (including hidden)
1368
+ get _columns() {
1369
+ return this.#n.columns ?? [];
1370
+ }
1371
+ set _columns(e) {
1372
+ this.#n.columns = e;
1373
+ }
1374
+ // visibleColumns returns only visible columns for rendering
1375
+ // This is what header/row rendering should use
1376
+ get visibleColumns() {
1377
+ return this._columns.filter((e) => !e.hidden);
1378
+ }
1379
+ // ================== RUNTIME STATE ==================
1380
+ // User-driven state changes at runtime (sort, etc.)
1381
+ // Visibility is stored in effectiveConfig.columns[].hidden
1382
+ rowPool = [];
1383
+ __rowRenderEpoch = 0;
1384
+ activeEditRows = -1;
1385
+ resizeController;
1386
+ __didInitialAutoSize = !1;
1387
+ __lightDomColumnsCache;
1388
+ __originalColumnNodes;
1389
+ headerRowEl;
1390
+ bodyEl;
1391
+ virtualization = {
1392
+ enabled: !0,
1393
+ rowHeight: 28,
1394
+ // Initial state - will recalculate after first render
1395
+ bypassThreshold: 24,
1396
+ // Skip virtualization if <= this many rows (saves overhead)
1397
+ start: 0,
1398
+ end: 0,
1399
+ container: null,
1400
+ // Faux scrollbar element
1401
+ viewportEl: null,
1402
+ // Rows viewport for measuring visible height
1403
+ totalHeightEl: null
1404
+ // Spacer for virtual height
1405
+ };
1406
+ sortState = null;
1407
+ __originalOrder = [];
1408
+ focusRow = 0;
1409
+ focusCol = 0;
1410
+ gridTemplate = "";
1411
+ rowEditSnapshots = /* @__PURE__ */ new Map();
1412
+ _changedRowIndices = /* @__PURE__ */ new Set();
1413
+ // ---------------- Public API Props (getters/setters) ----------------
1414
+ // Getters return the EFFECTIVE value (after merging), not the raw input.
1415
+ // This is what consumers and plugins need - the current resolved state.
1416
+ // Setters update input properties which trigger re-merge into effectiveConfig.
1417
+ get rows() {
1418
+ return this._rows;
1419
+ }
1420
+ set rows(e) {
1421
+ const t = this.#s;
1422
+ this.#s = e, t !== e && this.#j();
1423
+ }
1424
+ /**
1425
+ * Get the original unfiltered/unprocessed rows.
1426
+ * Use this when you need access to all source data regardless of active filters.
1427
+ */
1428
+ get sourceRows() {
1429
+ return this.#s;
1430
+ }
1431
+ get columns() {
1432
+ return [...this._columns];
1433
+ }
1434
+ set columns(e) {
1435
+ const t = this.#r;
1436
+ this.#r = e, t !== e && this.#Y();
1437
+ }
1438
+ get gridConfig() {
1439
+ return this.#n;
1440
+ }
1441
+ set gridConfig(e) {
1442
+ const t = this.#b;
1443
+ this.#b = e, t !== e && this.#Z();
1444
+ }
1445
+ get fitMode() {
1446
+ return this.#n.fitMode ?? "stretch";
1447
+ }
1448
+ set fitMode(e) {
1449
+ const t = this.#v;
1450
+ this.#v = e, t !== e && this.#U();
1451
+ }
1452
+ get editOn() {
1453
+ return this.#n.editOn;
1454
+ }
1455
+ set editOn(e) {
1456
+ const t = this.#C;
1457
+ this.#C = e, t !== e && this.#X();
1458
+ }
1459
+ // Effective config accessor for internal modules and plugins
1460
+ // Returns the merged config (single source of truth) before plugin processing
1461
+ // Use this when you need the raw merged config (e.g., for column definitions including hidden)
1462
+ get effectiveConfig() {
1463
+ return this.#n;
1464
+ }
1465
+ constructor() {
1466
+ super(), this.#t = this.attachShadow({ mode: "open" }), this.#W(), this.#D = new Promise((e) => this.#H = e);
1467
+ }
1468
+ #W() {
1469
+ const e = new CSSStyleSheet();
1470
+ e.replaceSync(we), this.#t.adoptedStyleSheets = [e];
1471
+ }
1472
+ // ---------------- Plugin System ----------------
1473
+ /**
1474
+ * Get a plugin instance by its class.
1475
+ * Used by plugins for inter-plugin communication.
1476
+ */
1477
+ getPlugin(e) {
1478
+ return this.#o?.getPlugin(e);
1479
+ }
1480
+ /**
1481
+ * Get a plugin instance by its name.
1482
+ * Used for loose coupling between plugins (avoids static imports).
1483
+ */
1484
+ getPluginByName(e) {
1485
+ return this.#o?.getPluginByName(e);
1486
+ }
1487
+ /**
1488
+ * Request a full re-render of the grid.
1489
+ * Called by plugins when they need the grid to update.
1490
+ * Note: This does NOT reset plugin state - just re-processes rows/columns and renders.
1491
+ */
1492
+ requestRender() {
1493
+ this.#A(), this.#k(), this.#_(), this.updateTemplate(), this.refreshVirtualWindow(!0);
1494
+ }
1495
+ /**
1496
+ * Request a lightweight style update without rebuilding DOM.
1497
+ * Called by plugins when they only need to update CSS classes/styles.
1498
+ * This runs all plugin afterRender hooks without rebuilding row/column DOM.
1499
+ */
1500
+ requestAfterRender() {
1501
+ this.#g();
1502
+ }
1503
+ /**
1504
+ * Initialize plugin system with instances from config.
1505
+ * Plugins are class instances passed in gridConfig.plugins[].
1506
+ */
1507
+ #z() {
1508
+ this.#o = new Ye(this);
1509
+ const e = this.#n?.plugins, t = Array.isArray(e) ? e : [];
1510
+ this.#o.attachAll(t);
1511
+ }
1512
+ /**
1513
+ * Inject all plugin styles into the shadow DOM.
1514
+ * Must be called after #render() since innerHTML wipes existing content.
1515
+ */
1516
+ #N() {
1517
+ const e = this.#o?.getAllStyles() ?? "";
1518
+ if (e) {
1519
+ const t = document.createElement("style");
1520
+ t.setAttribute("data-plugin", "all"), t.textContent = e, this.#t.appendChild(t);
1521
+ }
1522
+ }
1523
+ /**
1524
+ * Update plugins when grid config changes.
1525
+ * With class-based plugins, we need to detach old and attach new.
1526
+ */
1527
+ #q() {
1528
+ this.#o && this.#o.detachAll(), this.#z(), this.#N(), this.#E = this.#o?.getAll().some((e) => e.onScroll) ?? !1;
1529
+ }
1530
+ /**
1531
+ * Clean up plugin states when grid disconnects.
1532
+ */
1533
+ #F() {
1534
+ this.#o?.detachAll();
1535
+ }
1536
+ /**
1537
+ * Collect tool panels and header content from all plugins.
1538
+ * Called after plugins are attached but before render.
1539
+ */
1540
+ #V() {
1541
+ if (!this.#o) return;
1542
+ const e = this.#o.getToolPanels();
1543
+ for (const { panel: n } of e)
1544
+ this.#e.toolPanels.has(n.id) || this.#e.toolPanels.set(n.id, n);
1545
+ const t = this.#o.getHeaderContents();
1546
+ for (const { content: n } of t)
1547
+ this.#e.headerContents.has(n.id) || this.#e.headerContents.set(n.id, n);
1548
+ }
1549
+ // ---------------- Lifecycle ----------------
1550
+ connectedCallback() {
1551
+ this.hasAttribute("tabindex") || (this.tabIndex = 0), this._rows = Array.isArray(this.#s) ? [...this.#s] : [], this.#d(), this.#z(), this.#V(), this.#S || (this.#K(), this.#N(), this.#S = !0), this.#I();
1552
+ }
1553
+ disconnectedCallback() {
1554
+ this.#F(), je(this.#e), this.#l = !1, this.#u && (document.removeEventListener("keydown", this.#u, !0), this.#u = void 0), this.#f && (document.removeEventListener("mousedown", this.#f, !1), this.#f = void 0), this.#p && (document.removeEventListener("mousemove", this.#p), this.#p = void 0), this.#w && (document.removeEventListener("mouseup", this.#w), this.#w = void 0), this.resizeController && this.resizeController.dispose(), this.#h = !1;
1555
+ }
1556
+ #I() {
1557
+ const t = this.#t.querySelector(".tbw-grid-content") ?? this.#t.querySelector(".tbw-grid-root");
1558
+ if (this.headerRowEl = t?.querySelector(".header-row"), this.virtualization.totalHeightEl = t?.querySelector(".faux-vscroll-spacer"), this.virtualization.viewportEl = t?.querySelector(".rows-viewport"), this.bodyEl = t?.querySelector(".rows"), this.#l) {
1559
+ te(this.#t, this.#e), Ge(this.#t, this.#n?.shell, this.#e);
1560
+ const s = this.#n?.shell?.toolPanel?.defaultOpen;
1561
+ s && this.#e.toolPanels.has(s) && this.openToolPanel(s);
1562
+ }
1563
+ this.setAttribute("data-upgraded", ""), this.hasAttribute("role") || this.setAttribute("role", "grid"), this.#h = !0, this.#a(), this.addEventListener("keydown", (s) => He(this, s)), this.#u || (this.#u = (s) => {
1564
+ s.key === "Escape" && this.activeEditRows !== -1 && this.#O(this.activeEditRows, !0);
1565
+ }, document.addEventListener("keydown", this.#u, !0)), this.#f || (this.#f = (s) => {
1566
+ if (this.activeEditRows === -1) return;
1567
+ const r = this.findRenderedRowElement(this.activeEditRows);
1568
+ !r || (s.composedPath && s.composedPath() || []).includes(r) || this.#O(this.activeEditRows, !1);
1569
+ }, document.addEventListener("mousedown", this.#f, !1));
1570
+ const n = t?.querySelector(".faux-vscroll"), i = t?.querySelector(".rows");
1571
+ if (this.virtualization.container = n ?? this, this.#E = this.#o?.getAll().some((s) => s.onScroll) ?? !1, n && i) {
1572
+ n.addEventListener(
1573
+ "scroll",
1574
+ () => {
1575
+ if (!this.virtualization.enabled && !this.#E) return;
1576
+ const r = n.scrollTop, l = this.virtualization.rowHeight, a = -(r % l);
1577
+ i.style.transform = `translateY(${a}px)`, this.#y = r, this.#x || (this.#x = requestAnimationFrame(() => {
1578
+ this.#x = 0, this.#y !== null && (this.#te(this.#y), this.#y = null);
1579
+ }));
1580
+ },
1581
+ { passive: !0 }
1582
+ );
1583
+ const s = t?.querySelector(".rows-body");
1584
+ s && s.addEventListener(
1585
+ "wheel",
1586
+ (r) => {
1587
+ r.preventDefault(), n.scrollTop += r.deltaY;
1588
+ },
1589
+ { passive: !1 }
1590
+ );
1591
+ }
1592
+ this.resizeController = Be(this), this.#t.addEventListener("mousedown", (s) => this.#oe(s)), this.#p || (this.#p = (s) => this.#ne(s), document.addEventListener("mousemove", this.#p)), this.#w || (this.#w = (s) => this.#ie(s), document.addEventListener("mouseup", this.#w)), this.virtualization.enabled && requestAnimationFrame(() => this.refreshVirtualWindow(!0)), requestAnimationFrame(() => {
1593
+ const s = this.bodyEl.querySelector(".data-grid-row");
1594
+ if (s) {
1595
+ const r = s.getBoundingClientRect().height;
1596
+ r && Math.abs(r - this.virtualization.rowHeight) > 0.1 && (this.virtualization.rowHeight = r, this.refreshVirtualWindow(!0));
1597
+ }
1598
+ }), queueMicrotask(() => this.#G()), requestAnimationFrame(() => requestAnimationFrame(() => this.#H?.()));
1599
+ }
1600
+ // ---------------- Event Emitters ----------------
1601
+ #i(e, t) {
1602
+ this.dispatchEvent(new CustomEvent(e, { detail: t, bubbles: !0, composed: !0 }));
1603
+ }
1604
+ emitCellCommit(e) {
1605
+ this.#i("cell-commit", e);
1606
+ }
1607
+ emitRowCommit(e) {
1608
+ this.#i("row-commit", e);
1609
+ }
1610
+ emitSortChange(e) {
1611
+ this.#i("sort-change", e);
1612
+ }
1613
+ emitColumnResize(e) {
1614
+ this.#i("column-resize", e);
1615
+ }
1616
+ emitActivateCell(e) {
1617
+ this.#i("activate-cell", e);
1618
+ }
1619
+ /** Update ARIA selection attributes on rendered rows/cells */
1620
+ #G() {
1621
+ this.bodyEl?.querySelectorAll(".data-grid-row")?.forEach((t, n) => {
1622
+ const i = n === this.focusRow;
1623
+ t.setAttribute("aria-selected", String(i)), t.querySelectorAll(".cell").forEach((s, r) => {
1624
+ s.setAttribute("aria-selected", String(i && r === this.focusCol));
1625
+ });
1626
+ });
1627
+ }
1628
+ // ---------------- Watch Handlers ----------------
1629
+ #U() {
1630
+ if (!this.#h) return;
1631
+ this.#d(), this.#n.fitMode === "fixed" ? (this.__didInitialAutoSize = !1, this.#B()) : (this._columns.forEach((t) => {
1632
+ !t.__userResized && t.__autoSized && delete t.width;
1633
+ }), this.updateTemplate());
1634
+ }
1635
+ #X() {
1636
+ this.#h && (this.#d(), this.rowPool.length = 0, this.bodyEl && (this.bodyEl.innerHTML = ""), this.__rowRenderEpoch++, this.refreshVirtualWindow(!0));
1637
+ }
1638
+ #j() {
1639
+ this._rows = Array.isArray(this.#s) ? [...this.#s] : [], this.#A(), !this.#r || Array.isArray(this.#r) && this.#r.length === 0 ? this.#a() : this.refreshVirtualWindow(!0);
1640
+ }
1641
+ #Y() {
1642
+ j(this), this.#h && (this.#d(), this.#a());
1643
+ }
1644
+ #Z() {
1645
+ this.#h && (this.#d(), this.#q(), this.#A(), this.#k(), this.#_(), this.updateTemplate(), this.refreshVirtualWindow(!0));
1646
+ }
1647
+ // ---------------- Helper Wrappers ----------------
1648
+ #J() {
1649
+ Oe(this);
1650
+ }
1651
+ #_() {
1652
+ V(this);
1653
+ }
1654
+ updateTemplate() {
1655
+ he(this);
1656
+ }
1657
+ #B() {
1658
+ Me(this);
1659
+ }
1660
+ #k() {
1661
+ if (this.#o) {
1662
+ const e = this._columns.filter((n) => !n.hidden), t = this.#o.processColumns([...e]);
1663
+ if (t !== e) {
1664
+ const n = new Map(t.map((s, r) => [s.field, { col: s, order: r }])), i = this._columns.map((s) => {
1665
+ if (s.hidden) return s;
1666
+ const r = n.get(s.field);
1667
+ return r ? r.col : s;
1668
+ });
1669
+ this._columns = i;
1670
+ }
1671
+ }
1672
+ }
1673
+ /** Execute all plugin afterRender hooks */
1674
+ #g() {
1675
+ this.#o?.afterRender();
1676
+ }
1677
+ /** Recompute row model via plugin hooks (grouping, tree, filtering, etc.). */
1678
+ #A() {
1679
+ j(this);
1680
+ const e = Array.isArray(this.#s) ? [...this.#s] : [], t = this.#o?.processRows(e) ?? e;
1681
+ this._rows = t;
1682
+ }
1683
+ /**
1684
+ * Build the canonical effective configuration by merging all input sources.
1685
+ *
1686
+ * This is the **single source of truth** for the grid's configuration.
1687
+ * All inputs (gridConfig, light DOM, individual props) converge here.
1688
+ *
1689
+ * **Precedence (lowest → highest):**
1690
+ * 1. `gridConfig` property - base config object
1691
+ * 2. Light DOM `<tbw-grid-column>` elements - declarative columns
1692
+ * 3. `columns` property - programmatic columns override
1693
+ * 4. Inferred columns - auto-detected from row data
1694
+ * 5. Individual props (`fitMode`, `editOn`) - convenience overrides
1695
+ *
1696
+ * After this method runs:
1697
+ * - `#effectiveConfig` contains the merged result
1698
+ * - `_columns` is NOT set here (done by #getColumnConfiguration + #processColumns)
1699
+ * - Plugins receive config via their attach() method
1700
+ */
1701
+ #d() {
1702
+ const e = this.#b ? { ...this.#b } : {};
1703
+ let t = Array.isArray(e.columns) ? [...e.columns] : [];
1704
+ const n = (this.__lightDomColumnsCache || []).map((i) => ({
1705
+ ...i
1706
+ }));
1707
+ if (n.length) {
1708
+ const i = {};
1709
+ t.forEach((s) => i[s.field] = s), n.forEach((s) => {
1710
+ const r = i[s.field];
1711
+ r ? (s.header && !r.header && (r.header = s.header), s.type && !r.type && (r.type = s.type), r.sortable = r.sortable || s.sortable, s.resizable && (r.resizable = !0), s.editable && (r.editable = !0)) : (t.push(s), i[s.field] = s);
1712
+ });
1713
+ }
1714
+ if (this.#r && this.#r.length && (t = [...this.#r]), (!t || t.length === 0) && this._rows.length && (t = ce(this._rows).columns), t.length) {
1715
+ t.forEach((r) => {
1716
+ r.sortable === void 0 && (r.sortable = !0), r.resizable === void 0 && (r.resizable = !0);
1717
+ });
1718
+ const i = this.#n.columns;
1719
+ i?.some((r) => r.__compiledView || r.__compiledEditor) ? e.columns = i : e.columns = t;
1720
+ } else {
1721
+ const i = this.#n.columns;
1722
+ i?.some((s) => s.__compiledView || s.__compiledEditor) && (e.columns = i);
1723
+ }
1724
+ this.#v && (e.fitMode = this.#v), e.fitMode || (e.fitMode = "stretch"), this.#C && (e.editOn = this.#C), e.columnState && !this.#c && (this.#c = e.columnState), this.#n = e, e.fitMode === "fixed" && this._columns.forEach((i) => {
1725
+ i.width == null && (i.width = 80);
1726
+ });
1727
+ }
1728
+ // ---------------- Delegate Wrappers ----------------
1729
+ #P(e, t, n = this.__rowRenderEpoch) {
1730
+ this.#T || (this.#T = (i, s, r) => this.#o?.renderRow(i, s, r) ?? !1), qe(this, e, t, n, this.#T);
1731
+ }
1732
+ #Q(e, t) {
1733
+ A(this, e, t);
1734
+ }
1735
+ #O(e, t) {
1736
+ Ie(this, e, t);
1737
+ }
1738
+ // ---------------- Core Helpers ----------------
1739
+ #a() {
1740
+ if (!this.isConnected || !this.headerRowEl || !this.bodyEl)
1741
+ return;
1742
+ const e = this.#b?.columns || this.#r || [];
1743
+ if (e.length) {
1744
+ const n = new Map(this._columns.filter((s) => s.hidden).map((s) => [s.field, !0])), i = e.map((s) => ({
1745
+ ...s,
1746
+ hidden: n.get(s.field) ?? s.hidden
1747
+ }));
1748
+ this._columns = i;
1749
+ }
1750
+ if (this.#J(), this.#d(), this.#q(), this.#A(), this.#k(), this.#c) {
1751
+ const n = this.#c;
1752
+ this.#c = void 0, this.#$(n);
1753
+ }
1754
+ this.#_(), this.updateTemplate(), this.refreshVirtualWindow(!0), this.#n.fitMode === "fixed" && !this.__didInitialAutoSize && requestAnimationFrame(() => this.#B()), this.bodyEl && (this.bodyEl.style.display = "", this.bodyEl.style.gridTemplateColumns = ""), queueMicrotask(() => this.#g());
1755
+ }
1756
+ /** Internal method to apply column state without triggering setup loop */
1757
+ #$(e) {
1758
+ const t = this.#n.columns ?? [], n = this.#o?.getAll() ?? [];
1759
+ ge(this, e, t, n);
1760
+ for (const i of e.columns) {
1761
+ const s = t.find((r) => r.field === i.field);
1762
+ s && (s.hidden = !i.visible);
1763
+ }
1764
+ }
1765
+ #ee() {
1766
+ return this._rows.length <= this.virtualization.bypassThreshold;
1767
+ }
1768
+ #te(e) {
1769
+ if (this.refreshVirtualWindow(!1), this.#E) {
1770
+ const t = this.virtualization.container, n = {
1771
+ scrollTop: e,
1772
+ scrollLeft: t?.scrollLeft ?? 0,
1773
+ scrollHeight: t?.scrollHeight ?? 0,
1774
+ scrollWidth: t?.scrollWidth ?? 0,
1775
+ clientHeight: t?.clientHeight ?? 0,
1776
+ clientWidth: t?.clientWidth ?? 0,
1777
+ originalEvent: new Event("scroll")
1778
+ };
1779
+ this.#o?.onScroll(n);
1780
+ }
1781
+ }
1782
+ findHeaderRow() {
1783
+ return this.#t.querySelector(".header-row");
1784
+ }
1785
+ findRenderedRowElement(e) {
1786
+ return Array.from(this.bodyEl.querySelectorAll(".data-grid-row")).find((t) => {
1787
+ const n = t.querySelector(".cell[data-row]");
1788
+ return n && Number(n.getAttribute("data-row")) === e;
1789
+ }) || null;
1790
+ }
1791
+ /**
1792
+ * Dispatch a cell click event to the plugin system.
1793
+ * Returns true if any plugin handled the event.
1794
+ */
1795
+ dispatchCellClick(e, t, n, i) {
1796
+ const s = this._rows[t], r = this._columns[n];
1797
+ if (!s || !r) return !1;
1798
+ const l = {
1799
+ row: s,
1800
+ rowIndex: t,
1801
+ colIndex: n,
1802
+ field: r.field,
1803
+ value: s[r.field],
1804
+ cellEl: i,
1805
+ originalEvent: e
1806
+ };
1807
+ return this.#o?.onCellClick(l) ?? !1;
1808
+ }
1809
+ /**
1810
+ * Dispatch a header click event to the plugin system.
1811
+ * Returns true if any plugin handled the event.
1812
+ */
1813
+ dispatchHeaderClick(e, t, n) {
1814
+ const i = this._columns[t];
1815
+ if (!i) return !1;
1816
+ const s = {
1817
+ colIndex: t,
1818
+ field: i.field,
1819
+ column: i,
1820
+ headerEl: n,
1821
+ originalEvent: e
1822
+ };
1823
+ return this.#o?.onHeaderClick(s) ?? !1;
1824
+ }
1825
+ /**
1826
+ * Dispatch a keyboard event to the plugin system.
1827
+ * Returns true if any plugin handled the event.
1828
+ */
1829
+ dispatchKeyDown(e) {
1830
+ return this.#o?.onKeyDown(e) ?? !1;
1831
+ }
1832
+ /**
1833
+ * Build a CellMouseEvent from a native MouseEvent.
1834
+ * Extracts cell/row information from the event target.
1835
+ */
1836
+ #M(e, t) {
1837
+ let n = null;
1838
+ const i = e.composedPath?.();
1839
+ if (i && i.length > 0 ? n = i[0] : n = e.target, n && !this.#t.contains(n)) {
1840
+ const p = this.#t.elementFromPoint(e.clientX, e.clientY);
1841
+ p && (n = p);
1842
+ }
1843
+ const s = n?.closest?.("[data-col]"), r = n?.closest?.(".data-grid-row"), l = n?.closest?.(".header-row");
1844
+ let a, h, u, w, c, d;
1845
+ return s && (a = parseInt(s.getAttribute("data-row") ?? "-1", 10), h = parseInt(s.getAttribute("data-col") ?? "-1", 10), a >= 0 && h >= 0 && (u = this._rows[a], d = this._columns[h], w = d?.field, c = u && w ? u[w] : void 0)), {
1846
+ type: t,
1847
+ row: u,
1848
+ rowIndex: a !== void 0 && a >= 0 ? a : void 0,
1849
+ colIndex: h !== void 0 && h >= 0 ? h : void 0,
1850
+ field: w,
1851
+ value: c,
1852
+ column: d,
1853
+ originalEvent: e,
1854
+ cellElement: s ?? void 0,
1855
+ rowElement: r ?? void 0,
1856
+ isHeader: !!l,
1857
+ cell: a !== void 0 && h !== void 0 && a >= 0 && h >= 0 ? { row: a, col: h } : void 0
1858
+ };
1859
+ }
1860
+ /**
1861
+ * Handle mousedown events and dispatch to plugin system.
1862
+ */
1863
+ #oe(e) {
1864
+ const t = this.#M(e, "mousedown");
1865
+ (this.#o?.onCellMouseDown(t) ?? !1) && (this.#R = !0);
1866
+ }
1867
+ /**
1868
+ * Handle mousemove events (only when dragging).
1869
+ */
1870
+ #ne(e) {
1871
+ if (!this.#R) return;
1872
+ const t = this.#M(e, "mousemove");
1873
+ this.#o?.onCellMouseMove(t);
1874
+ }
1875
+ /**
1876
+ * Handle mouseup events.
1877
+ */
1878
+ #ie(e) {
1879
+ if (!this.#R) return;
1880
+ const t = this.#M(e, "mouseup");
1881
+ this.#o?.onCellMouseUp(t), this.#R = !1;
1882
+ }
1883
+ // API consumed by internal utils (rows.ts)
1884
+ get changedRows() {
1885
+ return Array.from(this._changedRowIndices).map((e) => this._rows[e]);
1886
+ }
1887
+ get changedRowIndices() {
1888
+ return Array.from(this._changedRowIndices);
1889
+ }
1890
+ async resetChangedRows(e) {
1891
+ this._changedRowIndices.clear(), e || this.#i("changed-rows-reset", { rows: this.changedRows, indices: this.changedRowIndices }), this.rowPool.forEach((t) => t.classList.remove("changed"));
1892
+ }
1893
+ async beginBulkEdit(e) {
1894
+ this.#Q(e, this._rows[e]);
1895
+ }
1896
+ async commitActiveRowEdit() {
1897
+ this.activeEditRows !== -1 && this.#O(this.activeEditRows, !1);
1898
+ }
1899
+ async ready() {
1900
+ return this.#D;
1901
+ }
1902
+ async forceLayout() {
1903
+ this.#a(), await new Promise((e) => requestAnimationFrame(() => requestAnimationFrame(e)));
1904
+ }
1905
+ /** Public method: returns a frozen snapshot of the merged effective configuration */
1906
+ async getConfig() {
1907
+ return Object.freeze({ ...this.#n || {} });
1908
+ }
1909
+ // ---------------- Column Visibility API ----------------
1910
+ /**
1911
+ * Set the visibility of a column.
1912
+ * @param field - The field name of the column
1913
+ * @param visible - Whether the column should be visible
1914
+ * @returns True if visibility was changed, false if column not found or locked
1915
+ */
1916
+ setColumnVisible(e, t) {
1917
+ const n = this.#n.columns, i = n?.find((l) => l.field === e);
1918
+ if (!i || !t && i.lockVisible || !t && (n ?? []).filter((a) => !a.hidden && a.field !== e).length === 0)
1919
+ return !1;
1920
+ const s = !!i.hidden, r = !t;
1921
+ return s !== r ? (i.hidden = r, this.#i("column-visibility", {
1922
+ field: e,
1923
+ visible: t,
1924
+ visibleColumns: (n ?? []).filter((l) => !l.hidden).map((l) => l.field)
1925
+ }), this.rowPool.length = 0, this.bodyEl && (this.bodyEl.innerHTML = ""), this.__rowRenderEpoch++, this.#a(), this.requestStateChange(), !0) : !1;
1926
+ }
1927
+ /**
1928
+ * Toggle the visibility of a column.
1929
+ * @param field - The field name of the column
1930
+ * @returns True if visibility was toggled, false if column not found or locked
1931
+ */
1932
+ toggleColumnVisibility(e) {
1933
+ const i = !!this.#n.columns?.find((s) => s.field === e)?.hidden;
1934
+ return this.setColumnVisible(e, i);
1935
+ }
1936
+ /**
1937
+ * Check if a column is currently visible.
1938
+ * @param field - The field name of the column
1939
+ * @returns True if visible, false if hidden or not found
1940
+ */
1941
+ isColumnVisible(e) {
1942
+ const n = this.#n.columns?.find((i) => i.field === e);
1943
+ return n ? !n.hidden : !1;
1944
+ }
1945
+ /**
1946
+ * Show all columns.
1947
+ */
1948
+ showAllColumns() {
1949
+ const e = this.#n.columns;
1950
+ e?.some((n) => n.hidden) && (e?.forEach((n) => {
1951
+ n.hidden = !1;
1952
+ }), this.#i("column-visibility", {
1953
+ visibleColumns: (e ?? []).map((n) => n.field)
1954
+ }), this.rowPool.length = 0, this.bodyEl && (this.bodyEl.innerHTML = ""), this.__rowRenderEpoch++, this.#a(), this.requestStateChange());
1955
+ }
1956
+ /**
1957
+ * Get list of all column fields (including hidden).
1958
+ * Returns columns reflecting current display order (after reordering).
1959
+ * Hidden columns are interleaved at their original relative positions.
1960
+ * @returns Array of all field names with their visibility status
1961
+ */
1962
+ getAllColumns() {
1963
+ return (this.#n.columns ?? []).map((t) => ({
1964
+ field: t.field,
1965
+ header: t.header || t.field,
1966
+ visible: !t.hidden,
1967
+ lockVisible: t.lockVisible
1968
+ }));
1969
+ }
1970
+ /**
1971
+ * Reorder columns according to the specified field order.
1972
+ * This directly updates _columns in place without going through processColumns.
1973
+ * @param order - Array of field names in the desired order
1974
+ */
1975
+ setColumnOrder(e) {
1976
+ if (!e.length) return;
1977
+ const t = new Map(this._columns.map((i) => [i.field, i])), n = [];
1978
+ for (const i of e) {
1979
+ const s = t.get(i);
1980
+ s && (n.push(s), t.delete(i));
1981
+ }
1982
+ for (const i of t.values())
1983
+ n.push(i);
1984
+ this._columns = n, this.#_(), this.updateTemplate(), this.refreshVirtualWindow(!0);
1985
+ }
1986
+ /**
1987
+ * Get the current column order as an array of field names.
1988
+ * @returns Array of field names in display order
1989
+ */
1990
+ getColumnOrder() {
1991
+ return this._columns.map((e) => e.field);
1992
+ }
1993
+ // ---------------- Column State API ----------------
1994
+ /**
1995
+ * Get the current column state, including order, width, visibility, sort, and plugin state.
1996
+ * Returns a serializable object suitable for localStorage or database storage.
1997
+ */
1998
+ getColumnState() {
1999
+ const e = this.#o?.getAll() ?? [];
2000
+ return ae(this, e);
2001
+ }
2002
+ /**
2003
+ * Set the column state, restoring order, width, visibility, sort, and plugin state.
2004
+ * Use this to restore previously saved column state.
2005
+ */
2006
+ set columnState(e) {
2007
+ e && (this.#c = e, this.#S && this.#se(e));
2008
+ }
2009
+ /**
2010
+ * Get the current column state.
2011
+ */
2012
+ get columnState() {
2013
+ return this.getColumnState();
2014
+ }
2015
+ /**
2016
+ * Apply column state internally.
2017
+ */
2018
+ #se(e) {
2019
+ (this.#n.columns ?? []).forEach((n) => {
2020
+ n.hidden = !1;
2021
+ }), this.#$(e), this.#a();
2022
+ }
2023
+ /**
2024
+ * Request a state change event to be emitted.
2025
+ * Called internally after resize, reorder, visibility, or sort changes.
2026
+ * Plugins should call this after changing their state.
2027
+ * The event is debounced to avoid excessive events during drag operations.
2028
+ */
2029
+ requestStateChange() {
2030
+ this.#L || (this.#L = me(
2031
+ this,
2032
+ () => this.#o?.getAll() ?? [],
2033
+ (e) => this.#i("column-state-change", e)
2034
+ )), this.#L();
2035
+ }
2036
+ /**
2037
+ * Reset column state to initial configuration.
2038
+ * Clears all user modifications (order, width, visibility, sort).
2039
+ */
2040
+ resetColumnState() {
2041
+ this.#c = void 0, (this.#n.columns ?? []).forEach((n) => {
2042
+ n.hidden = !1;
2043
+ }), this.sortState = null, this.__originalOrder = [], this.#d(), this.#a();
2044
+ const t = this.#o?.getAll() ?? [];
2045
+ for (const n of t)
2046
+ if (n.applyColumnState)
2047
+ for (const i of this._columns)
2048
+ n.applyColumnState(i.field, {
2049
+ field: i.field,
2050
+ order: 0,
2051
+ visible: !0
2052
+ });
2053
+ this.requestStateChange();
2054
+ }
2055
+ // ---------------- Shell / Tool Panel API ----------------
2056
+ /**
2057
+ * Get the currently active tool panel ID, or null if none is open.
2058
+ */
2059
+ get activeToolPanel() {
2060
+ return this.#e.activePanel;
2061
+ }
2062
+ /**
2063
+ * Open a tool panel by ID.
2064
+ * Closes any currently open panel first.
2065
+ */
2066
+ openToolPanel(e) {
2067
+ if (!this.#e.toolPanels.get(e)) {
2068
+ console.warn(`[tbw-grid] Tool panel "${e}" not found`);
2069
+ return;
2070
+ }
2071
+ this.#e.activePanel && this.#e.activePanel !== e && this.closeToolPanel(), this.#e.activePanel = e, oe(this.#t, this.#e), ne(this.#t, this.#e), Ue(this.#t, this.#e), this.#i("tool-panel-open", { id: e });
2072
+ }
2073
+ /**
2074
+ * Close the currently open tool panel.
2075
+ */
2076
+ closeToolPanel() {
2077
+ if (!this.#e.activePanel) return;
2078
+ const e = this.#e.activePanel, t = this.#e.toolPanels.get(e);
2079
+ this.#e.activePanelCleanup && (this.#e.activePanelCleanup(), this.#e.activePanelCleanup = null), t?.onClose?.(), this.#e.activePanel = null, oe(this.#t, this.#e), ne(this.#t, this.#e), this.#i("tool-panel-close", { id: e });
2080
+ }
2081
+ /**
2082
+ * Toggle a tool panel open/closed.
2083
+ */
2084
+ toggleToolPanel(e) {
2085
+ this.#e.activePanel === e ? this.closeToolPanel() : this.openToolPanel(e);
2086
+ }
2087
+ /**
2088
+ * Get registered tool panel definitions.
2089
+ */
2090
+ getToolPanels() {
2091
+ return [...this.#e.toolPanels.values()];
2092
+ }
2093
+ /**
2094
+ * Register a custom tool panel (without creating a plugin).
2095
+ */
2096
+ registerToolPanel(e) {
2097
+ if (this.#e.toolPanels.has(e.id)) {
2098
+ console.warn(`[tbw-grid] Tool panel "${e.id}" already registered`);
2099
+ return;
2100
+ }
2101
+ this.#e.toolPanels.set(e.id, e), this.#l && this.#m();
2102
+ }
2103
+ /**
2104
+ * Unregister a custom tool panel.
2105
+ */
2106
+ unregisterToolPanel(e) {
2107
+ this.#e.activePanel === e && this.closeToolPanel(), this.#e.toolPanels.delete(e), this.#l && this.#m();
2108
+ }
2109
+ /**
2110
+ * Get registered header content definitions.
2111
+ */
2112
+ getHeaderContents() {
2113
+ return [...this.#e.headerContents.values()];
2114
+ }
2115
+ /**
2116
+ * Register custom header content (without creating a plugin).
2117
+ */
2118
+ registerHeaderContent(e) {
2119
+ if (this.#e.headerContents.has(e.id)) {
2120
+ console.warn(`[tbw-grid] Header content "${e.id}" already registered`);
2121
+ return;
2122
+ }
2123
+ this.#e.headerContents.set(e.id, e), this.#l && te(this.#t, this.#e);
2124
+ }
2125
+ /**
2126
+ * Unregister custom header content.
2127
+ */
2128
+ unregisterHeaderContent(e) {
2129
+ const t = this.#e.headerContentCleanups.get(e);
2130
+ t && (t(), this.#e.headerContentCleanups.delete(e)), this.#e.headerContents.get(e)?.onDestroy?.(), this.#e.headerContents.delete(e), this.#t.querySelector(`[data-header-content="${e}"]`)?.remove();
2131
+ }
2132
+ /**
2133
+ * Get all registered toolbar buttons.
2134
+ */
2135
+ getToolbarButtons() {
2136
+ return Xe(this.#n?.shell, this.#e);
2137
+ }
2138
+ /**
2139
+ * Register a custom toolbar button programmatically.
2140
+ */
2141
+ registerToolbarButton(e) {
2142
+ if (this.#e.toolbarButtons.has(e.id)) {
2143
+ console.warn(`[tbw-grid] Toolbar button "${e.id}" already registered`);
2144
+ return;
2145
+ }
2146
+ this.#e.toolbarButtons.set(e.id, e), this.#l && this.#m();
2147
+ }
2148
+ /**
2149
+ * Unregister a custom toolbar button.
2150
+ */
2151
+ unregisterToolbarButton(e) {
2152
+ const t = this.#e.toolbarButtonCleanups.get(e);
2153
+ t && (t(), this.#e.toolbarButtonCleanups.delete(e)), this.#e.toolbarButtons.delete(e), this.#l && this.#m();
2154
+ }
2155
+ /**
2156
+ * Enable/disable a toolbar button by ID.
2157
+ */
2158
+ setToolbarButtonDisabled(e, t) {
2159
+ const n = this.#e.toolbarButtons.get(e);
2160
+ n && (n.disabled = t);
2161
+ const i = this.#t.querySelector(`[data-btn="${e}"]`);
2162
+ i && (i.disabled = t);
2163
+ }
2164
+ /**
2165
+ * Re-parse light DOM shell elements and refresh shell header.
2166
+ * Call this after dynamically modifying <tbw-grid-header> children.
2167
+ */
2168
+ refreshShellHeader() {
2169
+ this.#m();
2170
+ }
2171
+ /**
2172
+ * Internal shell header refresh.
2173
+ */
2174
+ #m() {
2175
+ ee(this, this.#e), this.#K(), this.#I();
2176
+ }
2177
+ // ---------------- Virtual Window ----------------
2178
+ /**
2179
+ * Core virtualization routine. Chooses between bypass (small datasets), grouped window rendering,
2180
+ * or standard row window rendering.
2181
+ */
2182
+ refreshVirtualWindow(e = !1) {
2183
+ if (!this.bodyEl) return;
2184
+ const t = this._rows.length;
2185
+ if (!this.virtualization.enabled) {
2186
+ this.#P(0, t), this.#g();
2187
+ return;
2188
+ }
2189
+ if (this.#ee()) {
2190
+ this.virtualization.start = 0, this.virtualization.end = t, this.bodyEl.style.transform = "translateY(0px)", this.#P(0, t, this.__rowRenderEpoch), this.virtualization.totalHeightEl && (this.virtualization.totalHeightEl.style.height = `${t * this.virtualization.rowHeight}px`), this.setAttribute("aria-rowcount", String(t)), this.setAttribute("aria-colcount", String(this.visibleColumns.length)), this.#g();
2191
+ return;
2192
+ }
2193
+ const n = this.virtualization.container ?? this, s = (this.virtualization.viewportEl ?? n).clientHeight, r = this.virtualization.rowHeight, l = n.scrollTop;
2194
+ let a = Math.floor(l / r);
2195
+ a < 0 && (a = 0);
2196
+ const h = Math.ceil(s / r) + 2;
2197
+ let u = a + h;
2198
+ u > t && (u = t), this.virtualization.start = a, this.virtualization.end = u, this.virtualization.totalHeightEl && (this.virtualization.totalHeightEl.style.height = `${t * r}px`);
2199
+ const w = -(l % r);
2200
+ this.bodyEl.style.transform = `translateY(${w}px)`, this.#P(a, u, e ? ++this.__rowRenderEpoch : this.__rowRenderEpoch), this.setAttribute("aria-rowcount", String(t)), this.setAttribute("aria-colcount", String(this.visibleColumns.length)), e && this.#g();
2201
+ }
2202
+ // ---------------- Render ----------------
2203
+ #K() {
2204
+ ee(this, this.#e);
2205
+ const e = this.#n?.shell, t = Ke(e, this.#e), n = `
2206
+ <div class="tbw-scroll-area">
2207
+ <div class="rows-body-wrapper">
2208
+ <div class="rows-body">
2209
+ <div class="header">
2210
+ <div class="header-row" part="header-row"></div>
2211
+ </div>
2212
+ <div class="rows-container">
2213
+ <div class="rows-viewport">
2214
+ <div class="rows"></div>
2215
+ </div>
2216
+ </div>
2217
+ </div>
2218
+ </div>
2219
+ </div>
2220
+ <div class="faux-vscroll">
2221
+ <div class="faux-vscroll-spacer"></div>
2222
+ </div>
2223
+ `;
2224
+ if (t) {
2225
+ const i = We(e, this.#e), s = Fe(e, this.#e, n);
2226
+ this.#t.innerHTML = `
2227
+ <div class="tbw-grid-root has-shell">
2228
+ ${i}
2229
+ ${s}
2230
+ </div>
2231
+ `, this.#re(), this.#l = !0;
2232
+ } else
2233
+ this.#t.innerHTML = `
2234
+ <div class="tbw-grid-root">
2235
+ <div class="tbw-grid-content">
2236
+ ${n}
2237
+ </div>
2238
+ </div>
2239
+ `;
2240
+ }
2241
+ /**
2242
+ * Set up shell event listeners after render.
2243
+ */
2244
+ #re() {
2245
+ Ve(this.#t, this.#n?.shell, this.#e, {
2246
+ onPanelToggle: (e) => this.toggleToolPanel(e),
2247
+ onPanelClose: () => this.closeToolPanel(),
2248
+ onToolbarButtonClick: (e) => this.#le(e)
2249
+ });
2250
+ }
2251
+ /**
2252
+ * Handle toolbar button click (for config buttons with action).
2253
+ */
2254
+ #le(e) {
2255
+ const n = (this.#n?.shell?.header?.toolbarButtons ?? []).find((s) => s.id === e);
2256
+ if (n?.action) {
2257
+ n.action();
2258
+ return;
2259
+ }
2260
+ const i = this.#e.toolbarButtons.get(e);
2261
+ i?.action && i.action();
2262
+ }
2263
+ }
2264
+ customElements.get(q.tagName) || customElements.define(q.tagName, q);
2265
+ class ue {
2266
+ /** Plugin version - override in subclass if needed */
2267
+ version = "1.0.0";
2268
+ /** CSS styles to inject into the grid's shadow DOM */
2269
+ styles;
2270
+ /** Custom cell renderers keyed by type name */
2271
+ cellRenderers;
2272
+ /** Custom header renderers keyed by type name */
2273
+ headerRenderers;
2274
+ /** Custom cell editors keyed by type name */
2275
+ cellEditors;
2276
+ /** The grid instance this plugin is attached to */
2277
+ grid;
2278
+ /** Plugin configuration - merged with defaults in attach() */
2279
+ config;
2280
+ /** User-provided configuration from constructor */
2281
+ userConfig;
2282
+ /**
2283
+ * Default configuration - subclasses should override this getter.
2284
+ * Note: This must be a getter (not property initializer) for proper inheritance
2285
+ * since property initializers run after parent constructor.
2286
+ */
2287
+ get defaultConfig() {
2288
+ return {};
2289
+ }
2290
+ constructor(e = {}) {
2291
+ this.userConfig = e;
2292
+ }
2293
+ /**
2294
+ * Called when the plugin is attached to a grid.
2295
+ * Override to set up event listeners, initialize state, etc.
2296
+ */
2297
+ attach(e) {
2298
+ this.grid = e, this.config = { ...this.defaultConfig, ...this.userConfig };
2299
+ }
2300
+ /**
2301
+ * Called when the plugin is detached from a grid.
2302
+ * Override to clean up event listeners, timers, etc.
2303
+ */
2304
+ detach() {
2305
+ }
2306
+ /**
2307
+ * Get another plugin instance from the same grid.
2308
+ * Use for inter-plugin communication.
2309
+ */
2310
+ getPlugin(e) {
2311
+ return this.grid?.getPlugin(e);
2312
+ }
2313
+ /**
2314
+ * Emit a custom event from the grid.
2315
+ */
2316
+ emit(e, t) {
2317
+ this.grid?.dispatchEvent?.(new CustomEvent(e, { detail: t, bubbles: !0 }));
2318
+ }
2319
+ /**
2320
+ * Request a re-render of the grid.
2321
+ */
2322
+ requestRender() {
2323
+ this.grid?.requestRender?.();
2324
+ }
2325
+ /**
2326
+ * Request a lightweight style update without rebuilding DOM.
2327
+ * Use this instead of requestRender() when only CSS classes need updating.
2328
+ */
2329
+ requestAfterRender() {
2330
+ this.grid?.requestAfterRender?.();
2331
+ }
2332
+ /**
2333
+ * Get the current rows from the grid.
2334
+ */
2335
+ get rows() {
2336
+ return this.grid?.rows ?? [];
2337
+ }
2338
+ /**
2339
+ * Get the original unfiltered/unprocessed rows from the grid.
2340
+ * Use this when you need all source data regardless of active filters.
2341
+ */
2342
+ get sourceRows() {
2343
+ return this.grid?.sourceRows ?? [];
2344
+ }
2345
+ /**
2346
+ * Get the current columns from the grid.
2347
+ */
2348
+ get columns() {
2349
+ return this.grid?.columns ?? [];
2350
+ }
2351
+ /**
2352
+ * Get only visible columns from the grid (excludes hidden).
2353
+ * Use this for rendering that needs to match the grid template.
2354
+ */
2355
+ get visibleColumns() {
2356
+ return this.grid?.visibleColumns ?? [];
2357
+ }
2358
+ /**
2359
+ * Get the shadow root of the grid.
2360
+ */
2361
+ get shadowRoot() {
2362
+ return this.grid?.shadowRoot ?? null;
2363
+ }
2364
+ /**
2365
+ * Log a warning message.
2366
+ */
2367
+ warn(e) {
2368
+ console.warn(`[tbw-grid:${this.name}] ${e}`);
2369
+ }
2370
+ }
2371
+ function z(o) {
2372
+ return {
2373
+ startRow: Math.min(o.startRow, o.endRow),
2374
+ startCol: Math.min(o.startCol, o.endCol),
2375
+ endRow: Math.max(o.startRow, o.endRow),
2376
+ endCol: Math.max(o.startCol, o.endCol)
2377
+ };
2378
+ }
2379
+ function Ze(o) {
2380
+ const e = z(o);
2381
+ return {
2382
+ from: { row: e.startRow, col: e.startCol },
2383
+ to: { row: e.endRow, col: e.endCol }
2384
+ };
2385
+ }
2386
+ function K(o) {
2387
+ return o.map(Ze);
2388
+ }
2389
+ function Je(o, e, t) {
2390
+ const n = z(t);
2391
+ return o >= n.startRow && o <= n.endRow && e >= n.startCol && e <= n.endCol;
2392
+ }
2393
+ function ie(o, e, t) {
2394
+ return t.some((n) => Je(o, e, n));
2395
+ }
2396
+ function Qe(o) {
2397
+ const e = [], t = z(o);
2398
+ for (let n = t.startRow; n <= t.endRow; n++)
2399
+ for (let i = t.startCol; i <= t.endCol; i++)
2400
+ e.push({ row: n, col: i });
2401
+ return e;
2402
+ }
2403
+ function et(o) {
2404
+ const e = /* @__PURE__ */ new Map();
2405
+ for (const t of o)
2406
+ for (const n of Qe(t))
2407
+ e.set(`${n.row},${n.col}`, n);
2408
+ return [...e.values()];
2409
+ }
2410
+ function se(o, e) {
2411
+ return {
2412
+ startRow: o.row,
2413
+ startCol: o.col,
2414
+ endRow: e.row,
2415
+ endCol: e.col
2416
+ };
2417
+ }
2418
+ function tt(o, e, t) {
2419
+ if (o === "cell" && e.selectedCell)
2420
+ return {
2421
+ mode: o,
2422
+ ranges: [
2423
+ {
2424
+ from: { row: e.selectedCell.row, col: e.selectedCell.col },
2425
+ to: { row: e.selectedCell.row, col: e.selectedCell.col }
2426
+ }
2427
+ ]
2428
+ };
2429
+ if (o === "row" && e.selected.size > 0) {
2430
+ const n = [...e.selected].map((i) => ({
2431
+ from: { row: i, col: 0 },
2432
+ to: { row: i, col: t - 1 }
2433
+ }));
2434
+ return { mode: o, ranges: n };
2435
+ }
2436
+ return o === "range" && e.ranges.length > 0 ? { mode: o, ranges: K(e.ranges) } : { mode: o, ranges: [] };
2437
+ }
2438
+ class st extends ue {
2439
+ name = "selection";
2440
+ version = "1.0.0";
2441
+ get defaultConfig() {
2442
+ return {
2443
+ mode: "cell"
2444
+ };
2445
+ }
2446
+ // ===== Internal State =====
2447
+ /** Row selection state (row mode) */
2448
+ selected = /* @__PURE__ */ new Set();
2449
+ lastSelected = null;
2450
+ anchor = null;
2451
+ /** Range selection state (range mode) */
2452
+ ranges = [];
2453
+ activeRange = null;
2454
+ cellAnchor = null;
2455
+ isDragging = !1;
2456
+ /** Cell selection state (cell mode) */
2457
+ selectedCell = null;
2458
+ // ===== Lifecycle =====
2459
+ detach() {
2460
+ this.selected.clear(), this.ranges = [], this.activeRange = null, this.cellAnchor = null, this.isDragging = !1, this.selectedCell = null;
2461
+ }
2462
+ // ===== Event Handlers =====
2463
+ onCellClick(e) {
2464
+ const { rowIndex: t, colIndex: n, originalEvent: i } = e, { mode: s } = this.config;
2465
+ if (s === "cell")
2466
+ return this.selectedCell = { row: t, col: n }, this.emit("selection-change", this.#t()), this.requestAfterRender(), !1;
2467
+ if (s === "row")
2468
+ return this.selected.clear(), this.selected.add(t), this.lastSelected = t, this.emit("selection-change", this.#t()), this.requestAfterRender(), !1;
2469
+ if (s === "range") {
2470
+ const r = i.shiftKey, l = i.ctrlKey || i.metaKey;
2471
+ if (r && this.cellAnchor) {
2472
+ const a = se(this.cellAnchor, { row: t, col: n });
2473
+ l ? this.ranges.length > 0 ? this.ranges[this.ranges.length - 1] = a : this.ranges.push(a) : this.ranges = [a], this.activeRange = a;
2474
+ } else if (l) {
2475
+ const a = {
2476
+ startRow: t,
2477
+ startCol: n,
2478
+ endRow: t,
2479
+ endCol: n
2480
+ };
2481
+ this.ranges.push(a), this.activeRange = a, this.cellAnchor = { row: t, col: n };
2482
+ } else {
2483
+ const a = {
2484
+ startRow: t,
2485
+ startCol: n,
2486
+ endRow: t,
2487
+ endCol: n
2488
+ };
2489
+ this.ranges = [a], this.activeRange = a, this.cellAnchor = { row: t, col: n };
2490
+ }
2491
+ return this.emit("selection-change", this.#t()), this.requestAfterRender(), !1;
2492
+ }
2493
+ return !1;
2494
+ }
2495
+ onKeyDown(e) {
2496
+ const { mode: t } = this.config;
2497
+ if (e.key === "Escape")
2498
+ return t === "cell" ? this.selectedCell = null : t === "row" ? (this.selected.clear(), this.anchor = null) : t === "range" && (this.ranges = [], this.activeRange = null, this.cellAnchor = null), this.emit("selection-change", this.#t()), this.requestAfterRender(), !0;
2499
+ if (t === "range" && e.key === "a" && (e.ctrlKey || e.metaKey)) {
2500
+ const n = this.rows.length, i = this.columns.length;
2501
+ if (n > 0 && i > 0) {
2502
+ const s = {
2503
+ startRow: 0,
2504
+ startCol: 0,
2505
+ endRow: n - 1,
2506
+ endCol: i - 1
2507
+ };
2508
+ return this.ranges = [s], this.activeRange = s, this.emit("selection-change", this.#t()), this.requestAfterRender(), !0;
2509
+ }
2510
+ }
2511
+ return !1;
2512
+ }
2513
+ onCellMouseDown(e) {
2514
+ if (this.config.mode !== "range" || e.rowIndex === void 0 || e.colIndex === void 0 || e.rowIndex < 0 || e.originalEvent.shiftKey && this.cellAnchor)
2515
+ return;
2516
+ this.isDragging = !0;
2517
+ const t = e.rowIndex, n = e.colIndex;
2518
+ this.cellAnchor = { row: t, col: n }, e.originalEvent.ctrlKey || e.originalEvent.metaKey || (this.ranges = []);
2519
+ const s = {
2520
+ startRow: t,
2521
+ startCol: n,
2522
+ endRow: t,
2523
+ endCol: n
2524
+ };
2525
+ return this.ranges.push(s), this.activeRange = s, this.emit("selection-change", this.#t()), this.requestAfterRender(), !0;
2526
+ }
2527
+ onCellMouseMove(e) {
2528
+ if (this.config.mode !== "range" || !this.isDragging || !this.cellAnchor || e.rowIndex === void 0 || e.colIndex === void 0 || e.rowIndex < 0) return;
2529
+ const t = se(this.cellAnchor, { row: e.rowIndex, col: e.colIndex });
2530
+ 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;
2531
+ }
2532
+ onCellMouseUp(e) {
2533
+ if (this.config.mode === "range" && this.isDragging)
2534
+ return this.isDragging = !1, !0;
2535
+ }
2536
+ afterRender() {
2537
+ const e = this.shadowRoot;
2538
+ if (!e) return;
2539
+ const t = e.children[0], { mode: n } = this.config;
2540
+ this.grid.setAttribute("data-selection-mode", n), t && t.classList.toggle("selecting", this.isDragging), e.querySelectorAll(".cell").forEach((r) => {
2541
+ r.classList.remove("selected", "top", "bottom", "first", "last");
2542
+ });
2543
+ const s = e.querySelectorAll(".data-grid-row");
2544
+ if (s.forEach((r) => {
2545
+ r.classList.remove("selected");
2546
+ }), n === "row" && (s.forEach((r) => r.classList.remove("row-focus")), s.forEach((r) => {
2547
+ const l = r.querySelector(".cell[data-row]"), a = parseInt(l?.getAttribute("data-row") ?? "-1", 10);
2548
+ a >= 0 && this.selected.has(a) && r.classList.add("selected", "row-focus");
2549
+ })), n === "range" && this.ranges.length > 0) {
2550
+ const r = this.activeRange ? z(this.activeRange) : null;
2551
+ e.querySelectorAll(".cell[data-row][data-col]").forEach((a) => {
2552
+ const h = parseInt(a.getAttribute("data-row") ?? "-1", 10), u = parseInt(a.getAttribute("data-col") ?? "-1", 10);
2553
+ h >= 0 && u >= 0 && ie(h, u, this.ranges) && (a.classList.add("selected"), r && (h === r.startRow && a.classList.add("top"), h === r.endRow && a.classList.add("bottom"), u === r.startCol && a.classList.add("first"), u === r.endCol && a.classList.add("last")));
2554
+ });
2555
+ }
2556
+ }
2557
+ // ===== Public API =====
2558
+ /**
2559
+ * Get the selected cell (cell mode only).
2560
+ */
2561
+ getSelectedCell() {
2562
+ return this.selectedCell;
2563
+ }
2564
+ /**
2565
+ * Get all selected row indices (row mode).
2566
+ */
2567
+ getSelectedRows() {
2568
+ return [...this.selected];
2569
+ }
2570
+ /**
2571
+ * Get all selected cell ranges in public format.
2572
+ */
2573
+ getRanges() {
2574
+ return K(this.ranges);
2575
+ }
2576
+ /**
2577
+ * Get all selected cells across all ranges.
2578
+ */
2579
+ getSelectedCells() {
2580
+ return et(this.ranges);
2581
+ }
2582
+ /**
2583
+ * Check if a specific cell is in range selection.
2584
+ */
2585
+ isCellSelected(e, t) {
2586
+ return ie(e, t, this.ranges);
2587
+ }
2588
+ /**
2589
+ * Clear all selection.
2590
+ */
2591
+ clearSelection() {
2592
+ this.selectedCell = null, this.selected.clear(), this.anchor = null, this.ranges = [], this.activeRange = null, this.cellAnchor = null, this.emit("selection-change", { mode: this.config.mode, ranges: [] }), this.requestAfterRender();
2593
+ }
2594
+ /**
2595
+ * Set selected ranges programmatically.
2596
+ */
2597
+ setRanges(e) {
2598
+ this.ranges = e.map((t) => ({
2599
+ startRow: t.from.row,
2600
+ startCol: t.from.col,
2601
+ endRow: t.to.row,
2602
+ endCol: t.to.col
2603
+ })), this.activeRange = this.ranges.length > 0 ? this.ranges[this.ranges.length - 1] : null, this.emit("selection-change", {
2604
+ mode: this.config.mode,
2605
+ ranges: K(this.ranges)
2606
+ }), this.requestAfterRender();
2607
+ }
2608
+ // ===== Private Helpers =====
2609
+ #t() {
2610
+ return tt(
2611
+ this.config.mode,
2612
+ {
2613
+ selectedCell: this.selectedCell,
2614
+ selected: this.selected,
2615
+ ranges: this.ranges
2616
+ },
2617
+ this.columns.length
2618
+ );
2619
+ }
2620
+ // ===== Styles =====
2621
+ styles = `
2622
+ /* Prevent text selection during range drag */
2623
+ :host .selecting .data-grid-row > .cell {
2624
+ user-select: none;
2625
+ }
2626
+
2627
+ /* Row selection - use accent color for row focus */
2628
+ :host .data-grid-row.row-focus {
2629
+ background-color: var(--tbw-focus-background, rgba(from var(--tbw-color-accent) r g b / 12%));
2630
+ }
2631
+
2632
+ /* Disable cell-focus outline in row mode - row is the focus unit */
2633
+ :host([data-selection-mode="row"]) .cell-focus {
2634
+ outline: none;
2635
+ }
2636
+
2637
+ /* Selection cell styles - for range mode */
2638
+ :host .data-grid-row > .cell.selected {
2639
+ background-color: var(--tbw-range-selection-bg);
2640
+ }
2641
+ :host .data-grid-row > .cell.selected.top {
2642
+ border-top: 2px solid var(--tbw-range-border-color);
2643
+ }
2644
+ :host .data-grid-row > .cell.selected.bottom {
2645
+ border-bottom: 2px solid var(--tbw-range-border-color);
2646
+ }
2647
+ :host .data-grid-row > .cell.selected.first {
2648
+ border-left: 2px solid var(--tbw-range-border-color);
2649
+ }
2650
+ :host .data-grid-row > .cell.selected.last {
2651
+ border-right: 2px solid var(--tbw-range-border-color);
2652
+ }
2653
+ `;
2654
+ }
2655
+ function G(o, e, t) {
2656
+ return o.id !== void 0 ? String(o.id) : t ? `${t}-${e}` : String(e);
2657
+ }
2658
+ function fe(o, e, t, n = null, i = 0) {
2659
+ const s = e.childrenField ?? "children", r = [];
2660
+ for (let l = 0; l < o.length; l++) {
2661
+ const a = o[l], h = G(a, l, n), u = a[s], w = Array.isArray(u) && u.length > 0, c = t.has(h);
2662
+ if (r.push({
2663
+ key: h,
2664
+ data: a,
2665
+ depth: i,
2666
+ hasChildren: w,
2667
+ isExpanded: c,
2668
+ parentKey: n
2669
+ }), w && c) {
2670
+ const d = fe(u, e, t, h, i + 1);
2671
+ r.push(...d);
2672
+ }
2673
+ }
2674
+ return r;
2675
+ }
2676
+ function re(o, e) {
2677
+ const t = new Set(o);
2678
+ return t.has(e) ? t.delete(e) : t.add(e), t;
2679
+ }
2680
+ function W(o, e, t = null, n = 0) {
2681
+ const i = e.childrenField ?? "children", s = /* @__PURE__ */ new Set();
2682
+ for (let r = 0; r < o.length; r++) {
2683
+ const l = o[r], a = G(l, r, t), h = l[i];
2684
+ if (Array.isArray(h) && h.length > 0) {
2685
+ s.add(a);
2686
+ const u = W(h, e, a, n + 1);
2687
+ for (const w of u) s.add(w);
2688
+ }
2689
+ }
2690
+ return s;
2691
+ }
2692
+ function ot() {
2693
+ return /* @__PURE__ */ new Set();
2694
+ }
2695
+ function pe(o, e, t, n = null, i = 0) {
2696
+ const s = t.childrenField ?? "children";
2697
+ for (let r = 0; r < o.length; r++) {
2698
+ const l = o[r], a = G(l, r, n);
2699
+ if (a === e)
2700
+ return [a];
2701
+ const h = l[s];
2702
+ if (Array.isArray(h) && h.length > 0) {
2703
+ const u = pe(h, e, t, a, i + 1);
2704
+ if (u)
2705
+ return [a, ...u];
2706
+ }
2707
+ }
2708
+ return null;
2709
+ }
2710
+ function nt(o, e, t, n) {
2711
+ const i = pe(o, e, t);
2712
+ if (!i) return n;
2713
+ const s = new Set(n);
2714
+ for (let r = 0; r < i.length - 1; r++)
2715
+ s.add(i[r]);
2716
+ return s;
2717
+ }
2718
+ function le(o, e = "children") {
2719
+ if (!Array.isArray(o) || o.length === 0) return !1;
2720
+ for (const t of o)
2721
+ if (t && Array.isArray(t[e]) && t[e].length > 0)
2722
+ return !0;
2723
+ return !1;
2724
+ }
2725
+ function it(o) {
2726
+ if (!Array.isArray(o) || o.length === 0) return null;
2727
+ const e = ["children", "items", "nodes", "subRows", "nested"];
2728
+ for (const t of o)
2729
+ if (!(!t || typeof t != "object")) {
2730
+ for (const n of e)
2731
+ if (Array.isArray(t[n]) && t[n].length > 0)
2732
+ return n;
2733
+ }
2734
+ return null;
2735
+ }
2736
+ class rt extends ue {
2737
+ name = "tree";
2738
+ version = "1.0.0";
2739
+ get defaultConfig() {
2740
+ return {
2741
+ enabled: !0,
2742
+ childrenField: "children",
2743
+ autoDetect: !0,
2744
+ defaultExpanded: !1,
2745
+ indentWidth: 20,
2746
+ showExpandIcons: !0
2747
+ };
2748
+ }
2749
+ // ===== Internal State =====
2750
+ /** Set of expanded row keys */
2751
+ expandedKeys = /* @__PURE__ */ new Set();
2752
+ /** Whether initial expansion (based on defaultExpanded config) has been applied */
2753
+ initialExpansionDone = !1;
2754
+ /** Flattened tree rows for rendering */
2755
+ flattenedRows = [];
2756
+ /** Map from key to flattened row for quick lookup */
2757
+ rowKeyMap = /* @__PURE__ */ new Map();
2758
+ // ===== Lifecycle =====
2759
+ detach() {
2760
+ this.expandedKeys.clear(), this.initialExpansionDone = !1, this.flattenedRows = [], this.rowKeyMap.clear();
2761
+ }
2762
+ // ===== Auto-Detection =====
2763
+ /**
2764
+ * Detects if tree functionality should be enabled based on data structure.
2765
+ * Called by the grid during plugin initialization.
2766
+ */
2767
+ detect(e) {
2768
+ if (!this.config.autoDetect) return !1;
2769
+ const t = this.config.childrenField ?? it(e) ?? "children";
2770
+ return le(e, t);
2771
+ }
2772
+ // ===== Data Processing =====
2773
+ processRows(e) {
2774
+ const t = this.config.childrenField ?? "children";
2775
+ if (!le(e, t))
2776
+ return this.flattenedRows = [], this.rowKeyMap.clear(), [...e];
2777
+ this.config.defaultExpanded && !this.initialExpansionDone && (this.expandedKeys = W(e, this.config), this.initialExpansionDone = !0), this.flattenedRows = fe(e, this.config, this.expandedKeys), this.rowKeyMap.clear();
2778
+ for (const n of this.flattenedRows)
2779
+ this.rowKeyMap.set(n.key, n);
2780
+ return this.flattenedRows.map((n) => ({
2781
+ ...n.data,
2782
+ __treeKey: n.key,
2783
+ __treeDepth: n.depth,
2784
+ __treeHasChildren: n.hasChildren,
2785
+ __treeExpanded: n.isExpanded
2786
+ }));
2787
+ }
2788
+ processColumns(e) {
2789
+ if (this.flattenedRows.length === 0) return [...e];
2790
+ const t = this.config.indentWidth ?? 20, n = this.config.showExpandIcons ?? !0, i = [...e];
2791
+ if (i.length > 0) {
2792
+ const s = { ...i[0] }, r = s.viewRenderer;
2793
+ s.viewRenderer = (l) => {
2794
+ const { value: a, row: h, column: u } = l, w = h.__treeDepth ?? 0, c = h.__treeHasChildren ?? !1, d = h.__treeExpanded ?? !1, p = document.createElement("span");
2795
+ if (p.style.display = "flex", p.style.alignItems = "center", p.style.paddingLeft = `${w * t}px`, c && n) {
2796
+ const b = document.createElement("span");
2797
+ b.className = "tree-toggle", b.textContent = d ? "▼" : "▶", b.style.cursor = "pointer", b.style.marginRight = "4px", b.style.fontSize = "10px", b.setAttribute("data-tree-key", h.__treeKey), p.appendChild(b);
2798
+ } else if (n) {
2799
+ const b = document.createElement("span");
2800
+ b.style.width = "14px", b.style.display = "inline-block", p.appendChild(b);
2801
+ }
2802
+ const f = document.createElement("span");
2803
+ if (r) {
2804
+ const b = r(l);
2805
+ b instanceof Node ? f.appendChild(b) : f.textContent = String(b ?? a ?? "");
2806
+ } else
2807
+ f.textContent = String(a ?? "");
2808
+ return p.appendChild(f), p;
2809
+ }, i[0] = s;
2810
+ }
2811
+ return i;
2812
+ }
2813
+ // ===== Event Handlers =====
2814
+ onCellClick(e) {
2815
+ const t = e.originalEvent?.target;
2816
+ if (!t?.classList.contains("tree-toggle")) return !1;
2817
+ const n = t.getAttribute("data-tree-key");
2818
+ if (!n) return !1;
2819
+ const i = this.rowKeyMap.get(n);
2820
+ return i ? (this.expandedKeys = re(this.expandedKeys, n), this.emit("tree-expand", {
2821
+ key: n,
2822
+ row: i.data,
2823
+ expanded: this.expandedKeys.has(n),
2824
+ depth: i.depth
2825
+ }), this.requestRender(), !0) : !1;
2826
+ }
2827
+ // ===== Public API =====
2828
+ /**
2829
+ * Expand a specific node by key.
2830
+ */
2831
+ expand(e) {
2832
+ this.expandedKeys.add(e), this.requestRender();
2833
+ }
2834
+ /**
2835
+ * Collapse a specific node by key.
2836
+ */
2837
+ collapse(e) {
2838
+ this.expandedKeys.delete(e), this.requestRender();
2839
+ }
2840
+ /**
2841
+ * Toggle the expansion state of a node.
2842
+ */
2843
+ toggle(e) {
2844
+ this.expandedKeys = re(this.expandedKeys, e), this.requestRender();
2845
+ }
2846
+ /**
2847
+ * Expand all nodes in the tree.
2848
+ */
2849
+ expandAll() {
2850
+ this.expandedKeys = W(this.rows, this.config), this.requestRender();
2851
+ }
2852
+ /**
2853
+ * Collapse all nodes in the tree.
2854
+ */
2855
+ collapseAll() {
2856
+ this.expandedKeys = ot(), this.requestRender();
2857
+ }
2858
+ /**
2859
+ * Check if a node is currently expanded.
2860
+ */
2861
+ isExpanded(e) {
2862
+ return this.expandedKeys.has(e);
2863
+ }
2864
+ /**
2865
+ * Get all currently expanded keys.
2866
+ */
2867
+ getExpandedKeys() {
2868
+ return [...this.expandedKeys];
2869
+ }
2870
+ /**
2871
+ * Get the flattened tree rows with metadata.
2872
+ */
2873
+ getFlattenedRows() {
2874
+ return [...this.flattenedRows];
2875
+ }
2876
+ /**
2877
+ * Get a row's original data by its key.
2878
+ */
2879
+ getRowByKey(e) {
2880
+ return this.rowKeyMap.get(e)?.data;
2881
+ }
2882
+ /**
2883
+ * Expand all ancestors of a node to make it visible.
2884
+ */
2885
+ expandToKey(e) {
2886
+ this.expandedKeys = nt(this.rows, e, this.config, this.expandedKeys), this.requestRender();
2887
+ }
2888
+ // ===== Styles =====
2889
+ styles = `
2890
+ .tree-toggle {
2891
+ cursor: pointer;
2892
+ user-select: none;
2893
+ transition: transform 0.2s;
2894
+ }
2895
+ .tree-toggle:hover {
2896
+ color: var(--tbw-tree-accent, var(--tbw-color-accent));
2897
+ }
2898
+ `;
2899
+ }
2900
+ const v = {
2901
+ // Root structure
2902
+ ROOT: "tbw-grid-root",
2903
+ HEADER: "header",
2904
+ HEADER_ROW: "header-row",
2905
+ HEADER_CELL: "header-cell",
2906
+ // Body structure
2907
+ ROWS_VIEWPORT: "rows-viewport",
2908
+ ROWS_SPACER: "rows-spacer",
2909
+ ROWS_CONTAINER: "rows",
2910
+ // Row elements
2911
+ DATA_ROW: "data-row",
2912
+ GROUP_ROW: "group-row",
2913
+ // Cell elements
2914
+ DATA_CELL: "data-cell",
2915
+ // States
2916
+ SELECTED: "selected",
2917
+ FOCUSED: "focused",
2918
+ EDITING: "editing",
2919
+ EXPANDED: "expanded",
2920
+ COLLAPSED: "collapsed",
2921
+ DRAGGING: "dragging",
2922
+ RESIZING: "resizing",
2923
+ // Sorting
2924
+ SORTABLE: "sortable",
2925
+ SORTED_ASC: "sorted-asc",
2926
+ SORTED_DESC: "sorted-desc",
2927
+ // Visibility
2928
+ HIDDEN: "hidden",
2929
+ // Sticky/pinned
2930
+ STICKY_LEFT: "sticky-left",
2931
+ STICKY_RIGHT: "sticky-right",
2932
+ // Special rows
2933
+ PINNED_TOP: "pinned-top",
2934
+ PINNED_BOTTOM: "pinned-bottom",
2935
+ // Tree
2936
+ TREE_TOGGLE: "tree-toggle",
2937
+ TREE_INDENT: "tree-indent",
2938
+ // Grouping
2939
+ GROUP_TOGGLE: "group-toggle",
2940
+ GROUP_LABEL: "group-label",
2941
+ GROUP_COUNT: "group-count",
2942
+ // Selection
2943
+ RANGE_SELECTION: "range-selection",
2944
+ SELECTION_OVERLAY: "selection-overlay"
2945
+ }, H = {
2946
+ ROW_INDEX: "data-row-index",
2947
+ COL_INDEX: "data-col-index",
2948
+ FIELD: "data-field",
2949
+ GROUP_KEY: "data-group-key",
2950
+ TREE_LEVEL: "data-tree-level",
2951
+ STICKY: "data-sticky"
2952
+ }, lt = {
2953
+ ROOT: `.${v.ROOT}`,
2954
+ HEADER: `.${v.HEADER}`,
2955
+ HEADER_ROW: `.${v.HEADER_ROW}`,
2956
+ HEADER_CELL: `.${v.HEADER_CELL}`,
2957
+ ROWS_VIEWPORT: `.${v.ROWS_VIEWPORT}`,
2958
+ ROWS_CONTAINER: `.${v.ROWS_CONTAINER}`,
2959
+ DATA_ROW: `.${v.DATA_ROW}`,
2960
+ DATA_CELL: `.${v.DATA_CELL}`,
2961
+ GROUP_ROW: `.${v.GROUP_ROW}`,
2962
+ // By data attribute
2963
+ ROW_BY_INDEX: (o) => `.${v.DATA_ROW}[${H.ROW_INDEX}="${o}"]`,
2964
+ CELL_BY_FIELD: (o) => `.${v.DATA_CELL}[${H.FIELD}="${o}"]`,
2965
+ CELL_AT: (o, e) => `.${v.DATA_ROW}[${H.ROW_INDEX}="${o}"] .${v.DATA_CELL}[${H.COL_INDEX}="${e}"]`,
2966
+ // State selectors
2967
+ SELECTED_ROWS: `.${v.DATA_ROW}.${v.SELECTED}`,
2968
+ EDITING_CELL: `.${v.DATA_CELL}.${v.EDITING}`
2969
+ }, at = {
2970
+ // Colors
2971
+ COLOR_BG: "--tbw-color-bg",
2972
+ COLOR_FG: "--tbw-color-fg",
2973
+ COLOR_FG_MUTED: "--tbw-color-fg-muted",
2974
+ COLOR_BORDER: "--tbw-color-border",
2975
+ COLOR_ACCENT: "--tbw-color-accent",
2976
+ COLOR_HEADER_BG: "--tbw-color-header-bg",
2977
+ COLOR_HEADER_FG: "--tbw-color-header-fg",
2978
+ COLOR_SELECTION: "--tbw-color-selection",
2979
+ COLOR_ROW_HOVER: "--tbw-color-row-hover",
2980
+ COLOR_ROW_ALT: "--tbw-color-row-alt",
2981
+ // Sizing
2982
+ ROW_HEIGHT: "--tbw-row-height",
2983
+ HEADER_HEIGHT: "--tbw-header-height",
2984
+ CELL_PADDING: "--tbw-cell-padding",
2985
+ // Typography
2986
+ FONT_FAMILY: "--tbw-font-family",
2987
+ FONT_SIZE: "--tbw-font-size",
2988
+ // Borders
2989
+ BORDER_RADIUS: "--tbw-border-radius",
2990
+ FOCUS_OUTLINE: "--tbw-focus-outline"
2991
+ }, ct = {
2992
+ CELL_COMMIT: "cell-commit",
2993
+ ROW_COMMIT: "row-commit",
2994
+ CHANGED_ROWS_RESET: "changed-rows-reset",
2995
+ MOUNT_EXTERNAL_VIEW: "mount-external-view",
2996
+ MOUNT_EXTERNAL_EDITOR: "mount-external-editor",
2997
+ SORT_CHANGE: "sort-change",
2998
+ COLUMN_RESIZE: "column-resize",
2999
+ ACTIVATE_CELL: "activate-cell",
3000
+ GROUP_TOGGLE: "group-toggle",
3001
+ COLUMN_STATE_CHANGE: "column-state-change"
3002
+ }, dt = {
3003
+ // Selection plugin
3004
+ SELECTION_CHANGE: "selection-change",
3005
+ // Tree plugin
3006
+ TREE_EXPAND: "tree-expand",
3007
+ // Filtering plugin
3008
+ FILTER_CHANGE: "filter-change",
3009
+ // Sorting plugin
3010
+ SORT_MODEL_CHANGE: "sort-model-change",
3011
+ // Export plugin
3012
+ EXPORT_START: "export-start",
3013
+ EXPORT_COMPLETE: "export-complete",
3014
+ // Clipboard plugin
3015
+ CLIPBOARD_COPY: "clipboard-copy",
3016
+ CLIPBOARD_PASTE: "clipboard-paste",
3017
+ // Context menu plugin
3018
+ CONTEXT_MENU_OPEN: "context-menu-open",
3019
+ CONTEXT_MENU_CLOSE: "context-menu-close",
3020
+ // Undo/Redo plugin
3021
+ HISTORY_CHANGE: "history-change",
3022
+ // Server-side plugin
3023
+ SERVER_LOADING: "server-loading",
3024
+ SERVER_ERROR: "server-error",
3025
+ // Visibility plugin
3026
+ COLUMN_VISIBILITY_CHANGE: "column-visibility-change",
3027
+ // Reorder plugin
3028
+ COLUMN_REORDER: "column-reorder",
3029
+ // Master-detail plugin
3030
+ DETAIL_EXPAND: "detail-expand",
3031
+ // Grouping rows plugin
3032
+ GROUP_EXPAND: "group-expand"
3033
+ }, I = {
3034
+ sum: (o, e) => o.reduce((t, n) => t + (Number(n[e]) || 0), 0),
3035
+ avg: (o, e) => {
3036
+ const t = o.reduce((n, i) => n + (Number(i[e]) || 0), 0);
3037
+ return o.length ? t / o.length : 0;
3038
+ },
3039
+ count: (o) => o.length,
3040
+ min: (o, e) => Math.min(...o.map((t) => Number(t[e]) || 1 / 0)),
3041
+ max: (o, e) => Math.max(...o.map((t) => Number(t[e]) || -1 / 0)),
3042
+ first: (o, e) => o[0]?.[e],
3043
+ last: (o, e) => o[o.length - 1]?.[e]
3044
+ }, P = /* @__PURE__ */ new Map(), R = {
3045
+ /**
3046
+ * Register a custom aggregator function.
3047
+ */
3048
+ register(o, e) {
3049
+ P.set(o, e);
3050
+ },
3051
+ /**
3052
+ * Unregister a custom aggregator function.
3053
+ */
3054
+ unregister(o) {
3055
+ P.delete(o);
3056
+ },
3057
+ /**
3058
+ * Get an aggregator function by reference.
3059
+ */
3060
+ get(o) {
3061
+ if (o !== void 0)
3062
+ return typeof o == "function" ? o : P.get(o) ?? I[o];
3063
+ },
3064
+ /**
3065
+ * Run an aggregator on a set of rows.
3066
+ */
3067
+ run(o, e, t, n) {
3068
+ const i = this.get(o);
3069
+ return i ? i(e, t, n) : void 0;
3070
+ },
3071
+ /**
3072
+ * Check if an aggregator exists.
3073
+ */
3074
+ has(o) {
3075
+ return P.has(o) || o in I;
3076
+ },
3077
+ /**
3078
+ * List all available aggregator names.
3079
+ */
3080
+ list() {
3081
+ return [...Object.keys(I), ...P.keys()];
3082
+ }
3083
+ }, ht = R.register.bind(R), ut = R.unregister.bind(R), ft = R.get.bind(R), pt = R.run.bind(R), wt = R.list.bind(R);
3084
+ export {
3085
+ ue as BaseGridPlugin,
3086
+ ct as DGEvents,
3087
+ q as DataGridElement,
3088
+ O as FitModeEnum,
3089
+ at as GridCSSVars,
3090
+ v as GridClasses,
3091
+ H as GridDataAttrs,
3092
+ q as GridElement,
3093
+ lt as GridSelectors,
3094
+ dt as PluginEvents,
3095
+ Ye as PluginManager,
3096
+ st as SelectionPlugin,
3097
+ rt as TreePlugin,
3098
+ R as aggregatorRegistry,
3099
+ ft as getAggregator,
3100
+ wt as listAggregators,
3101
+ ht as registerAggregator,
3102
+ pt as runAggregator,
3103
+ ut as unregisterAggregator
3104
+ };
3105
+ //# sourceMappingURL=index.js.map