twico-ui 1.43.0 → 1.45.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 +19 -0
- package/dist/index.cjs +228 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +167 -3
- package/dist/index.d.ts +167 -3
- package/dist/index.mjs +228 -12
- package/dist/index.mjs.map +1 -1
- package/llms.txt +9 -0
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,25 @@
|
|
|
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.45.0](https://github.com/EncryptionL/twico-ui/compare/v1.44.0...v1.45.0) (2026-10-16)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **datatable:** lift getRowStyle's background off the <tr> instead of copying it ([e54165e](https://github.com/EncryptionL/twico-ui/commit/e54165e918dad9d8f0f819890ebb718684bdfc07)), closes [#242](https://github.com/EncryptionL/twico-ui/issues/242) [#481](https://github.com/EncryptionL/twico-ui/issues/481)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* **datatable:** getRowStyle / getRowClassName — row-level style hooks ([56a80e8](https://github.com/EncryptionL/twico-ui/commit/56a80e8c7adeb293923b5f2e490cf62234df3a3a)), closes [#345](https://github.com/EncryptionL/twico-ui/issues/345) [#242](https://github.com/EncryptionL/twico-ui/issues/242)
|
|
16
|
+
|
|
17
|
+
# [1.44.0](https://github.com/EncryptionL/twico-ui/compare/v1.43.0...v1.44.0) (2026-10-16)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
|
|
22
|
+
* **cardgrid,datatable:** selection + batch actions on CardGrid, disabledReason on batch actions ([dac8b30](https://github.com/EncryptionL/twico-ui/commit/dac8b30a36ad3387e09678435803dfaf474e02dd)), closes [#478](https://github.com/EncryptionL/twico-ui/issues/478) [#479](https://github.com/EncryptionL/twico-ui/issues/479) [#322](https://github.com/EncryptionL/twico-ui/issues/322) [399/#419](https://github.com/EncryptionL/twico-ui/issues/419) [pre-#460](https://github.com/pre-/issues/460)
|
|
23
|
+
|
|
5
24
|
# [1.43.0](https://github.com/EncryptionL/twico-ui/compare/v1.42.1...v1.43.0) (2026-10-07)
|
|
6
25
|
|
|
7
26
|
|
package/dist/index.cjs
CHANGED
|
@@ -7248,8 +7248,8 @@ function Currency({
|
|
|
7248
7248
|
}
|
|
7249
7249
|
function useFallbackName(ref, hasOwnName) {
|
|
7250
7250
|
const [needsFallback, setNeedsFallback] = React54__namespace.default.useState(false);
|
|
7251
|
-
const
|
|
7252
|
-
|
|
7251
|
+
const useIso2 = typeof document !== "undefined" ? React54__namespace.default.useLayoutEffect : React54__namespace.default.useEffect;
|
|
7252
|
+
useIso2(() => {
|
|
7253
7253
|
if (hasOwnName) {
|
|
7254
7254
|
setNeedsFallback(false);
|
|
7255
7255
|
return;
|
|
@@ -7265,7 +7265,6 @@ function useFallbackName(ref, hasOwnName) {
|
|
|
7265
7265
|
});
|
|
7266
7266
|
return !hasOwnName && needsFallback;
|
|
7267
7267
|
}
|
|
7268
|
-
typeof document !== "undefined" ? React54__namespace.default.useLayoutEffect : React54__namespace.default.useEffect;
|
|
7269
7268
|
var SELECT_CSS = `
|
|
7270
7269
|
.twc-field { display: flex; flex-direction: column; gap: var(--space-1-5); font-family: var(--font-sans); }
|
|
7271
7270
|
.twc-field__label { font-size: var(--text-sm); font-weight: var(--font-semibold); color: var(--color-text); display: flex; gap: 4px; align-items: center; }
|
|
@@ -9253,8 +9252,22 @@ var DT_CSS = `
|
|
|
9253
9252
|
.twc-dt__row:hover .twc-dt__row-resizer::after { background: var(--color-border-strong); }
|
|
9254
9253
|
.twc-dt__row-resizer:hover::after { background: var(--color-primary); }
|
|
9255
9254
|
|
|
9255
|
+
/* #481: the cell background reads --twc-dt-row-bg, which getRowStyle sets on the <tr>. It has to come
|
|
9256
|
+
through a custom property rather than straight off the row, because this rule paints an OPAQUE
|
|
9257
|
+
--color-surface on every cell: a background set on the <tr> would sit behind it and never show,
|
|
9258
|
+
which would make the commonest use of a row-style hook silently do nothing. Cells in a pinned
|
|
9259
|
+
COLUMN inherit it too, so a tinted row does not develop a hole where a sticky column scrolls over
|
|
9260
|
+
it.
|
|
9261
|
+
Layering: this rule is (0,1,0), the LOWEST specificity of any background in this sheet, so the
|
|
9262
|
+
row tint is the bottom layer above the plain surface and every built-in state covers it - hover,
|
|
9263
|
+
row selection, data-active, data-pinned-row, data-row-grabbed, the diff data-op washes, cell
|
|
9264
|
+
selection/active, inline editing (each (0,3,0), (0,4,0) for the pinned-column twins, or (0,2,0)
|
|
9265
|
+
for the cell-level ones) - and an inline per-cell cellStyle
|
|
9266
|
+
covers them all. That is the intended rule, not an accident of ordering: a row tint is a
|
|
9267
|
+
data-derived wash, and no data wash should be able to hide an interaction state. Consumers who
|
|
9268
|
+
need a tint that outranks those use getRowClassName and a rule of their own. */
|
|
9256
9269
|
.twc-dt__td { padding: 0 12px; height: var(--_rowh, 44px); border-bottom: var(--border-thin) solid var(--color-divider);
|
|
9257
|
-
font-size: var(--text-sm); color: var(--color-text); background: var(--color-surface);
|
|
9270
|
+
font-size: var(--text-sm); color: var(--color-text); background: var(--twc-dt-row-bg, var(--color-surface));
|
|
9258
9271
|
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 0; }
|
|
9259
9272
|
/* Wrap-text columns: content flows onto multiple lines (the row grows down) instead of
|
|
9260
9273
|
clipping to one line. height stays a per-row minimum, so single-line cells are unchanged. */
|
|
@@ -10021,6 +10034,8 @@ function Datatable({
|
|
|
10021
10034
|
onColumnVisibilityChange,
|
|
10022
10035
|
batchActions = [],
|
|
10023
10036
|
onRowSelectionChange,
|
|
10037
|
+
getRowStyle,
|
|
10038
|
+
getRowClassName,
|
|
10024
10039
|
showExport = false,
|
|
10025
10040
|
showDensity = false,
|
|
10026
10041
|
showPivot = false,
|
|
@@ -12596,7 +12611,17 @@ function Datatable({
|
|
|
12596
12611
|
const rowActive = selectionMode === "row" && activeRowVal === k;
|
|
12597
12612
|
const stickyStyle = pinSide === "top" ? { position: "sticky", top: headH, zIndex: 5 } : pinSide === "bottom" ? { position: "sticky", bottom: 0, zIndex: 5 } : void 0;
|
|
12598
12613
|
const h = rowHeights[k];
|
|
12599
|
-
const
|
|
12614
|
+
const userRowStyle = getRowStyle ? getRowStyle(row, ri) : void 0;
|
|
12615
|
+
const userRowClass = getRowClassName ? getRowClassName(row, ri) : void 0;
|
|
12616
|
+
const { background: _rowBgShorthand, backgroundColor: _rowBgColor, ...restRowStyle } = userRowStyle || {};
|
|
12617
|
+
const usable = (v) => typeof v === "string" && v.trim() !== "" ? v : void 0;
|
|
12618
|
+
const rowBg = usable(_rowBgShorthand) ?? usable(_rowBgColor);
|
|
12619
|
+
const rowStyle = {
|
|
12620
|
+
...restRowStyle,
|
|
12621
|
+
...rowBg != null ? { "--twc-dt-row-bg": rowBg } : {},
|
|
12622
|
+
...stickyStyle || {},
|
|
12623
|
+
...h ? { height: h } : {}
|
|
12624
|
+
};
|
|
12600
12625
|
const reorderable = canReorderRows && !pinSide;
|
|
12601
12626
|
const grabbed = rowGrab && rowGrab.key === k;
|
|
12602
12627
|
const grabTarget = rowGrab && !grabbed && midIdx != null && rowGrab.index === midIdx ? rowGrab.index >= keyIndexMid.get(rowGrab.key) ? "after" : "before" : void 0;
|
|
@@ -12604,7 +12629,7 @@ function Datatable({
|
|
|
12604
12629
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
12605
12630
|
"tr",
|
|
12606
12631
|
{
|
|
12607
|
-
className: "twc-dt__row",
|
|
12632
|
+
className: userRowClass ? `twc-dt__row ${userRowClass}` : "twc-dt__row",
|
|
12608
12633
|
role: "row",
|
|
12609
12634
|
"aria-rowindex": treeSeqByKey ? treeSeqByKey.get(k) + 2 : (paginated && !serverMode ? pageVal * sizeVal : 0) + ri + 2,
|
|
12610
12635
|
"aria-selected": (checkboxSelection ? sel : rowActive) || void 0,
|
|
@@ -12894,14 +12919,20 @@ function Datatable({
|
|
|
12894
12919
|
const isHidden = typeof a.hidden === "function" ? a.hidden(selKeys, selectedRows) : !!a.hidden;
|
|
12895
12920
|
if (isHidden) return null;
|
|
12896
12921
|
const isDisabled = typeof a.disabled === "function" ? a.disabled(selKeys, selectedRows) : !!a.disabled;
|
|
12897
|
-
|
|
12922
|
+
const reason = isDisabled && a.disabledReason != null ? typeof a.disabledReason === "function" ? a.disabledReason(selKeys, selectedRows) : a.disabledReason : null;
|
|
12923
|
+
const soft = isDisabled && reason != null;
|
|
12924
|
+
const btn = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12898
12925
|
"button",
|
|
12899
12926
|
{
|
|
12900
12927
|
type: "button",
|
|
12901
12928
|
className: "twc-dt__batch-btn",
|
|
12902
12929
|
"data-danger": a.danger || void 0,
|
|
12903
|
-
disabled: isDisabled,
|
|
12904
|
-
|
|
12930
|
+
disabled: isDisabled && !soft,
|
|
12931
|
+
"aria-disabled": soft || void 0,
|
|
12932
|
+
onClick: (e) => {
|
|
12933
|
+
if (isDisabled) return;
|
|
12934
|
+
a.onClick?.(selKeys, selectedRows, clearSelection, { anchorEl: e.currentTarget });
|
|
12935
|
+
},
|
|
12905
12936
|
children: [
|
|
12906
12937
|
a.icon,
|
|
12907
12938
|
a.label
|
|
@@ -12909,6 +12940,7 @@ function Datatable({
|
|
|
12909
12940
|
},
|
|
12910
12941
|
i
|
|
12911
12942
|
);
|
|
12943
|
+
return reason != null ? /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { label: reason, placement: "top", children: btn }, i) : btn;
|
|
12912
12944
|
})
|
|
12913
12945
|
] })
|
|
12914
12946
|
] }) : null,
|
|
@@ -14339,6 +14371,42 @@ var CARDGRID_CSS = `
|
|
|
14339
14371
|
.twc-cardgrid__footer { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-2); }
|
|
14340
14372
|
.twc-cardgrid__count { font-size: var(--text-sm); color: var(--color-text-muted); }
|
|
14341
14373
|
.twc-cardgrid__perpage { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--text-sm); color: var(--color-text-muted); }
|
|
14374
|
+
|
|
14375
|
+
/* #478: selection. The card's selected state is a RING, not a background tint: a card is usually a
|
|
14376
|
+
full-bleed thumbnail, so a tint is invisible behind the image. The ring is drawn with box-shadow on
|
|
14377
|
+
a wrapper so it never participates in layout (no reflow when a card becomes selected) and it reads
|
|
14378
|
+
in both themes, --color-primary clearing 3:1 against both surfaces as a non-text indicator. */
|
|
14379
|
+
.twc-cardgrid__item { position: relative; border-radius: var(--radius-lg); transition: box-shadow var(--duration-fast) var(--ease-standard); }
|
|
14380
|
+
.twc-cardgrid__item[data-selected="true"] { box-shadow: 0 0 0 var(--border-medium) var(--color-primary); }
|
|
14381
|
+
/* The overlay is the GRID's checkbox, not the card's: renderCard owns the whole body, so a
|
|
14382
|
+
consumer-rendered checkbox would compete with the card's own click target and have to be positioned
|
|
14383
|
+
against a thumbnail whose size only the consumer knows. Placement is configurable, and a consumer who
|
|
14384
|
+
wants it inline instead uses the third renderCard argument and sets selectionPlacement="none". */
|
|
14385
|
+
.twc-cardgrid__pick { position: absolute; z-index: 2; display: inline-flex; padding: var(--space-1);
|
|
14386
|
+
background: color-mix(in srgb, var(--color-surface) 82%, transparent); border-radius: var(--radius-md);
|
|
14387
|
+
backdrop-filter: blur(4px); }
|
|
14388
|
+
.twc-cardgrid__item[data-place="top-start"] .twc-cardgrid__pick { top: var(--space-2); inset-inline-start: var(--space-2); }
|
|
14389
|
+
.twc-cardgrid__item[data-place="top-end"] .twc-cardgrid__pick { top: var(--space-2); inset-inline-end: var(--space-2); }
|
|
14390
|
+
.twc-cardgrid__item[data-place="bottom-start"] .twc-cardgrid__pick { bottom: var(--space-2); inset-inline-start: var(--space-2); }
|
|
14391
|
+
.twc-cardgrid__item[data-place="bottom-end"] .twc-cardgrid__pick { bottom: var(--space-2); inset-inline-end: var(--space-2); }
|
|
14392
|
+
.twc-cardgrid__batch { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2);
|
|
14393
|
+
padding: var(--space-2) var(--space-3); border: var(--border-thin) solid var(--color-primary-border);
|
|
14394
|
+
background: var(--color-primary-subtle); border-radius: var(--radius-md); }
|
|
14395
|
+
.twc-cardgrid__batch-count { font-size: var(--text-sm); font-weight: var(--font-semibold); color: var(--color-primary-subtle-fg); }
|
|
14396
|
+
.twc-cardgrid__batch-actions { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin-inline-start: auto; }
|
|
14397
|
+
.twc-cardgrid__batch-btn { display: inline-flex; align-items: center; gap: var(--space-2); height: var(--control-h-sm);
|
|
14398
|
+
padding-inline: var(--space-3); border: var(--border-thin) solid var(--color-border); background: var(--color-surface);
|
|
14399
|
+
color: var(--color-text); font-family: inherit; font-size: var(--text-xs); font-weight: var(--font-semibold);
|
|
14400
|
+
border-radius: var(--radius-md); cursor: pointer; }
|
|
14401
|
+
.twc-cardgrid__batch-btn:hover:not(:disabled):not([aria-disabled="true"]) { border-color: var(--color-primary-subtle-fg); color: var(--color-primary-subtle-fg); }
|
|
14402
|
+
.twc-cardgrid__batch-btn:disabled, .twc-cardgrid__batch-btn[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; }
|
|
14403
|
+
.twc-cardgrid__batch-btn[data-danger="true"] { color: var(--color-danger-subtle-fg); }
|
|
14404
|
+
.twc-cardgrid__batch-btn svg { width: 15px; height: 15px; }
|
|
14405
|
+
.twc-cardgrid__batch-x { display: inline-grid; place-items: center; width: 26px; height: 26px; flex: none;
|
|
14406
|
+
border: none; background: transparent; color: var(--color-primary-subtle-fg); cursor: pointer; border-radius: var(--radius-sm); }
|
|
14407
|
+
.twc-cardgrid__batch-x:hover { background: color-mix(in srgb, var(--color-primary) 14%, transparent); }
|
|
14408
|
+
.twc-cardgrid__batch-x svg { width: 15px; height: 15px; }
|
|
14409
|
+
.twc-cardgrid__selall { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--text-sm); color: var(--color-text-muted); }
|
|
14342
14410
|
`;
|
|
14343
14411
|
function CardGrid({
|
|
14344
14412
|
rows = [],
|
|
@@ -14375,6 +14443,16 @@ function CardGrid({
|
|
|
14375
14443
|
sortMinWidth,
|
|
14376
14444
|
// slots / states
|
|
14377
14445
|
toolbar,
|
|
14446
|
+
// #478: selection + batch actions, deliberately the SAME vocabulary as Datatable rather than a new
|
|
14447
|
+
// one - a card grid is the surface where "pick several of these and do one thing to them" is close to
|
|
14448
|
+
// the whole point, and it was the only Datatable affordance CardGrid lacked.
|
|
14449
|
+
checkboxSelection = false,
|
|
14450
|
+
batchActions = [],
|
|
14451
|
+
onRowSelectionChange,
|
|
14452
|
+
selectionPlacement = "top-start",
|
|
14453
|
+
selectionLabel,
|
|
14454
|
+
showSelectAll = true,
|
|
14455
|
+
retainSelectedRows = false,
|
|
14378
14456
|
emptyState = "No results.",
|
|
14379
14457
|
label,
|
|
14380
14458
|
id,
|
|
@@ -14451,6 +14529,62 @@ function CardGrid({
|
|
|
14451
14529
|
return () => clearTimeout(t);
|
|
14452
14530
|
}, [serverMode, queryKey]);
|
|
14453
14531
|
const keyOf = typeof rowKey === "function" ? rowKey : (r2) => r2 && r2[rowKey];
|
|
14532
|
+
const [selected, setSelected] = React54__namespace.default.useState(() => /* @__PURE__ */ new Set());
|
|
14533
|
+
const retainCap = retainSelectedRows === true ? 1e3 : retainSelectedRows || 0;
|
|
14534
|
+
const retainedRef = React54__namespace.default.useRef(/* @__PURE__ */ new Map());
|
|
14535
|
+
const selKeys = React54__namespace.default.useMemo(() => [...selected], [selected]);
|
|
14536
|
+
const selectedRows = React54__namespace.default.useMemo(() => {
|
|
14537
|
+
const onPage = new Map(pageRows.map((r2, i) => [keyOf(r2, i), r2]));
|
|
14538
|
+
return selKeys.map((k) => onPage.get(k) ?? retainedRef.current.get(k)).filter((r2) => r2 !== void 0);
|
|
14539
|
+
}, [selKeys, pageRows]);
|
|
14540
|
+
const clearSelection = React54__namespace.default.useCallback(() => {
|
|
14541
|
+
retainedRef.current.clear();
|
|
14542
|
+
setSelected(/* @__PURE__ */ new Set());
|
|
14543
|
+
}, []);
|
|
14544
|
+
const toggleKey = React54__namespace.default.useCallback((key, row) => {
|
|
14545
|
+
setSelected((prev) => {
|
|
14546
|
+
const next = new Set(prev);
|
|
14547
|
+
if (next.has(key)) {
|
|
14548
|
+
next.delete(key);
|
|
14549
|
+
retainedRef.current.delete(key);
|
|
14550
|
+
} else {
|
|
14551
|
+
next.add(key);
|
|
14552
|
+
if (retainCap > 0 && row !== void 0 && retainedRef.current.size < retainCap) retainedRef.current.set(key, row);
|
|
14553
|
+
}
|
|
14554
|
+
return next;
|
|
14555
|
+
});
|
|
14556
|
+
}, [retainCap]);
|
|
14557
|
+
const pageKeys = pageRows.map((r2, i) => keyOf(r2, i));
|
|
14558
|
+
const pageSelectedCount = pageKeys.filter((k) => selected.has(k)).length;
|
|
14559
|
+
const allPageSelected = pageKeys.length > 0 && pageSelectedCount === pageKeys.length;
|
|
14560
|
+
const somePageSelected = pageSelectedCount > 0 && !allPageSelected;
|
|
14561
|
+
const togglePage = () => {
|
|
14562
|
+
setSelected((prev) => {
|
|
14563
|
+
const next = new Set(prev);
|
|
14564
|
+
pageRows.forEach((r2, i) => {
|
|
14565
|
+
const k = keyOf(r2, i);
|
|
14566
|
+
if (allPageSelected) {
|
|
14567
|
+
next.delete(k);
|
|
14568
|
+
retainedRef.current.delete(k);
|
|
14569
|
+
} else {
|
|
14570
|
+
next.add(k);
|
|
14571
|
+
if (retainCap > 0 && retainedRef.current.size < retainCap) retainedRef.current.set(k, r2);
|
|
14572
|
+
}
|
|
14573
|
+
});
|
|
14574
|
+
return next;
|
|
14575
|
+
});
|
|
14576
|
+
};
|
|
14577
|
+
const onSelRef = React54__namespace.default.useRef(onRowSelectionChange);
|
|
14578
|
+
onSelRef.current = onRowSelectionChange;
|
|
14579
|
+
const prevSelSigRef = React54__namespace.default.useRef(null);
|
|
14580
|
+
React54__namespace.default.useEffect(() => {
|
|
14581
|
+
const cb = onSelRef.current;
|
|
14582
|
+
if (!cb) return;
|
|
14583
|
+
const sig = selKeys.join(",");
|
|
14584
|
+
if (sig === prevSelSigRef.current) return;
|
|
14585
|
+
prevSelSigRef.current = sig;
|
|
14586
|
+
cb(selKeys, selectedRows);
|
|
14587
|
+
}, [selKeys, selectedRows]);
|
|
14454
14588
|
const from = total === 0 ? 0 : Math.min(shownPage * sizeVal + 1, total);
|
|
14455
14589
|
const to = paginated ? Math.min((shownPage + 1) * sizeVal, total) : total;
|
|
14456
14590
|
const rppOptions = Array.from(new Set([...pageSizeOptions || [], pageSize].filter((n) => n > 0))).sort((a, b) => a - b).map((n) => ({ value: String(n), label: String(n) }));
|
|
@@ -14503,6 +14637,64 @@ function CardGrid({
|
|
|
14503
14637
|
)
|
|
14504
14638
|
] }) : null
|
|
14505
14639
|
] }) : null,
|
|
14640
|
+
checkboxSelection && showSelectAll && pageRows.length > 0 && selected.size === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "twc-cardgrid__selall", children: [
|
|
14641
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14642
|
+
Checkbox,
|
|
14643
|
+
{
|
|
14644
|
+
checked: allPageSelected,
|
|
14645
|
+
indeterminate: somePageSelected,
|
|
14646
|
+
onChange: togglePage,
|
|
14647
|
+
"aria-label": "Select all on this page"
|
|
14648
|
+
}
|
|
14649
|
+
),
|
|
14650
|
+
"Select all on this page"
|
|
14651
|
+
] }) : null,
|
|
14652
|
+
checkboxSelection && selected.size > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-cardgrid__batch", children: [
|
|
14653
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-cardgrid__batch-x", onClick: clearSelection, "aria-label": "Clear selection", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6 6 18M6 6l12 12" }) }) }),
|
|
14654
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-cardgrid__batch-count", children: [
|
|
14655
|
+
selected.size,
|
|
14656
|
+
" selected"
|
|
14657
|
+
] }),
|
|
14658
|
+
showSelectAll && pageRows.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "twc-cardgrid__selall", children: [
|
|
14659
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14660
|
+
Checkbox,
|
|
14661
|
+
{
|
|
14662
|
+
checked: allPageSelected,
|
|
14663
|
+
indeterminate: somePageSelected,
|
|
14664
|
+
onChange: togglePage,
|
|
14665
|
+
"aria-label": "Select all on this page"
|
|
14666
|
+
}
|
|
14667
|
+
),
|
|
14668
|
+
"This page"
|
|
14669
|
+
] }) : null,
|
|
14670
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-cardgrid__batch-actions", children: batchActions.map((a, i) => {
|
|
14671
|
+
const isHidden = typeof a.hidden === "function" ? a.hidden(selKeys, selectedRows) : !!a.hidden;
|
|
14672
|
+
if (isHidden) return null;
|
|
14673
|
+
const isDisabled = typeof a.disabled === "function" ? a.disabled(selKeys, selectedRows) : !!a.disabled;
|
|
14674
|
+
const reason = isDisabled && a.disabledReason != null ? typeof a.disabledReason === "function" ? a.disabledReason(selKeys, selectedRows) : a.disabledReason : null;
|
|
14675
|
+
const soft = isDisabled && reason != null;
|
|
14676
|
+
const btn = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14677
|
+
"button",
|
|
14678
|
+
{
|
|
14679
|
+
type: "button",
|
|
14680
|
+
className: "twc-cardgrid__batch-btn",
|
|
14681
|
+
"data-danger": a.danger || void 0,
|
|
14682
|
+
disabled: isDisabled && !soft,
|
|
14683
|
+
"aria-disabled": soft || void 0,
|
|
14684
|
+
onClick: (e) => {
|
|
14685
|
+
if (isDisabled) return;
|
|
14686
|
+
a.onClick?.(selKeys, selectedRows, clearSelection, { anchorEl: e.currentTarget });
|
|
14687
|
+
},
|
|
14688
|
+
children: [
|
|
14689
|
+
a.icon,
|
|
14690
|
+
a.label
|
|
14691
|
+
]
|
|
14692
|
+
},
|
|
14693
|
+
i
|
|
14694
|
+
);
|
|
14695
|
+
return reason != null ? /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { label: reason, placement: "top", children: btn }, i) : btn;
|
|
14696
|
+
}) })
|
|
14697
|
+
] }) : null,
|
|
14506
14698
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-cardgrid__body", "data-loading": loading || void 0, "aria-busy": loading || void 0, children: [
|
|
14507
14699
|
loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-cardgrid__overlay", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-cardgrid__spinner", role: "status", "aria-label": "Loading" }) }) : null,
|
|
14508
14700
|
pageRows.length === 0 && !loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-cardgrid__empty", children: emptyState }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -14514,7 +14706,31 @@ function CardGrid({
|
|
|
14514
14706
|
gap,
|
|
14515
14707
|
role: "list",
|
|
14516
14708
|
"aria-labelledby": label ? `${fieldId}-label` : void 0,
|
|
14517
|
-
children: pageRows.map((row, i) =>
|
|
14709
|
+
children: pageRows.map((row, i) => {
|
|
14710
|
+
const k = keyOf(row, i);
|
|
14711
|
+
const isSel = checkboxSelection && selected.has(k);
|
|
14712
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14713
|
+
"div",
|
|
14714
|
+
{
|
|
14715
|
+
role: "listitem",
|
|
14716
|
+
className: "twc-cardgrid__item",
|
|
14717
|
+
"data-selected": isSel || void 0,
|
|
14718
|
+
"data-place": checkboxSelection ? selectionPlacement : void 0,
|
|
14719
|
+
children: [
|
|
14720
|
+
checkboxSelection && selectionPlacement !== "none" ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-cardgrid__pick", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14721
|
+
Checkbox,
|
|
14722
|
+
{
|
|
14723
|
+
checked: isSel,
|
|
14724
|
+
onChange: () => toggleKey(k, row),
|
|
14725
|
+
"aria-label": selectionLabel ? selectionLabel(row, i) : "Select item"
|
|
14726
|
+
}
|
|
14727
|
+
) }) : null,
|
|
14728
|
+
renderCard(row, i, checkboxSelection ? { selected: isSel, toggle: () => toggleKey(k, row) } : void 0)
|
|
14729
|
+
]
|
|
14730
|
+
},
|
|
14731
|
+
k ?? i
|
|
14732
|
+
);
|
|
14733
|
+
})
|
|
14518
14734
|
}
|
|
14519
14735
|
)
|
|
14520
14736
|
] }),
|
|
@@ -19531,7 +19747,7 @@ function Tag({
|
|
|
19531
19747
|
}, "aria-label": _removeLabel, type: "button", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6 6 18M6 6l12 12" }) }) }) : null
|
|
19532
19748
|
] });
|
|
19533
19749
|
}
|
|
19534
|
-
var
|
|
19750
|
+
var useIso = typeof document !== "undefined" ? React54__namespace.default.useLayoutEffect : React54__namespace.default.useEffect;
|
|
19535
19751
|
var TEXTAREA_CSS = `
|
|
19536
19752
|
.twc-field { display: flex; flex-direction: column; gap: var(--space-1-5); font-family: var(--font-sans); }
|
|
19537
19753
|
.twc-field__label { font-size: var(--text-sm); font-weight: var(--font-semibold); color: var(--color-text); display: flex; gap: 4px; align-items: center; }
|
|
@@ -19630,7 +19846,7 @@ var Textarea = React54__namespace.default.forwardRef(function Textarea2({
|
|
|
19630
19846
|
el.style.height = `${next}px`;
|
|
19631
19847
|
el.style.overflowY = el.scrollHeight + vBorder > maxH ? "auto" : "hidden";
|
|
19632
19848
|
};
|
|
19633
|
-
|
|
19849
|
+
useIso(() => {
|
|
19634
19850
|
if (autosize && innerRef.current) resize();
|
|
19635
19851
|
}, [autosize, rest.value, minRows, maxRows, rows]);
|
|
19636
19852
|
const handleInput = (e) => {
|