twico-ui 1.19.1 → 1.20.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/CHANGELOG.md +14 -0
- package/dist/index.cjs +35 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.mjs +35 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to Twico UI are documented here (newest first). This file is generated automatically on each release by [semantic-release](https://semantic-release.gitbook.io/) from [Conventional Commits](https://www.conventionalcommits.org/) — do not edit it by hand. The same notes appear on each [GitHub Release](https://github.com/EncryptionL/twico-ui/releases).
|
|
4
4
|
|
|
5
|
+
## [1.20.1](https://github.com/EncryptionL/twico-ui/compare/v1.20.0...v1.20.1) (2026-07-23)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **datatable:** Esc cancels a cell edit for custom renderEditCell editors ([f886023](https://github.com/EncryptionL/twico-ui/commit/f88602390edf75b1217b5ecd5a659951ce9c7748)), closes [#273](https://github.com/EncryptionL/twico-ui/issues/273)
|
|
11
|
+
|
|
12
|
+
# [1.20.0](https://github.com/EncryptionL/twico-ui/compare/v1.19.1...v1.20.0) (2026-07-23)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* **datatable:** add column filterType, decoupling filter operators from the edit type ([68dbb6e](https://github.com/EncryptionL/twico-ui/commit/68dbb6e80cc3e50fd1072eff5fa8cf2415259ef0)), closes [#271](https://github.com/EncryptionL/twico-ui/issues/271) [263/#267](https://github.com/EncryptionL/twico-ui/issues/267) [#269](https://github.com/EncryptionL/twico-ui/issues/269) [#269](https://github.com/EncryptionL/twico-ui/issues/269) [#270](https://github.com/EncryptionL/twico-ui/issues/270) [#271](https://github.com/EncryptionL/twico-ui/issues/271)
|
|
18
|
+
|
|
5
19
|
## [1.19.1](https://github.com/EncryptionL/twico-ui/compare/v1.19.0...v1.19.1) (2026-07-23)
|
|
6
20
|
|
|
7
21
|
|
package/dist/index.cjs
CHANGED
|
@@ -6769,6 +6769,7 @@ function Select({
|
|
|
6769
6769
|
"data-disabled": o.disabled || void 0,
|
|
6770
6770
|
"data-selected": isSel || void 0,
|
|
6771
6771
|
"data-active": idx === active || void 0,
|
|
6772
|
+
title: typeof o.label === "string" ? o.label : void 0,
|
|
6772
6773
|
onMouseEnter: () => {
|
|
6773
6774
|
if (!o.disabled) setActive(idx);
|
|
6774
6775
|
},
|
|
@@ -8495,13 +8496,15 @@ th.twc-dt__rownum .twc-dt__th-inner { padding-inline: 8px; gap: 2px; justify-con
|
|
|
8495
8496
|
.twc-dt__col-list { max-height: 230px; overflow-y: auto; }
|
|
8496
8497
|
.twc-dt__col-row { display: flex; align-items: center; gap: 10px; padding: 7px 8px; border-radius: var(--radius-md); cursor: pointer; }
|
|
8497
8498
|
.twc-dt__col-row:hover { background: var(--color-surface-sunken); }
|
|
8498
|
-
|
|
8499
|
+
/* #271 (columns-panel analog of #263/#267): grab lives on the grip only, not the whole row \u2014 the row
|
|
8500
|
+
keeps its 'cursor: pointer' (toggles visibility) and stays a drag source for the mouse. */
|
|
8499
8501
|
.twc-dt__col-row[data-dragging="true"] { opacity: 0.5; }
|
|
8500
8502
|
.twc-dt__col-row[data-dropbefore="true"] { box-shadow: inset 0 3px 0 var(--color-primary); }
|
|
8501
8503
|
.twc-dt__col-row[data-dropafter="true"] { box-shadow: inset 0 -3px 0 var(--color-primary); }
|
|
8502
|
-
.twc-dt__col-grip { display: inline-flex; color: var(--color-text-subtle); flex: none; opacity: 0.45; }
|
|
8504
|
+
.twc-dt__col-grip { display: inline-flex; color: var(--color-text-subtle); flex: none; opacity: 0.45; cursor: grab; }
|
|
8503
8505
|
.twc-dt__col-row:hover .twc-dt__col-grip { opacity: 0.8; }
|
|
8504
8506
|
.twc-dt__col-grip svg { width: 14px; height: 14px; }
|
|
8507
|
+
.twc-dt__col-grip:active, .twc-dt__col-row[data-dragging="true"] .twc-dt__col-grip { cursor: grabbing; }
|
|
8505
8508
|
.twc-dt__col-name { flex: 1; font-size: var(--text-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
8506
8509
|
.twc-dt__col-pins { display: inline-flex; gap: 2px; flex: none; }
|
|
8507
8510
|
.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); }
|
|
@@ -8639,6 +8642,11 @@ var NUM_OPS = [
|
|
|
8639
8642
|
];
|
|
8640
8643
|
var opsFor = (type) => type === "number" ? NUM_OPS : STR_OPS;
|
|
8641
8644
|
var isMultiOp = (op) => op === "isAnyOf";
|
|
8645
|
+
var filterTypeOf = (col) => {
|
|
8646
|
+
const ft = col && col.filterType;
|
|
8647
|
+
if (ft === "number" || ft === "string") return ft;
|
|
8648
|
+
return col && col.type === "number" ? "number" : "string";
|
|
8649
|
+
};
|
|
8642
8650
|
var getColVal = (col, row) => col && col.valueGetter ? col.valueGetter(row) : row == null ? void 0 : row[col && col.field];
|
|
8643
8651
|
var diffValueNode = (col, v, row) => col.renderCell ? col.renderCell(v, row) : col.valueFormatter ? col.valueFormatter(v, row) : v == null ? "" : v;
|
|
8644
8652
|
function renderDiffCell(col, val, row) {
|
|
@@ -8721,7 +8729,10 @@ function runDatatableQuery(rows, query, options = {}) {
|
|
|
8721
8729
|
let out = Array.isArray(rows) ? rows : [];
|
|
8722
8730
|
const quick = String(q.quickFilter || "").trim().toLowerCase();
|
|
8723
8731
|
if (quick) out = out.filter((r2) => searchFields.some((f) => String(gv(f, r2) ?? "").toLowerCase().includes(quick)));
|
|
8724
|
-
for (const f of q.filters || [])
|
|
8732
|
+
for (const f of q.filters || []) {
|
|
8733
|
+
const fc = cols.find((c) => c.field === f.field);
|
|
8734
|
+
out = out.filter((r2) => testFilter(gv(f.field, r2), f.op, f.value, filterTypeOf(fc)));
|
|
8735
|
+
}
|
|
8725
8736
|
if (q.sort && q.sort.field) {
|
|
8726
8737
|
const { field, dir } = q.sort, numeric = typeOf(field) === "number";
|
|
8727
8738
|
out = [...out].sort((a, b) => {
|
|
@@ -9539,7 +9550,7 @@ function Datatable({
|
|
|
9539
9550
|
for (const f of filters) {
|
|
9540
9551
|
const col = colByField[f.field];
|
|
9541
9552
|
if (!col) continue;
|
|
9542
|
-
out = out.filter((r2) => testFilter(getColVal(col, r2), f.op, f.value, col
|
|
9553
|
+
out = out.filter((r2) => testFilter(getColVal(col, r2), f.op, f.value, filterTypeOf(col)));
|
|
9543
9554
|
}
|
|
9544
9555
|
if (sort) {
|
|
9545
9556
|
const col = colByField[sort.field];
|
|
@@ -9857,7 +9868,7 @@ function Datatable({
|
|
|
9857
9868
|
}
|
|
9858
9869
|
function addFilter(field) {
|
|
9859
9870
|
const col = colByField[field] || cols[0];
|
|
9860
|
-
setFilters((f) => [...f, { id: Date.now() + Math.random(), field: col.field, op: opsFor(col
|
|
9871
|
+
setFilters((f) => [...f, { id: Date.now() + Math.random(), field: col.field, op: opsFor(filterTypeOf(col))[0].value, value: "" }]);
|
|
9861
9872
|
}
|
|
9862
9873
|
function setPin(field, side) {
|
|
9863
9874
|
setPins((p) => {
|
|
@@ -10487,7 +10498,22 @@ function Datatable({
|
|
|
10487
10498
|
// async Combobox, …) and drives the lifecycle via commit/cancel. Wrapped in
|
|
10488
10499
|
// .twc-dt__editor-wrap so inline clicks (and any .twc-pop portal dropdown) don't
|
|
10489
10500
|
// trip the outside-click auto-cancel.
|
|
10490
|
-
|
|
10501
|
+
// #273: the wrapper handles Escape → cancel so it works for every custom editor without
|
|
10502
|
+
// each having to wire a keydown (they only get commit/cancel). A custom control that
|
|
10503
|
+
// wants Escape itself (e.g. to close its own open dropdown) stops propagation first.
|
|
10504
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10505
|
+
"div",
|
|
10506
|
+
{
|
|
10507
|
+
className: "twc-dt__editor-wrap",
|
|
10508
|
+
onKeyDown: (e) => {
|
|
10509
|
+
if (e.key === "Escape") {
|
|
10510
|
+
e.stopPropagation();
|
|
10511
|
+
cancelEdit();
|
|
10512
|
+
}
|
|
10513
|
+
},
|
|
10514
|
+
children: c.renderEditCell({ value: editing.value, row, field: c.field, commit: (v) => commitEdit(v), cancel: cancelEdit })
|
|
10515
|
+
}
|
|
10516
|
+
)
|
|
10491
10517
|
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
10492
10518
|
EditCell,
|
|
10493
10519
|
{
|
|
@@ -11672,7 +11698,7 @@ function Datatable({
|
|
|
11672
11698
|
] }),
|
|
11673
11699
|
filters.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__empty", style: { padding: "16px 12px" }, children: "No filters applied" }) : filters.map((f) => {
|
|
11674
11700
|
const col = colByField[f.field] || cols[0];
|
|
11675
|
-
const ops = opsFor(col
|
|
11701
|
+
const ops = opsFor(filterTypeOf(col));
|
|
11676
11702
|
const op = ops.find((o) => o.value === f.op) || ops[0];
|
|
11677
11703
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__frow", children: [
|
|
11678
11704
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__f-col", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -11684,7 +11710,7 @@ function Datatable({
|
|
|
11684
11710
|
options: filterableCols.map((c) => ({ value: c.field, label: c.headerName })),
|
|
11685
11711
|
onChange: (v) => {
|
|
11686
11712
|
const nc = colByField[v];
|
|
11687
|
-
setFilters((arr) => arr.map((x) => x.id === f.id ? { ...x, field: v, op: opsFor(nc
|
|
11713
|
+
setFilters((arr) => arr.map((x) => x.id === f.id ? { ...x, field: v, op: opsFor(filterTypeOf(nc))[0].value, value: "" } : x));
|
|
11688
11714
|
}
|
|
11689
11715
|
}
|
|
11690
11716
|
) }),
|
|
@@ -11723,7 +11749,7 @@ function Datatable({
|
|
|
11723
11749
|
Input,
|
|
11724
11750
|
{
|
|
11725
11751
|
size: "sm",
|
|
11726
|
-
type: col
|
|
11752
|
+
type: filterTypeOf(col) === "number" ? "number" : "text",
|
|
11727
11753
|
placeholder: "Value",
|
|
11728
11754
|
value: f.value,
|
|
11729
11755
|
onChange: (e) => setFilters((arr) => arr.map((x) => x.id === f.id ? { ...x, value: e.target.value } : x))
|