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/CHANGELOG.md +15 -0
- package/dist/index.cjs +53 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.mjs +53 -12
- package/dist/index.mjs.map +1 -1
- package/llms.txt +1 -0
- package/package.json +1 -1
- package/styles/twico-ui.css +7 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,21 @@
|
|
|
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.21.1](https://github.com/EncryptionL/twico-ui/compare/v1.21.0...v1.21.1) (2026-07-29)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **datatable:** auto-fit filter panel field widths to the widest label ([29ca74c](https://github.com/EncryptionL/twico-ui/commit/29ca74cd89fde500ca024f574488a59feaa87ee0)), closes [#289](https://github.com/EncryptionL/twico-ui/issues/289)
|
|
11
|
+
* **overlay:** stack tooltips below toasts, and dropdowns above ([7236003](https://github.com/EncryptionL/twico-ui/commit/7236003bbf97f73b7440abd89b39aa846b02edc1)), closes [#288](https://github.com/EncryptionL/twico-ui/issues/288)
|
|
12
|
+
|
|
13
|
+
# [1.21.0](https://github.com/EncryptionL/twico-ui/compare/v1.20.2...v1.21.0) (2026-07-28)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Features
|
|
17
|
+
|
|
18
|
+
* **datatable:** add toolbarActions slot for custom toolbar controls ([c1c3142](https://github.com/EncryptionL/twico-ui/commit/c1c3142787cb2a21811b16d6774f0e1f2c6045b9)), closes [#286](https://github.com/EncryptionL/twico-ui/issues/286)
|
|
19
|
+
|
|
5
20
|
## [1.20.2](https://github.com/EncryptionL/twico-ui/compare/v1.20.1...v1.20.2) (2026-07-24)
|
|
6
21
|
|
|
7
22
|
|
package/dist/index.cjs
CHANGED
|
@@ -5488,7 +5488,7 @@ function ColorPicker({
|
|
|
5488
5488
|
role: "dialog",
|
|
5489
5489
|
"aria-modal": "true",
|
|
5490
5490
|
"aria-label": "Color picker",
|
|
5491
|
-
style: { position: "fixed", left: coords.left, right: "auto", top: coords.top, bottom: coords.bottom, zIndex: "var(--z-
|
|
5491
|
+
style: { position: "fixed", left: coords.left, right: "auto", top: coords.top, bottom: coords.bottom, zIndex: "var(--z-floating)" },
|
|
5492
5492
|
children: [
|
|
5493
5493
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
5494
5494
|
"div",
|
|
@@ -5966,7 +5966,7 @@ function Combobox({
|
|
|
5966
5966
|
role: "listbox",
|
|
5967
5967
|
ref: popRef,
|
|
5968
5968
|
"data-placement": coords.flip ? "top" : "bottom",
|
|
5969
|
-
style: { position: "fixed", left: coords.left, top: coords.top, bottom: coords.bottom, width: coords.width, right: "auto", zIndex: "var(--z-
|
|
5969
|
+
style: { position: "fixed", left: coords.left, top: coords.top, bottom: coords.bottom, width: coords.width, right: "auto", zIndex: "var(--z-floating)" },
|
|
5970
5970
|
children: popInner
|
|
5971
5971
|
}
|
|
5972
5972
|
),
|
|
@@ -6853,7 +6853,7 @@ function Select({
|
|
|
6853
6853
|
ref: popRef,
|
|
6854
6854
|
"data-state": popState,
|
|
6855
6855
|
"data-placement": coords.flip ? "top" : "bottom",
|
|
6856
|
-
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-
|
|
6856
|
+
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)" },
|
|
6857
6857
|
children: popInner
|
|
6858
6858
|
}
|
|
6859
6859
|
),
|
|
@@ -7620,7 +7620,7 @@ function MultiSelect({
|
|
|
7620
7620
|
className: "twc-pop twc-pop--portal",
|
|
7621
7621
|
ref: popRef,
|
|
7622
7622
|
"data-placement": coords.flip ? "top" : "bottom",
|
|
7623
|
-
style: { position: "fixed", left: coords.left, top: coords.top, bottom: coords.bottom, width: coords.width, right: "auto", zIndex: "var(--z-
|
|
7623
|
+
style: { position: "fixed", left: coords.left, top: coords.top, bottom: coords.bottom, width: coords.width, right: "auto", zIndex: "var(--z-floating)" },
|
|
7624
7624
|
children: popInner
|
|
7625
7625
|
}
|
|
7626
7626
|
),
|
|
@@ -8128,6 +8128,8 @@ var DT_CSS = `
|
|
|
8128
8128
|
/* Toolbar */
|
|
8129
8129
|
.twc-dt__toolbar { position: relative; z-index: 10; display: flex; align-items: center; gap: 6px; padding: 8px 10px;
|
|
8130
8130
|
border-bottom: var(--border-thin) solid var(--color-divider); flex-wrap: wrap; }
|
|
8131
|
+
/* #286: host-supplied leading toolbar slot \u2014 a flex cluster so multiple buttons align with the built-ins. */
|
|
8132
|
+
.twc-dt__toolbar-actions { display: inline-flex; align-items: center; gap: 6px; }
|
|
8131
8133
|
/* z-index above the scroll area's sticky header (z:3) so a toolbar button's
|
|
8132
8134
|
hover tooltip (a ::after that hangs below the bar) paints over the table
|
|
8133
8135
|
instead of being covered by the header/first rows. */
|
|
@@ -8525,9 +8527,14 @@ th.twc-dt__rownum .twc-dt__th-inner { padding-inline: 8px; gap: 2px; justify-con
|
|
|
8525
8527
|
|
|
8526
8528
|
/* Filter panel */
|
|
8527
8529
|
.twc-dt__filters { width: 580px; max-width: calc(100vw - 32px); }
|
|
8528
|
-
|
|
8529
|
-
|
|
8530
|
-
.twc-
|
|
8530
|
+
/* #289: wrap is a safety net \u2014 a beyond-cap label or the narrow responsive panel drops the value input
|
|
8531
|
+
to its own line instead of clipping the remove button; no effect in the normal (capped) case. */
|
|
8532
|
+
.twc-dt__frow { display: flex; align-items: center; gap: 6px; padding: 5px 4px; flex-wrap: wrap; }
|
|
8533
|
+
/* #289: column-field auto-fits the widest header label \u2014 JS writes --twc-dt-fcol-w (measured, clamped),
|
|
8534
|
+
the max-width is the hard backstop that keeps the value input above its 140px floor inside the 580px
|
|
8535
|
+
panel even if the var is stale/too large. Fallback 118px = the previous fixed behavior. */
|
|
8536
|
+
.twc-dt__f-col { flex: none; width: var(--twc-dt-fcol-w, 118px); min-width: 118px; max-width: 210px; }
|
|
8537
|
+
.twc-dt__f-op { flex: none; width: var(--twc-dt-fop-w, 118px); min-width: 118px; max-width: 170px; }
|
|
8531
8538
|
.twc-dt__f-val { flex: 1; min-width: 140px; }
|
|
8532
8539
|
.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; }
|
|
8533
8540
|
.twc-dt__frm-x:hover { background: var(--color-danger-subtle); color: var(--color-danger-subtle-fg); }
|
|
@@ -8642,6 +8649,7 @@ var NUM_OPS = [
|
|
|
8642
8649
|
];
|
|
8643
8650
|
var opsFor = (type) => type === "number" ? NUM_OPS : STR_OPS;
|
|
8644
8651
|
var isMultiOp = (op) => op === "isAnyOf";
|
|
8652
|
+
var ALL_OP_LABELS = [...new Set([...STR_OPS, ...NUM_OPS].map((o) => o.label))];
|
|
8645
8653
|
var filterTypeOf = (col) => {
|
|
8646
8654
|
const ft = col && col.filterType;
|
|
8647
8655
|
if (ft === "number" || ft === "string") return ft;
|
|
@@ -9082,6 +9090,7 @@ function Datatable({
|
|
|
9082
9090
|
searchable = true,
|
|
9083
9091
|
quickFilter,
|
|
9084
9092
|
onQuickFilterChange,
|
|
9093
|
+
toolbarActions,
|
|
9085
9094
|
rowPinning = false,
|
|
9086
9095
|
rowReorder = false,
|
|
9087
9096
|
rowResize = false,
|
|
@@ -9313,6 +9322,8 @@ function Datatable({
|
|
|
9313
9322
|
};
|
|
9314
9323
|
}, []);
|
|
9315
9324
|
const scrollRef = React51__namespace.default.useRef(null);
|
|
9325
|
+
const filterPanelRef = React51__namespace.default.useRef(null);
|
|
9326
|
+
const measureCanvas = React51__namespace.default.useRef(null);
|
|
9316
9327
|
const [scrollTop, setScrollTop] = React51__namespace.default.useState(0);
|
|
9317
9328
|
const [viewportH, setViewportH] = React51__namespace.default.useState(0);
|
|
9318
9329
|
const [ovTip, setOvTip] = React51__namespace.default.useState(null);
|
|
@@ -10346,7 +10357,36 @@ function Datatable({
|
|
|
10346
10357
|
] });
|
|
10347
10358
|
}
|
|
10348
10359
|
const tableMinWidth = leadW + ordered.reduce((a, c) => a + widthOf(c), 0);
|
|
10349
|
-
const filterableCols = cols.filter((c) => c.filterable);
|
|
10360
|
+
const filterableCols = React51__namespace.default.useMemo(() => cols.filter((c) => c.filterable), [cols]);
|
|
10361
|
+
React51__namespace.default.useEffect(() => {
|
|
10362
|
+
const el = filterPanelRef.current;
|
|
10363
|
+
if (panel !== "filters" || !el || typeof document === "undefined") return void 0;
|
|
10364
|
+
const measure = () => {
|
|
10365
|
+
if (!el.isConnected) return;
|
|
10366
|
+
const trigger = el.querySelector(".twc-sel__trigger");
|
|
10367
|
+
const cs = getComputedStyle(trigger || el);
|
|
10368
|
+
const ctx = (measureCanvas.current || (measureCanvas.current = document.createElement("canvas"))).getContext("2d");
|
|
10369
|
+
if (!ctx) return;
|
|
10370
|
+
ctx.font = cs.font || `${cs.fontStyle} ${cs.fontWeight} ${cs.fontSize}/${cs.lineHeight} ${cs.fontFamily}`;
|
|
10371
|
+
const pad2 = trigger ? (parseFloat(cs.paddingLeft) || 0) + (parseFloat(cs.paddingRight) || 0) : 24;
|
|
10372
|
+
const chrome = pad2 + 8 + 16 + 4;
|
|
10373
|
+
const widest = (labels) => labels.reduce((m, l) => Math.max(m, ctx.measureText(String(l)).width), 0);
|
|
10374
|
+
const colCap = Math.max(118, Math.min(210, el.clientWidth - 118 - 30 - 140 - 3 * 6 - 2 * 4));
|
|
10375
|
+
const colW = Math.min(colCap, Math.max(118, Math.ceil(widest(filterableCols.map((c) => c.headerName ?? c.field)) + chrome)));
|
|
10376
|
+
const opW = Math.min(170, Math.max(118, Math.ceil(widest(ALL_OP_LABELS) + chrome)));
|
|
10377
|
+
if (Number.isFinite(colW)) el.style.setProperty("--twc-dt-fcol-w", `${colW}px`);
|
|
10378
|
+
if (Number.isFinite(opW)) el.style.setProperty("--twc-dt-fop-w", `${opW}px`);
|
|
10379
|
+
};
|
|
10380
|
+
measure();
|
|
10381
|
+
document.fonts?.ready?.then?.(measure).catch?.(() => {
|
|
10382
|
+
});
|
|
10383
|
+
let ro;
|
|
10384
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
10385
|
+
ro = new ResizeObserver(measure);
|
|
10386
|
+
ro.observe(el);
|
|
10387
|
+
}
|
|
10388
|
+
return () => ro?.disconnect();
|
|
10389
|
+
}, [panel, filterableCols, filters.length]);
|
|
10350
10390
|
const orderIdxOf = (f) => {
|
|
10351
10391
|
const i = order.indexOf(f);
|
|
10352
10392
|
return i === -1 ? 9999 : i;
|
|
@@ -10664,6 +10704,7 @@ function Datatable({
|
|
|
10664
10704
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-dt ${className}`, ref: rootRef, "data-density": density, "data-resizing": resizing || void 0, ...rest, children: [
|
|
10665
10705
|
__twcStyles,
|
|
10666
10706
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__toolbar", "data-compact": compact || void 0, children: [
|
|
10707
|
+
toolbarActions != null ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__toolbar-actions", children: toolbarActions }) : null,
|
|
10667
10708
|
(batchActions.length || hasBatchEditor) && selected.size > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__batch", children: [
|
|
10668
10709
|
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dt__batch-x", onClick: clearSelection, "aria-label": "Clear selection", children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.x }) }),
|
|
10669
10710
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-dt__batch-count", children: [
|
|
@@ -11715,7 +11756,7 @@ function Datatable({
|
|
|
11715
11756
|
] })
|
|
11716
11757
|
] });
|
|
11717
11758
|
})() : null,
|
|
11718
|
-
panel === "filters" && panelPos ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__pop twc-dt__filters", style: { top: panelPos.top, left: panelPos.left }, children: [
|
|
11759
|
+
panel === "filters" && panelPos ? /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: filterPanelRef, className: "twc-dt__pop twc-dt__filters", style: { top: panelPos.top, left: panelPos.left }, children: [
|
|
11719
11760
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__panel-head", children: [
|
|
11720
11761
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__panel-title", children: "Filters" }),
|
|
11721
11762
|
filters.length ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dt__link", onClick: () => setFilters([]), children: "Clear all" }) : null
|
|
@@ -12588,7 +12629,7 @@ function DatePicker({
|
|
|
12588
12629
|
role: "dialog",
|
|
12589
12630
|
"aria-modal": "true",
|
|
12590
12631
|
"aria-label": "Choose date",
|
|
12591
|
-
style: { position: "fixed", left: coords.left, right: "auto", top: coords.top, bottom: coords.bottom, zIndex: "var(--z-
|
|
12632
|
+
style: { position: "fixed", left: coords.left, right: "auto", top: coords.top, bottom: coords.bottom, zIndex: "var(--z-floating)" },
|
|
12592
12633
|
children: [
|
|
12593
12634
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dp__head", children: [
|
|
12594
12635
|
/* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m15 18-6-6 6-6" }) }) }),
|
|
@@ -13165,7 +13206,7 @@ function DateRangePicker({
|
|
|
13165
13206
|
role: "dialog",
|
|
13166
13207
|
"aria-modal": "true",
|
|
13167
13208
|
"aria-label": "Choose date range",
|
|
13168
|
-
style: { position: "fixed", left: coords.left, right: "auto", top: coords.top, bottom: coords.bottom, zIndex: "var(--z-
|
|
13209
|
+
style: { position: "fixed", left: coords.left, right: "auto", top: coords.top, bottom: coords.bottom, zIndex: "var(--z-floating)" },
|
|
13169
13210
|
children: [
|
|
13170
13211
|
presetItems.length ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-drp__presets", children: presetItems.map((p, i) => /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-drp__preset", onClick: () => applyPreset(p), children: p.label }, i)) }) : null,
|
|
13171
13212
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-drp__cal", children: [
|
|
@@ -13694,7 +13735,7 @@ function TimePicker({
|
|
|
13694
13735
|
role: "dialog",
|
|
13695
13736
|
"aria-modal": "true",
|
|
13696
13737
|
"aria-label": "Choose time",
|
|
13697
|
-
style: { position: "fixed", left: coords.left, right: "auto", top: coords.top, bottom: coords.bottom, zIndex: "var(--z-
|
|
13738
|
+
style: { position: "fixed", left: coords.left, right: "auto", top: coords.top, bottom: coords.bottom, zIndex: "var(--z-floating)" },
|
|
13698
13739
|
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-tp__cols", children: columns.map((col) => {
|
|
13699
13740
|
const firstTab = col.items.find((it) => it.selected) || col.items.find((it) => !it.disabled);
|
|
13700
13741
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-tp__col", role: "listbox", "aria-label": col.aria, "data-col": col.key, children: [
|