sellmate-design-system-react 0.1.10 → 0.1.11

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 (129) hide show
  1. package/dist/components/SActionModal/SActionModal.cjs +3 -1
  2. package/dist/components/SActionModal/SActionModal.cjs.map +1 -1
  3. package/dist/components/SActionModal/SActionModal.js +3 -1
  4. package/dist/components/SActionModal/SActionModal.js.map +1 -1
  5. package/dist/components/SBarcodeInput/SBarcodeInput.cjs +15 -2
  6. package/dist/components/SBarcodeInput/SBarcodeInput.cjs.map +1 -1
  7. package/dist/components/SBarcodeInput/SBarcodeInput.d.ts +3 -1
  8. package/dist/components/SBarcodeInput/SBarcodeInput.js +15 -2
  9. package/dist/components/SBarcodeInput/SBarcodeInput.js.map +1 -1
  10. package/dist/components/SCalendar/SCalendar.cjs +2 -0
  11. package/dist/components/SCalendar/SCalendar.cjs.map +1 -1
  12. package/dist/components/SCalendar/SCalendar.js +2 -0
  13. package/dist/components/SCalendar/SCalendar.js.map +1 -1
  14. package/dist/components/SChip/SChip.cjs +2 -0
  15. package/dist/components/SChip/SChip.cjs.map +1 -1
  16. package/dist/components/SChip/SChip.js +2 -0
  17. package/dist/components/SChip/SChip.js.map +1 -1
  18. package/dist/components/SChipInput/SChipInput.cjs +21 -3
  19. package/dist/components/SChipInput/SChipInput.cjs.map +1 -1
  20. package/dist/components/SChipInput/SChipInput.d.ts +5 -0
  21. package/dist/components/SChipInput/SChipInput.js +21 -3
  22. package/dist/components/SChipInput/SChipInput.js.map +1 -1
  23. package/dist/components/SChipInput/index.d.ts +1 -1
  24. package/dist/components/SConfirmModal/SConfirmModal.cjs +13 -10
  25. package/dist/components/SConfirmModal/SConfirmModal.cjs.map +1 -1
  26. package/dist/components/SConfirmModal/SConfirmModal.d.ts +7 -4
  27. package/dist/components/SConfirmModal/SConfirmModal.js +13 -10
  28. package/dist/components/SConfirmModal/SConfirmModal.js.map +1 -1
  29. package/dist/components/SDatePicker/SDatePicker.cjs +15 -2
  30. package/dist/components/SDatePicker/SDatePicker.cjs.map +1 -1
  31. package/dist/components/SDatePicker/SDatePicker.d.ts +3 -1
  32. package/dist/components/SDatePicker/SDatePicker.js +15 -2
  33. package/dist/components/SDatePicker/SDatePicker.js.map +1 -1
  34. package/dist/components/SDateRangePicker/SDateRangePicker.cjs +15 -2
  35. package/dist/components/SDateRangePicker/SDateRangePicker.cjs.map +1 -1
  36. package/dist/components/SDateRangePicker/SDateRangePicker.d.ts +3 -1
  37. package/dist/components/SDateRangePicker/SDateRangePicker.js +15 -2
  38. package/dist/components/SDateRangePicker/SDateRangePicker.js.map +1 -1
  39. package/dist/components/SDropdownButton/SDropdownButton.cjs +2 -0
  40. package/dist/components/SDropdownButton/SDropdownButton.cjs.map +1 -1
  41. package/dist/components/SDropdownButton/SDropdownButton.js +2 -0
  42. package/dist/components/SDropdownButton/SDropdownButton.js.map +1 -1
  43. package/dist/components/SField/SField.cjs +13 -2
  44. package/dist/components/SField/SField.cjs.map +1 -1
  45. package/dist/components/SField/SField.d.ts +4 -1
  46. package/dist/components/SField/SField.js +13 -2
  47. package/dist/components/SField/SField.js.map +1 -1
  48. package/dist/components/SFilePicker/SFilePicker.cjs +16 -3
  49. package/dist/components/SFilePicker/SFilePicker.cjs.map +1 -1
  50. package/dist/components/SFilePicker/SFilePicker.d.ts +3 -1
  51. package/dist/components/SFilePicker/SFilePicker.js +16 -3
  52. package/dist/components/SFilePicker/SFilePicker.js.map +1 -1
  53. package/dist/components/SGhostButton/SGhostButton.cjs +2 -0
  54. package/dist/components/SGhostButton/SGhostButton.cjs.map +1 -1
  55. package/dist/components/SGhostButton/SGhostButton.js +2 -0
  56. package/dist/components/SGhostButton/SGhostButton.js.map +1 -1
  57. package/dist/components/SGuide/SGuide.cjs +2 -0
  58. package/dist/components/SGuide/SGuide.cjs.map +1 -1
  59. package/dist/components/SGuide/SGuide.js +2 -0
  60. package/dist/components/SGuide/SGuide.js.map +1 -1
  61. package/dist/components/SInput/SInput.cjs +15 -2
  62. package/dist/components/SInput/SInput.cjs.map +1 -1
  63. package/dist/components/SInput/SInput.d.ts +4 -1
  64. package/dist/components/SInput/SInput.js +15 -2
  65. package/dist/components/SInput/SInput.js.map +1 -1
  66. package/dist/components/SKeyValueTable/SKeyValueTable.cjs +496 -206
  67. package/dist/components/SKeyValueTable/SKeyValueTable.cjs.map +1 -1
  68. package/dist/components/SKeyValueTable/SKeyValueTable.d.ts +27 -6
  69. package/dist/components/SKeyValueTable/SKeyValueTable.js +495 -205
  70. package/dist/components/SKeyValueTable/SKeyValueTable.js.map +1 -1
  71. package/dist/components/SLoadingModal/SLoadingModal.cjs +3 -1
  72. package/dist/components/SLoadingModal/SLoadingModal.cjs.map +1 -1
  73. package/dist/components/SLoadingModal/SLoadingModal.js +3 -1
  74. package/dist/components/SLoadingModal/SLoadingModal.js.map +1 -1
  75. package/dist/components/SModalContainer/SModalContainer.cjs +3 -1
  76. package/dist/components/SModalContainer/SModalContainer.cjs.map +1 -1
  77. package/dist/components/SModalContainer/SModalContainer.js +3 -1
  78. package/dist/components/SModalContainer/SModalContainer.js.map +1 -1
  79. package/dist/components/SNumberInput/SNumberInput.cjs +15 -2
  80. package/dist/components/SNumberInput/SNumberInput.cjs.map +1 -1
  81. package/dist/components/SNumberInput/SNumberInput.d.ts +2 -0
  82. package/dist/components/SNumberInput/SNumberInput.js +15 -2
  83. package/dist/components/SNumberInput/SNumberInput.js.map +1 -1
  84. package/dist/components/SPopover/SPopover.cjs +2 -0
  85. package/dist/components/SPopover/SPopover.cjs.map +1 -1
  86. package/dist/components/SPopover/SPopover.js +2 -0
  87. package/dist/components/SPopover/SPopover.js.map +1 -1
  88. package/dist/components/SPortal/SPortal.cjs +2 -0
  89. package/dist/components/SPortal/SPortal.cjs.map +1 -1
  90. package/dist/components/SPortal/SPortal.js +2 -0
  91. package/dist/components/SPortal/SPortal.js.map +1 -1
  92. package/dist/components/SSelect/SSelect.cjs +530 -262
  93. package/dist/components/SSelect/SSelect.cjs.map +1 -1
  94. package/dist/components/SSelect/SSelect.d.ts +4 -2
  95. package/dist/components/SSelect/SSelect.js +531 -262
  96. package/dist/components/SSelect/SSelect.js.map +1 -1
  97. package/dist/components/STable/STable.cjs +529 -261
  98. package/dist/components/STable/STable.cjs.map +1 -1
  99. package/dist/components/STable/STable.js +530 -261
  100. package/dist/components/STable/STable.js.map +1 -1
  101. package/dist/components/STextLink/STextLink.cjs +2 -0
  102. package/dist/components/STextLink/STextLink.cjs.map +1 -1
  103. package/dist/components/STextLink/STextLink.js +2 -0
  104. package/dist/components/STextLink/STextLink.js.map +1 -1
  105. package/dist/components/STextarea/STextarea.cjs +15 -2
  106. package/dist/components/STextarea/STextarea.cjs.map +1 -1
  107. package/dist/components/STextarea/STextarea.d.ts +2 -0
  108. package/dist/components/STextarea/STextarea.js +15 -2
  109. package/dist/components/STextarea/STextarea.js.map +1 -1
  110. package/dist/components/SToast/SToast.cjs +2 -0
  111. package/dist/components/SToast/SToast.cjs.map +1 -1
  112. package/dist/components/SToast/SToast.js +2 -0
  113. package/dist/components/SToast/SToast.js.map +1 -1
  114. package/dist/components/SToast/SToastContainer.cjs +2 -0
  115. package/dist/components/SToast/SToastContainer.cjs.map +1 -1
  116. package/dist/components/SToast/SToastContainer.js +2 -0
  117. package/dist/components/SToast/SToastContainer.js.map +1 -1
  118. package/dist/components/STooltip/STooltip.cjs +2 -0
  119. package/dist/components/STooltip/STooltip.cjs.map +1 -1
  120. package/dist/components/STooltip/STooltip.js +2 -0
  121. package/dist/components/STooltip/STooltip.js.map +1 -1
  122. package/dist/index.cjs +412 -184
  123. package/dist/index.cjs.map +1 -1
  124. package/dist/index.d.ts +0 -1
  125. package/dist/index.js +413 -184
  126. package/dist/index.js.map +1 -1
  127. package/dist/lib/portal-container.d.ts +7 -0
  128. package/dist/styles.css +61 -37
  129. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3505,10 +3505,15 @@ var FLOATING_SLIDE_ANIM = [
3505
3505
  "data-[state=closed]:data-[side=right]:animate-floating-out-right"
3506
3506
  ].join(" ");
