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.cjs CHANGED
@@ -5671,6 +5671,10 @@ var COMBO_CSS = `
5671
5671
  .twc-opt__main { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
5672
5672
  .twc-opt__label { line-height: 1.3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
5673
5673
  .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; }
5674
+ /* #300: wrapOptions \u2014 let long labels/descriptions wrap onto multiple lines instead of truncating.
5675
+ overflow-wrap: anywhere also breaks a single very long token so it can't overflow the popover edge. */
5676
+ .twc-opt[data-wrap="true"] { align-items: flex-start; }
5677
+ .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; }
5674
5678
  .twc-opt__check { flex: none; color: var(--color-primary); display: inline-flex; }
5675
5679
  .twc-opt__check svg { width: 16px; height: 16px; }
5676
5680
  .twc-pop__empty { padding: 14px 12px; text-align: center; font-size: var(--text-sm); color: var(--color-text-subtle); }
@@ -5731,8 +5735,9 @@ function Combobox({
5731
5735
  loading = false,
5732
5736
  emptyText = "No results found",
5733
5737
  name,
5734
- virtualized = false,
5738
+ virtualized: virtualizedProp = false,
5735
5739
  overscan = 8,
5740
+ wrapOptions = false,
5736
5741
  id,
5737
5742
  className = "",
5738
5743
  onFocus,
@@ -5740,6 +5745,8 @@ function Combobox({
5740
5745
  ...rest
5741
5746
  }) {
5742
5747
  const __twcStyles = useScopedStyles("twc-combo-styles", COMBO_CSS);
5748
+ if (virtualizedProp && wrapOptions) warnOnce("combobox-wrap-virtualized", "twico-ui Combobox: `wrapOptions` disables `virtualized` \u2014 wrapped option rows aren't a fixed height.");
5749
+ const virtualized = virtualizedProp && !wrapOptions;
5743
5750
  const groups = React51__namespace.default.useMemo(() => normalizeGroups(options), [options]);
5744
5751
  const flat = React51__namespace.default.useMemo(() => groups.flatMap((g) => g.options), [groups]);
5745
5752
  const autoId = React51__namespace.default.useId();
@@ -5926,6 +5933,7 @@ function Combobox({
5926
5933
  "data-disabled": o.disabled || void 0,
5927
5934
  "data-selected": isSel || void 0,
5928
5935
  "data-active": idx === active || void 0,
5936
+ "data-wrap": wrapOptions || void 0,
5929
5937
  onMouseEnter: () => {
5930
5938
  if (!o.disabled) setActive(idx);
5931
5939
  },
@@ -8552,6 +8560,13 @@ th.twc-dt__rownum .twc-dt__th-inner { padding-inline: 8px; gap: 2px; justify-con
8552
8560
  .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; }
8553
8561
  .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); }
8554
8562
  .twc-dt__link:hover { background: var(--color-primary-subtle); }
8563
+ /* #303: AND/OR connective toggle (segmented pill) in the Filters panel head. */
8564
+ .twc-dt__flogic { display: inline-flex; border: var(--border-thin) solid var(--color-border); border-radius: var(--radius-md); overflow: hidden; }
8565
+ .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; }
8566
+ .twc-dt__flogic-btn + .twc-dt__flogic-btn { border-inline-start: var(--border-thin) solid var(--color-border); }
8567
+ .twc-dt__flogic-btn:hover { background: var(--color-surface-sunken); }
8568
+ .twc-dt__flogic-btn[data-active] { background: var(--color-primary); color: var(--color-primary-fg); }
8569
+ .twc-dt__flogic-btn[data-active]:hover { background: var(--color-primary); }
8555
8570
 
8556
8571
  /* Filter panel \u2014 user-resizable (#292): panel size + per-field widths resolve through a two-tier CSS var
8557
8572
  cascade \u2014 user drag (-usr) > #289 measured auto-fit (-fit) > 118px fallback \u2014 entirely in clamp(), so
@@ -8582,7 +8597,9 @@ th.twc-dt__rownum .twc-dt__th-inner { padding-inline: 8px; gap: 2px; justify-con
8582
8597
  /* value: the flex shock-absorber by default; the first drag flips it to a fixed width (data-val-fixed). */
8583
8598
  .twc-dt__f-val { position: relative; flex: 1 1 140px; min-width: 140px; }
8584
8599
  .twc-dt__filters[data-val-fixed] .twc-dt__f-val { flex: 0 0 clamp(140px, var(--twc-dt-fval-usr, 240px), 640px); }
8585
- .twc-dt__filters[data-val-fixed] .twc-dt__frm-x { margin-inline-start: auto; }
8600
+ /* #303: each row now has two .twc-dt__frm-x (the add-condition "+" then remove "x"); put the auto margin
8601
+ only on the first so the pair hugs the row end together (two auto margins would split the free space). */
8602
+ .twc-dt__filters[data-val-fixed] .twc-dt__frm-x:first-of-type { margin-inline-start: auto; }
8586
8603
  .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; }
8587
8604
  .twc-dt__frm-x:hover { background: var(--color-danger-subtle); color: var(--color-danger-subtle-fg); }
8588
8605
  .twc-dt__frm-x svg { width: 15px; height: 15px; }
@@ -8602,6 +8619,13 @@ th.twc-dt__rownum .twc-dt__th-inner { padding-inline: 8px; gap: 2px; justify-con
8602
8619
  .twc-dt__f-rz { width: 16px; inset-inline-end: -6px; opacity: 0.4; }
8603
8620
  .twc-dt__pop-grip { width: 20px; height: 20px; opacity: 0.6; }
8604
8621
  }
8622
+ /* #304: generic resizable popovers. When the grip commits a size, the panel carries data-pop-sized +
8623
+ --twc-dt-pop-w/-h; the width override beats each panel default (incl. inline widths) and the inner
8624
+ scroll list drops its max-height and flexes to fill the taller panel. The panel keeps its base
8625
+ position: fixed (the absolute grip anchors to it) \u2014 do NOT set position here (see #294). Filters keep
8626
+ their own data-panel-sized system (untouched). */
8627
+ .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); }
8628
+ .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; }
8605
8629
  .twc-dt__empty { padding: 30px 12px; text-align: center; color: var(--color-text-subtle); font-size: var(--text-sm); }
8606
8630
 
8607
8631
  /* Action cell */
@@ -8831,9 +8855,10 @@ function runDatatableQuery(rows, query, options = {}) {
8831
8855
  let out = Array.isArray(rows) ? rows : [];
8832
8856
  const quick = String(q.quickFilter || "").trim().toLowerCase();
8833
8857
  if (quick) out = out.filter((r2) => searchFields.some((f) => String(gv(f, r2) ?? "").toLowerCase().includes(quick)));
8834
- for (const f of q.filters || []) {
8835
- const fc = cols.find((c) => c.field === f.field);
8836
- out = out.filter((r2) => testFilter(gv(f.field, r2), f.op, f.value, filterTypeOf(fc)));
8858
+ const qF = (q.filters || []).map((f) => [cols.find((c) => c.field === f.field), f]).filter(([fc]) => fc);
8859
+ if (qF.length) {
8860
+ if (q.filterLogic === "or") out = out.filter((r2) => qF.some(([fc, f]) => testFilter(gv(f.field, r2), f.op, f.value, filterTypeOf(fc))));
8861
+ else for (const [fc, f] of qF) out = out.filter((r2) => testFilter(gv(f.field, r2), f.op, f.value, filterTypeOf(fc)));
8837
8862
  }
8838
8863
  if (q.sort && q.sort.field) {
8839
8864
  const { field, dir } = q.sort, numeric = typeOf(field) === "number";
@@ -9155,6 +9180,7 @@ function Datatable({
9155
9180
  onQuickFilterChange,
9156
9181
  toolbarActions,
9157
9182
  resizableFilters = true,
9183
+ resizablePopovers = false,
9158
9184
  filterFieldMaxWidth,
9159
9185
  rowPinning = false,
9160
9186
  rowReorder = false,
@@ -9244,6 +9270,7 @@ function Datatable({
9244
9270
  });
9245
9271
  const [sort, setSort] = React51__namespace.default.useState(null);
9246
9272
  const [filters, setFilters] = React51__namespace.default.useState([]);
9273
+ const [filterLogic, setFilterLogic] = React51__namespace.default.useState("and");
9247
9274
  const [hidden, setHidden] = React51__namespace.default.useState(() => /* @__PURE__ */ new Set());
9248
9275
  const [showRowNum, setShowRowNum] = React51__namespace.default.useState(rowNumbers);
9249
9276
  const [wrapped, setWrapped] = React51__namespace.default.useState(() => new Set((columns || []).filter((c) => c.wrapText).map((c) => c.field)));
@@ -9309,9 +9336,12 @@ function Datatable({
9309
9336
  const rowFocusRef = React51__namespace.default.useRef(null);
9310
9337
  const [fWidths, setFWidths] = React51__namespace.default.useState({});
9311
9338
  const [fPanelSize, setFPanelSize] = React51__namespace.default.useState(null);
9339
+ const [popSizes, setPopSizes] = React51__namespace.default.useState({});
9312
9340
  const serializeState = () => ({
9313
9341
  filters: filters.map(({ id, ...f }) => f),
9314
9342
  // strip the internal row id
9343
+ filterLogic,
9344
+ // #303: "and" (default) | "or"
9315
9345
  sort,
9316
9346
  quickFilter: quick,
9317
9347
  page: pageVal,
@@ -9324,12 +9354,15 @@ function Datatable({
9324
9354
  density,
9325
9355
  // #292: additive, optional — user-resized filter panel + field widths (panel-global, not per column).
9326
9356
  filterPanelSize: fPanelSize || void 0,
9327
- filterFieldWidths: fWidths.col != null || fWidths.op != null || fWidths.val != null ? fWidths : void 0
9357
+ filterFieldWidths: fWidths.col != null || fWidths.op != null || fWidths.val != null ? fWidths : void 0,
9358
+ // #304: additive, optional — user-resized sizes of the other toolbar popovers, keyed by popover id.
9359
+ popoverSizes: Object.keys(popSizes).length ? popSizes : void 0
9328
9360
  });
9329
9361
  const applyState = (s) => {
9330
9362
  if (!s || typeof s !== "object") return;
9331
9363
  const known = new Set(cols.map((c) => c.field).filter(Boolean));
9332
9364
  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 })));
9365
+ if (s.filterLogic === "or" || s.filterLogic === "and") setFilterLogic(s.filterLogic);
9333
9366
  if ("sort" in s) setSort(s.sort && known.has(s.sort.field) ? { field: s.sort.field, dir: s.sort.dir === "desc" ? "desc" : "asc" } : null);
9334
9367
  if (typeof s.quickFilter === "string" && quickFilter === void 0) setInternalQuick(s.quickFilter);
9335
9368
  if (typeof s.page === "number" && !pageControlled) setInternalPage(Math.max(0, Math.floor(s.page)));
@@ -9359,6 +9392,14 @@ function Datatable({
9359
9392
  const h = typeof s.filterPanelSize.h === "number" ? clampNum(s.filterPanelSize.h, 120, fMaxH()) : void 0;
9360
9393
  if (w != null || h != null) setFPanelSize({ ...w != null ? { w } : {}, ...h != null ? { h } : {} });
9361
9394
  }
9395
+ if (s.popoverSizes && typeof s.popoverSizes === "object") {
9396
+ const next = {};
9397
+ for (const [id, sz] of Object.entries(s.popoverSizes)) {
9398
+ if (!sz || typeof sz !== "object" || typeof sz.w !== "number" || typeof sz.h !== "number") continue;
9399
+ next[id] = { w: clampNum(sz.w, popMinW(id), fMaxW()), h: clampNum(sz.h, 120, fMaxH()) };
9400
+ }
9401
+ if (Object.keys(next).length) setPopSizes(next);
9402
+ }
9362
9403
  };
9363
9404
  const stateReadyRef = React51__namespace.default.useRef(false);
9364
9405
  const stateRestoredRef = React51__namespace.default.useRef(false);
@@ -9376,7 +9417,7 @@ function Datatable({
9376
9417
  }
9377
9418
  }
9378
9419
  return void 0;
9379
- }, [filters, sort, quick, pageVal, sizeVal, order, widths, hidden, pins, density, fWidths, fPanelSize, stateKey]);
9420
+ }, [filters, filterLogic, sort, quick, pageVal, sizeVal, order, widths, hidden, pins, density, fWidths, fPanelSize, popSizes, stateKey]);
9380
9421
  const restoreState = () => {
9381
9422
  let saved = null;
9382
9423
  if (stateKey) {
@@ -9643,24 +9684,26 @@ function Datatable({
9643
9684
  const CHK_W = checkboxSelection ? rowReorder ? 68 : 44 : 0;
9644
9685
  const numLeft = CHK_W;
9645
9686
  const leadW = numLeft + (showRowNum ? NUM_W : 0);
9687
+ const visLeft = React51__namespace.default.useMemo(() => pins.left.filter((f) => colByField[f] && !hidden.has(f)), [pins.left, colByField, hidden]);
9688
+ const visRight = React51__namespace.default.useMemo(() => pins.right.filter((f) => colByField[f] && !hidden.has(f)), [pins.right, colByField, hidden]);
9646
9689
  const stickyOf = (field) => {
9647
- if (pins.left.includes(field)) {
9690
+ if (visLeft.includes(field)) {
9648
9691
  let off = leadW;
9649
- for (const f of pins.left) {
9692
+ for (const f of visLeft) {
9650
9693
  if (f === field) break;
9651
9694
  off += widthOf(colByField[f] || {});
9652
9695
  }
9653
- const isEdge = pins.left[pins.left.length - 1] === field;
9696
+ const isEdge = visLeft[visLeft.length - 1] === field;
9654
9697
  return { style: { insetInlineStart: off }, pin: "left", edge: isEdge ? "left" : void 0 };
9655
9698
  }
9656
- if (pins.right.includes(field)) {
9699
+ if (visRight.includes(field)) {
9657
9700
  let off = 0;
9658
- const rev = [...pins.right].reverse();
9701
+ const rev = [...visRight].reverse();
9659
9702
  for (const f of rev) {
9660
9703
  if (f === field) break;
9661
9704
  off += widthOf(colByField[f] || {});
9662
9705
  }
9663
- const isEdge = pins.right[0] === field;
9706
+ const isEdge = visRight[0] === field;
9664
9707
  return { style: { insetInlineEnd: off }, pin: "right", edge: isEdge ? "right" : void 0 };
9665
9708
  }
9666
9709
  return {};
@@ -9679,10 +9722,13 @@ function Datatable({
9679
9722
  const searchCols = searchFields && searchFields.length ? searchFields.map((f) => colByField[f] || { field: f }) : visibleCols;
9680
9723
  out = out.filter((r2) => searchCols.some((c) => String(getColVal(c, r2) ?? "").toLowerCase().includes(q)));
9681
9724
  }
9682
- for (const f of filters) {
9683
- const col = colByField[f.field];
9684
- if (!col) continue;
9685
- out = out.filter((r2) => testFilter(getColVal(col, r2), f.op, f.value, filterTypeOf(col)));
9725
+ const activeF = filters.map((f) => [colByField[f.field], f]).filter(([col]) => col);
9726
+ if (activeF.length) {
9727
+ if (filterLogic === "or") {
9728
+ out = out.filter((r2) => activeF.some(([col, f]) => testFilter(getColVal(col, r2), f.op, f.value, filterTypeOf(col))));
9729
+ } else {
9730
+ for (const [col, f] of activeF) out = out.filter((r2) => testFilter(getColVal(col, r2), f.op, f.value, filterTypeOf(col)));
9731
+ }
9686
9732
  }
9687
9733
  if (sort) {
9688
9734
  const col = colByField[sort.field];
@@ -9699,7 +9745,7 @@ function Datatable({
9699
9745
  out = [...out].sort((a, b) => (idx.get(keyOf(a)) ?? 1e9) - (idx.get(keyOf(b)) ?? 1e9));
9700
9746
  }
9701
9747
  return out;
9702
- }, [rows, quick, filters, sort, visibleCols, colByField, serverMode, rowOrder, searchFields]);
9748
+ }, [rows, quick, filters, filterLogic, sort, visibleCols, colByField, serverMode, rowOrder, searchFields]);
9703
9749
  const paginated = pageSize > 0;
9704
9750
  const serverTotal = rowCount == null ? processed.length : rowCount;
9705
9751
  const totalRows = serverMode ? serverTotal : processed.length;
@@ -9974,6 +10020,8 @@ function Datatable({
9974
10020
  pageSize: sizeVal,
9975
10021
  sort,
9976
10022
  filters: filters.map(({ id, ...f }) => f),
10023
+ filterLogic,
10024
+ // #303: "and" (default) | "or" — the server groups its WHERE accordingly
9977
10025
  quickFilter: quick.trim(),
9978
10026
  visibleColumns,
9979
10027
  hiddenColumns
@@ -9981,7 +10029,7 @@ function Datatable({
9981
10029
  });
9982
10030
  }, 250);
9983
10031
  return () => clearTimeout(t);
9984
- }, [serverMode, pageVal, sizeVal, sort, filters, quick, visibleColumns, hiddenColumns]);
10032
+ }, [serverMode, pageVal, sizeVal, sort, filters, filterLogic, quick, visibleColumns, hiddenColumns]);
9985
10033
  const onColVisRef = React51__namespace.default.useRef(onColumnVisibilityChange);
9986
10034
  onColVisRef.current = onColumnVisibilityChange;
9987
10035
  const lastVisibleKey = React51__namespace.default.useRef(null);
@@ -10639,7 +10687,97 @@ function Datatable({
10639
10687
  }
10640
10688
  };
10641
10689
  const hasFilterSizeOverride = fWidths.col != null || fWidths.op != null || fWidths.val != null || fPanelSize != null;
10642
- const fieldHandle = (field, rowIdx) => resizableFilters && rowIdx === 0 ? /* @__PURE__ */ jsxRuntime.jsx(
10690
+ const POP_MIN_W = { columns: 240, agg: 240, pivot: 260, batchedit: 260 };
10691
+ const popMinW = (id) => POP_MIN_W[id] || 200;
10692
+ const clearPop = (id, node) => {
10693
+ if (node) {
10694
+ node.style.removeProperty("--twc-dt-pop-w");
10695
+ node.style.removeProperty("--twc-dt-pop-h");
10696
+ node.removeAttribute("data-pop-sized");
10697
+ }
10698
+ setPopSizes((s) => {
10699
+ if (!(id in s)) return s;
10700
+ const n = { ...s };
10701
+ delete n[id];
10702
+ return n;
10703
+ });
10704
+ };
10705
+ const startPopResize = (id) => (e) => {
10706
+ if (e.button != null && e.button !== 0) return;
10707
+ e.preventDefault();
10708
+ e.stopPropagation();
10709
+ const pop = e.currentTarget.closest(".twc-dt__pop");
10710
+ if (!pop) return;
10711
+ const grip = e.currentTarget;
10712
+ const startX = e.clientX, startY = e.clientY;
10713
+ const r2 = pop.getBoundingClientRect();
10714
+ const startW = r2.width, startH = r2.height;
10715
+ const dir = typeof getComputedStyle !== "undefined" && getComputedStyle(pop).direction === "rtl" ? -1 : 1;
10716
+ pop.style.setProperty("--twc-dt-pop-w", `${startW}px`);
10717
+ pop.style.setProperty("--twc-dt-pop-h", `${startH}px`);
10718
+ grip.setAttribute("data-active", "true");
10719
+ pop.setAttribute("data-pop-sized", "");
10720
+ let lw = startW, lh = startH;
10721
+ const onMove = (ev) => {
10722
+ lw = clampNum(startW + (ev.clientX - startX) * dir, popMinW(id), fMaxW());
10723
+ lh = clampNum(startH + (ev.clientY - startY), 120, fMaxH());
10724
+ pop.style.setProperty("--twc-dt-pop-w", `${lw}px`);
10725
+ pop.style.setProperty("--twc-dt-pop-h", `${lh}px`);
10726
+ };
10727
+ const onUp = () => {
10728
+ setPopSizes((s) => ({ ...s, [id]: { w: lw, h: lh } }));
10729
+ grip.removeAttribute("data-active");
10730
+ window.removeEventListener("pointermove", onMove);
10731
+ window.removeEventListener("pointerup", onUp);
10732
+ };
10733
+ window.addEventListener("pointermove", onMove);
10734
+ window.addEventListener("pointerup", onUp);
10735
+ };
10736
+ const onPopGripKey = (id) => (e) => {
10737
+ if (e.key === "Enter" || e.key === " " || e.key === "Backspace") {
10738
+ e.preventDefault();
10739
+ clearPop(id, e.currentTarget.closest(".twc-dt__pop"));
10740
+ return;
10741
+ }
10742
+ if (!["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "Home", "End"].includes(e.key)) return;
10743
+ e.preventDefault();
10744
+ const pop = e.currentTarget.closest(".twc-dt__pop");
10745
+ if (!pop) return;
10746
+ const r2 = pop.getBoundingClientRect();
10747
+ const step = e.shiftKey ? 4 : 20;
10748
+ const dir = typeof getComputedStyle !== "undefined" && getComputedStyle(pop).direction === "rtl" ? -1 : 1;
10749
+ let w = r2.width, h = r2.height;
10750
+ if (e.key === "ArrowRight") w += step * dir;
10751
+ else if (e.key === "ArrowLeft") w -= step * dir;
10752
+ else if (e.key === "ArrowDown") h += step;
10753
+ else if (e.key === "ArrowUp") h -= step;
10754
+ else if (e.key === "Home") {
10755
+ w = popMinW(id);
10756
+ h = 120;
10757
+ } else if (e.key === "End") {
10758
+ w = fMaxW();
10759
+ h = fMaxH();
10760
+ }
10761
+ setPopSizes((s) => ({ ...s, [id]: { w: clampNum(w, popMinW(id), fMaxW()), h: clampNum(h, 120, fMaxH()) } }));
10762
+ };
10763
+ const popStyle = (id) => popSizes[id] ? { "--twc-dt-pop-w": `${popSizes[id].w}px`, "--twc-dt-pop-h": `${popSizes[id].h}px` } : null;
10764
+ const popGrip = (id) => resizablePopovers ? /* @__PURE__ */ jsxRuntime.jsx(
10765
+ "span",
10766
+ {
10767
+ className: "twc-dt__pop-grip",
10768
+ role: "slider",
10769
+ tabIndex: 0,
10770
+ "aria-label": "Resize panel (Enter or double-click to reset)",
10771
+ "aria-valuetext": popSizes[id] ? `Width ${Math.round(popSizes[id].w)} pixels, height ${Math.round(popSizes[id].h)} pixels` : "Default size",
10772
+ onPointerDown: startPopResize(id),
10773
+ onKeyDown: onPopGripKey(id),
10774
+ onDoubleClick: (e) => {
10775
+ e.preventDefault();
10776
+ clearPop(id, e.currentTarget.closest(".twc-dt__pop"));
10777
+ }
10778
+ }
10779
+ ) : null;
10780
+ const fieldHandle = (field, rowIdx) => (resizableFilters || resizablePopovers) && rowIdx === 0 ? /* @__PURE__ */ jsxRuntime.jsx(
10643
10781
  "span",
10644
10782
  {
10645
10783
  className: "twc-dt__f-rz",
@@ -10761,7 +10899,7 @@ function Datatable({
10761
10899
  onDragEnd: reorderable ? () => setRowDrag({ from: null, over: null, after: false }) : void 0,
10762
10900
  onClick: (e) => handleRowClick(e, k, row),
10763
10901
  children: [
10764
- checkboxSelection ? /* @__PURE__ */ jsxRuntime.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: [
10902
+ checkboxSelection ? /* @__PURE__ */ jsxRuntime.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: [
10765
10903
  /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { display: "inline-flex", alignItems: "center", gap: 4 }, children: [
10766
10904
  reorderable ? rowHandle(k, midIdx, row) : null,
10767
10905
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -10786,7 +10924,7 @@ function Datatable({
10786
10924
  ] }),
10787
10925
  rowResize && !pinSide ? /* @__PURE__ */ jsxRuntime.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
10788
10926
  ] }) : null,
10789
- showRowNum ? /* @__PURE__ */ jsxRuntime.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,
10927
+ showRowNum ? /* @__PURE__ */ jsxRuntime.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,
10790
10928
  ordered.map((c, ci) => {
10791
10929
  const st = stickyOf(c.field);
10792
10930
  const val = getColVal(c, row);
@@ -11196,7 +11334,7 @@ function Datatable({
11196
11334
  onKeyDown: onGridKeyDown,
11197
11335
  children: [
11198
11336
  /* @__PURE__ */ jsxRuntime.jsx("thead", { ref: theadRef, children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { role: "row", "aria-rowindex": 1, children: [
11199
- checkboxSelection ? /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx("div", { className: "twc-dt__th-inner", style: { justifyContent: "center", padding: 0 }, children: /* @__PURE__ */ jsxRuntime.jsx(
11337
+ checkboxSelection ? /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx("div", { className: "twc-dt__th-inner", style: { justifyContent: "center", padding: 0 }, children: /* @__PURE__ */ jsxRuntime.jsx(
11200
11338
  "span",
11201
11339
  {
11202
11340
  className: "twc-dt__check",
@@ -11216,7 +11354,7 @@ function Datatable({
11216
11354
  children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: allSel ? I.check : I.minus })
11217
11355
  }
11218
11356
  ) }) }) : null,
11219
- showRowNum ? /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsxs("div", { className: "twc-dt__th-inner", children: [
11357
+ showRowNum ? /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsxs("div", { className: "twc-dt__th-inner", children: [
11220
11358
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__th-label", style: { flex: "none", cursor: "default" }, children: "#" }),
11221
11359
  /* @__PURE__ */ jsxRuntime.jsx(
11222
11360
  "button",
@@ -11394,8 +11532,8 @@ function Datatable({
11394
11532
  pinnedBottomRows.map((row) => renderLeaf(row, keyIndex.get(keyOf(row)), "bottom"))
11395
11533
  ] }) }),
11396
11534
  hasAggregation && aggOn && !loading && paged.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("tfoot", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { role: "row", children: [
11397
- checkboxSelection ? /* @__PURE__ */ jsxRuntime.jsx("td", { role: "gridcell", "data-pin": "left", "data-pin-edge": pins.left.length || showRowNum ? void 0 : "left", style: { insetInlineStart: 0, width: CHK_W } }) : null,
11398
- showRowNum ? /* @__PURE__ */ jsxRuntime.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,
11535
+ checkboxSelection ? /* @__PURE__ */ jsxRuntime.jsx("td", { role: "gridcell", "data-pin": "left", "data-pin-edge": visLeft.length || showRowNum ? void 0 : "left", style: { insetInlineStart: 0, width: CHK_W } }) : null,
11536
+ showRowNum ? /* @__PURE__ */ jsxRuntime.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,
11399
11537
  ordered.map((c) => {
11400
11538
  const st = stickyOf(c.field);
11401
11539
  const v = aggregate(c);
@@ -11494,7 +11632,7 @@ function Datatable({
11494
11632
  delete values[f];
11495
11633
  return { ...b, fields, values };
11496
11634
  });
11497
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__pop twc-dt__cfg", style: { top: batchEditPos.top, left: batchEditPos.left, width: 320 }, children: [
11635
+ return /* @__PURE__ */ jsxRuntime.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: [
11498
11636
  /* @__PURE__ */ jsxRuntime.jsx(Caret, { pos: batchEditPos }),
11499
11637
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__cfg-head", children: [
11500
11638
  "Edit ",
@@ -11556,7 +11694,8 @@ function Datatable({
11556
11694
  "Apply to ",
11557
11695
  selected.size
11558
11696
  ] })
11559
- ] })
11697
+ ] }),
11698
+ popGrip("batchedit")
11560
11699
  ] });
11561
11700
  })() : null,
11562
11701
  colMenu && menuPos ? /* @__PURE__ */ jsxRuntime.jsxs(
@@ -11729,7 +11868,7 @@ function Datatable({
11729
11868
  ]
11730
11869
  }
11731
11870
  ) : null,
11732
- panel === "columns" && panelPos ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__pop twc-dt__cols", style: { top: panelPos.top, left: panelPos.left }, role: "dialog", "aria-label": "Column settings", children: [
11871
+ panel === "columns" && panelPos ? /* @__PURE__ */ jsxRuntime.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: [
11733
11872
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__panel-head", children: [
11734
11873
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-dt__panel-title", children: [
11735
11874
  "Columns ",
@@ -11854,9 +11993,10 @@ function Datatable({
11854
11993
  c.field
11855
11994
  );
11856
11995
  })
11857
- ] })
11996
+ ] }),
11997
+ popGrip("columns")
11858
11998
  ] }) : null,
11859
- panel === "agg" && panelPos ? /* @__PURE__ */ jsxRuntime.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: [
11999
+ panel === "agg" && panelPos ? /* @__PURE__ */ jsxRuntime.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: [
11860
12000
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__panel-head", children: [
11861
12001
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__panel-title", children: "Aggregation" }),
11862
12002
  /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dt__link", onClick: () => setAggConfig({}), children: "Clear" })
@@ -11905,13 +12045,14 @@ function Datatable({
11905
12045
  }
11906
12046
  ) })
11907
12047
  ] }, c.field);
11908
- }) })
12048
+ }) }),
12049
+ popGrip("agg")
11909
12050
  ] }) : null,
11910
12051
  panel === "pivot" && panelPos ? (() => {
11911
12052
  const fieldOpts = ordered.filter((c) => c.type !== "actions").map((c) => ({ value: c.field, label: c.headerName }));
11912
12053
  const aggOpts = [{ value: "sum", label: "Sum" }, { value: "avg", label: "Avg" }, { value: "min", label: "Min" }, { value: "max", label: "Max" }, { value: "count", label: "Count" }];
11913
12054
  const valueFieldOpts = ordered.filter((c) => c.type !== "actions" && !pivotConfig.values.some((v) => v.field === c.field)).map((c) => ({ value: c.field, label: c.headerName }));
11914
- return /* @__PURE__ */ jsxRuntime.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: [
12055
+ return /* @__PURE__ */ jsxRuntime.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: [
11915
12056
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__panel-head", children: [
11916
12057
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__panel-title", children: "Pivot" }),
11917
12058
  /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dt__link", onClick: () => {
@@ -11919,106 +12060,109 @@ function Datatable({
11919
12060
  setPivotOn(false);
11920
12061
  }, children: "Reset" })
11921
12062
  ] }),
11922
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__cfg-toggle", children: [
11923
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Pivot mode" }),
11924
- /* @__PURE__ */ jsxRuntime.jsx(
11925
- "span",
11926
- {
11927
- className: "twc-dt__sw",
11928
- "data-on": pivotOn || void 0,
11929
- role: "switch",
11930
- "aria-checked": pivotOn,
11931
- tabIndex: 0,
11932
- onClick: () => setPivotOn((v) => !v),
11933
- onKeyDown: (e) => {
11934
- if (e.key === "Enter" || e.key === " ") {
11935
- e.preventDefault();
11936
- setPivotOn((v) => !v);
12063
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__pivot-body", children: [
12064
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__cfg-toggle", children: [
12065
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Pivot mode" }),
12066
+ /* @__PURE__ */ jsxRuntime.jsx(
12067
+ "span",
12068
+ {
12069
+ className: "twc-dt__sw",
12070
+ "data-on": pivotOn || void 0,
12071
+ role: "switch",
12072
+ "aria-checked": pivotOn,
12073
+ tabIndex: 0,
12074
+ onClick: () => setPivotOn((v) => !v),
12075
+ onKeyDown: (e) => {
12076
+ if (e.key === "Enter" || e.key === " ") {
12077
+ e.preventDefault();
12078
+ setPivotOn((v) => !v);
12079
+ }
11937
12080
  }
11938
12081
  }
11939
- }
11940
- )
11941
- ] }),
11942
- !pivotActive && pivotOn ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__cfg-hint", children: [
11943
- "Add at least one ",
11944
- /* @__PURE__ */ jsxRuntime.jsx("b", { children: "Row" }),
11945
- " field and one ",
11946
- /* @__PURE__ */ jsxRuntime.jsx("b", { children: "Value" }),
11947
- " to see the pivot."
11948
- ] }) : null,
11949
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__cfg-section", children: [
11950
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__cfg-label", children: "Rows" }),
11951
- /* @__PURE__ */ jsxRuntime.jsx(
11952
- MultiSelect,
11953
- {
11954
- portal: true,
11955
- placeholder: "Add row fields\u2026",
11956
- value: pivotConfig.rows,
11957
- options: fieldOpts,
11958
- onChange: (vals) => {
11959
- setPivotConfig((p) => ({ ...p, rows: vals }));
11960
- if (vals.length) setPivotOn(true);
11961
- }
11962
- }
11963
- )
11964
- ] }),
11965
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__cfg-section", children: [
11966
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__cfg-label", children: "Columns" }),
11967
- /* @__PURE__ */ jsxRuntime.jsx(
11968
- MultiSelect,
11969
- {
11970
- portal: true,
11971
- placeholder: "Add column fields\u2026",
11972
- value: pivotConfig.columns,
11973
- options: fieldOpts,
11974
- onChange: (vals) => setPivotConfig((p) => ({ ...p, columns: vals }))
11975
- }
11976
- )
11977
- ] }),
11978
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__cfg-section", children: [
11979
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__cfg-label", children: "Values" }),
11980
- pivotConfig.values.map((v, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__cfg-row", children: [
11981
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__cfg-name", children: colByField[v.field]?.headerName || v.field }),
11982
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__cfg-ctl", children: /* @__PURE__ */ jsxRuntime.jsx(
11983
- Select,
12082
+ )
12083
+ ] }),
12084
+ !pivotActive && pivotOn ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__cfg-hint", children: [
12085
+ "Add at least one ",
12086
+ /* @__PURE__ */ jsxRuntime.jsx("b", { children: "Row" }),
12087
+ " field and one ",
12088
+ /* @__PURE__ */ jsxRuntime.jsx("b", { children: "Value" }),
12089
+ " to see the pivot."
12090
+ ] }) : null,
12091
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__cfg-section", children: [
12092
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__cfg-label", children: "Rows" }),
12093
+ /* @__PURE__ */ jsxRuntime.jsx(
12094
+ MultiSelect,
11984
12095
  {
11985
- size: "sm",
11986
- value: v.agg || "sum",
11987
- options: aggOpts,
11988
12096
  portal: true,
11989
- onChange: (a) => setPivotConfig((p) => ({ ...p, values: p.values.map((x, j) => j === i ? { ...x, agg: a } : x) }))
12097
+ placeholder: "Add row fields\u2026",
12098
+ value: pivotConfig.rows,
12099
+ options: fieldOpts,
12100
+ onChange: (vals) => {
12101
+ setPivotConfig((p) => ({ ...p, rows: vals }));
12102
+ if (vals.length) setPivotOn(true);
12103
+ }
11990
12104
  }
11991
- ) }),
12105
+ )
12106
+ ] }),
12107
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__cfg-section", children: [
12108
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__cfg-label", children: "Columns" }),
11992
12109
  /* @__PURE__ */ jsxRuntime.jsx(
11993
- "button",
12110
+ MultiSelect,
11994
12111
  {
11995
- type: "button",
11996
- className: "twc-dt__cfg-x",
11997
- "aria-label": `Remove ${colByField[v.field]?.headerName || v.field}`,
11998
- onClick: () => setPivotConfig((p) => ({ ...p, values: p.values.filter((_, j) => j !== i) })),
11999
- children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.x })
12112
+ portal: true,
12113
+ placeholder: "Add column fields\u2026",
12114
+ value: pivotConfig.columns,
12115
+ options: fieldOpts,
12116
+ onChange: (vals) => setPivotConfig((p) => ({ ...p, columns: vals }))
12000
12117
  }
12001
12118
  )
12002
- ] }, v.field + i)),
12003
- valueFieldOpts.length ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__cfg-add", children: /* @__PURE__ */ jsxRuntime.jsx(
12004
- Select,
12005
- {
12006
- size: "sm",
12007
- placeholder: "Add value field\u2026",
12008
- value: "",
12009
- options: valueFieldOpts,
12010
- portal: true,
12011
- searchable: true,
12012
- searchPlaceholder: "Search fields\u2026",
12013
- onChange: (f) => {
12014
- if (f) {
12015
- setPivotConfig((p) => p.values.some((x) => x.field === f) ? p : { ...p, values: [...p.values, { field: f, agg: "sum" }] });
12016
- setPivotOn(true);
12119
+ ] }),
12120
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__cfg-section", children: [
12121
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__cfg-label", children: "Values" }),
12122
+ pivotConfig.values.map((v, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__cfg-row", children: [
12123
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__cfg-name", children: colByField[v.field]?.headerName || v.field }),
12124
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__cfg-ctl", children: /* @__PURE__ */ jsxRuntime.jsx(
12125
+ Select,
12126
+ {
12127
+ size: "sm",
12128
+ value: v.agg || "sum",
12129
+ options: aggOpts,
12130
+ portal: true,
12131
+ onChange: (a) => setPivotConfig((p) => ({ ...p, values: p.values.map((x, j) => j === i ? { ...x, agg: a } : x) }))
12132
+ }
12133
+ ) }),
12134
+ /* @__PURE__ */ jsxRuntime.jsx(
12135
+ "button",
12136
+ {
12137
+ type: "button",
12138
+ className: "twc-dt__cfg-x",
12139
+ "aria-label": `Remove ${colByField[v.field]?.headerName || v.field}`,
12140
+ onClick: () => setPivotConfig((p) => ({ ...p, values: p.values.filter((_, j) => j !== i) })),
12141
+ children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.x })
12142
+ }
12143
+ )
12144
+ ] }, v.field + i)),
12145
+ valueFieldOpts.length ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__cfg-add", children: /* @__PURE__ */ jsxRuntime.jsx(
12146
+ Select,
12147
+ {
12148
+ size: "sm",
12149
+ placeholder: "Add value field\u2026",
12150
+ value: "",
12151
+ options: valueFieldOpts,
12152
+ portal: true,
12153
+ searchable: true,
12154
+ searchPlaceholder: "Search fields\u2026",
12155
+ onChange: (f) => {
12156
+ if (f) {
12157
+ setPivotConfig((p) => p.values.some((x) => x.field === f) ? p : { ...p, values: [...p.values, { field: f, agg: "sum" }] });
12158
+ setPivotOn(true);
12159
+ }
12017
12160
  }
12018
12161
  }
12019
- }
12020
- ) }) : null
12021
- ] })
12162
+ ) }) : null
12163
+ ] })
12164
+ ] }),
12165
+ popGrip("pivot")
12022
12166
  ] });
12023
12167
  })() : null,
12024
12168
  panel === "filters" && panelPos ? /* @__PURE__ */ jsxRuntime.jsxs(
@@ -12042,8 +12186,12 @@ function Datatable({
12042
12186
  children: [
12043
12187
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__panel-head", children: [
12044
12188
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__panel-title", children: "Filters" }),
12045
- /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { display: "inline-flex", gap: 2 }, children: [
12046
- resizableFilters && hasFilterSizeOverride ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dt__link", onClick: resetFilterSizes, children: "Reset sizes" }) : null,
12189
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { display: "inline-flex", alignItems: "center", gap: 6 }, children: [
12190
+ filters.length > 1 ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-dt__flogic", role: "group", "aria-label": "Combine filters with", children: [
12191
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dt__flogic-btn", "data-active": filterLogic === "and" || void 0, "aria-pressed": filterLogic === "and", onClick: () => setFilterLogic("and"), children: "AND" }),
12192
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dt__flogic-btn", "data-active": filterLogic === "or" || void 0, "aria-pressed": filterLogic === "or", onClick: () => setFilterLogic("or"), children: "OR" })
12193
+ ] }) : null,
12194
+ (resizableFilters || resizablePopovers) && hasFilterSizeOverride ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dt__link", onClick: resetFilterSizes, children: "Reset sizes" }) : null,
12047
12195
  filters.length ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dt__link", onClick: () => setFilters([]), children: "Clear all" }) : null
12048
12196
  ] })
12049
12197
  ] }),
@@ -12115,6 +12263,7 @@ function Datatable({
12115
12263
  ),
12116
12264
  fieldHandle("val", i)
12117
12265
  ] }),
12266
+ /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(Svg, { d: I.plus }) }),
12118
12267
  /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(Svg, { d: I.x }) })
12119
12268
  ] }, f.id);
12120
12269
  }) }),
@@ -12122,7 +12271,7 @@ function Datatable({
12122
12271
  /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.plus, style: { color: "var(--color-primary)" } }),
12123
12272
  " Add filter"
12124
12273
  ] }) }),
12125
- resizableFilters ? /* @__PURE__ */ jsxRuntime.jsx(
12274
+ resizableFilters || resizablePopovers ? /* @__PURE__ */ jsxRuntime.jsx(
12126
12275
  "span",
12127
12276
  {
12128
12277
  className: "twc-dt__pop-grip",