@toolbox-web/grid 0.3.2 → 0.4.0

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 (138) hide show
  1. package/README.md +5 -4
  2. package/all.d.ts +19 -19
  3. package/all.d.ts.map +1 -1
  4. package/all.js +1775 -1202
  5. package/all.js.map +1 -1
  6. package/index.js +2143 -2015
  7. package/index.js.map +1 -1
  8. package/lib/core/grid.d.ts +22 -12
  9. package/lib/core/grid.d.ts.map +1 -1
  10. package/lib/core/internal/columns.d.ts +0 -9
  11. package/lib/core/internal/columns.d.ts.map +1 -1
  12. package/lib/core/internal/config-manager.d.ts +236 -0
  13. package/lib/core/internal/config-manager.d.ts.map +1 -0
  14. package/lib/core/internal/event-delegation.d.ts.map +1 -1
  15. package/lib/core/internal/header.d.ts.map +1 -1
  16. package/lib/core/internal/keyboard.d.ts.map +1 -1
  17. package/lib/core/internal/render-scheduler.d.ts +123 -0
  18. package/lib/core/internal/render-scheduler.d.ts.map +1 -0
  19. package/lib/core/internal/rows.d.ts +8 -3
  20. package/lib/core/internal/rows.d.ts.map +1 -1
  21. package/lib/core/internal/sanitize.d.ts +10 -2
  22. package/lib/core/internal/sanitize.d.ts.map +1 -1
  23. package/lib/core/internal/shell.d.ts +40 -2
  24. package/lib/core/internal/shell.d.ts.map +1 -1
  25. package/lib/core/internal/validate-config.d.ts +11 -0
  26. package/lib/core/internal/validate-config.d.ts.map +1 -0
  27. package/lib/core/plugin/base-plugin.d.ts +70 -0
  28. package/lib/core/plugin/base-plugin.d.ts.map +1 -1
  29. package/lib/core/plugin/plugin-manager.d.ts +13 -2
  30. package/lib/core/plugin/plugin-manager.d.ts.map +1 -1
  31. package/lib/core/plugin/types.d.ts +17 -3
  32. package/lib/core/plugin/types.d.ts.map +1 -1
  33. package/lib/core/types.d.ts +112 -12
  34. package/lib/core/types.d.ts.map +1 -1
  35. package/lib/plugins/clipboard/ClipboardPlugin.d.ts.map +1 -1
  36. package/lib/plugins/clipboard/index.js +50 -18
  37. package/lib/plugins/clipboard/index.js.map +1 -1
  38. package/lib/plugins/column-virtualization/index.js +60 -25
  39. package/lib/plugins/column-virtualization/index.js.map +1 -1
  40. package/lib/plugins/context-menu/index.js +51 -16
  41. package/lib/plugins/context-menu/index.js.map +1 -1
  42. package/lib/plugins/editing/EditingPlugin.d.ts +117 -0
  43. package/lib/plugins/editing/EditingPlugin.d.ts.map +1 -0
  44. package/lib/{core/internal → plugins/editing}/editors.d.ts +1 -1
  45. package/lib/plugins/editing/editors.d.ts.map +1 -0
  46. package/lib/plugins/editing/index.d.ts +8 -0
  47. package/lib/plugins/editing/index.d.ts.map +1 -0
  48. package/lib/plugins/editing/index.js +705 -0
  49. package/lib/plugins/editing/index.js.map +1 -0
  50. package/lib/plugins/editing/types.d.ts +45 -0
  51. package/lib/plugins/editing/types.d.ts.map +1 -0
  52. package/lib/plugins/export/ExportPlugin.d.ts.map +1 -1
  53. package/lib/plugins/export/index.js +74 -39
  54. package/lib/plugins/export/index.js.map +1 -1
  55. package/lib/plugins/filtering/FilteringPlugin.d.ts.map +1 -1
  56. package/lib/plugins/filtering/index.js +87 -50
  57. package/lib/plugins/filtering/index.js.map +1 -1
  58. package/lib/plugins/grouping-columns/grouping-columns.d.ts +4 -4
  59. package/lib/plugins/grouping-columns/grouping-columns.d.ts.map +1 -1
  60. package/lib/plugins/grouping-columns/index.js +59 -24
  61. package/lib/plugins/grouping-columns/index.js.map +1 -1
  62. package/lib/plugins/grouping-rows/GroupingRowsPlugin.d.ts.map +1 -1
  63. package/lib/plugins/grouping-rows/grouping-rows.d.ts.map +1 -1
  64. package/lib/plugins/grouping-rows/index.js +46 -11
  65. package/lib/plugins/grouping-rows/index.js.map +1 -1
  66. package/lib/plugins/master-detail/MasterDetailPlugin.d.ts +2 -2
  67. package/lib/plugins/master-detail/MasterDetailPlugin.d.ts.map +1 -1
  68. package/lib/plugins/master-detail/index.js +140 -102
  69. package/lib/plugins/master-detail/index.js.map +1 -1
  70. package/lib/plugins/master-detail/types.d.ts +12 -2
  71. package/lib/plugins/master-detail/types.d.ts.map +1 -1
  72. package/lib/plugins/multi-sort/MultiSortPlugin.d.ts.map +1 -1
  73. package/lib/plugins/multi-sort/index.js +59 -22
  74. package/lib/plugins/multi-sort/index.js.map +1 -1
  75. package/lib/plugins/pinned-columns/index.js +41 -6
  76. package/lib/plugins/pinned-columns/index.js.map +1 -1
  77. package/lib/plugins/pinned-rows/PinnedRowsPlugin.d.ts.map +1 -1
  78. package/lib/plugins/pinned-rows/index.js +45 -9
  79. package/lib/plugins/pinned-rows/index.js.map +1 -1
  80. package/lib/plugins/pivot/index.js +42 -7
  81. package/lib/plugins/pivot/index.js.map +1 -1
  82. package/lib/plugins/reorder/ReorderPlugin.d.ts.map +1 -1
  83. package/lib/plugins/reorder/index.js +59 -19
  84. package/lib/plugins/reorder/index.js.map +1 -1
  85. package/lib/plugins/selection/index.js +41 -6
  86. package/lib/plugins/selection/index.js.map +1 -1
  87. package/lib/plugins/server-side/index.js +48 -13
  88. package/lib/plugins/server-side/index.js.map +1 -1
  89. package/lib/plugins/tree/TreePlugin.d.ts +3 -3
  90. package/lib/plugins/tree/TreePlugin.d.ts.map +1 -1
  91. package/lib/plugins/tree/index.js +165 -126
  92. package/lib/plugins/tree/index.js.map +1 -1
  93. package/lib/plugins/tree/tree-data.d.ts +6 -6
  94. package/lib/plugins/tree/tree-data.d.ts.map +1 -1
  95. package/lib/plugins/tree/tree-detect.d.ts +5 -9
  96. package/lib/plugins/tree/tree-detect.d.ts.map +1 -1
  97. package/lib/plugins/tree/types.d.ts +16 -4
  98. package/lib/plugins/tree/types.d.ts.map +1 -1
  99. package/lib/plugins/undo-redo/index.js +46 -11
  100. package/lib/plugins/undo-redo/index.js.map +1 -1
  101. package/lib/plugins/visibility/index.js +37 -2
  102. package/lib/plugins/visibility/index.js.map +1 -1
  103. package/package.json +1 -1
  104. package/public.d.ts +104 -13
  105. package/public.d.ts.map +1 -1
  106. package/umd/grid.all.umd.js +31 -19
  107. package/umd/grid.all.umd.js.map +1 -1
  108. package/umd/grid.umd.js +18 -6
  109. package/umd/grid.umd.js.map +1 -1
  110. package/umd/plugins/clipboard.umd.js +1 -1
  111. package/umd/plugins/clipboard.umd.js.map +1 -1
  112. package/umd/plugins/editing.umd.js +2 -0
  113. package/umd/plugins/editing.umd.js.map +1 -0
  114. package/umd/plugins/export.umd.js +2 -2
  115. package/umd/plugins/export.umd.js.map +1 -1
  116. package/umd/plugins/filtering.umd.js +1 -1
  117. package/umd/plugins/filtering.umd.js.map +1 -1
  118. package/umd/plugins/grouping-columns.umd.js +1 -1
  119. package/umd/plugins/grouping-columns.umd.js.map +1 -1
  120. package/umd/plugins/grouping-rows.umd.js +1 -1
  121. package/umd/plugins/grouping-rows.umd.js.map +1 -1
  122. package/umd/plugins/master-detail.umd.js +1 -1
  123. package/umd/plugins/master-detail.umd.js.map +1 -1
  124. package/umd/plugins/multi-sort.umd.js +1 -1
  125. package/umd/plugins/multi-sort.umd.js.map +1 -1
  126. package/umd/plugins/pinned-rows.umd.js +1 -1
  127. package/umd/plugins/pinned-rows.umd.js.map +1 -1
  128. package/umd/plugins/reorder.umd.js +1 -1
  129. package/umd/plugins/reorder.umd.js.map +1 -1
  130. package/umd/plugins/tree.umd.js +1 -1
  131. package/umd/plugins/tree.umd.js.map +1 -1
  132. package/lib/core/internal/column-state.d.ts +0 -124
  133. package/lib/core/internal/column-state.d.ts.map +0 -1
  134. package/lib/core/internal/editing.d.ts +0 -76
  135. package/lib/core/internal/editing.d.ts.map +0 -1
  136. package/lib/core/internal/editors.d.ts.map +0 -1
  137. package/lib/core/internal/grid-internals.d.ts +0 -83
  138. package/lib/core/internal/grid-internals.d.ts.map +0 -1
