sellmate-design-system-react 0.1.9 → 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 (148) 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 +16 -3
  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 +16 -3
  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 +22 -4
  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 +22 -4
  22. package/dist/components/SChipInput/SChipInput.js.map +1 -1
  23. package/dist/components/SChipInput/index.d.ts +1 -1
  24. package/dist/components/SCircleProgress/SCircleProgress.cjs +69 -50
  25. package/dist/components/SCircleProgress/SCircleProgress.cjs.map +1 -1
  26. package/dist/components/SCircleProgress/SCircleProgress.d.ts +2 -0
  27. package/dist/components/SCircleProgress/SCircleProgress.js +69 -50
  28. package/dist/components/SCircleProgress/SCircleProgress.js.map +1 -1
  29. package/dist/components/SConfirmModal/SConfirmModal.cjs +13 -10
  30. package/dist/components/SConfirmModal/SConfirmModal.cjs.map +1 -1
  31. package/dist/components/SConfirmModal/SConfirmModal.d.ts +7 -4
  32. package/dist/components/SConfirmModal/SConfirmModal.js +13 -10
  33. package/dist/components/SConfirmModal/SConfirmModal.js.map +1 -1
  34. package/dist/components/SDatePicker/SDatePicker.cjs +16 -3
  35. package/dist/components/SDatePicker/SDatePicker.cjs.map +1 -1
  36. package/dist/components/SDatePicker/SDatePicker.d.ts +3 -1
  37. package/dist/components/SDatePicker/SDatePicker.js +16 -3
  38. package/dist/components/SDatePicker/SDatePicker.js.map +1 -1
  39. package/dist/components/SDateRangePicker/SDateRangePicker.cjs +16 -3
  40. package/dist/components/SDateRangePicker/SDateRangePicker.cjs.map +1 -1
  41. package/dist/components/SDateRangePicker/SDateRangePicker.d.ts +3 -1
  42. package/dist/components/SDateRangePicker/SDateRangePicker.js +16 -3
  43. package/dist/components/SDateRangePicker/SDateRangePicker.js.map +1 -1
  44. package/dist/components/SDropdownButton/SDropdownButton.cjs +2 -0
  45. package/dist/components/SDropdownButton/SDropdownButton.cjs.map +1 -1
  46. package/dist/components/SDropdownButton/SDropdownButton.js +2 -0
  47. package/dist/components/SDropdownButton/SDropdownButton.js.map +1 -1
  48. package/dist/components/SField/SField.cjs +14 -3
  49. package/dist/components/SField/SField.cjs.map +1 -1
  50. package/dist/components/SField/SField.d.ts +4 -1
  51. package/dist/components/SField/SField.js +14 -3
  52. package/dist/components/SField/SField.js.map +1 -1
  53. package/dist/components/SFilePicker/SFilePicker.cjs +51 -19
  54. package/dist/components/SFilePicker/SFilePicker.cjs.map +1 -1
  55. package/dist/components/SFilePicker/SFilePicker.d.ts +4 -2
  56. package/dist/components/SFilePicker/SFilePicker.js +50 -19
  57. package/dist/components/SFilePicker/SFilePicker.js.map +1 -1
  58. package/dist/components/SGhostButton/SGhostButton.cjs +2 -0
  59. package/dist/components/SGhostButton/SGhostButton.cjs.map +1 -1
  60. package/dist/components/SGhostButton/SGhostButton.js +2 -0
  61. package/dist/components/SGhostButton/SGhostButton.js.map +1 -1
  62. package/dist/components/SGuide/SGuide.cjs +2 -0
  63. package/dist/components/SGuide/SGuide.cjs.map +1 -1
  64. package/dist/components/SGuide/SGuide.js +2 -0
  65. package/dist/components/SGuide/SGuide.js.map +1 -1
  66. package/dist/components/SInput/SInput.cjs +16 -3
  67. package/dist/components/SInput/SInput.cjs.map +1 -1
  68. package/dist/components/SInput/SInput.d.ts +4 -1
  69. package/dist/components/SInput/SInput.js +16 -3
  70. package/dist/components/SInput/SInput.js.map +1 -1
  71. package/dist/components/SKeyValueTable/SKeyValueTable.cjs +530 -219
  72. package/dist/components/SKeyValueTable/SKeyValueTable.cjs.map +1 -1
  73. package/dist/components/SKeyValueTable/SKeyValueTable.d.ts +27 -6
  74. package/dist/components/SKeyValueTable/SKeyValueTable.js +529 -218
  75. package/dist/components/SKeyValueTable/SKeyValueTable.js.map +1 -1
  76. package/dist/components/SLoadingContainer/SLoadingContainer.cjs +69 -50
  77. package/dist/components/SLoadingContainer/SLoadingContainer.cjs.map +1 -1
  78. package/dist/components/SLoadingContainer/SLoadingContainer.js +69 -50
  79. package/dist/components/SLoadingContainer/SLoadingContainer.js.map +1 -1
  80. package/dist/components/SLoadingContainer/loading.cjs +69 -50
  81. package/dist/components/SLoadingContainer/loading.cjs.map +1 -1
  82. package/dist/components/SLoadingContainer/loading.js +69 -50
  83. package/dist/components/SLoadingContainer/loading.js.map +1 -1
  84. package/dist/components/SLoadingModal/SLoadingModal.cjs +75 -51
  85. package/dist/components/SLoadingModal/SLoadingModal.cjs.map +1 -1
  86. package/dist/components/SLoadingModal/SLoadingModal.d.ts +3 -1
  87. package/dist/components/SLoadingModal/SLoadingModal.js +75 -51
  88. package/dist/components/SLoadingModal/SLoadingModal.js.map +1 -1
  89. package/dist/components/SModalContainer/SModalContainer.cjs +3 -1
  90. package/dist/components/SModalContainer/SModalContainer.cjs.map +1 -1
  91. package/dist/components/SModalContainer/SModalContainer.js +3 -1
  92. package/dist/components/SModalContainer/SModalContainer.js.map +1 -1
  93. package/dist/components/SNumberInput/SNumberInput.cjs +16 -3
  94. package/dist/components/SNumberInput/SNumberInput.cjs.map +1 -1
  95. package/dist/components/SNumberInput/SNumberInput.d.ts +2 -0
  96. package/dist/components/SNumberInput/SNumberInput.js +16 -3
  97. package/dist/components/SNumberInput/SNumberInput.js.map +1 -1
  98. package/dist/components/SPopover/SPopover.cjs +2 -0
  99. package/dist/components/SPopover/SPopover.cjs.map +1 -1
  100. package/dist/components/SPopover/SPopover.js +2 -0
  101. package/dist/components/SPopover/SPopover.js.map +1 -1
  102. package/dist/components/SPortal/SPortal.cjs +2 -0
  103. package/dist/components/SPortal/SPortal.cjs.map +1 -1
  104. package/dist/components/SPortal/SPortal.js +2 -0
  105. package/dist/components/SPortal/SPortal.js.map +1 -1
  106. package/dist/components/SRadio/SRadioGroup.cjs +1 -1
  107. package/dist/components/SRadio/SRadioGroup.cjs.map +1 -1
  108. package/dist/components/SRadio/SRadioGroup.js +1 -1
  109. package/dist/components/SRadio/SRadioGroup.js.map +1 -1
  110. package/dist/components/SSelect/SSelect.cjs +530 -258
  111. package/dist/components/SSelect/SSelect.cjs.map +1 -1
  112. package/dist/components/SSelect/SSelect.d.ts +4 -2
  113. package/dist/components/SSelect/SSelect.js +531 -258
  114. package/dist/components/SSelect/SSelect.js.map +1 -1
  115. package/dist/components/STable/STable.cjs +603 -309
  116. package/dist/components/STable/STable.cjs.map +1 -1
  117. package/dist/components/STable/STable.js +604 -309
  118. package/dist/components/STable/STable.js.map +1 -1
  119. package/dist/components/STextLink/STextLink.cjs +2 -0
  120. package/dist/components/STextLink/STextLink.cjs.map +1 -1
  121. package/dist/components/STextLink/STextLink.js +2 -0
  122. package/dist/components/STextLink/STextLink.js.map +1 -1
  123. package/dist/components/STextarea/STextarea.cjs +16 -3
  124. package/dist/components/STextarea/STextarea.cjs.map +1 -1
  125. package/dist/components/STextarea/STextarea.d.ts +2 -0
  126. package/dist/components/STextarea/STextarea.js +16 -3
  127. package/dist/components/STextarea/STextarea.js.map +1 -1
  128. package/dist/components/SToast/SToast.cjs +2 -0
  129. package/dist/components/SToast/SToast.cjs.map +1 -1
  130. package/dist/components/SToast/SToast.js +2 -0
  131. package/dist/components/SToast/SToast.js.map +1 -1
  132. package/dist/components/SToast/SToastContainer.cjs +2 -0
  133. package/dist/components/SToast/SToastContainer.cjs.map +1 -1
  134. package/dist/components/SToast/SToastContainer.js +2 -0
  135. package/dist/components/SToast/SToastContainer.js.map +1 -1
  136. package/dist/components/STooltip/STooltip.cjs +3 -1
  137. package/dist/components/STooltip/STooltip.cjs.map +1 -1
  138. package/dist/components/STooltip/STooltip.js +3 -1
  139. package/dist/components/STooltip/STooltip.js.map +1 -1
  140. package/dist/index.cjs +522 -248
  141. package/dist/index.cjs.map +1 -1
  142. package/dist/index.d.ts +0 -1
  143. package/dist/index.js +523 -248
  144. package/dist/index.js.map +1 -1
  145. package/dist/lib/portal-container.d.ts +7 -0
  146. package/dist/styles.css +123 -58
  147. package/dist/theme.css +45 -21
  148. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -3328,12 +3328,35 @@ var COLOR_MAP = {
3328
3328
  };
