@toolbox-web/grid 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/README.md +10 -13
  2. package/all.js +1101 -1048
  3. package/all.js.map +1 -1
  4. package/index.js +245 -137
  5. package/index.js.map +1 -1
  6. package/lib/core/grid.d.ts +10 -0
  7. package/lib/core/grid.d.ts.map +1 -1
  8. package/lib/core/internal/config-manager.d.ts +1 -0
  9. package/lib/core/internal/config-manager.d.ts.map +1 -1
  10. package/lib/core/internal/keyboard.d.ts.map +1 -1
  11. package/lib/core/internal/utils.d.ts +1 -0
  12. package/lib/core/internal/utils.d.ts.map +1 -1
  13. package/lib/core/plugin/base-plugin.d.ts +57 -1
  14. package/lib/core/plugin/base-plugin.d.ts.map +1 -1
  15. package/lib/core/plugin/expander-column.d.ts +51 -0
  16. package/lib/core/plugin/expander-column.d.ts.map +1 -0
  17. package/lib/core/plugin/types.d.ts +117 -1
  18. package/lib/core/plugin/types.d.ts.map +1 -1
  19. package/lib/core/types.d.ts +4 -2
  20. package/lib/core/types.d.ts.map +1 -1
  21. package/lib/plugins/clipboard/ClipboardPlugin.d.ts +5 -4
  22. package/lib/plugins/clipboard/ClipboardPlugin.d.ts.map +1 -1
  23. package/lib/plugins/clipboard/index.d.ts +1 -1
  24. package/lib/plugins/clipboard/index.d.ts.map +1 -1
  25. package/lib/plugins/clipboard/index.js +282 -188
  26. package/lib/plugins/clipboard/index.js.map +1 -1
  27. package/lib/plugins/clipboard/types.d.ts +72 -2
  28. package/lib/plugins/clipboard/types.d.ts.map +1 -1
  29. package/lib/plugins/column-virtualization/ColumnVirtualizationPlugin.d.ts +0 -1
  30. package/lib/plugins/column-virtualization/ColumnVirtualizationPlugin.d.ts.map +1 -1
  31. package/lib/plugins/column-virtualization/index.js +102 -26
  32. package/lib/plugins/column-virtualization/index.js.map +1 -1
  33. package/lib/plugins/context-menu/ContextMenuPlugin.d.ts +0 -1
  34. package/lib/plugins/context-menu/ContextMenuPlugin.d.ts.map +1 -1
  35. package/lib/plugins/context-menu/index.js +154 -78
  36. package/lib/plugins/context-menu/index.js.map +1 -1
  37. package/lib/plugins/editing/EditingPlugin.d.ts +1 -7
  38. package/lib/plugins/editing/EditingPlugin.d.ts.map +1 -1
  39. package/lib/plugins/editing/index.js +200 -136
  40. package/lib/plugins/editing/index.js.map +1 -1
  41. package/lib/plugins/export/ExportPlugin.d.ts +0 -1
  42. package/lib/plugins/export/ExportPlugin.d.ts.map +1 -1
  43. package/lib/plugins/export/index.js +175 -99
  44. package/lib/plugins/export/index.js.map +1 -1
  45. package/lib/plugins/filtering/FilteringPlugin.d.ts +5 -2
  46. package/lib/plugins/filtering/FilteringPlugin.d.ts.map +1 -1
  47. package/lib/plugins/filtering/index.js +129 -43
  48. package/lib/plugins/filtering/index.js.map +1 -1
  49. package/lib/plugins/grouping-columns/GroupingColumnsPlugin.d.ts +1 -2
  50. package/lib/plugins/grouping-columns/GroupingColumnsPlugin.d.ts.map +1 -1
  51. package/lib/plugins/grouping-columns/grouping-columns.d.ts +1 -1
  52. package/lib/plugins/grouping-columns/grouping-columns.d.ts.map +1 -1
  53. package/lib/plugins/grouping-columns/index.js +144 -66
  54. package/lib/plugins/grouping-columns/index.js.map +1 -1
  55. package/lib/plugins/grouping-rows/GroupingRowsPlugin.d.ts +14 -2
  56. package/lib/plugins/grouping-rows/GroupingRowsPlugin.d.ts.map +1 -1
  57. package/lib/plugins/grouping-rows/index.js +230 -138
  58. package/lib/plugins/grouping-rows/index.js.map +1 -1
  59. package/lib/plugins/master-detail/MasterDetailPlugin.d.ts +13 -11
  60. package/lib/plugins/master-detail/MasterDetailPlugin.d.ts.map +1 -1
  61. package/lib/plugins/master-detail/index.js +265 -196
  62. package/lib/plugins/master-detail/index.js.map +1 -1
  63. package/lib/plugins/master-detail/types.d.ts +0 -10
  64. package/lib/plugins/master-detail/types.d.ts.map +1 -1
  65. package/lib/plugins/multi-sort/MultiSortPlugin.d.ts +1 -2
  66. package/lib/plugins/multi-sort/MultiSortPlugin.d.ts.map +1 -1
  67. package/lib/plugins/multi-sort/index.js +105 -31
  68. package/lib/plugins/multi-sort/index.js.map +1 -1
  69. package/lib/plugins/pinned-columns/PinnedColumnsPlugin.d.ts +0 -1
  70. package/lib/plugins/pinned-columns/PinnedColumnsPlugin.d.ts.map +1 -1
  71. package/lib/plugins/pinned-columns/index.js +128 -52
  72. package/lib/plugins/pinned-columns/index.js.map +1 -1
  73. package/lib/plugins/pinned-rows/PinnedRowsPlugin.d.ts +1 -2
  74. package/lib/plugins/pinned-rows/PinnedRowsPlugin.d.ts.map +1 -1
  75. package/lib/plugins/pinned-rows/index.js +162 -88
  76. package/lib/plugins/pinned-rows/index.js.map +1 -1
  77. package/lib/plugins/pivot/PivotPlugin.d.ts +26 -4
  78. package/lib/plugins/pivot/PivotPlugin.d.ts.map +1 -1
  79. package/lib/plugins/pivot/index.js +398 -310
  80. package/lib/plugins/pivot/index.js.map +1 -1
  81. package/lib/plugins/pivot/pivot-rows.d.ts +2 -1
  82. package/lib/plugins/pivot/pivot-rows.d.ts.map +1 -1
  83. package/lib/plugins/reorder/ReorderPlugin.d.ts +13 -10
  84. package/lib/plugins/reorder/ReorderPlugin.d.ts.map +1 -1
  85. package/lib/plugins/reorder/index.js +288 -226
  86. package/lib/plugins/reorder/index.js.map +1 -1
  87. package/lib/plugins/selection/SelectionPlugin.d.ts +21 -3
  88. package/lib/plugins/selection/SelectionPlugin.d.ts.map +1 -1
  89. package/lib/plugins/selection/index.d.ts +2 -2
  90. package/lib/plugins/selection/index.d.ts.map +1 -1
  91. package/lib/plugins/selection/index.js +276 -145
  92. package/lib/plugins/selection/index.js.map +1 -1
  93. package/lib/plugins/selection/types.d.ts +24 -0
  94. package/lib/plugins/selection/types.d.ts.map +1 -1
  95. package/lib/plugins/server-side/ServerSidePlugin.d.ts +0 -1
  96. package/lib/plugins/server-side/ServerSidePlugin.d.ts.map +1 -1
  97. package/lib/plugins/server-side/index.js +83 -7
  98. package/lib/plugins/server-side/index.js.map +1 -1
  99. package/lib/plugins/tree/TreePlugin.d.ts +5 -1
  100. package/lib/plugins/tree/TreePlugin.d.ts.map +1 -1
  101. package/lib/plugins/tree/index.js +197 -112
  102. package/lib/plugins/tree/index.js.map +1 -1
  103. package/lib/plugins/tree/types.d.ts +0 -10
  104. package/lib/plugins/tree/types.d.ts.map +1 -1
  105. package/lib/plugins/undo-redo/UndoRedoPlugin.d.ts +0 -1
  106. package/lib/plugins/undo-redo/UndoRedoPlugin.d.ts.map +1 -1
  107. package/lib/plugins/undo-redo/index.js +93 -17
  108. package/lib/plugins/undo-redo/index.js.map +1 -1
  109. package/lib/plugins/visibility/VisibilityPlugin.d.ts +7 -4
  110. package/lib/plugins/visibility/VisibilityPlugin.d.ts.map +1 -1
  111. package/lib/plugins/visibility/index.js +144 -65
  112. package/lib/plugins/visibility/index.js.map +1 -1
  113. package/package.json +1 -1
  114. package/umd/grid.all.umd.js +17 -19
  115. package/umd/grid.all.umd.js.map +1 -1
  116. package/umd/grid.umd.js +7 -7
  117. package/umd/grid.umd.js.map +1 -1
  118. package/umd/plugins/clipboard.umd.js +5 -7
  119. package/umd/plugins/clipboard.umd.js.map +1 -1
  120. package/umd/plugins/column-virtualization.umd.js +1 -1
  121. package/umd/plugins/column-virtualization.umd.js.map +1 -1
  122. package/umd/plugins/context-menu.umd.js +1 -1
  123. package/umd/plugins/context-menu.umd.js.map +1 -1
  124. package/umd/plugins/editing.umd.js +1 -1
  125. package/umd/plugins/editing.umd.js.map +1 -1
  126. package/umd/plugins/export.umd.js +1 -1
  127. package/umd/plugins/export.umd.js.map +1 -1
  128. package/umd/plugins/filtering.umd.js +1 -1
  129. package/umd/plugins/filtering.umd.js.map +1 -1
  130. package/umd/plugins/grouping-columns.umd.js +1 -1
  131. package/umd/plugins/grouping-columns.umd.js.map +1 -1
  132. package/umd/plugins/grouping-rows.umd.js +1 -1
  133. package/umd/plugins/grouping-rows.umd.js.map +1 -1
  134. package/umd/plugins/master-detail.umd.js +1 -1
  135. package/umd/plugins/master-detail.umd.js.map +1 -1
  136. package/umd/plugins/multi-sort.umd.js +1 -1
  137. package/umd/plugins/multi-sort.umd.js.map +1 -1
  138. package/umd/plugins/pinned-columns.umd.js +1 -1
  139. package/umd/plugins/pinned-columns.umd.js.map +1 -1
  140. package/umd/plugins/pinned-rows.umd.js +1 -1
  141. package/umd/plugins/pinned-rows.umd.js.map +1 -1
  142. package/umd/plugins/pivot.umd.js +1 -1
  143. package/umd/plugins/pivot.umd.js.map +1 -1
  144. package/umd/plugins/reorder.umd.js +1 -1
  145. package/umd/plugins/reorder.umd.js.map +1 -1
  146. package/umd/plugins/selection.umd.js +1 -1
  147. package/umd/plugins/selection.umd.js.map +1 -1
  148. package/umd/plugins/server-side.umd.js +1 -1
  149. package/umd/plugins/server-side.umd.js.map +1 -1
  150. package/umd/plugins/tree.umd.js +1 -1
  151. package/umd/plugins/tree.umd.js.map +1 -1
  152. package/umd/plugins/undo-redo.umd.js +1 -1
  153. package/umd/plugins/undo-redo.umd.js.map +1 -1
  154. package/umd/plugins/visibility.umd.js +1 -1
  155. package/umd/plugins/visibility.umd.js.map +1 -1
  156. package/lib/core/internal/editing.d.ts +0 -76
  157. package/lib/core/internal/editing.d.ts.map +0 -1
