@toolbox-web/grid 1.14.0 → 1.15.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 (82) hide show
  1. package/README.md +5 -1
  2. package/all.js +1888 -1433
  3. package/all.js.map +1 -1
  4. package/index.js +188 -149
  5. package/index.js.map +1 -1
  6. package/lib/core/grid.d.ts.map +1 -1
  7. package/lib/core/internal/loading.d.ts +2 -0
  8. package/lib/core/internal/loading.d.ts.map +1 -1
  9. package/lib/core/internal/rows.d.ts.map +1 -1
  10. package/lib/core/internal/validate-config.d.ts.map +1 -1
  11. package/lib/plugins/column-virtualization/ColumnVirtualizationPlugin.d.ts.map +1 -1
  12. package/lib/plugins/column-virtualization/index.js +1 -1
  13. package/lib/plugins/column-virtualization/index.js.map +1 -1
  14. package/lib/plugins/context-menu/ContextMenuPlugin.d.ts +20 -1
  15. package/lib/plugins/context-menu/ContextMenuPlugin.d.ts.map +1 -1
  16. package/lib/plugins/context-menu/index.d.ts +1 -1
  17. package/lib/plugins/context-menu/index.d.ts.map +1 -1
  18. package/lib/plugins/context-menu/index.js +153 -70
  19. package/lib/plugins/context-menu/index.js.map +1 -1
  20. package/lib/plugins/context-menu/menu.d.ts +7 -0
  21. package/lib/plugins/context-menu/menu.d.ts.map +1 -1
  22. package/lib/plugins/context-menu/types.d.ts +46 -0
  23. package/lib/plugins/context-menu/types.d.ts.map +1 -1
  24. package/lib/plugins/editing/EditingPlugin.d.ts.map +1 -1
  25. package/lib/plugins/editing/index.js +214 -197
  26. package/lib/plugins/editing/index.js.map +1 -1
  27. package/lib/plugins/filtering/FilteringPlugin.d.ts +9 -1
  28. package/lib/plugins/filtering/FilteringPlugin.d.ts.map +1 -1
  29. package/lib/plugins/filtering/filter-model.d.ts.map +1 -1
  30. package/lib/plugins/filtering/index.js +348 -283
  31. package/lib/plugins/filtering/index.js.map +1 -1
  32. package/lib/plugins/grouping-columns/GroupingColumnsPlugin.d.ts +5 -1
  33. package/lib/plugins/grouping-columns/GroupingColumnsPlugin.d.ts.map +1 -1
  34. package/lib/plugins/grouping-columns/index.js +242 -109
  35. package/lib/plugins/grouping-columns/index.js.map +1 -1
  36. package/lib/plugins/grouping-columns/types.d.ts +7 -0
  37. package/lib/plugins/grouping-columns/types.d.ts.map +1 -1
  38. package/lib/plugins/pinned-columns/PinnedColumnsPlugin.d.ts +11 -1
  39. package/lib/plugins/pinned-columns/PinnedColumnsPlugin.d.ts.map +1 -1
  40. package/lib/plugins/pinned-columns/index.d.ts +1 -1
  41. package/lib/plugins/pinned-columns/index.d.ts.map +1 -1
  42. package/lib/plugins/pinned-columns/index.js +174 -79
  43. package/lib/plugins/pinned-columns/index.js.map +1 -1
  44. package/lib/plugins/pinned-columns/pinned-columns.d.ts +23 -4
  45. package/lib/plugins/pinned-columns/pinned-columns.d.ts.map +1 -1
  46. package/lib/plugins/pinned-columns/types.d.ts +21 -9
  47. package/lib/plugins/pinned-columns/types.d.ts.map +1 -1
  48. package/lib/plugins/reorder/index.js.map +1 -1
  49. package/lib/plugins/responsive/index.js.map +1 -1
  50. package/lib/plugins/row-reorder/index.js.map +1 -1
  51. package/lib/plugins/selection/SelectionPlugin.d.ts.map +1 -1
  52. package/lib/plugins/selection/index.js +122 -122
  53. package/lib/plugins/selection/index.js.map +1 -1
  54. package/lib/plugins/visibility/VisibilityPlugin.d.ts +42 -2
  55. package/lib/plugins/visibility/VisibilityPlugin.d.ts.map +1 -1
  56. package/lib/plugins/visibility/index.d.ts +1 -1
  57. package/lib/plugins/visibility/index.d.ts.map +1 -1
  58. package/lib/plugins/visibility/index.js +219 -59
  59. package/lib/plugins/visibility/index.js.map +1 -1
  60. package/lib/plugins/visibility/types.d.ts +25 -0
  61. package/lib/plugins/visibility/types.d.ts.map +1 -1
  62. package/package.json +1 -1
  63. package/umd/grid.all.umd.js +30 -30
  64. package/umd/grid.all.umd.js.map +1 -1
  65. package/umd/grid.umd.js +4 -4
  66. package/umd/grid.umd.js.map +1 -1
  67. package/umd/plugins/column-virtualization.umd.js +1 -1
  68. package/umd/plugins/column-virtualization.umd.js.map +1 -1
  69. package/umd/plugins/context-menu.umd.js +1 -1
  70. package/umd/plugins/context-menu.umd.js.map +1 -1
  71. package/umd/plugins/editing.umd.js +1 -1
  72. package/umd/plugins/editing.umd.js.map +1 -1
  73. package/umd/plugins/filtering.umd.js +1 -1
  74. package/umd/plugins/filtering.umd.js.map +1 -1
  75. package/umd/plugins/grouping-columns.umd.js +1 -1
  76. package/umd/plugins/grouping-columns.umd.js.map +1 -1
  77. package/umd/plugins/pinned-columns.umd.js +1 -1
  78. package/umd/plugins/pinned-columns.umd.js.map +1 -1
  79. package/umd/plugins/selection.umd.js +2 -2
  80. package/umd/plugins/selection.umd.js.map +1 -1
  81. package/umd/plugins/visibility.umd.js +1 -1
  82. package/umd/plugins/visibility.umd.js.map +1 -1
