sellmate-design-system-react 9.0.0-beta.75 → 9.0.0-beta.76

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.
Files changed (36) hide show
  1. package/AGENTS.md +35 -0
  2. package/README.md +5 -5
  3. package/bin/sellmate-ds.mjs +91 -59
  4. package/dist/components/SCircleProgress/README.md +6 -3
  5. package/dist/components/SCircleProgress/SCircleProgress.d.ts +11 -3
  6. package/dist/components/SLinearProgress/README.md +2 -2
  7. package/dist/components/SLinearProgress/SLinearProgress.d.ts +8 -2
  8. package/dist/components/SSelect/README.md +18 -2
  9. package/dist/components/SSelect/SSelect.d.ts +28 -5
  10. package/dist/components/SSelect/index.d.ts +1 -1
  11. package/dist/components/STable/README.md +29 -20
  12. package/dist/components/STable/STable.d.ts +47 -31
  13. package/dist/components/STable/index.d.ts +1 -1
  14. package/dist/index.cjs +107 -50
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.js +107 -50
  17. package/dist/index.js.map +1 -1
  18. package/dist/llms-full.txt +90 -28
  19. package/dist/llms.txt +37 -1
  20. package/dist/styles.css +16 -0
  21. package/dist/theme.css +3 -0
  22. package/eslint/index.mjs +42 -42
  23. package/eslint/lib/class-names.mjs +23 -25
  24. package/eslint/lib/table-column.mjs +11 -11
  25. package/eslint/rules/component-group-gap.mjs +32 -30
  26. package/eslint/rules/divider-vertical-height.mjs +22 -22
  27. package/eslint/rules/field-width-grade.mjs +50 -50
  28. package/eslint/rules/no-arbitrary-class.mjs +63 -20
  29. package/eslint/rules/no-off-scale-spacing.mjs +61 -41
  30. package/eslint/rules/no-raw-html-control.mjs +38 -36
  31. package/eslint/rules/prefer-typo-preset.mjs +23 -17
  32. package/eslint/rules/require-locale-number.mjs +14 -19
  33. package/eslint/rules/table-column-width.mjs +21 -17
  34. package/eslint/rules/table-numeric-align.mjs +14 -14
  35. package/eslint/scale.gen.mjs +1 -1
  36. package/package.json +3 -3
package/dist/index.cjs CHANGED
@@ -3792,43 +3792,46 @@ var STROKE = 12;
3792
3792
  var CIRCUMFERENCE = 2 * Math.PI * RADIUS;
3793
3793
  var COLOR_MAP = {
3794
3794
  primary: { arc: "var(--cmp-progress-color-active)", track: "var(--cmp-progress-color-track)" },
3795
- // inverse: 어두운 배경용 — arc 흰색, track 은 흰색 40%(회색 링)
3796
- inverse: { arc: "var(--color-white)", track: "rgba(255,255,255,0.4)" },
3797
- error: { arc: "var(--color-red-75)", track: "var(--cmp-progress-color-track)" },
3798
- complete: { arc: "#01BB4B", track: "var(--cmp-progress-color-track)" },
3795
+ // inverse: 어두운 배경용 — arc 는 반전색, track 은 반전색을 inverse-opacity 만큼만(회색 링)
3796
+ inverse: {
3797
+ arc: "var(--cmp-progress-inverse-color)",
3798
+ track: "color-mix(in srgb, var(--cmp-progress-inverse-color) var(--cmp-progress-inverse-opacity), transparent)"
3799
+ },
3800
+ warning: { arc: "var(--cmp-progress-color-warning)", track: "var(--cmp-progress-color-track)" },
3801
+ error: { arc: "var(--cmp-progress-color-error)", track: "var(--cmp-progress-color-track)" },
3802
+ complete: { arc: "var(--cmp-progress-color-success)", track: "var(--cmp-progress-color-track)" },
3799
3803
  // neutral: 콘텐츠가 아직 없는 자리를 채우는 용도 — arc 도 회색이라 진행률보다 "대기"로 읽힌다
3800
- neutral: { arc: "var(--color-grey-35)", track: "var(--cmp-progress-color-track)" }
3804
+ neutral: { arc: "var(--cmp-progress-color-neutral)", track: "var(--cmp-progress-color-track)" }
3801
3805
  };
