sellmate-design-system-react 9.0.0-beta.77 → 9.0.0-beta.78

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.js CHANGED
@@ -15587,6 +15587,7 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
15587
15587
  name,
15588
15588
  options = [],
15589
15589
  type = "default",
15590
+ valueDisplay = "text",
15590
15591
  showSearch = false,
15591
15592
  showSelectAll = false,
15592
15593
  allSelectedLabel = "\uC804\uCCB4",
@@ -15619,6 +15620,7 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
15619
15620
  hint,
15620
15621
  errorMessage,
15621
15622
  width,
15623
+ size = "sm",
15622
15624
  className,
15623
15625
  style
15624
15626
  }, ref) {
@@ -15923,6 +15925,16 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
15923
15925
  }
15924
15926
  return labelByValue.get(selected[0]) ?? valueOptions.get(selected[0])?.label ?? selected[0];
15925
15927
  })();
15928
+ const showChips = valueDisplay === "chip" && multi && selected.length > 0 && !allSelected;
15929
+ const disabledValues = useMemo(
15930
+ () => new Set(flat.filter((o) => !o.isGroup && o.disabled).map((o) => o.value)),
15931
+ [flat]
15932
+ );
15933
+ const chips = showChips ? selected.map((v) => ({
15934
+ value: v,
15935
+ label: labelByValue.get(v) ?? valueOptions.get(v)?.label ?? v,
15936
+ removable: !effectiveDisabled && !disabledValues.has(v)
15937
+ })) : [];
15926
15938
  const isPlaceholder = selected.length === 0;
15927
15939
  const showTriggerSpinner = loading2 && !effectiveDisabled;
15928
15940
  const showClear = clearable && !effectiveDisabled && !isPlaceholder;
@@ -15930,6 +15942,12 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
15930
15942
  emit3([]);
15931
15943
  if (rules && rules.length > 0) setRuleError(runRules(multi ? [] : "", rules));
15932
15944
  };