3507
3507
  var PortalContainerContext = createContext(null);
3508
+ var InsideModalContext = createContext(false);
3508
3509
  var PortalContainerProvider = PortalContainerContext.Provider;
3510
+ var InsideModalProvider = InsideModalContext.Provider;
3509
3511
  function usePortalContainer() {
3510
3512
  return useContext(PortalContainerContext) ?? void 0;
3511
3513
  }
3514
+ function useInsideModal() {
3515
+ return useContext(InsideModalContext);
3516
+ }
3512
3517
  var SIZE_CONFIG = {
3513
3518
  sm: {
3514
3519
  gap: 4,
@@ -4619,7 +4624,7 @@ function SModalContainer({
4619
4624
  className: "absolute right-[16px] top-[16px] z-10"
4620
4625
  }
4621
4626
  ),
4622
- /* @__PURE__ */ jsx(PortalContainerProvider, { value: portalContainer, children })
4627
+ /* @__PURE__ */ jsx(InsideModalProvider, { value: true, children: /* @__PURE__ */ jsx(PortalContainerProvider, { value: portalContainer, children }) })
4623
4628
  ]
4624
4629
  }
4625
4630
  )
@@ -4665,7 +4670,8 @@ function SConfirmModal({
4665
4670
  tagSize = "sm",
4666
4671
  tagColor = "grey",
4667
4672
  slotLabel,
4668
- children,
4673
+ tagSlot,
4674
+ optionSlot,
4669
4675
  mainButtonLabel = "\uD655\uC778",
4670
4676
  mainButtonName,
4671
4677
  subButtonLabel,
@@ -4675,6 +4681,9 @@ function SConfirmModal({
4675
4681
  }) {
4676
4682
  const iconName = TYPE_ICON[type];
4677
4683
  const mainStyle = MAIN_BUTTON_STYLE[mainButtonName ?? DEFAULT_MAIN_BUTTON[type]];
4684
+ const tagNode = tagSlot ?? (tagLabel ? /* @__PURE__ */ jsx(STag, { shape: tagShape, size: tagSize, color: tagColor, label: tagLabel }) : null);
4685
+ const optionNode = optionSlot ?? (slotLabel ? /* @__PURE__ */ jsx("span", { children: slotLabel }) : null);
4686
+ const hasBody = topMessage.length > 0 || bottomMessage.length > 0 || tagNode != null || optionNode != null;
4678
4687
  return /* @__PURE__ */ jsx(
4679
4688
  SModalContainer,
4680
4689
  {
@@ -4700,15 +4709,12 @@ function SConfirmModal({
4700
4709
  }
4701
4710
  )
4702
4711
  ] }),
4703
- (topMessage.length > 0 || bottomMessage.length > 0 || tagLabel || slotLabel || children) && /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-[20px] text-center text-[12px] font-normal leading-[20px] text-[color:var(--cmp-modal-confirm-message-color)]", children: [
4712
+ hasBody && /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-[20px] text-center text-[12px] font-normal leading-[20px] text-[color:var(--cmp-modal-confirm-message-color)] w-full", children: [
4704
4713
  topMessage.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-[2px]", children: topMessage.map((m, i) => /* @__PURE__ */ jsx("p", { className: "m-0", children: m }, i)) }),
4705
- (tagLabel || slotLabel || children) && // content-box: 흰 박스 + 1px 테두리 + 패딩 + 14/700 (원본 sd-confirm-modal__content-box)
4706
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-[8px] rounded-[8px] border border-solid border-[color:var(--color-grey-30)] bg-white px-[16px] py-[12px] text-[14px] font-bold leading-[22px]", children: [
4707
- tagLabel && /* @__PURE__ */ jsx(STag, { shape: tagShape, size: tagSize, color: tagColor, label: tagLabel }),
4708
- slotLabel && /* @__PURE__ */ jsx("span", { children: slotLabel }),
4709
- children
4710
- ] }),
4711
- bottomMessage.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-[2px]", children: bottomMessage.map((m, i) => /* @__PURE__ */ jsx("p", { className: "m-0", children: m }, i)) })
4714
+ tagNode != null && // tag 위치 content-box: 흰 박스 + 1px 테두리 + 패딩 + 14/700 (원본 sd-confirm-modal__content-box)
4715
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center gap-[8px] rounded-[8px] border border-solid border-[color:var(--color-grey-30)] bg-white px-[16px] py-[12px] text-[14px] font-bold leading-[22px] w-full", children: tagNode }),
4716
+ bottomMessage.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-[2px]", children: bottomMessage.map((m, i) => /* @__PURE__ */ jsx("p", { className: "m-0", children: m }, i)) }),
4717
+ optionNode != null && optionNode
4712
4718
  ] })
4713
4719
  ] }),