3802
- var DEFAULT_SIZE = 80;
3803
3806
  var clamp = (v) => Number.isFinite(v) ? Math.max(0, Math.min(100, v)) : 0;
3804
3807
  var SCircleProgress = /* @__PURE__ */ react.forwardRef(
3805
3808
  function SCircleProgress2({
3806
3809
  value = 0,
3807
3810
  type = "primary",
3808
3811
  indeterminate = false,
3809
- size = DEFAULT_SIZE,
3812
+ size,
3810
3813
  label,
3811
3814
  innerValue = false,
3812
3815
  className,
3813
3816
  style
3814
3817
  }, ref) {
3815
3818
  const v = clamp(value);
3816
- const dimension = typeof size === "number" ? `${size}px` : size;
3819
+ const dimension = size === void 0 ? "var(--cmp-progress-circular-size)" : typeof size === "number" ? `${size}px` : size;
3817
3820
  const colors = COLOR_MAP[type];
3818
3821
  const c = VIEWBOX / 2;
3819
- const percentColor = v === 0 ? "var(--sys-color-fg-tertiary, #888888)" : colors.arc;
3822
+ const percentColor = v === 0 ? "var(--sys-color-fg-tertiary)" : colors.arc;
3820
3823
  const filled = v / 100 * CIRCUMFERENCE;
3821
3824
  const showPercent = !indeterminate;
3822
3825
  const percentNode = /* @__PURE__ */ jsxRuntime.jsxs(
3823
3826
  "span",
3824
3827
  {
3825
3828
  className: cn(
3826
- "text-center text-[16px] font-bold",
3829
+ "typo-heading-md text-center",
3827
3830
  innerValue ? (
3828
3831
  // leading-[normal]: 26px leading 은 폰트 content(19px) 위아래로 홀수(7px)만큼 남아
3829
3832
  // 3px/4px 로 쪼개지고 글자가 링 중심보다 위로 뜬다. (leading-normal 은 1.5 라 동일 문제)
3830
3833
  "absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 leading-[normal]"
3831
- ) : "leading-[26px]"
3834
+ ) : void 0
3832
3835
  ),
3833
3836
  style: { color: percentColor },
3834
3837
  children: [
@@ -3894,7 +3897,7 @@ var SCircleProgress = /* @__PURE__ */ react.forwardRef(
3894
3897
  showPercent && innerValue && percentNode
3895
3898
  ] }),
3896
3899
  showPercent && !innerValue && percentNode,
3897
- label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-center text-[12px] font-normal leading-[20px] text-[color:var(--cmp-progress-color-label)]", children: label })
3900
+ label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "typo-feedback-sm-regular text-center text-[color:var(--cmp-progress-color-label)]", children: label })
3898
3901
  ]
3899
3902
  }
3900
3903
  );
@@ -7631,6 +7634,10 @@ function TreeBranch({ expanded, children }) {
7631
7634
  }
7632
7635
  );
7633
7636
  }