3329
3329
  var clamp2 = (v) => Number.isFinite(v) ? Math.max(0, Math.min(100, v)) : 0;
3330
3330
  var SCircleProgress = react.forwardRef(
3331
- function SCircleProgress2({ value = 0, type = "primary", indeterminate = false, label, className, style }, ref) {
3331
+ function SCircleProgress2({
3332
+ value = 0,
3333
+ type = "primary",
3334
+ indeterminate = false,
3335
+ label,
3336
+ innerValue = false,
3337
+ className,
3338
+ style
3339
+ }, ref) {
3332
3340
  const v = clamp2(value);
3333
3341
  const colors = COLOR_MAP[type];
3334
3342
  const c = VIEWBOX / 2;
3335
3343
  const percentColor = v === 0 ? "var(--sys-color-fg-tertiary, #888888)" : colors.arc;
3336
3344
  const filled = v / 100 * CIRCUMFERENCE;
3345
+ const showPercent = !indeterminate;
3346
+ const percentNode = /* @__PURE__ */ jsxRuntime.jsxs(
3347
+ "span",
3348
+ {
3349
+ className: cn(
3350
+ "text-center text-[16px] font-bold leading-[26px]",
3351
+ innerValue && "absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2"
3352
+ ),
3353
+ style: { color: percentColor },
3354
+ children: [
3355
+ Math.round(v),
3356
+ "%"
3357
+ ]
3358
+ }
3359
+ );
3337
3360
  return /* @__PURE__ */ jsxRuntime.jsxs(
3338
3361
  "div",
3339
3362
  {
@@ -3344,57 +3367,53 @@ var SCircleProgress = react.forwardRef(
3344
3367
  ),
3345
3368
  style,
3346
3369
  children: [
3347
- /* @__PURE__ */ jsxRuntime.jsxs(
3348
- "svg",
3349
- {
3350
- viewBox: `0 0 ${VIEWBOX} ${VIEWBOX}`,
3351
- xmlns: "http://www.w3.org/2000/svg",
3352
- className: cn("h-[80px] w-[80px]", indeterminate && "origin-center animate-circle-spin"),
3353
- children: [
3354
- /* @__PURE__ */ jsxRuntime.jsx(
3355
- "circle",
3356
- {
3357
- cx: c,
3358
- cy: c,
3359
- r: RADIUS,
3360
- fill: "none",
3361
- strokeWidth: STROKE,
3362
- style: { stroke: colors.track }
3363
- }
3370
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(innerValue && "relative"), children: [
3371
+ /* @__PURE__ */ jsxRuntime.jsxs(
3372
+ "svg",
3373
+ {
3374
+ viewBox: `0 0 ${VIEWBOX} ${VIEWBOX}`,
3375
+ xmlns: "http://www.w3.org/2000/svg",
3376
+ className: cn(
3377
+ "h-[80px] w-[80px]",
3378
+ indeterminate && "origin-center animate-circle-spin"
3364
3379
  ),
3365
- /* @__PURE__ */ jsxRuntime.jsx(
3366
- "circle",
3367
- {
3368
- cx: c,
3369
- cy: c,
3370
- r: RADIUS,
3371
- fill: "none",
3372
- strokeWidth: STROKE,
3373
- strokeLinecap: "round",
3374
- className: cn(
3375
- "origin-center",
3376
- indeterminate ? "animate-circle-arc" : "-rotate-90 transition-[stroke-dasharray] duration-[400ms] ease-linear"
3377
- ),
3378
- style: {
3379
- stroke: colors.arc,
3380
- ...indeterminate ? {} : { strokeDasharray: `${filled} ${CIRCUMFERENCE}`, strokeDashoffset: 0 }
3380
+ children: [
3381
+ /* @__PURE__ */ jsxRuntime.jsx(
3382
+ "circle",
3383
+ {
3384
+ cx: c,
3385
+ cy: c,
3386
+ r: RADIUS,
3387
+ fill: "none",
3388
+ strokeWidth: STROKE,
3389
+ style: { stroke: colors.track }
3381
3390
  }
3382
- }
3383
- )
3384
- ]
3385
- }
3386
- ),
3387
- !indeterminate && /* @__PURE__ */ jsxRuntime.jsxs(
3388
- "span",
3389
- {
3390
- className: "text-center text-[16px] font-bold leading-[26px]",
3391
- style: { color: percentColor },
3392
- children: [
3393
- Math.round(v),
3394
- "%"
3395
- ]
3396
- }
3397
- ),
3391
+ ),
3392
+ /* @__PURE__ */ jsxRuntime.jsx(
3393
+ "circle",
3394
+ {
3395
+ cx: c,
3396
+ cy: c,
3397
+ r: RADIUS,
3398
+ fill: "none",
3399
+ strokeWidth: STROKE,
3400
+ strokeLinecap: "round",
3401
+ className: cn(
3402
+ "origin-center",
3403
+ indeterminate ? "animate-circle-arc" : "-rotate-90 transition-[stroke-dasharray] duration-[400ms] ease-linear"
3404
+ ),
3405
+ style: {
3406
+ stroke: colors.arc,
3407
+ ...indeterminate ? {} : { strokeDasharray: `${filled} ${CIRCUMFERENCE}`, strokeDashoffset: 0 }
3408
+ }
3409
+ }
3410
+ )
3411
+ ]
3412
+ }
3413
+ ),
3414
+ showPercent && innerValue && percentNode
3415
+ ] }),
3416
+ showPercent && !innerValue && percentNode,
3398
3417
  label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-center text-[12px] font-normal leading-[20px] text-[color:var(--cmp-progress-color-label)]", children: label })
3399
3418
  ]
3400
3419
  }
@@ -3514,10 +3533,15 @@ var FLOATING_SLIDE_ANIM = [
3514
3533
  "data-[state=closed]:data-[side=right]:animate-floating-out-right"
3515
3534
  ].join(" ");
3516
3535
  var PortalContainerContext = react.createContext(null);
3536
+ var InsideModalContext = react.createContext(false);
3517
3537
  var PortalContainerProvider = PortalContainerContext.Provider;
3538
+ var InsideModalProvider = InsideModalContext.Provider;
3518
3539
  function usePortalContainer() {
3519
3540
  return react.useContext(PortalContainerContext) ?? void 0;
3520
3541
  }
3542
+ function useInsideModal() {
3543
+ return react.useContext(InsideModalContext);
3544
+ }
3521
3545
  var SIZE_CONFIG = {
3522
3546
  sm: {
3523
3547
  gap: 4,
@@ -4153,7 +4177,7 @@ var STooltip = react.forwardRef(function STooltip2({
4153
4177
  if (disabled || body == null) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: triggerNode });
4154
4178
  const isHover = trigger === "hover";
4155
4179
  const contentClass = cn(
4156
- "z-50 max-w-xs rounded-[6px] px-[16px] py-[12px] text-[12px] leading-[20px] shadow-[2px_2px_12px_2px_rgba(0,0,0,0.1)]",
4180
+ "z-50 max-w-xs rounded-[6px] px-[16px] py-[12px] text-[12px] leading-[20px]",
4157
4181
  FLOATING_SLIDE_ANIM,
4158
4182
  className
4159
4183
  );
@@ -4628,7 +4652,7 @@ function SModalContainer({
4628
4652
  className: "absolute right-[16px] top-[16px] z-10"
4629
4653
  }
4630
4654
  ),
4631
- /* @__PURE__ */ jsxRuntime.jsx(PortalContainerProvider, { value: portalContainer, children })
4655
+ /* @__PURE__ */ jsxRuntime.jsx(InsideModalProvider, { value: true, children: /* @__PURE__ */ jsxRuntime.jsx(PortalContainerProvider, { value: portalContainer, children }) })
4632
4656
  ]
4633
4657
  }
4634
4658
  )
@@ -4674,7 +4698,8 @@ function SConfirmModal({
4674
4698
  tagSize = "sm",
4675
4699
  tagColor = "grey",
4676
4700
  slotLabel,
4677
- children,
4701
+ tagSlot,
4702
+ optionSlot,
4678
4703
  mainButtonLabel = "\uD655\uC778",
4679
4704
  mainButtonName,
4680
4705
  subButtonLabel,
@@ -4684,6 +4709,9 @@ function SConfirmModal({
4684
4709
  }) {
4685
4710
  const iconName = TYPE_ICON[type];
4686
4711
  const mainStyle = MAIN_BUTTON_STYLE[mainButtonName ?? DEFAULT_MAIN_BUTTON[type]];
4712
+ const tagNode = tagSlot ?? (tagLabel ? /* @__PURE__ */ jsxRuntime.jsx(STag, { shape: tagShape, size: tagSize, color: tagColor, label: tagLabel }) : null);
4713
+ const optionNode = optionSlot ?? (slotLabel ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: slotLabel }) : null);
4714
+ const hasBody = topMessage.length > 0 || bottomMessage.length > 0 || tagNode != null || optionNode != null;
4687
4715
  return /* @__PURE__ */ jsxRuntime.jsx(
4688
4716
  SModalContainer,
4689
4717
  {
@@ -4709,15 +4737,12 @@ function SConfirmModal({
4709
4737
  }
4710
4738
  )
4711
4739
  ] }),
4712
- (topMessage.length > 0 || bottomMessage.length > 0 || tagLabel || slotLabel || children) && /* @__PURE__ */ jsxRuntime.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: [
4740
+ hasBody && /* @__PURE__ */ jsxRuntime.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: [
4713
4741
  topMessage.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-[2px]", children: topMessage.map((m, i) => /* @__PURE__ */ jsxRuntime.jsx("p", { className: "m-0", children: m }, i)) }),
4714
- (tagLabel || slotLabel || children) && // content-box: 흰 박스 + 1px 테두리 + 패딩 + 14/700 (원본 sd-confirm-modal__content-box)
4715
- /* @__PURE__ */ jsxRuntime.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: [
4716
- tagLabel && /* @__PURE__ */ jsxRuntime.jsx(STag, { shape: tagShape, size: tagSize, color: tagColor, label: tagLabel }),
4717
- slotLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { children: slotLabel }),
4718
- children
4719
- ] }),
4720
- bottomMessage.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-[2px]", children: bottomMessage.map((m, i) => /* @__PURE__ */ jsxRuntime.jsx("p", { className: "m-0", children: m }, i)) })
4742
+ tagNode != null && // tag 위치 content-box: 흰 박스 + 1px 테두리 + 패딩 + 14/700 (원본 sd-confirm-modal__content-box)
4743
+ /* @__PURE__ */ jsxRuntime.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 }),
4744
+ bottomMessage.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-[2px]", children: bottomMessage.map((m, i) => /* @__PURE__ */ jsxRuntime.jsx("p", { className: "m-0", children: m }, i)) }),
4745
+ optionNode != null && optionNode
4721
4746
  ] })
