@toolbox-web/grid 1.4.0 → 1.6.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 (76) hide show
  1. package/all.js +859 -671
  2. package/all.js.map +1 -1
  3. package/index.js +513 -495
  4. package/index.js.map +1 -1
  5. package/lib/core/internal/header.d.ts.map +1 -1
  6. package/lib/core/internal/rows.d.ts +8 -0
  7. package/lib/core/internal/rows.d.ts.map +1 -1
  8. package/lib/core/types.d.ts +82 -17
  9. package/lib/core/types.d.ts.map +1 -1
  10. package/lib/plugins/clipboard/index.js.map +1 -1
  11. package/lib/plugins/column-virtualization/index.js.map +1 -1
  12. package/lib/plugins/context-menu/index.js.map +1 -1
  13. package/lib/plugins/editing/index.js.map +1 -1
  14. package/lib/plugins/editing/types.d.ts +68 -0
  15. package/lib/plugins/editing/types.d.ts.map +1 -1
  16. package/lib/plugins/export/index.d.ts +1 -1
  17. package/lib/plugins/export/index.d.ts.map +1 -1
  18. package/lib/plugins/export/index.js.map +1 -1
  19. package/lib/plugins/filtering/FilteringPlugin.d.ts +18 -1
  20. package/lib/plugins/filtering/FilteringPlugin.d.ts.map +1 -1
  21. package/lib/plugins/filtering/index.d.ts +1 -1
  22. package/lib/plugins/filtering/index.d.ts.map +1 -1
  23. package/lib/plugins/filtering/index.js +313 -183
  24. package/lib/plugins/filtering/index.js.map +1 -1
  25. package/lib/plugins/filtering/types.d.ts +81 -2
  26. package/lib/plugins/filtering/types.d.ts.map +1 -1
  27. package/lib/plugins/grouping-columns/index.js.map +1 -1
  28. package/lib/plugins/grouping-rows/GroupingRowsPlugin.d.ts +12 -3
  29. package/lib/plugins/grouping-rows/GroupingRowsPlugin.d.ts.map +1 -1
  30. package/lib/plugins/grouping-rows/grouping-rows.d.ts +13 -2
  31. package/lib/plugins/grouping-rows/grouping-rows.d.ts.map +1 -1
  32. package/lib/plugins/grouping-rows/index.d.ts +1 -1
  33. package/lib/plugins/grouping-rows/index.d.ts.map +1 -1
  34. package/lib/plugins/grouping-rows/index.js +199 -125
  35. package/lib/plugins/grouping-rows/index.js.map +1 -1
  36. package/lib/plugins/grouping-rows/types.d.ts +24 -2
  37. package/lib/plugins/grouping-rows/types.d.ts.map +1 -1
  38. package/lib/plugins/master-detail/index.d.ts +1 -1
  39. package/lib/plugins/master-detail/index.d.ts.map +1 -1
  40. package/lib/plugins/master-detail/index.js.map +1 -1
  41. package/lib/plugins/multi-sort/index.js.map +1 -1
  42. package/lib/plugins/pinned-columns/index.js.map +1 -1
  43. package/lib/plugins/pinned-rows/index.js +1 -1
  44. package/lib/plugins/pinned-rows/index.js.map +1 -1
  45. package/lib/plugins/pivot/index.js.map +1 -1
  46. package/lib/plugins/print/index.js.map +1 -1
  47. package/lib/plugins/reorder/index.js.map +1 -1
  48. package/lib/plugins/responsive/index.js.map +1 -1
  49. package/lib/plugins/row-reorder/index.js.map +1 -1
  50. package/lib/plugins/selection/SelectionPlugin.d.ts +5 -0
  51. package/lib/plugins/selection/SelectionPlugin.d.ts.map +1 -1
  52. package/lib/plugins/selection/index.js +90 -77
  53. package/lib/plugins/selection/index.js.map +1 -1
  54. package/lib/plugins/selection/types.d.ts +45 -0
  55. package/lib/plugins/selection/types.d.ts.map +1 -1
  56. package/lib/plugins/server-side/index.js.map +1 -1
  57. package/lib/plugins/tree/index.js.map +1 -1
  58. package/lib/plugins/undo-redo/index.d.ts +1 -1
  59. package/lib/plugins/undo-redo/index.d.ts.map +1 -1
  60. package/lib/plugins/undo-redo/index.js.map +1 -1
  61. package/lib/plugins/visibility/index.d.ts +1 -1
  62. package/lib/plugins/visibility/index.d.ts.map +1 -1
  63. package/lib/plugins/visibility/index.js.map +1 -1
  64. package/package.json +1 -1
  65. package/umd/grid.all.umd.js +27 -24
  66. package/umd/grid.all.umd.js.map +1 -1
  67. package/umd/grid.umd.js +10 -10
  68. package/umd/grid.umd.js.map +1 -1
  69. package/umd/plugins/filtering.umd.js +1 -1
  70. package/umd/plugins/filtering.umd.js.map +1 -1
  71. package/umd/plugins/grouping-rows.umd.js +4 -1
  72. package/umd/plugins/grouping-rows.umd.js.map +1 -1
  73. package/umd/plugins/pinned-rows.umd.js +1 -1
  74. package/umd/plugins/pinned-rows.umd.js.map +1 -1
  75. package/umd/plugins/selection.umd.js +2 -2
  76. package/umd/plugins/selection.umd.js.map +1 -1