4714
4720
  /* @__PURE__ */ jsxs("div", { className: "flex gap-[8px]", children: [
@@ -5209,6 +5215,7 @@ var SField = forwardRef(function SField2({
5209
5215
  name,
5210
5216
  label = "",
5211
5217
  icon,
5218
+ iconColor,
5212
5219
  labelTooltip = "",
5213
5220
  labelTooltipProps,
5214
5221
  labelWidth,
@@ -5286,7 +5293,15 @@ var SField = forwardRef(function SField2({
5286
5293
  lineHeight: `${s.lineHeight}px`
5287
5294
  },
5288
5295
  children: [
5289
- icon && /* @__PURE__ */ jsx(SIcon, { name: icon, size: s.icon, style: { marginRight: s.labelGap } }),
5296
+ icon && /* @__PURE__ */ jsx(
5297
+ SIcon,
5298
+ {
5299
+ name: icon,
5300
+ size: s.icon,
5301
+ color: iconColor,
5302
+ style: { marginRight: s.labelGap }
5303
+ }
5304
+ ),
5290
5305
  /* @__PURE__ */ jsx("span", { className: "min-w-0 overflow-hidden text-ellipsis whitespace-nowrap", children: label }),
5291
5306
  (labelTooltip !== "" || labelTooltipProps) && /* @__PURE__ */ jsx("span", { className: "shrink-0", style: { marginLeft: s.labelGap }, children: /* @__PURE__ */ jsx(
5292
5307
  STooltip,
@@ -5336,7 +5351,7 @@ var SField = forwardRef(function SField2({
5336
5351
  borderBottomLeftRadius: s.radius - 1
5337
5352
  },
5338
5353
  children: [
5339
- icon && !label && /* @__PURE__ */ jsx(SIcon, { name: icon, size: s.icon }),
5354
+ icon && !label && /* @__PURE__ */ jsx(SIcon, { name: icon, size: s.icon, color: iconColor }),
5340
5355
  effectiveAddonLabel
5341
5356
  ]
5342
5357
  }
@@ -5408,6 +5423,7 @@ var SSelect = forwardRef(function SSelect2({
5408
5423
  label,
5409
5424
  labelWidth,
5410
5425
  icon,
5426
+ iconColor,
5411
5427
  labelTooltip,
5412
5428
  addonLabel,
5413
5429
  addonAlign,
@@ -5419,18 +5435,15 @@ var SSelect = forwardRef(function SSelect2({
5419
5435
  }, ref) {
5420
5436
  const multi = type === "multi" || type === "multi_depth";
5421
5437
  const portalContainer = usePortalContainer();
5438
+ const insideModal = useInsideModal();
5422
5439
  const [search, setSearch] = useState("");
5423
5440
  const [ruleError, setRuleError] = useState("");
5424
5441
  const [open, setOpen] = useState(false);
5442
+ const [pendingOpen, setPendingOpen] = useState(false);
5443
+ const [focusedIndex, setFocusedIndex] = useState(-1);
5425
5444
  const triggerRef = useRef(null);
5426
- useImperativeHandle(
5427
- ref,
5428
- () => ({
5429
- focus: () => triggerRef.current?.focus(),
5430
- open: () => setOpen(true)
5431
- }),
5432
- []
5433
- );
5445
+ const searchInputRef = useRef(null);
5446
+ const listRef = useRef(null);
5434
5447
  const flat = useMemo(() => flattenOptions(options), [options]);
5435
5448
  const selectable = useMemo(() => selectableOptions(flat), [flat]);
5436
5449
  const hasLeaf = useMemo(() => flat.some((o) => !o.isGroup), [flat]);
@@ -5448,6 +5461,46 @@ var SSelect = forwardRef(function SSelect2({
5448
5461
  const arr = Array.isArray(value) ? value : [value];
5449
5462
  return arr.map((v) => v != null && typeof v === "object" ? v.value : v).filter((v) => v != null && v !== "").map(String);
5450
5463
  }, [value]);
5464
+ const selectedRef = useRef(selected);
5465
+ selectedRef.current = selected;
5466
+ const emit2 = (next) => {
5467
+ if (!onValueChange) return;
5468
+ const mapped = next.map(
5469
+ (v) => emitValue ? rawByValue.get(v) ?? v : optionByValue.get(v) ?? { value: v, label: v }
5470
+ );
5471
+ onValueChange(multi ? mapped : mapped[0] ?? (emitValue ? "" : null));
5472
+ };
5473
+ const commitOpen = (next) => {
5474
+ setOpen(next);
5475
+ onOpenChange?.(next);
5476
+ if (!next) {
5477
+ setPendingOpen(false);
5478
+ setSearch("");
5479
+ if (rules && rules.length > 0) {
5480
+ setRuleError(runRules(multi ? selectedRef.current : selectedRef.current[0] ?? "", rules));
5481
+ }
5482
+ }
5483
+ };
5484
+ const requestOpen = (next) => {
5485
+ if (next && insideModal && portalContainer == null) {
5486
+ setPendingOpen(true);
5487
+ return;
5488
+ }
5489
+ commitOpen(next);
5490
+ };
5491
+ useEffect(() => {
5492
+ if (!insideModal || portalContainer == null || !pendingOpen) return;
5493
+ setPendingOpen(false);
5494
+ commitOpen(true);
5495
+ }, [insideModal, pendingOpen, portalContainer]);
5496
+ useImperativeHandle(
5497
+ ref,
5498
+ () => ({
5499
+ focus: () => triggerRef.current?.focus(),
5500
+ open: () => requestOpen(true)
5501
+ }),
5502
+ [insideModal, portalContainer]
5503
+ );
5451
5504
  useFormField({
5452
5505
  name,
5453
5506
  validate: () => {
@@ -5457,13 +5510,6 @@ var SSelect = forwardRef(function SSelect2({
5457
5510
  },
5458
5511
  resetValidation: () => setRuleError("")
5459
5512
  });
5460
- const emit2 = (next) => {
5461
- if (!onValueChange) return;
5462
- const mapped = next.map(
5463
- (v) => emitValue ? rawByValue.get(v) ?? v : optionByValue.get(v) ?? { value: v, label: v }
5464
- );
5465
- onValueChange(multi ? mapped : mapped[0] ?? (emitValue ? "" : null));
5466
- };
5467
5513
  const filtered = useMemo(() => {
5468
5514
  if (!showSearch || search.trim() === "") return flat;
5469
5515
  const q = search.trim().toLowerCase();
@@ -5474,6 +5520,16 @@ var SSelect = forwardRef(function SSelect2({
5474
5520
  const allValues = selectable.map((o) => o.value);
5475
5521
  const allSelected = allValues.length > 0 && allValues.every((v) => selected.includes(v));
5476
5522
  const hasItems = filtered.some((o) => !o.isGroup);
5523
+ const navigableItems = useMemo(() => {
5524
+ const items = [];
5525
+ if (multi && useSelectAll && allValues.length > 0) {
5526
+ items.push({ value: "__select_all__", isSelectAll: true });
5527
+ }
5528
+ filtered.forEach((o) => {
5529
+ if (!o.isGroup && !o.disabled) items.push({ value: o.value });
5530
+ });
5531
+ return items;
5532
+ }, [allValues.length, filtered, multi, useSelectAll]);
5477
5533
  const triggerText = (() => {
5478
5534
  if (selected.length === 0) return placeholder;
5479
5535
  if (multi) {
@@ -5483,26 +5539,119 @@ var SSelect = forwardRef(function SSelect2({
5483
5539
  return labelByValue.get(selected[0]) ?? selected[0];
5484
5540
  })();
5485
5541
  const isPlaceholder = selected.length === 0;
5486
- const selectStore = /* @__PURE__ */ jsxs(
5487
- Ariakit.SelectProvider,
5542
+ const handleSelect = (nextValue) => {
5543
+ if (multi) {
5544
+ const next = selected.includes(nextValue) ? selected.filter((v) => v !== nextValue) : [...selected, nextValue];
5545
+ emit2(next);
5546
+ return;
5547
+ }
5548
+ emit2([nextValue]);
5549
+ commitOpen(false);
5550
+ };
5551
+ const handleSelectAll = () => {
5552
+ emit2(allSelected ? [] : allValues);
5553
+ };
5554
+ useEffect(() => {
5555
+ if (!open) {
5556
+ setFocusedIndex(-1);
5557
+ return;
5558
+ }
5559
+ setFocusedIndex(navigableItems.length > 0 ? 0 : -1);
5560
+ }, [open, navigableItems.length]);
5561
+ useEffect(() => {
5562
+ if (!open) return;
5563
+ setFocusedIndex(navigableItems.length > 0 ? 0 : -1);
5564
+ }, [search, open, navigableItems.length]);
5565
+ useEffect(() => {
5566
+ if (!open || focusedIndex < 0) return;
5567
+ const list = listRef.current;
5568
+ const focusedEl = list?.querySelector('[data-select-focused="true"]');
5569
+ if (!list || !focusedEl) return;
5570
+ const listRect = list.getBoundingClientRect();
5571
+ const itemRect = focusedEl.getBoundingClientRect();
5572
+ if (itemRect.top < listRect.top) {
5573
+ list.scrollTop += itemRect.top - listRect.top;
5574
+ } else if (itemRect.bottom > listRect.bottom) {
5575
+ list.scrollTop += itemRect.bottom - listRect.bottom;
5576
+ }
5577
+ }, [focusedIndex, open]);
5578
+ const moveFocusedIndex = (direction) => {
5579
+ if (!open || navigableItems.length === 0) return;
5580
+ setFocusedIndex((current) => {
5581
+ if (direction === "next") {
5582
+ return current < 0 ? 0 : (current + 1) % navigableItems.length;
5583
+ }
5584
+ return current <= 0 ? navigableItems.length - 1 : current - 1;
5585
+ });
5586
+ };
5587
+ const selectFocusedItem = () => {
5588
+ if (focusedIndex < 0 || focusedIndex >= navigableItems.length) return;
5589
+ const focused = navigableItems[focusedIndex];
5590
+ if (focused.isSelectAll) {
5591
+ handleSelectAll();
5592
+ return;
5593
+ }
5594
+ handleSelect(focused.value);
5595
+ };
5596
+ const handleKeyDown = (event) => {
5597
+ if (!open) {
5598
+ if ((event.key === "ArrowDown" || event.key === "ArrowUp") && !effectiveDisabled) {
5599
+ event.preventDefault();
5600
+ requestOpen(true);
5601
+ }
5602
+ return;
5603
+ }
5604
+ if (event.key === "ArrowDown") {
5605
+ event.preventDefault();
5606
+ moveFocusedIndex("next");
5607
+ return;
5608
+ }
5609
+ if (event.key === "ArrowUp") {
5610
+ event.preventDefault();
5611
+ moveFocusedIndex("prev");
5612
+ return;
5613
+ }
5614
+ if (event.key === "Enter") {
5615
+ event.preventDefault();
5616
+ selectFocusedItem();
5617
+ return;
5618
+ }
5619
+ if (event.key === "Escape") {
5620
+ event.preventDefault();
5621
+ commitOpen(false);
5622
+ }
5623
+ };
5624
+ return /* @__PURE__ */ jsxs(
5625
+ SField,
5488
5626
  {
5489
- animated: portalContainer == null ? 150 : false,
5490
- value: multi ? selected : selected[0] ?? "",
5491
- setValue: (v) => emit2(Array.isArray(v) ? v : v === "" ? [] : [v]),
5492
- open,
5493
- setOpen: (o) => {
5494
- setOpen(o);
5495
- onOpenChange?.(o);
5496
- if (!o && rules && rules.length > 0) {
5497
- setRuleError(runRules(multi ? selected : selected[0] ?? "", rules));
5498
- }
5499
- },
5627
+ label,
5628
+ labelWidth,
5629
+ icon,
5630
+ iconColor,
5631
+ labelTooltip,
5632
+ labelTooltipProps,
5633
+ addonLabel,
5634
+ addonAlign,
5635
+ hint,
5636
+ error: error || ruleError !== "",
5637
+ status: rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0,
5638
+ errorMessage: ruleError !== "" ? ruleError : errorMessage,
5639
+ disabled: effectiveDisabled,
5640
+ width,
5641
+ className,
5642
+ style,
5500
5643
  children: [
5644
+ name && /* @__PURE__ */ jsx("input", { type: "hidden", name, value: selected.join(",") }),
5501
5645
  /* @__PURE__ */ jsxs(
5502
- Ariakit.Select,
5646
+ "button",
5503
5647
  {
5504
5648
  ref: triggerRef,
5649
+ type: "button",
5505
5650
  disabled: effectiveDisabled,
5651
+ "aria-haspopup": "listbox",
5652
+ "aria-expanded": open,
5653
+ onClick: () => requestOpen(!open),
5654
+ onKeyDown: handleKeyDown,
5506
5655
  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",
5507
5656
  style: {
5508
5657
  color: effectiveDisabled ? "var(--cmp-select-text-disabled)" : isPlaceholder ? "var(--cmp-select-icon-default)" : "var(--cmp-select-text-default)"
@@ -5527,178 +5676,229 @@ var SSelect = forwardRef(function SSelect2({
5527
5676
  ]
5528
5677
  }
5529
5678
  ),
5530
- /* @__PURE__ */ jsxs(
5531
- Ariakit.SelectPopover,
5679
+ /* @__PURE__ */ jsx(
5680
+ SPortal,
5532
5681
  {
5533
- portal: true,
5534
- portalElement: portalContainer,
5535
- gutter: 4,
5536
- sameWidth: !dropdownWidth,
5537
- className: "z-50 overflow-auto rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] shadow-[2px_2px_12px_2px_rgba(0,0,0,0.1)] data-[enter]:animate-floating-in-bottom data-[leave]:animate-floating-out-bottom",
5682
+ open,
5683
+ onClose: () => commitOpen(false),
5684
+ onOpenChange: (next) => {
5685
+ if (next) requestOpen(true);
5686
+ },
5687
+ anchorRef: triggerRef,
5688
+ placement: "bottom",
5689
+ align: "start",
5690
+ offset: 4,
5691
+ fit: !dropdownWidth,
5692
+ onOpenAutoFocus: (event) => {
5693
+ if (!showSearch) {
5694
+ event.preventDefault();
5695
+ return;
5696
+ }
5697
+ event.preventDefault();
5698
+ requestAnimationFrame(() => searchInputRef.current?.focus());
5699
+ },
5700
+ onCloseAutoFocus: (event) => {
5701
+ event.preventDefault();
5702
+ triggerRef.current?.focus();
5703
+ },
5704
+ className: "rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] py-[4px] shadow-[2px_2px_12px_2px_rgba(0,0,0,0.1)]",
5538
5705
  style: {
5539
- maxHeight: dropdownHeight,
5540
5706
  ...dropdownWidth ? { width: dropdownWidth } : {},
5541
5707
  maxWidth: maxDropdownWidth
5542
5708
  },
5543
- children: [
5544
- showSearch && // 원본 sd-select-list-item-search: sticky + 검색 아이콘 + 테두리 input + focus-within + clear
5545
- /* @__PURE__ */ jsx("div", { className: "sticky top-0 z-[1] bg-[var(--cmp-listBox-bg)] px-[8px] py-[4px]", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-[6px] rounded-[4px] border border-solid border-[color:var(--color-grey-45)] bg-white px-[8px] py-[4px] focus-within:border-[color:var(--sys-color-field-border-focus)]", children: [
5546
- /* @__PURE__ */ jsx(SIcon, { name: "search", size: 16, color: "var(--color-grey-70)", className: "shrink-0" }),
5547
- /* @__PURE__ */ jsx(
5548
- Ariakit.Combobox,
5549
- {
5550
- autoSelect: true,
5551
- placeholder: "\uAC80\uC0C9",
5552
- className: "min-w-0 flex-1 border-none bg-transparent text-[12px] leading-[20px] text-[color:var(--cmp-select-text-default)] outline-none placeholder:text-[color:var(--color-grey-55)]"
5553
- }
5554
- ),
5555
- search !== "" && /* @__PURE__ */ jsx(
5556
- SGhostButton,
5557
- {
5558
- icon: "close",
5559
- size: "xxs",
5560
- intent: "default",
5561
- ariaLabel: "\uAC80\uC0C9\uC5B4 \uC9C0\uC6B0\uAE30",
5562
- onClick: () => setSearch(""),
5563
- className: "shrink-0"
5564
- }
5565
- )
5566
- ] }) }),
5567
- multi && useSelectAll && /* @__PURE__ */ jsx(
5568
- "button",
5569
- {
5570
- type: "button",
5571
- className: "flex w-full items-center px-[12px] py-[4px] text-left text-[12px] leading-[20px] text-[color:var(--cmp-listItem-content-default)] hover:bg-[var(--cmp-listItem-bg-hover)] hover:text-[color:var(--cmp-listItem-content-hover)]",
5572
- onClick: () => emit2(allSelected ? [] : allValues),
5573
- children: allSelectedLabel
5574
- }
5575
- ),
5576
- hasItems ? /* @__PURE__ */ jsx(ItemList, { items: filtered, multi, selected, useSearch: showSearch }) : (
5577
- // 원본 sd-select-listbox__empty (표시할 항목이 없을 때)
5578
- /* @__PURE__ */ jsx("div", { className: "px-[12px] py-[12px] text-left text-[12px] leading-[20px] text-[color:var(--cmp-listItem-content-disabled)]", children: "\uD45C\uC2DC\uD560 \uD56D\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4." })
5579
- )
5580
- ]
5709
+ children: /* @__PURE__ */ jsxs(
5710
+ "div",
5711
+ {
5712
+ ref: listRef,
5713
+ className: "overflow-auto [scrollbar-width:auto] [&::-webkit-scrollbar]:w-[8px] [&::-webkit-scrollbar]:bg-[var(--color-grey-25)] [&::-webkit-scrollbar:horizontal]:h-[8px] [&::-webkit-scrollbar-thumb]:rounded-[4px] [&::-webkit-scrollbar-thumb]:bg-[var(--color-grey-45)] [&::-webkit-scrollbar-track]:bg-[var(--color-grey-25)]",
5714
+ style: { maxHeight: dropdownHeight },
5715
+ onMouseLeave: () => setFocusedIndex(-1),
5716
+ children: [
5717
+ showSearch && /* @__PURE__ */ jsx("div", { className: "sticky top-0 z-[1] bg-[var(--cmp-listBox-bg)] px-[8px] py-[4px]", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-[6px] rounded-[4px] border border-solid border-[color:var(--color-grey-45)] bg-white px-[8px] py-[4px] focus-within:border-[color:var(--sys-color-field-border-focus)]", children: [
5718
+ /* @__PURE__ */ jsx(SIcon, { name: "search", size: 16, color: "var(--color-grey-70)", className: "shrink-0" }),
5719
+ /* @__PURE__ */ jsx(
5720
+ "input",
5721
+ {
5722
+ ref: searchInputRef,
5723
+ value: search,
5724
+ onChange: (e) => setSearch(e.target.value),
5725
+ onKeyDown: handleKeyDown,
5726
+ placeholder: "\uAC80\uC0C9",
5727
+ className: "min-w-0 flex-1 border-none bg-transparent text-[12px] leading-[20px] text-[color:var(--cmp-select-text-default)] outline-none placeholder:text-[color:var(--color-grey-55)]"
5728
+ }
5729
+ ),
5730
+ search !== "" && /* @__PURE__ */ jsx(
5731
+ SGhostButton,
5732
+ {
5733
+ icon: "close",
5734
+ size: "xxs",
5735
+ intent: "default",
5736
+ ariaLabel: "\uAC80\uC0C9\uC5B4 \uC9C0\uC6B0\uAE30",
5737
+ onClick: () => setSearch(""),
5738
+ className: "shrink-0"
5739
+ }
5740
+ )
5741
+ ] }) }),
5742
+ hasItems ? /* @__PURE__ */ jsx(
5743
+ ItemList,
5744
+ {
5745
+ items: filtered,
5746
+ multi,
5747
+ selected,
5748
+ focusedValue: navigableItems[focusedIndex]?.isSelectAll ? "__select_all__" : navigableItems[focusedIndex]?.value,
5749
+ showSelectAll: multi && useSelectAll && allValues.length > 0,
5750
+ selectAllLabel: allSelectedLabel,
5751
+ selectAllSelected: allSelected,
5752
+ onSelectAll: handleSelectAll,
5753
+ onSelect: handleSelect,
5754
+ onHoverValue: (value2) => {
5755
+ const index = navigableItems.findIndex(
5756
+ (item) => item.isSelectAll ? value2 === "__select_all__" : item.value === value2
5757
+ );
5758
+ if (index >= 0) setFocusedIndex(index);
5759
+ }
5760
+ }
5761
+ ) : /* @__PURE__ */ jsx("div", { className: "px-[12px] py-[12px] text-left text-[12px] leading-[20px] text-[color:var(--cmp-listItem-content-disabled)]", children: "\uD45C\uC2DC\uD560 \uD56D\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4." })
5762
+ ]
5763
+ }
5764
+ )
5581
5765
  }
5582
5766
  )
5583
5767
  ]
5584
5768
  }
5585
5769
  );
5586
- const control = showSearch ? /* @__PURE__ */ jsx(Ariakit.ComboboxProvider, { value: search, setValue: setSearch, resetValueOnHide: true, children: selectStore }) : selectStore;
5587
- return /* @__PURE__ */ jsxs(
5588
- SField,
5589
- {
5590
- label,
5591
- labelWidth,
5592
- icon,
5593
- labelTooltip,
5594
- labelTooltipProps,
5595
- addonLabel,
5596
- addonAlign,
5597
- hint,
5598
- error: error || ruleError !== "",
5599
- status: rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0,
5600
- errorMessage: ruleError !== "" ? ruleError : errorMessage,
5601
- disabled: effectiveDisabled,
5602
- width,
5603
- className,
5604
- style,
5605
- children: [
5606
- name && /* @__PURE__ */ jsx("input", { type: "hidden", name, value: selected.join(",") }),
5607
- control
5608
- ]
5609
- }
5610
- );
5611
5770
  });
5612
5771
  SSelect.displayName = "SSelect";
5613
5772
  function ItemList({
5614
5773
  items,
5615
5774
  multi,
5616
5775
  selected,
5617
- useSearch
5776
+ focusedValue,
5777
+ showSelectAll,
5778
+ selectAllLabel,
5779
+ selectAllSelected,
5780
+ onSelectAll,
5781
+ onSelect,
5782
+ onHoverValue
5618
5783
  }) {
5619
5784
  const itemBase = cn(
5620
- // group: 체크박스 inverse(group-data-[active-item])를 위해 필요
5621
- "group flex cursor-pointer select-none items-center gap-[8px] text-[12px] leading-[20px] outline-none",
5785
+ "group flex w-full cursor-pointer select-none items-center gap-[8px] border-none bg-transparent text-left text-[12px] leading-[20px] outline-none",
5622
5786
  "text-[color:var(--cmp-listItem-content-default)]",
5623
- // Ariakit은 disabled 항목에 aria-disabled를 붙이므로 aria-disabled 변형으로 스타일 (data-disabled 아님)
5624
- "aria-disabled:cursor-not-allowed aria-disabled:text-[color:var(--cmp-listItem-content-disabled)]"
5625
- );
5626
- const activeClass = "data-[active-item]:bg-[var(--cmp-listItem-bg-hover)] data-[active-item]:text-[color:var(--cmp-listItem-content-hover)]";
5627
- return /* @__PURE__ */ jsx(Fragment, { children: items.map((o) => {
5628
- const padLeft = o.depth === 1 ? 12 : o.depth === 2 ? 20 : 28;
5629
- if (o.isGroup) {
5630
- const isDepth1 = o.depth === 1;
5631
- return /* @__PURE__ */ jsx(
5632
- "div",
5633
- {
5634
- className: cn(
5635
- "select-none py-[4px] pr-[12px] text-[12px] leading-[20px] text-[color:var(--cmp-listItem-content-default)]",
5636
- isDepth1 ? "border-t border-solid border-[color:var(--cmp-listItem-depth1-border-color)] bg-[var(--cmp-listItem-depth1-bg-default)] font-bold" : "bg-[var(--cmp-listItem-depth2-middle-bg)] font-medium",
5637
- // 하위가 전부 비활성이면(select.config 에서 bubble-up) 어미 그룹도 비활성 처리:
5638
- // 텍스트는 회색(#888), depth1 그룹은 파란 배경 대신 회색(#EEE)으로 (depth2 는 #F6F6F6 유지)
5639
- o.disabled && "cursor-not-allowed text-[color:var(--cmp-listItem-content-disabled)]",
5640
- o.disabled && isDepth1 && "bg-[var(--cmp-listItem-depth1-bg-disabled)]"
5641
- ),
5642
- style: { paddingLeft: padLeft },
5643
- children: o.label
5644
- },
5645
- o.value
5646
- );
5647
- }
5648
- const isSelected = selected.includes(o.value);
5649
- return /* @__PURE__ */ jsxs(
5650
- Ariakit.SelectItem,
5787
+ "disabled:cursor-not-allowed disabled:text-[color:var(--cmp-listItem-content-disabled)]"
5788
+ );
5789
+ const activeClass = "hover:bg-[var(--cmp-listItem-bg-hover)] hover:text-[color:var(--cmp-listItem-content-hover)] focus:bg-[var(--cmp-listItem-bg-hover)] focus:text-[color:var(--cmp-listItem-content-hover)]";
5790
+ return /* @__PURE__ */ jsxs("div", { role: "listbox", "aria-multiselectable": multi || void 0, children: [
5791
+ showSelectAll && /* @__PURE__ */ jsxs(
5792
+ "button",
5651
5793
  {
5652
- value: o.value,
5653
- disabled: o.disabled,
5654
- accessibleWhenDisabled: true,
5794
+ type: "button",
5795
+ "data-select-focused": focusedValue === "__select_all__" ? "true" : void 0,
5796
+ "data-select-active": focusedValue === "__select_all__" ? "true" : void 0,
5655
5797
  className: cn(
5656
5798
  itemBase,
5657
- isSelected && !multi && "font-bold text-[color:var(--cmp-listItem-content-selected)]",
5658
- // Ariakit은 disabled 항목도 hover 시 active(data-active-item) 처리하므로,
5659
- // 비활성 항목에는 hover 하이라이트를 적용하지 않아 회색 비활성 스타일을 유지한다.
5660
- // (원본 Stencil의 `--focused...:not(--disabled)` 규칙과 동일한 의도)
5661
- !o.disabled && activeClass
5799
+ focusedValue === "__select_all__" && "bg-[var(--cmp-listItem-bg-hover)] text-[color:var(--cmp-listItem-content-hover)]"
5662
5800
  ),
5663
- style: { paddingTop: 4, paddingBottom: 4, paddingRight: 12, paddingLeft: padLeft },
5664
- render: useSearch ? /* @__PURE__ */ jsx(Ariakit.ComboboxItem, {}) : void 0,
5801
+ style: { paddingTop: 4, paddingBottom: 4, paddingRight: 12, paddingLeft: 12 },
5802
+ onMouseEnter: () => onHoverValue("__select_all__"),
5803
+ onClick: onSelectAll,
5665
5804
  children: [
5666
- multi && // hover(active) 시 checkbox inverse — 파란 hover 배경 위에서 checked/unchecked 모두 흰 테두리 + 투명 배경
5667
5805
  /* @__PURE__ */ jsx(
5668
5806
  "span",
5669
5807
  {
5670
5808
  className: cn(
5671
5809
  "flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center rounded-[2px] border border-solid",
5672
- o.disabled ? (
5673
- // 비활성: 회색 채움(#E1E1E1) + 회색 테두리(#CCCCCC)
5674
- "cursor-not-allowed border-[color:var(--cmp-checkbox-border-disabled)] bg-[var(--cmp-checkbox-bg-disabled)]"
5675
- ) : cn(
5676
- "group-data-[active-item]:border-[color:var(--cmp-checkbox-checked-border-inverse)]",
5677
- isSelected ? "border-[color:var(--cmp-checkbox-checked-bg-default)] bg-[var(--cmp-checkbox-checked-bg-default)] group-data-[active-item]:bg-transparent" : "border-[color:var(--cmp-checkbox-unchecked-border-default)] bg-transparent"
5678
- )
5810
+ selectAllSelected ? focusedValue === "__select_all__" ? "border-[color:var(--cmp-checkbox-checked-border-inverse)] bg-[var(--cmp-checkbox-checked-bg-default)]" : "border-[color:var(--cmp-checkbox-checked-bg-default)] bg-[var(--cmp-checkbox-checked-bg-default)]" : "border-[color:var(--cmp-checkbox-unchecked-border-default)] bg-[var(--cmp-checkbox-unchecked-bg-default)]"
5679
5811
  ),
5680
- children: isSelected && /* @__PURE__ */ jsx(
5812
+ children: selectAllSelected && /* @__PURE__ */ jsx(
5681
5813
  SIcon,
5682
5814
  {
5683
5815
  name: "checkboxCheck",
5684
5816
  size: 12,
5685
- color: o.disabled ? "var(--cmp-checkbox-checked-icon-disabled)" : "var(--cmp-checkbox-checked-icon-default)"
5817
+ color: "var(--cmp-checkbox-checked-icon-default)"
5686
5818
  }
5687
5819
  )
5688
5820
  }
5689
5821
  ),
5690
- isHtmlLabel(o.label) ? /* @__PURE__ */ jsx(
5691
- "span",
5692
- {
5693
- className: "flex-1 truncate",
5694
- dangerouslySetInnerHTML: { __html: sanitizeInlineHtml(o.label) }
5695
- }
5696
- ) : /* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: o.label })
5822
+ /* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: selectAllLabel })
5697
5823
  ]
5698
- },
5699
- o.value
5700
- );
5701
- }) });
5824
+ }
5825
+ ),
5826
+ items.map((o) => {
5827
+ const padLeft = o.depth === 1 ? 12 : o.depth === 2 ? 20 : 28;
5828
+ if (o.isGroup) {
5829
+ const isDepth1 = o.depth === 1;
5830
+ return /* @__PURE__ */ jsx(
5831
+ "div",
5832
+ {
5833
+ className: cn(
5834
+ "select-none py-[4px] pr-[12px] text-[12px] leading-[20px] text-[color:var(--cmp-listItem-content-default)]",
5835
+ isDepth1 ? "border-t border-solid border-[color:var(--cmp-listItem-depth1-border-color)] bg-[var(--cmp-listItem-depth1-bg-default)] font-bold" : "bg-[var(--cmp-listItem-depth2-middle-bg)] font-medium",
5836
+ // 하위가 전부 비활성이면(select.config 에서 bubble-up) 어미 그룹도 비활성 처리:
5837
+ // 텍스트는 회색(#888), depth1 그룹은 파란 배경 대신 회색(#EEE)으로 (depth2 는 #F6F6F6 유지)
5838
+ o.disabled && "cursor-not-allowed text-[color:var(--cmp-listItem-content-disabled)]",
5839
+ o.disabled && isDepth1 && "bg-[var(--cmp-listItem-depth1-bg-disabled)]"
5840
+ ),
5841
+ style: { paddingLeft: padLeft },
5842
+ children: o.label
5843
+ },
5844
+ o.value
5845
+ );
5846
+ }
5847
+ const isSelected = selected.includes(o.value);
5848
+ return /* @__PURE__ */ jsxs(
5849
+ "button",
5850
+ {
5851
+ type: "button",
5852
+ disabled: o.disabled,
5853
+ role: "option",
5854
+ "aria-selected": isSelected,
5855
+ "data-select-focused": focusedValue === o.value ? "true" : void 0,
5856
+ "data-select-active": focusedValue === o.value ? "true" : void 0,
5857
+ className: cn(
5858
+ itemBase,
5859
+ isSelected && !multi && "font-bold text-[color:var(--cmp-listItem-content-selected)]",
5860
+ focusedValue === o.value && "bg-[var(--cmp-listItem-bg-hover)] text-[color:var(--cmp-listItem-content-hover)]",
5861
+ activeClass
5862
+ ),
5863
+ style: { paddingTop: 4, paddingBottom: 4, paddingRight: 12, paddingLeft: padLeft },
5864
+ onMouseEnter: () => onHoverValue(o.value),
5865
+ onClick: () => onSelect(o.value),
5866
+ children: [
5867
+ multi && /* @__PURE__ */ jsx(
5868
+ "span",
5869
+ {
5870
+ className: cn(
5871
+ "flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center rounded-[2px] border border-solid",
5872
+ o.disabled ? (
5873
+ // 비활성: 회색 채움(#E1E1E1) + 회색 테두리(#CCCCCC)
5874
+ "cursor-not-allowed border-[color:var(--cmp-checkbox-border-disabled)] bg-[var(--cmp-checkbox-bg-disabled)]"
5875
+ ) : cn(
5876
+ isSelected ? focusedValue === o.value ? "border-[color:var(--cmp-checkbox-checked-border-inverse)] bg-[var(--cmp-checkbox-checked-bg-default)]" : "border-[color:var(--cmp-checkbox-checked-bg-default)] bg-[var(--cmp-checkbox-checked-bg-default)]" : "border-[color:var(--cmp-checkbox-unchecked-border-default)] bg-[var(--cmp-checkbox-unchecked-bg-default)]"
5877
+ )
5878
+ ),
5879
+ children: isSelected && /* @__PURE__ */ jsx(
5880
+ SIcon,
5881
+ {
5882
+ name: "checkboxCheck",
5883
+ size: 12,
5884
+ color: o.disabled ? "var(--cmp-checkbox-checked-icon-disabled)" : "var(--cmp-checkbox-checked-icon-default)"
5885
+ }
5886
+ )
5887
+ }
5888
+ ),
5889
+ isHtmlLabel(o.label) ? /* @__PURE__ */ jsx(
5890
+ "span",
5891
+ {
5892
+ className: "flex-1 truncate",
5893
+ dangerouslySetInnerHTML: { __html: sanitizeInlineHtml(o.label) }
5894
+ }
5895
+ ) : /* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: o.label })
5896
+ ]
5897
+ },
5898
+ o.value
5899
+ );
5900
+ })
5901
+ ] });
5702
5902
  }
5703
5903
  var DEFAULT_ROW_HEIGHT = 44;
5704
5904
  var DENSE_ROW_HEIGHT = 32;
@@ -5974,7 +6174,7 @@ var STable = forwardRef(function STable2({
5974
6174
  };
5975
6175
  const radiusClass = radius === "full" ? "rounded-none" : radius === "useTop" ? "rounded-b-[var(--cmp-table-radius)] rounded-t-none" : "rounded-[var(--cmp-table-radius)]";
5976
6176
  const cellPadY = dense ? "var(--cmp-table-body-paddingY-dense)" : "var(--cmp-table-body-paddingY-default)";
5977
- const cellPadX = dense ? "var(--cmp-table-body-paddingX-default)" : "var(--cmp-table-body-paddingX-wide)";
6177
+ const cellPadX = "var(--cmp-table-body-paddingX-wide)";
5978
6178
  const rowH = dense ? "var(--cmp-table-body-dense-height)" : "var(--cmp-table-body-default-height)";
5979
6179
  const totalColSpan = visibleCols.length + (selectable ? 1 : 0);
5980
6180
  const stickyInfo = (i) => {
@@ -6221,6 +6421,7 @@ var SInput = forwardRef(function SInput2({
6221
6421
  type = "text",
6222
6422
  size = "sm",
6223
6423
  icon,
6424
+ iconColor,
6224
6425
  prefix,
6225
6426
  suffix,
6226
6427
  clearable = false,
@@ -6274,6 +6475,7 @@ var SInput = forwardRef(function SInput2({
6274
6475
  labelTooltip,
6275
6476
  labelTooltipProps,
6276
6477
  icon,
6478
+ iconColor,
6277
6479
  size,
6278
6480
  hint,
6279
6481
  error: resolvedError,
@@ -6375,6 +6577,7 @@ var STextarea = forwardRef(function STextarea2({
6375
6577
  label,
6376
6578
  labelWidth,
6377
6579
  icon,
6580
+ iconColor,
6378
6581
  labelTooltip,
6379
6582
  labelTooltipProps,
6380
6583
  addonLabel,
@@ -6411,6 +6614,7 @@ var STextarea = forwardRef(function STextarea2({
6411
6614
  label,
6412
6615
  labelWidth,
6413
6616
  icon,
6617
+ iconColor,
6414
6618
  labelTooltip,
6415
6619
  labelTooltipProps,
6416
6620
  addonLabel,
@@ -6543,6 +6747,7 @@ var SNumberInput = forwardRef(function SNumberInput2({
6543
6747
  label,
6544
6748
  labelWidth,
6545
6749
  icon,
6750
+ iconColor,
6546
6751
  labelTooltip,
6547
6752
  labelTooltipProps,
6548
6753
  addonLabel,
@@ -6701,6 +6906,7 @@ var SNumberInput = forwardRef(function SNumberInput2({
6701
6906
  label,
6702
6907
  labelWidth,
6703
6908
  icon,
6909
+ iconColor,
6704
6910
  labelTooltip,
6705
6911
  labelTooltipProps,
6706
6912
  addonLabel,
@@ -7176,6 +7382,7 @@ function SDatePicker({
7176
7382
  label,
7177
7383
  labelWidth,
7178
7384
  icon,
7385
+ iconColor,
7179
7386
  labelTooltip,
7180
7387
  labelTooltipProps,
7181
7388
  addonLabel,
@@ -7214,6 +7421,7 @@ function SDatePicker({
7214
7421
  label,
7215
7422
  labelWidth,
7216
7423
  icon,
7424
+ iconColor,
7217
7425
  labelTooltip,
7218
7426
  labelTooltipProps,
7219
7427
  addonLabel,
@@ -7482,6 +7690,7 @@ function SDateRangePicker({
7482
7690
  label,
7483
7691
  labelWidth,
7484
7692
  icon,
7693
+ iconColor,
7485
7694
  labelTooltip,
7486
7695
  labelTooltipProps,
7487
7696
  addonLabel,
@@ -7524,6 +7733,7 @@ function SDateRangePicker({
7524
7733
  label,
7525
7734
  labelWidth,
7526
7735
  icon,
7736
+ iconColor,
7527
7737
  labelTooltip,
7528
7738
  labelTooltipProps,
7529
7739
  addonLabel,
@@ -7785,6 +7995,7 @@ function SFilePicker({
7785
7995
  label,
7786
7996
  labelWidth,
7787
7997
  icon,
7998
+ iconColor,
7788
7999
  labelTooltip,
7789
8000
  labelTooltipProps,
7790
8001
  addonLabel,
@@ -7954,7 +8165,7 @@ function SFilePicker({
7954
8165
  unmountOnHide: true,
7955
8166
  getAnchorRect: () => contentBoxRef.current?.getBoundingClientRect() ?? null,
7956
8167
  style: { minWidth: contentBoxRef.current?.offsetWidth },
7957
- className: "z-50 box-border flex flex-col items-stretch gap-[8px] rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] p-[8px] shadow-[2px_2px_12px_2px_rgba(0,0,0,0.1)]",
8168
+ className: "z-50 box-border flex flex-col items-start gap-[8px] rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] p-[8px] shadow-[2px_2px_12px_2px_rgba(0,0,0,0.1)]",
7958
8169
  children: filesArr.map((f, i) => /* @__PURE__ */ jsx(SChip, { value: f.name, editable: false, onRemove: () => removeChip(i) }, i))
7959
8170
  }
7960
8171
  )
@@ -7968,6 +8179,7 @@ function SFilePicker({
7968
8179
  label,
7969
8180
  labelWidth,
7970
8181
  icon,
8182
+ iconColor,
7971
8183
  labelTooltip,
7972
8184
  labelTooltipProps,
7973
8185
  addonLabel,
@@ -7990,21 +8202,26 @@ function SFilePicker({
7990
8202
  var cssLen2 = (v) => v == null ? void 0 : typeof v === "number" ? `${v}px` : v;
7991
8203
  function SKeyValueTable({
7992
8204
  fields = [],
8205
+ values = {},
7993
8206
  search = false,
7994
8207
  radius = "default",
7995
- dense = false,
7996
8208
  onChange,
7997
8209
  onSearch,
7998
8210
  className,
7999
8211
  style
8000
8212
  }) {
8001
8213
  if (fields.length === 0) return null;
8002
- const emit2 = (name, value) => onChange?.({ name, value });
8003
- const cellHeight = dense ? "var(--cmp-table-body-dense-height)" : "var(--cmp-table-keyValue-height)";
8004
- const cellPadY = dense ? "var(--cmp-table-body-paddingY-dense)" : "var(--cmp-table-keyValue-body-paddingY)";
8214
+ const emit2 = (name, value) => onChange?.({
8215
+ name,
8216
+ value,
8217
+ values: { ...values, [name]: value }
8218
+ });
8219
+ const cellHeight = "var(--cmp-table-keyValue-height)";
8220
+ const cellPadY = "var(--cmp-table-keyValue-body-paddingY)";
8005
8221
  const renderField = (f) => {
8006
8222
  if (f.render) return f.render;
8007
- const opt = f.options ?? {};
8223
+ const opt = { ...f.options ?? {} };
8224
+ if (Object.prototype.hasOwnProperty.call(values, f.name)) opt.value = values[f.name];
8008
8225
  const up = (v) => emit2(f.name, v);
8009
8226
  switch (f.type) {
8010
8227
  case "input":
@@ -8116,7 +8333,10 @@ function SKeyValueTable({
8116
8333
  rowSpan: f.tdRowSpan && f.tdRowSpan > 1 ? f.tdRowSpan : void 0,
8117
8334
  colSpan: f.tdColSpan && f.tdColSpan > 1 ? f.tdColSpan : void 0,
8118
8335
  className: cn(
8119
- "box-border bg-[var(--sys-color-bg-frame)] px-[var(--cmp-table-keyValue-body-paddingX-default)] align-middle",
8336
+ "box-border bg-[var(--sys-color-bg-frame)] align-middle",
8337
+ // text 타입(및 미지정 기본값)은 읽기 전용 콘텐츠라 넓은 paddingX(wide),
8338
+ // 폼 필드 셀은 default paddingX 유지
8339
+ f.type == null || f.type === "text" ? "px-[var(--cmp-table-keyValue-body-paddingX-wide)]" : "px-[var(--cmp-table-keyValue-body-paddingX-default)]",
8120
8340
  cellBorder,
8121
8341
  f.tdClass
8122
8342
  ),
@@ -8609,6 +8829,7 @@ var SChipInput = forwardRef(function SChipInput2({
8609
8829
  error,
8610
8830
  useReset = false,
8611
8831
  maxCount,
8832
+ metaPlacement = "end",
8612
8833
  duplicateLabel,
8613
8834
  suggestions = [],
8614
8835
  loadingSuggestions = false,
@@ -8622,6 +8843,7 @@ var SChipInput = forwardRef(function SChipInput2({
8622
8843
  width,
8623
8844
  status,
8624
8845
  icon,
8846
+ iconColor,
8625
8847
  labelTooltip,
8626
8848
  labelTooltipProps,
8627
8849
  className,
@@ -8756,6 +8978,7 @@ var SChipInput = forwardRef(function SChipInput2({
8756
8978
  labelWidth,
8757
8979
  labelHeight: `calc(var(--cmp-chipInput-${size}-minHeight) + 2px)`,
8758
8980
  icon,
8981
+ iconColor,
8759
8982
  labelTooltip,
8760
8983
  labelTooltipProps,
8761
8984
  size,
@@ -8903,7 +9126,11 @@ var SChipInput = forwardRef(function SChipInput2({
8903
9126
  showMetaInfo && /* @__PURE__ */ jsxs(
8904
9127
  "div",
8905
9128
  {
8906
- className: "s-chip-input__meta ml-auto flex items-center gap-8",
9129
+ className: cn(
9130
+ "s-chip-input__meta flex items-center gap-8",
9131
+ metaPlacement === "end" && "ml-auto"
9132
+ ),
9133
+ "data-placement": metaPlacement,
8907
9134
  onMouseDown: (e) => e.preventDefault(),
8908
9135
  children: [
8909
9136
  /* @__PURE__ */ jsx(
@@ -9043,6 +9270,7 @@ var SBarcodeInput = forwardRef(
9043
9270
  label,
9044
9271
  labelWidth,
9045
9272
  icon,
9273
+ iconColor,
9046
9274
  labelTooltip,
9047
9275
  labelTooltipProps,
9048
9276
  addonLabel,
@@ -9074,6 +9302,7 @@ var SBarcodeInput = forwardRef(
9074
9302
  label,
9075
9303
  labelWidth,
9076
9304
  icon,
9305
+ iconColor,
9077
9306
  labelTooltip,
9078
9307
  labelTooltipProps,
9079
9308
  addonLabel,
@@ -9152,6 +9381,6 @@ var SBarcodeInput = forwardRef(
9152
9381
  }
9153
9382
  );
9154
9383
 
9155
- export { BADGE_COLORS, BUTTON_COLORS, BUTTON_SIZES, COLOR_KEYS, ICONS, SActionModal, SBadge, SBarcodeInput, SButton, SCalendar, SCallout, SCard, SCheckbox, SChip, SChipInput, SCircleProgress, SConfirmModal, SDatePicker, SDateRangePicker, SDivider, SDropdownButton, SField, SFilePicker, SForm, SGhostButton, SGuide, SIcon, SInput, SKeyValueTable, SLinearProgress, SLoadingContainer, SLoadingModal, SLoadingViewport, SModalContainer, SNumberInput, SPagination, SPopover, SPopup, SPortal, SRadio, SRadioButton, SRadioGroup, SSelect, SSwitch, STable, STabs, STag, STextLink, STextarea, SToast, SToastContainer, SToggle, STooltip, TAG_COLORS, TAG_SHAPES, TAG_SIZES, buttonPreset, cn, isColorKey, loading, resolveColor };
9384
+ export { BADGE_COLORS, BUTTON_COLORS, BUTTON_SIZES, COLOR_KEYS, ICONS, SActionModal, SBadge, SBarcodeInput, SButton, SCalendar, SCallout, SCard, SCheckbox, SChip, SChipInput, SCircleProgress, SConfirmModal, SDatePicker, SDateRangePicker, SDivider, SDropdownButton, SField, SFilePicker, SForm, SGhostButton, SGuide, SIcon, SInput, SKeyValueTable, SLinearProgress, SLoadingContainer, SLoadingModal, SLoadingViewport, SNumberInput, SPagination, SPopover, SPopup, SPortal, SRadio, SRadioButton, SRadioGroup, SSelect, SSwitch, STable, STabs, STag, STextLink, STextarea, SToast, SToastContainer, SToggle, STooltip, TAG_COLORS, TAG_SHAPES, TAG_SIZES, buttonPreset, cn, isColorKey, loading, resolveColor };
9156
9385
  //# sourceMappingURL=index.js.map
9157
9386
  //# sourceMappingURL=index.js.map