twico-ui 1.20.2 → 1.21.1

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.d.cts CHANGED
@@ -1810,6 +1810,10 @@ interface DatatableProps<T = any> extends Omit<React.HTMLAttributes<HTMLDivEleme
1810
1810
  quickFilter?: string;
1811
1811
  /** Fires with the new quick-search string as the user types (and when a host sets it). */
1812
1812
  onQuickFilterChange?: (value: string) => void;
1813
+ /** Custom node rendered in a **leading slot** of the toolbar row, before the built-in Columns/Filters
1814
+ * cluster (#286) — for host controls like an "Add row" button or bulk actions. Mirrors `CardGrid`'s
1815
+ * `toolbar` prop, so no internal-class/absolute-position hacks are needed. */
1816
+ toolbarActions?: React.ReactNode;
1813
1817
  /**
1814
1818
  * Actions shown in the toolbar when one or more rows are selected (requires
1815
1819
  * `checkboxSelection`). Each handler receives the selected keys, the resolved
package/dist/index.d.ts CHANGED
@@ -1810,6 +1810,10 @@ interface DatatableProps<T = any> extends Omit<React.HTMLAttributes<HTMLDivEleme
1810
1810
  quickFilter?: string;
1811
1811
  /** Fires with the new quick-search string as the user types (and when a host sets it). */
1812
1812
  onQuickFilterChange?: (value: string) => void;
