sellmate-design-system-react 0.1.7 → 0.1.9

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 (146) hide show
  1. package/dist/components/SActionModal/SActionModal.cjs +11 -3
  2. package/dist/components/SActionModal/SActionModal.cjs.map +1 -1
  3. package/dist/components/SActionModal/SActionModal.js +11 -3
  4. package/dist/components/SActionModal/SActionModal.js.map +1 -1
  5. package/dist/components/SBarcodeInput/SBarcodeInput.cjs +226 -209
  6. package/dist/components/SBarcodeInput/SBarcodeInput.cjs.map +1 -1
  7. package/dist/components/SBarcodeInput/SBarcodeInput.js +226 -209
  8. package/dist/components/SBarcodeInput/SBarcodeInput.js.map +1 -1
  9. package/dist/components/SCalendar/SCalendar.cjs +9 -1
  10. package/dist/components/SCalendar/SCalendar.cjs.map +1 -1
  11. package/dist/components/SCalendar/SCalendar.js +9 -1
  12. package/dist/components/SCalendar/SCalendar.js.map +1 -1
  13. package/dist/components/SChip/SChip.cjs +9 -1
  14. package/dist/components/SChip/SChip.cjs.map +1 -1
  15. package/dist/components/SChip/SChip.d.ts +1 -1
  16. package/dist/components/SChip/SChip.js +9 -1
  17. package/dist/components/SChip/SChip.js.map +1 -1
  18. package/dist/components/SChipInput/SChipInput.cjs +260 -235
  19. package/dist/components/SChipInput/SChipInput.cjs.map +1 -1
  20. package/dist/components/SChipInput/SChipInput.js +259 -235
  21. package/dist/components/SChipInput/SChipInput.js.map +1 -1
  22. package/dist/components/SCircleProgress/SCircleProgress.cjs +56 -58
  23. package/dist/components/SCircleProgress/SCircleProgress.cjs.map +1 -1
  24. package/dist/components/SCircleProgress/SCircleProgress.js +56 -58
  25. package/dist/components/SCircleProgress/SCircleProgress.js.map +1 -1
  26. package/dist/components/SConfirmModal/SConfirmModal.cjs +9 -1
  27. package/dist/components/SConfirmModal/SConfirmModal.cjs.map +1 -1
  28. package/dist/components/SConfirmModal/SConfirmModal.js +9 -1
  29. package/dist/components/SConfirmModal/SConfirmModal.js.map +1 -1
  30. package/dist/components/SDatePicker/SDatePicker.cjs +247 -221
  31. package/dist/components/SDatePicker/SDatePicker.cjs.map +1 -1
  32. package/dist/components/SDatePicker/SDatePicker.js +247 -221
  33. package/dist/components/SDatePicker/SDatePicker.js.map +1 -1
  34. package/dist/components/SDateRangePicker/SDateRangePicker.cjs +308 -256
  35. package/dist/components/SDateRangePicker/SDateRangePicker.cjs.map +1 -1
  36. package/dist/components/SDateRangePicker/SDateRangePicker.js +308 -256
  37. package/dist/components/SDateRangePicker/SDateRangePicker.js.map +1 -1
  38. package/dist/components/SDropdownButton/SDropdownButton.cjs +51 -4
  39. package/dist/components/SDropdownButton/SDropdownButton.cjs.map +1 -1
  40. package/dist/components/SDropdownButton/SDropdownButton.js +52 -5
  41. package/dist/components/SDropdownButton/SDropdownButton.js.map +1 -1
  42. package/dist/components/SField/SField.cjs +226 -21
  43. package/dist/components/SField/SField.cjs.map +1 -1
  44. package/dist/components/SField/SField.d.ts +11 -0
  45. package/dist/components/SField/SField.js +226 -21
  46. package/dist/components/SField/SField.js.map +1 -1
  47. package/dist/components/SFilePicker/SFilePicker.cjs +306 -278
  48. package/dist/components/SFilePicker/SFilePicker.cjs.map +1 -1
  49. package/dist/components/SFilePicker/SFilePicker.d.ts +4 -2
  50. package/dist/components/SFilePicker/SFilePicker.js +306 -278
  51. package/dist/components/SFilePicker/SFilePicker.js.map +1 -1
  52. package/dist/components/SGhostButton/SGhostButton.cjs +8 -0
  53. package/dist/components/SGhostButton/SGhostButton.cjs.map +1 -1
  54. package/dist/components/SGhostButton/SGhostButton.js +8 -0
  55. package/dist/components/SGhostButton/SGhostButton.js.map +1 -1
  56. package/dist/components/SGuide/SGuide.cjs +12 -1
  57. package/dist/components/SGuide/SGuide.cjs.map +1 -1
  58. package/dist/components/SGuide/SGuide.js +12 -1
  59. package/dist/components/SGuide/SGuide.js.map +1 -1
  60. package/dist/components/SInput/SInput.cjs +226 -209
  61. package/dist/components/SInput/SInput.cjs.map +1 -1
  62. package/dist/components/SInput/SInput.js +226 -209
  63. package/dist/components/SInput/SInput.js.map +1 -1
  64. package/dist/components/SKeyValueTable/SKeyValueTable.cjs +640 -453
  65. package/dist/components/SKeyValueTable/SKeyValueTable.cjs.map +1 -1
  66. package/dist/components/SKeyValueTable/SKeyValueTable.d.ts +3 -1
  67. package/dist/components/SKeyValueTable/SKeyValueTable.js +640 -453
  68. package/dist/components/SKeyValueTable/SKeyValueTable.js.map +1 -1
  69. package/dist/components/SLoadingContainer/SLoadingContainer.cjs +64 -58
  70. package/dist/components/SLoadingContainer/SLoadingContainer.cjs.map +1 -1
  71. package/dist/components/SLoadingContainer/SLoadingContainer.js +64 -58
  72. package/dist/components/SLoadingContainer/SLoadingContainer.js.map +1 -1
  73. package/dist/components/SLoadingContainer/loading.cjs +64 -58
  74. package/dist/components/SLoadingContainer/loading.cjs.map +1 -1
  75. package/dist/components/SLoadingContainer/loading.js +64 -58
  76. package/dist/components/SLoadingContainer/loading.js.map +1 -1
  77. package/dist/components/SLoadingModal/SLoadingModal.cjs +68 -61
  78. package/dist/components/SLoadingModal/SLoadingModal.cjs.map +1 -1
  79. package/dist/components/SLoadingModal/SLoadingModal.js +68 -61
  80. package/dist/components/SLoadingModal/SLoadingModal.js.map +1 -1
  81. package/dist/components/SModalContainer/SModalContainer.cjs +9 -1
  82. package/dist/components/SModalContainer/SModalContainer.cjs.map +1 -1
  83. package/dist/components/SModalContainer/SModalContainer.js +9 -1
  84. package/dist/components/SModalContainer/SModalContainer.js.map +1 -1
  85. package/dist/components/SNumberInput/SNumberInput.cjs +334 -50
  86. package/dist/components/SNumberInput/SNumberInput.cjs.map +1 -1
  87. package/dist/components/SNumberInput/SNumberInput.d.ts +2 -0
  88. package/dist/components/SNumberInput/SNumberInput.js +334 -50
  89. package/dist/components/SNumberInput/SNumberInput.js.map +1 -1
  90. package/dist/components/SPagination/SPagination.cjs +1 -1
  91. package/dist/components/SPagination/SPagination.cjs.map +1 -1
  92. package/dist/components/SPagination/SPagination.js +1 -1
  93. package/dist/components/SPagination/SPagination.js.map +1 -1
  94. package/dist/components/SPopover/SPopover.cjs +20 -3
  95. package/dist/components/SPopover/SPopover.cjs.map +1 -1
  96. package/dist/components/SPopover/SPopover.js +20 -4
  97. package/dist/components/SPopover/SPopover.js.map +1 -1
  98. package/dist/components/SPopup/SPopup.cjs +2 -2
  99. package/dist/components/SPopup/SPopup.cjs.map +1 -1
  100. package/dist/components/SPopup/SPopup.js +2 -2
  101. package/dist/components/SPopup/SPopup.js.map +1 -1
  102. package/dist/components/SPortal/SPortal.cjs +8 -0
  103. package/dist/components/SPortal/SPortal.cjs.map +1 -1
  104. package/dist/components/SPortal/SPortal.js +8 -0
  105. package/dist/components/SPortal/SPortal.js.map +1 -1
  106. package/dist/components/SSelect/SSelect.cjs +76 -32
  107. package/dist/components/SSelect/SSelect.cjs.map +1 -1
  108. package/dist/components/SSelect/SSelect.js +76 -32
  109. package/dist/components/SSelect/SSelect.js.map +1 -1
  110. package/dist/components/STable/STable.cjs +133 -91
  111. package/dist/components/STable/STable.cjs.map +1 -1
  112. package/dist/components/STable/STable.js +133 -91
  113. package/dist/components/STable/STable.js.map +1 -1
  114. package/dist/components/STextLink/STextLink.cjs +137 -3
  115. package/dist/components/STextLink/STextLink.cjs.map +1 -1
  116. package/dist/components/STextLink/STextLink.d.ts +1 -1
  117. package/dist/components/STextLink/STextLink.js +118 -4
  118. package/dist/components/STextLink/STextLink.js.map +1 -1
  119. package/dist/components/STextarea/STextarea.cjs +226 -21
  120. package/dist/components/STextarea/STextarea.cjs.map +1 -1
  121. package/dist/components/STextarea/STextarea.js +226 -21
  122. package/dist/components/STextarea/STextarea.js.map +1 -1
  123. package/dist/components/SToast/SToast.cjs +8 -0
  124. package/dist/components/SToast/SToast.cjs.map +1 -1
  125. package/dist/components/SToast/SToast.js +8 -0
  126. package/dist/components/SToast/SToast.js.map +1 -1
  127. package/dist/components/SToast/SToastContainer.cjs +11 -3
  128. package/dist/components/SToast/SToastContainer.cjs.map +1 -1
  129. package/dist/components/SToast/SToastContainer.js +11 -3
  130. package/dist/components/SToast/SToastContainer.js.map +1 -1
  131. package/dist/components/STooltip/STooltip.cjs +217 -14
  132. package/dist/components/STooltip/STooltip.cjs.map +1 -1
  133. package/dist/components/STooltip/STooltip.js +217 -14
  134. package/dist/components/STooltip/STooltip.js.map +1 -1
  135. package/dist/index.cjs +532 -300
  136. package/dist/index.cjs.map +1 -1
  137. package/dist/index.js +531 -300
  138. package/dist/index.js.map +1 -1
  139. package/dist/lib/floating-anim.cjs +8 -0
  140. package/dist/lib/floating-anim.cjs.map +1 -1
  141. package/dist/lib/floating-anim.d.ts +5 -1
  142. package/dist/lib/floating-anim.js +8 -0
  143. package/dist/lib/floating-anim.js.map +1 -1
  144. package/dist/styles.css +175 -66
  145. package/dist/theme.css +49 -22
  146. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ import { forwardRef, useState, useEffect, useRef, useCallback, createContext, us
4
4
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
5
  import { createPortal } from 'react-dom';
6
6
  import { createRoot } from 'react-dom/client';
7
+ import * as RTooltip from '@radix-ui/react-tooltip';
7
8
  import * as RDropdown from '@radix-ui/react-dropdown-menu';
8
9
  import * as RPopover2 from '@radix-ui/react-popover';
9
10
  import * as RSwitch from '@radix-ui/react-switch';
@@ -3291,11 +3292,11 @@ var RADIUS = 34;
3291
3292
  var STROKE = 12;
3292
3293
  var CIRCUMFERENCE = 2 * Math.PI * RADIUS;
3293
3294
  var COLOR_MAP = {
3294
- primary: { arc: "var(--cmp-spinner-color-arc)", track: "var(--cmp-spinner-color-track)" },
3295
+ primary: { arc: "var(--cmp-progress-active-color)", track: "var(--cmp-progress-color-track)" },
3295
3296
  // inverse: 어두운 배경용 — arc 흰색, track 은 흰색 40%(회색 링)
3296
3297
  inverse: { arc: "var(--color-white)", track: "rgba(255,255,255,0.4)" },
3297
- error: { arc: "var(--color-red-75)", track: "var(--cmp-spinner-color-track)" },
3298
- complete: { arc: "#01BB4B", track: "var(--cmp-spinner-color-track)" }
3298
+ error: { arc: "var(--color-red-75)", track: "var(--cmp-progress-color-track)" },
3299
+ complete: { arc: "#01BB4B", track: "var(--cmp-progress-color-track)" }
3299
3300
  };
3300
3301
  var clamp2 = (v) => Number.isFinite(v) ? Math.max(0, Math.min(100, v)) : 0;
3301
3302
  var SCircleProgress = forwardRef(
@@ -3309,65 +3310,63 @@ var SCircleProgress = forwardRef(
3309
3310
  "div",
3310
3311
  {
3311
3312
  ref,
3312
- className: cn("inline-flex flex-col items-center gap-[8px]", className),
3313
+ className: cn(
3314
+ "inline-flex flex-col items-center gap-[var(--cmp-progress-circular-gap)]",
3315
+ className
3316
+ ),
3313
3317
  style,
3314
3318
  children: [
3315
- /* @__PURE__ */ jsxs("div", { className: "relative h-[80px] w-[80px]", children: [
3316
- /* @__PURE__ */ jsxs(
3317
- "svg",
3318
- {
3319
- viewBox: `0 0 ${VIEWBOX} ${VIEWBOX}`,
3320
- xmlns: "http://www.w3.org/2000/svg",
3321
- className: cn(
3322
- "h-[80px] w-[80px]",
3323
- indeterminate && "origin-center animate-circle-spin"
3319
+ /* @__PURE__ */ jsxs(
3320
+ "svg",
3321
+ {
3322
+ viewBox: `0 0 ${VIEWBOX} ${VIEWBOX}`,
3323
+ xmlns: "http://www.w3.org/2000/svg",
3324
+ className: cn("h-[80px] w-[80px]", indeterminate && "origin-center animate-circle-spin"),
3325
+ children: [
3326
+ /* @__PURE__ */ jsx(
3327
+ "circle",
3328
+ {
3329
+ cx: c,
3330
+ cy: c,
3331
+ r: RADIUS,
3332
+ fill: "none",
3333
+ strokeWidth: STROKE,
3334
+ style: { stroke: colors.track }
3335
+ }
3324
3336
  ),
3325
- children: [
3326
- /* @__PURE__ */ jsx(
3327
- "circle",
3328
- {
3329
- cx: c,
3330
- cy: c,
3331
- r: RADIUS,
3332
- fill: "none",
3333
- strokeWidth: STROKE,
3334
- style: { stroke: colors.track }
3335
- }
3336
- ),
3337
- /* @__PURE__ */ jsx(
3338
- "circle",
3339
- {
3340
- cx: c,
3341
- cy: c,
3342
- r: RADIUS,
3343
- fill: "none",
3344
- strokeWidth: STROKE,
3345
- strokeLinecap: "round",
3346
- className: cn(
3347
- "origin-center",
3348
- indeterminate ? "animate-circle-arc" : "-rotate-90 transition-[stroke-dasharray] duration-[400ms] ease-linear"
3349
- ),
3350
- style: {
3351
- stroke: colors.arc,
3352
- ...indeterminate ? {} : { strokeDasharray: `${filled} ${CIRCUMFERENCE}`, strokeDashoffset: 0 }
3353
- }
3337
+ /* @__PURE__ */ jsx(
3338
+ "circle",
3339
+ {
3340
+ cx: c,
3341
+ cy: c,
3342
+ r: RADIUS,
3343
+ fill: "none",
3344
+ strokeWidth: STROKE,
3345
+ strokeLinecap: "round",
3346
+ className: cn(
3347
+ "origin-center",
3348
+ indeterminate ? "animate-circle-arc" : "-rotate-90 transition-[stroke-dasharray] duration-[400ms] ease-linear"
3349
+ ),
3350
+ style: {
3351
+ stroke: colors.arc,
3352
+ ...indeterminate ? {} : { strokeDasharray: `${filled} ${CIRCUMFERENCE}`, strokeDashoffset: 0 }
3354
3353
  }
3355
- )
3356
- ]
3357
- }
3358
- ),
3359
- !indeterminate && /* @__PURE__ */ jsxs(
3360
- "span",
3361
- {
3362
- className: "absolute inset-0 flex items-center justify-center text-[16px] font-bold leading-[26px]",
3363
- style: { color: percentColor },
3364
- children: [
3365
- Math.round(v),
3366
- "%"
3367
- ]
3368
- }
3369
- )
3370
- ] }),
3354
+ }
3355
+ )
3356
+ ]
3357
+ }
3358
+ ),
3359
+ !indeterminate && /* @__PURE__ */ jsxs(
3360
+ "span",
3361
+ {
3362
+ className: "text-center text-[16px] font-bold leading-[26px]",
3363
+ style: { color: percentColor },
3364
+ children: [
3365
+ Math.round(v),
3366
+ "%"
3367
+ ]
3368
+ }
3369
+ ),
3371
3370
  label && /* @__PURE__ */ jsx("span", { className: "text-center text-[12px] font-normal leading-[20px] text-[color:var(--cmp-progress-color-label)]", children: label })
3372
3371
  ]
3373
3372
  }
@@ -3378,6 +3377,14 @@ var SLoadingContainer = forwardRef(
3378
3377
  function SLoadingContainer2({ open = false, message, zIndex = 1200, className, style }, ref) {
3379
3378
  const [mounted2, setMounted] = useState(false);
3380
3379
  useEffect(() => setMounted(true), []);
3380
+ useEffect(() => {
3381
+ if (!open) return;
3382
+ const prev = document.body.style.overflow;
3383
+ document.body.style.overflow = "hidden";
3384
+ return () => {
3385
+ document.body.style.overflow = prev;
3386
+ };
3387
+ }, [open]);
3381
3388
  const innerRef = useRef(null);
3382
3389
  const setRef = useCallback(
3383
3390
  (node) => {
@@ -3458,6 +3465,31 @@ var loading = {
3458
3465
  setState({ open: false });
3459
3466
  }
3460
3467
  };
3468
+
3469
+ // src/lib/floating-anim.ts
3470
+ var FLOATING_SLIDE_ANIM = [
3471
+ "data-[state=open]:data-[side=top]:animate-floating-in-top",
3472
+ "data-[state=delayed-open]:data-[side=top]:animate-floating-in-top",
3473
+ "data-[state=instant-open]:data-[side=top]:animate-floating-in-top",
3474
+ "data-[state=closed]:data-[side=top]:animate-floating-out-top",
3475
+ "data-[state=open]:data-[side=bottom]:animate-floating-in-bottom",
3476
+ "data-[state=delayed-open]:data-[side=bottom]:animate-floating-in-bottom",
3477
+ "data-[state=instant-open]:data-[side=bottom]:animate-floating-in-bottom",
3478
+ "data-[state=closed]:data-[side=bottom]:animate-floating-out-bottom",
3479
+ "data-[state=open]:data-[side=left]:animate-floating-in-left",
3480
+ "data-[state=delayed-open]:data-[side=left]:animate-floating-in-left",
3481
+ "data-[state=instant-open]:data-[side=left]:animate-floating-in-left",
3482
+ "data-[state=closed]:data-[side=left]:animate-floating-out-left",
3483
+ "data-[state=open]:data-[side=right]:animate-floating-in-right",
3484
+ "data-[state=delayed-open]:data-[side=right]:animate-floating-in-right",
3485
+ "data-[state=instant-open]:data-[side=right]:animate-floating-in-right",
3486
+ "data-[state=closed]:data-[side=right]:animate-floating-out-right"
3487
+ ].join(" ");
3488
+ var PortalContainerContext = createContext(null);
3489
+ var PortalContainerProvider = PortalContainerContext.Provider;
3490
+ function usePortalContainer() {
3491
+ return useContext(PortalContainerContext) ?? void 0;
3492
+ }
3461
3493
  var SIZE_CONFIG = {
3462
3494
  sm: {
3463
3495
  gap: 4,
@@ -3491,6 +3523,7 @@ var STextLink = forwardRef(function STextLink2({
3491
3523
  className,
3492
3524
  onClick,
3493
3525
  children,
3526
+ style,
3494
3527
  ...rest
3495
3528
  }, ref) {
3496
3529
  const s = SIZE_CONFIG[size];
@@ -3499,13 +3532,13 @@ var STextLink = forwardRef(function STextLink2({
3499
3532
  const handle = () => {
3500
3533
  if (!disabled) onClick?.();
3501
3534
  };
3502
- return /* @__PURE__ */ jsxs(
3535
+ const portalContainer = usePortalContainer();
3536
+ const link = /* @__PURE__ */ jsxs(
3503
3537
  "span",
3504
3538
  {
3505
3539
  ref,
3506
3540
  role: "button",
3507
3541
  tabIndex: disabled ? -1 : 0,
3508
- title: tooltipText,
3509
3542
  onClick: handle,
3510
3543
  onKeyDown: (e) => {
3511
3544
  if (e.key === "Enter" || e.key === " ") {
@@ -3520,7 +3553,7 @@ var STextLink = forwardRef(function STextLink2({
3520
3553
  disabled && "cursor-not-allowed",
3521
3554
  className
3522
3555
  ),
3523
- style: { gap: s.gap, color: contentColor },
3556
+ style: { gap: s.gap, color: contentColor, ...style },
3524
3557
  ...rest,
3525
3558
  children: [
3526
3559
  icon && /* @__PURE__ */ jsx(SIcon, { name: icon, size: s.iconSize, color: resolvedIconColor }),
@@ -3543,12 +3576,13 @@ var STextLink = forwardRef(function STextLink2({
3543
3576
  ]
3544
3577
  }
3545
3578
  );
3579
+ const text = (tooltipText ?? "").trim();
3580
+ if (text === "") return link;
3581
+ return /* @__PURE__ */ jsx(RTooltip.Provider, { delayDuration: 200, children: /* @__PURE__ */ jsxs(RTooltip.Root, { children: [
3582
+ /* @__PURE__ */ jsx(RTooltip.Trigger, { asChild: true, children: link }),
3583
+ /* @__PURE__ */ jsx(RTooltip.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(RTooltip.Content, { side: "top", sideOffset: 4, className: cn("z-50", FLOATING_SLIDE_ANIM), children: /* @__PURE__ */ jsx(STag, { shape: "square", size: "xs", color: "grey", label: text }) }) })
3584
+ ] }) });
3546
3585
  });
3547
- var PortalContainerContext = createContext(null);
3548
- var PortalContainerProvider = PortalContainerContext.Provider;
3549
- function usePortalContainer() {
3550
- return useContext(PortalContainerContext) ?? void 0;
3551
- }
3552
3586
 
3553
3587
  // src/lib/sanitize-inline-html.ts
3554
3588
  var ALLOWED_INLINE_TAGS = /* @__PURE__ */ new Set(["A", "B", "STRONG", "I", "EM", "BR", "SPAN"]);
@@ -3619,15 +3653,15 @@ var sanitizeInlineHtml = (value) => {
3619
3653
  return template.innerHTML;
3620
3654
  };
3621
3655
  var SIZE = {
3622
- xs: { height: 24, paddingX: 8, gap: 6, arrow: 12, fontSize: 12, minWidth: 44, splitMinWidth: 60 },
3656
+ xs: { height: 24, paddingX: 8, gap: 6, arrow: 12, fontSize: 12, minWidth: 64, splitMinWidth: 72 },
3623
3657
  sm: {
3624
3658
  height: 28,
3625
3659
  paddingX: 12,
3626
3660
  gap: 8,
3627
3661
  arrow: 12,
3628
3662
  fontSize: 12,
3629
- minWidth: 70,
3630
- splitMinWidth: 76
3663
+ minWidth: 72,
3664
+ splitMinWidth: 88
3631
3665
  },
3632
3666
  md: {
3633
3667
  height: 36,
@@ -3677,6 +3711,25 @@ var SDropdownButton = forwardRef(
3677
3711
  }, ref) {
3678
3712
  const portalContainer = usePortalContainer();
3679
3713
  const [open, setOpen] = useState(false);
3714
+ const splitWrapRef = useRef(null);
3715
+ const splitToggleRef = useRef(null);
3716
+ const [splitAlignOffset, setSplitAlignOffset] = useState(0);
3717
+ const [splitWidth, setSplitWidth] = useState(0);
3718
+ useEffect(() => {
3719
+ if (!split) return;
3720
+ const update = () => {
3721
+ if (splitWrapRef.current && splitToggleRef.current) {
3722
+ setSplitAlignOffset(
3723
+ -(splitWrapRef.current.offsetWidth - splitToggleRef.current.offsetWidth)
3724
+ );
3725
+ setSplitWidth(splitWrapRef.current.offsetWidth);
3726
+ }
3727
+ };
3728
+ update();
3729
+ const ro = new ResizeObserver(update);
3730
+ ro.observe(splitWrapRef.current);
3731
+ return () => ro.disconnect();
3732
+ }, [split, label]);
3680
3733
  useImperativeHandle(
3681
3734
  ref,
3682
3735
  () => ({
@@ -3714,7 +3767,13 @@ var SDropdownButton = forwardRef(
3714
3767
  {
3715
3768
  sideOffset: 4,
3716
3769
  align: "start",
3717
- className: "z-50 min-w-[var(--radix-dropdown-menu-trigger-width)] overflow-hidden rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] py-[4px] shadow-normal-sm",
3770
+ alignOffset: split ? splitAlignOffset : 0,
3771
+ className: cn(
3772
+ "z-50 overflow-hidden rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] shadow-normal-sm",
3773
+ !split && "min-w-[var(--radix-dropdown-menu-trigger-width)]",
3774
+ FLOATING_SLIDE_ANIM
3775
+ ),
3776
+ style: split ? { minWidth: splitWidth } : void 0,
3718
3777
  children: items.map((it) => /* @__PURE__ */ jsxs(
3719
3778
  RDropdown.Item,
3720
3779
  {
@@ -3748,6 +3807,7 @@ var SDropdownButton = forwardRef(
3748
3807
  split ? /* @__PURE__ */ jsxs(
3749
3808
  "div",
3750
3809
  {
3810
+ ref: splitWrapRef,
3751
3811
  className: cn("inline-flex items-stretch", className),
3752
3812
  style: { minWidth: s.splitMinWidth, ...style },
3753
3813
  children: [
@@ -3770,6 +3830,7 @@ var SDropdownButton = forwardRef(
3770
3830
  /* @__PURE__ */ jsx(RDropdown.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(
3771
3831
  "button",
3772
3832
  {
3833
+ ref: splitToggleRef,
3773
3834
  type: "button",
3774
3835
  disabled,
3775
3836
  "aria-label": "\uBA54\uB274 \uC5F4\uAE30",
@@ -3813,18 +3874,6 @@ var SDropdownButton = forwardRef(
3813
3874
  }
3814
3875
  );
3815
3876
  SDropdownButton.displayName = "SDropdownButton";
3816
-
3817
- // src/lib/floating-anim.ts
3818
- var FLOATING_SLIDE_ANIM = [
3819
- "data-[state=open]:data-[side=top]:animate-floating-in-top",
3820
- "data-[state=closed]:data-[side=top]:animate-floating-out-top",
3821
- "data-[state=open]:data-[side=bottom]:animate-floating-in-bottom",
3822
- "data-[state=closed]:data-[side=bottom]:animate-floating-out-bottom",
3823
- "data-[state=open]:data-[side=left]:animate-floating-in-left",
3824
- "data-[state=closed]:data-[side=left]:animate-floating-out-left",
3825
- "data-[state=open]:data-[side=right]:animate-floating-in-right",
3826
- "data-[state=closed]:data-[side=right]:animate-floating-out-right"
3827
- ].join(" ");
3828
3877
  var SIZE2 = {
3829
3878
  xxs: { icon: 12, radius: "sm" },
3830
3879
  xs: { icon: 16, radius: "sm" },
@@ -4017,7 +4066,8 @@ var HIDE_DELAY_MS = 100;
4017
4066
  function useBody(content, message = []) {
4018
4067
  if (content != null) return content;
4019
4068
  if (message.length === 0) return null;
4020
- return /* @__PURE__ */ jsx(Fragment, { children: message.map((line, i) => /* @__PURE__ */ jsx("div", { children: line }, i)) });
4069
+ const singleLine = message.length === 1;
4070
+ return /* @__PURE__ */ jsx(Fragment, { children: message.map((line, i) => /* @__PURE__ */ jsx("div", { className: singleLine ? "leading-[24px]" : void 0, children: line }, i)) });
4021
4071
  }
4022
4072
  var STooltip = forwardRef(function STooltip2({
4023
4073
  content,
@@ -4075,7 +4125,7 @@ var STooltip = forwardRef(function STooltip2({
4075
4125
  if (disabled || body == null) return /* @__PURE__ */ jsx(Fragment, { children: triggerNode });
4076
4126
  const isHover = trigger === "hover";
4077
4127
  const contentClass = cn(
4078
- "z-50 max-w-xs rounded-[6px] px-[16px] py-[12px] text-[12px] leading-[20px]",
4128
+ "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)]",
4079
4129
  FLOATING_SLIDE_ANIM,
4080
4130
  className
4081
4131
  );
@@ -4120,11 +4170,17 @@ var STooltip = forwardRef(function STooltip2({
4120
4170
  /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-[12px]", children: [
4121
4171
  /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: body }),
4122
4172
  useClose && /* @__PURE__ */ jsx(
4123
- RPopover2.Close,
4173
+ SGhostButton,
4124
4174
  {
4125
- "aria-label": "\uB2EB\uAE30",
4126
- className: "shrink-0 cursor-pointer opacity-70 hover:opacity-100",
4127
- children: /* @__PURE__ */ jsx(SIcon, { name: "close", size: 16, color: fg })
4175
+ icon: "close",
4176
+ size: "xs",
4177
+ intent: tooltipType === "default" ? "inverse" : "default",
4178
+ ariaLabel: "\uB2EB\uAE30",
4179
+ className: "shrink-0",
4180
+ onClick: () => {
4181
+ cancelHide();
4182
+ setOpen(false);
4183
+ }
4128
4184
  }
4129
4185
  )
4130
4186
  ] }),
@@ -4358,9 +4414,9 @@ var SPopup = forwardRef(function SPopup2({
4358
4414
  useFooter && /* @__PURE__ */ jsxs(
4359
4415
  "footer",
4360
4416
  {
4361
- className: "relative z-[1] flex h-[52px] w-full flex-shrink-0 items-center gap-[var(--cmp-popup-footer-gap)] px-[var(--cmp-popup-footer-paddingX)] py-[var(--cmp-popup-footer-paddingY)]",
4417
+ className: "relative z-[1] flex h-[52px] w-full flex-shrink-0 items-center gap-[var(--cmp-overlay-footer-gap)] px-[var(--cmp-overlay-footer-paddingX)] py-[var(--cmp-overlay-footer-paddingY)]",
4362
4418
  style: {
4363
- background: "var(--cmp-popup-footer-bg)",
4419
+ background: "var(--cmp-overlay-footer-bg-default)",
4364
4420
  boxShadow: "var(--shadow-spread-md)"
4365
4421
  },
4366
4422
  children: [
@@ -4439,7 +4495,10 @@ function SGuide({
4439
4495
  side: "bottom",
4440
4496
  align: "start",
4441
4497
  sideOffset: 4,
4442
- className: "relative z-50 rounded-[var(--cmp-guide-contents-radius)] bg-[var(--color-white)]",
4498
+ className: cn(
4499
+ "relative z-50 rounded-[var(--cmp-guide-contents-radius)] bg-[var(--color-white)]",
4500
+ FLOATING_SLIDE_ANIM
4501
+ ),
4443
4502
  style: {
4444
4503
  width: popupWidth != null ? popupWidth : 426,
4445
4504
  padding: "var(--cmp-guide-contents-paddingY) var(--cmp-guide-contents-paddingX)",
@@ -4548,7 +4607,7 @@ function SModalContainer({
4548
4607
  ]
4549
4608
  }
4550
4609
  ) }),
4551
- /* @__PURE__ */ jsx("div", { ref: setPortalContainer, className: "fixed left-0 top-0 z-[1001]" })
4610
+ /* @__PURE__ */ jsx("div", { ref: setPortalContainer, className: "pointer-events-auto fixed left-0 top-0 z-[1001]" })
4552
4611
  ] }) });
4553
4612
  }
4554
4613
  var TYPE_ICON = {
@@ -4686,9 +4745,9 @@ function SActionModal({
4686
4745
  showClose: true,
4687
4746
  width,
4688
4747
  height,
4689
- className: "w-fit min-w-[480px]",
4748
+ className: "w-fit min-w-[480px] min-h-[320px]",
4690
4749
  children: /* @__PURE__ */ jsxs("div", { className: "flex h-full min-h-[320px] flex-col", children: [
4691
- /* @__PURE__ */ jsx("header", { className: "flex flex-shrink-0 items-center gap-[var(--cmp-modal-action-header-gap)] py-[var(--cmp-modal-action-header-paddingY)] pl-[var(--cmp-modal-action-header-paddingX)] pr-[calc(var(--cmp-modal-action-header-paddingX)+20px)]", children: /* @__PURE__ */ jsx("h2", { className: "text-[16px] font-bold leading-[26px] text-[color:var(--cmp-modal-action-title-color)]", children: modalTitle }) }),
4750
+ /* @__PURE__ */ jsx("header", { className: "flex flex-shrink-0 items-center gap-[var(--cmp-overlay-header-gap)] py-[var(--cmp-overlay-header-paddingY)] pl-[var(--cmp-overlay-header-paddingX)] pr-[calc(var(--cmp-overlay-header-paddingX)+20px)]", children: /* @__PURE__ */ jsx("h2", { className: "text-[16px] font-bold leading-[26px] text-[color:var(--cmp-overlay-header-title-color)]", children: modalTitle }) }),
4692
4751
  /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-auto px-[var(--cmp-modal-action-body-paddingX)] pb-[var(--cmp-modal-action-body-paddingBottom)]", children }),
4693
4752
  button && /* @__PURE__ */ jsx(
4694
4753
  "footer",
@@ -4718,7 +4777,7 @@ function SActionModal({
4718
4777
  );
4719
4778
  }
4720
4779
  var DEFAULT_MESSAGE = {
4721
- loading: "",
4780
+ loading: "\uC791\uC5C5 \uC9C4\uD589\uC911...",
4722
4781
  error: "\uC791\uC5C5\uC5D0 \uC2E4\uD328\uD558\uC600\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD574 \uC8FC\uC138\uC694."
4723
4782
  };
4724
4783
  var DEFAULT_BUTTON_LABEL = {
@@ -4740,6 +4799,7 @@ function SLoadingModal({
4740
4799
  }) {
4741
4800
  const resolvedMessage = message ?? DEFAULT_MESSAGE[state2];
4742
4801
  const lines = Array.isArray(resolvedMessage) ? resolvedMessage : resolvedMessage ? [resolvedMessage] : [];
4802
+ const showButton = useButton || state2 === "error";
4743
4803
  return /* @__PURE__ */ jsx(
4744
4804
  SModalContainer,
4745
4805
  {
@@ -4759,7 +4819,7 @@ function SLoadingModal({
4759
4819
  },
4760
4820
  i
4761
4821
  )) }),
4762
- useButton && /* @__PURE__ */ jsx(
4822
+ showButton && /* @__PURE__ */ jsx(
4763
4823
  SButton,
4764
4824
  {
4765
4825
  color: "neutral",
@@ -4990,7 +5050,7 @@ function SPagination({
4990
5050
  style,
4991
5051
  children: [
4992
5052
  /* @__PURE__ */ jsx("div", { className: "flex min-w-[calc(var(--cmp-pagination-height)*2+var(--cmp-pagination-move-gap))] items-center justify-end gap-[var(--cmp-pagination-move-gap)]", children: prevButtons }),
4993
- simple ? /* @__PURE__ */ jsxs("div", { className: "flex h-[var(--cmp-pagination-height)] items-center gap-[var(--cmp-pagination-move-gap)] px-[var(--cmp-pagination-paddingX)] text-[12px] font-medium leading-[20px] text-[color:var(--cmp-pagination-item-content-default)]", children: [
5053
+ simple ? /* @__PURE__ */ jsxs("div", { className: "flex h-[var(--cmp-pagination-height)] items-center gap-[var(--cmp-pagination-simple-gap)] px-[var(--cmp-pagination-paddingX)] text-[12px] font-medium leading-[20px] text-[color:var(--cmp-pagination-item-content-default)]", children: [
4994
5054
  /* @__PURE__ */ jsx("span", { className: "font-bold text-[color:var(--cmp-pagination-item-content-selected)]", children: currentPage }),
4995
5055
  /* @__PURE__ */ jsx("span", { children: "/" }),
4996
5056
  /* @__PURE__ */ jsx("span", { children: lastPage })
@@ -5114,8 +5174,8 @@ function useFormField(field) {
5114
5174
  }, [ctx, name]);
5115
5175
  }
5116
5176
  var FIELD_SIZE = {
5117
- sm: { height: 28, radius: 4, fieldGap: 12, labelGap: 6, fontSize: 12, lineHeight: 20, icon: 12 },
5118
- md: { height: 36, radius: 6, fieldGap: 16, labelGap: 8, fontSize: 14, lineHeight: 24, icon: 12 }
5177
+ sm: { height: 28, radius: 4, fieldGap: 12, labelGap: 6, fontSize: 12, lineHeight: 20, icon: 16 },
5178
+ md: { height: 36, radius: 6, fieldGap: 16, labelGap: 8, fontSize: 14, lineHeight: 24, icon: 16 }
5119
5179
  };
5120
5180
  var ALIGN = {
5121
5181
  start: "flex-start",
@@ -5130,6 +5190,7 @@ var SField = forwardRef(function SField2({
5130
5190
  labelTooltip = "",
5131
5191
  labelTooltipProps,
5132
5192
  labelWidth,
5193
+ labelHeight,
5133
5194
  size = "sm",
5134
5195
  addonLabel = "",
5135
5196
  addonAlign = "start",
@@ -5144,6 +5205,7 @@ var SField = forwardRef(function SField2({
5144
5205
  readOnly = false,
5145
5206
  width,
5146
5207
  multiline = false,
5208
+ borderless = false,
5147
5209
  children,
5148
5210
  className,
5149
5211
  style,
@@ -5177,8 +5239,8 @@ var SField = forwardRef(function SField2({
5177
5239
  const resolvedSuccess = status === "pass";
5178
5240
  const showError = resolvedError && errorMessage !== "";
5179
5241
  const interactive = !disabled && !readOnly;
5180
- const borderColor = disabled ? "var(--color-grey-45)" : interactive && focused ? "var(--sys-color-field-border-focus)" : resolvedSuccess ? "var(--sys-color-field-border-success)" : resolvedError ? "var(--sys-color-field-border-danger)" : "var(--sys-color-field-border-default)";
5181
- const bgColor = disabled ? "var(--color-grey-30)" : readOnly ? "var(--sys-color-field-bg-readOnly)" : "var(--sys-color-field-bg-default)";
5242
+ const borderColor = borderless ? "transparent" : disabled ? "var(--color-grey-45)" : interactive && focused ? "var(--sys-color-field-border-focus)" : resolvedSuccess ? "var(--sys-color-field-border-success)" : resolvedError ? "var(--sys-color-field-border-danger)" : "var(--sys-color-field-border-default)";
5243
+ const bgColor = borderless ? "transparent" : disabled ? "var(--color-grey-30)" : readOnly ? "var(--sys-color-field-bg-readOnly)" : "var(--sys-color-field-bg-default)";
5182
5244
  const textColor = disabled ? "var(--color-grey-65)" : readOnly ? "var(--sys-color-field-text-readOnly)" : "var(--sys-color-field-text-default)";
5183
5245
  return /* @__PURE__ */ jsx(
5184
5246
  "div",
@@ -5195,7 +5257,7 @@ var SField = forwardRef(function SField2({
5195
5257
  {
5196
5258
  className: "flex shrink-0 items-center font-bold text-(--sys-color-field-text-default)",
5197
5259
  style: {
5198
- height: s.height,
5260
+ height: cssLen(labelHeight) ?? s.height,
5199
5261
  marginRight: s.fieldGap,
5200
5262
  width: cssLen(labelWidth),
5201
5263
  fontSize: s.fontSize,
@@ -5221,14 +5283,14 @@ var SField = forwardRef(function SField2({
5221
5283
  {
5222
5284
  className: cn(
5223
5285
  "relative box-border flex min-w-0 items-stretch overflow-hidden border border-solid border-(--field-bc)",
5224
- interactive && "hover:border-(--sys-color-field-border-focus) hover:shadow-[0px_0px_4px_0px_#0071ff66] focus-within:border-(--sys-color-field-border-focus) focus-within:shadow-[0px_0px_4px_0px_#0071ff66]",
5286
+ interactive && !borderless && "hover:border-(--sys-color-field-border-focus) hover:shadow-[0px_0px_4px_0px_#0071ff66] focus-within:border-(--sys-color-field-border-focus) focus-within:shadow-[0px_0px_4px_0px_#0071ff66]",
5225
5287
  disabled && "cursor-not-allowed"
5226
5288
  ),
5227
5289
  style: {
5228
5290
  // @ts-expect-error CSS 변수
5229
5291
  "--field-bc": borderColor,
5230
5292
  // focused/hovered prop이 명시된 경우 강조를 즉시 반영
5231
- ...interactive && focused ? { boxShadow: "0px 0px 4px 0px #0071ff66" } : {},
5293
+ ...interactive && !borderless && focused ? { boxShadow: "0px 0px 4px 0px #0071ff66" } : {},
5232
5294
  ...multiline ? { minHeight: s.height } : { height: s.height },
5233
5295
  "width": cssLen(width),
5234
5296
  "borderRadius": s.radius,
@@ -5273,15 +5335,28 @@ function flattenOptions(options, depth = 1) {
5273
5335
  const out = [];
5274
5336
  for (const o of options) {
5275
5337
  const hasChildren = Array.isArray(o.children) && o.children.length > 0;
5276
- out.push({
5277
- value: String(o.value),
5278
- label: o.label,
5279
- disabled: !!o.disabled,
5280
- depth,
5281
- isGroup: hasChildren,
5282
- raw: o.value
5283
- });
5284
- if (hasChildren) out.push(...flattenOptions(o.children, depth + 1));
5338
+ if (hasChildren) {
5339
+ const childFlat = flattenOptions(o.children, depth + 1);
5340
+ const allChildrenDisabled = childFlat.every((c) => c.disabled);
5341
+ out.push({
5342
+ value: String(o.value),
5343
+ label: o.label,
5344
+ disabled: !!o.disabled || allChildrenDisabled,
5345
+ depth,
5346
+ isGroup: true,
5347
+ raw: o.value
5348
+ });
5349
+ out.push(...childFlat);
5350
+ } else {
5351
+ out.push({
5352
+ value: String(o.value),
5353
+ label: o.label,
5354
+ disabled: !!o.disabled,
5355
+ depth,
5356
+ isGroup: false,
5357
+ raw: o.value
5358
+ });
5359
+ }
5285
5360
  }
5286
5361
  return out;
5287
5362
  }
@@ -5336,6 +5411,9 @@ var SSelect = forwardRef(function SSelect2({
5336
5411
  );
5337
5412
  const flat = useMemo(() => flattenOptions(options), [options]);
5338
5413
  const selectable = useMemo(() => selectableOptions(flat), [flat]);
5414
+ const hasLeaf = useMemo(() => flat.some((o) => !o.isGroup), [flat]);
5415
+ const allOptionsDisabled = hasLeaf && selectable.length === 0;
5416
+ const effectiveDisabled = disabled || allOptionsDisabled;
5339
5417
  const showSearch = useSearch && selectable.length >= SEARCH_THRESHOLD;
5340
5418
  const labelByValue = useMemo(() => new Map(flat.map((o) => [o.value, o.label])), [flat]);
5341
5419
  const rawByValue = useMemo(() => new Map(flat.map((o) => [o.value, o.raw])), [flat]);
@@ -5386,6 +5464,7 @@ var SSelect = forwardRef(function SSelect2({
5386
5464
  const selectStore = /* @__PURE__ */ jsxs(
5387
5465
  Ariakit.SelectProvider,
5388
5466
  {
5467
+ animated: portalContainer == null ? 150 : false,
5389
5468
  value: multi ? selected : selected[0] ?? "",
5390
5469
  setValue: (v) => emit2(Array.isArray(v) ? v : v === "" ? [] : [v]),
5391
5470
  open,
@@ -5401,10 +5480,10 @@ var SSelect = forwardRef(function SSelect2({
5401
5480
  Ariakit.Select,
5402
5481
  {
5403
5482
  ref: triggerRef,
5404
- disabled,
5483
+ disabled: effectiveDisabled,
5405
5484
  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",
5406
5485
  style: {
5407
- color: disabled ? "var(--cmp-select-text-disabled)" : isPlaceholder ? "var(--cmp-select-icon-default)" : "var(--cmp-select-text-default)"
5486
+ color: effectiveDisabled ? "var(--cmp-select-text-disabled)" : isPlaceholder ? "var(--cmp-select-icon-default)" : "var(--cmp-select-text-default)"
5408
5487
  },
5409
5488
  children: [
5410
5489
  isHtmlLabel(triggerText) ? /* @__PURE__ */ jsx(
@@ -5419,7 +5498,7 @@ var SSelect = forwardRef(function SSelect2({
5419
5498
  {
5420
5499
  name: "chevronDown",
5421
5500
  size: 12,
5422
- color: disabled ? "var(--cmp-select-icon-disabled)" : "var(--cmp-select-icon-default)",
5501
+ color: effectiveDisabled ? "var(--cmp-select-icon-disabled)" : "var(--cmp-select-icon-default)",
5423
5502
  className: cn("shrink-0 transition-transform duration-200", open && "rotate-180")
5424
5503
  }
5425
5504
  )
@@ -5433,7 +5512,7 @@ var SSelect = forwardRef(function SSelect2({
5433
5512
  portalElement: portalContainer,
5434
5513
  gutter: 4,
5435
5514
  sameWidth: !dropdownWidth,
5436
- className: "z-50 overflow-auto rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] py-[4px] shadow-[2px_2px_12px_2px_rgba(0,0,0,0.1)]",
5515
+ 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",
5437
5516
  style: {
5438
5517
  maxHeight: dropdownHeight,
5439
5518
  ...dropdownWidth ? { width: dropdownWidth } : {},
@@ -5474,7 +5553,7 @@ var SSelect = forwardRef(function SSelect2({
5474
5553
  ),
5475
5554
  hasItems ? /* @__PURE__ */ jsx(ItemList, { items: filtered, multi, selected, useSearch: showSearch }) : (
5476
5555
  // 원본 sd-select-listbox__empty (표시할 항목이 없을 때)
5477
- /* @__PURE__ */ jsx("div", { className: "px-[12px] py-[12px] text-center text-[12px] leading-[20px] text-[color:var(--cmp-listItem-content-disabled)]", children: "\uD45C\uC2DC\uD560 \uD56D\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4." })
5556
+ /* @__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." })
5478
5557
  )
5479
5558
  ]
5480
5559
  }
@@ -5497,7 +5576,7 @@ var SSelect = forwardRef(function SSelect2({
5497
5576
  error: error || ruleError !== "",
5498
5577
  status: rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0,
5499
5578
  errorMessage: ruleError !== "" ? ruleError : errorMessage,
5500
- disabled,
5579
+ disabled: effectiveDisabled,
5501
5580
  width,
5502
5581
  className,
5503
5582
  style,
@@ -5532,7 +5611,11 @@ function ItemList({
5532
5611
  {
5533
5612
  className: cn(
5534
5613
  "select-none py-[4px] pr-[12px] text-[12px] leading-[20px] text-[color:var(--cmp-listItem-content-default)]",
5535
- 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"
5614
+ 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",
5615
+ // 하위가 전부 비활성이면(select.config 에서 bubble-up) 어미 그룹도 비활성 처리:
5616
+ // 텍스트는 회색(#888), depth1 그룹은 파란 배경 대신 회색(#EEE)으로 (depth2 는 #F6F6F6 유지)
5617
+ o.disabled && "text-[color:var(--cmp-listItem-content-disabled)]",
5618
+ o.disabled && isDepth1 && "bg-[var(--cmp-listItem-depth1-bg-disabled)]"
5536
5619
  ),
5537
5620
  style: { paddingLeft: padLeft },
5538
5621
  children: o.label
@@ -5559,15 +5642,21 @@ function ItemList({
5559
5642
  "span",
5560
5643
  {
5561
5644
  className: cn(
5562
- "flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center rounded-[2px] border border-solid group-data-[active-item]:border-[color:var(--cmp-checkbox-checked-border-inverse)]",
5563
- 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"
5645
+ "flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center rounded-[2px] border border-solid",
5646
+ o.disabled ? (
5647
+ // 비활성: 회색 채움(#E1E1E1) + 회색 테두리(#CCCCCC)
5648
+ "border-[color:var(--cmp-checkbox-border-disabled)] bg-[var(--cmp-checkbox-bg-disabled)]"
5649
+ ) : cn(
5650
+ "group-data-[active-item]:border-[color:var(--cmp-checkbox-checked-border-inverse)]",
5651
+ 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"
5652
+ )
5564
5653
  ),
5565
5654
  children: isSelected && /* @__PURE__ */ jsx(
5566
5655
  SIcon,
5567
5656
  {
5568
5657
  name: "checkboxCheck",
5569
5658
  size: 12,
5570
- color: "var(--cmp-checkbox-checked-icon-default)"
5659
+ color: o.disabled ? "var(--cmp-checkbox-checked-icon-disabled)" : "var(--cmp-checkbox-checked-icon-default)"
5571
5660
  }
5572
5661
  )
5573
5662
  }
@@ -6346,8 +6435,8 @@ var STextarea = forwardRef(function STextarea2({
6346
6435
  );
6347
6436
  });
6348
6437
  var PAD2 = {
6349
- sm: { fontSize: 12, stepper: 20, icon: 12 },
6350
- md: { fontSize: 14, stepper: 24, icon: 14 }
6438
+ sm: { fontSize: 12, lineHeight: 20, stepper: 20, icon: 12 },
6439
+ md: { fontSize: 14, lineHeight: 24, stepper: 24, icon: 14 }
6351
6440
  };
6352
6441
  var toNumber = (val) => {
6353
6442
  if (val === null || val === void 0 || val === "") return null;
@@ -6365,6 +6454,38 @@ var formatWithCommas = (value) => {
6365
6454
  const result = isNeg ? "-" + formatted : formatted;
6366
6455
  return decPart !== void 0 && decPart !== "" ? result + "." + decPart : result;
6367
6456
  };
6457
+ var addCommas = (value) => value.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
6458
+ var formatInputWithCommas = (value) => {
6459
+ const isNeg = value.startsWith("-");
6460
+ const unsigned = isNeg ? value.slice(1) : value;
6461
+ const hasDecimal = unsigned.includes(".");
6462
+ const [intPart = "", decPart = ""] = unsigned.split(".");
6463
+ const formattedInt = addCommas(intPart === "" ? "0" : intPart);
6464
+ return `${isNeg ? "-" : ""}${formattedInt}${hasDecimal ? `.${decPart}` : ""}`;
6465
+ };
6466
+ var getDecimalLimit = (useDecimal, maxDecimalLength) => {
6467
+ if (!useDecimal || maxDecimalLength === void 0 || !Number.isFinite(maxDecimalLength)) {
6468
+ return void 0;
6469
+ }
6470
+ return Math.max(0, Math.floor(maxDecimalLength));
6471
+ };
6472
+ var applyDecimalLimit = (value, decimalLimit) => {
6473
+ if (value === null || decimalLimit === void 0) return value;
6474
+ return Number(value.toFixed(decimalLimit));
6475
+ };
6476
+ var getLogicalCaret = (value, caret) => {
6477
+ return value.slice(0, caret ?? value.length).replace(/,/g, "").length;
6478
+ };
6479
+ var getDisplayCaret = (value, logicalCaret) => {
6480
+ if (logicalCaret <= 0) return 0;
6481
+ let seen = 0;
6482
+ for (let i = 0; i < value.length; i += 1) {
6483
+ if (value[i] === ",") continue;
6484
+ seen += 1;
6485
+ if (seen >= logicalCaret) return i + 1;
6486
+ }
6487
+ return value.length;
6488
+ };
6368
6489
  var SNumberInput = forwardRef(function SNumberInput2({
6369
6490
  value,
6370
6491
  onValueChange,
@@ -6374,6 +6495,7 @@ var SNumberInput = forwardRef(function SNumberInput2({
6374
6495
  step = 1,
6375
6496
  useButton = false,
6376
6497
  useDecimal = false,
6498
+ maxDecimalLength,
6377
6499
  inputPrefix = "",
6378
6500
  inputSuffix = "",
6379
6501
  inputClass,
@@ -6405,7 +6527,8 @@ var SNumberInput = forwardRef(function SNumberInput2({
6405
6527
  }, ref) {
6406
6528
  const p = PAD2[size];
6407
6529
  const padX = `var(--cmp-numberInput-${size}-paddingX)`;
6408
- const numValue = toNumber(value);
6530
+ const decimalLimit = getDecimalLimit(useDecimal, maxDecimalLength);
6531
+ const numValue = applyDecimalLimit(toNumber(value), decimalLimit);
6409
6532
  const [display, setDisplay] = useState(() => formatWithCommas(numValue));
6410
6533
  const [ruleError, setRuleError] = useState("");
6411
6534
  const innerRef = useRef(null);
@@ -6415,8 +6538,9 @@ var SNumberInput = forwardRef(function SNumberInput2({
6415
6538
  else if (ref) ref.current = el;
6416
6539
  };
6417
6540
  useEffect(() => {
6418
- setDisplay(formatWithCommas(toNumber(value)));
6419
- }, [value]);
6541
+ if (document.activeElement === innerRef.current) return;
6542
+ setDisplay(formatWithCommas(applyDecimalLimit(toNumber(value), decimalLimit)));
6543
+ }, [decimalLimit, value]);
6420
6544
  useFormField({
6421
6545
  name,
6422
6546
  validate: () => {
@@ -6428,48 +6552,87 @@ var SNumberInput = forwardRef(function SNumberInput2({
6428
6552
  });
6429
6553
  const resolvedError = error || ruleError !== "";
6430
6554
  const resolvedStatus = status ?? (rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0);
6431
- const emit2 = (n) => {
6432
- setDisplay(formatWithCommas(n));
6433
- onValueChange?.(n);
6555
+ const restoreCaret = (nextDisplay, logicalCaret) => {
6556
+ const input = innerRef.current;
6557
+ if (logicalCaret === void 0 || !input || document.activeElement !== input) return;
6558
+ const nextCaret = getDisplayCaret(nextDisplay, logicalCaret);
6559
+ requestAnimationFrame(() => {
6560
+ if (document.activeElement !== input) return;
6561
+ input.setSelectionRange(nextCaret, nextCaret);
6562
+ });
6563
+ };
6564
+ const setDisplayWithCaret = (nextDisplay, logicalCaret) => {
6565
+ setDisplay(nextDisplay);
6566
+ restoreCaret(nextDisplay, logicalCaret);
6567
+ };
6568
+ const resetRejectedInput = (target, logicalCaret) => {
6569
+ target.value = display;
6570
+ restoreCaret(display, Math.min(logicalCaret, display.replace(/,/g, "").length));
6571
+ };
6572
+ const emit2 = (n, logicalCaret) => {
6573
+ const next = applyDecimalLimit(n, decimalLimit);
6574
+ const nextDisplay = formatWithCommas(next);
6575
+ setDisplayWithCaret(nextDisplay, logicalCaret);
6576
+ onValueChange?.(next);
6434
6577
  };
6435
6578
  const incDisabled = disabled || readOnly || numValue !== null && numValue >= max;
6436
6579
  const decDisabled = disabled || readOnly || numValue !== null && numValue <= min;
6437
6580
  const increment = () => {
6438
6581
  if (incDisabled) return;
6439
6582
  const cur = numValue ?? (min === Number.NEGATIVE_INFINITY ? 0 : min);
6440
- const next = Math.min(cur + step, max);
6583
+ const next = applyDecimalLimit(Math.min(cur + step, max), decimalLimit);
6441
6584
  if (next !== cur) emit2(next);
6442
6585
  };
6443
6586
  const decrement = () => {
6444
6587
  if (decDisabled) return;
6445
6588
  const cur = numValue ?? (min === Number.NEGATIVE_INFINITY ? 0 : min);
6446
- const next = Math.max(cur - step, min);
6589
+ const next = applyDecimalLimit(Math.max(cur - step, min), decimalLimit);
6447
6590
  if (next !== cur) emit2(next);
6448
6591
  };
6449
- const handleInput = (raw) => {
6592
+ const handleInput = (event) => {
6593
+ const target = event.currentTarget;
6594
+ const raw = target.value;
6595
+ const logicalCaret = getLogicalCaret(raw, target.selectionStart);
6450
6596
  if (raw === "") {
6451
- setDisplay("");
6597
+ setDisplayWithCaret("", 0);
6452
6598
  onValueChange?.(null);
6453
6599
  return;
6454
6600
  }
6455
6601
  const cleaned = raw.replace(/,/g, "");
6456
6602
  const decimals = (cleaned.match(/\./g) || []).length;
6457
- if (decimals > 1) return;
6603
+ if (decimals > 1) {
6604
+ resetRejectedInput(target, logicalCaret);
6605
+ return;
6606
+ }
6458
6607
  if (cleaned === "-" || cleaned === "." || cleaned === "-.") {
6459
- setDisplay(cleaned);
6608
+ setDisplayWithCaret(cleaned, logicalCaret);
6609
+ return;
6610
+ }
6611
+ if (!useDecimal && cleaned.includes(".")) {
6612
+ resetRejectedInput(target, logicalCaret);
6460
6613
  return;
6461
6614
  }
6462
- if (!useDecimal && cleaned.includes(".")) return;
6615
+ if (decimalLimit !== void 0 && cleaned.includes(".")) {
6616
+ const fraction = cleaned.split(".")[1] ?? "";
6617
+ if (fraction.length > decimalLimit) {
6618
+ resetRejectedInput(target, logicalCaret);
6619
+ return;
6620
+ }
6621
+ }
6463
6622
  if (cleaned.endsWith(".") && decimals === 1) {
6464
6623
  const parsed2 = toNumber(cleaned.slice(0, -1));
6465
6624
  if (parsed2 !== null) {
6466
- setDisplay(formatWithCommas(parsed2) + ".");
6625
+ setDisplayWithCaret(formatInputWithCommas(cleaned), logicalCaret);
6467
6626
  return;
6468
6627
  }
6469
6628
  }
6470
6629
  const parsed = toNumber(cleaned);
6471
- if (parsed === null) return;
6472
- emit2(parsed);
6630
+ if (parsed === null) {
6631
+ resetRejectedInput(target, logicalCaret);
6632
+ return;
6633
+ }
6634
+ setDisplayWithCaret(formatInputWithCommas(cleaned), logicalCaret);
6635
+ onValueChange?.(applyDecimalLimit(parsed, decimalLimit));
6473
6636
  };
6474
6637
  const stepper = (dir) => {
6475
6638
  const off = dir === "inc" ? incDisabled : decDisabled;
@@ -6482,8 +6645,8 @@ var SNumberInput = forwardRef(function SNumberInput2({
6482
6645
  "aria-label": dir === "inc" ? "\uC99D\uAC00" : "\uAC10\uC18C",
6483
6646
  onClick: dir === "inc" ? increment : decrement,
6484
6647
  className: cn(
6485
- "flex flex-shrink-0 items-center justify-center",
6486
- off ? "cursor-not-allowed" : "cursor-pointer"
6648
+ "flex flex-shrink-0 items-center justify-center border border-solid border-transparent transition-colors",
6649
+ off ? "cursor-not-allowed" : "cursor-pointer hover:border-[var(--color-border-accentLight)]"
6487
6650
  ),
6488
6651
  style: {
6489
6652
  width: `var(--cmp-numberInput-stepper-${size}-size)`,
@@ -6532,24 +6695,26 @@ var SNumberInput = forwardRef(function SNumberInput2({
6532
6695
  style: {
6533
6696
  // 원본 sd-number-input: content gap = padding-x 토큰 (gap 토큰 아님)
6534
6697
  gap: `var(--cmp-numberInput-${size}-paddingX)`,
6535
- padding: `0 ${useButton ? padX : `calc(${padX} * 2)`}`
6698
+ padding: `0 ${useButton ? padX : `calc(${padX} * 2)`}`,
6699
+ fontSize: p.fontSize,
6700
+ lineHeight: `${p.lineHeight}px`
6536
6701
  },
6537
6702
  children: [
6538
6703
  useButton && stepper("dec"),
6539
- inputPrefix !== "" && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", style: { fontSize: p.fontSize, color: affixColor }, children: inputPrefix }),
6704
+ inputPrefix !== "" && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", style: { color: affixColor }, children: inputPrefix }),
6540
6705
  /* @__PURE__ */ jsx(
6541
6706
  "input",
6542
6707
  {
6543
6708
  ref: setRefs,
6544
6709
  name,
6545
6710
  type: "text",
6546
- inputMode: "numeric",
6711
+ inputMode: useDecimal ? "decimal" : "numeric",
6547
6712
  value: display,
6548
6713
  placeholder,
6549
6714
  disabled,
6550
6715
  readOnly,
6551
6716
  autoFocus,
6552
- onChange: (e) => handleInput(e.target.value),
6717
+ onChange: handleInput,
6553
6718
  onKeyDown: (e) => {
6554
6719
  if (e.key === "ArrowUp") {
6555
6720
  e.preventDefault();
@@ -6561,26 +6726,29 @@ var SNumberInput = forwardRef(function SNumberInput2({
6561
6726
  },
6562
6727
  onFocus: (e) => onFocus?.(e),
6563
6728
  onBlur: (e) => {
6564
- const n = toNumber(display);
6729
+ const cleaned = display.replace(/,/g, "");
6730
+ const n = toNumber(cleaned);
6565
6731
  const clamped = n === null ? null : Math.min(Math.max(n, min), max);
6566
6732
  if (clamped !== n) emit2(clamped);
6567
- else setDisplay(formatWithCommas(n));
6733
+ else setDisplay(n === null ? "" : formatInputWithCommas(cleaned));
6568
6734
  if (rules && rules.length > 0) setRuleError(runRules(clamped, rules));
6569
6735
  onBlur?.(e);
6570
6736
  },
6571
6737
  className: cn(
6572
- "h-full min-w-0 flex-1 border-0 bg-transparent p-0 outline-none placeholder:text-[color:var(--cmp-numberInput-text-placeholder)] disabled:cursor-not-allowed",
6738
+ // h-full 대신 라인박스 높이 그대로 두어 prefix/suffix 동일하게 flex 로 수직 센터링
6739
+ // (h-full 이면 input 내부 텍스트 센터링을 브라우저가 수행해 1px 어긋날 수 있음)
6740
+ "min-w-0 flex-1 border-0 bg-transparent p-0 outline-none placeholder:text-[color:var(--cmp-numberInput-text-placeholder)] disabled:cursor-not-allowed",
6573
6741
  inputClass
6574
6742
  ),
6575
6743
  style: {
6576
- fontSize: p.fontSize,
6744
+ // fontSize/lineHeight 는 컨테이너에서 상속
6577
6745
  textAlign: useButton ? "center" : "right",
6578
6746
  color: disabled ? "var(--cmp-numberInput-text-disabled)" : "var(--cmp-numberInput-text-default)",
6579
6747
  ...inputStyle
6580
6748
  }
6581
6749
  }
6582
6750
  ),
6583
- inputSuffix !== "" && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", style: { fontSize: p.fontSize, color: affixColor }, children: inputSuffix }),
6751
+ inputSuffix !== "" && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", style: { color: affixColor }, children: inputSuffix }),
6584
6752
  useButton && stepper("inc")
6585
6753
  ]
6586
6754
  }
@@ -6906,7 +7074,7 @@ function SCalendar({
6906
7074
  "span",
6907
7075
  {
6908
7076
  className: cn(
6909
- "flex h-[var(--cmp-datepicker-calendar-day-circle-size)] w-[var(--cmp-datepicker-calendar-day-circle-size)] items-center justify-center rounded-[var(--cmp-datepicker-calendar-day-circle-radius)] border border-solid border-transparent text-[14px]",
7077
+ "flex h-[var(--cmp-datepicker-calendar-day-circle-size)] w-[var(--cmp-datepicker-calendar-day-circle-size)] items-center justify-center rounded-[var(--cmp-datepicker-calendar-day-circle-radius)] border border-solid border-transparent text-[14px] leading-[var(--cmp-datepicker-calendar-day-circle-size)]",
6910
7078
  selected ? "bg-[var(--cmp-datepicker-calendar-day-select-bg)] text-[color:var(--cmp-datepicker-calendar-day-select-text)]" : disabled ? "text-[color:var(--cmp-datepicker-calendar-day-disabled-text)]" : "text-[color:var(--cmp-datepicker-calendar-day-default-text)] hover:border-[color:var(--cmp-datepicker-calendar-day-hover-border)]",
6911
7079
  isToday && !disabled && "font-bold"
6912
7080
  ),
@@ -7068,16 +7236,25 @@ function SDatePicker({
7068
7236
  ]
7069
7237
  }
7070
7238
  ) }),
7071
- /* @__PURE__ */ jsx(RPopover2.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(RPopover2.Content, { side: "bottom", align: "start", sideOffset: 4, className: "z-50", children: /* @__PURE__ */ jsx(
7072
- SCalendar,
7239
+ /* @__PURE__ */ jsx(RPopover2.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
7240
+ RPopover2.Content,
7073
7241
  {
7074
- value: value ?? void 0,
7075
- selectable,
7076
- elevated: true,
7077
- onValueChange: select,
7078
- onViewChange
7242
+ side: "bottom",
7243
+ align: "start",
7244
+ sideOffset: 4,
7245
+ className: cn("z-50", FLOATING_SLIDE_ANIM),
7246
+ children: /* @__PURE__ */ jsx(
7247
+ SCalendar,
7248
+ {
7249
+ value: value ?? void 0,
7250
+ selectable,
7251
+ elevated: true,
7252
+ onValueChange: select,
7253
+ onViewChange
7254
+ }
7255
+ )
7079
7256
  }
7080
- ) }) })
7257
+ ) })
7081
7258
  ] })
7082
7259
  }
7083
7260
  );
@@ -7087,6 +7264,7 @@ function RangeCalendar({
7087
7264
  selectable,
7088
7265
  maxRange,
7089
7266
  onSelect,
7267
+ onPendingStartChange,
7090
7268
  onViewChange
7091
7269
  }) {
7092
7270
  const today = todayStr();
@@ -7149,9 +7327,11 @@ function RangeCalendar({
7149
7327
  setStart(d);
7150
7328
  setEnd(null);
7151
7329
  setHover(null);
7330
+ onPendingStartChange?.(d);
7152
7331
  return;
7153
7332
  }
7154
7333
  setEnd(d);
7334
+ onPendingStartChange?.(null);
7155
7335
  onSelect([start, d]);
7156
7336
  };
7157
7337
  const GRID_COLS = "grid grid-cols-[repeat(7,var(--cmp-datepicker-calendar-day-width))]";
@@ -7286,8 +7466,11 @@ function SDateRangePicker({
7286
7466
  const portalContainer = usePortalContainer();
7287
7467
  const [open, setOpen] = useState(false);
7288
7468
  const [ruleError, setRuleError] = useState("");
7469
+ const [pendingStart, setPendingStart] = useState(null);
7289
7470
  const hasValue = value != null && value[0] !== "" && value[1] !== "";
7290
- const display = hasValue ? `${value[0]} ~ ${value[1]}` : placeholder;
7471
+ const hasDisplay = pendingStart != null || hasValue;
7472
+ const startText = pendingStart ?? (hasValue ? value[0] : "");
7473
+ const endText = pendingStart ? "" : hasValue ? value[1] : "";
7291
7474
  useFormField({
7292
7475
  name,
7293
7476
  validate: () => {
@@ -7301,6 +7484,7 @@ function SDateRangePicker({
7301
7484
  const resolvedStatus = status ?? (rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0);
7302
7485
  const dims = size === "md" ? { padX: 16, gap: 12, icon: 20, minW: 104, fontSize: 14, lineHeight: 24, radius: 6 } : { padX: 12, gap: 8, icon: 16, minW: 80, fontSize: 12, lineHeight: 20, radius: 4 };
7303
7486
  const select = (r) => {
7487
+ setPendingStart(null);
7304
7488
  onValueChange?.(r);
7305
7489
  if (rules && rules.length > 0) setRuleError(runRules(r, rules));
7306
7490
  setOpen(false);
@@ -7325,52 +7509,80 @@ function SDateRangePicker({
7325
7509
  disabled,
7326
7510
  className,
7327
7511
  style,
7328
- children: /* @__PURE__ */ jsxs(RPopover2.Root, { open, onOpenChange: (o) => !disabled && setOpen(o), children: [
7329
- /* @__PURE__ */ jsx(RPopover2.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
7330
- "button",
7331
- {
7332
- type: "button",
7333
- name,
7334
- disabled,
7335
- className: "flex h-full w-full items-center overflow-hidden bg-transparent outline-none disabled:cursor-not-allowed",
7336
- style: { padding: `0 ${dims.padX}px`, gap: dims.gap, borderRadius: dims.radius },
7337
- children: [
7338
- /* @__PURE__ */ jsx(
7339
- SIcon,
7340
- {
7341
- name: "date",
7342
- size: dims.icon,
7343
- color: disabled ? "var(--cmp-datepicker-icon-disabled)" : "var(--cmp-datepicker-icon-default)",
7344
- className: "flex-shrink-0"
7345
- }
7346
- ),
7347
- /* @__PURE__ */ jsx(
7348
- "span",
7349
- {
7350
- className: "flex-1 truncate text-center",
7351
- style: {
7352
- minWidth: dims.minW,
7353
- fontSize: dims.fontSize,
7354
- lineHeight: `${dims.lineHeight}px`,
7355
- color: disabled ? "var(--cmp-datepicker-text-disabled)" : hasValue ? "var(--cmp-datepicker-text-default)" : "var(--cmp-field-hint-color)"
7356
- },
7357
- children: display
7358
- }
7359
- )
7360
- ]
7361
- }
7362
- ) }),
7363
- /* @__PURE__ */ jsx(RPopover2.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(RPopover2.Content, { side: "bottom", align: "start", sideOffset: 4, className: "z-50", children: /* @__PURE__ */ jsx(
7364
- RangeCalendar,
7365
- {
7366
- value: value ?? null,
7367
- selectable,
7368
- maxRange,
7369
- onSelect: select,
7370
- onViewChange
7371
- }
7372
- ) }) })
7373
- ] })
7512
+ children: /* @__PURE__ */ jsxs(
7513
+ RPopover2.Root,
7514
+ {
7515
+ open,
7516
+ onOpenChange: (o) => {
7517
+ if (disabled) return;
7518
+ setOpen(o);
7519
+ if (!o) setPendingStart(null);
7520
+ },
7521
+ children: [
7522
+ /* @__PURE__ */ jsx(RPopover2.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
7523
+ "button",
7524
+ {
7525
+ type: "button",
7526
+ name,
7527
+ disabled,
7528
+ className: "flex h-full w-full items-center overflow-hidden bg-transparent outline-none disabled:cursor-not-allowed",
7529
+ style: { padding: `0 ${dims.padX}px`, gap: dims.gap, borderRadius: dims.radius },
7530
+ children: [
7531
+ /* @__PURE__ */ jsx(
7532
+ SIcon,
7533
+ {
7534
+ name: "date",
7535
+ size: dims.icon,
7536
+ color: disabled ? "var(--cmp-datepicker-icon-disabled)" : "var(--cmp-datepicker-icon-default)",
7537
+ className: "flex-shrink-0"
7538
+ }
7539
+ ),
7540
+ /* @__PURE__ */ jsx(
7541
+ "span",
7542
+ {
7543
+ className: cn(
7544
+ "flex-1 items-center",
7545
+ hasDisplay ? "flex" : "block truncate text-center"
7546
+ ),
7547
+ style: {
7548
+ minWidth: dims.minW,
7549
+ fontSize: dims.fontSize,
7550
+ lineHeight: `${dims.lineHeight}px`,
7551
+ color: disabled ? "var(--cmp-datepicker-text-disabled)" : hasDisplay ? "var(--cmp-datepicker-text-default)" : "var(--cmp-field-hint-color)"
7552
+ },
7553
+ children: hasDisplay ? /* @__PURE__ */ jsxs(Fragment, { children: [
7554
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-right", children: startText }),
7555
+ /* @__PURE__ */ jsx("span", { className: "px-[4px]", children: "~" }),
7556
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-left", children: endText })
7557
+ ] }) : placeholder
7558
+ }
7559
+ )
7560
+ ]
7561
+ }
7562
+ ) }),
7563
+ /* @__PURE__ */ jsx(RPopover2.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
7564
+ RPopover2.Content,
7565
+ {
7566
+ side: "bottom",
7567
+ align: "start",
7568
+ sideOffset: 4,
7569
+ className: cn("z-50", FLOATING_SLIDE_ANIM),
7570
+ children: /* @__PURE__ */ jsx(
7571
+ RangeCalendar,
7572
+ {
7573
+ value: value ?? null,
7574
+ selectable,
7575
+ maxRange,
7576
+ onSelect: select,
7577
+ onPendingStartChange: setPendingStart,
7578
+ onViewChange
7579
+ }
7580
+ )
7581
+ }
7582
+ ) })
7583
+ ]
7584
+ }
7585
+ )
7374
7586
  }
7375
7587
  );
7376
7588
  }
@@ -7379,7 +7591,7 @@ var SChip = forwardRef(function SChip2({
7379
7591
  value = "",
7380
7592
  error: errorProp = false,
7381
7593
  disabled = false,
7382
- editable = true,
7594
+ editable = false,
7383
7595
  showRemove = true,
7384
7596
  placeholder = "",
7385
7597
  rules,
@@ -7532,6 +7744,7 @@ function SFilePicker({
7532
7744
  hovered = false,
7533
7745
  inline = false,
7534
7746
  multiple = false,
7747
+ useMultipleListBox = false,
7535
7748
  accept,
7536
7749
  maxFileSize,
7537
7750
  maxTotalSize,
@@ -7559,8 +7772,8 @@ function SFilePicker({
7559
7772
  const inputRef = useRef(null);
7560
7773
  const [ruleError, setRuleError] = useState("");
7561
7774
  const files = multiple ? Array.isArray(value) ? value : [] : value && !Array.isArray(value) ? value : null;
7562
- const hasSingle = !multiple && !!files;
7563
- const displayText = hasSingle ? files.name : placeholder;
7775
+ const hasFiles = multiple ? files.length > 0 : !!files;
7776
+ const displayText = !hasFiles ? placeholder : multiple ? files.map((f) => f.name).join(", ") : files.name;
7564
7777
  useFormField({
7565
7778
  name,
7566
7779
  validate: () => {
@@ -7624,78 +7837,88 @@ function SFilePicker({
7624
7837
  const padX = size === "md" ? "var(--cmp-filepicker-md-paddingX)" : "var(--cmp-filepicker-sm-paddingX)";
7625
7838
  const iconSize = size === "md" ? 20 : 16;
7626
7839
  const gapCls = size === "md" ? "gap-[var(--cmp-filepicker-md-gap)]" : "gap-[var(--cmp-filepicker-sm-gap)]";
7627
- const content = /* @__PURE__ */ jsxs("div", { className: cn("flex h-full w-full items-center", gapCls), style: { padding: `0 ${padX}` }, children: [
7628
- /* @__PURE__ */ jsx(
7629
- "input",
7630
- {
7631
- ref: inputRef,
7632
- type: "file",
7633
- className: "hidden",
7634
- disabled,
7635
- multiple,
7636
- accept,
7637
- name: resolvedName,
7638
- onChange,
7639
- "aria-label": placeholder
7640
- }
7641
- ),
7642
- /* @__PURE__ */ jsxs(
7643
- "button",
7644
- {
7645
- type: "button",
7646
- disabled,
7647
- onClick: open,
7648
- "aria-label": placeholder,
7649
- className: cn(
7650
- "flex min-w-0 flex-1 items-center bg-transparent text-left",
7651
- gapCls,
7652
- disabled ? "cursor-not-allowed" : "cursor-pointer"
7840
+ const inlinePlaceholder = inline && !disabled && !hasFiles;
7841
+ const content = /* @__PURE__ */ jsxs(
7842
+ "div",
7843
+ {
7844
+ className: cn("group/filepicker flex h-full w-full items-center", gapCls),
7845
+ style: { padding: inline ? 0 : `0 ${padX}` },
7846
+ children: [
7847
+ /* @__PURE__ */ jsx(
7848
+ "input",
7849
+ {
7850
+ ref: inputRef,
7851
+ type: "file",
7852
+ className: "hidden",
7853
+ disabled,
7854
+ multiple,
7855
+ accept,
7856
+ name: resolvedName,
7857
+ onChange,
7858
+ "aria-label": placeholder
7859
+ }
7653
7860
  ),
7654
- children: [
7655
- /* @__PURE__ */ jsx(
7656
- SIcon,
7657
- {
7658
- name: "attachFile",
7659
- size: iconSize,
7660
- color: disabled ? "var(--cmp-filepicker-icon-disabled)" : "var(--color-grey-65)"
7661
- }
7662
- ),
7663
- /* @__PURE__ */ jsx(
7664
- "span",
7665
- {
7666
- className: "min-w-0 flex-1 truncate text-[12px]",
7667
- style: {
7668
- color: disabled ? "var(--cmp-filepicker-text-disabled)" : hasSingle ? "var(--cmp-filepicker-text-default)" : "var(--cmp-filepicker-text-placeholder)"
7669
- },
7670
- children: displayText
7671
- }
7672
- )
7673
- ]
7674
- }
7675
- ),
7676
- !disabled && hasSingle && /* @__PURE__ */ jsx(SGhostButton, { icon: "close", size: "xxs", ariaLabel: "clear", onClick: clear })
7677
- ] });
7678
- const chips = multiple && files.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-[8px] flex flex-wrap gap-[8px]", children: files.map((f, i) => /* @__PURE__ */ jsx(SChip, { value: f.name, editable: false, onRemove: () => removeChip(i) }, i)) });
7679
- if (inline) {
7680
- return /* @__PURE__ */ jsxs("div", { className: cn("inline-flex flex-col", className), style, children: [
7681
- /* @__PURE__ */ jsx(
7682
- "div",
7683
- {
7684
- className: "box-border flex items-center rounded-[var(--cmp-filepicker-sm-radius)] border border-solid border-[color:var(--cmp-filepicker-border-default)] bg-[var(--cmp-filepicker-bg-default)]",
7685
- style: {
7686
- height: "var(--cmp-filepicker-sm-height)",
7687
- width: typeof width === "number" ? `${width}px` : width
7688
- },
7689
- children: content
7690
- }
7861
+ /* @__PURE__ */ jsxs(
7862
+ "button",
7863
+ {
7864
+ type: "button",
7865
+ disabled,
7866
+ onClick: open,
7867
+ "aria-label": placeholder,
7868
+ className: cn(
7869
+ "flex min-w-0 flex-1 items-center bg-transparent text-left",
7870
+ gapCls,
7871
+ disabled ? "cursor-not-allowed" : "cursor-pointer"
7872
+ ),
7873
+ children: [
7874
+ /* @__PURE__ */ jsx(
7875
+ SIcon,
7876
+ {
7877
+ name: "attachFile",
7878
+ size: iconSize,
7879
+ color: disabled ? "var(--cmp-filepicker-icon-disabled)" : "var(--color-grey-65)"
7880
+ }
7881
+ ),
7882
+ /* @__PURE__ */ jsx(
7883
+ "span",
7884
+ {
7885
+ className: cn(
7886
+ "min-w-0 flex-1 truncate text-[12px]",
7887
+ inlinePlaceholder && "text-[color:var(--cmp-filepicker-text-placeholder)] transition-colors group-hover/filepicker:text-[color:var(--cmp-filepicker-text-default)]"
7888
+ ),
7889
+ style: inlinePlaceholder ? void 0 : {
7890
+ color: disabled ? "var(--cmp-filepicker-text-disabled)" : hasFiles ? "var(--cmp-filepicker-text-default)" : "var(--cmp-filepicker-text-placeholder)"
7891
+ },
7892
+ children: displayText
7893
+ }
7894
+ )
7895
+ ]
7896
+ }
7897
+ ),
7898
+ !disabled && hasFiles && /* @__PURE__ */ jsx(SGhostButton, { icon: "close", size: "xxs", ariaLabel: "clear", onClick: clear })
7899
+ ]
7900
+ }
7901
+ );
7902
+ const chips = multiple && files.length > 0 && /* @__PURE__ */ jsx(
7903
+ "div",
7904
+ {
7905
+ className: cn(
7906
+ "mt-[8px] flex gap-[8px]",
7907
+ 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"
7691
7908
  ),
7692
- chips
7693
- ] });
7694
- }
7909
+ style: useMultipleListBox ? {
7910
+ width: typeof width === "number" ? `${width}px` : width,
7911
+ // label 이 있으면 SField 입력 박스 시작 위치(labelWidth + fieldGap)에 맞춰 정렬
7912
+ marginLeft: label && labelWidth != null ? `calc(${typeof labelWidth === "number" ? `${labelWidth}px` : labelWidth} + var(--sys-space-field-${size}-gap))` : void 0
7913
+ } : void 0,
7914
+ children: files.map((f, i) => /* @__PURE__ */ jsx(SChip, { value: f.name, editable: false, onRemove: () => removeChip(i) }, i))
7915
+ }
7916
+ );
7695
7917
  return /* @__PURE__ */ jsxs("div", { className, style, children: [
7696
7918
  /* @__PURE__ */ jsx(
7697
7919
  SField,
7698
7920
  {
7921
+ borderless: inline,
7699
7922
  label,
7700
7923
  labelWidth,
7701
7924
  icon,
@@ -7723,6 +7946,7 @@ function SKeyValueTable({
7723
7946
  fields = [],
7724
7947
  search = false,
7725
7948
  radius = "default",
7949
+ dense = false,
7726
7950
  onChange,
7727
7951
  onSearch,
7728
7952
  className,
@@ -7730,6 +7954,8 @@ function SKeyValueTable({
7730
7954
  }) {
7731
7955
  if (fields.length === 0) return null;
7732
7956
  const emit2 = (name, value) => onChange?.({ name, value });
7957
+ const cellHeight = dense ? "var(--cmp-table-body-dense-height)" : "var(--cmp-table-keyValue-height)";
7958
+ const cellPadY = dense ? "var(--cmp-table-body-dense-paddingY)" : "var(--cmp-table-keyValue-body-paddingY)";
7733
7959
  const renderField = (f) => {
7734
7960
  if (f.render) return f.render;
7735
7961
  const opt = f.options ?? {};
@@ -7810,10 +8036,15 @@ function SKeyValueTable({
7810
8036
  rowSpan: f.thRowSpan && f.thRowSpan > 1 ? f.thRowSpan : void 0,
7811
8037
  colSpan: f.thColSpan && f.thColSpan > 1 ? f.thColSpan : void 0,
7812
8038
  className: cn(
7813
- "h-[var(--cmp-table-keyValue-height)] box-border bg-[var(--cmp-table-header-bg)] px-[var(--cmp-table-header-paddingX)] py-[var(--cmp-table-keyValue-body-padding)] text-left align-middle",
8039
+ "box-border bg-[var(--cmp-table-header-bg)] px-[var(--cmp-table-header-paddingX)] text-left align-middle",
7814
8040
  cellBorder,
7815
8041
  f.thClass
7816
8042
  ),
8043
+ style: {
8044
+ height: cellHeight,
8045
+ paddingTop: cellPadY,
8046
+ paddingBottom: cellPadY
8047
+ },
7817
8048
  children: /* @__PURE__ */ jsxs("div", { className: "flex h-full w-full items-center justify-between gap-[var(--cmp-table-header-gap)]", children: [
7818
8049
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-[8px]", children: [
7819
8050
  /* @__PURE__ */ jsx("span", { className: "text-[12px] font-bold leading-[20px] text-[color:var(--sys-color-fg-primary)]", children: f.label }),
@@ -7839,10 +8070,11 @@ function SKeyValueTable({
7839
8070
  rowSpan: f.tdRowSpan && f.tdRowSpan > 1 ? f.tdRowSpan : void 0,
7840
8071
  colSpan: f.tdColSpan && f.tdColSpan > 1 ? f.tdColSpan : void 0,
7841
8072
  className: cn(
7842
- "h-[var(--cmp-table-keyValue-height)] box-border bg-[var(--sys-color-bg-frame)] p-[var(--cmp-table-keyValue-body-padding)] align-middle",
8073
+ "box-border bg-[var(--sys-color-bg-frame)] px-[var(--cmp-table-keyValue-body-paddingX-default)] align-middle",
7843
8074
  cellBorder,
7844
8075
  f.tdClass
7845
8076
  ),
8077
+ style: { height: cellHeight, paddingTop: cellPadY, paddingBottom: cellPadY },
7846
8078
  children: renderField(f)
7847
8079
  },
7848
8080
  `td-${r}-${c}`
@@ -7963,9 +8195,9 @@ var POS_ANCHOR = {
7963
8195
  "top-left": { top: 20, left: 20 },
7964
8196
  "top-center": { top: 20, left: "50%" },
7965
8197
  "top-right": { top: 20, right: 20 },
7966
- "bottom-left": { bottom: 20, left: 20 },
7967
- "bottom-center": { bottom: 20, left: "50%" },
7968
- "bottom-right": { bottom: 20, right: 20 }
8198
+ "bottom-left": { bottom: 100, left: 20 },
8199
+ "bottom-center": { bottom: 100, left: "50%" },
8200
+ "bottom-right": { bottom: 100, right: 20 }
7969
8201
  };
7970
8202
  var counter = 0;
7971
8203
  var SToastContainer = forwardRef(
@@ -8325,7 +8557,7 @@ var SChipInput = forwardRef(function SChipInput2({
8325
8557
  disabledChips = [],
8326
8558
  size = "sm",
8327
8559
  disabled = false,
8328
- placeholder = "\uC785\uB825\uD574 \uC8FC\uC138\uC694.",
8560
+ placeholder = "\uD0DC\uADF8 \uC785\uB825 (Enter\uB85C \uB4F1\uB85D / \uCF64\uB9C8\uB85C \uAD6C\uBD84 / \uB744\uC5B4\uC4F0\uAE30 \uBD88\uAC00)",
8329
8561
  name,
8330
8562
  rules,
8331
8563
  error,
@@ -8476,6 +8708,7 @@ var SChipInput = forwardRef(function SChipInput2({
8476
8708
  {
8477
8709
  label,
8478
8710
  labelWidth,
8711
+ labelHeight: `calc(var(--cmp-chipInput-${size}-minHeight) + 2px)`,
8479
8712
  icon,
8480
8713
  labelTooltip,
8481
8714
  labelTooltipProps,
@@ -8546,9 +8779,11 @@ var SChipInput = forwardRef(function SChipInput2({
8546
8779
  paddingInline: isFieldFilled ? "var(--cmp-chip-paddingX)" : void 0,
8547
8780
  borderWidth: isFieldFilled ? "var(--cmp-chip-border-width)" : void 0,
8548
8781
  borderStyle: isFieldFilled ? "solid" : void 0,
8549
- borderColor: isFieldFilled ? "transparent" : void 0,
8782
+ // 작성중 필드는 SChip의 editable 수정중(editing) 스타일과 동일하게 —
8783
+ // bg/보더/글자색 모두 focus 토큰을 사용한다.
8784
+ borderColor: isFieldFilled ? "var(--cmp-chip-border-focus)" : void 0,
8550
8785
  borderRadius: isFieldFilled ? "var(--cmp-chip-radius)" : 0,
8551
- background: isFieldFilled ? "var(--cmp-chip-bg-default)" : "transparent",
8786
+ background: isFieldFilled ? "var(--cmp-chip-bg-focus)" : "transparent",
8552
8787
  overflow: "hidden"
8553
8788
  },
8554
8789
  children: [
@@ -8557,7 +8792,7 @@ var SChipInput = forwardRef(function SChipInput2({
8557
8792
  {
8558
8793
  "aria-hidden": true,
8559
8794
  className: cn(
8560
- "invisible col-start-1 row-start-1 whitespace-pre font-medium",
8795
+ "invisible col-start-1 row-start-1 whitespace-pre font-normal",
8561
8796
  size === "md" ? "text-14 leading-24" : "text-12 leading-20"
8562
8797
  ),
8563
8798
  children: inputValue !== "" ? inputValue : values.length === 0 ? placeholder : ""
@@ -8570,12 +8805,14 @@ var SChipInput = forwardRef(function SChipInput2({
8570
8805
  name: resolvedName,
8571
8806
  size: 1,
8572
8807
  className: cn(
8573
- "s-chip-input__input col-start-1 row-start-1 w-full border-0 bg-transparent p-0 font-medium text-(--cmp-chip-content-focus) outline-none placeholder:text-(--cmp-chipInput-text-placeholder) disabled:cursor-not-allowed",
8808
+ "s-chip-input__input col-start-1 row-start-1 w-full border-0 bg-transparent p-0 font-normal text-(--cmp-chip-content-focus) outline-none placeholder:text-(--cmp-chipInput-text-placeholder) disabled:cursor-not-allowed",
8574
8809
  size === "md" ? "text-14 leading-24" : "text-12 leading-20"
8575
8810
  ),
8576
8811
  style: {
8577
8812
  minWidth: "1ch",
8578
- height: "var(--cmp-chip-height)",
8813
+ // height 지정하지 않고 line-height(20/24px)에 맞춰 자동 크기로 둔다.
8814
+ // var(--cmp-chip-height)(24px)로 고정하면 네이티브 <input>이 남는 세로 여백에
8815
+ // 텍스트를 아래로 밀어 넣어, 확정된 chip 텍스트보다 2px 낮게 보인다.
8579
8816
  margin: 0,
8580
8817
  overflow: "hidden",
8581
8818
  textOverflow: "ellipsis"
@@ -8620,7 +8857,7 @@ var SChipInput = forwardRef(function SChipInput2({
8620
8857
  showMetaInfo && /* @__PURE__ */ jsxs(
8621
8858
  "div",
8622
8859
  {
8623
- className: "s-chip-input__meta flex items-center gap-8",
8860
+ className: "s-chip-input__meta ml-auto flex items-center gap-8",
8624
8861
  onMouseDown: (e) => e.preventDefault(),
8625
8862
  children: [
8626
8863
  /* @__PURE__ */ jsx(
@@ -8630,17 +8867,11 @@ var SChipInput = forwardRef(function SChipInput2({
8630
8867
  style: { width: 1, height: 12, backgroundColor: "#E1E1E1" }
8631
8868
  }
8632
8869
  ),
8633
- showMaxCount && /* @__PURE__ */ jsxs(
8634
- "span",
8635
- {
8636
- className: "s-chip-input__max-count text-12 text-(--cmp-chipInput-text-placeholder)",
8637
- children: [
8638
- "\uCD5C\uB300 ",
8639
- maxCount,
8640
- "\uAC1C"
8641
- ]
8642
- }
8643
- ),
8870
+ showMaxCount && /* @__PURE__ */ jsxs("span", { className: "s-chip-input__max-count text-12 text-(--cmp-chipInput-text-placeholder)", children: [
8871
+ "\uCD5C\uB300 ",
8872
+ maxCount,
8873
+ "\uAC1C"
8874
+ ] }),
8644
8875
  showResetLink && /* @__PURE__ */ jsx(
8645
8876
  STextLink,
8646
8877
  {