twico-ui 1.36.0 → 1.37.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/CHANGELOG.md +14 -0
- package/dist/index.cjs +30 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -3
- package/dist/index.d.ts +19 -3
- package/dist/index.mjs +30 -16
- package/dist/index.mjs.map +1 -1
- package/llms.txt +3 -1
- package/package.json +2 -2
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.37.0](https://github.com/EncryptionL/twico-ui/compare/v1.36.1...v1.37.0) (2026-09-11)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **overlay:** safer Dialog/Drawer defaults + Popover height clamp ([#371](https://github.com/EncryptionL/twico-ui/issues/371), [#372](https://github.com/EncryptionL/twico-ui/issues/372), [#373](https://github.com/EncryptionL/twico-ui/issues/373)) ([0f7a386](https://github.com/EncryptionL/twico-ui/commit/0f7a38656956bb9ef7cdd0331d2b5e6776aa7d7c))
|
|
11
|
+
|
|
12
|
+
## [1.36.1](https://github.com/EncryptionL/twico-ui/compare/v1.36.0...v1.36.1) (2026-09-09)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* **datatable:** runtime combine into a valueGetter/renderCell target ([#369](https://github.com/EncryptionL/twico-ui/issues/369)) ([6363f38](https://github.com/EncryptionL/twico-ui/commit/6363f38ffd2b754dc7be9ddb6f47cbfc9bab10e2)), closes [#338](https://github.com/EncryptionL/twico-ui/issues/338)
|
|
18
|
+
|
|
5
19
|
# [1.36.0](https://github.com/EncryptionL/twico-ui/compare/v1.35.0...v1.36.0) (2026-09-09)
|
|
6
20
|
|
|
7
21
|
|
package/dist/index.cjs
CHANGED
|
@@ -9381,7 +9381,7 @@ function Datatable({
|
|
|
9381
9381
|
for (const c of columnsProp) if (c && c.field != null) byField[c.field] = c;
|
|
9382
9382
|
return [DIFF_OP_COLUMN, ...columnsProp.map((c) => {
|
|
9383
9383
|
const cfg = combineCfg(userCombine[c.field] || c.combine);
|
|
9384
|
-
const base = cfg && !c.valueGetter ? { ...c, valueGetter: combineValueGetter(combineSrcCols(cfg, byField), cfg) } : c;
|
|
9384
|
+
const base = cfg && (!!userCombine[c.field] || !c.valueGetter) ? { ...c, valueGetter: combineValueGetter(combineSrcCols(cfg, byField), cfg) } : c;
|
|
9385
9385
|
return { ...base, renderCell: (val, row) => renderDiffCell(base, val, row) };
|
|
9386
9386
|
})];
|
|
9387
9387
|
},
|
|
@@ -9432,15 +9432,17 @@ function Datatable({
|
|
|
9432
9432
|
const cfg = combineCfg(userCombine[c.field] || c.combine);
|
|
9433
9433
|
if (!cfg) continue;
|
|
9434
9434
|
const srcCols = combineSrcCols(cfg, byField);
|
|
9435
|
+
const explicit = !!userCombine[c.field];
|
|
9436
|
+
const useJoin = explicit || !c.valueGetter;
|
|
9435
9437
|
out[i] = {
|
|
9436
9438
|
...c,
|
|
9437
9439
|
editable: false,
|
|
9438
9440
|
// the combined value is synthetic — inline editing would write to a phantom field
|
|
9439
|
-
valueGetter:
|
|
9440
|
-
//
|
|
9441
|
-
//
|
|
9442
|
-
//
|
|
9443
|
-
renderCell: c.renderCell
|
|
9441
|
+
valueGetter: useJoin ? combineValueGetter(srcCols, cfg) : c.valueGetter,
|
|
9442
|
+
// In diff mode the diff `columns` memo already wrapped renderCell in renderDiffCell (over the enriched
|
|
9443
|
+
// combined value) — keep that wrapper, or an EXPLICIT combine's `!explicit` short-circuit would strip the
|
|
9444
|
+
// diff arrows / old→new styling (#369 review). Declarative diff already preserved it (c.renderCell truthy).
|
|
9445
|
+
renderCell: isDiff ? c.renderCell : !explicit && c.renderCell || (useJoin ? ((value, row) => renderCombined(srcCols, row, cfg)) : void 0)
|
|
9444
9446
|
};
|
|
9445
9447
|
}
|
|
9446
9448
|
return out;
|
|
@@ -15431,6 +15433,10 @@ var DIALOG_CSS = `
|
|
|
15431
15433
|
.twc-dialog__close svg { width: 18px; height: 18px; }
|
|
15432
15434
|
.twc-dialog__body { padding: var(--space-4) var(--space-5); font-size: var(--text-sm); color: var(--color-text-muted); line-height: var(--leading-normal); }
|
|
15433
15435
|
.twc-dialog__footer { display: flex; gap: var(--space-2); justify-content: flex-end; padding: 0 var(--space-5) var(--space-5); }
|
|
15436
|
+
/* #372: header/body and body/footer rules (on by default). Per-region data-divider so the rule is
|
|
15437
|
+
suppressed when the region is empty (no footer; a header with only a close button and no title/description). */
|
|
15438
|
+
.twc-dialog__header[data-divider="true"] { padding-bottom: var(--space-4); border-bottom: var(--border-thin) solid var(--color-divider); }
|
|
15439
|
+
.twc-dialog__footer[data-divider="true"] { padding-top: var(--space-4); border-top: var(--border-thin) solid var(--color-divider); }
|
|
15434
15440
|
`;
|
|
15435
15441
|
function Dialog({
|
|
15436
15442
|
open,
|
|
@@ -15440,7 +15446,8 @@ function Dialog({
|
|
|
15440
15446
|
footer,
|
|
15441
15447
|
children,
|
|
15442
15448
|
size = "md",
|
|
15443
|
-
scrollBody =
|
|
15449
|
+
scrollBody = true,
|
|
15450
|
+
dividers = true,
|
|
15444
15451
|
closeOnBackdrop = true,
|
|
15445
15452
|
className = "",
|
|
15446
15453
|
...rest
|
|
@@ -15481,7 +15488,7 @@ function Dialog({
|
|
|
15481
15488
|
}, children: [
|
|
15482
15489
|
__twcStyles,
|
|
15483
15490
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { ref: dialogRef, className: `twc-dialog ${className}`, "data-state": state, "data-size": size, "data-scroll-body": scrollBody ? "true" : void 0, role: "dialog", "aria-modal": "true", tabIndex: -1, "aria-labelledby": title ? titleId : void 0, "aria-label": !title ? "Dialog" : void 0, "aria-describedby": description ? descId : void 0, ...rest, children: [
|
|
15484
|
-
title || description || onClose ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dialog__header", children: [
|
|
15491
|
+
title || description || onClose ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dialog__header", "data-divider": dividers && (title || description) && (children || footer) ? "true" : void 0, children: [
|
|
15485
15492
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dialog__titles", children: [
|
|
15486
15493
|
title ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dialog__title", id: titleId, children: title }) : null,
|
|
15487
15494
|
description ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dialog__desc", id: descId, children: description }) : null
|
|
@@ -15489,7 +15496,7 @@ function Dialog({
|
|
|
15489
15496
|
onClose ? /* @__PURE__ */ jsxRuntime.jsx("button", { className: "twc-dialog__close", onClick: onClose, "aria-label": "Close", type: "button", 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: "M18 6 6 18M6 6l12 12" }) }) }) : null
|
|
15490
15497
|
] }) : null,
|
|
15491
15498
|
children ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dialog__body", children }) : null,
|
|
15492
|
-
footer ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dialog__footer", children: footer }) : null
|
|
15499
|
+
footer ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dialog__footer", "data-divider": dividers && children ? "true" : void 0, children: footer }) : null
|
|
15493
15500
|
] })
|
|
15494
15501
|
] });
|
|
15495
15502
|
return renderPortal(overlay);
|
|
@@ -15589,7 +15596,11 @@ var DRAWER_CSS = `
|
|
|
15589
15596
|
.twc-drawer__close:hover { background: var(--color-surface-sunken); color: var(--color-text); }
|
|
15590
15597
|
.twc-drawer__close svg { width: 18px; height: 18px; }
|
|
15591
15598
|
.twc-drawer__body { flex: 1; overflow-y: auto; padding: var(--space-2) var(--space-5) var(--space-5); font-size: var(--text-sm); color: var(--color-text-muted); line-height: var(--leading-normal); }
|
|
15592
|
-
.twc-drawer__footer { display: flex; gap: var(--space-2); justify-content: flex-end; padding: var(--space-4) var(--space-5);
|
|
15599
|
+
.twc-drawer__footer { display: flex; gap: var(--space-2); justify-content: flex-end; padding: var(--space-4) var(--space-5); }
|
|
15600
|
+
/* #372: header/footer rules (on by default), consistent with Dialog. Per-region data-divider so an empty
|
|
15601
|
+
region grows no stray line (no footer; a header with only a close button and no title/description). */
|
|
15602
|
+
.twc-drawer__header[data-divider="true"] { border-bottom: var(--border-thin) solid var(--color-divider); }
|
|
15603
|
+
.twc-drawer__footer[data-divider="true"] { border-top: var(--border-thin) solid var(--color-divider); }
|
|
15593
15604
|
@media (prefers-reduced-motion: reduce) {
|
|
15594
15605
|
.twc-drawer__overlay[data-state], .twc-drawer[data-state] { animation-duration: 1ms; }
|
|
15595
15606
|
}
|
|
@@ -15605,6 +15616,7 @@ function Drawer({
|
|
|
15605
15616
|
width,
|
|
15606
15617
|
height,
|
|
15607
15618
|
closeOnBackdrop = true,
|
|
15619
|
+
dividers = true,
|
|
15608
15620
|
children,
|
|
15609
15621
|
className = "",
|
|
15610
15622
|
style,
|
|
@@ -15650,7 +15662,7 @@ function Drawer({
|
|
|
15650
15662
|
}, children: [
|
|
15651
15663
|
__twcStyles,
|
|
15652
15664
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { ref: panelRef, className: `twc-drawer ${className}`, "data-side": side, "data-state": state, role: "dialog", "aria-modal": "true", tabIndex: -1, "aria-labelledby": title ? titleId : void 0, "aria-label": !title ? "Drawer" : void 0, "aria-describedby": description ? descId : void 0, style: { ...dim ? sizeVar : null, ...style }, ...rest, children: [
|
|
15653
|
-
title || description || onClose ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-drawer__header", children: [
|
|
15665
|
+
title || description || onClose ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-drawer__header", "data-divider": dividers && (title || description) ? "true" : void 0, children: [
|
|
15654
15666
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-drawer__titles", children: [
|
|
15655
15667
|
title ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-drawer__title", id: titleId, children: title }) : null,
|
|
15656
15668
|
description ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-drawer__desc", id: descId, children: description }) : null
|
|
@@ -15658,7 +15670,7 @@ function Drawer({
|
|
|
15658
15670
|
onClose ? /* @__PURE__ */ jsxRuntime.jsx("button", { className: "twc-drawer__close", onClick: onClose, "aria-label": "Close", type: "button", 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: "M18 6 6 18M6 6l12 12" }) }) }) : null
|
|
15659
15671
|
] }) : null,
|
|
15660
15672
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-drawer__body", children }),
|
|
15661
|
-
footer ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-drawer__footer", children: footer }) : null
|
|
15673
|
+
footer ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-drawer__footer", "data-divider": dividers ? "true" : void 0, children: footer }) : null
|
|
15662
15674
|
] })
|
|
15663
15675
|
] });
|
|
15664
15676
|
return renderPortal(overlay);
|
|
@@ -16359,7 +16371,9 @@ var POPOVER_CSS = `
|
|
|
16359
16371
|
.twc-popover__arrow { position: absolute; width: 11px; height: 11px; background: var(--color-surface-raised);
|
|
16360
16372
|
border-left: var(--border-thin) solid var(--color-border); border-top: var(--border-thin) solid var(--color-border);
|
|
16361
16373
|
transform: rotate(45deg); }
|
|
16362
|
-
|
|
16374
|
+
/* #373: cap the panel to the room place() measured and scroll INSIDE the inner (not the panel \u2014 the panel
|
|
16375
|
+
must keep overflow visible so the absolutely-positioned arrow isn't clipped) so a tall panel's footer stays reachable. */
|
|
16376
|
+
.twc-popover__inner { padding: var(--space-4); font-size: var(--text-sm); color: var(--color-text-muted); line-height: var(--leading-normal); overflow-y: auto; }
|
|
16363
16377
|
.twc-popover__title { font-size: var(--text-sm); font-weight: var(--font-bold); color: var(--color-text); margin-bottom: 4px; }
|
|
16364
16378
|
`;
|
|
16365
16379
|
function Popover({
|
|
@@ -16421,7 +16435,7 @@ function Popover({
|
|
|
16421
16435
|
l = Math.max(M, Math.min(l, vw - w - M));
|
|
16422
16436
|
left = l;
|
|
16423
16437
|
arrow = { left: Math.min(Math.max(r2.left + r2.width / 2 - l - 5.5, 10), w - 20), [flip ? "bottom" : "top"]: -6 };
|
|
16424
|
-
return setPos({ top, bottom, left, width: w, flip, arrow });
|
|
16438
|
+
return setPos({ top, bottom, left, width: w, flip, arrow, maxHeight: flip ? spaceAbove : spaceBelow });
|
|
16425
16439
|
}
|
|
16426
16440
|
const ph = popRef.current ? popRef.current.offsetHeight : 120;
|
|
16427
16441
|
let onRight = placement === "right";
|
|
@@ -16433,7 +16447,7 @@ function Popover({
|
|
|
16433
16447
|
const cy = r2.top + r2.height / 2;
|
|
16434
16448
|
top = Math.max(M, Math.min(cy - ph / 2, vh - ph - M));
|
|
16435
16449
|
arrow = { top: Math.min(Math.max(cy - top - 5.5, 8), ph - 18), [onRight ? "left" : "right"]: -6 };
|
|
16436
|
-
setPos({ top, left, width: w, flip: false, arrow });
|
|
16450
|
+
setPos({ top, left, width: w, flip: false, arrow, maxHeight: vh - 2 * M });
|
|
16437
16451
|
}, [placement, align, width]);
|
|
16438
16452
|
React51__namespace.default.useEffect(() => {
|
|
16439
16453
|
if (!open) return;
|
|
@@ -16499,7 +16513,7 @@ function Popover({
|
|
|
16499
16513
|
children: [
|
|
16500
16514
|
__twcStyles,
|
|
16501
16515
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-popover__arrow", style: pos.arrow, "aria-hidden": "true" }),
|
|
16502
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-popover__inner", children: [
|
|
16516
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-popover__inner", style: { maxHeight: pos.maxHeight }, children: [
|
|
16503
16517
|
title ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-popover__title", id: `${popId}-title`, children: title }) : null,
|
|
16504
16518
|
children
|
|
16505
16519
|
] })
|