1813
+ /** Custom node rendered in a **leading slot** of the toolbar row, before the built-in Columns/Filters
1814
+ * cluster (#286) — for host controls like an "Add row" button or bulk actions. Mirrors `CardGrid`'s
1815
+ * `toolbar` prop, so no internal-class/absolute-position hacks are needed. */
1816
+ toolbarActions?: React.ReactNode;
1813
1817
  /**
1814
1818
  * Actions shown in the toolbar when one or more rows are selected (requires
1815
1819
  * `checkboxSelection`). Each handler receives the selected keys, the resolved
package/dist/index.mjs CHANGED
@@ -5467,7 +5467,7 @@ function ColorPicker({
5467
5467
  role: "dialog",
5468
5468
  "aria-modal": "true",
5469
5469
  "aria-label": "Color picker",
5470
- style: { position: "fixed", left: coords.left, right: "auto", top: coords.top, bottom: coords.bottom, zIndex: "var(--z-tooltip)" },
5470
+ style: { position: "fixed", left: coords.left, right: "auto", top: coords.top, bottom: coords.bottom, zIndex: "var(--z-floating)" },
5471
5471
  children: [
5472
5472
  /* @__PURE__ */ jsxs(
5473
5473
  "div",
@@ -5945,7 +5945,7 @@ function Combobox({
5945
5945
  role: "listbox",
5946
5946
  ref: popRef,
5947
5947
  "data-placement": coords.flip ? "top" : "bottom",
5948
- style: { position: "fixed", left: coords.left, top: coords.top, bottom: coords.bottom, width: coords.width, right: "auto", zIndex: "var(--z-tooltip)" },
5948
+ style: { position: "fixed", left: coords.left, top: coords.top, bottom: coords.bottom, width: coords.width, right: "auto", zIndex: "var(--z-floating)" },
5949
5949
  children: popInner
5950
5950
  }
5951
5951
  ),
@@ -6832,7 +6832,7 @@ function Select({
6832
6832
  ref: popRef,
6833
6833
  "data-state": popState,
6834
6834
  "data-placement": coords.flip ? "top" : "bottom",
6835
- style: { position: "fixed", left: coords.left, top: coords.top, bottom: coords.bottom, width: coords.width, minWidth: coords.minWidth, maxWidth: coords.maxWidth, right: "auto", zIndex: "var(--z-tooltip)" },
6835
+ style: { position: "fixed", left: coords.left, top: coords.top, bottom: coords.bottom, width: coords.width, minWidth: coords.minWidth, maxWidth: coords.maxWidth, right: "auto", zIndex: "var(--z-floating)" },
6836
6836
  children: popInner
6837
6837
  }
6838
6838
  ),
@@ -7599,7 +7599,7 @@ function MultiSelect({
7599
7599
  className: "twc-pop twc-pop--portal",
7600
7600
  ref: popRef,
7601
7601
  "data-placement": coords.flip ? "top" : "bottom",
7602
- style: { position: "fixed", left: coords.left, top: coords.top, bottom: coords.bottom, width: coords.width, right: "auto", zIndex: "var(--z-tooltip)" },
7602
+ style: { position: "fixed", left: coords.left, top: coords.top, bottom: coords.bottom, width: coords.width, right: "auto", zIndex: "var(--z-floating)" },
7603
7603
  children: popInner
7604
7604
  }
7605
7605
  ),
@@ -8107,6 +8107,8 @@ var DT_CSS = `
8107
8107
  /* Toolbar */
8108
8108
  .twc-dt__toolbar { position: relative; z-index: 10; display: flex; align-items: center; gap: 6px; padding: 8px 10px;
8109
8109
  border-bottom: var(--border-thin) solid var(--color-divider); flex-wrap: wrap; }
8110
+ /* #286: host-supplied leading toolbar slot \u2014 a flex cluster so multiple buttons align with the built-ins. */
8111
+ .twc-dt__toolbar-actions { display: inline-flex; align-items: center; gap: 6px; }
8110
8112
  /* z-index above the scroll area's sticky header (z:3) so a toolbar button's
8111
8113
  hover tooltip (a ::after that hangs below the bar) paints over the table
8112
8114
  instead of being covered by the header/first rows. */
@@ -8504,9 +8506,14 @@ th.twc-dt__rownum .twc-dt__th-inner { padding-inline: 8px; gap: 2px; justify-con
8504
8506
 
8505
8507
  /* Filter panel */
8506
8508
  .twc-dt__filters { width: 580px; max-width: calc(100vw - 32px); }
8507
- .twc-dt__frow { display: flex; align-items: center; gap: 6px; padding: 5px 4px; }
8508
- .twc-dt__f-col { width: 118px; flex: none; }
8509
- .twc-dt__f-op { width: 118px; flex: none; }
8509
+ /* #289: wrap is a safety net \u2014 a beyond-cap label or the narrow responsive panel drops the value input
8510
+ to its own line instead of clipping the remove button; no effect in the normal (capped) case. */
8511
+ .twc-dt__frow { display: flex; align-items: center; gap: 6px; padding: 5px 4px; flex-wrap: wrap; }
8512
+ /* #289: column-field auto-fits the widest header label \u2014 JS writes --twc-dt-fcol-w (measured, clamped),
8513
+ the max-width is the hard backstop that keeps the value input above its 140px floor inside the 580px
8514
+ panel even if the var is stale/too large. Fallback 118px = the previous fixed behavior. */
8515
+ .twc-dt__f-col { flex: none; width: var(--twc-dt-fcol-w, 118px); min-width: 118px; max-width: 210px; }
8516
+ .twc-dt__f-op { flex: none; width: var(--twc-dt-fop-w, 118px); min-width: 118px; max-width: 170px; }
8510
8517
  .twc-dt__f-val { flex: 1; min-width: 140px; }
8511
8518
  .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; }
8512
8519
  .twc-dt__frm-x:hover { background: var(--color-danger-subtle); color: var(--color-danger-subtle-fg); }
@@ -8621,6 +8628,7 @@ var NUM_OPS = [
8621
8628
  ];
8622
8629
  var opsFor = (type) => type === "number" ? NUM_OPS : STR_OPS;
8623
8630
  var isMultiOp = (op) => op === "isAnyOf";
8631
+ var ALL_OP_LABELS = [...new Set([...STR_OPS, ...NUM_OPS].map((o) => o.label))];
8624
8632
  var filterTypeOf = (col) => {
8625
8633
  const ft = col && col.filterType;
8626
8634
  if (ft === "number" || ft === "string") return ft;
@@ -9061,6 +9069,7 @@ function Datatable({
9061
9069
  searchable = true,
9062
9070
  quickFilter,
9063
9071
  onQuickFilterChange,
9072
+ toolbarActions,
9064
9073
  rowPinning = false,
9065
9074
  rowReorder = false,
9066
9075
  rowResize = false,
@@ -9292,6 +9301,8 @@ function Datatable({
9292
9301
  };
9293
9302
  }, []);
9294
9303
  const scrollRef = React51__default.useRef(null);
9304
+ const filterPanelRef = React51__default.useRef(null);
9305
+ const measureCanvas = React51__default.useRef(null);
9295
9306
  const [scrollTop, setScrollTop] = React51__default.useState(0);
9296
9307
  const [viewportH, setViewportH] = React51__default.useState(0);
9297
9308
  const [ovTip, setOvTip] = React51__default.useState(null);
@@ -10325,7 +10336,36 @@ function Datatable({
10325
10336
  ] });
10326
10337
  }
10327
10338
  const tableMinWidth = leadW + ordered.reduce((a, c) => a + widthOf(c), 0);
10328
- const filterableCols = cols.filter((c) => c.filterable);
10339
+ const filterableCols = React51__default.useMemo(() => cols.filter((c) => c.filterable), [cols]);
10340
+ React51__default.useEffect(() => {
10341
+ const el = filterPanelRef.current;
10342
+ if (panel !== "filters" || !el || typeof document === "undefined") return void 0;
10343
+ const measure = () => {
10344
+ if (!el.isConnected) return;
10345
+ const trigger = el.querySelector(".twc-sel__trigger");
10346
+ const cs = getComputedStyle(trigger || el);
10347
+ const ctx = (measureCanvas.current || (measureCanvas.current = document.createElement("canvas"))).getContext("2d");
10348
+ if (!ctx) return;
10349
+ ctx.font = cs.font || `${cs.fontStyle} ${cs.fontWeight} ${cs.fontSize}/${cs.lineHeight} ${cs.fontFamily}`;
10350
+ const pad2 = trigger ? (parseFloat(cs.paddingLeft) || 0) + (parseFloat(cs.paddingRight) || 0) : 24;
10351
+ const chrome = pad2 + 8 + 16 + 4;
10352
+ const widest = (labels) => labels.reduce((m, l) => Math.max(m, ctx.measureText(String(l)).width), 0);
10353
+ const colCap = Math.max(118, Math.min(210, el.clientWidth - 118 - 30 - 140 - 3 * 6 - 2 * 4));
10354
+ const colW = Math.min(colCap, Math.max(118, Math.ceil(widest(filterableCols.map((c) => c.headerName ?? c.field)) + chrome)));
10355
+ const opW = Math.min(170, Math.max(118, Math.ceil(widest(ALL_OP_LABELS) + chrome)));
10356
+ if (Number.isFinite(colW)) el.style.setProperty("--twc-dt-fcol-w", `${colW}px`);
10357
+ if (Number.isFinite(opW)) el.style.setProperty("--twc-dt-fop-w", `${opW}px`);
10358
+ };
10359
+ measure();
10360
+ document.fonts?.ready?.then?.(measure).catch?.(() => {
10361
+ });
10362
+ let ro;
10363
+ if (typeof ResizeObserver !== "undefined") {
10364
+ ro = new ResizeObserver(measure);
10365
+ ro.observe(el);
10366
+ }
10367
+ return () => ro?.disconnect();
10368
+ }, [panel, filterableCols, filters.length]);
10329
10369
  const orderIdxOf = (f) => {
10330
10370
  const i = order.indexOf(f);
10331
10371
  return i === -1 ? 9999 : i;
@@ -10643,6 +10683,7 @@ function Datatable({
10643
10683
  return /* @__PURE__ */ jsxs("div", { className: `twc-dt ${className}`, ref: rootRef, "data-density": density, "data-resizing": resizing || void 0, ...rest, children: [
10644
10684
  __twcStyles,
10645
10685
  /* @__PURE__ */ jsxs("div", { className: "twc-dt__toolbar", "data-compact": compact || void 0, children: [
10686
+ toolbarActions != null ? /* @__PURE__ */ jsx("div", { className: "twc-dt__toolbar-actions", children: toolbarActions }) : null,
10646
10687
  (batchActions.length || hasBatchEditor) && selected.size > 0 ? /* @__PURE__ */ jsxs("div", { className: "twc-dt__batch", children: [
10647
10688
  /* @__PURE__ */ jsx("button", { type: "button", className: "twc-dt__batch-x", onClick: clearSelection, "aria-label": "Clear selection", children: /* @__PURE__ */ jsx(Svg, { d: I.x }) }),
10648
10689
  /* @__PURE__ */ jsxs("span", { className: "twc-dt__batch-count", children: [
@@ -11694,7 +11735,7 @@ function Datatable({
11694
11735
  ] })
11695
11736
  ] });
11696
11737
  })() : null,
11697
- panel === "filters" && panelPos ? /* @__PURE__ */ jsxs("div", { className: "twc-dt__pop twc-dt__filters", style: { top: panelPos.top, left: panelPos.left }, children: [
11738
+ panel === "filters" && panelPos ? /* @__PURE__ */ jsxs("div", { ref: filterPanelRef, className: "twc-dt__pop twc-dt__filters", style: { top: panelPos.top, left: panelPos.left }, children: [
11698
11739
  /* @__PURE__ */ jsxs("div", { className: "twc-dt__panel-head", children: [
11699
11740
  /* @__PURE__ */ jsx("span", { className: "twc-dt__panel-title", children: "Filters" }),
11700
11741
  filters.length ? /* @__PURE__ */ jsx("button", { type: "button", className: "twc-dt__link", onClick: () => setFilters([]), children: "Clear all" }) : null
@@ -12567,7 +12608,7 @@ function DatePicker({
12567
12608
  role: "dialog",
12568
12609
  "aria-modal": "true",
12569
12610
  "aria-label": "Choose date",
12570
- style: { position: "fixed", left: coords.left, right: "auto", top: coords.top, bottom: coords.bottom, zIndex: "var(--z-tooltip)" },
12611
+ style: { position: "fixed", left: coords.left, right: "auto", top: coords.top, bottom: coords.bottom, zIndex: "var(--z-floating)" },
12571
12612
  children: [
12572
12613
  /* @__PURE__ */ jsxs("div", { className: "twc-dp__head", children: [
12573
12614
  /* @__PURE__ */ jsx("button", { type: "button", className: "twc-dp__nav", "aria-label": mode === "years" ? "Previous decade" : mode === "months" ? "Previous year" : "Previous month", onClick: () => setView(mode === "years" ? new Date(y - 10, m, 1) : mode === "months" ? new Date(y - 1, m, 1) : new Date(y, m - 1, 1)), children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "m15 18-6-6 6-6" }) }) }),
@@ -13144,7 +13185,7 @@ function DateRangePicker({
13144
13185
  role: "dialog",
13145
13186
  "aria-modal": "true",
13146
13187
  "aria-label": "Choose date range",
13147
- style: { position: "fixed", left: coords.left, right: "auto", top: coords.top, bottom: coords.bottom, zIndex: "var(--z-tooltip)" },
13188
+ style: { position: "fixed", left: coords.left, right: "auto", top: coords.top, bottom: coords.bottom, zIndex: "var(--z-floating)" },
13148
13189
  children: [
13149
13190
  presetItems.length ? /* @__PURE__ */ jsx("div", { className: "twc-drp__presets", children: presetItems.map((p, i) => /* @__PURE__ */ jsx("button", { type: "button", className: "twc-drp__preset", onClick: () => applyPreset(p), children: p.label }, i)) }) : null,
13150
13191
  /* @__PURE__ */ jsxs("div", { className: "twc-drp__cal", children: [
@@ -13673,7 +13714,7 @@ function TimePicker({
13673
13714
  role: "dialog",
13674
13715
  "aria-modal": "true",
13675
13716
  "aria-label": "Choose time",
13676
- style: { position: "fixed", left: coords.left, right: "auto", top: coords.top, bottom: coords.bottom, zIndex: "var(--z-tooltip)" },
13717
+ style: { position: "fixed", left: coords.left, right: "auto", top: coords.top, bottom: coords.bottom, zIndex: "var(--z-floating)" },
13677
13718
  children: /* @__PURE__ */ jsx("div", { className: "twc-tp__cols", children: columns.map((col) => {
13678
13719
  const firstTab = col.items.find((it) => it.selected) || col.items.find((it) => !it.disabled);
13679
13720
  return /* @__PURE__ */ jsxs("div", { className: "twc-tp__col", role: "listbox", "aria-label": col.aria, "data-col": col.key, children: [