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 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 useIso3 = typeof document !== "undefined" ? React54__namespace.default.useLayoutEffect : React54__namespace.default.useEffect;
7252
- useIso3(() => {
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 rowStyle = { ...stickyStyle || {}, ...h ? { height: h } : {} };
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
- return /* @__PURE__ */ jsxRuntime.jsxs(
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
- onClick: (e) => a.onClick?.(selKeys, selectedRows, clearSelection, { anchorEl: e.currentTarget }),
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) => /* @__PURE__ */ jsxRuntime.jsx("div", { role: "listitem", children: renderCard(row, i) }, keyOf(row, i) ?? 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 useIso2 = typeof document !== "undefined" ? React54__namespace.default.useLayoutEffect : React54__namespace.default.useEffect;
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
- useIso2(() => {
19849
+ useIso(() => {
19634
19850
  if (autosize && innerRef.current) resize();
19635
19851
  }, [autosize, rest.value, minRows, maxRows, rows]);
19636
19852
  const handleInput = (e) => {