twico-ui 1.22.3 → 1.24.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.
package/dist/index.mjs CHANGED
@@ -5650,6 +5650,10 @@ var COMBO_CSS = `
5650
5650
  .twc-opt__main { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
5651
5651
  .twc-opt__label { line-height: 1.3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
5652
5652
  .twc-opt__desc { font-size: var(--text-xs); color: var(--color-text-muted); line-height: 1.3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
5653
+ /* #300: wrapOptions \u2014 let long labels/descriptions wrap onto multiple lines instead of truncating.
5654
+ overflow-wrap: anywhere also breaks a single very long token so it can't overflow the popover edge. */
5655
+ .twc-opt[data-wrap="true"] { align-items: flex-start; }
5656
+ .twc-opt[data-wrap="true"] .twc-opt__label, .twc-opt[data-wrap="true"] .twc-opt__desc { overflow: visible; text-overflow: clip; white-space: normal; overflow-wrap: anywhere; }
5653
5657
  .twc-opt__check { flex: none; color: var(--color-primary); display: inline-flex; }
5654
5658
  .twc-opt__check svg { width: 16px; height: 16px; }
5655
5659
  .twc-pop__empty { padding: 14px 12px; text-align: center; font-size: var(--text-sm); color: var(--color-text-subtle); }
@@ -5710,8 +5714,9 @@ function Combobox({
5710
5714
  loading = false,
5711
5715
  emptyText = "No results found",
5712
5716
  name,
5713
- virtualized = false,
5717
+ virtualized: virtualizedProp = false,
5714
5718
  overscan = 8,
5719
+ wrapOptions = false,
5715
5720
  id,
5716
5721
  className = "",
5717
5722
  onFocus,
@@ -5719,6 +5724,8 @@ function Combobox({
5719
5724
  ...rest
5720
5725
  }) {
5721
5726
  const __twcStyles = useScopedStyles("twc-combo-styles", COMBO_CSS);
5727
+ if (virtualizedProp && wrapOptions) warnOnce("combobox-wrap-virtualized", "twico-ui Combobox: `wrapOptions` disables `virtualized` \u2014 wrapped option rows aren't a fixed height.");
5728
+ const virtualized = virtualizedProp && !wrapOptions;
5722
5729
  const groups = React51__default.useMemo(() => normalizeGroups(options), [options]);
5723
5730
  const flat = React51__default.useMemo(() => groups.flatMap((g) => g.options), [groups]);
5724
5731
  const autoId = React51__default.useId();
@@ -5905,6 +5912,7 @@ function Combobox({
5905
5912
  "data-disabled": o.disabled || void 0,
5906
5913
  "data-selected": isSel || void 0,
5907
5914
  "data-active": idx === active || void 0,
5915
+ "data-wrap": wrapOptions || void 0,
5908
5916
  onMouseEnter: () => {
5909
5917
  if (!o.disabled) setActive(idx);
5910
5918
  },
@@ -8531,6 +8539,13 @@ th.twc-dt__rownum .twc-dt__th-inner { padding-inline: 8px; gap: 2px; justify-con
8531
8539
  .twc-dt__panel-count { font-weight: 600; color: var(--color-text-muted); text-transform: none; letter-spacing: 0; margin-inline-start: 6px; font-variant-numeric: tabular-nums; }
8532
8540
  .twc-dt__link { border: none; background: transparent; color: var(--color-primary); font-family: inherit; font-size: var(--text-xs); font-weight: 600; cursor: pointer; padding: 2px 4px; border-radius: var(--radius-sm); }
8533
8541
  .twc-dt__link:hover { background: var(--color-primary-subtle); }
8542
+ /* #303: AND/OR connective toggle (segmented pill) in the Filters panel head. */
8543
+ .twc-dt__flogic { display: inline-flex; border: var(--border-thin) solid var(--color-border); border-radius: var(--radius-md); overflow: hidden; }
8544
+ .twc-dt__flogic-btn { border: none; background: transparent; color: var(--color-text-muted); font-family: inherit; font-size: 10px; font-weight: 700; letter-spacing: var(--tracking-wide); cursor: pointer; padding: 2px 8px; }
8545
+ .twc-dt__flogic-btn + .twc-dt__flogic-btn { border-inline-start: var(--border-thin) solid var(--color-border); }
8546
+ .twc-dt__flogic-btn:hover { background: var(--color-surface-sunken); }
8547
+ .twc-dt__flogic-btn[data-active] { background: var(--color-primary); color: var(--color-primary-fg); }
8548
+ .twc-dt__flogic-btn[data-active]:hover { background: var(--color-primary); }
8534
8549
 
8535
8550
  /* Filter panel \u2014 user-resizable (#292): panel size + per-field widths resolve through a two-tier CSS var
8536
8551
  cascade \u2014 user drag (-usr) > #289 measured auto-fit (-fit) > 118px fallback \u2014 entirely in clamp(), so
@@ -8561,7 +8576,9 @@ th.twc-dt__rownum .twc-dt__th-inner { padding-inline: 8px; gap: 2px; justify-con
8561
8576
  /* value: the flex shock-absorber by default; the first drag flips it to a fixed width (data-val-fixed). */
8562
8577
  .twc-dt__f-val { position: relative; flex: 1 1 140px; min-width: 140px; }
8563
8578
  .twc-dt__filters[data-val-fixed] .twc-dt__f-val { flex: 0 0 clamp(140px, var(--twc-dt-fval-usr, 240px), 640px); }
8564
- .twc-dt__filters[data-val-fixed] .twc-dt__frm-x { margin-inline-start: auto; }
8579
+ /* #303: each row now has two .twc-dt__frm-x (the add-condition "+" then remove "x"); put the auto margin
8580
+ only on the first so the pair hugs the row end together (two auto margins would split the free space). */
8581
+ .twc-dt__filters[data-val-fixed] .twc-dt__frm-x:first-of-type { margin-inline-start: auto; }
8565
8582
  .twc-dt__frm-x { display: inline-grid; place-items: center; width: 30px; height: 38px; border: none; background: transparent; color: var(--color-text-subtle); border-radius: var(--radius-md); cursor: pointer; flex: none; align-self: flex-start; }
8566
8583
  .twc-dt__frm-x:hover { background: var(--color-danger-subtle); color: var(--color-danger-subtle-fg); }
8567
8584
  .twc-dt__frm-x svg { width: 15px; height: 15px; }
@@ -8581,6 +8598,13 @@ th.twc-dt__rownum .twc-dt__th-inner { padding-inline: 8px; gap: 2px; justify-con
8581
8598
  .twc-dt__f-rz { width: 16px; inset-inline-end: -6px; opacity: 0.4; }
8582
8599
  .twc-dt__pop-grip { width: 20px; height: 20px; opacity: 0.6; }
8583
8600
  }
8601
+ /* #304: generic resizable popovers. When the grip commits a size, the panel carries data-pop-sized +
8602
+ --twc-dt-pop-w/-h; the width override beats each panel default (incl. inline widths) and the inner
8603
+ scroll list drops its max-height and flexes to fill the taller panel. The panel keeps its base
8604
+ position: fixed (the absolute grip anchors to it) \u2014 do NOT set position here (see #294). Filters keep
8605
+ their own data-panel-sized system (untouched). */
8606
+ .twc-dt__pop[data-pop-sized] { display: flex; flex-direction: column; width: var(--twc-dt-pop-w) !important; height: var(--twc-dt-pop-h); max-width: calc(100vw - 32px); max-height: calc(100vh - 32px); }
8607
+ .twc-dt__pop[data-pop-sized] .twc-dt__col-list, .twc-dt__pop[data-pop-sized] .twc-dt__cfg-list, .twc-dt__pop[data-pop-sized] .twc-dt__pivot-body { max-height: none; flex: 1 1 auto; overflow-y: auto; }
8584
8608
  .twc-dt__empty { padding: 30px 12px; text-align: center; color: var(--color-text-subtle); font-size: var(--text-sm); }
8585
8609
 
8586
8610
  /* Action cell */
@@ -8810,9 +8834,10 @@ function runDatatableQuery(rows, query, options = {}) {
8810
8834
  let out = Array.isArray(rows) ? rows : [];
8811
8835
  const quick = String(q.quickFilter || "").trim().toLowerCase();
8812
8836
  if (quick) out = out.filter((r2) => searchFields.some((f) => String(gv(f, r2) ?? "").toLowerCase().includes(quick)));
8813
- for (const f of q.filters || []) {
8814
- const fc = cols.find((c) => c.field === f.field);
8815
- out = out.filter((r2) => testFilter(gv(f.field, r2), f.op, f.value, filterTypeOf(fc)));
8837
+ const qF = (q.filters || []).map((f) => [cols.find((c) => c.field === f.field), f]).filter(([fc]) => fc);
8838
+ if (qF.length) {
8839
+ if (q.filterLogic === "or") out = out.filter((r2) => qF.some(([fc, f]) => testFilter(gv(f.field, r2), f.op, f.value, filterTypeOf(fc))));
8840
+ else for (const [fc, f] of qF) out = out.filter((r2) => testFilter(gv(f.field, r2), f.op, f.value, filterTypeOf(fc)));
8816
8841
  }
8817
8842
  if (q.sort && q.sort.field) {
8818
8843
  const { field, dir } = q.sort, numeric = typeOf(field) === "number";
@@ -9134,6 +9159,7 @@ function Datatable({
9134
9159
  onQuickFilterChange,
9135
9160
  toolbarActions,
9136
9161
  resizableFilters = true,
9162
+ resizablePopovers = false,
9137
9163
  filterFieldMaxWidth,
9138
9164
  rowPinning = false,
9139
9165
  rowReorder = false,
@@ -9223,6 +9249,7 @@ function Datatable({
9223
9249
  });
9224
9250
  const [sort, setSort] = React51__default.useState(null);
9225
9251
  const [filters, setFilters] = React51__default.useState([]);
9252
+ const [filterLogic, setFilterLogic] = React51__default.useState("and");
9226
9253
  const [hidden, setHidden] = React51__default.useState(() => /* @__PURE__ */ new Set());
9227
9254
  const [showRowNum, setShowRowNum] = React51__default.useState(rowNumbers);
9228
9255
  const [wrapped, setWrapped] = React51__default.useState(() => new Set((columns || []).filter((c) => c.wrapText).map((c) => c.field)));
@@ -9288,9 +9315,12 @@ function Datatable({
9288
9315
  const rowFocusRef = React51__default.useRef(null);
9289
9316
  const [fWidths, setFWidths] = React51__default.useState({});
9290
9317
  const [fPanelSize, setFPanelSize] = React51__default.useState(null);
9318
+ const [popSizes, setPopSizes] = React51__default.useState({});
9291
9319
  const serializeState = () => ({
9292
9320
  filters: filters.map(({ id, ...f }) => f),
9293
9321
  // strip the internal row id
9322
+ filterLogic,
9323
+ // #303: "and" (default) | "or"
9294
9324
  sort,
9295
9325
  quickFilter: quick,
9296
9326
  page: pageVal,
@@ -9303,12 +9333,15 @@ function Datatable({
9303
9333
  density,
9304
9334
  // #292: additive, optional — user-resized filter panel + field widths (panel-global, not per column).
9305
9335
  filterPanelSize: fPanelSize || void 0,
9306
- filterFieldWidths: fWidths.col != null || fWidths.op != null || fWidths.val != null ? fWidths : void 0
9336
+ filterFieldWidths: fWidths.col != null || fWidths.op != null || fWidths.val != null ? fWidths : void 0,
9337
+ // #304: additive, optional — user-resized sizes of the other toolbar popovers, keyed by popover id.
9338
+ popoverSizes: Object.keys(popSizes).length ? popSizes : void 0
9307
9339
  });
9308
9340
  const applyState = (s) => {
9309
9341
  if (!s || typeof s !== "object") return;
9310
9342
  const known = new Set(cols.map((c) => c.field).filter(Boolean));
9311
9343
  if (Array.isArray(s.filters)) setFilters(s.filters.filter((f) => f && known.has(f.field)).map((f, i) => ({ id: Date.now() + Math.random() + i, field: f.field, op: f.op, value: f.value })));
9344
+ if (s.filterLogic === "or" || s.filterLogic === "and") setFilterLogic(s.filterLogic);
9312
9345
  if ("sort" in s) setSort(s.sort && known.has(s.sort.field) ? { field: s.sort.field, dir: s.sort.dir === "desc" ? "desc" : "asc" } : null);
9313
9346
  if (typeof s.quickFilter === "string" && quickFilter === void 0) setInternalQuick(s.quickFilter);
9314
9347
  if (typeof s.page === "number" && !pageControlled) setInternalPage(Math.max(0, Math.floor(s.page)));
@@ -9338,6 +9371,14 @@ function Datatable({
9338
9371
  const h = typeof s.filterPanelSize.h === "number" ? clampNum(s.filterPanelSize.h, 120, fMaxH()) : void 0;
9339
9372
  if (w != null || h != null) setFPanelSize({ ...w != null ? { w } : {}, ...h != null ? { h } : {} });
9340
9373
  }
9374
+ if (s.popoverSizes && typeof s.popoverSizes === "object") {
9375
+ const next = {};
9376
+ for (const [id, sz] of Object.entries(s.popoverSizes)) {
9377
+ if (!sz || typeof sz !== "object" || typeof sz.w !== "number" || typeof sz.h !== "number") continue;
9378
+ next[id] = { w: clampNum(sz.w, popMinW(id), fMaxW()), h: clampNum(sz.h, 120, fMaxH()) };
9379
+ }
9380
+ if (Object.keys(next).length) setPopSizes(next);
9381
+ }
9341
9382
  };
9342
9383
  const stateReadyRef = React51__default.useRef(false);
9343
9384
  const stateRestoredRef = React51__default.useRef(false);
@@ -9355,7 +9396,7 @@ function Datatable({
9355
9396
  }
9356
9397
  }
9357
9398
  return void 0;
9358
- }, [filters, sort, quick, pageVal, sizeVal, order, widths, hidden, pins, density, fWidths, fPanelSize, stateKey]);
9399
+ }, [filters, filterLogic, sort, quick, pageVal, sizeVal, order, widths, hidden, pins, density, fWidths, fPanelSize, popSizes, stateKey]);
9359
9400
  const restoreState = () => {
9360
9401
  let saved = null;
9361
9402
  if (stateKey) {
@@ -9622,24 +9663,26 @@ function Datatable({
9622
9663
  const CHK_W = checkboxSelection ? rowReorder ? 68 : 44 : 0;
9623
9664
  const numLeft = CHK_W;
9624
9665
  const leadW = numLeft + (showRowNum ? NUM_W : 0);
9666
+ const visLeft = React51__default.useMemo(() => pins.left.filter((f) => colByField[f] && !hidden.has(f)), [pins.left, colByField, hidden]);
9667
+ const visRight = React51__default.useMemo(() => pins.right.filter((f) => colByField[f] && !hidden.has(f)), [pins.right, colByField, hidden]);
9625
9668
  const stickyOf = (field) => {
9626
- if (pins.left.includes(field)) {
9669
+ if (visLeft.includes(field)) {
9627
9670
  let off = leadW;
9628
- for (const f of pins.left) {
9671
+ for (const f of visLeft) {
9629
9672
  if (f === field) break;
9630
9673
  off += widthOf(colByField[f] || {});
9631
9674
  }
9632
- const isEdge = pins.left[pins.left.length - 1] === field;
9675
+ const isEdge = visLeft[visLeft.length - 1] === field;
9633
9676
  return { style: { insetInlineStart: off }, pin: "left", edge: isEdge ? "left" : void 0 };
9634
9677
  }
9635
- if (pins.right.includes(field)) {
9678
+ if (visRight.includes(field)) {
9636
9679
  let off = 0;
9637
- const rev = [...pins.right].reverse();
9680
+ const rev = [...visRight].reverse();
9638
9681
  for (const f of rev) {
9639
9682
  if (f === field) break;
9640
9683
  off += widthOf(colByField[f] || {});
9641
9684
  }
9642
- const isEdge = pins.right[0] === field;
9685
+ const isEdge = visRight[0] === field;
9643
9686
  return { style: { insetInlineEnd: off }, pin: "right", edge: isEdge ? "right" : void 0 };
9644
9687
  }
9645
9688
  return {};
@@ -9658,10 +9701,13 @@ function Datatable({
9658
9701
  const searchCols = searchFields && searchFields.length ? searchFields.map((f) => colByField[f] || { field: f }) : visibleCols;
9659
9702
  out = out.filter((r2) => searchCols.some((c) => String(getColVal(c, r2) ?? "").toLowerCase().includes(q)));
9660
9703
  }
9661
- for (const f of filters) {
9662
- const col = colByField[f.field];
9663
- if (!col) continue;
9664
- out = out.filter((r2) => testFilter(getColVal(col, r2), f.op, f.value, filterTypeOf(col)));
9704
+ const activeF = filters.map((f) => [colByField[f.field], f]).filter(([col]) => col);
9705
+ if (activeF.length) {
9706
+ if (filterLogic === "or") {
9707
+ out = out.filter((r2) => activeF.some(([col, f]) => testFilter(getColVal(col, r2), f.op, f.value, filterTypeOf(col))));
9708
+ } else {
9709
+ for (const [col, f] of activeF) out = out.filter((r2) => testFilter(getColVal(col, r2), f.op, f.value, filterTypeOf(col)));
9710
+ }
9665
9711
  }
9666
9712
  if (sort) {
9667
9713
  const col = colByField[sort.field];
@@ -9678,7 +9724,7 @@ function Datatable({
9678
9724
  out = [...out].sort((a, b) => (idx.get(keyOf(a)) ?? 1e9) - (idx.get(keyOf(b)) ?? 1e9));
9679
9725
  }
9680
9726
  return out;
9681
- }, [rows, quick, filters, sort, visibleCols, colByField, serverMode, rowOrder, searchFields]);
9727
+ }, [rows, quick, filters, filterLogic, sort, visibleCols, colByField, serverMode, rowOrder, searchFields]);
9682
9728
  const paginated = pageSize > 0;
9683
9729
  const serverTotal = rowCount == null ? processed.length : rowCount;
9684
9730
  const totalRows = serverMode ? serverTotal : processed.length;
@@ -9953,6 +9999,8 @@ function Datatable({
9953
9999
  pageSize: sizeVal,
9954
10000
  sort,
9955
10001
  filters: filters.map(({ id, ...f }) => f),
10002
+ filterLogic,
10003
+ // #303: "and" (default) | "or" — the server groups its WHERE accordingly
9956
10004
  quickFilter: quick.trim(),
9957
10005
  visibleColumns,
9958
10006
  hiddenColumns
@@ -9960,7 +10008,7 @@ function Datatable({
9960
10008
  });
9961
10009
  }, 250);
9962
10010
  return () => clearTimeout(t);
9963
- }, [serverMode, pageVal, sizeVal, sort, filters, quick, visibleColumns, hiddenColumns]);
10011
+ }, [serverMode, pageVal, sizeVal, sort, filters, filterLogic, quick, visibleColumns, hiddenColumns]);
9964
10012
  const onColVisRef = React51__default.useRef(onColumnVisibilityChange);
9965
10013
  onColVisRef.current = onColumnVisibilityChange;
9966
10014
  const lastVisibleKey = React51__default.useRef(null);
@@ -10618,7 +10666,97 @@ function Datatable({
10618
10666
  }
10619
10667
  };
10620
10668
  const hasFilterSizeOverride = fWidths.col != null || fWidths.op != null || fWidths.val != null || fPanelSize != null;
10621
- const fieldHandle = (field, rowIdx) => resizableFilters && rowIdx === 0 ? /* @__PURE__ */ jsx(
10669
+ const POP_MIN_W = { columns: 240, agg: 240, pivot: 260, batchedit: 260 };
10670
+ const popMinW = (id) => POP_MIN_W[id] || 200;
10671
+ const clearPop = (id, node) => {
10672
+ if (node) {
10673
+ node.style.removeProperty("--twc-dt-pop-w");
10674
+ node.style.removeProperty("--twc-dt-pop-h");
10675
+ node.removeAttribute("data-pop-sized");
10676
+ }
10677
+ setPopSizes((s) => {
10678
+ if (!(id in s)) return s;
10679
+ const n = { ...s };
10680
+ delete n[id];
10681
+ return n;
10682
+ });
10683
+ };
10684
+ const startPopResize = (id) => (e) => {
10685
+ if (e.button != null && e.button !== 0) return;
10686
+ e.preventDefault();
10687
+ e.stopPropagation();
10688
+ const pop = e.currentTarget.closest(".twc-dt__pop");
10689
+ if (!pop) return;
10690
+ const grip = e.currentTarget;
10691
+ const startX = e.clientX, startY = e.clientY;
10692
+ const r2 = pop.getBoundingClientRect();
10693
+ const startW = r2.width, startH = r2.height;
10694
+ const dir = typeof getComputedStyle !== "undefined" && getComputedStyle(pop).direction === "rtl" ? -1 : 1;
10695
+ pop.style.setProperty("--twc-dt-pop-w", `${startW}px`);
10696
+ pop.style.setProperty("--twc-dt-pop-h", `${startH}px`);
10697
+ grip.setAttribute("data-active", "true");
10698
+ pop.setAttribute("data-pop-sized", "");
10699
+ let lw = startW, lh = startH;
10700
+ const onMove = (ev) => {
10701
+ lw = clampNum(startW + (ev.clientX - startX) * dir, popMinW(id), fMaxW());
10702
+ lh = clampNum(startH + (ev.clientY - startY), 120, fMaxH());
10703
+ pop.style.setProperty("--twc-dt-pop-w", `${lw}px`);
10704
+ pop.style.setProperty("--twc-dt-pop-h", `${lh}px`);
10705
+ };
10706
+ const onUp = () => {
10707
+ setPopSizes((s) => ({ ...s, [id]: { w: lw, h: lh } }));
10708
+ grip.removeAttribute("data-active");
10709
+ window.removeEventListener("pointermove", onMove);
10710
+ window.removeEventListener("pointerup", onUp);
10711
+ };
10712
+ window.addEventListener("pointermove", onMove);
10713
+ window.addEventListener("pointerup", onUp);
10714
+ };
10715
+ const onPopGripKey = (id) => (e) => {
10716
+ if (e.key === "Enter" || e.key === " " || e.key === "Backspace") {
10717
+ e.preventDefault();
10718
+ clearPop(id, e.currentTarget.closest(".twc-dt__pop"));
10719
+ return;
10720
+ }
10721
+ if (!["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "Home", "End"].includes(e.key)) return;
10722
+ e.preventDefault();
10723
+ const pop = e.currentTarget.closest(".twc-dt__pop");
10724
+ if (!pop) return;
10725
+ const r2 = pop.getBoundingClientRect();
10726
+ const step = e.shiftKey ? 4 : 20;
10727
+ const dir = typeof getComputedStyle !== "undefined" && getComputedStyle(pop).direction === "rtl" ? -1 : 1;
10728
+ let w = r2.width, h = r2.height;
10729
+ if (e.key === "ArrowRight") w += step * dir;
10730
+ else if (e.key === "ArrowLeft") w -= step * dir;
10731
+ else if (e.key === "ArrowDown") h += step;
10732
+ else if (e.key === "ArrowUp") h -= step;
10733
+ else if (e.key === "Home") {
10734
+ w = popMinW(id);
10735
+ h = 120;
10736
+ } else if (e.key === "End") {
10737
+ w = fMaxW();
10738
+ h = fMaxH();
10739
+ }
10740
+ setPopSizes((s) => ({ ...s, [id]: { w: clampNum(w, popMinW(id), fMaxW()), h: clampNum(h, 120, fMaxH()) } }));
10741
+ };
10742
+ const popStyle = (id) => popSizes[id] ? { "--twc-dt-pop-w": `${popSizes[id].w}px`, "--twc-dt-pop-h": `${popSizes[id].h}px` } : null;
10743
+ const popGrip = (id) => resizablePopovers ? /* @__PURE__ */ jsx(
10744
+ "span",
10745
+ {
10746
+ className: "twc-dt__pop-grip",
10747
+ role: "slider",
10748
+ tabIndex: 0,
10749
+ "aria-label": "Resize panel (Enter or double-click to reset)",
10750
+ "aria-valuetext": popSizes[id] ? `Width ${Math.round(popSizes[id].w)} pixels, height ${Math.round(popSizes[id].h)} pixels` : "Default size",
10751
+ onPointerDown: startPopResize(id),
10752
+ onKeyDown: onPopGripKey(id),
10753
+ onDoubleClick: (e) => {
10754
+ e.preventDefault();
10755
+ clearPop(id, e.currentTarget.closest(".twc-dt__pop"));
10756
+ }
10757
+ }
10758
+ ) : null;
10759
+ const fieldHandle = (field, rowIdx) => (resizableFilters || resizablePopovers) && rowIdx === 0 ? /* @__PURE__ */ jsx(
10622
10760
  "span",
10623
10761
  {
10624
10762
  className: "twc-dt__f-rz",
@@ -10740,7 +10878,7 @@ function Datatable({
10740
10878
  onDragEnd: reorderable ? () => setRowDrag({ from: null, over: null, after: false }) : void 0,
10741
10879
  onClick: (e) => handleRowClick(e, k, row),
10742
10880
  children: [
10743
- checkboxSelection ? /* @__PURE__ */ jsxs("td", { className: "twc-dt__td", role: "gridcell", "data-pin": "left", "data-pin-edge": pins.left.length || showRowNum ? void 0 : "left", style: { insetInlineStart: 0, width: CHK_W }, children: [
10881
+ checkboxSelection ? /* @__PURE__ */ jsxs("td", { className: "twc-dt__td", role: "gridcell", "data-pin": "left", "data-pin-edge": visLeft.length || showRowNum ? void 0 : "left", style: { insetInlineStart: 0, width: CHK_W }, children: [
10744
10882
  /* @__PURE__ */ jsxs("span", { style: { display: "inline-flex", alignItems: "center", gap: 4 }, children: [
10745
10883
  reorderable ? rowHandle(k, midIdx, row) : null,
10746
10884
  /* @__PURE__ */ jsx(
@@ -10765,7 +10903,7 @@ function Datatable({
10765
10903
  ] }),
10766
10904
  rowResize && !pinSide ? /* @__PURE__ */ jsx("span", { className: "twc-dt__row-resizer", title: "Drag to resize row", onPointerDown: (e) => startRowResize(e, k, e.currentTarget.closest("tr")), onClick: (e) => e.stopPropagation() }) : null
10767
10905
  ] }) : null,
10768
- showRowNum ? /* @__PURE__ */ jsx("td", { className: "twc-dt__td twc-dt__rownum", role: "gridcell", "aria-hidden": "true", "data-pin": "left", "data-pin-edge": pins.left.length ? void 0 : "left", style: { insetInlineStart: numLeft, width: NUM_W }, children: typeof ri === "number" ? (paginated || serverMode ? pageVal * sizeVal : 0) + ri + 1 : "" }) : null,
10906
+ showRowNum ? /* @__PURE__ */ jsx("td", { className: "twc-dt__td twc-dt__rownum", role: "gridcell", "aria-hidden": "true", "data-pin": "left", "data-pin-edge": visLeft.length ? void 0 : "left", style: { insetInlineStart: numLeft, width: NUM_W }, children: typeof ri === "number" ? (paginated || serverMode ? pageVal * sizeVal : 0) + ri + 1 : "" }) : null,
10769
10907
  ordered.map((c, ci) => {
10770
10908
  const st = stickyOf(c.field);
10771
10909
  const val = getColVal(c, row);
@@ -11175,7 +11313,7 @@ function Datatable({
11175
11313
  onKeyDown: onGridKeyDown,
11176
11314
  children: [
11177
11315
  /* @__PURE__ */ jsx("thead", { ref: theadRef, children: /* @__PURE__ */ jsxs("tr", { role: "row", "aria-rowindex": 1, children: [
11178
- checkboxSelection ? /* @__PURE__ */ jsx("th", { className: "twc-dt__th", role: "columnheader", "aria-label": "Select", "data-pin": "left", "data-pin-edge": pins.left.length || showRowNum ? void 0 : "left", style: { insetInlineStart: 0, width: CHK_W, minWidth: CHK_W }, children: /* @__PURE__ */ jsx("div", { className: "twc-dt__th-inner", style: { justifyContent: "center", padding: 0 }, children: /* @__PURE__ */ jsx(
11316
+ checkboxSelection ? /* @__PURE__ */ jsx("th", { className: "twc-dt__th", role: "columnheader", "aria-label": "Select", "data-pin": "left", "data-pin-edge": visLeft.length || showRowNum ? void 0 : "left", style: { insetInlineStart: 0, width: CHK_W, minWidth: CHK_W }, children: /* @__PURE__ */ jsx("div", { className: "twc-dt__th-inner", style: { justifyContent: "center", padding: 0 }, children: /* @__PURE__ */ jsx(
11179
11317
  "span",
11180
11318
  {
11181
11319
  className: "twc-dt__check",
@@ -11195,7 +11333,7 @@ function Datatable({
11195
11333
  children: /* @__PURE__ */ jsx(Svg, { d: allSel ? I.check : I.minus })
11196
11334
  }
11197
11335
  ) }) }) : null,
11198
- showRowNum ? /* @__PURE__ */ jsx("th", { className: "twc-dt__th twc-dt__rownum", role: "columnheader", "aria-label": "Row number", "data-pin": "left", "data-pin-edge": pins.left.length ? void 0 : "left", style: { insetInlineStart: numLeft, width: NUM_W, minWidth: NUM_W }, children: /* @__PURE__ */ jsxs("div", { className: "twc-dt__th-inner", children: [
11336
+ showRowNum ? /* @__PURE__ */ jsx("th", { className: "twc-dt__th twc-dt__rownum", role: "columnheader", "aria-label": "Row number", "data-pin": "left", "data-pin-edge": visLeft.length ? void 0 : "left", style: { insetInlineStart: numLeft, width: NUM_W, minWidth: NUM_W }, children: /* @__PURE__ */ jsxs("div", { className: "twc-dt__th-inner", children: [
11199
11337
  /* @__PURE__ */ jsx("span", { className: "twc-dt__th-label", style: { flex: "none", cursor: "default" }, children: "#" }),
11200
11338
  /* @__PURE__ */ jsx(
11201
11339
  "button",
@@ -11373,8 +11511,8 @@ function Datatable({
11373
11511
  pinnedBottomRows.map((row) => renderLeaf(row, keyIndex.get(keyOf(row)), "bottom"))
11374
11512
  ] }) }),
11375
11513
  hasAggregation && aggOn && !loading && paged.length > 0 ? /* @__PURE__ */ jsx("tfoot", { children: /* @__PURE__ */ jsxs("tr", { role: "row", children: [
11376
- checkboxSelection ? /* @__PURE__ */ jsx("td", { role: "gridcell", "data-pin": "left", "data-pin-edge": pins.left.length || showRowNum ? void 0 : "left", style: { insetInlineStart: 0, width: CHK_W } }) : null,
11377
- showRowNum ? /* @__PURE__ */ jsx("td", { className: "twc-dt__rownum", role: "gridcell", "aria-hidden": "true", "data-pin": "left", "data-pin-edge": pins.left.length ? void 0 : "left", style: { insetInlineStart: numLeft, width: NUM_W } }) : null,
11514
+ checkboxSelection ? /* @__PURE__ */ jsx("td", { role: "gridcell", "data-pin": "left", "data-pin-edge": visLeft.length || showRowNum ? void 0 : "left", style: { insetInlineStart: 0, width: CHK_W } }) : null,
11515
+ showRowNum ? /* @__PURE__ */ jsx("td", { className: "twc-dt__rownum", role: "gridcell", "aria-hidden": "true", "data-pin": "left", "data-pin-edge": visLeft.length ? void 0 : "left", style: { insetInlineStart: numLeft, width: NUM_W } }) : null,
11378
11516
  ordered.map((c) => {
11379
11517
  const st = stickyOf(c.field);
11380
11518
  const v = aggregate(c);
@@ -11473,7 +11611,7 @@ function Datatable({
11473
11611
  delete values[f];
11474
11612
  return { ...b, fields, values };
11475
11613
  });
11476
- return /* @__PURE__ */ jsxs("div", { className: "twc-dt__pop twc-dt__cfg", style: { top: batchEditPos.top, left: batchEditPos.left, width: 320 }, children: [
11614
+ return /* @__PURE__ */ jsxs("div", { className: "twc-dt__pop twc-dt__cfg", style: { top: batchEditPos.top, left: batchEditPos.left, width: 320, ...popStyle("batchedit") }, "data-pop-sized": popSizes.batchedit ? "" : void 0, children: [
11477
11615
  /* @__PURE__ */ jsx(Caret, { pos: batchEditPos }),
11478
11616
  /* @__PURE__ */ jsxs("div", { className: "twc-dt__cfg-head", children: [
11479
11617
  "Edit ",
@@ -11535,7 +11673,8 @@ function Datatable({
11535
11673
  "Apply to ",
11536
11674
  selected.size
11537
11675
  ] })
11538
- ] })
11676
+ ] }),
11677
+ popGrip("batchedit")
11539
11678
  ] });
11540
11679
  })() : null,
11541
11680
  colMenu && menuPos ? /* @__PURE__ */ jsxs(
@@ -11708,7 +11847,7 @@ function Datatable({
11708
11847
  ]
11709
11848
  }
11710
11849
  ) : null,
11711
- panel === "columns" && panelPos ? /* @__PURE__ */ jsxs("div", { className: "twc-dt__pop twc-dt__cols", style: { top: panelPos.top, left: panelPos.left }, role: "dialog", "aria-label": "Column settings", children: [
11850
+ panel === "columns" && panelPos ? /* @__PURE__ */ jsxs("div", { className: "twc-dt__pop twc-dt__cols", style: { top: panelPos.top, left: panelPos.left, ...popStyle("columns") }, "data-pop-sized": popSizes.columns ? "" : void 0, role: "dialog", "aria-label": "Column settings", children: [
11712
11851
  /* @__PURE__ */ jsxs("div", { className: "twc-dt__panel-head", children: [
11713
11852
  /* @__PURE__ */ jsxs("span", { className: "twc-dt__panel-title", children: [
11714
11853
  "Columns ",
@@ -11833,9 +11972,10 @@ function Datatable({
11833
11972
  c.field
11834
11973
  );
11835
11974
  })
11836
- ] })
11975
+ ] }),
11976
+ popGrip("columns")
11837
11977
  ] }) : null,
11838
- panel === "agg" && panelPos ? /* @__PURE__ */ jsxs("div", { className: "twc-dt__pop twc-dt__cfg", style: { top: panelPos.top, left: panelPos.left, width: 300 }, role: "dialog", "aria-label": "Aggregation settings", children: [
11978
+ panel === "agg" && panelPos ? /* @__PURE__ */ jsxs("div", { className: "twc-dt__pop twc-dt__cfg", style: { top: panelPos.top, left: panelPos.left, width: 300, ...popStyle("agg") }, "data-pop-sized": popSizes.agg ? "" : void 0, role: "dialog", "aria-label": "Aggregation settings", children: [
11839
11979
  /* @__PURE__ */ jsxs("div", { className: "twc-dt__panel-head", children: [
11840
11980
  /* @__PURE__ */ jsx("span", { className: "twc-dt__panel-title", children: "Aggregation" }),
11841
11981
  /* @__PURE__ */ jsx("button", { type: "button", className: "twc-dt__link", onClick: () => setAggConfig({}), children: "Clear" })
@@ -11884,13 +12024,14 @@ function Datatable({
11884
12024
  }
11885
12025
  ) })
11886
12026
  ] }, c.field);
11887
- }) })
12027
+ }) }),
12028
+ popGrip("agg")
11888
12029
  ] }) : null,
11889
12030
  panel === "pivot" && panelPos ? (() => {
11890
12031
  const fieldOpts = ordered.filter((c) => c.type !== "actions").map((c) => ({ value: c.field, label: c.headerName }));
11891
12032
  const aggOpts = [{ value: "sum", label: "Sum" }, { value: "avg", label: "Avg" }, { value: "min", label: "Min" }, { value: "max", label: "Max" }, { value: "count", label: "Count" }];
11892
12033
  const valueFieldOpts = ordered.filter((c) => c.type !== "actions" && !pivotConfig.values.some((v) => v.field === c.field)).map((c) => ({ value: c.field, label: c.headerName }));
11893
- return /* @__PURE__ */ jsxs("div", { className: "twc-dt__pop twc-dt__cfg", style: { top: panelPos.top, left: panelPos.left, width: 320 }, role: "dialog", "aria-label": "Pivot settings", children: [
12034
+ return /* @__PURE__ */ jsxs("div", { className: "twc-dt__pop twc-dt__cfg", style: { top: panelPos.top, left: panelPos.left, width: 320, ...popStyle("pivot") }, "data-pop-sized": popSizes.pivot ? "" : void 0, role: "dialog", "aria-label": "Pivot settings", children: [
11894
12035
  /* @__PURE__ */ jsxs("div", { className: "twc-dt__panel-head", children: [
11895
12036
  /* @__PURE__ */ jsx("span", { className: "twc-dt__panel-title", children: "Pivot" }),
11896
12037
  /* @__PURE__ */ jsx("button", { type: "button", className: "twc-dt__link", onClick: () => {
@@ -11898,106 +12039,109 @@ function Datatable({
11898
12039
  setPivotOn(false);
11899
12040
  }, children: "Reset" })
11900
12041
  ] }),
11901
- /* @__PURE__ */ jsxs("div", { className: "twc-dt__cfg-toggle", children: [
11902
- /* @__PURE__ */ jsx("span", { children: "Pivot mode" }),
11903
- /* @__PURE__ */ jsx(
11904
- "span",
11905
- {
11906
- className: "twc-dt__sw",
11907
- "data-on": pivotOn || void 0,
11908
- role: "switch",
11909
- "aria-checked": pivotOn,
11910
- tabIndex: 0,
11911
- onClick: () => setPivotOn((v) => !v),
11912
- onKeyDown: (e) => {
11913
- if (e.key === "Enter" || e.key === " ") {
11914
- e.preventDefault();
11915
- setPivotOn((v) => !v);
12042
+ /* @__PURE__ */ jsxs("div", { className: "twc-dt__pivot-body", children: [
12043
+ /* @__PURE__ */ jsxs("div", { className: "twc-dt__cfg-toggle", children: [
12044
+ /* @__PURE__ */ jsx("span", { children: "Pivot mode" }),
12045
+ /* @__PURE__ */ jsx(
12046
+ "span",
12047
+ {
12048
+ className: "twc-dt__sw",
12049
+ "data-on": pivotOn || void 0,
12050
+ role: "switch",
12051
+ "aria-checked": pivotOn,
12052
+ tabIndex: 0,
12053
+ onClick: () => setPivotOn((v) => !v),
12054
+ onKeyDown: (e) => {
12055
+ if (e.key === "Enter" || e.key === " ") {
12056
+ e.preventDefault();
12057
+ setPivotOn((v) => !v);
12058
+ }
11916
12059
  }
11917
12060
  }
11918
- }
11919
- )
11920
- ] }),
11921
- !pivotActive && pivotOn ? /* @__PURE__ */ jsxs("div", { className: "twc-dt__cfg-hint", children: [
11922
- "Add at least one ",
11923
- /* @__PURE__ */ jsx("b", { children: "Row" }),
11924
- " field and one ",
11925
- /* @__PURE__ */ jsx("b", { children: "Value" }),
11926
- " to see the pivot."
11927
- ] }) : null,
11928
- /* @__PURE__ */ jsxs("div", { className: "twc-dt__cfg-section", children: [
11929
- /* @__PURE__ */ jsx("span", { className: "twc-dt__cfg-label", children: "Rows" }),
11930
- /* @__PURE__ */ jsx(
11931
- MultiSelect,
11932
- {
11933
- portal: true,
11934
- placeholder: "Add row fields\u2026",
11935
- value: pivotConfig.rows,
11936
- options: fieldOpts,
11937
- onChange: (vals) => {
11938
- setPivotConfig((p) => ({ ...p, rows: vals }));
11939
- if (vals.length) setPivotOn(true);
11940
- }
11941
- }
11942
- )
11943
- ] }),
11944
- /* @__PURE__ */ jsxs("div", { className: "twc-dt__cfg-section", children: [
11945
- /* @__PURE__ */ jsx("span", { className: "twc-dt__cfg-label", children: "Columns" }),
11946
- /* @__PURE__ */ jsx(
11947
- MultiSelect,
11948
- {
11949
- portal: true,
11950
- placeholder: "Add column fields\u2026",
11951
- value: pivotConfig.columns,
11952
- options: fieldOpts,
11953
- onChange: (vals) => setPivotConfig((p) => ({ ...p, columns: vals }))
11954
- }
11955
- )
11956
- ] }),
11957
- /* @__PURE__ */ jsxs("div", { className: "twc-dt__cfg-section", children: [
11958
- /* @__PURE__ */ jsx("span", { className: "twc-dt__cfg-label", children: "Values" }),
11959
- pivotConfig.values.map((v, i) => /* @__PURE__ */ jsxs("div", { className: "twc-dt__cfg-row", children: [
11960
- /* @__PURE__ */ jsx("span", { className: "twc-dt__cfg-name", children: colByField[v.field]?.headerName || v.field }),
11961
- /* @__PURE__ */ jsx("div", { className: "twc-dt__cfg-ctl", children: /* @__PURE__ */ jsx(
11962
- Select,
12061
+ )
12062
+ ] }),
12063
+ !pivotActive && pivotOn ? /* @__PURE__ */ jsxs("div", { className: "twc-dt__cfg-hint", children: [
12064
+ "Add at least one ",
12065
+ /* @__PURE__ */ jsx("b", { children: "Row" }),
12066
+ " field and one ",
12067
+ /* @__PURE__ */ jsx("b", { children: "Value" }),
12068
+ " to see the pivot."
12069
+ ] }) : null,
12070
+ /* @__PURE__ */ jsxs("div", { className: "twc-dt__cfg-section", children: [
12071
+ /* @__PURE__ */ jsx("span", { className: "twc-dt__cfg-label", children: "Rows" }),
12072
+ /* @__PURE__ */ jsx(
12073
+ MultiSelect,
11963
12074
  {
11964
- size: "sm",
11965
- value: v.agg || "sum",
11966
- options: aggOpts,
11967
12075
  portal: true,
11968
- onChange: (a) => setPivotConfig((p) => ({ ...p, values: p.values.map((x, j) => j === i ? { ...x, agg: a } : x) }))
12076
+ placeholder: "Add row fields\u2026",
12077
+ value: pivotConfig.rows,
12078
+ options: fieldOpts,
12079
+ onChange: (vals) => {
12080
+ setPivotConfig((p) => ({ ...p, rows: vals }));
12081
+ if (vals.length) setPivotOn(true);
12082
+ }
11969
12083
  }
11970
- ) }),
12084
+ )
12085
+ ] }),
12086
+ /* @__PURE__ */ jsxs("div", { className: "twc-dt__cfg-section", children: [
12087
+ /* @__PURE__ */ jsx("span", { className: "twc-dt__cfg-label", children: "Columns" }),
11971
12088
  /* @__PURE__ */ jsx(
11972
- "button",
12089
+ MultiSelect,
11973
12090
  {
11974
- type: "button",
11975
- className: "twc-dt__cfg-x",
11976
- "aria-label": `Remove ${colByField[v.field]?.headerName || v.field}`,
11977
- onClick: () => setPivotConfig((p) => ({ ...p, values: p.values.filter((_, j) => j !== i) })),
11978
- children: /* @__PURE__ */ jsx(Svg, { d: I.x })
12091
+ portal: true,
12092
+ placeholder: "Add column fields\u2026",
12093
+ value: pivotConfig.columns,
12094
+ options: fieldOpts,
12095
+ onChange: (vals) => setPivotConfig((p) => ({ ...p, columns: vals }))
11979
12096
  }
11980
12097
  )
11981
- ] }, v.field + i)),
11982
- valueFieldOpts.length ? /* @__PURE__ */ jsx("div", { className: "twc-dt__cfg-add", children: /* @__PURE__ */ jsx(
11983
- Select,
11984
- {
11985
- size: "sm",
11986
- placeholder: "Add value field\u2026",
11987
- value: "",
11988
- options: valueFieldOpts,
11989
- portal: true,
11990
- searchable: true,
11991
- searchPlaceholder: "Search fields\u2026",
11992
- onChange: (f) => {
11993
- if (f) {
11994
- setPivotConfig((p) => p.values.some((x) => x.field === f) ? p : { ...p, values: [...p.values, { field: f, agg: "sum" }] });
11995
- setPivotOn(true);
12098
+ ] }),
12099
+ /* @__PURE__ */ jsxs("div", { className: "twc-dt__cfg-section", children: [
12100
+ /* @__PURE__ */ jsx("span", { className: "twc-dt__cfg-label", children: "Values" }),
12101
+ pivotConfig.values.map((v, i) => /* @__PURE__ */ jsxs("div", { className: "twc-dt__cfg-row", children: [
12102
+ /* @__PURE__ */ jsx("span", { className: "twc-dt__cfg-name", children: colByField[v.field]?.headerName || v.field }),
12103
+ /* @__PURE__ */ jsx("div", { className: "twc-dt__cfg-ctl", children: /* @__PURE__ */ jsx(
12104
+ Select,
12105
+ {
12106
+ size: "sm",
12107
+ value: v.agg || "sum",
12108
+ options: aggOpts,
12109
+ portal: true,
12110
+ onChange: (a) => setPivotConfig((p) => ({ ...p, values: p.values.map((x, j) => j === i ? { ...x, agg: a } : x) }))
12111
+ }
12112
+ ) }),
12113
+ /* @__PURE__ */ jsx(
12114
+ "button",
12115
+ {
12116
+ type: "button",
12117
+ className: "twc-dt__cfg-x",
12118
+ "aria-label": `Remove ${colByField[v.field]?.headerName || v.field}`,
12119
+ onClick: () => setPivotConfig((p) => ({ ...p, values: p.values.filter((_, j) => j !== i) })),
12120
+ children: /* @__PURE__ */ jsx(Svg, { d: I.x })
12121
+ }
12122
+ )
12123
+ ] }, v.field + i)),
12124
+ valueFieldOpts.length ? /* @__PURE__ */ jsx("div", { className: "twc-dt__cfg-add", children: /* @__PURE__ */ jsx(
12125
+ Select,
12126
+ {
12127
+ size: "sm",
12128
+ placeholder: "Add value field\u2026",
12129
+ value: "",
12130
+ options: valueFieldOpts,
12131
+ portal: true,
12132
+ searchable: true,
12133
+ searchPlaceholder: "Search fields\u2026",
12134
+ onChange: (f) => {
12135
+ if (f) {
12136
+ setPivotConfig((p) => p.values.some((x) => x.field === f) ? p : { ...p, values: [...p.values, { field: f, agg: "sum" }] });
12137
+ setPivotOn(true);
12138
+ }
11996
12139
  }
11997
12140
  }
11998
- }
11999
- ) }) : null
12000
- ] })
12141
+ ) }) : null
12142
+ ] })
12143
+ ] }),
12144
+ popGrip("pivot")
12001
12145
  ] });
12002
12146
  })() : null,
12003
12147
  panel === "filters" && panelPos ? /* @__PURE__ */ jsxs(
@@ -12021,8 +12165,12 @@ function Datatable({
12021
12165
  children: [
12022
12166
  /* @__PURE__ */ jsxs("div", { className: "twc-dt__panel-head", children: [
12023
12167
  /* @__PURE__ */ jsx("span", { className: "twc-dt__panel-title", children: "Filters" }),
12024
- /* @__PURE__ */ jsxs("span", { style: { display: "inline-flex", gap: 2 }, children: [
12025
- resizableFilters && hasFilterSizeOverride ? /* @__PURE__ */ jsx("button", { type: "button", className: "twc-dt__link", onClick: resetFilterSizes, children: "Reset sizes" }) : null,
12168
+ /* @__PURE__ */ jsxs("span", { style: { display: "inline-flex", alignItems: "center", gap: 6 }, children: [
12169
+ filters.length > 1 ? /* @__PURE__ */ jsxs("span", { className: "twc-dt__flogic", role: "group", "aria-label": "Combine filters with", children: [
12170
+ /* @__PURE__ */ jsx("button", { type: "button", className: "twc-dt__flogic-btn", "data-active": filterLogic === "and" || void 0, "aria-pressed": filterLogic === "and", onClick: () => setFilterLogic("and"), children: "AND" }),
12171
+ /* @__PURE__ */ jsx("button", { type: "button", className: "twc-dt__flogic-btn", "data-active": filterLogic === "or" || void 0, "aria-pressed": filterLogic === "or", onClick: () => setFilterLogic("or"), children: "OR" })
12172
+ ] }) : null,
12173
+ (resizableFilters || resizablePopovers) && hasFilterSizeOverride ? /* @__PURE__ */ jsx("button", { type: "button", className: "twc-dt__link", onClick: resetFilterSizes, children: "Reset sizes" }) : null,
12026
12174
  filters.length ? /* @__PURE__ */ jsx("button", { type: "button", className: "twc-dt__link", onClick: () => setFilters([]), children: "Clear all" }) : null
12027
12175
  ] })
12028
12176
  ] }),
@@ -12094,6 +12242,7 @@ function Datatable({
12094
12242
  ),
12095
12243
  fieldHandle("val", i)
12096
12244
  ] }),
12245
+ /* @__PURE__ */ jsx("button", { type: "button", className: "twc-dt__frm-x", "aria-label": `Add another condition on ${col.headerName}`, title: "Add another condition on this column", onClick: () => addFilter(f.field), children: /* @__PURE__ */ jsx(Svg, { d: I.plus }) }),
12097
12246
  /* @__PURE__ */ jsx("button", { type: "button", className: "twc-dt__frm-x", "aria-label": "Remove filter", onClick: () => setFilters((arr) => arr.filter((x) => x.id !== f.id)), children: /* @__PURE__ */ jsx(Svg, { d: I.x }) })
12098
12247
  ] }, f.id);
12099
12248
  }) }),
@@ -12101,7 +12250,7 @@ function Datatable({
12101
12250
  /* @__PURE__ */ jsx(Svg, { d: I.plus, style: { color: "var(--color-primary)" } }),
12102
12251
  " Add filter"
12103
12252
  ] }) }),
12104
- resizableFilters ? /* @__PURE__ */ jsx(
12253
+ resizableFilters || resizablePopovers ? /* @__PURE__ */ jsx(
12105
12254
  "span",
12106
12255
  {
12107
12256
  className: "twc-dt__pop-grip",