4722
4747
  ] }),
4723
4748
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-[8px]", children: [
@@ -4815,6 +4840,7 @@ var DEFAULT_BUTTON_LABEL = {
4815
4840
  function SLoadingModal({
4816
4841
  open,
4817
4842
  onOpenChange,
4843
+ onClose,
4818
4844
  persistent,
4819
4845
  state: state2 = "loading",
4820
4846
  progress,
@@ -4833,6 +4859,8 @@ function SLoadingModal({
4833
4859
  {
4834
4860
  open,
4835
4861
  onOpenChange,
4862
+ onClose,
4863
+ showClose: state2 === "error",
4836
4864
  persistent,
4837
4865
  ariaTitle: lines[0] || "\uB85C\uB529 \uC911",
4838
4866
  width,
@@ -5215,6 +5243,7 @@ var SField = react.forwardRef(function SField2({
5215
5243
  name,
5216
5244
  label = "",
5217
5245
  icon,
5246
+ iconColor,
5218
5247
  labelTooltip = "",
5219
5248
  labelTooltipProps,
5220
5249
  labelWidth,
@@ -5292,7 +5321,15 @@ var SField = react.forwardRef(function SField2({
5292
5321
  lineHeight: `${s.lineHeight}px`
5293
5322
  },
5294
5323
  children: [
5295
- icon && /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: icon, size: s.icon, style: { marginRight: s.labelGap } }),
5324
+ icon && /* @__PURE__ */ jsxRuntime.jsx(
5325
+ SIcon,
5326
+ {
5327
+ name: icon,
5328
+ size: s.icon,
5329
+ color: iconColor,
5330
+ style: { marginRight: s.labelGap }
5331
+ }
5332
+ ),
5296
5333
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 overflow-hidden text-ellipsis whitespace-nowrap", children: label }),
5297
5334
  (labelTooltip !== "" || labelTooltipProps) && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", style: { marginLeft: s.labelGap }, children: /* @__PURE__ */ jsxRuntime.jsx(
5298
5335
  STooltip,
@@ -5342,7 +5379,7 @@ var SField = react.forwardRef(function SField2({
5342
5379
  borderBottomLeftRadius: s.radius - 1
5343
5380
  },
5344
5381
  children: [
5345
- icon && !label && /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: icon, size: s.icon }),
5382
+ icon && !label && /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: icon, size: s.icon, color: iconColor }),
5346
5383
  effectiveAddonLabel
5347
5384
  ]
5348
5385
  }
@@ -5414,6 +5451,7 @@ var SSelect = react.forwardRef(function SSelect2({
5414
5451
  label,
5415
5452
  labelWidth,
5416
5453
  icon,
5454
+ iconColor,
5417
5455
  labelTooltip,
5418
5456
  addonLabel,
5419
5457
  addonAlign,
@@ -5425,18 +5463,15 @@ var SSelect = react.forwardRef(function SSelect2({
5425
5463
  }, ref) {
5426
5464
  const multi = type === "multi" || type === "multi_depth";
5427
5465
  const portalContainer = usePortalContainer();
5466
+ const insideModal = useInsideModal();
5428
5467
  const [search, setSearch] = react.useState("");
5429
5468
  const [ruleError, setRuleError] = react.useState("");
5430
5469
  const [open, setOpen] = react.useState(false);
5470
+ const [pendingOpen, setPendingOpen] = react.useState(false);
5471
+ const [focusedIndex, setFocusedIndex] = react.useState(-1);
5431
5472
  const triggerRef = react.useRef(null);
5432
- react.useImperativeHandle(
5433
- ref,
5434
- () => ({
5435
- focus: () => triggerRef.current?.focus(),
5436
- open: () => setOpen(true)
5437
- }),
5438
- []
5439
- );
5473
+ const searchInputRef = react.useRef(null);
5474
+ const listRef = react.useRef(null);
5440
5475
  const flat = react.useMemo(() => flattenOptions(options), [options]);
5441
5476
  const selectable = react.useMemo(() => selectableOptions(flat), [flat]);
5442
5477
  const hasLeaf = react.useMemo(() => flat.some((o) => !o.isGroup), [flat]);
@@ -5454,6 +5489,46 @@ var SSelect = react.forwardRef(function SSelect2({
5454
5489
  const arr = Array.isArray(value) ? value : [value];
5455
5490
  return arr.map((v) => v != null && typeof v === "object" ? v.value : v).filter((v) => v != null && v !== "").map(String);
5456
5491
  }, [value]);
5492
+ const selectedRef = react.useRef(selected);
5493
+ selectedRef.current = selected;
5494
+ const emit2 = (next) => {
5495
+ if (!onValueChange) return;
5496
+ const mapped = next.map(
5497
+ (v) => emitValue ? rawByValue.get(v) ?? v : optionByValue.get(v) ?? { value: v, label: v }
5498
+ );
5499
+ onValueChange(multi ? mapped : mapped[0] ?? (emitValue ? "" : null));
5500
+ };
5501
+ const commitOpen = (next) => {
5502
+ setOpen(next);
5503
+ onOpenChange?.(next);
5504
+ if (!next) {
5505
+ setPendingOpen(false);
5506
+ setSearch("");
5507
+ if (rules && rules.length > 0) {
5508
+ setRuleError(runRules(multi ? selectedRef.current : selectedRef.current[0] ?? "", rules));
5509
+ }
5510
+ }
5511
+ };
5512
+ const requestOpen = (next) => {
5513
+ if (next && insideModal && portalContainer == null) {
5514
+ setPendingOpen(true);
5515
+ return;
5516
+ }
5517
+ commitOpen(next);
5518
+ };
5519
+ react.useEffect(() => {
5520
+ if (!insideModal || portalContainer == null || !pendingOpen) return;
5521
+ setPendingOpen(false);
5522
+ commitOpen(true);
5523
+ }, [insideModal, pendingOpen, portalContainer]);
5524
+ react.useImperativeHandle(
5525
+ ref,
5526
+ () => ({
5527
+ focus: () => triggerRef.current?.focus(),
5528
+ open: () => requestOpen(true)
5529
+ }),
5530
+ [insideModal, portalContainer]
5531
+ );
5457
5532
  useFormField({
5458
5533
  name,
5459
5534
  validate: () => {
@@ -5463,13 +5538,6 @@ var SSelect = react.forwardRef(function SSelect2({
5463
5538
  },
5464
5539
  resetValidation: () => setRuleError("")
5465
5540
  });
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
5541
  const filtered = react.useMemo(() => {
5474
5542
  if (!showSearch || search.trim() === "") return flat;
5475
5543
  const q = search.trim().toLowerCase();
@@ -5480,6 +5548,16 @@ var SSelect = react.forwardRef(function SSelect2({
5480
5548
  const allValues = selectable.map((o) => o.value);
5481
5549
  const allSelected = allValues.length > 0 && allValues.every((v) => selected.includes(v));
5482
5550
  const hasItems = filtered.some((o) => !o.isGroup);
5551
+ const navigableItems = react.useMemo(() => {
5552
+ const items = [];
5553
+ if (multi && useSelectAll && allValues.length > 0) {
5554
+ items.push({ value: "__select_all__", isSelectAll: true });
5555
+ }
5556
+ filtered.forEach((o) => {
5557
+ if (!o.isGroup && !o.disabled) items.push({ value: o.value });
5558
+ });
5559
+ return items;
5560
+ }, [allValues.length, filtered, multi, useSelectAll]);
5483
5561
  const triggerText = (() => {
5484
5562
  if (selected.length === 0) return placeholder;
5485
5563
  if (multi) {
@@ -5489,26 +5567,119 @@ var SSelect = react.forwardRef(function SSelect2({
5489
5567
  return labelByValue.get(selected[0]) ?? selected[0];
5490
5568
  })();
5491
5569
  const isPlaceholder = selected.length === 0;
5492
- const selectStore = /* @__PURE__ */ jsxRuntime.jsxs(
5493
- Ariakit__namespace.SelectProvider,
5570
+ const handleSelect = (nextValue) => {
5571
+ if (multi) {
5572
+ const next = selected.includes(nextValue) ? selected.filter((v) => v !== nextValue) : [...selected, nextValue];
5573
+ emit2(next);
5574
+ return;
5575
+ }
5576
+ emit2([nextValue]);
5577
+ commitOpen(false);
5578
+ };
5579
+ const handleSelectAll = () => {
5580
+ emit2(allSelected ? [] : allValues);
5581
+ };
5582
+ react.useEffect(() => {
5583
+ if (!open) {
5584
+ setFocusedIndex(-1);
5585
+ return;
5586
+ }
5587
+ setFocusedIndex(navigableItems.length > 0 ? 0 : -1);
5588
+ }, [open, navigableItems.length]);
5589
+ react.useEffect(() => {
5590
+ if (!open) return;
5591
+ setFocusedIndex(navigableItems.length > 0 ? 0 : -1);
5592
+ }, [search, open, navigableItems.length]);
5593
+ react.useEffect(() => {
5594
+ if (!open || focusedIndex < 0) return;
5595
+ const list = listRef.current;
5596
+ const focusedEl = list?.querySelector('[data-select-focused="true"]');
5597
+ if (!list || !focusedEl) return;
5598
+ const listRect = list.getBoundingClientRect();
5599
+ const itemRect = focusedEl.getBoundingClientRect();
5600
+ if (itemRect.top < listRect.top) {
5601
+ list.scrollTop += itemRect.top - listRect.top;
5602
+ } else if (itemRect.bottom > listRect.bottom) {
5603
+ list.scrollTop += itemRect.bottom - listRect.bottom;
5604
+ }
5605
+ }, [focusedIndex, open]);
5606
+ const moveFocusedIndex = (direction) => {
5607
+ if (!open || navigableItems.length === 0) return;
5608
+ setFocusedIndex((current) => {
5609
+ if (direction === "next") {
5610
+ return current < 0 ? 0 : (current + 1) % navigableItems.length;
5611
+ }
5612
+ return current <= 0 ? navigableItems.length - 1 : current - 1;
5613
+ });
5614
+ };
5615
+ const selectFocusedItem = () => {
5616
+ if (focusedIndex < 0 || focusedIndex >= navigableItems.length) return;
5617
+ const focused = navigableItems[focusedIndex];
5618
+ if (focused.isSelectAll) {
5619
+ handleSelectAll();
5620
+ return;
5621
+ }
5622
+ handleSelect(focused.value);
5623
+ };
5624
+ const handleKeyDown = (event) => {
5625
+ if (!open) {
5626
+ if ((event.key === "ArrowDown" || event.key === "ArrowUp") && !effectiveDisabled) {
5627
+ event.preventDefault();
5628
+ requestOpen(true);
5629
+ }
5630
+ return;
5631
+ }
5632
+ if (event.key === "ArrowDown") {
5633
+ event.preventDefault();
5634
+ moveFocusedIndex("next");
5635
+ return;
5636
+ }
5637
+ if (event.key === "ArrowUp") {
5638
+ event.preventDefault();
5639
+ moveFocusedIndex("prev");
5640
+ return;
5641
+ }
5642
+ if (event.key === "Enter") {
5643
+ event.preventDefault();
5644
+ selectFocusedItem();
5645
+ return;
5646
+ }
5647
+ if (event.key === "Escape") {
5648
+ event.preventDefault();
5649
+ commitOpen(false);
5650
+ }
5651
+ };
5652
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5653
+ SField,
5494
5654
  {
5495
- animated: portalContainer == null ? 150 : false,
5496
- value: multi ? selected : selected[0] ?? "",
5497
- setValue: (v) => emit2(Array.isArray(v) ? v : v === "" ? [] : [v]),
5498
- open,
5499
- setOpen: (o) => {
5500
- setOpen(o);
5501
- onOpenChange?.(o);
5502
- if (!o && rules && rules.length > 0) {
5503
- setRuleError(runRules(multi ? selected : selected[0] ?? "", rules));
5504
- }
5505
- },
5655
+ label,
5656
+ labelWidth,
5657
+ icon,
5658
+ iconColor,
5659
+ labelTooltip,
5660
+ labelTooltipProps,
5661
+ addonLabel,
5662
+ addonAlign,
5663
+ hint,
5664
+ error: error || ruleError !== "",
5665
+ status: rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0,
5666
+ errorMessage: ruleError !== "" ? ruleError : errorMessage,
5667
+ disabled: effectiveDisabled,
5668
+ width,
5669
+ className,
5670
+ style,
5506
5671
  children: [
5672
+ name && /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name, value: selected.join(",") }),
5507
5673
  /* @__PURE__ */ jsxRuntime.jsxs(
5508
- Ariakit__namespace.Select,
5674
+ "button",
5509
5675
  {
5510
5676
  ref: triggerRef,
5677
+ type: "button",
5511
5678
  disabled: effectiveDisabled,
5679
+ "aria-haspopup": "listbox",
5680
+ "aria-expanded": open,
5681
+ onClick: () => requestOpen(!open),
5682
+ onKeyDown: handleKeyDown,
5512
5683
  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",
5513
5684
  style: {
5514
5685
  color: effectiveDisabled ? "var(--cmp-select-text-disabled)" : isPlaceholder ? "var(--cmp-select-icon-default)" : "var(--cmp-select-text-default)"
@@ -5533,174 +5704,229 @@ var SSelect = react.forwardRef(function SSelect2({
5533
5704
  ]
5534
5705
  }
5535
5706
  ),
5536
- /* @__PURE__ */ jsxRuntime.jsxs(
5537
- Ariakit__namespace.SelectPopover,
5707
+ /* @__PURE__ */ jsxRuntime.jsx(
5708
+ SPortal,
5538
5709
  {
5539
- portal: true,
5540
- portalElement: portalContainer,
5541
- gutter: 4,
5542
- sameWidth: !dropdownWidth,
5543
- 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",
5710
+ open,
5711
+ onClose: () => commitOpen(false),
5712
+ onOpenChange: (next) => {
5713
+ if (next) requestOpen(true);
5714
+ },
5715
+ anchorRef: triggerRef,
5716
+ placement: "bottom",
5717
+ align: "start",
5718
+ offset: 4,
5719
+ fit: !dropdownWidth,
5720
+ onOpenAutoFocus: (event) => {
5721
+ if (!showSearch) {
5722
+ event.preventDefault();
5723
+ return;
5724
+ }
5725
+ event.preventDefault();
5726
+ requestAnimationFrame(() => searchInputRef.current?.focus());
5727
+ },
5728
+ onCloseAutoFocus: (event) => {
5729
+ event.preventDefault();
5730
+ triggerRef.current?.focus();
5731
+ },
5732
+ className: "rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] py-[4px] shadow-[2px_2px_12px_2px_rgba(0,0,0,0.1)]",
5544
5733
  style: {
5545
- maxHeight: dropdownHeight,
5546
5734
  ...dropdownWidth ? { width: dropdownWidth } : {},
5547
5735
  maxWidth: maxDropdownWidth
5548
5736
  },
5549
- children: [
5550
- showSearch && // 원본 sd-select-list-item-search: sticky + 검색 아이콘 + 테두리 input + focus-within + clear
5551
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-0 z-[1] bg-[var(--cmp-listBox-bg)] px-[8px] py-[4px]", children: /* @__PURE__ */ jsxRuntime.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: [
5552
- /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "search", size: 16, color: "var(--color-grey-70)", className: "shrink-0" }),
5553
- /* @__PURE__ */ jsxRuntime.jsx(
5554
- Ariakit__namespace.Combobox,
5555
- {
5556
- autoSelect: true,
5557
- placeholder: "\uAC80\uC0C9",
5558
- 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)]"
5559
- }
5560
- ),
5561
- search !== "" && /* @__PURE__ */ jsxRuntime.jsx(
5562
- SGhostButton,
5563
- {
5564
- icon: "close",
5565
- size: "xxs",
5566
- intent: "default",
5567
- ariaLabel: "\uAC80\uC0C9\uC5B4 \uC9C0\uC6B0\uAE30",
5568
- onClick: () => setSearch(""),
5569
- className: "shrink-0"
5570
- }
5571
- )
5572
- ] }) }),
5573
- multi && useSelectAll && /* @__PURE__ */ jsxRuntime.jsx(
5574
- "button",
5575
- {
5576
- type: "button",
5577
- 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)]",
5578
- onClick: () => emit2(allSelected ? [] : allValues),
5579
- children: allSelectedLabel
5580
- }
5581
- ),
5582
- hasItems ? /* @__PURE__ */ jsxRuntime.jsx(ItemList, { items: filtered, multi, selected, useSearch: showSearch }) : (
5583
- // 원본 sd-select-listbox__empty (표시할 항목이 없을 때)
5584
- /* @__PURE__ */ jsxRuntime.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." })
5585
- )
5586
- ]
5737
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
5738
+ "div",
5739
+ {
5740
+ ref: listRef,
5741
+ 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)]",
5742
+ style: { maxHeight: dropdownHeight },
5743
+ onMouseLeave: () => setFocusedIndex(-1),
5744
+ children: [
5745
+ showSearch && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-0 z-[1] bg-[var(--cmp-listBox-bg)] px-[8px] py-[4px]", children: /* @__PURE__ */ jsxRuntime.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: [
5746
+ /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "search", size: 16, color: "var(--color-grey-70)", className: "shrink-0" }),
5747
+ /* @__PURE__ */ jsxRuntime.jsx(
5748
+ "input",
5749
+ {
5750
+ ref: searchInputRef,
5751
+ value: search,
5752
+ onChange: (e) => setSearch(e.target.value),
5753
+ onKeyDown: handleKeyDown,
5754
+ placeholder: "\uAC80\uC0C9",
5755
+ 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)]"
5756
+ }
5757
+ ),
5758
+ search !== "" && /* @__PURE__ */ jsxRuntime.jsx(
5759
+ SGhostButton,
5760
+ {
5761
+ icon: "close",
5762
+ size: "xxs",
5763
+ intent: "default",
5764
+ ariaLabel: "\uAC80\uC0C9\uC5B4 \uC9C0\uC6B0\uAE30",
5765
+ onClick: () => setSearch(""),
5766
+ className: "shrink-0"
5767
+ }
5768
+ )
5769
+ ] }) }),
5770
+ hasItems ? /* @__PURE__ */ jsxRuntime.jsx(
5771
+ ItemList,
5772
+ {
5773
+ items: filtered,
5774
+ multi,
5775
+ selected,
5776
+ focusedValue: navigableItems[focusedIndex]?.isSelectAll ? "__select_all__" : navigableItems[focusedIndex]?.value,
5777
+ showSelectAll: multi && useSelectAll && allValues.length > 0,
5778
+ selectAllLabel: allSelectedLabel,
5779
+ selectAllSelected: allSelected,
5780
+ onSelectAll: handleSelectAll,
5781
+ onSelect: handleSelect,
5782
+ onHoverValue: (value2) => {
5783
+ const index = navigableItems.findIndex(
5784
+ (item) => item.isSelectAll ? value2 === "__select_all__" : item.value === value2
5785
+ );
5786
+ if (index >= 0) setFocusedIndex(index);
5787
+ }
5788
+ }
5789
+ ) : /* @__PURE__ */ jsxRuntime.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." })
5790
+ ]
5791
+ }
5792
+ )
5587
5793
  }
5588
5794
  )
5589
5795
  ]
5590
5796
  }
5591
5797
  );
5592
- const control = showSearch ? /* @__PURE__ */ jsxRuntime.jsx(Ariakit__namespace.ComboboxProvider, { value: search, setValue: setSearch, resetValueOnHide: true, children: selectStore }) : selectStore;
5593
- return /* @__PURE__ */ jsxRuntime.jsxs(
5594
- SField,
5595
- {
5596
- label,
5597
- labelWidth,
5598
- icon,
5599
- labelTooltip,
5600
- labelTooltipProps,
5601
- addonLabel,
5602
- addonAlign,
5603
- hint,
5604
- error: error || ruleError !== "",
5605
- status: rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0,
5606
- errorMessage: ruleError !== "" ? ruleError : errorMessage,
5607
- disabled: effectiveDisabled,
5608
- width,
5609
- className,
5610
- style,
5611
- children: [
5612
- name && /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name, value: selected.join(",") }),
5613
- control
5614
- ]
5615
- }
5616
- );
5617
5798
  });