@@ -1,19 +1,19 @@
1
- function Y(N) {
2
- const { totalRows: e, viewportHeight: t, scrollTop: r, rowHeight: i, overscan: l } = N, c = Math.ceil(t / i);
3
- let d = Math.floor(r / i) - l;
4
- d < 0 && (d = 0);
5
- let a = d + c + l * 2;
6
- return a > e && (a = e), a === e && d > 0 && (d = Math.max(0, a - c - l * 2)), {
7
- start: d,
1
+ function G(x) {
2
+ const { totalRows: e, viewportHeight: t, scrollTop: r, rowHeight: n, overscan: i } = x, l = Math.ceil(t / n);
3
+ let u = Math.floor(r / n) - i;
4
+ u < 0 && (u = 0);
5
+ let a = u + l + i * 2;
6
+ return a > e && (a = e), a === e && u > 0 && (u = Math.max(0, a - l - i * 2)), {
7
+ start: u,
8
8
  end: a,
9
- offsetY: d * i,
10
- totalHeight: e * i
9
+ offsetY: u * n,
10
+ totalHeight: e * n
11
11
  };
12
12
  }
13
- function G(N, e) {
14
- return N <= e;
13
+ function $(x, e) {
14
+ return x <= e;
15
15
  }
16
- const z = '<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>', $ = {
16
+ const B = '<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>', K = {
17
17
  expand: "▶",
18
18
  collapse: "▼",
19
19
  sortAsc: "▲",
@@ -22,11 +22,11 @@ const z = '<svg viewBox="0 0 16 16" width="12" height="12"><path fill="currentCo
22
22
  submenuArrow: "▶",
23
23
  dragHandle: "⋮⋮",
24
24
  toolPanel: "☰",
25
- filter: z,
26
- filterActive: z,
25
+ filter: B,
26
+ filterActive: B,
27
27
  print: "🖨️"
28
28
  };
29
- class K {
29
+ class W {
30
30
  /**
31
31
  * Plugin dependencies - declare other plugins this one requires.
32
32
  *
@@ -316,7 +316,7 @@ class K {
316
316
  */
317
317
  get gridIcons() {
318
318
  const e = this.grid?.gridConfig?.icons ?? {};
319
- return { ...$, ...e };
319
+ return { ...K, ...e };
320
320
  }
321
321
  // #region Animation Helpers
322
322
  /**
@@ -392,42 +392,47 @@ class K {
392
392
  }
393
393
  // #endregion
394
394
  }
395
- function W(N) {
396
- return N.meta?.utility === !0;
395
+ function U(x) {
396
+ return x.meta?.utility === !0;
397
397
  }
398
- function j(N, e, t = !1) {
399
- const r = N[e.field];
398
+ function V(x) {
399
+ if (x instanceof Date) return x.getTime();
400
+ const e = Number(x);
401
+ return isNaN(e) ? new Date(x).getTime() : e;
402
+ }
403
+ function j(x, e, t = !1) {
404
+ const r = x[e.field];
400
405
  if (e.operator === "blank")
401
406
  return r == null || r === "";
402
407
  if (e.operator === "notBlank")
403
408
  return r != null && r !== "";
404
409
  if (r == null) return !1;
405
- const i = String(r), l = t ? i : i.toLowerCase(), c = t ? String(e.value) : String(e.value).toLowerCase();
410
+ const n = String(r), i = t ? n : n.toLowerCase(), l = t ? String(e.value) : String(e.value).toLowerCase();
406
411
  switch (e.operator) {
407
412
  // Text operators
408
413
  case "contains":
409
- return l.includes(c);
414
+ return i.includes(l);
410
415
  case "notContains":
411
- return !l.includes(c);
416
+ return !i.includes(l);
412
417
  case "equals":
413
- return l === c;
418
+ return i === l;
414
419
  case "notEquals":
415
- return l !== c;
420
+ return i !== l;
416
421
  case "startsWith":
417
- return l.startsWith(c);
422
+ return i.startsWith(l);
418
423
  case "endsWith":
419
- return l.endsWith(c);
420
- // Number/Date operators (use raw numeric values)
424
+ return i.endsWith(l);
425
+ // Number/Date operators (use toNumeric for Date objects and date strings)
421
426
  case "lessThan":
422
- return Number(r) < Number(e.value);
427
+ return V(r) < V(e.value);
423
428
  case "lessThanOrEqual":
424
- return Number(r) <= Number(e.value);
429
+ return V(r) <= V(e.value);
425
430
  case "greaterThan":
426
- return Number(r) > Number(e.value);
431
+ return V(r) > V(e.value);
427
432
  case "greaterThanOrEqual":
428
- return Number(r) >= Number(e.value);
433
+ return V(r) >= V(e.value);
429
434
  case "between":
430
- return Number(r) >= Number(e.value) && Number(r) <= Number(e.valueTo);
435
+ return V(r) >= V(e.value) && V(r) <= V(e.valueTo);
431
436
  // Set operators
432
437
  case "in":
433
438
  return Array.isArray(e.value) && e.value.includes(r);
@@ -437,12 +442,12 @@ function j(N, e, t = !1) {
437
442
  return !0;
438
443
  }
439
444
  }
440
- function U(N, e, t = !1) {
441
- return e.length ? N.filter((r) => e.every((i) => j(r, i, t))) : N;
445
+ function J(x, e, t = !1) {
446
+ return e.length ? x.filter((r) => e.every((n) => j(r, n, t))) : x;
442
447
  }
443
- function J(N) {
448
+ function Q(x) {
444
449
  return JSON.stringify(
445
- N.map((e) => ({
450
+ x.map((e) => ({
446
451
  field: e.field,
447
452
  operator: e.operator,
448
453
  value: e.value,
@@ -450,16 +455,16 @@ function J(N) {
450
455
  }))
451
456
  );
452
457
  }
453
- function B(N, e) {
458
+ function O(x, e) {
454
459
  const t = /* @__PURE__ */ new Set();
455
- for (const r of N) {
456
- const i = r[e];
457
- i != null && t.add(i);
460
+ for (const r of x) {
461
+ const n = r[e];
462
+ n != null && t.add(n);
458
463
  }
459
- return [...t].sort((r, i) => typeof r == "number" && typeof i == "number" ? r - i : String(r).localeCompare(String(i)));
464
+ return [...t].sort((r, n) => typeof r == "number" && typeof n == "number" ? r - n : String(r).localeCompare(String(n)));
460
465
  }
461
- const Q = '@layer tbw-plugins{tbw-grid .tbw-quick-filter-input{flex:1;max-width:300px;height:var(--tbw-input-height, 1.75rem);padding:var(--tbw-input-padding, 0 .5rem);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:var(--tbw-font-size-sm, .8125rem)}tbw-grid .tbw-quick-filter-input:focus{outline:none;border-color:var(--tbw-color-accent)}tbw-grid .header-cell.filtered:before{content:"";position:absolute;top:var(--tbw-spacing-xs, .25rem);right:var(--tbw-spacing-xs, .25rem);width:var(--tbw-indicator-size, .375rem);height:var(--tbw-indicator-size, .375rem);background:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));border-radius:50%}tbw-grid .tbw-filter-btn{display:var(--tbw-filter-btn-display, inline-flex);visibility:var(--tbw-filter-btn-visibility, visible);align-items:center;justify-content:center;background:transparent;border:none;cursor:pointer;padding:2px;margin-left:var(--tbw-spacing-xs, .25rem);opacity:.4;transition:opacity .15s,visibility 0s,display 0s allow-discrete;color:inherit;vertical-align:middle;transition-behavior:allow-discrete}tbw-grid .tbw-filter-btn:hover,tbw-grid .tbw-filter-btn.active{opacity:1;visibility:visible;display:inline-flex}tbw-grid .tbw-filter-btn.active{color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6))}tbw-grid .header-row .cell:hover .tbw-filter-btn,tbw-grid .header-row .cell.filtered .tbw-filter-btn{display:inline-flex;visibility:visible}}', X = "@layer tbw-plugins{.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, .25rem));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:var(--tbw-panel-padding, var(--tbw-spacing-lg, .75rem));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, .8125rem);transform-origin:top center}.tbw-filter-panel.tbw-filter-panel-above{transform-origin:bottom center}.tbw-filter-panel.tbw-filter-panel-animated{animation:tbw-filter-panel-enter var(--tbw-animation-duration, .15s) var(--tbw-animation-easing, ease-out)}.tbw-filter-panel.tbw-filter-panel-above.tbw-filter-panel-animated{animation:tbw-filter-panel-enter-above var(--tbw-animation-duration, .15s) var(--tbw-animation-easing, ease-out)}@keyframes tbw-filter-panel-enter{0%{opacity:0;transform:scaleY(.3) translateY(-10px)}to{opacity:1;transform:scaleY(1) translateY(0)}}@keyframes tbw-filter-panel-enter-above{0%{opacity:0;transform:scaleY(.3) translateY(10px)}to{opacity:1;transform:scaleY(1) translateY(0)}}@supports (anchor-name: --test){.tbw-filter-panel{position-anchor:--tbw-filter-anchor;top:anchor(bottom);left:anchor(left);margin-top:4px;position-try-fallbacks:flip-inline,flip-block,flip-block flip-inline}}.tbw-filter-search{margin-bottom:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem));min-height:var(--tbw-filter-item-height, 28px)}.tbw-filter-search-input{height:var(--tbw-filter-item-height, 28px);width:100%;padding:var(--tbw-filter-search-padding, var(--tbw-spacing-sm, .375rem) var(--tbw-spacing-md, .5rem));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, var(--tbw-border-radius, .25rem));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:var(--tbw-button-padding-sm, .25rem .125rem);margin-bottom:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem));border-bottom:1px solid var(--tbw-filter-divider, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));min-height:var(--tbw-filter-item-height, 28px)}.tbw-filter-actions .tbw-filter-value-item{flex:1}.tbw-filter-values{flex:1;overflow-y:auto;margin-bottom:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem));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:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem));padding:var(--tbw-button-padding-sm, .25rem .125rem);cursor:pointer;border-radius:3px;height:var(--tbw-filter-item-height, 28px)}.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:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem)) 0;text-align:center;font-style:italic}.tbw-filter-buttons{display:flex;gap:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem));padding-top:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem));border-top:1px solid var(--tbw-filter-divider, var(--tbw-color-border, light-dark(#d0d0d4, #454545)))}.tbw-filter-apply-btn{flex:1;padding:var(--tbw-filter-btn-padding, var(--tbw-button-padding, .375rem .75rem));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:var(--tbw-border-radius, .25rem);cursor:pointer;font-size:var(--tbw-font-size-sm, .8125rem);font-weight:var(--tbw-filter-btn-font-weight, 500);min-height:var(--tbw-filter-btn-min-height, auto)}.tbw-filter-apply-btn:hover{filter:brightness(.9)}.tbw-filter-clear-btn{flex:1;padding:var(--tbw-filter-btn-padding, var(--tbw-button-padding, .375rem .75rem));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:var(--tbw-border-radius, .25rem);cursor:pointer;font-size:var(--tbw-font-size-sm, .8125rem);font-weight:var(--tbw-filter-btn-font-weight, 500);min-height:var(--tbw-filter-btn-min-height, auto)}.tbw-filter-clear-btn:hover{background:var(--tbw-filter-hover, var(--tbw-color-row-hover, light-dark(#f0f6ff, #1c1c1c)))}.tbw-filter-range-inputs,.tbw-filter-date-range{display:flex;align-items:flex-end;gap:var(--tbw-spacing-sm, .375rem);margin-bottom:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem))}.tbw-filter-range-group,.tbw-filter-date-group{display:flex;flex-direction:column;gap:var(--tbw-spacing-xs, .25rem);flex:1}.tbw-filter-range-label{font-size:var(--tbw-font-size-xs, .75rem);color:var(--tbw-filter-muted, var(--tbw-color-fg-muted, light-dark(#555555, #aaaaaa)))}.tbw-filter-range-input,.tbw-filter-date-input{width:100%;height:var(--tbw-filter-item-height, 28px);padding:var(--tbw-spacing-xs, .25rem) var(--tbw-spacing-sm, .375rem);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, var(--tbw-border-radius, .25rem));font-size:inherit;box-sizing:border-box}.tbw-filter-range-input:focus,.tbw-filter-date-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-range-separator{color:var(--tbw-filter-muted, var(--tbw-color-fg-muted, light-dark(#555555, #aaaaaa)));padding-bottom:var(--tbw-spacing-xs, .25rem)}.tbw-filter-range-slider{position:relative;height:24px;margin:var(--tbw-spacing-md, .5rem) 0 var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem))}.tbw-filter-range-track{position:absolute;top:50%;left:0;right:0;height:4px;background:var(--tbw-filter-input-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));border-radius:2px;transform:translateY(-50%)}.tbw-filter-range-fill{position:absolute;top:50%;height:4px;background:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));border-radius:2px;transform:translateY(-50%)}.tbw-filter-range-thumb{position:absolute;top:0;width:100%;height:100%;background:none;pointer-events:none;-webkit-appearance:none;appearance:none}.tbw-filter-range-thumb::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:16px;height:16px;background:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));border:2px solid var(--tbw-filter-panel-bg, var(--tbw-color-panel-bg, light-dark(#eeeeee, #222222)));border-radius:50%;cursor:pointer;pointer-events:all;box-shadow:0 1px 3px #0003}.tbw-filter-range-thumb::-moz-range-thumb{width:16px;height:16px;background:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));border:2px solid var(--tbw-filter-panel-bg, var(--tbw-color-panel-bg, light-dark(#eeeeee, #222222)));border-radius:50%;cursor:pointer;pointer-events:all;box-shadow:0 1px 3px #0003}.tbw-filter-range-thumb::-webkit-slider-thumb:hover{transform:scale(1.1)}.tbw-filter-range-thumb::-moz-range-thumb:hover{transform:scale(1.1)}}";
462
- class I extends K {
466
+ const X = '@layer tbw-plugins{tbw-grid .tbw-quick-filter-input{flex:1;max-width:300px;height:var(--tbw-input-height, 1.75rem);padding:var(--tbw-input-padding, 0 .5rem);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:var(--tbw-font-size-sm, .8125rem)}tbw-grid .tbw-quick-filter-input:focus{outline:none;border-color:var(--tbw-color-accent)}tbw-grid .header-cell.filtered:before{content:"";position:absolute;top:var(--tbw-spacing-xs, .25rem);right:var(--tbw-spacing-xs, .25rem);width:var(--tbw-indicator-size, .375rem);height:var(--tbw-indicator-size, .375rem);background:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));border-radius:50%}tbw-grid .tbw-filter-btn{display:var(--tbw-filter-btn-display, inline-flex);visibility:var(--tbw-filter-btn-visibility, visible);align-items:center;justify-content:center;background:transparent;border:none;cursor:pointer;padding:2px;margin-left:var(--tbw-spacing-xs, .25rem);opacity:.4;transition:opacity .15s,visibility 0s,display 0s allow-discrete;color:inherit;vertical-align:middle;transition-behavior:allow-discrete}tbw-grid .tbw-filter-btn:hover,tbw-grid .tbw-filter-btn.active{opacity:1;visibility:visible;display:inline-flex}tbw-grid .tbw-filter-btn.active{color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6))}tbw-grid .header-row .cell:hover .tbw-filter-btn,tbw-grid .header-row .cell.filtered .tbw-filter-btn{display:inline-flex;visibility:visible}}', Z = "@layer tbw-plugins{.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, .25rem));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:var(--tbw-panel-padding, var(--tbw-spacing-lg, .75rem));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, .8125rem);transform-origin:top center}.tbw-filter-panel.tbw-filter-panel-above{transform-origin:bottom center}.tbw-filter-panel.tbw-filter-panel-animated{animation:tbw-filter-panel-enter var(--tbw-animation-duration, .15s) var(--tbw-animation-easing, ease-out)}.tbw-filter-panel.tbw-filter-panel-above.tbw-filter-panel-animated{animation:tbw-filter-panel-enter-above var(--tbw-animation-duration, .15s) var(--tbw-animation-easing, ease-out)}@keyframes tbw-filter-panel-enter{0%{opacity:0;transform:scaleY(.3) translateY(-10px)}to{opacity:1;transform:scaleY(1) translateY(0)}}@keyframes tbw-filter-panel-enter-above{0%{opacity:0;transform:scaleY(.3) translateY(10px)}to{opacity:1;transform:scaleY(1) translateY(0)}}@supports (anchor-name: --test){.tbw-filter-panel{position-anchor:--tbw-filter-anchor;top:anchor(bottom);left:anchor(left);margin-top:4px;position-try-fallbacks:flip-inline,flip-block,flip-block flip-inline}}.tbw-filter-search{margin-bottom:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem));min-height:var(--tbw-filter-item-height, 28px)}.tbw-filter-search-input{height:var(--tbw-filter-item-height, 28px);width:100%;padding:var(--tbw-filter-search-padding, var(--tbw-spacing-sm, .375rem) var(--tbw-spacing-md, .5rem));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, var(--tbw-border-radius, .25rem));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:var(--tbw-button-padding-sm, .25rem .125rem);margin-bottom:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem));border-bottom:1px solid var(--tbw-filter-divider, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));min-height:var(--tbw-filter-item-height, 28px)}.tbw-filter-actions .tbw-filter-value-item{flex:1}.tbw-filter-values{flex:1;overflow-y:auto;margin-bottom:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem));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:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem));padding:var(--tbw-button-padding-sm, .25rem .125rem);cursor:pointer;border-radius:3px;height:var(--tbw-filter-item-height, 28px)}.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:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem)) 0;text-align:center;font-style:italic}.tbw-filter-buttons{display:flex;gap:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem));padding-top:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem));border-top:1px solid var(--tbw-filter-divider, var(--tbw-color-border, light-dark(#d0d0d4, #454545)))}.tbw-filter-apply-btn{flex:1;padding:var(--tbw-filter-btn-padding, var(--tbw-button-padding, .375rem .75rem));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:var(--tbw-border-radius, .25rem);cursor:pointer;font-size:var(--tbw-font-size-sm, .8125rem);font-weight:var(--tbw-filter-btn-font-weight, 500);min-height:var(--tbw-filter-btn-min-height, auto)}.tbw-filter-apply-btn:hover{filter:brightness(.9)}.tbw-filter-clear-btn{flex:1;padding:var(--tbw-filter-btn-padding, var(--tbw-button-padding, .375rem .75rem));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:var(--tbw-border-radius, .25rem);cursor:pointer;font-size:var(--tbw-font-size-sm, .8125rem);font-weight:var(--tbw-filter-btn-font-weight, 500);min-height:var(--tbw-filter-btn-min-height, auto)}.tbw-filter-clear-btn:hover{background:var(--tbw-filter-hover, var(--tbw-color-row-hover, light-dark(#f0f6ff, #1c1c1c)))}.tbw-filter-range-inputs,.tbw-filter-date-range{display:flex;align-items:flex-end;gap:var(--tbw-spacing-sm, .375rem);margin-bottom:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem))}.tbw-filter-range-group,.tbw-filter-date-group{display:flex;flex-direction:column;gap:var(--tbw-spacing-xs, .25rem);flex:1}.tbw-filter-range-label{font-size:var(--tbw-font-size-xs, .75rem);color:var(--tbw-filter-muted, var(--tbw-color-fg-muted, light-dark(#555555, #aaaaaa)))}.tbw-filter-range-input,.tbw-filter-date-input{width:100%;height:var(--tbw-filter-item-height, 28px);padding:var(--tbw-spacing-xs, .25rem) var(--tbw-spacing-sm, .375rem);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, var(--tbw-border-radius, .25rem));font-size:inherit;box-sizing:border-box}.tbw-filter-range-input:focus,.tbw-filter-date-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-range-separator{color:var(--tbw-filter-muted, var(--tbw-color-fg-muted, light-dark(#555555, #aaaaaa)));padding-bottom:var(--tbw-spacing-xs, .25rem)}.tbw-filter-blank-option{display:flex;align-items:center;gap:var(--tbw-spacing-sm, .375rem);padding:var(--tbw-spacing-xs, .25rem) 0;margin-bottom:var(--tbw-spacing-xs, .25rem);font-size:var(--tbw-font-size-sm, .8125rem);cursor:pointer;-webkit-user-select:none;user-select:none}.tbw-filter-blank-checkbox{accent-color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));margin:0;cursor:pointer}.tbw-filter-date-range.tbw-filter-disabled{opacity:.4;pointer-events:none}.tbw-filter-range-slider{position:relative;height:24px;margin:var(--tbw-spacing-md, .5rem) 0 var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem))}.tbw-filter-range-track{position:absolute;top:50%;left:0;right:0;height:4px;background:var(--tbw-filter-input-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));border-radius:2px;transform:translateY(-50%)}.tbw-filter-range-fill{position:absolute;top:50%;height:4px;background:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));border-radius:2px;transform:translateY(-50%)}.tbw-filter-range-thumb{position:absolute;top:0;width:100%;height:100%;background:none;pointer-events:none;-webkit-appearance:none;appearance:none}.tbw-filter-range-thumb::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:16px;height:16px;background:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));border:2px solid var(--tbw-filter-panel-bg, var(--tbw-color-panel-bg, light-dark(#eeeeee, #222222)));border-radius:50%;cursor:pointer;pointer-events:all;box-shadow:0 1px 3px #0003}.tbw-filter-range-thumb::-moz-range-thumb{width:16px;height:16px;background:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));border:2px solid var(--tbw-filter-panel-bg, var(--tbw-color-panel-bg, light-dark(#eeeeee, #222222)));border-radius:50%;cursor:pointer;pointer-events:all;box-shadow:0 1px 3px #0003}.tbw-filter-range-thumb::-webkit-slider-thumb:hover{transform:scale(1.1)}.tbw-filter-range-thumb::-moz-range-thumb:hover{transform:scale(1.1)}}";
467
+ class _ extends W {
463
468
  /**
464
469
  * Plugin manifest - declares events emitted by this plugin.
465
470
  * @internal
@@ -470,12 +475,18 @@ class I extends K {
470
475
  type: "filter-applied",
471
476
  description: "Emitted when filter criteria change. Subscribers can react to row visibility changes."
472
477
  }
478
+ ],
479
+ queries: [
480
+ {
481
+ type: "getContextMenuItems",
482
+ description: "Contributes filter-related items to the header context menu"
483
+ }
473
484
  ]
474
485
  };
475
486
  /** @internal */
476
487
  name = "filtering";
477
488
  /** @internal */
478
- styles = Q;
489
+ styles = X;
479
490
  /** @internal */
480
491
  get defaultConfig() {
481
492
  return {
@@ -504,6 +515,8 @@ class I extends K {
504
515
  filters = /* @__PURE__ */ new Map();
505
516
  cachedResult = null;
506
517
  cacheKey = null;
518
+ /** Spot-check of input rows for cache invalidation when upstream plugins (e.g. sort) change row order */
519
+ cachedInputSpot = null;
507
520
  openPanelField = null;
508
521
  panelElement = null;
509
522
  panelAnchorElement = null;
@@ -531,7 +544,7 @@ class I extends K {
531
544
  return t;
532
545
  }
533
546
  }
534
- return I.DEFAULT_LIST_ITEM_HEIGHT;
547
+ return _.DEFAULT_LIST_ITEM_HEIGHT;
535
548
  }
536
549
  /**
537
550
  * Sync excludedValues map from a filter model (for set filters).
@@ -547,7 +560,37 @@ class I extends K {
547
560
  }
548
561
  /** @internal */
549
562
  detach() {
550
- this.filters.clear(), this.cachedResult = null, this.cacheKey = null, this.openPanelField = null, this.panelElement && (this.panelElement.remove(), this.panelElement = null), this.searchText.clear(), this.excludedValues.clear(), this.panelAbortController?.abort(), this.panelAbortController = null;
563
+ this.filters.clear(), this.cachedResult = null, this.cacheKey = null, this.cachedInputSpot = null, this.openPanelField = null, this.panelElement && (this.panelElement.remove(), this.panelElement = null), this.searchText.clear(), this.excludedValues.clear(), this.panelAbortController?.abort(), this.panelAbortController = null;
564
+ }
565
+ // #endregion
566
+ // #region Query Handlers
567
+ /**
568
+ * Handle inter-plugin queries.
569
+ * Contributes filter-related items to the header context menu.
570
+ * @internal
571
+ */
572
+ handleQuery(e) {
573
+ if (e.type === "getContextMenuItems") {
574
+ const t = e.context;
575
+ if (!t.isHeader) return;
576
+ const r = t.column;
577
+ if (!r?.field || !this.isFilteringEnabled() || !this.isColumnFilterable(r)) return;
578
+ const n = [], i = this.isFieldFiltered(r.field), l = this.filters.size > 0;
579
+ return i && n.push({
580
+ id: "filtering/clear-column-filter",
581
+ label: "Clear Filter",
582
+ icon: "✕",
583
+ order: 20,
584
+ action: () => this.clearFieldFilter(r.field)
585
+ }), l && n.push({
586
+ id: "filtering/clear-all-filters",
587
+ label: "Clear All Filters",
588
+ icon: "✕",
589
+ order: 21,
590
+ disabled: !l,
591
+ action: () => this.clearAllFilters()
592
+ }), n.length > 0 ? n : void 0;
593
+ }
551
594
  }
552
595
  // #endregion
553
596
  // #region Hooks
@@ -557,40 +600,45 @@ class I extends K {
557
600
  if (!t.length) return [...e];
558
601
  if (this.config.filterHandler)
559
602
  return this.cachedResult ? this.cachedResult : [...e];
560
- const r = J(t);
561
- if (this.cacheKey === r && this.cachedResult)
603
+ const r = Q(t), n = {
604
+ len: e.length,
605
+ first: e[0],
606
+ mid: e[Math.floor(e.length / 2)],
607
+ last: e[e.length - 1]
608
+ }, i = this.cachedInputSpot != null && n.len === this.cachedInputSpot.len && n.first === this.cachedInputSpot.first && n.mid === this.cachedInputSpot.mid && n.last === this.cachedInputSpot.last;
609
+ if (this.cacheKey === r && this.cachedResult && i)
562
610
  return this.cachedResult;
563
- const i = U([...e], t, this.config.caseSensitive);
564
- return this.cachedResult = i, this.cacheKey = r, i;
611
+ const l = J([...e], t, this.config.caseSensitive);
612
+ return this.cachedResult = l, this.cacheKey = r, this.cachedInputSpot = n, l;
565
613
  }
566
614
  /** @internal */
567
615
  afterRender() {
568
616
  const e = this.gridElement;
569
617
  if (!e) return;
570
618
  e.querySelectorAll('[part~="header-cell"]').forEach((r) => {
571
- const i = r.getAttribute("data-col");
572
- if (i === null) return;
573
- const l = this.visibleColumns[parseInt(i, 10)];
574
- if (!l || !this.isColumnFilterable(l) || W(l)) return;
575
- const c = l.field;
576
- if (!c) return;
577
- const d = this.filters.has(c);
619
+ const n = r.getAttribute("data-col");
620
+ if (n === null) return;
621
+ const i = this.visibleColumns[parseInt(n, 10)];
622
+ if (!i || !this.isColumnFilterable(i) || U(i)) return;
623
+ const l = i.field;
624
+ if (!l) return;
625
+ const u = this.filters.has(l);
578
626
  let a = r.querySelector(".tbw-filter-btn");
579
627
  if (a) {
580
- const w = a.classList.contains("active");
581
- if (a.classList.toggle("active", d), r.classList.toggle("filtered", d), w !== d) {
582
- const u = d ? "filterActive" : "filter";
583
- this.setIcon(a, this.resolveIcon(u));
628
+ const y = a.classList.contains("active");
629
+ if (a.classList.toggle("active", u), r.classList.toggle("filtered", u), y !== u) {
630
+ const h = u ? "filterActive" : "filter";
631
+ this.setIcon(a, this.resolveIcon(h));
584
632
  }
585
633
  return;
586
634
  }
587
- a = document.createElement("button"), a.className = "tbw-filter-btn", a.setAttribute("aria-label", `Filter ${l.header ?? c}`);
588
- const m = d ? "filterActive" : "filter";
589
- this.setIcon(a, this.resolveIcon(m)), d && (a.classList.add("active"), r.classList.add("filtered")), a.addEventListener("click", (w) => {
590
- w.stopPropagation(), this.toggleFilterPanel(c, l, a);
635
+ a = document.createElement("button"), a.className = "tbw-filter-btn", a.setAttribute("aria-label", `Filter ${i.header ?? l}`);
636
+ const f = u ? "filterActive" : "filter";
637
+ this.setIcon(a, this.resolveIcon(f)), u && (a.classList.add("active"), r.classList.add("filtered")), a.addEventListener("click", (y) => {
638
+ y.stopPropagation(), this.toggleFilterPanel(l, i, a);
591
639
  });
592
- const k = r.querySelector(".resize-handle");
593
- k ? r.insertBefore(a, k) : r.appendChild(a);
640
+ const N = r.querySelector(".resize-handle");
641
+ N ? r.insertBefore(a, N) : r.appendChild(a);
594
642
  });
595
643
  }
596
644
  // #endregion
@@ -606,7 +654,7 @@ class I extends K {
606
654
  const r = { ...t, field: e };
607
655
  this.filters.set(e, r), this.syncExcludedValues(e, r);
608
656
  }
609
- this.cachedResult = null, this.cacheKey = null, this.emit("filter-change", {
657
+ this.cachedResult = null, this.cacheKey = null, this.cachedInputSpot = null, this.emit("filter-change", {
610
658
  filters: [...this.filters.values()],
611
659
  filteredRowCount: 0
612
660
  // Will be accurate after processRows
@@ -637,7 +685,7 @@ class I extends K {
637
685
  this.filters.clear(), this.excludedValues.clear();
638
686
  for (const t of e)
639
687
  this.filters.set(t.field, t), this.syncExcludedValues(t.field, t);
640
- this.cachedResult = null, this.cacheKey = null, this.emit("filter-change", {
688
+ this.cachedResult = null, this.cacheKey = null, this.cachedInputSpot = null, this.emit("filter-change", {
641
689
  filters: [...this.filters.values()],
642
690
  filteredRowCount: 0
643
691
  }), this.emitPluginEvent("filter-applied", { filters: [...this.filters.values()] }), this.requestRender();
@@ -677,7 +725,7 @@ class I extends K {
677
725
  * Uses sourceRows to include all values regardless of current filter.
678
726
  */
679
727
  getUniqueValues(e) {
680
- return B(this.sourceRows, e);
728
+ return O(this.sourceRows, e);
681
729
  }
682
730
  // #endregion
683
731
  // #region Private Methods
@@ -688,8 +736,8 @@ class I extends K {
688
736
  copyGridThemeContext(e) {
689
737
  const t = this.gridElement;
690
738
  if (!t) return;
691
- for (const i of t.classList)
692
- i.startsWith("tbw-") || i === "selecting" || e.classList.add(i);
739
+ for (const n of t.classList)
740
+ n.startsWith("tbw-") || n === "selecting" || e.classList.add(n);
693
741
  const r = t.dataset.theme;
694
742
  r && (e.dataset.theme = r);
695
743
  }
@@ -703,7 +751,7 @@ class I extends K {
703
751
  return;
704
752
  }
705
753
  const e = document.createElement("style");
706
- e.id = "tbw-filter-panel-styles", e.textContent = X, document.head.appendChild(e), this.globalStylesInjected = !0;
754
+ e.id = "tbw-filter-panel-styles", e.textContent = Z, document.head.appendChild(e), this.globalStylesInjected = !0;
707
755
  }
708
756
  /**
709
757
  * Toggle the filter panel for a field
@@ -714,33 +762,33 @@ class I extends K {
714
762
  return;
715
763
  }
716
764
  this.closeFilterPanel();
717
- const i = document.createElement("div");
718
- if (i.className = "tbw-filter-panel", this.copyGridThemeContext(i), this.isAnimationEnabled && i.classList.add("tbw-filter-panel-animated"), this.panelElement = i, this.openPanelField = e, this.config.valuesHandler) {
719
- i.innerHTML = '<div class="tbw-filter-loading">Loading...</div>', document.body.appendChild(i), this.positionPanel(i, r), this.setupPanelCloseHandler(i, r), this.config.valuesHandler(e, t).then((c) => {
720
- this.openPanelField !== e || !this.panelElement || (i.innerHTML = "", this.renderPanelContent(e, t, i, c));
765
+ const n = document.createElement("div");
766
+ if (n.className = "tbw-filter-panel", this.copyGridThemeContext(n), this.isAnimationEnabled && n.classList.add("tbw-filter-panel-animated"), this.panelElement = n, this.openPanelField = e, this.config.valuesHandler) {
767
+ n.innerHTML = '<div class="tbw-filter-loading">Loading...</div>', document.body.appendChild(n), this.positionPanel(n, r), this.setupPanelCloseHandler(n, r), this.config.valuesHandler(e, t).then((l) => {
768
+ this.openPanelField !== e || !this.panelElement || (n.innerHTML = "", this.renderPanelContent(e, t, n, l));
721
769
  });
722
770
  return;
723
771
  }
724
- const l = B(this.sourceRows, e);
725
- document.body.appendChild(i), this.positionPanel(i, r), this.renderPanelContent(e, t, i, l), this.setupPanelCloseHandler(i, r);
772
+ const i = O(this.sourceRows, e);
773
+ document.body.appendChild(n), this.positionPanel(n, r), this.renderPanelContent(e, t, n, i), this.setupPanelCloseHandler(n, r);
726
774
  }
727
775
  /**
728
776
  * Render filter panel content with given values
729
777
  */
730
- renderPanelContent(e, t, r, i) {
731
- let l = this.excludedValues.get(e);
732
- l || (l = /* @__PURE__ */ new Set(), this.excludedValues.set(e, l));
733
- const c = this.searchText.get(e) ?? "", d = {
778
+ renderPanelContent(e, t, r, n) {
779
+ let i = this.excludedValues.get(e);
780
+ i || (i = /* @__PURE__ */ new Set(), this.excludedValues.set(e, i));
781
+ const l = this.searchText.get(e) ?? "", u = {
734
782
  field: e,
735
783
  column: t,
736
- uniqueValues: i,
737
- excludedValues: l,
738
- searchText: c,
739
- applySetFilter: (m) => {
740
- this.applySetFilter(e, m), this.closeFilterPanel();
784
+ uniqueValues: n,
785
+ excludedValues: i,
786
+ searchText: l,
787
+ applySetFilter: (f) => {
788
+ this.applySetFilter(e, f), this.closeFilterPanel();
741
789
  },
742
- applyTextFilter: (m, k, w) => {
743
- this.applyTextFilter(e, m, k, w), this.closeFilterPanel();
790
+ applyTextFilter: (f, N, y) => {
791
+ this.applyTextFilter(e, f, N, y), this.closeFilterPanel();
744
792
  },
745
793
  clearFilter: () => {
746
794
  this.clearFieldFilter(e), this.closeFilterPanel();
@@ -748,13 +796,13 @@ class I extends K {
748
796
  closePanel: () => this.closeFilterPanel()
749
797
  };
750
798
  let a = !1;
751
- if (this.config.filterPanelRenderer && (this.config.filterPanelRenderer(r, d), a = r.children.length > 0), !a && t.type) {
752
- const m = this.grid.effectiveConfig.typeDefaults?.[t.type];
753
- m?.filterPanelRenderer && (m.filterPanelRenderer(r, d), a = r.children.length > 0);
799
+ if (this.config.filterPanelRenderer && (this.config.filterPanelRenderer(r, u), a = r.children.length > 0), !a && t.type) {
800
+ const f = this.grid.effectiveConfig.typeDefaults?.[t.type];
801
+ f?.filterPanelRenderer && (f.filterPanelRenderer(r, u), a = r.children.length > 0);
754
802
  }
755
803
  if (!a) {
756
- const m = t.type;
757
- m === "number" ? this.renderNumberFilterPanel(r, d, i) : m === "date" ? this.renderDateFilterPanel(r, d, i) : this.renderDefaultFilterPanel(r, d, i, l);
804
+ const f = t.type;
805
+ f === "number" ? this.renderNumberFilterPanel(r, u, n) : f === "date" ? this.renderDateFilterPanel(r, u, n) : this.renderDefaultFilterPanel(r, u, n, i);
758
806
  }
759
807
  }
760
808
  /**
@@ -784,241 +832,258 @@ class I extends K {
784
832
  * Check if browser supports CSS Anchor Positioning
785
833
  */
786
834
  static checkAnchorPositioningSupport() {
787
- return I.supportsAnchorPositioning === null && (I.supportsAnchorPositioning = CSS.supports("anchor-name", "--test")), I.supportsAnchorPositioning;
835
+ return _.supportsAnchorPositioning === null && (_.supportsAnchorPositioning = CSS.supports("anchor-name", "--test")), _.supportsAnchorPositioning;
788
836
  }
789
837
  /**
790
838
  * Position the panel below the header cell
791
839
  * Uses CSS Anchor Positioning if supported, falls back to JS positioning
792
840
  */
793
841
  positionPanel(e, t) {
794
- const i = t.closest(".cell") ?? t;
795
- if (i.style.anchorName = "--tbw-filter-anchor", this.panelAnchorElement = i, I.checkAnchorPositioningSupport()) {
842
+ const n = t.closest(".cell") ?? t;
843
+ if (n.style.anchorName = "--tbw-filter-anchor", this.panelAnchorElement = n, _.checkAnchorPositioningSupport()) {
796
844
  requestAnimationFrame(() => {
797
- const c = e.getBoundingClientRect(), d = i.getBoundingClientRect();
798
- c.top < d.top && e.classList.add("tbw-filter-panel-above");
845
+ const l = e.getBoundingClientRect(), u = n.getBoundingClientRect();
846
+ l.top < u.top && e.classList.add("tbw-filter-panel-above");
799
847
  });
800
848
  return;
801
849
  }
802
- const l = i.getBoundingClientRect();
803
- e.style.position = "fixed", e.style.top = `${l.bottom + 4}px`, e.style.left = `${l.left}px`, requestAnimationFrame(() => {
804
- const c = e.getBoundingClientRect();
805
- c.right > window.innerWidth - 8 && (e.style.left = `${l.right - c.width}px`), c.bottom > window.innerHeight - 8 && (e.style.top = `${l.top - c.height - 4}px`, e.classList.add("tbw-filter-panel-above"));
850
+ const i = n.getBoundingClientRect();
851
+ e.style.position = "fixed", e.style.top = `${i.bottom + 4}px`, e.style.left = `${i.left}px`, requestAnimationFrame(() => {
852
+ const l = e.getBoundingClientRect();
853
+ l.right > window.innerWidth - 8 && (e.style.left = `${i.right - l.width}px`), l.bottom > window.innerHeight - 8 && (e.style.top = `${i.top - l.height - 4}px`, e.classList.add("tbw-filter-panel-above"));
806
854
  });
807
855
  }
808
856
  /**
809
857
  * Render the default filter panel content
810
858
  */
811
- renderDefaultFilterPanel(e, t, r, i) {
812
- const { field: l } = t, c = this.getListItemHeight(), d = document.createElement("div");
813
- d.className = "tbw-filter-search";
859
+ renderDefaultFilterPanel(e, t, r, n) {
860
+ const { field: i } = t, l = this.getListItemHeight(), u = document.createElement("div");
861
+ u.className = "tbw-filter-search";
814
862
  const a = document.createElement("input");
815
- a.type = "text", a.placeholder = "Search...", a.className = "tbw-filter-search-input", a.value = this.searchText.get(l) ?? "", d.appendChild(a), e.appendChild(d);
816
- const m = document.createElement("div");
817
- m.className = "tbw-filter-actions";
818
- const k = document.createElement("label");
819
- k.className = "tbw-filter-value-item", k.style.padding = "0", k.style.margin = "0";
820
- const w = document.createElement("input");
821
- w.type = "checkbox", w.className = "tbw-filter-checkbox";
822
- const u = document.createElement("span");
823
- u.textContent = "Select All", k.appendChild(w), k.appendChild(u), m.appendChild(k);
824
- const v = () => {
825
- const o = [...S.values()], h = o.every((n) => n), y = o.every((n) => !n);
826
- w.checked = h, w.indeterminate = !h && !y;
863
+ a.type = "text", a.placeholder = "Search...", a.className = "tbw-filter-search-input", a.value = this.searchText.get(i) ?? "", u.appendChild(a), e.appendChild(u);
864
+ const f = document.createElement("div");
865
+ f.className = "tbw-filter-actions";
866
+ const N = document.createElement("label");
867
+ N.className = "tbw-filter-value-item", N.style.padding = "0", N.style.margin = "0";
868
+ const y = document.createElement("input");
869
+ y.type = "checkbox", y.className = "tbw-filter-checkbox";
870
+ const h = document.createElement("span");
871
+ h.textContent = "Select All", N.appendChild(y), N.appendChild(h), f.appendChild(N);
872
+ const C = () => {
873
+ const s = [...k.values()], b = s.every((o) => o), m = s.every((o) => !o);
874
+ y.checked = b, y.indeterminate = !b && !m;
827
875
  };
828
- w.addEventListener("change", () => {
829
- const o = w.checked;
830
- for (const h of S.keys())
831
- S.set(h, o);
832
- v(), A();
833
- }), e.appendChild(m);
876
+ y.addEventListener("change", () => {
877
+ const s = y.checked;
878
+ for (const b of k.keys())
879
+ k.set(b, s);
880
+ C(), L();
881
+ }), e.appendChild(f);
882
+ const F = document.createElement("div");
883
+ F.className = "tbw-filter-values";
884
+ const w = document.createElement("div");
885
+ w.className = "tbw-filter-values-spacer", F.appendChild(w);
834
886
  const E = document.createElement("div");
835
- E.className = "tbw-filter-values";
836
- const g = document.createElement("div");
837
- g.className = "tbw-filter-values-spacer", E.appendChild(g);
838
- const x = document.createElement("div");
839
- x.className = "tbw-filter-values-content", E.appendChild(x);
840
- const S = /* @__PURE__ */ new Map();
841
- r.forEach((o) => {
842
- const h = o == null ? "__null__" : String(o);
843
- S.set(h, !i.has(o));
844
- }), v();
845
- let C = [];
846
- const R = (o, h) => {
847
- const y = o == null ? "(Blank)" : String(o), n = o == null ? "__null__" : String(o), s = document.createElement("label");
848
- s.className = "tbw-filter-value-item", s.style.position = "absolute", s.style.top = `calc(var(--tbw-filter-item-height, 28px) * ${h})`, s.style.left = "0", s.style.right = "0", s.style.boxSizing = "border-box";
849
- const F = document.createElement("input");
850
- F.type = "checkbox", F.className = "tbw-filter-checkbox", F.checked = S.get(n) ?? !0, F.dataset.value = n, F.addEventListener("change", () => {
851
- S.set(n, F.checked), v();
887
+ E.className = "tbw-filter-values-content", F.appendChild(E);
888
+ const k = /* @__PURE__ */ new Map();
889
+ r.forEach((s) => {
890
+ const b = s == null ? "__null__" : String(s);
891
+ k.set(b, !n.has(s));
892
+ }), C();
893
+ let T = [];
894
+ const R = (s, b) => {
895
+ const m = s == null ? "(Blank)" : String(s), o = s == null ? "__null__" : String(s), c = document.createElement("label");
896
+ c.className = "tbw-filter-value-item", c.style.position = "absolute", c.style.top = `calc(var(--tbw-filter-item-height, 28px) * ${b})`, c.style.left = "0", c.style.right = "0", c.style.boxSizing = "border-box";
897
+ const g = document.createElement("input");
898
+ g.type = "checkbox", g.className = "tbw-filter-checkbox", g.checked = k.get(o) ?? !0, g.dataset.value = o, g.addEventListener("change", () => {
899
+ k.set(o, g.checked), C();
852
900
  });
853
901
  const M = document.createElement("span");
854
- return M.textContent = y, s.appendChild(F), s.appendChild(M), s;
855
- }, A = () => {
856
- const o = C.length, h = E.clientHeight, y = E.scrollTop;
857
- if (g.style.height = `${o * c}px`, G(o, I.LIST_BYPASS_THRESHOLD / 3)) {
858
- x.innerHTML = "", x.style.transform = "translateY(0px)", C.forEach((s, F) => {
859
- x.appendChild(R(s, F));
902
+ return M.textContent = m, c.appendChild(g), c.appendChild(M), c;
903
+ }, L = () => {
904
+ const s = T.length, b = F.clientHeight, m = F.scrollTop;
905
+ if (w.style.height = `${s * l}px`, $(s, _.LIST_BYPASS_THRESHOLD / 3)) {
906
+ E.innerHTML = "", E.style.transform = "translateY(0px)", T.forEach((c, g) => {
907
+ E.appendChild(R(c, g));
860
908
  });
861
909
  return;
862
910
  }
863
- const n = Y({
864
- totalRows: o,
865
- viewportHeight: h,
866
- scrollTop: y,
867
- rowHeight: c,
868
- overscan: I.LIST_OVERSCAN
911
+ const o = G({
912
+ totalRows: s,
913
+ viewportHeight: b,
914
+ scrollTop: m,
915
+ rowHeight: l,
916
+ overscan: _.LIST_OVERSCAN
869
917
  });
870
- x.style.transform = `translateY(${n.offsetY}px)`, x.innerHTML = "";
871
- for (let s = n.start; s < n.end; s++)
872
- x.appendChild(R(C[s], s - n.start));
873
- }, f = (o) => {
874
- const h = this.config.caseSensitive ?? !1, y = h ? o : o.toLowerCase();
875
- if (C = r.filter((n) => {
876
- const s = n == null ? "(Blank)" : String(n), F = h ? s : s.toLowerCase();
877
- return !o || F.includes(y);
878
- }), C.length === 0) {
879
- g.style.height = "0px", x.innerHTML = "";
880
- const n = document.createElement("div");
881
- n.className = "tbw-filter-no-match", n.textContent = "No matching values", x.appendChild(n);
918
+ E.style.transform = `translateY(${o.offsetY}px)`, E.innerHTML = "";
919
+ for (let c = o.start; c < o.end; c++)
920
+ E.appendChild(R(T[c], c - o.start));
921
+ }, S = (s) => {
922
+ const b = this.config.caseSensitive ?? !1, m = b ? s : s.toLowerCase();
923
+ if (T = r.filter((o) => {
924
+ const c = o == null ? "(Blank)" : String(o), g = b ? c : c.toLowerCase();
925
+ return !s || g.includes(m);
926
+ }), T.length === 0) {
927
+ w.style.height = "0px", E.innerHTML = "";
928
+ const o = document.createElement("div");
929
+ o.className = "tbw-filter-no-match", o.textContent = "No matching values", E.appendChild(o);
882
930
  return;
883
931
  }
884
- A();
932
+ L();
885
933
  };
886
- E.addEventListener(
934
+ F.addEventListener(
887
935
  "scroll",
888
936
  () => {
889
- C.length > 0 && A();
937
+ T.length > 0 && L();
890
938
  },
891
939
  { passive: !0 }
892
- ), f(a.value), e.appendChild(E);
893
- let L;
940
+ ), S(a.value), e.appendChild(F);
941
+ let I;
894
942
  a.addEventListener("input", () => {
895
- clearTimeout(L), L = setTimeout(() => {
896
- this.searchText.set(l, a.value), f(a.value);
943
+ clearTimeout(I), I = setTimeout(() => {
944
+ this.searchText.set(i, a.value), S(a.value);
897
945
  }, this.config.debounceMs ?? 150);
898
946
  });
899
- const T = document.createElement("div");
900
- T.className = "tbw-filter-buttons";
901
- const P = document.createElement("button");
902
- P.className = "tbw-filter-apply-btn", P.textContent = "Apply", P.addEventListener("click", () => {
903
- const o = [];
904
- for (const [h, y] of S)
905
- if (!y)
906
- if (h === "__null__")
907
- o.push(null);
947
+ const P = document.createElement("div");
948
+ P.className = "tbw-filter-buttons";
949
+ const A = document.createElement("button");
950
+ A.className = "tbw-filter-apply-btn", A.textContent = "Apply", A.addEventListener("click", () => {
951
+ const s = [];
952
+ for (const [b, m] of k)
953
+ if (!m)
954
+ if (b === "__null__")
955
+ s.push(null);
908
956
  else {
909
- const n = r.find((s) => String(s) === h);
910
- o.push(n !== void 0 ? n : h);
957
+ const o = r.find((c) => String(c) === b);
958
+ s.push(o !== void 0 ? o : b);
911
959
  }
912
- t.applySetFilter(o);
913
- }), T.appendChild(P);
914
- const p = document.createElement("button");
915
- p.className = "tbw-filter-clear-btn", p.textContent = "Clear Filter", p.addEventListener("click", () => {
960
+ t.applySetFilter(s);
961
+ }), P.appendChild(A);
962
+ const v = document.createElement("button");
963
+ v.className = "tbw-filter-clear-btn", v.textContent = "Clear Filter", v.addEventListener("click", () => {
916
964
  t.clearFilter();
917
- }), T.appendChild(p), e.appendChild(T);
965
+ }), P.appendChild(v), e.appendChild(P);
918
966
  }
919
967
  /**
920
968
  * Render a number range filter panel with min/max inputs and slider
921
969
  */
922
970
  renderNumberFilterPanel(e, t, r) {
923
- const { field: i, column: l } = t, c = l.filterParams, d = l.editorParams, a = (b, V) => {
924
- if (typeof b == "number") return b;
925
- if (typeof b == "string") {
926
- const H = parseFloat(b);
927
- return isNaN(H) ? V : H;
971
+ const { field: n, column: i } = t, l = i.filterParams, u = i.editorParams, a = (p, D) => {
972
+ if (typeof p == "number") return p;
973
+ if (typeof p == "string") {
974
+ const z = parseFloat(p);
975
+ return isNaN(z) ? D : z;
928
976
  }
929
- return V;
930
- }, m = r.filter((b) => typeof b == "number" && !isNaN(b)), k = m.length > 0 ? Math.min(...m) : 0, w = m.length > 0 ? Math.max(...m) : 100, u = a(c?.min ?? d?.min, k), v = a(c?.max ?? d?.max, w), E = c?.step ?? d?.step ?? 1, g = this.filters.get(i);
931
- let x = u, S = v;
932
- g?.operator === "between" ? (x = a(g.value, u), S = a(g.valueTo, v)) : g?.operator === "greaterThanOrEqual" ? x = a(g.value, u) : g?.operator === "lessThanOrEqual" && (S = a(g.value, v));
933
- const C = document.createElement("div");
934
- C.className = "tbw-filter-range-inputs";
977
+ return D;
978
+ }, f = r.filter((p) => typeof p == "number" && !isNaN(p)), N = f.length > 0 ? Math.min(...f) : 0, y = f.length > 0 ? Math.max(...f) : 100, h = a(l?.min ?? u?.min, N), C = a(l?.max ?? u?.max, y), F = l?.step ?? u?.step ?? 1, w = this.filters.get(n);
979
+ let E = h, k = C;
980
+ w?.operator === "between" ? (E = a(w.value, h), k = a(w.valueTo, C)) : w?.operator === "greaterThanOrEqual" ? E = a(w.value, h) : w?.operator === "lessThanOrEqual" && (k = a(w.value, C));
981
+ const T = document.createElement("div");
982
+ T.className = "tbw-filter-range-inputs";
935
983
  const R = document.createElement("div");
936
984
  R.className = "tbw-filter-range-group";
985
+ const L = document.createElement("label");
986
+ L.textContent = "Min", L.className = "tbw-filter-range-label";
987
+ const S = document.createElement("input");
988
+ S.type = "number", S.className = "tbw-filter-range-input", S.min = String(h), S.max = String(C), S.step = String(F), S.value = String(E), R.appendChild(L), R.appendChild(S), T.appendChild(R);
989
+ const I = document.createElement("span");
990
+ I.className = "tbw-filter-range-separator", I.textContent = "–", T.appendChild(I);
991
+ const P = document.createElement("div");
992
+ P.className = "tbw-filter-range-group";
937
993
  const A = document.createElement("label");
938
- A.textContent = "Min", A.className = "tbw-filter-range-label";
939
- const f = document.createElement("input");
940
- f.type = "number", f.className = "tbw-filter-range-input", f.min = String(u), f.max = String(v), f.step = String(E), f.value = String(x), R.appendChild(A), R.appendChild(f), C.appendChild(R);
941
- const L = document.createElement("span");
942
- L.className = "tbw-filter-range-separator", L.textContent = "–", C.appendChild(L);
943
- const T = document.createElement("div");
944
- T.className = "tbw-filter-range-group";
945
- const P = document.createElement("label");
946
- P.textContent = "Max", P.className = "tbw-filter-range-label";
947
- const p = document.createElement("input");
948
- p.type = "number", p.className = "tbw-filter-range-input", p.min = String(u), p.max = String(v), p.step = String(E), p.value = String(S), T.appendChild(P), T.appendChild(p), C.appendChild(T), e.appendChild(C);
949
- const o = document.createElement("div");
950
- o.className = "tbw-filter-range-slider";
951
- const h = document.createElement("div");
952
- h.className = "tbw-filter-range-track";
953
- const y = document.createElement("div");
954
- y.className = "tbw-filter-range-fill";
955
- const n = document.createElement("input");
956
- n.type = "range", n.className = "tbw-filter-range-thumb tbw-filter-range-thumb-min", n.min = String(u), n.max = String(v), n.step = String(E), n.value = String(x);
957
- const s = document.createElement("input");
958
- s.type = "range", s.className = "tbw-filter-range-thumb tbw-filter-range-thumb-max", s.min = String(u), s.max = String(v), s.step = String(E), s.value = String(S), o.appendChild(h), o.appendChild(y), o.appendChild(n), o.appendChild(s), e.appendChild(o);
959
- const F = () => {
960
- const b = parseFloat(n.value), V = parseFloat(s.value), H = v - u, D = (b - u) / H * 100, O = (V - u) / H * 100;
961
- y.style.left = `${D}%`, y.style.width = `${O - D}%`;
994
+ A.textContent = "Max", A.className = "tbw-filter-range-label";
995
+ const v = document.createElement("input");
996
+ v.type = "number", v.className = "tbw-filter-range-input", v.min = String(h), v.max = String(C), v.step = String(F), v.value = String(k), P.appendChild(A), P.appendChild(v), T.appendChild(P), e.appendChild(T);
997
+ const s = document.createElement("div");
998
+ s.className = "tbw-filter-range-slider";
999
+ const b = document.createElement("div");
1000
+ b.className = "tbw-filter-range-track";
1001
+ const m = document.createElement("div");
1002
+ m.className = "tbw-filter-range-fill";
1003
+ const o = document.createElement("input");
1004
+ o.type = "range", o.className = "tbw-filter-range-thumb tbw-filter-range-thumb-min", o.min = String(h), o.max = String(C), o.step = String(F), o.value = String(E);
1005
+ const c = document.createElement("input");
1006
+ c.type = "range", c.className = "tbw-filter-range-thumb tbw-filter-range-thumb-max", c.min = String(h), c.max = String(C), c.step = String(F), c.value = String(k), s.appendChild(b), s.appendChild(m), s.appendChild(o), s.appendChild(c), e.appendChild(s);
1007
+ const g = () => {
1008
+ const p = parseFloat(o.value), D = parseFloat(c.value), z = C - h, q = (p - h) / z * 100, Y = (D - h) / z * 100;
1009
+ m.style.left = `${q}%`, m.style.width = `${Y - q}%`;
962
1010
  };
963
- n.addEventListener("input", () => {
964
- const b = Math.min(parseFloat(n.value), parseFloat(s.value));
965
- n.value = String(b), f.value = String(b), F();
966
- }), s.addEventListener("input", () => {
967
- const b = Math.max(parseFloat(s.value), parseFloat(n.value));
968
- s.value = String(b), p.value = String(b), F();
969
- }), f.addEventListener("input", () => {
970
- let b = parseFloat(f.value) || u;
971
- b = Math.max(u, Math.min(b, parseFloat(p.value))), n.value = String(b), F();
972
- }), p.addEventListener("input", () => {
973
- let b = parseFloat(p.value) || v;
974
- b = Math.min(v, Math.max(b, parseFloat(f.value))), s.value = String(b), F();
975
- }), F();
1011
+ o.addEventListener("input", () => {
1012
+ const p = Math.min(parseFloat(o.value), parseFloat(c.value));
1013
+ o.value = String(p), S.value = String(p), g();
1014
+ }), c.addEventListener("input", () => {
1015
+ const p = Math.max(parseFloat(c.value), parseFloat(o.value));
1016
+ c.value = String(p), v.value = String(p), g();
1017
+ }), S.addEventListener("input", () => {
1018
+ let p = parseFloat(S.value) || h;
1019
+ p = Math.max(h, Math.min(p, parseFloat(v.value))), o.value = String(p), g();
1020
+ }), v.addEventListener("input", () => {
1021
+ let p = parseFloat(v.value) || C;
1022
+ p = Math.min(C, Math.max(p, parseFloat(S.value))), c.value = String(p), g();
1023
+ }), g();
976
1024
  const M = document.createElement("div");
977
1025
  M.className = "tbw-filter-buttons";
978
- const _ = document.createElement("button");
979
- _.className = "tbw-filter-apply-btn", _.textContent = "Apply", _.addEventListener("click", () => {
980
- const b = parseFloat(f.value), V = parseFloat(p.value);
981
- t.applyTextFilter("between", b, V);
982
- }), M.appendChild(_);
983
- const q = document.createElement("button");
984
- q.className = "tbw-filter-clear-btn", q.textContent = "Clear Filter", q.addEventListener("click", () => {
1026
+ const H = document.createElement("button");
1027
+ H.className = "tbw-filter-apply-btn", H.textContent = "Apply", H.addEventListener("click", () => {
1028
+ const p = parseFloat(S.value), D = parseFloat(v.value);
1029
+ t.applyTextFilter("between", p, D);
1030
+ }), M.appendChild(H);
1031
+ const d = document.createElement("button");
1032
+ d.className = "tbw-filter-clear-btn", d.textContent = "Clear Filter", d.addEventListener("click", () => {
985
1033
  t.clearFilter();
986
- }), M.appendChild(q), e.appendChild(M);
1034
+ }), M.appendChild(d), e.appendChild(M);
987
1035
  }
988
1036
  /**
989
1037
  * Render a date range filter panel with from/to date inputs
990
1038
  */
991
1039
  renderDateFilterPanel(e, t, r) {
992
- const { field: i, column: l } = t, c = l.filterParams, d = l.editorParams, a = r.filter((n) => n instanceof Date || typeof n == "string" && !isNaN(Date.parse(n))).map((n) => n instanceof Date ? n : new Date(n)).filter((n) => !isNaN(n.getTime())), m = a.length > 0 ? new Date(Math.min(...a.map((n) => n.getTime()))) : null, k = a.length > 0 ? new Date(Math.max(...a.map((n) => n.getTime()))) : null, w = (n) => n ? n.toISOString().split("T")[0] : "", u = (n) => n ? typeof n == "string" ? n : typeof n == "number" ? w(new Date(n)) : "" : "", v = u(c?.min) || u(d?.min) || w(m), E = u(c?.max) || u(d?.max) || w(k), g = this.filters.get(i);
993
- let x = "", S = "";
994
- g?.operator === "between" ? (x = u(g.value) || "", S = u(g.valueTo) || "") : g?.operator === "greaterThanOrEqual" ? x = u(g.value) || "" : g?.operator === "lessThanOrEqual" && (S = u(g.value) || "");
995
- const C = document.createElement("div");
996
- C.className = "tbw-filter-date-range";
1040
+ const { field: n, column: i } = t, l = i.filterParams, u = i.editorParams, a = r.filter((d) => d instanceof Date || typeof d == "string" && !isNaN(Date.parse(d))).map((d) => d instanceof Date ? d : new Date(d)).filter((d) => !isNaN(d.getTime())), f = a.length > 0 ? new Date(Math.min(...a.map((d) => d.getTime()))) : null, N = a.length > 0 ? new Date(Math.max(...a.map((d) => d.getTime()))) : null, y = (d) => d ? d.toISOString().split("T")[0] : "", h = (d) => d ? typeof d == "string" ? d : typeof d == "number" ? y(new Date(d)) : "" : "", C = h(l?.min) || h(u?.min) || y(f), F = h(l?.max) || h(u?.max) || y(N), w = this.filters.get(n);
1041
+ let E = "", k = "";
1042
+ const T = w?.operator === "blank";
1043
+ w?.operator === "between" ? (E = h(w.value) || "", k = h(w.valueTo) || "") : w?.operator === "greaterThanOrEqual" ? E = h(w.value) || "" : w?.operator === "lessThanOrEqual" && (k = h(w.value) || "");
997
1044
  const R = document.createElement("div");
998
- R.className = "tbw-filter-date-group";
999
- const A = document.createElement("label");
1000
- A.textContent = "From", A.className = "tbw-filter-range-label";
1001
- const f = document.createElement("input");
1002
- f.type = "date", f.className = "tbw-filter-date-input", v && (f.min = v), E && (f.max = E), f.value = x, R.appendChild(A), R.appendChild(f), C.appendChild(R);
1003
- const L = document.createElement("span");
1004
- L.className = "tbw-filter-range-separator", L.textContent = "–", C.appendChild(L);
1005
- const T = document.createElement("div");
1006
- T.className = "tbw-filter-date-group";
1007
- const P = document.createElement("label");
1008
- P.textContent = "To", P.className = "tbw-filter-range-label";
1009
- const p = document.createElement("input");
1010
- p.type = "date", p.className = "tbw-filter-date-input", v && (p.min = v), E && (p.max = E), p.value = S, T.appendChild(P), T.appendChild(p), C.appendChild(T), e.appendChild(C);
1011
- const o = document.createElement("div");
1012
- o.className = "tbw-filter-buttons";
1013
- const h = document.createElement("button");
1014
- h.className = "tbw-filter-apply-btn", h.textContent = "Apply", h.addEventListener("click", () => {
1015
- const n = f.value, s = p.value;
1016
- n && s ? t.applyTextFilter("between", n, s) : n ? t.applyTextFilter("greaterThanOrEqual", n) : s ? t.applyTextFilter("lessThanOrEqual", s) : t.clearFilter();
1017
- }), o.appendChild(h);
1018
- const y = document.createElement("button");
1019
- y.className = "tbw-filter-clear-btn", y.textContent = "Clear Filter", y.addEventListener("click", () => {
1045
+ R.className = "tbw-filter-date-range";
1046
+ const L = document.createElement("div");
1047
+ L.className = "tbw-filter-date-group";
1048
+ const S = document.createElement("label");
1049
+ S.textContent = "From", S.className = "tbw-filter-range-label";
1050
+ const I = document.createElement("input");
1051
+ I.type = "date", I.className = "tbw-filter-date-input", C && (I.min = C), F && (I.max = F), I.value = E, L.appendChild(S), L.appendChild(I), R.appendChild(L);
1052
+ const P = document.createElement("span");
1053
+ P.className = "tbw-filter-range-separator", P.textContent = "–", R.appendChild(P);
1054
+ const A = document.createElement("div");
1055
+ A.className = "tbw-filter-date-group";
1056
+ const v = document.createElement("label");
1057
+ v.textContent = "To", v.className = "tbw-filter-range-label";
1058
+ const s = document.createElement("input");
1059
+ s.type = "date", s.className = "tbw-filter-date-input", C && (s.min = C), F && (s.max = F), s.value = k, A.appendChild(v), A.appendChild(s), R.appendChild(A), e.appendChild(R);
1060
+ const b = document.createElement("label");
1061
+ b.className = "tbw-filter-blank-option";
1062
+ const m = document.createElement("input");
1063
+ m.type = "checkbox", m.className = "tbw-filter-blank-checkbox", m.checked = T;
1064
+ const o = document.createTextNode("Show only blank");
1065
+ b.appendChild(m), b.appendChild(o);
1066
+ const c = (d) => {
1067
+ I.disabled = d, s.disabled = d, R.classList.toggle("tbw-filter-disabled", d);
1068
+ };
1069
+ c(T), m.addEventListener("change", () => {
1070
+ c(m.checked);
1071
+ }), e.appendChild(b);
1072
+ const g = document.createElement("div");
1073
+ g.className = "tbw-filter-buttons";
1074
+ const M = document.createElement("button");
1075
+ M.className = "tbw-filter-apply-btn", M.textContent = "Apply", M.addEventListener("click", () => {
1076
+ if (m.checked) {
1077
+ t.applyTextFilter("blank", "");
1078
+ return;
1079
+ }
1080
+ const d = I.value, p = s.value;
1081
+ d && p ? t.applyTextFilter("between", d, p) : d ? t.applyTextFilter("greaterThanOrEqual", d) : p ? t.applyTextFilter("lessThanOrEqual", p) : t.clearFilter();
1082
+ }), g.appendChild(M);
1083
+ const H = document.createElement("button");
1084
+ H.className = "tbw-filter-clear-btn", H.textContent = "Clear Filter", H.addEventListener("click", () => {
1020
1085
  t.clearFilter();
1021
- }), o.appendChild(y), e.appendChild(o);
1086
+ }), g.appendChild(H), e.appendChild(g);
1022
1087
  }
1023
1088
  /**
1024
1089
  * Apply a set filter (exclude values)
@@ -1034,31 +1099,31 @@ class I extends K {
1034
1099
  /**
1035
1100
  * Apply a text/number/date filter
1036
1101
  */
1037
- applyTextFilter(e, t, r, i) {
1102
+ applyTextFilter(e, t, r, n) {
1038
1103
  this.filters.set(e, {
1039
1104
  field: e,
1040
1105
  type: "text",
1041
1106
  operator: t,
1042
1107
  value: r,
1043
- valueTo: i
1108
+ valueTo: n
1044
1109
  }), this.applyFiltersInternal();
1045
1110
  }
1046
1111
  /**
1047
1112
  * Internal method to apply filters (sync or async based on config)
1048
1113
  */
1049
1114
  applyFiltersInternal() {
1050
- this.cachedResult = null, this.cacheKey = null;
1115
+ this.cachedResult = null, this.cacheKey = null, this.cachedInputSpot = null;
1051
1116
  const e = [...this.filters.values()];
1052
1117
  if (this.config.filterHandler) {
1053
1118
  const t = this.grid;
1054
1119
  t.setAttribute("aria-busy", "true");
1055
- const r = this.config.filterHandler(e, this.sourceRows), i = (l) => {
1056
- t.removeAttribute("aria-busy"), this.cachedResult = l, this.grid.rows = l, this.emit("filter-change", {
1120
+ const r = this.config.filterHandler(e, this.sourceRows), n = (i) => {
1121
+ t.removeAttribute("aria-busy"), this.cachedResult = i, this.grid.rows = i, this.emit("filter-change", {
1057
1122
  filters: e,
1058
- filteredRowCount: l.length
1123
+ filteredRowCount: i.length
1059
1124
  }), this.emitPluginEvent("filter-applied", { filters: e }), this.requestRender();
1060
1125
  };
1061
- r && typeof r.then == "function" ? r.then(i) : i(r);
1126
+ r && typeof r.then == "function" ? r.then(n) : n(r);
1062
1127
  return;
1063
1128
  }
1064
1129
  this.emit("filter-change", {
@@ -1100,11 +1165,11 @@ class I extends K {
1100
1165
  value: t.filter.value,
1101
1166
  valueTo: t.filter.valueTo
1102
1167
  };
1103
- this.filters.set(e, r), this.cachedResult = null, this.cacheKey = null;
1168
+ this.filters.set(e, r), this.cachedResult = null, this.cacheKey = null, this.cachedInputSpot = null;
1104
1169
  }
1105
1170
  // #endregion
1106
1171
  }
1107
1172
  export {
1108
- I as FilteringPlugin
1173
+ _ as FilteringPlugin
1109
1174
  };
1110
1175
  //# sourceMappingURL=index.js.map