@@ -2,10 +2,10 @@ function P(p) {
2
2
  const { totalRows: e, viewportHeight: t, scrollTop: r, rowHeight: l, overscan: n } = p, o = Math.ceil(t / l);
3
3
  let i = Math.floor(r / l) - n;
4
4
  i < 0 && (i = 0);
5
- let a = i + o + n * 2;
6
- return a > e && (a = e), a === e && i > 0 && (i = Math.max(0, a - o - n * 2)), {
5
+ let s = i + o + n * 2;
6
+ return s > e && (s = e), s === e && i > 0 && (i = Math.max(0, s - o - n * 2)), {
7
7
  start: i,
8
- end: a,
8
+ end: s,
9
9
  offsetY: i * l,
10
10
  totalHeight: e * l
11
11
  };
@@ -40,6 +40,12 @@ class _ {
40
40
  config;
41
41
  /** User-provided configuration from constructor */
42
42
  userConfig;
43
+ /**
44
+ * Plugin-level AbortController for event listener cleanup.
45
+ * Created fresh in attach(), aborted in detach().
46
+ * This ensures event listeners are properly cleaned up when plugins are re-attached.
47
+ */
48
+ #e;
43
49
  /**
44
50
  * Default configuration - subclasses should override this getter.
45
51
  * Note: This must be a getter (not property initializer) for proper inheritance
@@ -54,19 +60,48 @@ class _ {
54
60
  /**
55
61
  * Called when the plugin is attached to a grid.
56
62
  * Override to set up event listeners, initialize state, etc.
63
+ *
64
+ * @example
65
+ * ```ts
66
+ * attach(grid: GridElement): void {
67
+ * super.attach(grid);
68
+ * // Set up document-level listeners with auto-cleanup
69
+ * document.addEventListener('keydown', this.handleEscape, {
70
+ * signal: this.disconnectSignal
71
+ * });
72
+ * }
73
+ * ```
57
74
  */
58
75
  attach(e) {
59
- this.grid = e, this.config = { ...this.defaultConfig, ...this.userConfig };
76
+ this.#e?.abort(), this.#e = new AbortController(), this.grid = e, this.config = { ...this.defaultConfig, ...this.userConfig };
60
77
  }
61
78
  /**
62
79
  * Called when the plugin is detached from a grid.
63
80
  * Override to clean up event listeners, timers, etc.
81
+ *
82
+ * @example
83
+ * ```ts
84
+ * detach(): void {
85
+ * // Clean up any state not handled by disconnectSignal
86
+ * this.selectedRows.clear();
87
+ * this.cache = null;
88
+ * }
89
+ * ```
64
90
  */
65
91
  detach() {
92
+ this.#e?.abort(), this.#e = void 0;
66
93
  }
67
94
  /**
68
95
  * Get another plugin instance from the same grid.
69
96
  * Use for inter-plugin communication.
97
+ *
98
+ * @example
99
+ * ```ts
100
+ * const selection = this.getPlugin(SelectionPlugin);
101
+ * if (selection) {
102
+ * const selectedRows = selection.getSelectedRows();
103
+ * }
104
+ * ```
70
105
  */
71
106
  getPlugin(e) {
72
107
  return this.grid?.getPlugin(e);
@@ -140,7 +175,7 @@ class _ {
140
175
  * document.addEventListener('keydown', handler, { signal: this.disconnectSignal });
141
176
  */
142
177
  get disconnectSignal() {
143
- return this.grid?.disconnectSignal;
178
+ return this.#e?.signal ?? this.grid?.disconnectSignal;
144
179
  }
145
180
  /**
146
181
  * Get the grid-level icons configuration.
@@ -242,7 +277,7 @@ function N(p, e) {
242
277
  }
243
278
  return [...t].sort((r, l) => typeof r == "number" && typeof l == "number" ? r - l : String(r).localeCompare(String(l)));
244
279
  }
245
- const $ = ':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)}.header-cell.filtered:before{content:"";position:absolute;top:4px;right:4px;width:6px;height:6px;background:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));border-radius:50%}.tbw-filter-btn{display:inline-flex;align-items:center;justify-content:center;background:transparent;border:none;cursor:pointer;padding:2px;margin-left:4px;opacity:.4;transition:opacity .15s;color:inherit;vertical-align:middle}.tbw-filter-btn:hover,.tbw-filter-btn.active{opacity:1}.tbw-filter-btn.active{color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6))}', K = ".tbw-filter-panel{position:fixed;background:var(--tbw-filter-panel-bg, var(--tbw-color-panel-bg, light-dark(#eeeeee, #222222)));color:var(--tbw-filter-panel-fg, var(--tbw-color-fg, light-dark(#222222, #eeeeee)));border:1px solid var(--tbw-filter-panel-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));border-radius:var(--tbw-filter-panel-radius, var(--tbw-border-radius, 4px));box-shadow:0 4px 16px var(--tbw-filter-panel-shadow, var(--tbw-color-shadow, light-dark(rgba(0, 0, 0, .1), rgba(0, 0, 0, .3))));padding:12px;z-index:10000;min-width:200px;max-width:280px;max-height:350px;display:flex;flex-direction:column;font-family:var(--tbw-font-family, system-ui, sans-serif);font-size:var(--tbw-font-size, 13px)}.tbw-filter-search{margin-bottom:8px}.tbw-filter-search-input{width:100%;padding:6px 10px;background:var(--tbw-filter-input-bg, var(--tbw-color-bg, transparent));color:inherit;border:1px solid var(--tbw-filter-input-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));border-radius:var(--tbw-filter-input-radius, 4px);font-size:inherit;box-sizing:border-box}.tbw-filter-search-input:focus{outline:none;border-color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));box-shadow:0 0 0 2px rgba(from var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6)) r g b / 15%)}.tbw-filter-actions{display:flex;padding:4px 2px;margin-bottom:8px;border-bottom:1px solid var(--tbw-filter-divider, var(--tbw-color-border, light-dark(#d0d0d4, #454545)))}.tbw-filter-action-btn{background:transparent;border:none;color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));cursor:pointer;font-size:12px;padding:2px 0}.tbw-filter-action-btn:hover{text-decoration:underline}.tbw-filter-values{flex:1;overflow-y:auto;margin-bottom:8px;max-height:180px;position:relative}.tbw-filter-values-spacer{width:1px}.tbw-filter-values-content{position:absolute;top:0;left:0;right:0}.tbw-filter-value-item{display:flex;align-items:center;gap:8px;padding:4px 2px;cursor:pointer;border-radius:3px}.tbw-filter-value-item:hover{background:var(--tbw-filter-hover, var(--tbw-color-row-hover, light-dark(#f0f6ff, #1c1c1c)))}.tbw-filter-checkbox{margin:0;cursor:pointer;accent-color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6))}.tbw-filter-no-match{color:var(--tbw-filter-muted, var(--tbw-color-fg-muted, light-dark(#555555, #aaaaaa)));padding:8px 0;text-align:center;font-style:italic}.tbw-filter-buttons{display:flex;gap:8px;padding-top:8px;border-top:1px solid var(--tbw-filter-divider, var(--tbw-color-border, light-dark(#d0d0d4, #454545)))}.tbw-filter-apply-btn{flex:1;padding:6px 12px;background:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));color:var(--tbw-filter-accent-fg, var(--tbw-color-accent-fg, light-dark(#ffffff, #000000)));border:none;border-radius:4px;cursor:pointer;font-size:13px}.tbw-filter-apply-btn:hover{filter:brightness(.9)}.tbw-filter-clear-btn{flex:1;padding:6px 12px;background:transparent;color:var(--tbw-filter-muted, var(--tbw-color-fg-muted, light-dark(#555555, #aaaaaa)));border:1px solid var(--tbw-filter-input-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));border-radius:4px;cursor:pointer;font-size:13px}.tbw-filter-clear-btn:hover{background:var(--tbw-filter-hover, var(--tbw-color-row-hover, light-dark(#f0f6ff, #1c1c1c)))}";
280
+ const $ = ':host .tbw-quick-filter-input{flex:1;max-width:300px;height:28px;padding:0 8px;border:1px solid var(--tbw-color-border);border-radius:var(--tbw-border-radius);background:var(--tbw-color-bg);color:var(--tbw-color-fg);font-size:13px}:host .tbw-quick-filter-input:focus{outline:none;border-color:var(--tbw-color-accent)}:host .header-cell.filtered:before{content:"";position:absolute;top:4px;right:4px;width:6px;height:6px;background:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));border-radius:50%}:host .tbw-filter-btn{display:inline-flex;align-items:center;justify-content:center;background:transparent;border:none;cursor:pointer;padding:2px;margin-left:4px;opacity:.4;transition:opacity .15s;color:inherit;vertical-align:middle}:host .tbw-filter-btn:hover,:host .tbw-filter-btn.active{opacity:1}:host .tbw-filter-btn.active{color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6))}', K = ".tbw-filter-panel{position:fixed;background:var(--tbw-filter-panel-bg, var(--tbw-color-panel-bg, light-dark(#eeeeee, #222222)));color:var(--tbw-filter-panel-fg, var(--tbw-color-fg, light-dark(#222222, #eeeeee)));border:1px solid var(--tbw-filter-panel-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));border-radius:var(--tbw-filter-panel-radius, var(--tbw-border-radius, 4px));box-shadow:0 4px 16px var(--tbw-filter-panel-shadow, var(--tbw-color-shadow, light-dark(rgba(0, 0, 0, .1), rgba(0, 0, 0, .3))));padding:12px;z-index:10000;min-width:200px;max-width:280px;max-height:350px;display:flex;flex-direction:column;font-family:var(--tbw-font-family, system-ui, sans-serif);font-size:var(--tbw-font-size, 13px)}.tbw-filter-search{margin-bottom:8px}.tbw-filter-search-input{width:100%;padding:6px 10px;background:var(--tbw-filter-input-bg, var(--tbw-color-bg, transparent));color:inherit;border:1px solid var(--tbw-filter-input-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));border-radius:var(--tbw-filter-input-radius, 4px);font-size:inherit;box-sizing:border-box}.tbw-filter-search-input:focus{outline:none;border-color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));box-shadow:0 0 0 2px rgba(from var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6)) r g b / 15%)}.tbw-filter-actions{display:flex;padding:4px 2px;margin-bottom:8px;border-bottom:1px solid var(--tbw-filter-divider, var(--tbw-color-border, light-dark(#d0d0d4, #454545)))}.tbw-filter-action-btn{background:transparent;border:none;color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));cursor:pointer;font-size:12px;padding:2px 0}.tbw-filter-action-btn:hover{text-decoration:underline}.tbw-filter-values{flex:1;overflow-y:auto;margin-bottom:8px;max-height:180px;position:relative}.tbw-filter-values-spacer{width:1px}.tbw-filter-values-content{position:absolute;top:0;left:0;right:0}.tbw-filter-value-item{display:flex;align-items:center;gap:8px;padding:4px 2px;cursor:pointer;border-radius:3px}.tbw-filter-value-item:hover{background:var(--tbw-filter-hover, var(--tbw-color-row-hover, light-dark(#f0f6ff, #1c1c1c)))}.tbw-filter-checkbox{margin:0;cursor:pointer;accent-color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6))}.tbw-filter-no-match{color:var(--tbw-filter-muted, var(--tbw-color-fg-muted, light-dark(#555555, #aaaaaa)));padding:8px 0;text-align:center;font-style:italic}.tbw-filter-buttons{display:flex;gap:8px;padding-top:8px;border-top:1px solid var(--tbw-filter-divider, var(--tbw-color-border, light-dark(#d0d0d4, #454545)))}.tbw-filter-apply-btn{flex:1;padding:6px 12px;background:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));color:var(--tbw-filter-accent-fg, var(--tbw-color-accent-fg, light-dark(#ffffff, #000000)));border:none;border-radius:4px;cursor:pointer;font-size:13px}.tbw-filter-apply-btn:hover{filter:brightness(.9)}.tbw-filter-clear-btn{flex:1;padding:6px 12px;background:transparent;color:var(--tbw-filter-muted, var(--tbw-color-fg-muted, light-dark(#555555, #aaaaaa)));border:1px solid var(--tbw-filter-input-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));border-radius:4px;cursor:pointer;font-size:13px}.tbw-filter-clear-btn:hover{background:var(--tbw-filter-hover, var(--tbw-color-row-hover, light-dark(#f0f6ff, #1c1c1c)))}";
246
281
  class x extends _ {
247
282
  name = "filtering";
248
283
  version = "1.0.0";
@@ -302,14 +337,16 @@ class x extends _ {
302
337
  const o = n.field;
303
338
  if (!o) return;
304
339
  const i = this.filters.has(o);
305
- let a = r.querySelector(".tbw-filter-btn");
306
- if (a) {
307
- a.classList.toggle("active", i), r.classList.toggle("filtered", i);
340
+ let s = r.querySelector(".tbw-filter-btn");
341
+ if (s) {
342
+ s.classList.toggle("active", i), r.classList.toggle("filtered", i);
308
343
  return;
309
344
  }
310
- a = document.createElement("button"), a.className = "tbw-filter-btn", a.setAttribute("aria-label", `Filter ${n.header ?? o}`), a.innerHTML = '<svg viewBox="0 0 16 16" width="12" height="12"><path fill="currentColor" d="M6 10.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5zm-2-3a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm-2-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5z"/></svg>', i && (a.classList.add("active"), r.classList.add("filtered")), a.addEventListener("click", (f) => {
311
- f.stopPropagation(), this.toggleFilterPanel(o, n, a);
312
- }), r.appendChild(a);
345
+ s = document.createElement("button"), s.className = "tbw-filter-btn", s.setAttribute("aria-label", `Filter ${n.header ?? o}`), s.innerHTML = '<svg viewBox="0 0 16 16" width="12" height="12"><path fill="currentColor" d="M6 10.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5zm-2-3a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm-2-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5z"/></svg>', i && (s.classList.add("active"), r.classList.add("filtered")), s.addEventListener("click", (b) => {
346
+ b.stopPropagation(), this.toggleFilterPanel(o, n, s);
347
+ });
348
+ const f = r.querySelector(".resize-handle");
349
+ f ? r.insertBefore(s, f) : r.appendChild(s);
313
350
  });
314
351
  }
315
352
  // #endregion
@@ -440,16 +477,16 @@ class x extends _ {
440
477
  applySetFilter: (f) => {
441
478
  this.applySetFilter(e, f), this.closeFilterPanel();
442
479
  },
443
- applyTextFilter: (f, g, C) => {
444
- this.applyTextFilter(e, f, g, C), this.closeFilterPanel();
480
+ applyTextFilter: (f, b, C) => {
481
+ this.applyTextFilter(e, f, b, C), this.closeFilterPanel();
445
482
  },
446
483
  clearFilter: () => {
447
484
  this.clearFieldFilter(e), this.closeFilterPanel();
448
485
  },
449
486
  closePanel: () => this.closeFilterPanel()
450
487
  };
451
- let a = !1;
452
- this.config.filterPanelRenderer && (this.config.filterPanelRenderer(r, i), a = r.children.length > 0), a || this.renderDefaultFilterPanel(r, i, l, n);
488
+ let s = !1;
489
+ this.config.filterPanelRenderer && (this.config.filterPanelRenderer(r, i), s = r.children.length > 0), s || this.renderDefaultFilterPanel(r, i, l, n);
453
490
  }
454
491
  /**
455
492
  * Setup click-outside handler to close the panel
@@ -489,38 +526,38 @@ class x extends _ {
489
526
  o.className = "tbw-filter-search";
490
527
  const i = document.createElement("input");
491
528
  i.type = "text", i.placeholder = "Search...", i.className = "tbw-filter-search-input", i.value = this.searchText.get(n) ?? "", o.appendChild(i), e.appendChild(o);
492
- const a = document.createElement("div");
493
- a.className = "tbw-filter-actions";
529
+ const s = document.createElement("div");
530
+ s.className = "tbw-filter-actions";
494
531
  const f = document.createElement("label");
495
532
  f.className = "tbw-filter-value-item", f.style.padding = "0", f.style.margin = "0";
496
- const g = document.createElement("input");
497
- g.type = "checkbox", g.className = "tbw-filter-checkbox";
533
+ const b = document.createElement("input");
534
+ b.type = "checkbox", b.className = "tbw-filter-checkbox";
498
535
  const C = document.createElement("span");
499
- C.textContent = "Select All", f.appendChild(g), f.appendChild(C), a.appendChild(f);
536
+ C.textContent = "Select All", f.appendChild(b), f.appendChild(C), s.appendChild(f);
500
537
  const k = () => {
501
- const s = [...m.values()], u = s.every((d) => d), h = s.every((d) => !d);
502
- g.checked = u, g.indeterminate = !u && !h;
538
+ const a = [...m.values()], u = a.every((d) => d), h = a.every((d) => !d);
539
+ b.checked = u, b.indeterminate = !u && !h;
503
540
  };
504
- g.addEventListener("change", () => {
505
- const s = g.checked;
541
+ b.addEventListener("change", () => {
542
+ const a = b.checked;
506
543
  for (const u of m.keys())
507
- m.set(u, s);
544
+ m.set(u, a);
508
545
  k(), F();
509
- }), e.appendChild(a);
546
+ }), e.appendChild(s);
510
547
  const v = document.createElement("div");
511
548
  v.className = "tbw-filter-values";
512
549
  const S = document.createElement("div");
513
550
  S.className = "tbw-filter-values-spacer", v.appendChild(S);
514
- const b = document.createElement("div");
515
- b.className = "tbw-filter-values-content", v.appendChild(b);
551
+ const g = document.createElement("div");
552
+ g.className = "tbw-filter-values-content", v.appendChild(g);
516
553
  const m = /* @__PURE__ */ new Map();
517
- r.forEach((s) => {
518
- const u = s == null ? "__null__" : String(s);
519
- m.set(u, !l.has(s));
554
+ r.forEach((a) => {
555
+ const u = a == null ? "__null__" : String(a);
556
+ m.set(u, !l.has(a));
520
557
  }), k();
521
558
  let y = [];
522
- const I = (s, u) => {
523
- const h = s == null ? "(Blank)" : String(s), d = s == null ? "__null__" : String(s), c = document.createElement("label");
559
+ const I = (a, u) => {
560
+ const h = a == null ? "(Blank)" : String(a), d = a == null ? "__null__" : String(a), c = document.createElement("label");
524
561
  c.className = "tbw-filter-value-item", c.style.position = "absolute", c.style.top = `${u * x.LIST_ITEM_HEIGHT}px`, c.style.left = "0", c.style.right = "0", c.style.height = `${x.LIST_ITEM_HEIGHT}px`, c.style.boxSizing = "border-box";
525
562
  const w = document.createElement("input");
526
563
  w.type = "checkbox", w.className = "tbw-filter-checkbox", w.checked = m.get(d) ?? !0, w.dataset.value = d, w.addEventListener("change", () => {
@@ -529,32 +566,32 @@ class x extends _ {
529
566
  const H = document.createElement("span");
530
567
  return H.textContent = h, c.appendChild(w), c.appendChild(H), c;
531
568
  }, F = () => {
532
- const s = y.length, u = v.clientHeight, h = v.scrollTop;
533
- if (S.style.height = `${s * x.LIST_ITEM_HEIGHT}px`, M(s, x.LIST_BYPASS_THRESHOLD / 3)) {
534
- b.innerHTML = "", b.style.transform = "translateY(0px)", y.forEach((c, w) => {
535
- b.appendChild(I(c, w));
569
+ const a = y.length, u = v.clientHeight, h = v.scrollTop;
570
+ if (S.style.height = `${a * x.LIST_ITEM_HEIGHT}px`, M(a, x.LIST_BYPASS_THRESHOLD / 3)) {
571
+ g.innerHTML = "", g.style.transform = "translateY(0px)", y.forEach((c, w) => {
572
+ g.appendChild(I(c, w));
536
573
  });
537
574
  return;
538
575
  }
539
576
  const d = P({
540
- totalRows: s,
577
+ totalRows: a,
541
578
  viewportHeight: u,
542
579
  scrollTop: h,
543
580
  rowHeight: x.LIST_ITEM_HEIGHT,
544
581
  overscan: x.LIST_OVERSCAN
545
582
  });
546
- b.style.transform = `translateY(${d.offsetY}px)`, b.innerHTML = "";
583
+ g.style.transform = `translateY(${d.offsetY}px)`, g.innerHTML = "";
547
584
  for (let c = d.start; c < d.end; c++)
548
- b.appendChild(I(y[c], c - d.start));
549
- }, L = (s) => {
550
- const u = s.toLowerCase();
585
+ g.appendChild(I(y[c], c - d.start));
586
+ }, L = (a) => {
587
+ const u = a.toLowerCase();
551
588
  if (y = r.filter((h) => {
552
589
  const d = h == null ? "(Blank)" : String(h);
553
- return !s || d.toLowerCase().includes(u);
590
+ return !a || d.toLowerCase().includes(u);
554
591
  }), y.length === 0) {
555
- S.style.height = "0px", b.innerHTML = "";
592
+ S.style.height = "0px", g.innerHTML = "";
556
593
  const h = document.createElement("div");
557
- h.className = "tbw-filter-no-match", h.textContent = "No matching values", b.appendChild(h);
594
+ h.className = "tbw-filter-no-match", h.textContent = "No matching values", g.appendChild(h);
558
595
  return;
559
596
  }
560
597
  F();
@@ -576,16 +613,16 @@ class x extends _ {
576
613
  T.className = "tbw-filter-buttons";
577
614
  const E = document.createElement("button");
578
615
  E.className = "tbw-filter-apply-btn", E.textContent = "Apply", E.addEventListener("click", () => {
579
- const s = [];
616
+ const a = [];
580
617
  for (const [u, h] of m)
581
618
  if (!h)
582
619
  if (u === "__null__")
583
- s.push(null);
620
+ a.push(null);
584
621
  else {
585
622
  const d = r.find((c) => String(c) === u);
586
- s.push(d !== void 0 ? d : u);
623
+ a.push(d !== void 0 ? d : u);
587
624
  }
588
- t.applySetFilter(s);
625
+ t.applySetFilter(a);
589
626
  }), T.appendChild(E);
590
627
  const R = document.createElement("button");
591
628
  R.className = "tbw-filter-clear-btn", R.textContent = "Clear Filter", R.addEventListener("click", () => {