7637
+ function isRowControlClick(event) {
7638
+ const control = event.target.closest("[data-tree-control]");
7639
+ return control != null && event.currentTarget.contains(control);
7640
+ }
7634
7641
  function STreeAllItem({
7635
7642
  selected,
7636
7643
  indeterminate,
@@ -7653,14 +7660,16 @@ function STreeAllItem({
7653
7660
  "data-tree-row": rowId,
7654
7661
  tabIndex,
7655
7662
  onKeyDown,
7656
- onClick: onSelect,
7663
+ onClick: (event) => {
7664
+ if (!isRowControlClick(event)) onSelect(event);
7665
+ },
7657
7666
  className: cn(
7658
7667
  "group/tree-item box-border flex w-full cursor-pointer items-center overflow-hidden bg-(--cmp-tree-item-bg-default) px-(--cmp-tree-item-paddingX) text-left hover:bg-(--cmp-tree-item-bg-hover)",
7659
7668
  typography.rowHeight,
7660
7669
  border && "border-b border-(--cmp-tree-item-border-default)"
7661
7670
  ),
7662
7671
  children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "box-border flex min-w-0 flex-1 items-center gap-(--cmp-tree-item-contentGap)", children: [
7663
- /* @__PURE__ */ jsxRuntime.jsx("span", { onClick: (event) => event.stopPropagation(), className: "flex shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(SCheckbox, { value: checkboxValue, onValueChange: () => onSelect() }) }),
7672
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-tree-control": true, className: "flex shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(SCheckbox, { value: checkboxValue, onValueChange: () => onSelect() }) }),
7664
7673
  /* @__PURE__ */ jsxRuntime.jsx(
7665
7674
  "span",
7666
7675
  {
@@ -7691,6 +7700,10 @@ var STreeItemImpl = /* @__PURE__ */ react.forwardRef(function STreeItem({
7691
7700
  trailing,
7692
7701
  onToggle,
7693
7702
  onTreeSelect,
7703
+ // treeitem 은 포커스를 받을 수 있어야 한다. tab 순서는 STree 가 한 줄에만 0 을 줘서 정한다(roving).
7704
+ tabIndex = -1,
7705
+ // 줄 단위 키보드 조작(화살표·Enter·Space)은 줄 사이를 오가야 해서 STree 가 쥐고 내려준다
7706
+ onKeyDown,
7694
7707
  className,
7695
7708
  ...rest
7696
7709
  }, ref) {
@@ -7715,6 +7728,11 @@ var STreeItemImpl = /* @__PURE__ */ react.forwardRef(function STreeItem({
7715
7728
  onTreeSelect?.(node, event);
7716
7729
  };
7717
7730
  const handleRowClick = (event) => {
7731
+ if (isRowControlClick(event)) return;
7732
+ if (selectable && event.target.closest("[data-tree-label]")) {
7733
+ handleSelect(event);
7734
+ return;
7735
+ }
7718
7736
  if (hasChildren) onToggle?.(node, event);
7719
7737
  };
7720
7738
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -7726,6 +7744,8 @@ var STreeItemImpl = /* @__PURE__ */ react.forwardRef(function STreeItem({
7726
7744
  "aria-expanded": hasChildren ? expanded : void 0,
7727
7745
  "aria-selected": selectable ? selected : void 0,
7728
7746
  "aria-disabled": node.disabled || void 0,
7747
+ tabIndex,
7748
+ onKeyDown,
7729
7749
  onClick: handleRowClick,
7730
7750
  className: cn(
7731
7751
  "group/tree-item box-border flex w-full items-center gap-(--cmp-tree-item-rowGap) overflow-hidden bg-(--cmp-tree-item-bg-default) px-(--cmp-tree-item-paddingX) text-left",
@@ -7771,7 +7791,7 @@ var STreeItemImpl = /* @__PURE__ */ react.forwardRef(function STreeItem({
7771
7791
  selectable && /* @__PURE__ */ jsxRuntime.jsx(
7772
7792
  "span",
7773
7793
  {
7774
- onClick: (event) => event.stopPropagation(),
7794
+ "data-tree-control": true,
7775
7795
  className: "flex shrink-0",
7776
7796
  "aria-hidden": node.disabled ? "true" : void 0,
7777
7797
  children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -7787,11 +7807,7 @@ var STreeItemImpl = /* @__PURE__ */ react.forwardRef(function STreeItem({
7787
7807
  /* @__PURE__ */ jsxRuntime.jsx(
7788
7808
  "span",
7789
7809
  {
7790
- onClick: (event) => {
7791
- if (!selectable) return;
7792
- event.stopPropagation();
7793
- if (!node.disabled && selectable) onTreeSelect?.(node, event);
7794
- },
7810
+ "data-tree-label": true,
7795
7811
  className: cn(
7796
7812
  "block min-w-0 flex-1 truncate py-(--cmp-tree-item-paddingY) text-(--cmp-tree-item-text-default)",
7797
7813
  labelTypo,
@@ -8795,6 +8811,7 @@ var SContextAlert = /* @__PURE__ */ react.forwardRef(function SContextAlert2({ i
8795
8811
  });
8796
8812
  var FILL_COLOR = {
8797
8813
  primary: "var(--cmp-progress-color-active)",
8814
+ warning: "var(--cmp-progress-color-warning)",
8798
8815
  error: "var(--cmp-progress-color-error)",
8799
8816
  complete: "var(--cmp-progress-color-success)"
8800
8817
  };
@@ -8803,20 +8820,20 @@ var SLinearProgress = /* @__PURE__ */ react.forwardRef(
8803
8820
  function SLinearProgress2({ value = 0, type = "primary", size = "sm", indeterminate = false, label, className, style }, ref) {
8804
8821
  const v = clamp2(value);
8805
8822
  const fill = FILL_COLOR[type];
8806
- const valueColor = v === 0 ? "var(--sys-color-fg-tertiary, #888888)" : fill;
8823
+ const valueColor = v === 0 ? "var(--sys-color-fg-tertiary)" : fill;
8807
8824
  const valueText = `${Math.round(v)}%`;
8808
8825
  const showValue = !indeterminate && size !== "xs";
8809
8826
  return /* @__PURE__ */ jsxRuntime.jsxs(
8810
8827
  "div",
8811
8828
  {
8812
8829
  ref,
8813
- className: cn("flex w-full flex-col gap-[12px]", className),
8830
+ className: cn("flex w-full flex-col gap-[var(--cmp-progress-linear-gap)]", className),
8814
8831
  style,
8815
8832
  children: [
8816
8833
  /* @__PURE__ */ jsxRuntime.jsxs(
8817
8834
  "div",
8818
8835
  {
8819
- className: "relative w-full overflow-hidden rounded-full bg-[var(--cmp-progress-color-track)]",
8836
+ className: "relative w-full overflow-hidden rounded-[var(--cmp-progress-linear-radius)] bg-[var(--cmp-progress-color-track)]",
8820
8837
  style: { height: `var(--cmp-progress-linear-height-${size})` },
8821
8838
  children: [
8822
8839
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -8833,7 +8850,7 @@ var SLinearProgress = /* @__PURE__ */ react.forwardRef(
8833
8850
  /* @__PURE__ */ jsxRuntime.jsx(
8834
8851
  "span",
8835
8852
  {
8836
- className: "pointer-events-none absolute inset-x-0 top-1/2 -translate-y-1/2 select-none text-center text-[12px] font-bold leading-[20px]",
8853
+ className: "pointer-events-none absolute inset-x-0 top-1/2 -translate-y-1/2 typo-feedback-sm-bold select-none text-center",
8837
8854
  style: { color: valueColor },
8838
8855
  children: valueText
8839
8856
  }
@@ -8841,7 +8858,7 @@ var SLinearProgress = /* @__PURE__ */ react.forwardRef(
8841
8858
  /* @__PURE__ */ jsxRuntime.jsx(
8842
8859
  "span",
8843
8860
  {
8844
- className: "pointer-events-none absolute inset-x-0 top-1/2 -translate-y-1/2 select-none text-center text-[12px] font-bold leading-[20px] text-[color:var(--cmp-progress-bar-text)]",
8861
+ className: "pointer-events-none absolute inset-x-0 top-1/2 -translate-y-1/2 typo-feedback-sm-bold select-none text-center text-[color:var(--cmp-progress-bar-text)]",
8845
8862
  style: { clipPath: `inset(0 ${100 - v}% 0 0)` },
8846
8863
  children: valueText
8847
8864
  }
@@ -8850,7 +8867,7 @@ var SLinearProgress = /* @__PURE__ */ react.forwardRef(
8850
8867
  ]
8851
8868
  }
8852
8869
  ),
8853
- label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-center text-[12px] font-normal leading-[20px] text-[color:var(--cmp-progress-color-label)]", children: label })
8870
+ label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "typo-feedback-sm-regular text-center text-[color:var(--cmp-progress-color-label)]", children: label })
8854
8871
  ]
8855
8872
  }
8856
8873
  );
@@ -15728,10 +15745,12 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
15728
15745
  }
15729
15746
  commitOpen(next);
15730
15747
  };
15748
+ const commitOpenRef = react.useRef(commitOpen);
15749
+ commitOpenRef.current = commitOpen;
15731
15750
  react.useEffect(() => {
15732
15751
  if (!insideModal || portalContainer == null || !pendingOpen) return;
15733
15752
  setPendingOpen(false);
15734
- commitOpen(true);
15753
+ commitOpenRef.current(true);
15735
15754
  }, [insideModal, pendingOpen, portalContainer]);
15736
15755
  const requestOpenRef = react.useRef(requestOpen);
15737
15756
  requestOpenRef.current = requestOpen;
@@ -15933,6 +15952,7 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
15933
15952
  return labelByValue.get(selected[0]) ?? valueOptions.get(selected[0])?.label ?? selected[0];
15934
15953
  })();
15935
15954
  const isPlaceholder = selected.length === 0;
15955
+ const showTriggerSpinner = loading2 && !effectiveDisabled;
15936
15956
  const showClear = clearable && !effectiveDisabled && !isPlaceholder;
15937
15957
  const handleClear = () => {
15938
15958
  emit3([]);
@@ -16107,6 +16127,7 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
16107
16127
  "aria-expanded": open,
16108
16128
  "aria-controls": open ? listboxId : void 0,
16109
16129
  "aria-activedescendant": open && focusedIndex >= 0 ? activeOptionId : void 0,
16130
+ "aria-busy": showTriggerSpinner || void 0,
16110
16131
  onClick: () => requestOpen(!open),
16111
16132
  onKeyDown: handleKeyDown,
16112
16133
  className: "flex h-full w-full cursor-pointer items-center justify-between gap-[8px] bg-transparent px-[12px] text-left text-[12px] leading-[20px] outline-none disabled:cursor-not-allowed",
@@ -16158,7 +16179,7 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
16158
16179
  ]
16159
16180
  }
16160
16181
  ),
16161
- /* @__PURE__ */ jsxRuntime.jsx(
16182
+ showTriggerSpinner ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "inline-flex shrink-0", "data-select-trigger-spinner": true, children: /* @__PURE__ */ jsxRuntime.jsx(SCircleProgress, { indeterminate: true, type: "neutral", size: 12 }) }) : /* @__PURE__ */ jsxRuntime.jsx(
16162
16183
  SIcon,
16163
16184
  {
16164
16185
  name: "chevronDown",
@@ -16274,12 +16295,15 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
16274
16295
  // 첫 페이지를 받는 중에는 "없다"고 단정하지 않는다 — 아래 로딩 표시가 대신 나온다.
16275
16296
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-[12px] py-[12px] text-left text-[12px] leading-[20px] text-[color:var(--cmp-listBoxItem-content-disabled)]", children: "\uD45C\uC2DC\uD560 \uD56D\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4." })
16276
16297
  ),
16277
- loading2 && /* @__PURE__ */ jsxRuntime.jsx(
16298
+ loading2 && /* @__PURE__ */ jsxRuntime.jsxs(
16278
16299
  "div",
16279
16300
  {
16280
16301
  role: "status",
16281
- className: "px-[12px] py-[12px] text-center text-[12px] leading-[20px] text-[color:var(--cmp-listBoxItem-content-disabled)]",
16282
- children: "\uBD88\uB7EC\uC624\uB294 \uC911..."
16302
+ className: "flex items-center justify-center gap-[8px] px-[12px] py-[12px] text-[12px] leading-[20px] text-[color:var(--cmp-listBoxItem-content-disabled)]",
16303
+ children: [
16304
+ /* @__PURE__ */ jsxRuntime.jsx(SCircleProgress, { indeterminate: true, type: "neutral", size: 16 }),
16305
+ "\uBD88\uB7EC\uC624\uB294 \uC911..."
16306
+ ]
16283
16307
  }
16284
16308
  )
16285
16309
  ]
@@ -16549,7 +16573,7 @@ var colWidthFromDef = (c) => {
16549
16573
  const px = typeof c.width === "number" ? c.width : parseInt(c.width, 10);
16550
16574
  return Number.isFinite(px) ? px : DEFAULT_COLUMN_WIDTH;
16551
16575
  };
16552
- var STable = /* @__PURE__ */ react.forwardRef(function STable2({
16576
+ var STableImpl = /* @__PURE__ */ react.forwardRef(function STable({
16553
16577
  columns = [],
16554
16578
  headerGroups,
16555
16579
  rows = [],
@@ -17659,6 +17683,7 @@ var STable = /* @__PURE__ */ react.forwardRef(function STable2({
17659
17683
  }
17660
17684
  );
17661
17685
  });
17686
+ var STable2 = STableImpl;
17662
17687
  var COUNT_NULL = "var(--cmp-table-bar-count-null)";
17663
17688
  var totalColor = (n) => n > 0 ? "var(--cmp-table-bar-count-total)" : COUNT_NULL;
17664
17689
  var selectedColor = (n) => n > 0 ? "var(--color-brilliantblue-75)" : COUNT_NULL;
@@ -18465,11 +18490,13 @@ function SCalendar({
18465
18490
  const base = value || today;
18466
18491
  const [y, setY] = react.useState(() => Number(base.split("-")[0]));
18467
18492
  const [m, setM] = react.useState(() => Number(base.split("-")[1]));
18468
- react.useEffect(() => {
18493
+ const [syncedValue, setSyncedValue] = react.useState(value);
18494
+ if (syncedValue !== value) {
18495
+ setSyncedValue(value);
18469
18496
  const b = value || today;
18470
18497
  setY(Number(b.split("-")[0]));
18471
18498
  setM(Number(b.split("-")[1]));
18472
- }, [value]);
18499
+ }
18473
18500
  const cells = react.useMemo(() => monthCells(y, m), [y, m]);
18474
18501
  const eventMap = react.useMemo(() => {
18475
18502
  const map = /* @__PURE__ */ new Map();
@@ -19792,6 +19819,7 @@ var SChipImpl = /* @__PURE__ */ react.forwardRef(function SChip({
19792
19819
  {
19793
19820
  ref: inputRef,
19794
19821
  role: "textbox",
19822
+ tabIndex: 0,
19795
19823
  contentEditable: !disabled,
19796
19824
  suppressContentEditableWarning: true,
19797
19825
  spellCheck: false,
@@ -22216,6 +22244,7 @@ var SToastContainer = /* @__PURE__ */ react.forwardRef(
22216
22244
  const [mounted2, setMounted] = react.useState(false);
22217
22245
  const timers = react.useRef(/* @__PURE__ */ new Map());
22218
22246
  const elRefs = react.useRef(/* @__PURE__ */ new Map());
22247
+ const resizeObserverRef = react.useRef(null);
22219
22248
  const [heights, setHeights] = react.useState(/* @__PURE__ */ new Map());
22220
22249
  const onShowRef = react.useRef(onShow);
22221
22250
  const onDismissRef = react.useRef(onDismiss);
@@ -22229,6 +22258,8 @@ var SToastContainer = /* @__PURE__ */ react.forwardRef(
22229
22258
  if (!liveIds.current.has(id)) return;
22230
22259
  liveIds.current.delete(id);
22231
22260
  setToasts((prev) => prev.filter((t) => t.id !== id));
22261
+ const el = elRefs.current.get(id);
22262
+ if (el) resizeObserverRef.current?.unobserve(el);
22232
22263
  elRefs.current.delete(id);
22233
22264
  setHeights((prev) => {
22234
22265
  if (!prev.has(id)) return prev;
@@ -22262,21 +22293,31 @@ var SToastContainer = /* @__PURE__ */ react.forwardRef(
22262
22293
  });
22263
22294
  return () => cancelAnimationFrame(raf);
22264
22295
  }, [toasts]);
22265
- react.useLayoutEffect(() => {
22266
- let changed = false;
22267
- const next = new Map(heights);
22268
- toasts.forEach((t) => {
22269
- const el = elRefs.current.get(t.id);
22270
- if (el) {
22296
+ react.useEffect(() => {
22297
+ if (typeof ResizeObserver === "undefined") return;
22298
+ const observer = new ResizeObserver((entries4) => {
22299
+ const measured = [];
22300
+ for (const entry of entries4) {
22301
+ const el = entry.target;
22302
+ const id = el.dataset.toastId;
22271
22303
  const h = el.offsetHeight;
22272
- if (h > 0 && next.get(t.id) !== h) {
22273
- next.set(t.id, h);
22274
- changed = true;
22275
- }
22304
+ if (id != null && h > 0 && liveIds.current.has(id)) measured.push([id, h]);
22276
22305
  }
22306
+ if (measured.length === 0) return;
22307
+ setHeights((prev) => {
22308
+ if (measured.every(([id, h]) => prev.get(id) === h)) return prev;
22309
+ const next = new Map(prev);
22310
+ for (const [id, h] of measured) next.set(id, h);
22311
+ return next;
22312
+ });
22277
22313
  });
22278
- if (changed) setHeights(next);
22279
- });
22314
+ resizeObserverRef.current = observer;
22315
+ elRefs.current.forEach((el) => observer.observe(el));
22316
+ return () => {
22317
+ observer.disconnect();
22318
+ resizeObserverRef.current = null;
22319
+ };
22320
+ }, []);
22280
22321
  const scheduleAutoClose = react.useCallback(
22281
22322
  (id, duration) => {
22282
22323
  if (duration > 0)
@@ -22415,8 +22456,11 @@ var SToastContainer = /* @__PURE__ */ react.forwardRef(
22415
22456
  children: toasts.map((entry) => /* @__PURE__ */ jsxRuntime.jsx(
22416
22457
  "div",
22417
22458
  {
22459
+ "data-toast-id": entry.id,
22418
22460
  ref: (el) => {
22419
- if (el) elRefs.current.set(entry.id, el);
22461
+ if (el == null || elRefs.current.get(entry.id) === el) return;
22462
+ elRefs.current.set(entry.id, el);
22463
+ resizeObserverRef.current?.observe(el);
22420
22464
  },
22421
22465
  style: itemStyle(entry),
22422
22466
  children: /* @__PURE__ */ jsxRuntime.jsx(SToast, { ...entry.options, onClose: () => startDismiss(entry.id) })
@@ -26737,7 +26781,16 @@ var SChipInput = /* @__PURE__ */ react.forwardRef(function SChipInput2({
26737
26781
  const loading2 = effectiveAutocomplete ? loadingSuggestions && suggestions.length === 0 : loadingRecommendedItems && recommendedItems.length === 0;
26738
26782
  const isFieldEmpty = inputValue === "" && values.length > 0 && !focused;
26739
26783
  const isFieldFilled = inputValue !== "";
26784
+ const reopenDropdown = () => {
26785
+ setSuppressSuggestions(false);
26786
+ setSuppressRecommendations(false);
26787
+ };
26740
26788
  const onKeyDown = (e) => {
26789
+ if (e.key === "ArrowDown" && !showDropdown && (inputValue === "" ? suppressRecommendations : suppressSuggestions)) {
26790
+ e.preventDefault();
26791
+ reopenDropdown();
26792
+ return;
26793
+ }
26741
26794
  if (showDropdown && items.length > 0) {
26742
26795
  if (e.key === "ArrowDown") {
26743
26796
  e.preventDefault();
@@ -26815,10 +26868,10 @@ var SChipInput = /* @__PURE__ */ react.forwardRef(function SChipInput2({
26815
26868
  "relative box-border flex w-full flex-wrap content-center items-center gap-(--cmp-chipInput-chip-gap)",
26816
26869
  size === "md" ? "min-h-(--cmp-chipInput-md-minHeight) px-(--cmp-chipInput-md-paddingX) py-(--cmp-chipInput-md-paddingY)" : "min-h-(--cmp-chipInput-sm-minHeight) px-(--cmp-chipInput-sm-paddingX) py-(--cmp-chipInput-sm-paddingY)"
26817
26870
  ),
26871
+ role: "presentation",
26818
26872
  onClick: () => {
26819
26873
  if (!disabled) {
26820
- setSuppressSuggestions(false);
26821
- setSuppressRecommendations(false);
26874
+ reopenDropdown();
26822
26875
  inputRef.current?.focus();
26823
26876
  }
26824
26877
  },
@@ -26949,6 +27002,7 @@ var SChipInput = /* @__PURE__ */ react.forwardRef(function SChipInput2({
26949
27002
  metaPlacement === "end" && "ml-auto"
26950
27003
  ),
26951
27004
  "data-placement": metaPlacement,
27005
+ role: "presentation",
26952
27006
  onMouseDown: (e) => e.preventDefault(),
26953
27007
  children: [
26954
27008
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -27005,6 +27059,7 @@ var SChipInput = /* @__PURE__ */ react.forwardRef(function SChipInput2({
27005
27059
  {
27006
27060
  id: listboxId,
27007
27061
  role: "listbox",
27062
+ tabIndex: -1,
27008
27063
  className: "s-chip-input__suggestions flex w-full flex-col outline-none",
27009
27064
  onMouseDown: (e) => e.preventDefault(),
27010
27065
  children: [
@@ -27018,6 +27073,7 @@ var SChipInput = /* @__PURE__ */ react.forwardRef(function SChipInput2({
27018
27073
  id: active ? activeOptionId : void 0,
27019
27074
  role: "option",
27020
27075
  "aria-selected": selected || active,
27076
+ tabIndex: -1,
27021
27077
  className: "rounded-full",
27022
27078
  style: active ? { outline: "2px solid var(--color-border-accent)", outlineOffset: 1 } : void 0,
27023
27079
  onMouseDown: (e) => {
@@ -27037,6 +27093,7 @@ var SChipInput = /* @__PURE__ */ react.forwardRef(function SChipInput2({
27037
27093
  id: active ? activeOptionId : void 0,
27038
27094
  role: "option",
27039
27095
  "aria-selected": selected || active,
27096
+ tabIndex: -1,
27040
27097
  className: cn(
27041
27098
  "s-chip-input__suggestion-item flex shrink-0 cursor-pointer items-center gap-sd-8 overflow-hidden text-ellipsis whitespace-nowrap px-sd-12 py-sd-4 text-12 leading-sd-20",
27042
27099
  selected ? "cursor-default overflow-visible font-bold text-(--cmp-listBoxItem-content-selected)" : active ? "bg-(--cmp-listBoxItem-bg-hover) font-medium text-(--cmp-listBoxItem-content-hover)" : "text-(--cmp-listBoxItem-content-default)"
@@ -28305,7 +28362,7 @@ exports.SStepper = SStepper;
28305
28362
  exports.SSwitch = SSwitch;
28306
28363
  exports.SSystemActionButton = SSystemActionButton;
28307
28364
  exports.STEPPER_SIZES = STEPPER_SIZES;
28308
- exports.STable = STable;
28365
+ exports.STable = STable2;
28309
28366
  exports.STableBar = STableBar;
28310
28367
  exports.STabs = STabs;
28311
28368
  exports.STag = STag;