@@ -1,19 +1,19 @@
1
- function _(h) {
2
- const { totalRows: e, viewportHeight: t, scrollTop: r, rowHeight: i, overscan: n } = h, a = Math.ceil(t / i);
3
- let o = Math.floor(r / i) - n;
4
- o < 0 && (o = 0);
5
- let l = o + a + n * 2;
6
- return l > e && (l = e), l === e && o > 0 && (o = Math.max(0, l - a - n * 2)), {
7
- start: o,
8
- end: l,
9
- offsetY: o * i,
10
- totalHeight: e * i
1
+ function G(F) {
2
+ const { totalRows: e, viewportHeight: t, scrollTop: r, rowHeight: n, overscan: s } = F, o = Math.ceil(t / n);
3
+ let c = Math.floor(r / n) - s;
4
+ c < 0 && (c = 0);
5
+ let i = c + o + s * 2;
6
+ return i > e && (i = e), i === e && c > 0 && (c = Math.max(0, i - o - s * 2)), {
7
+ start: c,
8
+ end: i,
9
+ offsetY: c * n,
10
+ totalHeight: e * n
11
11
  };
12
12
  }
13
- function M(h, e) {
14
- return h <= e;
13
+ function $(F, e) {
14
+ return F <= e;
15
15
  }
16
- const H = '<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>', z = {
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 H = '<svg viewBox="0 0 16 16" width="12" height="12"><path fill="currentCo
22
22
  submenuArrow: "▶",
23
23
  dragHandle: "⋮⋮",
24
24
  toolPanel: "☰",
25
- filter: H,
26
- filterActive: H,
25
+ filter: B,
26
+ filterActive: B,
27
27
  print: "🖨️"
28
28
  };
29
- class q {
29
+ class W {
30
30
  /**
31
31
  * Plugin dependencies - declare other plugins this one requires.
32
32
  *
@@ -250,7 +250,7 @@ class q {
250
250
  */
251
251
  get gridIcons() {
252
252
  const e = this.grid?.gridConfig?.icons ?? {};
253
- return { ...z, ...e };
253
+ return { ...K, ...e };
254
254
  }
255
255
  // #region Animation Helpers
256
256
  /**
@@ -326,31 +326,31 @@ class q {
326
326
  }
327
327
  // #endregion
328
328
  }
329
- function B(h) {
330
- return h.meta?.utility === !0;
329
+ function j(F) {
330
+ return F.meta?.utility === !0;
331
331
  }
332
- function Y(h, e, t = !1) {
333
- const r = h[e.field];
332
+ function U(F, e, t = !1) {
333
+ const r = F[e.field];
334
334
  if (e.operator === "blank")
335
335
  return r == null || r === "";
336
336
  if (e.operator === "notBlank")
337
337
  return r != null && r !== "";
338
338
  if (r == null) return !1;
339
- const i = String(r), n = t ? i : i.toLowerCase(), a = t ? String(e.value) : String(e.value).toLowerCase();
339
+ const n = String(r), s = t ? n : n.toLowerCase(), o = t ? String(e.value) : String(e.value).toLowerCase();
340
340
  switch (e.operator) {
341
341
  // Text operators
342
342
  case "contains":
343
- return n.includes(a);
343
+ return s.includes(o);
344
344
  case "notContains":
345
- return !n.includes(a);
345
+ return !s.includes(o);
346
346
  case "equals":
347
- return n === a;
347
+ return s === o;
348
348
  case "notEquals":
349
- return n !== a;
349
+ return s !== o;
350
350
  case "startsWith":
351
- return n.startsWith(a);
351
+ return s.startsWith(o);
352
352
  case "endsWith":
353
- return n.endsWith(a);
353
+ return s.endsWith(o);
354
354
  // Number/Date operators (use raw numeric values)
355
355
  case "lessThan":
356
356
  return Number(r) < Number(e.value);
@@ -371,12 +371,12 @@ function Y(h, e, t = !1) {
371
371
  return !0;
372
372
  }
373
373
  }
374
- function D(h, e, t = !1) {
375
- return e.length ? h.filter((r) => e.every((i) => Y(r, i, t))) : h;
374
+ function J(F, e, t = !1) {
375
+ return e.length ? F.filter((r) => e.every((n) => U(r, n, t))) : F;
376
376
  }
377
- function $(h) {
377
+ function Q(F) {
378
378
  return JSON.stringify(
379
- h.map((e) => ({
379
+ F.map((e) => ({
380
380
  field: e.field,
381
381
  operator: e.operator,
382
382
  value: e.value,
@@ -384,20 +384,20 @@ function $(h) {
384
384
  }))
385
385
  );
386
386
  }
387
- function V(h, e) {
387
+ function O(F, e) {
388
388
  const t = /* @__PURE__ */ new Set();
389
- for (const r of h) {
390
- const i = r[e];
391
- i != null && t.add(i);
389
+ for (const r of F) {
390
+ const n = r[e];
391
+ n != null && t.add(n);
392
392
  }
393
- return [...t].sort((r, i) => typeof r == "number" && typeof i == "number" ? r - i : String(r).localeCompare(String(i)));
393
+ return [...t].sort((r, n) => typeof r == "number" && typeof n == "number" ? r - n : String(r).localeCompare(String(n)));
394
394
  }
395
- const G = '@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}}', K = "@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))}.tbw-filter-search-input{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)))}.tbw-filter-action-btn{background:transparent;border:none;color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));cursor:pointer;font-size:var(--tbw-font-size-xs, .75rem);padding:2px 0}.tbw-filter-action-btn:hover{text-decoration:underline}.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;min-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)))}}";
396
- class v extends q {
395
+ 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-action-btn{background:transparent;border:none;color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));cursor:pointer;font-size:var(--tbw-font-size-xs, .75rem);padding:2px 0}.tbw-filter-action-btn:hover{text-decoration:underline}.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-title{font-weight:500;margin-bottom:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem));padding-bottom:var(--tbw-spacing-sm, .375rem);border-bottom:1px solid var(--tbw-filter-divider, var(--tbw-color-border, light-dark(#d0d0d4, #454545)))}.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)}}";
396
+ class M extends W {
397
397
  /** @internal */
398
398
  name = "filtering";
399
399
  /** @internal */
400
- styles = G;
400
+ styles = X;
401
401
  /** @internal */
402
402
  get defaultConfig() {
403
403
  return {
@@ -407,6 +407,21 @@ class v extends q {
407
407
  useWorker: !0
408
408
  };
409
409
  }
410
+ // #region Helpers
411
+ /**
412
+ * Check if filtering is enabled at the grid level.
413
+ * Grid-wide `filterable: false` disables filtering for all columns.
414
+ */
415
+ isFilteringEnabled() {
416
+ return this.grid.effectiveConfig?.filterable !== !1;
417
+ }
418
+ /**
419
+ * Check if a specific column is filterable, respecting both grid-level and column-level settings.
420
+ */
421
+ isColumnFilterable(e) {
422
+ return this.isFilteringEnabled() ? e.filterable !== !1 : !1;
423
+ }
424
+ // #endregion
410
425
  // #region Internal State
411
426
  filters = /* @__PURE__ */ new Map();
412
427
  cachedResult = null;
@@ -438,7 +453,7 @@ class v extends q {
438
453
  return t;
439
454
  }
440
455
  }
441
- return v.DEFAULT_LIST_ITEM_HEIGHT;
456
+ return M.DEFAULT_LIST_ITEM_HEIGHT;
442
457
  }
443
458
  /**
444
459
  * Sync excludedValues map from a filter model (for set filters).
@@ -464,40 +479,40 @@ class v extends q {
464
479
  if (!t.length) return [...e];
465
480
  if (this.config.filterHandler)
466
481
  return this.cachedResult ? this.cachedResult : [...e];
467
- const r = $(t);
482
+ const r = Q(t);
468
483
  if (this.cacheKey === r && this.cachedResult)
469
484
  return this.cachedResult;
470
- const i = D([...e], t, this.config.caseSensitive);
471
- return this.cachedResult = i, this.cacheKey = r, i;
485
+ const n = J([...e], t, this.config.caseSensitive);
486
+ return this.cachedResult = n, this.cacheKey = r, n;
472
487
  }
473
488
  /** @internal */
474
489
  afterRender() {
475
490
  const e = this.gridElement;
476
491
  if (!e) return;
477
492
  e.querySelectorAll('[part~="header-cell"]').forEach((r) => {
478
- const i = r.getAttribute("data-col");
479
- if (i === null) return;
480
- const n = this.visibleColumns[parseInt(i, 10)];
481
- if (!n || n.filterable === !1 || B(n)) return;
482
- const a = n.field;
483
- if (!a) return;
484
- const o = this.filters.has(a);
485
- let l = r.querySelector(".tbw-filter-btn");
486
- if (l) {
487
- const b = l.classList.contains("active");
488
- if (l.classList.toggle("active", o), r.classList.toggle("filtered", o), b !== o) {
489
- const E = o ? "filterActive" : "filter";
490
- this.setIcon(l, this.resolveIcon(E));
493
+ const n = r.getAttribute("data-col");
494
+ if (n === null) return;
495
+ const s = this.visibleColumns[parseInt(n, 10)];
496
+ if (!s || !this.isColumnFilterable(s) || j(s)) return;
497
+ const o = s.field;
498
+ if (!o) return;
499
+ const c = this.filters.has(o);
500
+ let i = r.querySelector(".tbw-filter-btn");
501
+ if (i) {
502
+ const w = i.classList.contains("active");
503
+ if (i.classList.toggle("active", c), r.classList.toggle("filtered", c), w !== c) {
504
+ const b = c ? "filterActive" : "filter";
505
+ this.setIcon(i, this.resolveIcon(b));
491
506
  }
492
507
  return;
493
508
  }
494
- l = document.createElement("button"), l.className = "tbw-filter-btn", l.setAttribute("aria-label", `Filter ${n.header ?? a}`);
495
- const m = o ? "filterActive" : "filter";
496
- this.setIcon(l, this.resolveIcon(m)), o && (l.classList.add("active"), r.classList.add("filtered")), l.addEventListener("click", (b) => {
497
- b.stopPropagation(), this.toggleFilterPanel(a, n, l);
509
+ i = document.createElement("button"), i.className = "tbw-filter-btn", i.setAttribute("aria-label", `Filter ${s.header ?? o}`);
510
+ const m = c ? "filterActive" : "filter";
511
+ this.setIcon(i, this.resolveIcon(m)), c && (i.classList.add("active"), r.classList.add("filtered")), i.addEventListener("click", (w) => {
512
+ w.stopPropagation(), this.toggleFilterPanel(o, s, i);
498
513
  });
499
- const p = r.querySelector(".resize-handle");
500
- p ? r.insertBefore(l, p) : r.appendChild(l);
514
+ const S = r.querySelector(".resize-handle");
515
+ S ? r.insertBefore(i, S) : r.appendChild(i);
501
516
  });
502
517
  }
503
518
  // #endregion
@@ -584,7 +599,7 @@ class v extends q {
584
599
  * Uses sourceRows to include all values regardless of current filter.
585
600
  */
586
601
  getUniqueValues(e) {
587
- return V(this.sourceRows, e);
602
+ return O(this.sourceRows, e);
588
603
  }
589
604
  // #endregion
590
605
  // #region Private Methods
@@ -595,8 +610,8 @@ class v extends q {
595
610
  copyGridThemeContext(e) {
596
611
  const t = this.gridElement;
597
612
  if (!t) return;
598
- for (const i of t.classList)
599
- i.startsWith("tbw-") || i === "selecting" || e.classList.add(i);
613
+ for (const n of t.classList)
614
+ n.startsWith("tbw-") || n === "selecting" || e.classList.add(n);
600
615
  const r = t.dataset.theme;
601
616
  r && (e.dataset.theme = r);
602
617
  }
@@ -610,7 +625,7 @@ class v extends q {
610
625
  return;
611
626
  }
612
627
  const e = document.createElement("style");
613
- e.id = "tbw-filter-panel-styles", e.textContent = K, document.head.appendChild(e), this.globalStylesInjected = !0;
628
+ e.id = "tbw-filter-panel-styles", e.textContent = Z, document.head.appendChild(e), this.globalStylesInjected = !0;
614
629
  }
615
630
  /**
616
631
  * Toggle the filter panel for a field
@@ -621,41 +636,48 @@ class v extends q {
621
636
  return;
622
637
  }
623
638
  this.closeFilterPanel();
624
- const i = document.createElement("div");
625
- 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) {
626
- 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((a) => {
627
- this.openPanelField !== e || !this.panelElement || (i.innerHTML = "", this.renderPanelContent(e, t, i, a));
639
+ const n = document.createElement("div");
640
+ 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) {
641
+ 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((o) => {
642
+ this.openPanelField !== e || !this.panelElement || (n.innerHTML = "", this.renderPanelContent(e, t, n, o));
628
643
  });
629
644
  return;
630
645
  }
631
- const n = V(this.sourceRows, e);
632
- this.renderPanelContent(e, t, i, n), document.body.appendChild(i), this.positionPanel(i, r), this.setupPanelCloseHandler(i, r);
646
+ const s = O(this.sourceRows, e);
647
+ document.body.appendChild(n), this.positionPanel(n, r), this.renderPanelContent(e, t, n, s), this.setupPanelCloseHandler(n, r);
633
648
  }
634
649
  /**
635
650
  * Render filter panel content with given values
636
651
  */
637
- renderPanelContent(e, t, r, i) {
638
- let n = this.excludedValues.get(e);
639
- n || (n = /* @__PURE__ */ new Set(), this.excludedValues.set(e, n));
640
- const a = this.searchText.get(e) ?? "", o = {
652
+ renderPanelContent(e, t, r, n) {
653
+ let s = this.excludedValues.get(e);
654
+ s || (s = /* @__PURE__ */ new Set(), this.excludedValues.set(e, s));
655
+ const o = this.searchText.get(e) ?? "", c = {
641
656
  field: e,
642
657
  column: t,
643
- uniqueValues: i,
644
- excludedValues: n,
645
- searchText: a,
658
+ uniqueValues: n,
659
+ excludedValues: s,
660
+ searchText: o,
646
661
  applySetFilter: (m) => {
647
662
  this.applySetFilter(e, m), this.closeFilterPanel();
648
663
  },
649
- applyTextFilter: (m, p, b) => {
650
- this.applyTextFilter(e, m, p, b), this.closeFilterPanel();
664
+ applyTextFilter: (m, S, w) => {
665
+ this.applyTextFilter(e, m, S, w), this.closeFilterPanel();
651
666
  },
652
667
  clearFilter: () => {
653
668
  this.clearFieldFilter(e), this.closeFilterPanel();
654
669
  },
655
670
  closePanel: () => this.closeFilterPanel()
656
671
  };
657
- let l = !1;
658
- this.config.filterPanelRenderer && (this.config.filterPanelRenderer(r, o), l = r.children.length > 0), l || this.renderDefaultFilterPanel(r, o, i, n);
672
+ let i = !1;
673
+ if (this.config.filterPanelRenderer && (this.config.filterPanelRenderer(r, c), i = r.children.length > 0), !i && t.type) {
674
+ const m = this.grid.effectiveConfig.typeDefaults?.[t.type];
675
+ m?.filterPanelRenderer && (m.filterPanelRenderer(r, c), i = r.children.length > 0);
676
+ }
677
+ if (!i) {
678
+ const m = t.type;
679
+ m === "number" ? this.renderNumberFilterPanel(r, c, n) : m === "date" ? this.renderDateFilterPanel(r, c, n) : this.renderDefaultFilterPanel(r, c, n, s);
680
+ }
659
681
  }
660
682
  /**
661
683
  * Setup click-outside handler to close the panel
@@ -684,137 +706,245 @@ class v extends q {
684
706
  * Check if browser supports CSS Anchor Positioning
685
707
  */
686
708
  static checkAnchorPositioningSupport() {
687
- return v.supportsAnchorPositioning === null && (v.supportsAnchorPositioning = CSS.supports("anchor-name", "--test")), v.supportsAnchorPositioning;
709
+ return M.supportsAnchorPositioning === null && (M.supportsAnchorPositioning = CSS.supports("anchor-name", "--test")), M.supportsAnchorPositioning;
688
710
  }
689
711
  /**
690
712
  * Position the panel below the header cell
691
713
  * Uses CSS Anchor Positioning if supported, falls back to JS positioning
692
714
  */
693
715
  positionPanel(e, t) {
694
- const i = t.closest(".cell") ?? t;
695
- if (i.style.anchorName = "--tbw-filter-anchor", this.panelAnchorElement = i, v.checkAnchorPositioningSupport()) {
716
+ const n = t.closest(".cell") ?? t;
717
+ if (n.style.anchorName = "--tbw-filter-anchor", this.panelAnchorElement = n, M.checkAnchorPositioningSupport()) {
696
718
  requestAnimationFrame(() => {
697
- const a = e.getBoundingClientRect(), o = i.getBoundingClientRect();
698
- a.top < o.top && e.classList.add("tbw-filter-panel-above");
719
+ const o = e.getBoundingClientRect(), c = n.getBoundingClientRect();
720
+ o.top < c.top && e.classList.add("tbw-filter-panel-above");
699
721
  });
700
722
  return;
701
723
  }
702
- const n = i.getBoundingClientRect();
703
- e.style.position = "fixed", e.style.top = `${n.bottom + 4}px`, e.style.left = `${n.left}px`, requestAnimationFrame(() => {
704
- const a = e.getBoundingClientRect();
705
- a.right > window.innerWidth - 8 && (e.style.left = `${n.right - a.width}px`), a.bottom > window.innerHeight - 8 && (e.style.top = `${n.top - a.height - 4}px`, e.classList.add("tbw-filter-panel-above"));
724
+ const s = n.getBoundingClientRect();
725
+ e.style.position = "fixed", e.style.top = `${s.bottom + 4}px`, e.style.left = `${s.left}px`, requestAnimationFrame(() => {
726
+ const o = e.getBoundingClientRect();
727
+ o.right > window.innerWidth - 8 && (e.style.left = `${s.right - o.width}px`), o.bottom > window.innerHeight - 8 && (e.style.top = `${s.top - o.height - 4}px`, e.classList.add("tbw-filter-panel-above"));
706
728
  });
707
729
  }
708
730
  /**
709
731
  * Render the default filter panel content
710
732
  */
711
- renderDefaultFilterPanel(e, t, r, i) {
712
- const { field: n } = t, a = this.getListItemHeight(), o = document.createElement("div");
713
- o.className = "tbw-filter-search";
714
- const l = document.createElement("input");
715
- l.type = "text", l.placeholder = "Search...", l.className = "tbw-filter-search-input", l.value = this.searchText.get(n) ?? "", o.appendChild(l), e.appendChild(o);
733
+ renderDefaultFilterPanel(e, t, r, n) {
734
+ const { field: s } = t, o = this.getListItemHeight(), c = document.createElement("div");
735
+ c.className = "tbw-filter-search";
736
+ const i = document.createElement("input");
737
+ i.type = "text", i.placeholder = "Search...", i.className = "tbw-filter-search-input", i.value = this.searchText.get(s) ?? "", c.appendChild(i), e.appendChild(c);
716
738
  const m = document.createElement("div");
717
739
  m.className = "tbw-filter-actions";
718
- const p = document.createElement("label");
719
- p.className = "tbw-filter-value-item", p.style.padding = "0", p.style.margin = "0";
720
- const b = document.createElement("input");
721
- b.type = "checkbox", b.className = "tbw-filter-checkbox";
722
- const E = document.createElement("span");
723
- E.textContent = "Select All", p.appendChild(b), p.appendChild(E), m.appendChild(p);
724
- const F = () => {
725
- const s = [...x.values()], u = s.every((c) => c), w = s.every((c) => !c);
726
- b.checked = u, b.indeterminate = !u && !w;
740
+ const S = document.createElement("label");
741
+ S.className = "tbw-filter-value-item", S.style.padding = "0", S.style.margin = "0";
742
+ const w = document.createElement("input");
743
+ w.type = "checkbox", w.className = "tbw-filter-checkbox";
744
+ const b = document.createElement("span");
745
+ b.textContent = "Select All", S.appendChild(w), S.appendChild(b), m.appendChild(S);
746
+ const v = () => {
747
+ const l = [...E.values()], p = l.every((d) => d), C = l.every((d) => !d);
748
+ w.checked = p, w.indeterminate = !p && !C;
727
749
  };
728
- b.addEventListener("change", () => {
729
- const s = b.checked;
730
- for (const u of x.keys())
731
- x.set(u, s);
732
- F(), T();
750
+ w.addEventListener("change", () => {
751
+ const l = w.checked;
752
+ for (const p of E.keys())
753
+ E.set(p, l);
754
+ v(), R();
733
755
  }), e.appendChild(m);
734
756
  const y = document.createElement("div");
735
757
  y.className = "tbw-filter-values";
736
- const S = document.createElement("div");
737
- S.className = "tbw-filter-values-spacer", y.appendChild(S);
738
758
  const g = document.createElement("div");
739
- g.className = "tbw-filter-values-content", y.appendChild(g);
740
- const x = /* @__PURE__ */ new Map();
741
- r.forEach((s) => {
742
- const u = s == null ? "__null__" : String(s);
743
- x.set(u, !i.has(s));
744
- }), F();
745
- let C = [];
746
- const I = (s, u) => {
747
- const w = s == null ? "(Blank)" : String(s), c = s == null ? "__null__" : String(s), d = document.createElement("label");
748
- d.className = "tbw-filter-value-item", d.style.position = "absolute", d.style.top = `${u * a}px`, d.style.left = "0", d.style.right = "0", d.style.height = `${a}px`, d.style.boxSizing = "border-box";
749
- const f = document.createElement("input");
750
- f.type = "checkbox", f.className = "tbw-filter-checkbox", f.checked = x.get(c) ?? !0, f.dataset.value = c, f.addEventListener("change", () => {
751
- x.set(c, f.checked), F();
759
+ g.className = "tbw-filter-values-spacer", y.appendChild(g);
760
+ const x = document.createElement("div");
761
+ x.className = "tbw-filter-values-content", y.appendChild(x);
762
+ const E = /* @__PURE__ */ new Map();
763
+ r.forEach((l) => {
764
+ const p = l == null ? "__null__" : String(l);
765
+ E.set(p, !n.has(l));
766
+ }), v();
767
+ let N = [];
768
+ const k = (l, p) => {
769
+ const C = l == null ? "(Blank)" : String(l), d = l == null ? "__null__" : String(l), a = document.createElement("label");
770
+ a.className = "tbw-filter-value-item", a.style.position = "absolute", a.style.top = `calc(var(--tbw-filter-item-height, 28px) * ${p})`, a.style.left = "0", a.style.right = "0", a.style.boxSizing = "border-box";
771
+ const u = document.createElement("input");
772
+ u.type = "checkbox", u.className = "tbw-filter-checkbox", u.checked = E.get(d) ?? !0, u.dataset.value = d, u.addEventListener("change", () => {
773
+ E.set(d, u.checked), v();
752
774
  });
753
- const P = document.createElement("span");
754
- return P.textContent = w, d.appendChild(f), d.appendChild(P), d;
755
- }, T = () => {
756
- const s = C.length, u = y.clientHeight, w = y.scrollTop;
757
- if (S.style.height = `${s * a}px`, M(s, v.LIST_BYPASS_THRESHOLD / 3)) {
758
- g.innerHTML = "", g.style.transform = "translateY(0px)", C.forEach((d, f) => {
759
- g.appendChild(I(d, f));
775
+ const I = document.createElement("span");
776
+ return I.textContent = C, a.appendChild(u), a.appendChild(I), a;
777
+ }, R = () => {
778
+ const l = N.length, p = y.clientHeight, C = y.scrollTop;
779
+ if (g.style.height = `${l * o}px`, $(l, M.LIST_BYPASS_THRESHOLD / 3)) {
780
+ x.innerHTML = "", x.style.transform = "translateY(0px)", N.forEach((a, u) => {
781
+ x.appendChild(k(a, u));
760
782
  });
761
783
  return;
762
784
  }
763
- const c = _({
764
- totalRows: s,
765
- viewportHeight: u,
766
- scrollTop: w,
767
- rowHeight: a,
768
- overscan: v.LIST_OVERSCAN
785
+ const d = G({
786
+ totalRows: l,
787
+ viewportHeight: p,
788
+ scrollTop: C,
789
+ rowHeight: o,
790
+ overscan: M.LIST_OVERSCAN
769
791
  });
770
- g.style.transform = `translateY(${c.offsetY}px)`, g.innerHTML = "";
771
- for (let d = c.start; d < c.end; d++)
772
- g.appendChild(I(C[d], d - c.start));
773
- }, L = (s) => {
774
- const u = this.config.caseSensitive ?? !1, w = u ? s : s.toLowerCase();
775
- if (C = r.filter((c) => {
776
- const d = c == null ? "(Blank)" : String(c), f = u ? d : d.toLowerCase();
777
- return !s || f.includes(w);
778
- }), C.length === 0) {
779
- S.style.height = "0px", g.innerHTML = "";
780
- const c = document.createElement("div");
781
- c.className = "tbw-filter-no-match", c.textContent = "No matching values", g.appendChild(c);
792
+ x.style.transform = `translateY(${d.offsetY}px)`, x.innerHTML = "";
793
+ for (let a = d.start; a < d.end; a++)
794
+ x.appendChild(k(N[a], a - d.start));
795
+ }, P = (l) => {
796
+ const p = this.config.caseSensitive ?? !1, C = p ? l : l.toLowerCase();
797
+ if (N = r.filter((d) => {
798
+ const a = d == null ? "(Blank)" : String(d), u = p ? a : a.toLowerCase();
799
+ return !l || u.includes(C);
800
+ }), N.length === 0) {
801
+ g.style.height = "0px", x.innerHTML = "";
802
+ const d = document.createElement("div");
803
+ d.className = "tbw-filter-no-match", d.textContent = "No matching values", x.appendChild(d);
782
804
  return;
783
805
  }
784
- T();
806
+ R();
785
807
  };
786
808
  y.addEventListener(
787
809
  "scroll",
788
810
  () => {
789
- C.length > 0 && T();
811
+ N.length > 0 && R();
790
812
  },
791
813
  { passive: !0 }
792
- ), L(l.value), e.appendChild(y);
793
- let N;
794
- l.addEventListener("input", () => {
795
- clearTimeout(N), N = setTimeout(() => {
796
- this.searchText.set(n, l.value), L(l.value);
814
+ ), P(i.value), e.appendChild(y);
815
+ let f;
816
+ i.addEventListener("input", () => {
817
+ clearTimeout(f), f = setTimeout(() => {
818
+ this.searchText.set(s, i.value), P(i.value);
797
819
  }, this.config.debounceMs ?? 150);
798
820
  });
799
- const R = document.createElement("div");
800
- R.className = "tbw-filter-buttons";
801
- const k = document.createElement("button");
802
- k.className = "tbw-filter-apply-btn", k.textContent = "Apply", k.addEventListener("click", () => {
803
- const s = [];
804
- for (const [u, w] of x)
805
- if (!w)
806
- if (u === "__null__")
807
- s.push(null);
821
+ const A = document.createElement("div");
822
+ A.className = "tbw-filter-buttons";
823
+ const T = document.createElement("button");
824
+ T.className = "tbw-filter-apply-btn", T.textContent = "Apply", T.addEventListener("click", () => {
825
+ const l = [];
826
+ for (const [p, C] of E)
827
+ if (!C)
828
+ if (p === "__null__")
829
+ l.push(null);
808
830
  else {
809
- const c = r.find((d) => String(d) === u);
810
- s.push(c !== void 0 ? c : u);
831
+ const d = r.find((a) => String(a) === p);
832
+ l.push(d !== void 0 ? d : p);
811
833
  }
812
- t.applySetFilter(s);
813
- }), R.appendChild(k);
814
- const A = document.createElement("button");
815
- A.className = "tbw-filter-clear-btn", A.textContent = "Clear Filter", A.addEventListener("click", () => {
834
+ t.applySetFilter(l);
835
+ }), A.appendChild(T);
836
+ const L = document.createElement("button");
837
+ L.className = "tbw-filter-clear-btn", L.textContent = "Clear Filter", L.addEventListener("click", () => {
838
+ t.clearFilter();
839
+ }), A.appendChild(L), e.appendChild(A);
840
+ }
841
+ /**
842
+ * Render a number range filter panel with min/max inputs and slider
843
+ */
844
+ renderNumberFilterPanel(e, t, r) {
845
+ const { field: n, column: s } = t, o = s.filterParams, c = s.editorParams, i = (h, V) => {
846
+ if (typeof h == "number") return h;
847
+ if (typeof h == "string") {
848
+ const H = parseFloat(h);
849
+ return isNaN(H) ? V : H;
850
+ }
851
+ return V;
852
+ }, m = r.filter((h) => typeof h == "number" && !isNaN(h)), S = m.length > 0 ? Math.min(...m) : 0, w = m.length > 0 ? Math.max(...m) : 100, b = i(o?.min ?? c?.min, S), v = i(o?.max ?? c?.max, w), y = o?.step ?? c?.step ?? 1, g = this.filters.get(n);
853
+ let x = b, E = v;
854
+ g?.operator === "between" ? (x = i(g.value, b), E = i(g.valueTo, v)) : g?.operator === "greaterThanOrEqual" ? x = i(g.value, b) : g?.operator === "lessThanOrEqual" && (E = i(g.value, v));
855
+ const N = document.createElement("div");
856
+ N.className = "tbw-filter-range-title", N.textContent = s.header || n, e.appendChild(N);
857
+ const k = document.createElement("div");
858
+ k.className = "tbw-filter-range-inputs";
859
+ const R = document.createElement("div");
860
+ R.className = "tbw-filter-range-group";
861
+ const P = document.createElement("label");
862
+ P.textContent = "Min", P.className = "tbw-filter-range-label";
863
+ const f = document.createElement("input");
864
+ f.type = "number", f.className = "tbw-filter-range-input", f.min = String(b), f.max = String(v), f.step = String(y), f.value = String(x), R.appendChild(P), R.appendChild(f), k.appendChild(R);
865
+ const A = document.createElement("span");
866
+ A.className = "tbw-filter-range-separator", A.textContent = "–", k.appendChild(A);
867
+ const T = document.createElement("div");
868
+ T.className = "tbw-filter-range-group";
869
+ const L = document.createElement("label");
870
+ L.textContent = "Max", L.className = "tbw-filter-range-label";
871
+ const l = document.createElement("input");
872
+ l.type = "number", l.className = "tbw-filter-range-input", l.min = String(b), l.max = String(v), l.step = String(y), l.value = String(E), T.appendChild(L), T.appendChild(l), k.appendChild(T), e.appendChild(k);
873
+ const p = document.createElement("div");
874
+ p.className = "tbw-filter-range-slider";
875
+ const C = document.createElement("div");
876
+ C.className = "tbw-filter-range-track";
877
+ const d = document.createElement("div");
878
+ d.className = "tbw-filter-range-fill";
879
+ const a = document.createElement("input");
880
+ a.type = "range", a.className = "tbw-filter-range-thumb tbw-filter-range-thumb-min", a.min = String(b), a.max = String(v), a.step = String(y), a.value = String(x);
881
+ const u = document.createElement("input");
882
+ u.type = "range", u.className = "tbw-filter-range-thumb tbw-filter-range-thumb-max", u.min = String(b), u.max = String(v), u.step = String(y), u.value = String(E), p.appendChild(C), p.appendChild(d), p.appendChild(a), p.appendChild(u), e.appendChild(p);
883
+ const I = () => {
884
+ const h = parseFloat(a.value), V = parseFloat(u.value), H = v - b, q = (h - b) / H * 100, Y = (V - b) / H * 100;
885
+ d.style.left = `${q}%`, d.style.width = `${Y - q}%`;
886
+ };
887
+ a.addEventListener("input", () => {
888
+ const h = Math.min(parseFloat(a.value), parseFloat(u.value));
889
+ a.value = String(h), f.value = String(h), I();
890
+ }), u.addEventListener("input", () => {
891
+ const h = Math.max(parseFloat(u.value), parseFloat(a.value));
892
+ u.value = String(h), l.value = String(h), I();
893
+ }), f.addEventListener("input", () => {
894
+ let h = parseFloat(f.value) || b;
895
+ h = Math.max(b, Math.min(h, parseFloat(l.value))), a.value = String(h), I();
896
+ }), l.addEventListener("input", () => {
897
+ let h = parseFloat(l.value) || v;
898
+ h = Math.min(v, Math.max(h, parseFloat(f.value))), u.value = String(h), I();
899
+ }), I();
900
+ const _ = document.createElement("div");
901
+ _.className = "tbw-filter-buttons";
902
+ const z = document.createElement("button");
903
+ z.className = "tbw-filter-apply-btn", z.textContent = "Apply", z.addEventListener("click", () => {
904
+ const h = parseFloat(f.value), V = parseFloat(l.value);
905
+ t.applyTextFilter("between", h, V);
906
+ }), _.appendChild(z);
907
+ const D = document.createElement("button");
908
+ D.className = "tbw-filter-clear-btn", D.textContent = "Clear Filter", D.addEventListener("click", () => {
909
+ t.clearFilter();
910
+ }), _.appendChild(D), e.appendChild(_);
911
+ }
912
+ /**
913
+ * Render a date range filter panel with from/to date inputs
914
+ */
915
+ renderDateFilterPanel(e, t, r) {
916
+ const { field: n, column: s } = t, o = s.filterParams, c = s.editorParams, i = r.filter((a) => a instanceof Date || typeof a == "string" && !isNaN(Date.parse(a))).map((a) => a instanceof Date ? a : new Date(a)).filter((a) => !isNaN(a.getTime())), m = i.length > 0 ? new Date(Math.min(...i.map((a) => a.getTime()))) : null, S = i.length > 0 ? new Date(Math.max(...i.map((a) => a.getTime()))) : null, w = (a) => a ? a.toISOString().split("T")[0] : "", b = (a) => a ? typeof a == "string" ? a : typeof a == "number" ? w(new Date(a)) : "" : "", v = b(o?.min) || b(c?.min) || w(m), y = b(o?.max) || b(c?.max) || w(S), g = this.filters.get(n);
917
+ let x = "", E = "";
918
+ g?.operator === "between" ? (x = b(g.value) || "", E = b(g.valueTo) || "") : g?.operator === "greaterThanOrEqual" ? x = b(g.value) || "" : g?.operator === "lessThanOrEqual" && (E = b(g.value) || "");
919
+ const N = document.createElement("div");
920
+ N.className = "tbw-filter-range-title", N.textContent = s.header || n, e.appendChild(N);
921
+ const k = document.createElement("div");
922
+ k.className = "tbw-filter-date-range";
923
+ const R = document.createElement("div");
924
+ R.className = "tbw-filter-date-group";
925
+ const P = document.createElement("label");
926
+ P.textContent = "From", P.className = "tbw-filter-range-label";
927
+ const f = document.createElement("input");
928
+ f.type = "date", f.className = "tbw-filter-date-input", v && (f.min = v), y && (f.max = y), f.value = x, R.appendChild(P), R.appendChild(f), k.appendChild(R);
929
+ const A = document.createElement("span");
930
+ A.className = "tbw-filter-range-separator", A.textContent = "–", k.appendChild(A);
931
+ const T = document.createElement("div");
932
+ T.className = "tbw-filter-date-group";
933
+ const L = document.createElement("label");
934
+ L.textContent = "To", L.className = "tbw-filter-range-label";
935
+ const l = document.createElement("input");
936
+ l.type = "date", l.className = "tbw-filter-date-input", v && (l.min = v), y && (l.max = y), l.value = E, T.appendChild(L), T.appendChild(l), k.appendChild(T), e.appendChild(k);
937
+ const p = document.createElement("div");
938
+ p.className = "tbw-filter-buttons";
939
+ const C = document.createElement("button");
940
+ C.className = "tbw-filter-apply-btn", C.textContent = "Apply", C.addEventListener("click", () => {
941
+ const a = f.value, u = l.value;
942
+ a && u ? t.applyTextFilter("between", a, u) : a ? t.applyTextFilter("greaterThanOrEqual", a) : u ? t.applyTextFilter("lessThanOrEqual", u) : t.clearFilter();
943
+ }), p.appendChild(C);
944
+ const d = document.createElement("button");
945
+ d.className = "tbw-filter-clear-btn", d.textContent = "Clear Filter", d.addEventListener("click", () => {
816
946
  t.clearFilter();
817
- }), R.appendChild(A), e.appendChild(R);
947
+ }), p.appendChild(d), e.appendChild(p);
818
948
  }
819
949
  /**
820
950
  * Apply a set filter (exclude values)
@@ -828,15 +958,15 @@ class v extends q {
828
958
  }), this.applyFiltersInternal();
829
959
  }
830
960
  /**
831
- * Apply a text filter
961
+ * Apply a text/number/date filter
832
962
  */
833
- applyTextFilter(e, t, r, i) {
963
+ applyTextFilter(e, t, r, n) {
834
964
  this.filters.set(e, {
835
965
  field: e,
836
966
  type: "text",
837
967
  operator: t,
838
968
  value: r,
839
- valueTo: i
969
+ valueTo: n
840
970
  }), this.applyFiltersInternal();
841
971
  }
842
972
  /**
@@ -848,13 +978,13 @@ class v extends q {
848
978
  if (this.config.filterHandler) {
849
979
  const t = this.grid;
850
980
  t.setAttribute("aria-busy", "true");
851
- const r = this.config.filterHandler(e, this.sourceRows), i = (n) => {
852
- t.removeAttribute("aria-busy"), this.cachedResult = n, this.grid.rows = n, this.emit("filter-change", {
981
+ const r = this.config.filterHandler(e, this.sourceRows), n = (s) => {
982
+ t.removeAttribute("aria-busy"), this.cachedResult = s, this.grid.rows = s, this.emit("filter-change", {
853
983
  filters: e,
854
- filteredRowCount: n.length
984
+ filteredRowCount: s.length
855
985
  }), this.requestRender();
856
986
  };
857
- r && typeof r.then == "function" ? r.then(i) : i(r);
987
+ r && typeof r.then == "function" ? r.then(n) : n(r);
858
988
  return;
859
989
  }
860
990
  this.emit("filter-change", {
@@ -901,6 +1031,6 @@ class v extends q {
901
1031
  // #endregion
902
1032
  }
903
1033
  export {
904
- v as FilteringPlugin
1034
+ M as FilteringPlugin
905
1035
  };
906
1036
  //# sourceMappingURL=index.js.map