twico-ui 1.19.1 → 1.20.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.d.cts CHANGED
@@ -2046,6 +2046,13 @@ interface DatatableColumn<T = any> {
2046
2046
  headerName?: string;
2047
2047
  /** Data type. "actions" renders per-row action buttons via getActions. @default "string" */
2048
2048
  type?: "string" | "number" | "actions";
2049
+ /** Filter operators + value comparison for this column, **decoupled from the edit `type`** (#270).
2050
+ * A `"number"` column edits by coercing its commit with `Number()`, which would wipe a custom value
2051
+ * (e.g. a value+unit measurement edited via `renderEditCell`) — so such a column must edit as
2052
+ * `type: "string"`, yet may still want **numeric** filter operators (`=` `≠` `>` `≥` `<` `≤`).
2053
+ * Set `filterType: "number"` to offer them (provide a `valueGetter` returning the numeric value so
2054
+ * the comparison is numeric). Falls back to `type`. Sorting still uses `type`. @default type */
2055
+ filterType?: "string" | "number";
2049
2056
  /** Column width: a px number, or `"auto"` to size to the header's intrinsic width (chrome + label) so a short column fits without truncating or wasting the 160px default. @default 160 (120 for actions) */
2050
2057
  width?: number | "auto";
2051
2058
  /** Lower bound (px) for the resolved width, incl. `"auto"` and user resizes. */
package/dist/index.d.ts CHANGED
@@ -2046,6 +2046,13 @@ interface DatatableColumn<T = any> {
2046
2046
  headerName?: string;
2047
2047
  /** Data type. "actions" renders per-row action buttons via getActions. @default "string" */
2048
2048
  type?: "string" | "number" | "actions";
2049
+ /** Filter operators + value comparison for this column, **decoupled from the edit `type`** (#270).
2050
+ * A `"number"` column edits by coercing its commit with `Number()`, which would wipe a custom value
2051
+ * (e.g. a value+unit measurement edited via `renderEditCell`) — so such a column must edit as
2052
+ * `type: "string"`, yet may still want **numeric** filter operators (`=` `≠` `>` `≥` `<` `≤`).
2053
+ * Set `filterType: "number"` to offer them (provide a `valueGetter` returning the numeric value so
2054
+ * the comparison is numeric). Falls back to `type`. Sorting still uses `type`. @default type */
2055
+ filterType?: "string" | "number";
2049
2056
  /** Column width: a px number, or `"auto"` to size to the header's intrinsic width (chrome + label) so a short column fits without truncating or wasting the 160px default. @default 160 (120 for actions) */
2050
2057
  width?: number | "auto";
2051
2058
  /** Lower bound (px) for the resolved width, incl. `"auto"` and user resizes. */
package/dist/index.mjs CHANGED
@@ -6748,6 +6748,7 @@ function Select({
6748
6748
  "data-disabled": o.disabled || void 0,
6749
6749
  "data-selected": isSel || void 0,
6750
6750
  "data-active": idx === active || void 0,
6751
+ title: typeof o.label === "string" ? o.label : void 0,
6751
6752
  onMouseEnter: () => {
6752
6753
  if (!o.disabled) setActive(idx);
6753
6754
  },
@@ -8474,13 +8475,15 @@ th.twc-dt__rownum .twc-dt__th-inner { padding-inline: 8px; gap: 2px; justify-con
8474
8475
  .twc-dt__col-list { max-height: 230px; overflow-y: auto; }
8475
8476
  .twc-dt__col-row { display: flex; align-items: center; gap: 10px; padding: 7px 8px; border-radius: var(--radius-md); cursor: pointer; }
8476
8477
  .twc-dt__col-row:hover { background: var(--color-surface-sunken); }
8477
- .twc-dt__col-row[draggable="true"] { cursor: grab; }
8478
+ /* #271 (columns-panel analog of #263/#267): grab lives on the grip only, not the whole row \u2014 the row
8479
+ keeps its 'cursor: pointer' (toggles visibility) and stays a drag source for the mouse. */
8478
8480
  .twc-dt__col-row[data-dragging="true"] { opacity: 0.5; }
8479
8481
  .twc-dt__col-row[data-dropbefore="true"] { box-shadow: inset 0 3px 0 var(--color-primary); }
8480
8482
  .twc-dt__col-row[data-dropafter="true"] { box-shadow: inset 0 -3px 0 var(--color-primary); }
8481
- .twc-dt__col-grip { display: inline-flex; color: var(--color-text-subtle); flex: none; opacity: 0.45; }
8483
+ .twc-dt__col-grip { display: inline-flex; color: var(--color-text-subtle); flex: none; opacity: 0.45; cursor: grab; }
8482
8484
  .twc-dt__col-row:hover .twc-dt__col-grip { opacity: 0.8; }
8483
8485
  .twc-dt__col-grip svg { width: 14px; height: 14px; }
8486
+ .twc-dt__col-grip:active, .twc-dt__col-row[data-dragging="true"] .twc-dt__col-grip { cursor: grabbing; }
8484
8487
  .twc-dt__col-name { flex: 1; font-size: var(--text-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
8485
8488
  .twc-dt__col-pins { display: inline-flex; gap: 2px; flex: none; }
8486
8489
  .twc-dt__col-pin { display: inline-grid; place-items: center; width: 24px; height: 24px; border: none; padding: 0; background: transparent; color: var(--color-text-subtle); cursor: pointer; border-radius: var(--radius-sm); transition: background-color var(--duration-fast), color var(--duration-fast); }
@@ -8618,6 +8621,11 @@ var NUM_OPS = [
8618
8621
  ];
8619
8622
  var opsFor = (type) => type === "number" ? NUM_OPS : STR_OPS;
8620
8623
  var isMultiOp = (op) => op === "isAnyOf";
8624
+ var filterTypeOf = (col) => {
8625
+ const ft = col && col.filterType;
8626
+ if (ft === "number" || ft === "string") return ft;
8627
+ return col && col.type === "number" ? "number" : "string";
8628
+ };
8621
8629
  var getColVal = (col, row) => col && col.valueGetter ? col.valueGetter(row) : row == null ? void 0 : row[col && col.field];
8622
8630
  var diffValueNode = (col, v, row) => col.renderCell ? col.renderCell(v, row) : col.valueFormatter ? col.valueFormatter(v, row) : v == null ? "" : v;
8623
8631
  function renderDiffCell(col, val, row) {
@@ -8700,7 +8708,10 @@ function runDatatableQuery(rows, query, options = {}) {
8700
8708
  let out = Array.isArray(rows) ? rows : [];
8701
8709
  const quick = String(q.quickFilter || "").trim().toLowerCase();
8702
8710
  if (quick) out = out.filter((r2) => searchFields.some((f) => String(gv(f, r2) ?? "").toLowerCase().includes(quick)));
8703
- for (const f of q.filters || []) out = out.filter((r2) => testFilter(gv(f.field, r2), f.op, f.value, typeOf(f.field)));
8711
+ for (const f of q.filters || []) {
8712
+ const fc = cols.find((c) => c.field === f.field);
8713
+ out = out.filter((r2) => testFilter(gv(f.field, r2), f.op, f.value, filterTypeOf(fc)));
8714
+ }
8704
8715
  if (q.sort && q.sort.field) {
8705
8716
  const { field, dir } = q.sort, numeric = typeOf(field) === "number";
8706
8717
  out = [...out].sort((a, b) => {
@@ -9518,7 +9529,7 @@ function Datatable({
9518
9529
  for (const f of filters) {
9519
9530
  const col = colByField[f.field];
9520
9531
  if (!col) continue;
9521
- out = out.filter((r2) => testFilter(getColVal(col, r2), f.op, f.value, col.type));
9532
+ out = out.filter((r2) => testFilter(getColVal(col, r2), f.op, f.value, filterTypeOf(col)));
9522
9533
  }
9523
9534
  if (sort) {
9524
9535
  const col = colByField[sort.field];
@@ -9836,7 +9847,7 @@ function Datatable({
9836
9847
  }
9837
9848
  function addFilter(field) {
9838
9849
  const col = colByField[field] || cols[0];
9839
- setFilters((f) => [...f, { id: Date.now() + Math.random(), field: col.field, op: opsFor(col.type)[0].value, value: "" }]);
9850
+ setFilters((f) => [...f, { id: Date.now() + Math.random(), field: col.field, op: opsFor(filterTypeOf(col))[0].value, value: "" }]);
9840
9851
  }
9841
9852
  function setPin(field, side) {
9842
9853
  setPins((p) => {
@@ -11651,7 +11662,7 @@ function Datatable({
11651
11662
  ] }),
11652
11663
  filters.length === 0 ? /* @__PURE__ */ jsx("div", { className: "twc-dt__empty", style: { padding: "16px 12px" }, children: "No filters applied" }) : filters.map((f) => {
11653
11664
  const col = colByField[f.field] || cols[0];
11654
- const ops = opsFor(col.type);
11665
+ const ops = opsFor(filterTypeOf(col));
11655
11666
  const op = ops.find((o) => o.value === f.op) || ops[0];
11656
11667
  return /* @__PURE__ */ jsxs("div", { className: "twc-dt__frow", children: [
11657
11668
  /* @__PURE__ */ jsx("div", { className: "twc-dt__f-col", children: /* @__PURE__ */ jsx(
@@ -11663,7 +11674,7 @@ function Datatable({
11663
11674
  options: filterableCols.map((c) => ({ value: c.field, label: c.headerName })),
11664
11675
  onChange: (v) => {
11665
11676
  const nc = colByField[v];
11666
- setFilters((arr) => arr.map((x) => x.id === f.id ? { ...x, field: v, op: opsFor(nc.type)[0].value, value: "" } : x));
11677
+ setFilters((arr) => arr.map((x) => x.id === f.id ? { ...x, field: v, op: opsFor(filterTypeOf(nc))[0].value, value: "" } : x));
11667
11678
  }
11668
11679
  }
11669
11680
  ) }),
@@ -11702,7 +11713,7 @@ function Datatable({
11702
11713
  Input,
11703
11714
  {
11704
11715
  size: "sm",
11705
- type: col.type === "number" ? "number" : "text",
11716
+ type: filterTypeOf(col) === "number" ? "number" : "text",
11706
11717
  placeholder: "Value",
11707
11718
  value: f.value,
11708
11719
  onChange: (e) => setFilters((arr) => arr.map((x) => x.id === f.id ? { ...x, value: e.target.value } : x))