twico-ui 1.13.0 → 1.14.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 +79 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.mjs +79 -14
- package/dist/index.mjs.map +1 -1
- package/llms.txt +3 -0
- 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.14.1](https://github.com/EncryptionL/twico-ui/compare/v1.14.0...v1.14.1) (2026-07-14)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **styles:** input renders invisibly under React 19 hoist dedup; add Datatable external-search + renderEditCell ([#234](https://github.com/EncryptionL/twico-ui/issues/234), [#235](https://github.com/EncryptionL/twico-ui/issues/235), [#236](https://github.com/EncryptionL/twico-ui/issues/236)) ([f661ea9](https://github.com/EncryptionL/twico-ui/commit/f661ea90dab1bf4b97ee02e8f103fb44ce668f43)), closes [#232](https://github.com/EncryptionL/twico-ui/issues/232)
|
|
11
|
+
|
|
12
|
+
# [1.14.0](https://github.com/EncryptionL/twico-ui/compare/v1.13.0...v1.14.0) (2026-07-13)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* **datatable:** async/searchable "is any of" filter options via loadValueOptions ([#232](https://github.com/EncryptionL/twico-ui/issues/232)) ([2db2b32](https://github.com/EncryptionL/twico-ui/commit/2db2b3212bcda8cdea9430b6766f02a2b3dd0048)), closes [#208](https://github.com/EncryptionL/twico-ui/issues/208)
|
|
18
|
+
|
|
5
19
|
# [1.13.0](https://github.com/EncryptionL/twico-ui/compare/v1.12.0...v1.13.0) (2026-07-13)
|
|
6
20
|
|
|
7
21
|
|
package/dist/index.cjs
CHANGED
|
@@ -7091,7 +7091,8 @@ var FIELD_CSS2 = `
|
|
|
7091
7091
|
.twc-field__req { color: var(--color-danger); }
|
|
7092
7092
|
.twc-field__hint { font-size: var(--text-xs); color: var(--color-text-muted); }
|
|
7093
7093
|
.twc-field__error { font-size: var(--text-xs); color: var(--color-danger-subtle-fg); font-weight: var(--font-medium); }
|
|
7094
|
-
|
|
7094
|
+
`;
|
|
7095
|
+
var INPUT_EXTRA_CSS = `
|
|
7095
7096
|
.twc-input {
|
|
7096
7097
|
--_h: var(--control-h-md);
|
|
7097
7098
|
display: flex; align-items: center; gap: var(--space-2);
|
|
@@ -7100,6 +7101,7 @@ var FIELD_CSS2 = `
|
|
|
7100
7101
|
background: var(--color-surface);
|
|
7101
7102
|
border: var(--border-thin) solid var(--color-border);
|
|
7102
7103
|
border-radius: var(--radius-md);
|
|
7104
|
+
overflow: hidden;
|
|
7103
7105
|
transition: border-color var(--duration-fast) var(--ease-standard),
|
|
7104
7106
|
box-shadow var(--duration-fast) var(--ease-standard),
|
|
7105
7107
|
background-color var(--duration-fast) var(--ease-standard);
|
|
@@ -7133,9 +7135,6 @@ var FIELD_CSS2 = `
|
|
|
7133
7135
|
.twc-input__reveal:hover { background: var(--color-surface-sunken); color: var(--color-text); }
|
|
7134
7136
|
.twc-input__reveal:focus-visible { outline: none; box-shadow: var(--ring); }
|
|
7135
7137
|
.twc-input__reveal svg { width: 17px; height: 17px; }
|
|
7136
|
-
`;
|
|
7137
|
-
var INPUT_EXTRA_CSS = `
|
|
7138
|
-
.twc-input { overflow: hidden; }
|
|
7139
7138
|
.twc-input__addon { align-self: stretch; display: inline-flex; align-items: center; padding-inline: var(--space-3);
|
|
7140
7139
|
background: var(--color-surface-sunken); color: var(--color-text-muted); font-size: var(--text-sm);
|
|
7141
7140
|
font-weight: var(--font-semibold); white-space: nowrap; flex: none; }
|
|
@@ -8646,6 +8645,53 @@ function Caret({ pos }) {
|
|
|
8646
8645
|
const left = Math.max(12, Math.min(pos.anchorX - pos.left, pos.width - 20));
|
|
8647
8646
|
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__caret", style: { left } });
|
|
8648
8647
|
}
|
|
8648
|
+
function AsyncFilterValue({ col, value, onChange }) {
|
|
8649
|
+
const [opts, setOpts] = React51__namespace.default.useState([]);
|
|
8650
|
+
const [loading, setLoading] = React51__namespace.default.useState(false);
|
|
8651
|
+
const reqRef = React51__namespace.default.useRef(0);
|
|
8652
|
+
const debRef = React51__namespace.default.useRef();
|
|
8653
|
+
const load = React51__namespace.default.useCallback((query) => {
|
|
8654
|
+
const id = ++reqRef.current;
|
|
8655
|
+
setLoading(true);
|
|
8656
|
+
Promise.resolve(col.loadValueOptions(query)).then(
|
|
8657
|
+
(res) => {
|
|
8658
|
+
if (reqRef.current === id) {
|
|
8659
|
+
setOpts((Array.isArray(res) ? res : []).map((o) => typeof o === "string" ? { value: o, label: o } : o));
|
|
8660
|
+
setLoading(false);
|
|
8661
|
+
}
|
|
8662
|
+
},
|
|
8663
|
+
() => {
|
|
8664
|
+
if (reqRef.current === id) setLoading(false);
|
|
8665
|
+
}
|
|
8666
|
+
);
|
|
8667
|
+
}, [col]);
|
|
8668
|
+
React51__namespace.default.useEffect(() => {
|
|
8669
|
+
load("");
|
|
8670
|
+
return () => clearTimeout(debRef.current);
|
|
8671
|
+
}, [load]);
|
|
8672
|
+
const onInput = React51__namespace.default.useCallback((q) => {
|
|
8673
|
+
clearTimeout(debRef.current);
|
|
8674
|
+
debRef.current = setTimeout(() => load(q), 250);
|
|
8675
|
+
}, [load]);
|
|
8676
|
+
const selected = Array.isArray(value) ? value : [];
|
|
8677
|
+
const merged = React51__namespace.default.useMemo(() => {
|
|
8678
|
+
const seen2 = new Set(opts.map((o) => o.value));
|
|
8679
|
+
return [...selected.filter((v) => !seen2.has(v)).map((v) => ({ value: v, label: String(v) })), ...opts];
|
|
8680
|
+
}, [opts, selected]);
|
|
8681
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8682
|
+
MultiSelect,
|
|
8683
|
+
{
|
|
8684
|
+
portal: true,
|
|
8685
|
+
placeholder: "Any of\u2026",
|
|
8686
|
+
value: selected,
|
|
8687
|
+
options: merged,
|
|
8688
|
+
filter: false,
|
|
8689
|
+
loading,
|
|
8690
|
+
onInputChange: onInput,
|
|
8691
|
+
onChange
|
|
8692
|
+
}
|
|
8693
|
+
);
|
|
8694
|
+
}
|
|
8649
8695
|
function EditCell({ col, value, options, onChange, onCommit, onCommitValue, onCancel, onKeyDown }) {
|
|
8650
8696
|
const ref = React51__namespace.default.useRef(null);
|
|
8651
8697
|
const isSelect = col.editType === "select" || options && col.editType !== "text";
|
|
@@ -8846,6 +8892,9 @@ function Datatable({
|
|
|
8846
8892
|
rowGrouping = [],
|
|
8847
8893
|
rowNumbers = false,
|
|
8848
8894
|
searchFields = null,
|
|
8895
|
+
searchable = true,
|
|
8896
|
+
quickFilter,
|
|
8897
|
+
onQuickFilterChange,
|
|
8849
8898
|
rowPinning = false,
|
|
8850
8899
|
rowReorder = false,
|
|
8851
8900
|
rowResize = false,
|
|
@@ -8928,7 +8977,13 @@ function Datatable({
|
|
|
8928
8977
|
return { left, right };
|
|
8929
8978
|
});
|
|
8930
8979
|
const [density, setDensity] = React51__namespace.default.useState(densityProp);
|
|
8931
|
-
const [
|
|
8980
|
+
const [internalQuick, setInternalQuick] = React51__namespace.default.useState("");
|
|
8981
|
+
const quick = quickFilter !== void 0 ? quickFilter : internalQuick;
|
|
8982
|
+
const commitQuick = (v) => {
|
|
8983
|
+
onQuickFilterChange?.(v);
|
|
8984
|
+
if (quickFilter === void 0) setInternalQuick(v);
|
|
8985
|
+
commitPage(0);
|
|
8986
|
+
};
|
|
8932
8987
|
const [selected, setSelected] = React51__namespace.default.useState(() => /* @__PURE__ */ new Set());
|
|
8933
8988
|
const [activeRow, setActiveRow] = React51__namespace.default.useState(null);
|
|
8934
8989
|
const [activeCell, setActiveCell] = React51__namespace.default.useState(null);
|
|
@@ -9808,7 +9863,7 @@ function Datatable({
|
|
|
9808
9863
|
setSelected(/* @__PURE__ */ new Set());
|
|
9809
9864
|
}
|
|
9810
9865
|
const [editing, setEditing] = React51__namespace.default.useState(null);
|
|
9811
|
-
const isColEditable = (c) => c.type !== "actions" &&
|
|
9866
|
+
const isColEditable = (c) => c.type !== "actions" && c.editable !== false && (c.editable === true || c.renderEditCell != null || editMode);
|
|
9812
9867
|
function beginEdit(rowK, col, row) {
|
|
9813
9868
|
if (!isColEditable(col)) return;
|
|
9814
9869
|
setEditing({ key: rowK, field: col.field, value: row[col.field] ?? "" });
|
|
@@ -10139,7 +10194,13 @@ function Datatable({
|
|
|
10139
10194
|
!checkboxSelection && reorderable && ci === 0 && !isEditing ? /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { display: "inline-flex", alignItems: "center", gap: 6, maxWidth: "100%" }, children: [
|
|
10140
10195
|
rowHandle(k, midIdx, row),
|
|
10141
10196
|
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { overflow: "hidden", textOverflow: "ellipsis" }, children: isActions ? renderActions(c, row) : c.renderCell ? c.renderCell(val, row) : c.valueFormatter ? c.valueFormatter(val, row) : val })
|
|
10142
|
-
] }) : isEditing ?
|
|
10197
|
+
] }) : isEditing ? c.renderEditCell ? (
|
|
10198
|
+
// #236: full escape hatch — the host drops in its own editor (searchable/creatable/
|
|
10199
|
+
// async Combobox, …) and drives the lifecycle via commit/cancel. Wrapped in
|
|
10200
|
+
// .twc-dt__editor-wrap so inline clicks (and any .twc-pop portal dropdown) don't
|
|
10201
|
+
// trip the outside-click auto-cancel.
|
|
10202
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__editor-wrap", children: c.renderEditCell({ value: editing.value, row, field: c.field, commit: (v) => commitEdit(v), cancel: cancelEdit }) })
|
|
10203
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
10143
10204
|
EditCell,
|
|
10144
10205
|
{
|
|
10145
10206
|
col: c,
|
|
@@ -10429,13 +10490,10 @@ function Datatable({
|
|
|
10429
10490
|
}
|
|
10430
10491
|
)
|
|
10431
10492
|
] }) : null,
|
|
10432
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__search", children: [
|
|
10493
|
+
searchable ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__search", children: [
|
|
10433
10494
|
/* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.search }),
|
|
10434
|
-
/* @__PURE__ */ jsxRuntime.jsx("input", { placeholder: "Search\u2026", "aria-label": "Search rows", value: quick, onChange: (e) =>
|
|
10435
|
-
|
|
10436
|
-
commitPage(0);
|
|
10437
|
-
} })
|
|
10438
|
-
] })
|
|
10495
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { placeholder: "Search\u2026", "aria-label": "Search rows", value: quick, onChange: (e) => commitQuick(e.target.value) })
|
|
10496
|
+
] }) : null
|
|
10439
10497
|
] }),
|
|
10440
10498
|
!pivotActive && activeGroupBy.length ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__groupbar", children: [
|
|
10441
10499
|
/* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.group }),
|
|
@@ -11294,7 +11352,14 @@ function Datatable({
|
|
|
11294
11352
|
}))
|
|
11295
11353
|
}
|
|
11296
11354
|
) }),
|
|
11297
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__f-val", children: op.noInput ? null : op.multi ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
11355
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__f-val", children: op.noInput ? null : op.multi ? col.loadValueOptions ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
11356
|
+
AsyncFilterValue,
|
|
11357
|
+
{
|
|
11358
|
+
col,
|
|
11359
|
+
value: f.value,
|
|
11360
|
+
onChange: (vals) => setFilters((arr) => arr.map((x) => x.id === f.id ? { ...x, value: vals } : x))
|
|
11361
|
+
}
|
|
11362
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
11298
11363
|
MultiSelect,
|
|
11299
11364
|
{
|
|
11300
11365
|
portal: true,
|