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/dist/index.mjs CHANGED
@@ -7227,8 +7227,8 @@ function Currency({
7227
7227
  }
7228
7228
  function useFallbackName(ref, hasOwnName) {
7229
7229
  const [needsFallback, setNeedsFallback] = React54__default.useState(false);
7230
- const useIso3 = typeof document !== "undefined" ? React54__default.useLayoutEffect : React54__default.useEffect;
7231
- useIso3(() => {
7230
+ const useIso2 = typeof document !== "undefined" ? React54__default.useLayoutEffect : React54__default.useEffect;
7231
+ useIso2(() => {
7232
7232
  if (hasOwnName) {
7233
7233
  setNeedsFallback(false);
7234
7234
  return;
@@ -7244,7 +7244,6 @@ function useFallbackName(ref, hasOwnName) {
7244
7244
  });
7245
7245
  return !hasOwnName && needsFallback;
7246
7246
  }
7247
- typeof document !== "undefined" ? React54__default.useLayoutEffect : React54__default.useEffect;
7248
7247
  var SELECT_CSS = `
7249
7248
  .twc-field { display: flex; flex-direction: column; gap: var(--space-1-5); font-family: var(--font-sans); }
7250
7249
  .twc-field__label { font-size: var(--text-sm); font-weight: var(--font-semibold); color: var(--color-text); display: flex; gap: 4px; align-items: center; }
@@ -9232,8 +9231,22 @@ var DT_CSS = `
9232
9231
  .twc-dt__row:hover .twc-dt__row-resizer::after { background: var(--color-border-strong); }
9233
9232
  .twc-dt__row-resizer:hover::after { background: var(--color-primary); }
9234
9233
 
9234
+ /* #481: the cell background reads --twc-dt-row-bg, which getRowStyle sets on the <tr>. It has to come
9235
+ through a custom property rather than straight off the row, because this rule paints an OPAQUE
9236
+ --color-surface on every cell: a background set on the <tr> would sit behind it and never show,
9237
+ which would make the commonest use of a row-style hook silently do nothing. Cells in a pinned
9238
+ COLUMN inherit it too, so a tinted row does not develop a hole where a sticky column scrolls over
9239
+ it.
9240
+ Layering: this rule is (0,1,0), the LOWEST specificity of any background in this sheet, so the
9241
+ row tint is the bottom layer above the plain surface and every built-in state covers it - hover,
9242
+ row selection, data-active, data-pinned-row, data-row-grabbed, the diff data-op washes, cell
9243
+ selection/active, inline editing (each (0,3,0), (0,4,0) for the pinned-column twins, or (0,2,0)
9244
+ for the cell-level ones) - and an inline per-cell cellStyle
9245
+ covers them all. That is the intended rule, not an accident of ordering: a row tint is a
9246
+ data-derived wash, and no data wash should be able to hide an interaction state. Consumers who
9247
+ need a tint that outranks those use getRowClassName and a rule of their own. */
9235
9248
  .twc-dt__td { padding: 0 12px; height: var(--_rowh, 44px); border-bottom: var(--border-thin) solid var(--color-divider);
9236
- font-size: var(--text-sm); color: var(--color-text); background: var(--color-surface);
9249
+ font-size: var(--text-sm); color: var(--color-text); background: var(--twc-dt-row-bg, var(--color-surface));
9237
9250
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 0; }
9238
9251
  /* Wrap-text columns: content flows onto multiple lines (the row grows down) instead of
9239
9252
  clipping to one line. height stays a per-row minimum, so single-line cells are unchanged. */
@@ -10000,6 +10013,8 @@ function Datatable({
10000
10013
  onColumnVisibilityChange,
10001
10014
  batchActions = [],
10002
10015
  onRowSelectionChange,
10016
+ getRowStyle,
10017
+ getRowClassName,
10003
10018
  showExport = false,
10004
10019
  showDensity = false,
10005
10020
  showPivot = false,
@@ -12575,7 +12590,17 @@ function Datatable({
12575
12590
  const rowActive = selectionMode === "row" && activeRowVal === k;
12576
12591
  const stickyStyle = pinSide === "top" ? { position: "sticky", top: headH, zIndex: 5 } : pinSide === "bottom" ? { position: "sticky", bottom: 0, zIndex: 5 } : void 0;
12577
12592
  const h = rowHeights[k];
12578
- const rowStyle = { ...stickyStyle || {}, ...h ? { height: h } : {} };
12593
+ const userRowStyle = getRowStyle ? getRowStyle(row, ri) : void 0;
12594
+ const userRowClass = getRowClassName ? getRowClassName(row, ri) : void 0;
12595
+ const { background: _rowBgShorthand, backgroundColor: _rowBgColor, ...restRowStyle } = userRowStyle || {};
12596
+ const usable = (v) => typeof v === "string" && v.trim() !== "" ? v : void 0;
12597
+ const rowBg = usable(_rowBgShorthand) ?? usable(_rowBgColor);
12598
+ const rowStyle = {
12599
+ ...restRowStyle,
12600
+ ...rowBg != null ? { "--twc-dt-row-bg": rowBg } : {},
12601
+ ...stickyStyle || {},
12602
+ ...h ? { height: h } : {}
12603
+ };
12579
12604
  const reorderable = canReorderRows && !pinSide;
12580
12605
  const grabbed = rowGrab && rowGrab.key === k;
12581
12606
  const grabTarget = rowGrab && !grabbed && midIdx != null && rowGrab.index === midIdx ? rowGrab.index >= keyIndexMid.get(rowGrab.key) ? "after" : "before" : void 0;
@@ -12583,7 +12608,7 @@ function Datatable({
12583
12608
  /* @__PURE__ */ jsxs(
12584
12609
  "tr",
12585
12610
  {
12586
- className: "twc-dt__row",
12611
+ className: userRowClass ? `twc-dt__row ${userRowClass}` : "twc-dt__row",
12587
12612
  role: "row",
12588
12613
  "aria-rowindex": treeSeqByKey ? treeSeqByKey.get(k) + 2 : (paginated && !serverMode ? pageVal * sizeVal : 0) + ri + 2,
12589
12614
  "aria-selected": (checkboxSelection ? sel : rowActive) || void 0,
@@ -12873,14 +12898,20 @@ function Datatable({
12873
12898
  const isHidden = typeof a.hidden === "function" ? a.hidden(selKeys, selectedRows) : !!a.hidden;
12874
12899
  if (isHidden) return null;
12875
12900
  const isDisabled = typeof a.disabled === "function" ? a.disabled(selKeys, selectedRows) : !!a.disabled;
12876
- return /* @__PURE__ */ jsxs(
12901
+ const reason = isDisabled && a.disabledReason != null ? typeof a.disabledReason === "function" ? a.disabledReason(selKeys, selectedRows) : a.disabledReason : null;
12902
+ const soft = isDisabled && reason != null;
12903
+ const btn = /* @__PURE__ */ jsxs(
12877
12904
  "button",
12878
12905
  {
12879
12906
  type: "button",
12880
12907
  className: "twc-dt__batch-btn",
12881
12908
  "data-danger": a.danger || void 0,
12882
- disabled: isDisabled,
12883
- onClick: (e) => a.onClick?.(selKeys, selectedRows, clearSelection, { anchorEl: e.currentTarget }),
12909
+ disabled: isDisabled && !soft,
12910
+ "aria-disabled": soft || void 0,
12911
+ onClick: (e) => {
12912
+ if (isDisabled) return;
12913
+ a.onClick?.(selKeys, selectedRows, clearSelection, { anchorEl: e.currentTarget });
12914
+ },
12884
12915
  children: [
12885
12916
  a.icon,
12886
12917
  a.label
@@ -12888,6 +12919,7 @@ function Datatable({
12888
12919
  },
12889
12920
  i
12890
12921
  );
12922
+ return reason != null ? /* @__PURE__ */ jsx(Tooltip, { label: reason, placement: "top", children: btn }, i) : btn;
12891
12923
  })
12892
12924
  ] })
12893
12925
  ] }) : null,
@@ -14318,6 +14350,42 @@ var CARDGRID_CSS = `
14318
14350
  .twc-cardgrid__footer { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-2); }
14319
14351
  .twc-cardgrid__count { font-size: var(--text-sm); color: var(--color-text-muted); }
14320
14352
  .twc-cardgrid__perpage { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--text-sm); color: var(--color-text-muted); }
14353
+
14354
+ /* #478: selection. The card's selected state is a RING, not a background tint: a card is usually a
14355
+ full-bleed thumbnail, so a tint is invisible behind the image. The ring is drawn with box-shadow on
14356
+ a wrapper so it never participates in layout (no reflow when a card becomes selected) and it reads
14357
+ in both themes, --color-primary clearing 3:1 against both surfaces as a non-text indicator. */
14358
+ .twc-cardgrid__item { position: relative; border-radius: var(--radius-lg); transition: box-shadow var(--duration-fast) var(--ease-standard); }
14359
+ .twc-cardgrid__item[data-selected="true"] { box-shadow: 0 0 0 var(--border-medium) var(--color-primary); }
14360
+ /* The overlay is the GRID's checkbox, not the card's: renderCard owns the whole body, so a
14361
+ consumer-rendered checkbox would compete with the card's own click target and have to be positioned
14362
+ against a thumbnail whose size only the consumer knows. Placement is configurable, and a consumer who
14363
+ wants it inline instead uses the third renderCard argument and sets selectionPlacement="none". */
14364
+ .twc-cardgrid__pick { position: absolute; z-index: 2; display: inline-flex; padding: var(--space-1);
14365
+ background: color-mix(in srgb, var(--color-surface) 82%, transparent); border-radius: var(--radius-md);
14366
+ backdrop-filter: blur(4px); }
14367
+ .twc-cardgrid__item[data-place="top-start"] .twc-cardgrid__pick { top: var(--space-2); inset-inline-start: var(--space-2); }
14368
+ .twc-cardgrid__item[data-place="top-end"] .twc-cardgrid__pick { top: var(--space-2); inset-inline-end: var(--space-2); }
14369
+ .twc-cardgrid__item[data-place="bottom-start"] .twc-cardgrid__pick { bottom: var(--space-2); inset-inline-start: var(--space-2); }
14370
+ .twc-cardgrid__item[data-place="bottom-end"] .twc-cardgrid__pick { bottom: var(--space-2); inset-inline-end: var(--space-2); }
14371
+ .twc-cardgrid__batch { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2);
14372
+ padding: var(--space-2) var(--space-3); border: var(--border-thin) solid var(--color-primary-border);
14373
+ background: var(--color-primary-subtle); border-radius: var(--radius-md); }
14374
+ .twc-cardgrid__batch-count { font-size: var(--text-sm); font-weight: var(--font-semibold); color: var(--color-primary-subtle-fg); }
14375
+ .twc-cardgrid__batch-actions { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin-inline-start: auto; }
14376
+ .twc-cardgrid__batch-btn { display: inline-flex; align-items: center; gap: var(--space-2); height: var(--control-h-sm);
14377
+ padding-inline: var(--space-3); border: var(--border-thin) solid var(--color-border); background: var(--color-surface);
14378
+ color: var(--color-text); font-family: inherit; font-size: var(--text-xs); font-weight: var(--font-semibold);
14379
+ border-radius: var(--radius-md); cursor: pointer; }
14380
+ .twc-cardgrid__batch-btn:hover:not(:disabled):not([aria-disabled="true"]) { border-color: var(--color-primary-subtle-fg); color: var(--color-primary-subtle-fg); }
14381
+ .twc-cardgrid__batch-btn:disabled, .twc-cardgrid__batch-btn[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; }
14382
+ .twc-cardgrid__batch-btn[data-danger="true"] { color: var(--color-danger-subtle-fg); }
14383
+ .twc-cardgrid__batch-btn svg { width: 15px; height: 15px; }
14384
+ .twc-cardgrid__batch-x { display: inline-grid; place-items: center; width: 26px; height: 26px; flex: none;
14385
+ border: none; background: transparent; color: var(--color-primary-subtle-fg); cursor: pointer; border-radius: var(--radius-sm); }
14386
+ .twc-cardgrid__batch-x:hover { background: color-mix(in srgb, var(--color-primary) 14%, transparent); }
14387
+ .twc-cardgrid__batch-x svg { width: 15px; height: 15px; }
14388
+ .twc-cardgrid__selall { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--text-sm); color: var(--color-text-muted); }
14321
14389
  `;
14322
14390
  function CardGrid({
14323
14391
  rows = [],
@@ -14354,6 +14422,16 @@ function CardGrid({
14354
14422
  sortMinWidth,
14355
14423
  // slots / states
14356
14424
  toolbar,
14425
+ // #478: selection + batch actions, deliberately the SAME vocabulary as Datatable rather than a new
14426
+ // one - a card grid is the surface where "pick several of these and do one thing to them" is close to
14427
+ // the whole point, and it was the only Datatable affordance CardGrid lacked.
14428
+ checkboxSelection = false,
14429
+ batchActions = [],
14430
+ onRowSelectionChange,
14431
+ selectionPlacement = "top-start",
14432
+ selectionLabel,
14433
+ showSelectAll = true,
14434
+ retainSelectedRows = false,
14357
14435
  emptyState = "No results.",
14358
14436
  label,
14359
14437
  id,
@@ -14430,6 +14508,62 @@ function CardGrid({
14430
14508
  return () => clearTimeout(t);
14431
14509
  }, [serverMode, queryKey]);
14432
14510
  const keyOf = typeof rowKey === "function" ? rowKey : (r2) => r2 && r2[rowKey];
14511
+ const [selected, setSelected] = React54__default.useState(() => /* @__PURE__ */ new Set());
14512
+ const retainCap = retainSelectedRows === true ? 1e3 : retainSelectedRows || 0;
14513
+ const retainedRef = React54__default.useRef(/* @__PURE__ */ new Map());
14514
+ const selKeys = React54__default.useMemo(() => [...selected], [selected]);
14515
+ const selectedRows = React54__default.useMemo(() => {
14516
+ const onPage = new Map(pageRows.map((r2, i) => [keyOf(r2, i), r2]));
14517
+ return selKeys.map((k) => onPage.get(k) ?? retainedRef.current.get(k)).filter((r2) => r2 !== void 0);
14518
+ }, [selKeys, pageRows]);
14519
+ const clearSelection = React54__default.useCallback(() => {
14520
+ retainedRef.current.clear();
14521
+ setSelected(/* @__PURE__ */ new Set());
14522
+ }, []);
14523
+ const toggleKey = React54__default.useCallback((key, row) => {
14524
+ setSelected((prev) => {
14525
+ const next = new Set(prev);
14526
+ if (next.has(key)) {
14527
+ next.delete(key);
14528
+ retainedRef.current.delete(key);
14529
+ } else {
14530
+ next.add(key);
14531
+ if (retainCap > 0 && row !== void 0 && retainedRef.current.size < retainCap) retainedRef.current.set(key, row);
14532
+ }
14533
+ return next;
14534
+ });
14535
+ }, [retainCap]);
14536
+ const pageKeys = pageRows.map((r2, i) => keyOf(r2, i));
14537
+ const pageSelectedCount = pageKeys.filter((k) => selected.has(k)).length;
14538
+ const allPageSelected = pageKeys.length > 0 && pageSelectedCount === pageKeys.length;
14539
+ const somePageSelected = pageSelectedCount > 0 && !allPageSelected;
14540
+ const togglePage = () => {
14541
+ setSelected((prev) => {
14542
+ const next = new Set(prev);
14543
+ pageRows.forEach((r2, i) => {
14544
+ const k = keyOf(r2, i);
14545
+ if (allPageSelected) {
14546
+ next.delete(k);
14547
+ retainedRef.current.delete(k);
14548
+ } else {
14549
+ next.add(k);
14550
+ if (retainCap > 0 && retainedRef.current.size < retainCap) retainedRef.current.set(k, r2);
14551
+ }
14552
+ });
14553
+ return next;
14554
+ });
14555
+ };
14556
+ const onSelRef = React54__default.useRef(onRowSelectionChange);
14557
+ onSelRef.current = onRowSelectionChange;
14558
+ const prevSelSigRef = React54__default.useRef(null);
14559
+ React54__default.useEffect(() => {
14560
+ const cb = onSelRef.current;
14561
+ if (!cb) return;
14562
+ const sig = selKeys.join(",");
14563
+ if (sig === prevSelSigRef.current) return;
14564
+ prevSelSigRef.current = sig;
14565
+ cb(selKeys, selectedRows);
14566
+ }, [selKeys, selectedRows]);
14433
14567
  const from = total === 0 ? 0 : Math.min(shownPage * sizeVal + 1, total);
14434
14568
  const to = paginated ? Math.min((shownPage + 1) * sizeVal, total) : total;
14435
14569
  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) }));
@@ -14482,6 +14616,64 @@ function CardGrid({
14482
14616
  )
14483
14617
  ] }) : null
14484
14618
  ] }) : null,
14619
+ checkboxSelection && showSelectAll && pageRows.length > 0 && selected.size === 0 ? /* @__PURE__ */ jsxs("label", { className: "twc-cardgrid__selall", children: [
14620
+ /* @__PURE__ */ jsx(
14621
+ Checkbox,
14622
+ {
14623
+ checked: allPageSelected,
14624
+ indeterminate: somePageSelected,
14625
+ onChange: togglePage,
14626
+ "aria-label": "Select all on this page"
14627
+ }
14628
+ ),
14629
+ "Select all on this page"
14630
+ ] }) : null,
14631
+ checkboxSelection && selected.size > 0 ? /* @__PURE__ */ jsxs("div", { className: "twc-cardgrid__batch", children: [
14632
+ /* @__PURE__ */ jsx("button", { type: "button", className: "twc-cardgrid__batch-x", onClick: clearSelection, "aria-label": "Clear selection", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M18 6 6 18M6 6l12 12" }) }) }),
14633
+ /* @__PURE__ */ jsxs("span", { className: "twc-cardgrid__batch-count", children: [
14634
+ selected.size,
14635
+ " selected"
14636
+ ] }),
14637
+ showSelectAll && pageRows.length > 0 ? /* @__PURE__ */ jsxs("label", { className: "twc-cardgrid__selall", children: [
14638
+ /* @__PURE__ */ jsx(
14639
+ Checkbox,
14640
+ {
14641
+ checked: allPageSelected,
14642
+ indeterminate: somePageSelected,
14643
+ onChange: togglePage,
14644
+ "aria-label": "Select all on this page"
14645
+ }
14646
+ ),
14647
+ "This page"
14648
+ ] }) : null,
14649
+ /* @__PURE__ */ jsx("div", { className: "twc-cardgrid__batch-actions", children: batchActions.map((a, i) => {
14650
+ const isHidden = typeof a.hidden === "function" ? a.hidden(selKeys, selectedRows) : !!a.hidden;
14651
+ if (isHidden) return null;
14652
+ const isDisabled = typeof a.disabled === "function" ? a.disabled(selKeys, selectedRows) : !!a.disabled;
14653
+ const reason = isDisabled && a.disabledReason != null ? typeof a.disabledReason === "function" ? a.disabledReason(selKeys, selectedRows) : a.disabledReason : null;
14654
+ const soft = isDisabled && reason != null;
14655
+ const btn = /* @__PURE__ */ jsxs(
14656
+ "button",
14657
+ {
14658
+ type: "button",
14659
+ className: "twc-cardgrid__batch-btn",
14660
+ "data-danger": a.danger || void 0,
14661
+ disabled: isDisabled && !soft,
14662
+ "aria-disabled": soft || void 0,
14663
+ onClick: (e) => {
14664
+ if (isDisabled) return;
14665
+ a.onClick?.(selKeys, selectedRows, clearSelection, { anchorEl: e.currentTarget });
14666
+ },
14667
+ children: [
14668
+ a.icon,
14669
+ a.label
14670
+ ]
14671
+ },
14672
+ i
14673
+ );
14674
+ return reason != null ? /* @__PURE__ */ jsx(Tooltip, { label: reason, placement: "top", children: btn }, i) : btn;
14675
+ }) })
14676
+ ] }) : null,
14485
14677
  /* @__PURE__ */ jsxs("div", { className: "twc-cardgrid__body", "data-loading": loading || void 0, "aria-busy": loading || void 0, children: [
14486
14678
  loading ? /* @__PURE__ */ jsx("div", { className: "twc-cardgrid__overlay", children: /* @__PURE__ */ jsx("div", { className: "twc-cardgrid__spinner", role: "status", "aria-label": "Loading" }) }) : null,
14487
14679
  pageRows.length === 0 && !loading ? /* @__PURE__ */ jsx("div", { className: "twc-cardgrid__empty", children: emptyState }) : /* @__PURE__ */ jsx(
@@ -14493,7 +14685,31 @@ function CardGrid({
14493
14685
  gap,
14494
14686
  role: "list",
14495
14687
  "aria-labelledby": label ? `${fieldId}-label` : void 0,
14496
- children: pageRows.map((row, i) => /* @__PURE__ */ jsx("div", { role: "listitem", children: renderCard(row, i) }, keyOf(row, i) ?? i))
14688
+ children: pageRows.map((row, i) => {
14689
+ const k = keyOf(row, i);
14690
+ const isSel = checkboxSelection && selected.has(k);
14691
+ return /* @__PURE__ */ jsxs(
14692
+ "div",
14693
+ {
14694
+ role: "listitem",
14695
+ className: "twc-cardgrid__item",
14696
+ "data-selected": isSel || void 0,
14697
+ "data-place": checkboxSelection ? selectionPlacement : void 0,
14698
+ children: [
14699
+ checkboxSelection && selectionPlacement !== "none" ? /* @__PURE__ */ jsx("span", { className: "twc-cardgrid__pick", children: /* @__PURE__ */ jsx(
14700
+ Checkbox,
14701
+ {
14702
+ checked: isSel,
14703
+ onChange: () => toggleKey(k, row),
14704
+ "aria-label": selectionLabel ? selectionLabel(row, i) : "Select item"
14705
+ }
14706
+ ) }) : null,
14707
+ renderCard(row, i, checkboxSelection ? { selected: isSel, toggle: () => toggleKey(k, row) } : void 0)
14708
+ ]
14709
+ },
14710
+ k ?? i
14711
+ );
14712
+ })
14497
14713
  }
14498
14714
  )
14499
14715
  ] }),
@@ -19510,7 +19726,7 @@ function Tag({
19510
19726
  }, "aria-label": _removeLabel, type: "button", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M18 6 6 18M6 6l12 12" }) }) }) : null
19511
19727
  ] });
19512
19728
  }
19513
- var useIso2 = typeof document !== "undefined" ? React54__default.useLayoutEffect : React54__default.useEffect;
19729
+ var useIso = typeof document !== "undefined" ? React54__default.useLayoutEffect : React54__default.useEffect;
19514
19730
  var TEXTAREA_CSS = `
19515
19731
  .twc-field { display: flex; flex-direction: column; gap: var(--space-1-5); font-family: var(--font-sans); }
19516
19732
  .twc-field__label { font-size: var(--text-sm); font-weight: var(--font-semibold); color: var(--color-text); display: flex; gap: 4px; align-items: center; }
@@ -19609,7 +19825,7 @@ var Textarea = React54__default.forwardRef(function Textarea2({
19609
19825
  el.style.height = `${next}px`;
19610
19826
  el.style.overflowY = el.scrollHeight + vBorder > maxH ? "auto" : "hidden";
19611
19827
  };
19612
- useIso2(() => {
19828
+ useIso(() => {
19613
19829
  if (autosize && innerRef.current) resize();
19614
19830
  }, [autosize, rest.value, minRows, maxRows, rows]);
19615
19831
  const handleInput = (e) => {