5618
5799
  SSelect.displayName = "SSelect";
5619
5800
  function ItemList({
5620
5801
  items,
5621
5802
  multi,
5622
5803
  selected,
5623
- useSearch
5804
+ focusedValue,
5805
+ showSelectAll,
5806
+ selectAllLabel,
5807
+ selectAllSelected,
5808
+ onSelectAll,
5809
+ onSelect,
5810
+ onHoverValue
5624
5811
  }) {
5625
5812
  const itemBase = cn(
5626
- // group: 체크박스 inverse(group-data-[active-item])를 위해 필요
5627
- "group flex cursor-pointer select-none items-center gap-[8px] text-[12px] leading-[20px] outline-none",
5813
+ "group flex w-full cursor-pointer select-none items-center gap-[8px] border-none bg-transparent text-left text-[12px] leading-[20px] outline-none",
5628
5814
  "text-[color:var(--cmp-listItem-content-default)]",
5629
- // Ariakit은 disabled 항목에 aria-disabled를 붙이므로 aria-disabled 변형으로 스타일 (data-disabled 아님)
5630
- "aria-disabled:cursor-not-allowed aria-disabled:text-[color:var(--cmp-listItem-content-disabled)]"
5631
- );
5632
- const activeClass = "data-[active-item]:bg-[var(--cmp-listItem-bg-hover)] data-[active-item]:text-[color:var(--cmp-listItem-content-hover)]";
5633
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: items.map((o) => {
5634
- const padLeft = o.depth === 1 ? 12 : o.depth === 2 ? 20 : 28;
5635
- if (o.isGroup) {
5636
- const isDepth1 = o.depth === 1;
5637
- return /* @__PURE__ */ jsxRuntime.jsx(
5638
- "div",
5639
- {
5640
- className: cn(
5641
- "select-none py-[4px] pr-[12px] text-[12px] leading-[20px] text-[color:var(--cmp-listItem-content-default)]",
5642
- 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",
5643
- // 하위가 전부 비활성이면(select.config 에서 bubble-up) 어미 그룹도 비활성 처리:
5644
- // 텍스트는 회색(#888), depth1 그룹은 파란 배경 대신 회색(#EEE)으로 (depth2 는 #F6F6F6 유지)
5645
- o.disabled && "text-[color:var(--cmp-listItem-content-disabled)]",
5646
- o.disabled && isDepth1 && "bg-[var(--cmp-listItem-depth1-bg-disabled)]"
5647
- ),
5648
- style: { paddingLeft: padLeft },
5649
- children: o.label
5650
- },
5651
- o.value
5652
- );
5653
- }
5654
- const isSelected = selected.includes(o.value);
5655
- return /* @__PURE__ */ jsxRuntime.jsxs(
5656
- Ariakit__namespace.SelectItem,
5815
+ "disabled:cursor-not-allowed disabled:text-[color:var(--cmp-listItem-content-disabled)]"
5816
+ );
5817
+ 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)]";
5818
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "listbox", "aria-multiselectable": multi || void 0, children: [
5819
+ showSelectAll && /* @__PURE__ */ jsxRuntime.jsxs(
5820
+ "button",
5657
5821
  {
5658
- value: o.value,
5659
- disabled: o.disabled,
5822
+ type: "button",
5823
+ "data-select-focused": focusedValue === "__select_all__" ? "true" : void 0,
5824
+ "data-select-active": focusedValue === "__select_all__" ? "true" : void 0,
5660
5825
  className: cn(
5661
5826
  itemBase,
5662
- isSelected && !multi && "font-bold text-[color:var(--cmp-listItem-content-selected)]",
5663
- activeClass
5827
+ focusedValue === "__select_all__" && "bg-[var(--cmp-listItem-bg-hover)] text-[color:var(--cmp-listItem-content-hover)]"
5664
5828
  ),
5665
- style: { paddingTop: 4, paddingBottom: 4, paddingRight: 12, paddingLeft: padLeft },
5666
- render: useSearch ? /* @__PURE__ */ jsxRuntime.jsx(Ariakit__namespace.ComboboxItem, {}) : void 0,
5829
+ style: { paddingTop: 4, paddingBottom: 4, paddingRight: 12, paddingLeft: 12 },
5830
+ onMouseEnter: () => onHoverValue("__select_all__"),
5831
+ onClick: onSelectAll,
5667
5832
  children: [
5668
- multi && // hover(active) 시 checkbox inverse — 파란 hover 배경 위에서 checked/unchecked 모두 흰 테두리 + 투명 배경
5669
5833
  /* @__PURE__ */ jsxRuntime.jsx(
5670
5834
  "span",
5671
5835
  {
5672
5836
  className: cn(
5673
5837
  "flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center rounded-[2px] border border-solid",
5674
- o.disabled ? (
5675
- // 비활성: 회색 채움(#E1E1E1) + 회색 테두리(#CCCCCC)
5676
- "border-[color:var(--cmp-checkbox-border-disabled)] bg-[var(--cmp-checkbox-bg-disabled)]"
5677
- ) : cn(
5678
- "group-data-[active-item]:border-[color:var(--cmp-checkbox-checked-border-inverse)]",
5679
- 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"
5680
- )
5838
+ 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)]"
5681
5839
  ),
5682
- children: isSelected && /* @__PURE__ */ jsxRuntime.jsx(
5840
+ children: selectAllSelected && /* @__PURE__ */ jsxRuntime.jsx(
5683
5841
  SIcon,
5684
5842
  {
5685
5843
  name: "checkboxCheck",
5686
5844
  size: 12,
5687
- color: o.disabled ? "var(--cmp-checkbox-checked-icon-disabled)" : "var(--cmp-checkbox-checked-icon-default)"
5845
+ color: "var(--cmp-checkbox-checked-icon-default)"
5688
5846
  }
5689
5847
  )
5690
5848
  }
5691
5849
  ),
5692
- isHtmlLabel(o.label) ? /* @__PURE__ */ jsxRuntime.jsx(
5693
- "span",
5694
- {
5695
- className: "flex-1 truncate",
5696
- dangerouslySetInnerHTML: { __html: sanitizeInlineHtml(o.label) }
5697
- }
5698
- ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate", children: o.label })
5850
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate", children: selectAllLabel })
5699
5851
  ]
5700
- },
5701
- o.value
5702
- );
5703
- }) });
5852
+ }
5853
+ ),
5854
+ items.map((o) => {
5855
+ const padLeft = o.depth === 1 ? 12 : o.depth === 2 ? 20 : 28;
5856
+ if (o.isGroup) {
5857
+ const isDepth1 = o.depth === 1;
5858
+ return /* @__PURE__ */ jsxRuntime.jsx(
5859
+ "div",
5860
+ {
5861
+ className: cn(
5862
+ "select-none py-[4px] pr-[12px] text-[12px] leading-[20px] text-[color:var(--cmp-listItem-content-default)]",
5863
+ 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",
5864
+ // 하위가 전부 비활성이면(select.config 에서 bubble-up) 어미 그룹도 비활성 처리:
5865
+ // 텍스트는 회색(#888), depth1 그룹은 파란 배경 대신 회색(#EEE)으로 (depth2 는 #F6F6F6 유지)
5866
+ o.disabled && "cursor-not-allowed text-[color:var(--cmp-listItem-content-disabled)]",
5867
+ o.disabled && isDepth1 && "bg-[var(--cmp-listItem-depth1-bg-disabled)]"
5868
+ ),
5869
+ style: { paddingLeft: padLeft },
5870
+ children: o.label
5871
+ },
5872
+ o.value
5873
+ );
5874
+ }
5875
+ const isSelected = selected.includes(o.value);
5876
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5877
+ "button",
5878
+ {
5879
+ type: "button",
5880
+ disabled: o.disabled,
5881
+ role: "option",
5882
+ "aria-selected": isSelected,
5883
+ "data-select-focused": focusedValue === o.value ? "true" : void 0,
5884
+ "data-select-active": focusedValue === o.value ? "true" : void 0,
5885
+ className: cn(
5886
+ itemBase,
5887
+ isSelected && !multi && "font-bold text-[color:var(--cmp-listItem-content-selected)]",
5888
+ focusedValue === o.value && "bg-[var(--cmp-listItem-bg-hover)] text-[color:var(--cmp-listItem-content-hover)]",
5889
+ activeClass
5890
+ ),
5891
+ style: { paddingTop: 4, paddingBottom: 4, paddingRight: 12, paddingLeft: padLeft },
5892
+ onMouseEnter: () => onHoverValue(o.value),
5893
+ onClick: () => onSelect(o.value),
5894
+ children: [
5895
+ multi && /* @__PURE__ */ jsxRuntime.jsx(
5896
+ "span",
5897
+ {
5898
+ className: cn(
5899
+ "flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center rounded-[2px] border border-solid",
5900
+ o.disabled ? (
5901
+ // 비활성: 회색 채움(#E1E1E1) + 회색 테두리(#CCCCCC)
5902
+ "cursor-not-allowed border-[color:var(--cmp-checkbox-border-disabled)] bg-[var(--cmp-checkbox-bg-disabled)]"
5903
+ ) : cn(
5904
+ 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)]"
5905
+ )
5906
+ ),
5907
+ children: isSelected && /* @__PURE__ */ jsxRuntime.jsx(
5908
+ SIcon,
5909
+ {
5910
+ name: "checkboxCheck",
5911
+ size: 12,
5912
+ color: o.disabled ? "var(--cmp-checkbox-checked-icon-disabled)" : "var(--cmp-checkbox-checked-icon-default)"
5913
+ }
5914
+ )
5915
+ }
5916
+ ),
5917
+ isHtmlLabel(o.label) ? /* @__PURE__ */ jsxRuntime.jsx(
5918
+ "span",
5919
+ {
5920
+ className: "flex-1 truncate",
5921
+ dangerouslySetInnerHTML: { __html: sanitizeInlineHtml(o.label) }
5922
+ }
5923
+ ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate", children: o.label })
5924
+ ]
5925
+ },
5926
+ o.value
5927
+ );
5928
+ })
5929
+ ] });
5704
5930
  }