15945
+ const handleRemoveChip = (target) => {
15946
+ const next = selected.filter((v) => v !== target);
15947
+ emit3(next);
15948
+ if (rules && rules.length > 0) setRuleError(runRules(next, rules));
15949
+ triggerRef.current?.focus();
15950
+ };
15933
15951
  const handleSelect = (nextValue, index, extend = false) => {
15934
15952
  if (multi) {
15935
15953
  const anchor = rangeAnchorRef.current;
@@ -16085,6 +16103,8 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
16085
16103
  errorMessage: ruleError !== "" ? ruleError : errorMessage,
16086
16104
  disabled: effectiveDisabled,
16087
16105
  width,
16106
+ size,
16107
+ multiline: showChips,
16088
16108
  className,
16089
16109
  style,
16090
16110
  children: [
@@ -16102,55 +16122,59 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
16102
16122
  "aria-busy": showTriggerSpinner || void 0,
16103
16123
  onClick: () => requestOpen(!open),
16104
16124
  onKeyDown: handleKeyDown,
16105
- 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",
16125
+ className: cn(
16126
+ "flex h-full w-full cursor-pointer items-center justify-between bg-transparent text-left outline-none disabled:cursor-not-allowed",
16127
+ size === "md" ? "typo-body-md-default gap-(--cmp-select-md-gap) px-(--cmp-select-md-paddingX)" : "typo-body-sm-default gap-(--cmp-select-sm-gap) px-(--cmp-select-sm-paddingX)"
16128
+ ),
16106
16129
  style: {
16130
+ // 칩 한 줄이 기본 높이 안에서 세로 가운데에 오는 여백. 줄이 늘면 같은 여백을 유지한 채 트리거가 커진다.
16131
+ // sm 칩은 높이가 라벨 줄높이(typo-body-xs-medium)라 남는 높이가 4px 로 떨어진다.
16132
+ paddingBlock: showChips ? size === "md" ? "calc((var(--cmp-select-md-height) - var(--cmp-select-md-borderWidth) * 2 - var(--cmp-chip-height)) / 2)" : "var(--spacing-sd-4)" : void 0,
16107
16133
  color: effectiveDisabled ? "var(--cmp-select-text-disabled)" : isPlaceholder ? "var(--cmp-select-icon-default)" : "var(--cmp-select-text-default)"
16108
16134
  },
16109
16135
  children: [
16110
- isHtmlLabel(triggerText) ? /* @__PURE__ */ jsx(
16111
- "span",
16112
- {
16113
- className: "truncate",
16114
- dangerouslySetInnerHTML: { __html: sanitizeInlineHtml(triggerText) }
16115
- }
16116
- ) : /* @__PURE__ */ jsx("span", { className: "truncate", children: triggerText }),
16117
- /* @__PURE__ */ jsxs("span", { className: "flex shrink-0 items-center gap-[8px]", children: [
16118
- showClear && /* @__PURE__ */ jsxs(
16136
+ showChips ? (
16137
+ // md 는 SChip 과 같은 모양(높이 --cmp-chip-height)이다. SChip 을 그대로 넣지 않는 것은
16138
+ // SChip 의 × 가 <button> 이라 트리거 button 안에 중첩할 수 없어서다 — 모양만 같은 토큰으로 맞춘다.
16139
+ // sm 은 28px 트리거에 들어가도록 낮춘 칩 — 높이를 주지 않고 라벨 줄높이(typo-body-xs-medium)가 정한다.
16140
+ // 두 크기 모두 패딩·라벨↔× 간격은 chip 토큰 그대로.
16141
+ /* @__PURE__ */ jsx(
16119
16142
  "span",
16120
16143
  {
16121
- role: "button",
16122
- tabIndex: 0,
16123
- "aria-label": "\uC120\uD0DD \uC9C0\uC6B0\uAE30",
16124
- className: "group/select-clear relative inline-flex shrink-0 cursor-pointer items-center justify-center",
16125
- style: {
16126
- width: "var(--cmp-ghostButton-xxs-size)",
16127
- height: "var(--cmp-ghostButton-xxs-size)",
16128
- borderRadius: "var(--cmp-ghostButton-radius-sm)"
16129
- },
16130
- onClick: (event) => {
16131
- event.preventDefault();
16132
- event.stopPropagation();
16133
- handleClear();
16134
- },
16135
- onKeyDown: (event) => {
16136
- if (event.key !== "Enter" && event.key !== " ") return;
16137
- event.preventDefault();
16138
- event.stopPropagation();
16139
- handleClear();
16140
- },
16141
- children: [
16142
- /* @__PURE__ */ jsx(
16143
- "span",
16144
- {
16145
- "aria-hidden": true,
16146
- className: "pointer-events-none absolute inset-0 rounded-[inherit] opacity-0 transition-opacity duration-200 group-hover/select-clear:opacity-5",
16147
- style: { background: "var(--cmp-ghostButton-default-hover-bg)" }
16148
- }
16149
- ),
16150
- /* @__PURE__ */ jsx(SIcon, { name: "close", size: 12, color: "var(--cmp-ghostButton-default-content)" })
16151
- ]
16144
+ className: cn(
16145
+ "flex min-w-0 flex-1 flex-wrap items-center",
16146
+ size === "md" ? "gap-(--cmp-chipInput-chip-gap)" : "gap-sd-6"
16147
+ ),
16148
+ children: chips.map((chip) => /* @__PURE__ */ jsxs(
16149
+ "span",
16150
+ {
16151
+ className: cn(
16152
+ "box-border inline-flex min-w-0 max-w-full items-center gap-(--cmp-chip-gap) overflow-hidden whitespace-nowrap px-(--cmp-chip-paddingX)",
16153
+ size === "md" ? "h-(--cmp-chip-height) text-[12px] font-medium leading-[20px]" : "typo-body-xs-medium"
16154
+ ),
16155
+ style: {
16156
+ borderRadius: "var(--cmp-chip-radius)",
16157
+ background: chip.removable ? "var(--cmp-chip-bg-default)" : "var(--cmp-chip-bg-disabled)",
16158
+ color: chip.removable ? "var(--cmp-chip-content-default)" : "var(--cmp-chip-content-disabled)"
16159
+ },
16160
+ children: [
16161
+ /* @__PURE__ */ jsx(TriggerLabel, { label: chip.label }),
16162
+ chip.removable && /* @__PURE__ */ jsx(
16163
+ TriggerRemoveButton,
16164
+ {
16165
+ ariaLabel: `${isHtmlLabel(chip.label) ? extractText(chip.label) : chip.label} \uC120\uD0DD \uD574\uC81C`,
16166
+ onRemove: () => handleRemoveChip(chip.value)
16167
+ }
16168
+ )
16169
+ ]
16170
+ },
16171
+ chip.value
16172
+ ))
16152
16173
  }
16153
- ),
16174
+ )
16175
+ ) : /* @__PURE__ */ jsx(TriggerLabel, { label: triggerText }),
16176
+ /* @__PURE__ */ jsxs("span", { className: "flex shrink-0 items-center gap-[8px]", children: [
16177
+ showClear && /* @__PURE__ */ jsx(TriggerRemoveButton, { ariaLabel: "\uC120\uD0DD \uC9C0\uC6B0\uAE30", onRemove: handleClear }),
16154
16178
  showTriggerSpinner ? /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "inline-flex shrink-0", "data-select-trigger-spinner": true, children: /* @__PURE__ */ jsx(SCircleProgress, { indeterminate: true, type: "neutral", size: 12 }) }) : /* @__PURE__ */ jsx(
16155
16179
  SIcon,
16156
16180
  {
@@ -16482,6 +16506,47 @@ function ItemList({
16482
16506
  bottomSpacer > 0 && /* @__PURE__ */ jsx("div", { "aria-hidden": true, style: { height: bottomSpacer } })
16483
16507
  ] });
16484
16508
  }
16509
+ function TriggerLabel({ label }) {
16510
+ return isHtmlLabel(label) ? /* @__PURE__ */ jsx("span", { className: "truncate", dangerouslySetInnerHTML: { __html: sanitizeInlineHtml(label) } }) : /* @__PURE__ */ jsx("span", { className: "truncate", children: label });
16511
+ }
16512
+ function TriggerRemoveButton({ ariaLabel, onRemove }) {
16513
+ return /* @__PURE__ */ jsxs(
16514
+ "span",
16515
+ {
16516
+ role: "button",
16517
+ tabIndex: 0,
16518
+ "aria-label": ariaLabel,
16519
+ className: "group/select-remove relative inline-flex shrink-0 cursor-pointer items-center justify-center",
16520
+ style: {
16521
+ width: "var(--cmp-ghostButton-xxs-size)",
16522
+ height: "var(--cmp-ghostButton-xxs-size)",
16523
+ borderRadius: "var(--cmp-ghostButton-radius-sm)"
16524
+ },
16525
+ onClick: (event) => {
16526
+ event.preventDefault();
16527
+ event.stopPropagation();
16528
+ onRemove();
16529
+ },
16530
+ onKeyDown: (event) => {
16531
+ if (event.key !== "Enter" && event.key !== " ") return;
16532
+ event.preventDefault();
16533
+ event.stopPropagation();
16534
+ onRemove();
16535
+ },
16536
+ children: [
16537
+ /* @__PURE__ */ jsx(
16538
+ "span",
16539
+ {
16540
+ "aria-hidden": true,
16541
+ className: "pointer-events-none absolute inset-0 rounded-[inherit] opacity-0 transition-opacity duration-200 group-hover/select-remove:opacity-5",
16542
+ style: { background: "var(--cmp-ghostButton-default-hover-bg)" }
16543
+ }
16544
+ ),
16545
+ /* @__PURE__ */ jsx(SIcon, { name: "close", size: 12, color: "var(--cmp-ghostButton-default-content)" })
16546
+ ]
16547
+ }
16548
+ );
16549
+ }
16485
16550
  function CheckboxBox({
16486
16551
  state: state2,
16487
16552
  disabled = false,
@@ -22545,71 +22610,76 @@ function SRadioButton({
22545
22610
  }) {
22546
22611
  const s = SIZE_CONFIG2[size];
22547
22612
  const [hoveredValue, setHoveredValue] = useState(null);
22548
- return /* @__PURE__ */ jsx(
22549
- "div",
22550
- {
22551
- role: "radiogroup",
22552
- "aria-disabled": disabled,
22553
- className: cn("inline-flex", className),
22554
- style,
22555
- children: options.map((o, i) => {
22556
- const selected = o.value === value;
22557
- const od = disabled || o.disabled;
22558
- const first = i === 0;
22559
- const last = i === options.length - 1;
22560
- const tooltip = showTooltip && o.tooltip ? o.tooltip : void 0;
22561
- const button = /* @__PURE__ */ jsx(
22562
- "button",
22563
- {
22564
- type: "button",
22565
- role: "radio",
22566
- name,
22567
- "aria-checked": selected,
22568
- disabled: od,
22569
- onClick: () => !od && !selected && onValueChange?.(o.value),
22570
- onMouseEnter: tooltip ? () => setHoveredValue(o.value) : void 0,
22571
- onMouseLeave: tooltip ? () => setHoveredValue(null) : void 0,
22572
- onFocus: tooltip ? () => setHoveredValue(o.value) : void 0,
22573
- onBlur: tooltip ? () => setHoveredValue(null) : void 0,
22574
- className: cn(
22575
- "relative box-border grow inline-flex items-center justify-center whitespace-nowrap border border-solid font-medium transition-colors",
22576
- first ? "" : "-ml-px",
22577
- selected ? "z-10" : "",
22578
- !od && !selected && "hover:!bg-[var(--cmp-radioButton-bg-hover)] hover:!text-[color:var(--cmp-radioButton-content-hover)] hover:!border-[color:var(--cmp-radioButton-bg-hover)] hover:z-10",
22579
- od ? "cursor-not-allowed" : "cursor-pointer"
22580
- ),
22581
- style: {
22582
- height: `var(--cmp-radioButton-${size}-height)`,
22583
- padding: `0 var(--cmp-radioButton-${size}-paddingX)`,
22584
- fontSize: `${s.fontSize}px`,
22585
- lineHeight: `${s.lineHeight}px`,
22586
- borderRadius: [
22587
- first ? s.radius : "0",
22588
- last ? s.radius : "0",
22589
- last ? s.radius : "0",
22590
- first ? s.radius : "0"
22591
- ].join(" "),
22592
- background: od ? "var(--cmp-radioButton-bg-disabled)" : "var(--cmp-radioButton-bg-default)",
22593
- borderColor: od ? "var(--cmp-radioButton-border-disabled)" : selected ? "var(--cmp-radioButton-border-select)" : "var(--cmp-radioButton-border-default)",
22594
- color: od ? "var(--cmp-radioButton-content-disabled)" : selected ? "var(--cmp-radioButton-content-select)" : "var(--cmp-radioButton-content-default)"
22613
+ return (
22614
+ // isolate: 선택·hover 버튼의 z-10 은 겹친 테두리(-ml-px) 위로 올리기 위한 값이라 그룹 안에서
22615
+ // 끝나야 한다. 빼면 상위 컨텍스트까지 올라가 모달 안 floating 밴드(z-2)를 이겨, 위에서 연
22616
+ // SSelect listbox 위로 선택된 버튼만 뚫고 그려진다.
22617
+ /* @__PURE__ */ jsx(
22618
+ "div",
22619
+ {
22620
+ role: "radiogroup",
22621
+ "aria-disabled": disabled,
22622
+ className: cn("inline-flex isolate", className),
22623
+ style,
22624
+ children: options.map((o, i) => {
22625
+ const selected = o.value === value;
22626
+ const od = disabled || o.disabled;
22627
+ const first = i === 0;
22628
+ const last = i === options.length - 1;
22629
+ const tooltip = showTooltip && o.tooltip ? o.tooltip : void 0;
22630
+ const button = /* @__PURE__ */ jsx(
22631
+ "button",
22632
+ {
22633
+ type: "button",
22634
+ role: "radio",
22635
+ name,
22636
+ "aria-checked": selected,
22637
+ disabled: od,
22638
+ onClick: () => !od && !selected && onValueChange?.(o.value),
22639
+ onMouseEnter: tooltip ? () => setHoveredValue(o.value) : void 0,
22640
+ onMouseLeave: tooltip ? () => setHoveredValue(null) : void 0,
22641
+ onFocus: tooltip ? () => setHoveredValue(o.value) : void 0,
22642
+ onBlur: tooltip ? () => setHoveredValue(null) : void 0,
22643
+ className: cn(
22644
+ "relative box-border grow inline-flex items-center justify-center whitespace-nowrap border border-solid font-medium transition-colors",
22645
+ first ? "" : "-ml-px",
22646
+ selected ? "z-10" : "",
22647
+ !od && !selected && "hover:!bg-[var(--cmp-radioButton-bg-hover)] hover:!text-[color:var(--cmp-radioButton-content-hover)] hover:!border-[color:var(--cmp-radioButton-bg-hover)] hover:z-10",
22648
+ od ? "cursor-not-allowed" : "cursor-pointer"
22649
+ ),
22650
+ style: {
22651
+ height: `var(--cmp-radioButton-${size}-height)`,
22652
+ padding: `0 var(--cmp-radioButton-${size}-paddingX)`,
22653
+ fontSize: `${s.fontSize}px`,
22654
+ lineHeight: `${s.lineHeight}px`,
22655
+ borderRadius: [
22656
+ first ? s.radius : "0",
22657
+ last ? s.radius : "0",
22658
+ last ? s.radius : "0",
22659
+ first ? s.radius : "0"
22660
+ ].join(" "),
22661
+ background: od ? "var(--cmp-radioButton-bg-disabled)" : "var(--cmp-radioButton-bg-default)",
22662
+ borderColor: od ? "var(--cmp-radioButton-border-disabled)" : selected ? "var(--cmp-radioButton-border-select)" : "var(--cmp-radioButton-border-default)",
22663
+ color: od ? "var(--cmp-radioButton-content-disabled)" : selected ? "var(--cmp-radioButton-content-select)" : "var(--cmp-radioButton-content-default)"
22664
+ },
22665
+ children: o.label
22595
22666
  },
22596
- children: o.label
22597
- },
22598
- o.value
22599
- );
22600
- return tooltip ? /* @__PURE__ */ jsx(
22601
- STooltip2,
22602
- {
22603
- trigger: "none",
22604
- open: hoveredValue === o.value,
22605
- tooltipType: "accent",
22606
- message: [tooltip],
22607
- children: button
22608
- },
22609
- o.value
22610
- ) : button;
22611
- })
22612
- }
22667
+ o.value
22668
+ );
22669
+ return tooltip ? /* @__PURE__ */ jsx(
22670
+ STooltip2,
22671
+ {
22672
+ trigger: "none",
22673
+ open: hoveredValue === o.value,
22674
+ tooltipType: "accent",
22675
+ message: [tooltip],
22676
+ children: button
22677
+ },
22678
+ o.value
22679
+ ) : button;
22680
+ })
22681
+ }
22682
+ )
22613
22683
  );
22614
22684
  }
22615
22685
  function SRadioCard({