@@ -10,7 +10,7 @@ function P(p) {
10
10
  totalHeight: e * l
11
11
  };
12
12
  }
13
- function M(p, e) {
13
+ function _(p, e) {
14
14
  return p <= e;
15
15
  }
16
16
  const V = {
@@ -23,7 +23,7 @@ const V = {
23
23
  dragHandle: "⋮⋮",
24
24
  toolPanel: "☰"
25
25
  };
26
- class _ {
26
+ class M {
27
27
  /**
28
28
  * Plugin dependencies - declare other plugins this one requires.
29
29
  *
@@ -40,8 +40,11 @@ class _ {
40
40
  * ```
41
41
  */
42
42
  static dependencies;
43
- /** Plugin version - override in subclass if needed */
44
- version = "1.0.0";
43
+ /**
44
+ * Plugin version - defaults to grid version for built-in plugins.
45
+ * Third-party plugins can override with their own semver.
46
+ */
47
+ version = typeof __GRID_VERSION__ < "u" ? __GRID_VERSION__ : "dev";
45
48
  /** CSS styles to inject into the grid's shadow DOM */
46
49
  styles;
47
50
  /** Custom cell renderers keyed by type name */
@@ -128,12 +131,28 @@ class _ {
128
131
  emit(e, t) {
129
132
  this.grid?.dispatchEvent?.(new CustomEvent(e, { detail: t, bubbles: !0 }));
130
133
  }
134
+ /**
135
+ * Emit a cancelable custom event from the grid.
136
+ * @returns `true` if the event was cancelled (preventDefault called), `false` otherwise
137
+ */
138
+ emitCancelable(e, t) {
139
+ const r = new CustomEvent(e, { detail: t, bubbles: !0, cancelable: !0 });
140
+ return this.grid?.dispatchEvent?.(r), r.defaultPrevented;
141
+ }
131
142
  /**
132
143
  * Request a re-render of the grid.
133
144
  */
134
145
  requestRender() {
135
146
  this.grid?.requestRender?.();
136
147
  }
148
+ /**
149
+ * Request a re-render and restore focus styling afterward.
150
+ * Use this when a plugin action (like expand/collapse) triggers a render
151
+ * but needs to maintain keyboard navigation focus.
152
+ */
153
+ requestRenderWithFocus() {
154
+ this.grid?.requestRenderWithFocus?.();
155
+ }
137
156
  /**
138
157
  * Request a lightweight style update without rebuilding DOM.
139
158
  * Use this instead of requestRender() when only CSS classes need updating.
@@ -167,6 +186,19 @@ class _ {
167
186
  get visibleColumns() {
168
187
  return this.grid?._visibleColumns ?? [];
169
188
  }
189
+ /**
190
+ * Get the grid as an HTMLElement for direct DOM operations.
191
+ * Use sparingly - prefer the typed GridElementRef API when possible.
192
+ *
193
+ * @example
194
+ * ```ts
195
+ * const width = this.gridElement.clientWidth;
196
+ * this.gridElement.classList.add('my-plugin-active');
197
+ * ```
198
+ */
199
+ get gridElement() {
200
+ return this.grid;
201
+ }
170
202
  /**
171
203
  * Get the shadow root of the grid.
172
204
  */
@@ -201,6 +233,51 @@ class _ {
201
233
  const e = this.grid?.gridConfig?.icons ?? {};
202
234
  return { ...V, ...e };
203
235
  }
236
+ // #region Animation Helpers
237
+ /**
238
+ * Check if animations are enabled at the grid level.
239
+ * Respects gridConfig.animation.mode and the CSS variable set by the grid.
240
+ *
241
+ * Plugins should use this to skip animations when:
242
+ * - Animation mode is 'off' or `false`
243
+ * - User prefers reduced motion and mode is 'reduced-motion' (default)
244
+ *
245
+ * @example
246
+ * ```ts
247
+ * private get animationStyle(): 'slide' | 'fade' | false {
248
+ * if (!this.isAnimationEnabled) return false;
249
+ * return this.config.animation ?? 'slide';
250
+ * }
251
+ * ```
252
+ */
253
+ get isAnimationEnabled() {
254
+ const e = this.grid?.effectiveConfig?.animation?.mode ?? "reduced-motion";
255
+ if (e === !1 || e === "off") return !1;
256
+ if (e === !0 || e === "on") return !0;
257
+ const t = this.shadowRoot?.host;
258
+ return t ? getComputedStyle(t).getPropertyValue("--tbw-animation-enabled").trim() !== "0" : !0;
259
+ }
260
+ /**
261
+ * Get the animation duration in milliseconds from CSS variable.
262
+ * Falls back to 200ms if not set.
263
+ *
264
+ * Plugins can use this for their animation timing to stay consistent
265
+ * with the grid-level animation.duration setting.
266
+ *
267
+ * @example
268
+ * ```ts
269
+ * element.animate(keyframes, { duration: this.animationDuration });
270
+ * ```
271
+ */
272
+ get animationDuration() {
273
+ const e = this.shadowRoot?.host;
274
+ if (e) {
275
+ const t = getComputedStyle(e).getPropertyValue("--tbw-animation-duration").trim(), r = parseInt(t, 10);
276
+ if (!isNaN(r)) return r;
277
+ }
278
+ return 200;
279
+ }
280
+ // #endregion
204
281
  /**
205
282
  * Resolve an icon value to string or HTMLElement.
206
283
  * Checks plugin config first, then grid-level icons, then defaults.
@@ -293,10 +370,10 @@ function N(p, e) {
293
370
  }
294
371
  return [...t].sort((r, l) => typeof r == "number" && typeof l == "number" ? r - l : String(r).localeCompare(String(l)));
295
372
  }
296
- 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)))}";
297
- class x extends _ {
373
+ const G = ':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))}', $ = ".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)))}";
374
+ class x extends M {
298
375
  name = "filtering";
299
- version = "1.0.0";
376
+ styles = G;
300
377
  get defaultConfig() {
301
378
  return {
302
379
  debounceMs: 300,
@@ -321,6 +398,12 @@ class x extends _ {
321
398
  static LIST_OVERSCAN = 3;
322
399
  static LIST_BYPASS_THRESHOLD = 50;
323
400
  // Don't virtualize if < 50 items
401
+ /**
402
+ * Sync excludedValues map from a filter model (for set filters).
403
+ */
404
+ syncExcludedValues(e, t) {
405
+ t ? t.type === "set" && t.operator === "notIn" && Array.isArray(t.value) ? this.excludedValues.set(e, new Set(t.value)) : t.type === "set" && this.excludedValues.delete(e) : this.excludedValues.delete(e);
406
+ }
324
407
  // #endregion
325
408
  // #region Lifecycle
326
409
  attach(e) {
@@ -372,7 +455,13 @@ class x extends _ {
372
455
  * Pass null to remove the filter.
373
456
  */
374
457
  setFilter(e, t) {
375
- t === null ? (this.filters.delete(e), this.excludedValues.delete(e)) : (this.filters.set(e, { ...t, field: e }), t.type === "set" && t.operator === "notIn" && Array.isArray(t.value) ? this.excludedValues.set(e, new Set(t.value)) : t.type === "set" && this.excludedValues.delete(e)), this.cachedResult = null, this.cacheKey = null, this.emit("filter-change", {
458
+ if (t === null)
459
+ this.filters.delete(e), this.syncExcludedValues(e, null);
460
+ else {
461
+ const r = { ...t, field: e };
462
+ this.filters.set(e, r), this.syncExcludedValues(e, r);
463
+ }
464
+ this.cachedResult = null, this.cacheKey = null, this.emit("filter-change", {
376
465
  filters: [...this.filters.values()],
377
466
  filteredRowCount: 0
378
467
  // Will be accurate after processRows
@@ -402,7 +491,7 @@ class x extends _ {
402
491
  setFilterModel(e) {
403
492
  this.filters.clear(), this.excludedValues.clear();
404
493
  for (const t of e)
405
- this.filters.set(t.field, t), t.type === "set" && t.operator === "notIn" && Array.isArray(t.value) && this.excludedValues.set(t.field, new Set(t.value));
494
+ this.filters.set(t.field, t), this.syncExcludedValues(t.field, t);
406
495
  this.cachedResult = null, this.cacheKey = null, this.emit("filter-change", {
407
496
  filters: [...this.filters.values()],
408
497
  filteredRowCount: 0
@@ -457,7 +546,7 @@ class x extends _ {
457
546
  return;
458
547
  }
459
548
  const e = document.createElement("style");
460
- e.id = "tbw-filter-panel-styles", e.textContent = K, document.head.appendChild(e), this.globalStylesInjected = !0;
549
+ e.id = "tbw-filter-panel-styles", e.textContent = $, document.head.appendChild(e), this.globalStylesInjected = !0;
461
550
  }
462
551
  /**
463
552
  * Toggle the filter panel for a field
@@ -551,39 +640,39 @@ class x extends _ {
551
640
  const C = document.createElement("span");
552
641
  C.textContent = "Select All", f.appendChild(b), f.appendChild(C), s.appendChild(f);
553
642
  const k = () => {
554
- const a = [...m.values()], u = a.every((d) => d), h = a.every((d) => !d);
643
+ const a = [...v.values()], u = a.every((d) => d), h = a.every((d) => !d);
555
644
  b.checked = u, b.indeterminate = !u && !h;
556
645
  };
557
646
  b.addEventListener("change", () => {
558
647
  const a = b.checked;
559
- for (const u of m.keys())
560
- m.set(u, a);
648
+ for (const u of v.keys())
649
+ v.set(u, a);
561
650
  k(), F();
562
651
  }), e.appendChild(s);
563
- const v = document.createElement("div");
564
- v.className = "tbw-filter-values";
565
- const S = document.createElement("div");
566
- S.className = "tbw-filter-values-spacer", v.appendChild(S);
652
+ const m = document.createElement("div");
653
+ m.className = "tbw-filter-values";
654
+ const E = document.createElement("div");
655
+ E.className = "tbw-filter-values-spacer", m.appendChild(E);
567
656
  const g = document.createElement("div");
568
- g.className = "tbw-filter-values-content", v.appendChild(g);
569
- const m = /* @__PURE__ */ new Map();
657
+ g.className = "tbw-filter-values-content", m.appendChild(g);
658
+ const v = /* @__PURE__ */ new Map();
570
659
  r.forEach((a) => {
571
660
  const u = a == null ? "__null__" : String(a);
572
- m.set(u, !l.has(a));
661
+ v.set(u, !l.has(a));
573
662
  }), k();
574
663
  let y = [];
575
664
  const I = (a, u) => {
576
665
  const h = a == null ? "(Blank)" : String(a), d = a == null ? "__null__" : String(a), c = document.createElement("label");
577
666
  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";
578
667
  const w = document.createElement("input");
579
- w.type = "checkbox", w.className = "tbw-filter-checkbox", w.checked = m.get(d) ?? !0, w.dataset.value = d, w.addEventListener("change", () => {
580
- m.set(d, w.checked), k();
668
+ w.type = "checkbox", w.className = "tbw-filter-checkbox", w.checked = v.get(d) ?? !0, w.dataset.value = d, w.addEventListener("change", () => {
669
+ v.set(d, w.checked), k();
581
670
  });
582
- const H = document.createElement("span");
583
- return H.textContent = h, c.appendChild(w), c.appendChild(H), c;
671
+ const A = document.createElement("span");
672
+ return A.textContent = h, c.appendChild(w), c.appendChild(A), c;
584
673
  }, F = () => {
585
- const a = y.length, u = v.clientHeight, h = v.scrollTop;
586
- if (S.style.height = `${a * x.LIST_ITEM_HEIGHT}px`, M(a, x.LIST_BYPASS_THRESHOLD / 3)) {
674
+ const a = y.length, u = m.clientHeight, h = m.scrollTop;
675
+ if (E.style.height = `${a * x.LIST_ITEM_HEIGHT}px`, _(a, x.LIST_BYPASS_THRESHOLD / 3)) {
587
676
  g.innerHTML = "", g.style.transform = "translateY(0px)", y.forEach((c, w) => {
588
677
  g.appendChild(I(c, w));
589
678
  });
@@ -605,32 +694,32 @@ class x extends _ {
605
694
  const d = h == null ? "(Blank)" : String(h);
606
695
  return !a || d.toLowerCase().includes(u);
607
696
  }), y.length === 0) {
608
- S.style.height = "0px", g.innerHTML = "";
697
+ E.style.height = "0px", g.innerHTML = "";
609
698
  const h = document.createElement("div");
610
699
  h.className = "tbw-filter-no-match", h.textContent = "No matching values", g.appendChild(h);
611
700
  return;
612
701
  }
613
702
  F();
614
703
  };
615
- v.addEventListener(
704
+ m.addEventListener(
616
705
  "scroll",
617
706
  () => {
618
707
  y.length > 0 && F();
619
708
  },
620
709
  { passive: !0 }
621
- ), L(i.value), e.appendChild(v);
622
- let A;
710
+ ), L(i.value), e.appendChild(m);
711
+ let H;
623
712
  i.addEventListener("input", () => {
624
- clearTimeout(A), A = setTimeout(() => {
713
+ clearTimeout(H), H = setTimeout(() => {
625
714
  this.searchText.set(n, i.value), L(i.value);
626
715
  }, this.config.debounceMs ?? 150);
627
716
  });
628
- const T = document.createElement("div");
629
- T.className = "tbw-filter-buttons";
630
- const E = document.createElement("button");
631
- E.className = "tbw-filter-apply-btn", E.textContent = "Apply", E.addEventListener("click", () => {
717
+ const S = document.createElement("div");
718
+ S.className = "tbw-filter-buttons";
719
+ const R = document.createElement("button");
720
+ R.className = "tbw-filter-apply-btn", R.textContent = "Apply", R.addEventListener("click", () => {
632
721
  const a = [];
633
- for (const [u, h] of m)
722
+ for (const [u, h] of v)
634
723
  if (!h)
635
724
  if (u === "__null__")
636
725
  a.push(null);
@@ -639,11 +728,11 @@ class x extends _ {
639
728
  a.push(d !== void 0 ? d : u);
640
729
  }
641
730
  t.applySetFilter(a);
642
- }), T.appendChild(E);
643
- const R = document.createElement("button");
644
- R.className = "tbw-filter-clear-btn", R.textContent = "Clear Filter", R.addEventListener("click", () => {
731
+ }), S.appendChild(R);
732
+ const T = document.createElement("button");
733
+ T.className = "tbw-filter-clear-btn", T.textContent = "Clear Filter", T.addEventListener("click", () => {
645
734
  t.clearFilter();
646
- }), T.appendChild(R), e.appendChild(T);
735
+ }), S.appendChild(T), e.appendChild(S);
647
736
  }
648
737
  /**
649
738
  * Apply a set filter (exclude values)
@@ -726,9 +815,6 @@ class x extends _ {
726
815
  this.filters.set(e, r), this.cachedResult = null, this.cacheKey = null;
727
816
  }
728
817
  // #endregion
729
- // #region Styles
730
- styles = $;
731
- // #endregion
732
818
  }
733
819
  export {
734
820
  x as FilteringPlugin