5705
5931
  var DEFAULT_ROW_HEIGHT = 44;
5706
5932
  var DENSE_ROW_HEIGHT = 32;
@@ -5975,7 +6201,8 @@ var STable = react.forwardRef(function STable2({
5975
6201
  else onSelectedChange?.([...selected, row]);
5976
6202
  };
5977
6203
  const radiusClass = radius === "full" ? "rounded-none" : radius === "useTop" ? "rounded-b-[var(--cmp-table-radius)] rounded-t-none" : "rounded-[var(--cmp-table-radius)]";
5978
- const cellPadY = dense ? "var(--cmp-table-body-dense-paddingY)" : "var(--cmp-table-body-default-paddingY)";
6204
+ const cellPadY = dense ? "var(--cmp-table-body-paddingY-dense)" : "var(--cmp-table-body-paddingY-default)";
6205
+ const cellPadX = "var(--cmp-table-body-paddingX-wide)";
5979
6206
  const rowH = dense ? "var(--cmp-table-body-dense-height)" : "var(--cmp-table-body-default-height)";
5980
6207
  const totalColSpan = visibleCols.length + (selectable ? 1 : 0);
5981
6208
  const stickyInfo = (i) => {
@@ -6150,13 +6377,15 @@ var STable = react.forwardRef(function STable2({
6150
6377
  className: cn(
6151
6378
  // 원본 .td: 컬럼 폭에 맞춰 내용 말줄임(overflow hidden + ellipsis) + 행 구분선(border-b)
6152
6379
  // 셀 배경은 흰색으로 채워 뒤 배경이 비치지 않게 하고, hover 시 행 배경(grey_05)을 따른다.
6153
- "overflow-hidden text-ellipsis whitespace-nowrap border-b border-solid border-[color:var(--cmp-table-border-color)] px-[16px] text-[12px] leading-[20px] text-[color:var(--sys-color-fg-primary)]",
6380
+ "overflow-hidden text-ellipsis whitespace-nowrap border-b border-solid border-[color:var(--cmp-table-border-color)] text-[12px] leading-[20px] text-[color:var(--sys-color-fg-primary)]",
6154
6381
  rowBg,
6155
6382
  "group-hover:bg-[var(--color-grey-05)]",
6156
6383
  stickyShadowClass(i),
6157
6384
  col.tdClass
6158
6385
  ),
6159
6386
  style: {
6387
+ paddingLeft: cellPadX,
6388
+ paddingRight: cellPadX,
6160
6389
  paddingTop: cellPadY,
6161
6390
  paddingBottom: cellPadY,
6162
6391
  textAlign: col.align ?? "left",
@@ -6220,6 +6449,7 @@ var SInput = react.forwardRef(function SInput2({
6220
6449
  type = "text",
6221
6450
  size = "sm",
6222
6451
  icon,
6452
+ iconColor,
6223
6453
  prefix,
6224
6454
  suffix,
6225
6455
  clearable = false,
@@ -6273,6 +6503,7 @@ var SInput = react.forwardRef(function SInput2({
6273
6503
  labelTooltip,
6274
6504
  labelTooltipProps,
6275
6505
  icon,
6506
+ iconColor,
6276
6507
  size,
6277
6508
  hint,
6278
6509
  error: resolvedError,
@@ -6374,6 +6605,7 @@ var STextarea = react.forwardRef(function STextarea2({
6374
6605
  label,
6375
6606
  labelWidth,
6376
6607
  icon,
6608
+ iconColor,
6377
6609
  labelTooltip,
6378
6610
  labelTooltipProps,
6379
6611
  addonLabel,
@@ -6410,6 +6642,7 @@ var STextarea = react.forwardRef(function STextarea2({
6410
6642
  label,
6411
6643
  labelWidth,
6412
6644
  icon,
6645
+ iconColor,
6413
6646
  labelTooltip,
6414
6647
  labelTooltipProps,
6415
6648
  addonLabel,
@@ -6542,6 +6775,7 @@ var SNumberInput = react.forwardRef(function SNumberInput2({
6542
6775
  label,
6543
6776
  labelWidth,
6544
6777
  icon,
6778
+ iconColor,
6545
6779
  labelTooltip,
6546
6780
  labelTooltipProps,
6547
6781
  addonLabel,
@@ -6700,6 +6934,7 @@ var SNumberInput = react.forwardRef(function SNumberInput2({
6700
6934
  label,
6701
6935
  labelWidth,
6702
6936
  icon,
6937
+ iconColor,
6703
6938
  labelTooltip,
6704
6939
  labelTooltipProps,
6705
6940
  addonLabel,
@@ -6890,7 +7125,7 @@ function SRadioGroup({
6890
7125
  role: "radiogroup",
6891
7126
  className: cn(
6892
7127
  "inline-flex",
6893
- direction === "vertical" ? "flex-col gap-[8px]" : "flex-row gap-[20px]",
7128
+ direction === "vertical" ? "flex-col gap-[var(--cmp-radio-group-gap-vertical)]" : "flex-row gap-[var(--cmp-radio-group-gap-horizontal)]",
6894
7129
  className
6895
7130
  ),
6896
7131
  style,
@@ -7175,6 +7410,7 @@ function SDatePicker({
7175
7410
  label,
7176
7411
  labelWidth,
7177
7412
  icon,
7413
+ iconColor,
7178
7414
  labelTooltip,
7179
7415
  labelTooltipProps,
7180
7416
  addonLabel,
@@ -7213,6 +7449,7 @@ function SDatePicker({
7213
7449
  label,
7214
7450
  labelWidth,
7215
7451
  icon,
7452
+ iconColor,
7216
7453
  labelTooltip,
7217
7454
  labelTooltipProps,
7218
7455
  addonLabel,
@@ -7481,6 +7718,7 @@ function SDateRangePicker({
7481
7718
  label,
7482
7719
  labelWidth,
7483
7720
  icon,
7721
+ iconColor,
7484
7722
  labelTooltip,
7485
7723
  labelTooltipProps,
7486
7724
  addonLabel,
@@ -7523,6 +7761,7 @@ function SDateRangePicker({
7523
7761
  label,
7524
7762
  labelWidth,
7525
7763
  icon,
7764
+ iconColor,
7526
7765
  labelTooltip,
7527
7766
  labelTooltipProps,
7528
7767
  addonLabel,
@@ -7784,6 +8023,7 @@ function SFilePicker({
7784
8023
  label,
7785
8024
  labelWidth,
7786
8025
  icon,
8026
+ iconColor,
7787
8027
  labelTooltip,
7788
8028
  labelTooltipProps,
7789
8029
  addonLabel,
@@ -7798,7 +8038,10 @@ function SFilePicker({
7798
8038
  const autoId = react.useId();
7799
8039
  const resolvedName = name ?? autoId;
7800
8040
  const inputRef = react.useRef(null);
8041
+ const contentBoxRef = react.useRef(null);
7801
8042
  const [ruleError, setRuleError] = react.useState("");
8043
+ const [listOpen, setListOpen] = react.useState(false);
8044
+ const portalContainer = usePortalContainer();
7802
8045
  const files = multiple ? Array.isArray(value) ? value : [] : value && !Array.isArray(value) ? value : null;
7803
8046
  const hasFiles = multiple ? files.length > 0 : !!files;
7804
8047
  const displayText = !hasFiles ? placeholder : multiple ? files.map((f) => f.name).join(", ") : files.name;
@@ -7852,10 +8095,12 @@ function SFilePicker({
7852
8095
  e.stopPropagation();
7853
8096
  if (disabled) return;
7854
8097
  onValueChange?.(multiple ? [] : null);
8098
+ setListOpen(false);
7855
8099
  };
7856
8100
  const removeChip = (i) => {
7857
8101
  const next = files.filter((_, idx) => idx !== i);
7858
8102
  onValueChange?.(next);
8103
+ if (next.length === 0) setListOpen(false);
7859
8104
  };
7860
8105
  const open = () => {
7861
8106
  if (!disabled) inputRef.current?.click();
@@ -7866,9 +8111,12 @@ function SFilePicker({
7866
8111
  const iconSize = size === "md" ? 20 : 16;
7867
8112
  const gapCls = size === "md" ? "gap-[var(--cmp-filepicker-md-gap)]" : "gap-[var(--cmp-filepicker-sm-gap)]";
7868
8113
  const inlinePlaceholder = inline && !disabled && !hasFiles;
7869
- const content = /* @__PURE__ */ jsxRuntime.jsxs(
8114
+ const showListbox = multiple && useMultipleListBox;
8115
+ const filesArr = multiple ? files : [];
8116
+ const contentInner = /* @__PURE__ */ jsxRuntime.jsxs(
7870
8117
  "div",
7871
8118
  {
8119
+ ref: contentBoxRef,
7872
8120
  className: cn("group/filepicker flex h-full w-full items-center", gapCls),
7873
8121
  style: { padding: inline ? 0 : `0 ${padX}` },
7874
8122
  children: [
@@ -7923,25 +8171,34 @@ function SFilePicker({
7923
8171
  ]
7924
8172
  }
7925
8173
  ),
8174
+ showListbox && hasFiles && !disabled && /* @__PURE__ */ jsxRuntime.jsx(
8175
+ Ariakit__namespace.PopoverDisclosure,
8176
+ {
8177
+ render: /* @__PURE__ */ jsxRuntime.jsx(SGhostButton, { icon: "caretDown", size: "xxs", ariaLabel: "toggle file list" }),
8178
+ className: cn("shrink-0 transition-transform duration-150", listOpen && "rotate-180")
8179
+ }
8180
+ ),
7926
8181
  !disabled && hasFiles && /* @__PURE__ */ jsxRuntime.jsx(SGhostButton, { icon: "close", size: "xxs", ariaLabel: "clear", onClick: clear })
7927
8182
  ]
7928
8183
  }
7929
8184
  );
7930
- const chips = multiple && files.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
7931
- "div",
7932
- {
7933
- className: cn(
7934
- "mt-[8px] flex gap-[8px]",
7935
- useMultipleListBox ? "box-border flex-col items-start rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] p-[8px] shadow-[2px_2px_12px_2px_rgba(0,0,0,0.1)]" : "flex-wrap"
7936
- ),
7937
- style: useMultipleListBox ? {
7938
- width: typeof width === "number" ? `${width}px` : width,
7939
- // label 이 있으면 SField 입력 박스 시작 위치(labelWidth + fieldGap)에 맞춰 정렬
7940
- marginLeft: label && labelWidth != null ? `calc(${typeof labelWidth === "number" ? `${labelWidth}px` : labelWidth} + var(--sys-space-field-${size}-gap))` : void 0
7941
- } : void 0,
7942
- children: files.map((f, i) => /* @__PURE__ */ jsxRuntime.jsx(SChip, { value: f.name, editable: false, onRemove: () => removeChip(i) }, i))
7943
- }
7944
- );
8185
+ const content = showListbox ? /* @__PURE__ */ jsxRuntime.jsxs(Ariakit__namespace.PopoverProvider, { open: listOpen, setOpen: setListOpen, placement: "bottom-start", children: [
8186
+ contentInner,
8187
+ /* @__PURE__ */ jsxRuntime.jsx(
8188
+ Ariakit__namespace.Popover,
8189
+ {
8190
+ portal: true,
8191
+ portalElement: portalContainer,
8192
+ gutter: 4,
8193
+ unmountOnHide: true,
8194
+ getAnchorRect: () => contentBoxRef.current?.getBoundingClientRect() ?? null,
8195
+ style: { minWidth: contentBoxRef.current?.offsetWidth },
8196
+ 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)]",
8197
+ children: filesArr.map((f, i) => /* @__PURE__ */ jsxRuntime.jsx(SChip, { value: f.name, editable: false, onRemove: () => removeChip(i) }, i))
8198
+ }
8199
+ )
8200
+ ] }) : contentInner;
8201
+ const chips = multiple && !useMultipleListBox && filesArr.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-[8px] flex flex-wrap gap-[8px]", children: filesArr.map((f, i) => /* @__PURE__ */ jsxRuntime.jsx(SChip, { value: f.name, editable: false, onRemove: () => removeChip(i) }, i)) });
7945
8202
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style, children: [
7946
8203
  /* @__PURE__ */ jsxRuntime.jsx(
7947
8204
  SField,
@@ -7950,6 +8207,7 @@ function SFilePicker({
7950
8207
  label,
7951
8208
  labelWidth,
7952
8209
  icon,
8210
+ iconColor,
7953
8211
  labelTooltip,
7954
8212
  labelTooltipProps,
7955
8213
  addonLabel,
@@ -7972,21 +8230,26 @@ function SFilePicker({
7972
8230
  var cssLen2 = (v) => v == null ? void 0 : typeof v === "number" ? `${v}px` : v;
7973
8231
  function SKeyValueTable({
7974
8232
  fields = [],
8233
+ values = {},
7975
8234
  search = false,
7976
8235
  radius = "default",
7977
- dense = false,
7978
8236
  onChange,
7979
8237
  onSearch,
7980
8238
  className,
7981
8239
  style
7982
8240
  }) {
7983
8241
  if (fields.length === 0) return null;
7984
- const emit2 = (name, value) => onChange?.({ name, value });
7985
- const cellHeight = dense ? "var(--cmp-table-body-dense-height)" : "var(--cmp-table-keyValue-height)";
7986
- const cellPadY = dense ? "var(--cmp-table-body-dense-paddingY)" : "var(--cmp-table-keyValue-body-paddingY)";
8242
+ const emit2 = (name, value) => onChange?.({
8243
+ name,
8244
+ value,
8245
+ values: { ...values, [name]: value }
8246
+ });
8247
+ const cellHeight = "var(--cmp-table-keyValue-height)";
8248
+ const cellPadY = "var(--cmp-table-keyValue-body-paddingY)";
7987
8249
  const renderField = (f) => {
7988
8250
  if (f.render) return f.render;
7989
- const opt = f.options ?? {};
8251
+ const opt = { ...f.options ?? {} };
8252
+ if (Object.prototype.hasOwnProperty.call(values, f.name)) opt.value = values[f.name];
7990
8253
  const up = (v) => emit2(f.name, v);
7991
8254
  switch (f.type) {
7992
8255
  case "input":
@@ -8098,7 +8361,10 @@ function SKeyValueTable({
8098
8361
  rowSpan: f.tdRowSpan && f.tdRowSpan > 1 ? f.tdRowSpan : void 0,
8099
8362
  colSpan: f.tdColSpan && f.tdColSpan > 1 ? f.tdColSpan : void 0,
8100
8363
  className: cn(
8101
- "box-border bg-[var(--sys-color-bg-frame)] px-[var(--cmp-table-keyValue-body-paddingX-default)] align-middle",
8364
+ "box-border bg-[var(--sys-color-bg-frame)] align-middle",
8365
+ // text 타입(및 미지정 기본값)은 읽기 전용 콘텐츠라 넓은 paddingX(wide),
8366
+ // 폼 필드 셀은 default paddingX 유지
8367
+ f.type == null || f.type === "text" ? "px-[var(--cmp-table-keyValue-body-paddingX-wide)]" : "px-[var(--cmp-table-keyValue-body-paddingX-default)]",
8102
8368
  cellBorder,
8103
8369
  f.tdClass
8104
8370
  ),
@@ -8591,6 +8857,7 @@ var SChipInput = react.forwardRef(function SChipInput2({
8591
8857
  error,
8592
8858
  useReset = false,
8593
8859
  maxCount,
8860
+ metaPlacement = "end",
8594
8861
  duplicateLabel,
8595
8862
  suggestions = [],
8596
8863
  loadingSuggestions = false,
@@ -8604,6 +8871,7 @@ var SChipInput = react.forwardRef(function SChipInput2({
8604
8871
  width,
8605
8872
  status,
8606
8873
  icon,
8874
+ iconColor,
8607
8875
  labelTooltip,
8608
8876
  labelTooltipProps,
8609
8877
  className,
@@ -8738,6 +9006,7 @@ var SChipInput = react.forwardRef(function SChipInput2({
8738
9006
  labelWidth,
8739
9007
  labelHeight: `calc(var(--cmp-chipInput-${size}-minHeight) + 2px)`,
8740
9008
  icon,
9009
+ iconColor,
8741
9010
  labelTooltip,
8742
9011
  labelTooltipProps,
8743
9012
  size,
@@ -8885,7 +9154,11 @@ var SChipInput = react.forwardRef(function SChipInput2({
8885
9154
  showMetaInfo && /* @__PURE__ */ jsxRuntime.jsxs(
8886
9155
  "div",
8887
9156
  {
8888
- className: "s-chip-input__meta ml-auto flex items-center gap-8",
9157
+ className: cn(
9158
+ "s-chip-input__meta flex items-center gap-8",
9159
+ metaPlacement === "end" && "ml-auto"
9160
+ ),
9161
+ "data-placement": metaPlacement,
8889
9162
  onMouseDown: (e) => e.preventDefault(),
8890
9163
  children: [
8891
9164
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -9025,6 +9298,7 @@ var SBarcodeInput = react.forwardRef(
9025
9298
  label,
9026
9299
  labelWidth,
9027
9300
  icon,
9301
+ iconColor,
9028
9302
  labelTooltip,
9029
9303
  labelTooltipProps,
9030
9304
  addonLabel,
@@ -9056,6 +9330,7 @@ var SBarcodeInput = react.forwardRef(
9056
9330
  label,
9057
9331
  labelWidth,
9058
9332
  icon,
9333
+ iconColor,
9059
9334
  labelTooltip,
9060
9335
  labelTooltipProps,
9061
9336
  addonLabel,
@@ -9167,7 +9442,6 @@ exports.SLinearProgress = SLinearProgress;
9167
9442
  exports.SLoadingContainer = SLoadingContainer;
9168
9443
  exports.SLoadingModal = SLoadingModal;
9169
9444
  exports.SLoadingViewport = SLoadingViewport;
9170
- exports.SModalContainer = SModalContainer;
9171
9445
  exports.SNumberInput = SNumberInput;
9172
9446
  exports.SPagination = SPagination;
9173
9447
  exports.SPopover = SPopover;