sellmate-design-system-react 0.1.8 → 0.1.10

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 (110) hide show
  1. package/dist/components/SActionModal/SActionModal.cjs +1 -1
  2. package/dist/components/SActionModal/SActionModal.cjs.map +1 -1
  3. package/dist/components/SActionModal/SActionModal.js +1 -1
  4. package/dist/components/SActionModal/SActionModal.js.map +1 -1
  5. package/dist/components/SBarcodeInput/SBarcodeInput.cjs +217 -208
  6. package/dist/components/SBarcodeInput/SBarcodeInput.cjs.map +1 -1
  7. package/dist/components/SBarcodeInput/SBarcodeInput.js +217 -208
  8. package/dist/components/SBarcodeInput/SBarcodeInput.js.map +1 -1
  9. package/dist/components/SCalendar/SCalendar.cjs +1 -1
  10. package/dist/components/SCalendar/SCalendar.cjs.map +1 -1
  11. package/dist/components/SCalendar/SCalendar.js +1 -1
  12. package/dist/components/SCalendar/SCalendar.js.map +1 -1
  13. package/dist/components/SChip/SChip.cjs +1 -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 +1 -1
  17. package/dist/components/SChip/SChip.js.map +1 -1
  18. package/dist/components/SChipInput/SChipInput.cjs +234 -220
  19. package/dist/components/SChipInput/SChipInput.cjs.map +1 -1
  20. package/dist/components/SChipInput/SChipInput.js +234 -220
  21. package/dist/components/SChipInput/SChipInput.js.map +1 -1
  22. package/dist/components/SCircleProgress/SCircleProgress.cjs +31 -14
  23. package/dist/components/SCircleProgress/SCircleProgress.cjs.map +1 -1
  24. package/dist/components/SCircleProgress/SCircleProgress.d.ts +2 -0
  25. package/dist/components/SCircleProgress/SCircleProgress.js +31 -14
  26. package/dist/components/SCircleProgress/SCircleProgress.js.map +1 -1
  27. package/dist/components/SDatePicker/SDatePicker.cjs +222 -213
  28. package/dist/components/SDatePicker/SDatePicker.cjs.map +1 -1
  29. package/dist/components/SDatePicker/SDatePicker.js +222 -213
  30. package/dist/components/SDatePicker/SDatePicker.js.map +1 -1
  31. package/dist/components/SDateRangePicker/SDateRangePicker.cjs +297 -262
  32. package/dist/components/SDateRangePicker/SDateRangePicker.cjs.map +1 -1
  33. package/dist/components/SDateRangePicker/SDateRangePicker.js +297 -262
  34. package/dist/components/SDateRangePicker/SDateRangePicker.js.map +1 -1
  35. package/dist/components/SDropdownButton/SDropdownButton.cjs +4 -4
  36. package/dist/components/SDropdownButton/SDropdownButton.cjs.map +1 -1
  37. package/dist/components/SDropdownButton/SDropdownButton.js +4 -4
  38. package/dist/components/SDropdownButton/SDropdownButton.js.map +1 -1
  39. package/dist/components/SField/SField.cjs +217 -20
  40. package/dist/components/SField/SField.cjs.map +1 -1
  41. package/dist/components/SField/SField.d.ts +11 -0
  42. package/dist/components/SField/SField.js +217 -20
  43. package/dist/components/SField/SField.js.map +1 -1
  44. package/dist/components/SFilePicker/SFilePicker.cjs +315 -276
  45. package/dist/components/SFilePicker/SFilePicker.cjs.map +1 -1
  46. package/dist/components/SFilePicker/SFilePicker.d.ts +4 -2
  47. package/dist/components/SFilePicker/SFilePicker.js +314 -276
  48. package/dist/components/SFilePicker/SFilePicker.js.map +1 -1
  49. package/dist/components/SInput/SInput.cjs +217 -208
  50. package/dist/components/SInput/SInput.cjs.map +1 -1
  51. package/dist/components/SInput/SInput.js +217 -208
  52. package/dist/components/SInput/SInput.js.map +1 -1
  53. package/dist/components/SKeyValueTable/SKeyValueTable.cjs +631 -450
  54. package/dist/components/SKeyValueTable/SKeyValueTable.cjs.map +1 -1
  55. package/dist/components/SKeyValueTable/SKeyValueTable.d.ts +3 -1
  56. package/dist/components/SKeyValueTable/SKeyValueTable.js +631 -450
  57. package/dist/components/SKeyValueTable/SKeyValueTable.js.map +1 -1
  58. package/dist/components/SLoadingContainer/SLoadingContainer.cjs +39 -14
  59. package/dist/components/SLoadingContainer/SLoadingContainer.cjs.map +1 -1
  60. package/dist/components/SLoadingContainer/SLoadingContainer.js +39 -14
  61. package/dist/components/SLoadingContainer/SLoadingContainer.js.map +1 -1
  62. package/dist/components/SLoadingContainer/loading.cjs +39 -14
  63. package/dist/components/SLoadingContainer/loading.cjs.map +1 -1
  64. package/dist/components/SLoadingContainer/loading.js +39 -14
  65. package/dist/components/SLoadingContainer/loading.js.map +1 -1
  66. package/dist/components/SLoadingModal/SLoadingModal.cjs +37 -16
  67. package/dist/components/SLoadingModal/SLoadingModal.cjs.map +1 -1
  68. package/dist/components/SLoadingModal/SLoadingModal.d.ts +3 -1
  69. package/dist/components/SLoadingModal/SLoadingModal.js +37 -16
  70. package/dist/components/SLoadingModal/SLoadingModal.js.map +1 -1
  71. package/dist/components/SNumberInput/SNumberInput.cjs +325 -49
  72. package/dist/components/SNumberInput/SNumberInput.cjs.map +1 -1
  73. package/dist/components/SNumberInput/SNumberInput.d.ts +2 -0
  74. package/dist/components/SNumberInput/SNumberInput.js +325 -49
  75. package/dist/components/SNumberInput/SNumberInput.js.map +1 -1
  76. package/dist/components/SPagination/SPagination.cjs +1 -1
  77. package/dist/components/SPagination/SPagination.cjs.map +1 -1
  78. package/dist/components/SPagination/SPagination.js +1 -1
  79. package/dist/components/SPagination/SPagination.js.map +1 -1
  80. package/dist/components/SRadio/SRadioGroup.cjs +1 -1
  81. package/dist/components/SRadio/SRadioGroup.cjs.map +1 -1
  82. package/dist/components/SRadio/SRadioGroup.js +1 -1
  83. package/dist/components/SRadio/SRadioGroup.js.map +1 -1
  84. package/dist/components/SSelect/SSelect.cjs +71 -32
  85. package/dist/components/SSelect/SSelect.cjs.map +1 -1
  86. package/dist/components/SSelect/SSelect.js +71 -32
  87. package/dist/components/SSelect/SSelect.js.map +1 -1
  88. package/dist/components/STable/STable.cjs +108 -49
  89. package/dist/components/STable/STable.cjs.map +1 -1
  90. package/dist/components/STable/STable.js +108 -49
  91. package/dist/components/STable/STable.js.map +1 -1
  92. package/dist/components/STextarea/STextarea.cjs +217 -20
  93. package/dist/components/STextarea/STextarea.cjs.map +1 -1
  94. package/dist/components/STextarea/STextarea.js +217 -20
  95. package/dist/components/STextarea/STextarea.js.map +1 -1
  96. package/dist/components/SToast/SToastContainer.cjs +3 -3
  97. package/dist/components/SToast/SToastContainer.cjs.map +1 -1
  98. package/dist/components/SToast/SToastContainer.js +3 -3
  99. package/dist/components/SToast/SToastContainer.js.map +1 -1
  100. package/dist/components/STooltip/STooltip.cjs +208 -13
  101. package/dist/components/STooltip/STooltip.cjs.map +1 -1
  102. package/dist/components/STooltip/STooltip.js +208 -13
  103. package/dist/components/STooltip/STooltip.js.map +1 -1
  104. package/dist/index.cjs +439 -221
  105. package/dist/index.cjs.map +1 -1
  106. package/dist/index.js +439 -221
  107. package/dist/index.js.map +1 -1
  108. package/dist/styles.css +113 -48
  109. package/dist/theme.css +49 -23
  110. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -3328,20 +3328,46 @@ 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
  {
3340
3363
  ref,
3341
- className: cn("inline-flex flex-col items-center gap-[8px]", className),
3364
+ className: cn(
3365
+ "inline-flex flex-col items-center gap-[var(--cmp-progress-circular-gap)]",
3366
+ className
3367
+ ),
3342
3368
  style,
3343
3369
  children: [
3344
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative h-[80px] w-[80px]", children: [
3370
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(innerValue && "relative"), children: [
3345
3371
  /* @__PURE__ */ jsxRuntime.jsxs(
3346
3372
  "svg",
3347
3373
  {
@@ -3385,18 +3411,9 @@ var SCircleProgress = react.forwardRef(
3385
3411
  ]
3386
3412
  }
3387
3413
  ),
3388
- !indeterminate && /* @__PURE__ */ jsxRuntime.jsxs(
3389
- "span",
3390
- {
3391
- className: "absolute inset-0 flex items-center justify-center text-[16px] font-bold leading-[26px]",
3392
- style: { color: percentColor },
3393
- children: [
3394
- Math.round(v),
3395
- "%"
3396
- ]
3397
- }
3398
- )
3414
+ showPercent && innerValue && percentNode
3399
3415
  ] }),
3416
+ showPercent && !innerValue && percentNode,
3400
3417
  label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-center text-[12px] font-normal leading-[20px] text-[color:var(--cmp-progress-color-label)]", children: label })
3401
3418
  ]
3402
3419
  }
@@ -3407,6 +3424,14 @@ var SLoadingContainer = react.forwardRef(
3407
3424
  function SLoadingContainer2({ open = false, message, zIndex = 1200, className, style }, ref) {
3408
3425
  const [mounted2, setMounted] = react.useState(false);
3409
3426
  react.useEffect(() => setMounted(true), []);
3427
+ react.useEffect(() => {
3428
+ if (!open) return;
3429
+ const prev = document.body.style.overflow;
3430
+ document.body.style.overflow = "hidden";
3431
+ return () => {
3432
+ document.body.style.overflow = prev;
3433
+ };
3434
+ }, [open]);
3410
3435
  const innerRef = react.useRef(null);
3411
3436
  const setRef = react.useCallback(
3412
3437
  (node) => {
@@ -3675,15 +3700,15 @@ var sanitizeInlineHtml = (value) => {
3675
3700
  return template.innerHTML;
3676
3701
  };
3677
3702
  var SIZE = {
3678
- xs: { height: 24, paddingX: 8, gap: 6, arrow: 12, fontSize: 12, minWidth: 44, splitMinWidth: 60 },
3703
+ xs: { height: 24, paddingX: 8, gap: 6, arrow: 12, fontSize: 12, minWidth: 64, splitMinWidth: 72 },
3679
3704
  sm: {
3680
3705
  height: 28,
3681
3706
  paddingX: 12,
3682
3707
  gap: 8,
3683
3708
  arrow: 12,
3684
3709
  fontSize: 12,
3685
- minWidth: 70,
3686
- splitMinWidth: 76
3710
+ minWidth: 72,
3711
+ splitMinWidth: 88
3687
3712
  },
3688
3713
  md: {
3689
3714
  height: 36,
@@ -3791,7 +3816,7 @@ var SDropdownButton = react.forwardRef(
3791
3816
  align: "start",
3792
3817
  alignOffset: split ? splitAlignOffset : 0,
3793
3818
  className: cn(
3794
- "z-50 overflow-hidden rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] py-[4px] shadow-normal-sm",
3819
+ "z-50 overflow-hidden rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] shadow-normal-sm",
3795
3820
  !split && "min-w-[var(--radix-dropdown-menu-trigger-width)]",
3796
3821
  FLOATING_SLIDE_ANIM
3797
3822
  ),
@@ -4088,7 +4113,8 @@ var HIDE_DELAY_MS = 100;
4088
4113
  function useBody(content, message = []) {
4089
4114
  if (content != null) return content;
4090
4115
  if (message.length === 0) return null;
4091
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: message.map((line, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { children: line }, i)) });
4116
+ const singleLine = message.length === 1;
4117
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: message.map((line, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: singleLine ? "leading-[24px]" : void 0, children: line }, i)) });
4092
4118
  }
4093
4119
  var STooltip = react.forwardRef(function STooltip2({
4094
4120
  content,
@@ -4191,11 +4217,17 @@ var STooltip = react.forwardRef(function STooltip2({
4191
4217
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-[12px]", children: [
4192
4218
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children: body }),
4193
4219
  useClose && /* @__PURE__ */ jsxRuntime.jsx(
4194
- RPopover2__namespace.Close,
4220
+ SGhostButton,
4195
4221
  {
4196
- "aria-label": "\uB2EB\uAE30",
4197
- className: "shrink-0 cursor-pointer opacity-70 hover:opacity-100",
4198
- children: /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "close", size: 16, color: fg })
4222
+ icon: "close",
4223
+ size: "xs",
4224
+ intent: tooltipType === "default" ? "inverse" : "default",
4225
+ ariaLabel: "\uB2EB\uAE30",
4226
+ className: "shrink-0",
4227
+ onClick: () => {
4228
+ cancelHide();
4229
+ setOpen(false);
4230
+ }
4199
4231
  }
4200
4232
  )
4201
4233
  ] }),
@@ -4760,7 +4792,7 @@ function SActionModal({
4760
4792
  showClose: true,
4761
4793
  width,
4762
4794
  height,
4763
- className: "w-fit min-w-[480px]",
4795
+ className: "w-fit min-w-[480px] min-h-[320px]",
4764
4796
  children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full min-h-[320px] flex-col", children: [
4765
4797
  /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx("h2", { className: "text-[16px] font-bold leading-[26px] text-[color:var(--cmp-overlay-header-title-color)]", children: modalTitle }) }),
4766
4798
  /* @__PURE__ */ jsxRuntime.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 }),
@@ -4792,7 +4824,7 @@ function SActionModal({
4792
4824
  );
4793
4825
  }
4794
4826
  var DEFAULT_MESSAGE = {
4795
- loading: "",
4827
+ loading: "\uC791\uC5C5 \uC9C4\uD589\uC911...",
4796
4828
  error: "\uC791\uC5C5\uC5D0 \uC2E4\uD328\uD558\uC600\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD574 \uC8FC\uC138\uC694."
4797
4829
  };
4798
4830
  var DEFAULT_BUTTON_LABEL = {
@@ -4802,6 +4834,7 @@ var DEFAULT_BUTTON_LABEL = {
4802
4834
  function SLoadingModal({
4803
4835
  open,
4804
4836
  onOpenChange,
4837
+ onClose,
4805
4838
  persistent,
4806
4839
  state: state2 = "loading",
4807
4840
  progress,
@@ -4814,11 +4847,14 @@ function SLoadingModal({
4814
4847
  }) {
4815
4848
  const resolvedMessage = message ?? DEFAULT_MESSAGE[state2];
4816
4849
  const lines = Array.isArray(resolvedMessage) ? resolvedMessage : resolvedMessage ? [resolvedMessage] : [];
4850
+ const showButton = useButton || state2 === "error";
4817
4851
  return /* @__PURE__ */ jsxRuntime.jsx(
4818
4852
  SModalContainer,
4819
4853
  {
4820
4854
  open,
4821
4855
  onOpenChange,
4856
+ onClose,
4857
+ showClose: state2 === "error",
4822
4858
  persistent,
4823
4859
  ariaTitle: lines[0] || "\uB85C\uB529 \uC911",
4824
4860
  width,
@@ -4833,7 +4869,7 @@ function SLoadingModal({
4833
4869
  },
4834
4870
  i
4835
4871
  )) }),
4836
- useButton && /* @__PURE__ */ jsxRuntime.jsx(
4872
+ showButton && /* @__PURE__ */ jsxRuntime.jsx(
4837
4873
  SButton,
4838
4874
  {
4839
4875
  color: "neutral",
@@ -5064,7 +5100,7 @@ function SPagination({
5064
5100
  style,
5065
5101
  children: [
5066
5102
  /* @__PURE__ */ jsxRuntime.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 }),
5067
- simple ? /* @__PURE__ */ jsxRuntime.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: [
5103
+ simple ? /* @__PURE__ */ jsxRuntime.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: [
5068
5104
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-bold text-[color:var(--cmp-pagination-item-content-selected)]", children: currentPage }),
5069
5105
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "/" }),
5070
5106
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: lastPage })
@@ -5188,8 +5224,8 @@ function useFormField(field) {
5188
5224
  }, [ctx, name]);
5189
5225
  }
5190
5226
  var FIELD_SIZE = {
5191
- sm: { height: 28, radius: 4, fieldGap: 12, labelGap: 6, fontSize: 12, lineHeight: 20, icon: 12 },
5192
- md: { height: 36, radius: 6, fieldGap: 16, labelGap: 8, fontSize: 14, lineHeight: 24, icon: 12 }
5227
+ sm: { height: 28, radius: 4, fieldGap: 12, labelGap: 6, fontSize: 12, lineHeight: 20, icon: 16 },
5228
+ md: { height: 36, radius: 6, fieldGap: 16, labelGap: 8, fontSize: 14, lineHeight: 24, icon: 16 }
5193
5229
  };
5194
5230
  var ALIGN = {
5195
5231
  start: "flex-start",
@@ -5204,6 +5240,7 @@ var SField = react.forwardRef(function SField2({
5204
5240
  labelTooltip = "",
5205
5241
  labelTooltipProps,
5206
5242
  labelWidth,
5243
+ labelHeight,
5207
5244
  size = "sm",
5208
5245
  addonLabel = "",
5209
5246
  addonAlign = "start",
@@ -5218,6 +5255,7 @@ var SField = react.forwardRef(function SField2({
5218
5255
  readOnly = false,
5219
5256
  width,
5220
5257
  multiline = false,
5258
+ borderless = false,
5221
5259
  children,
5222
5260
  className,
5223
5261
  style,
@@ -5251,8 +5289,8 @@ var SField = react.forwardRef(function SField2({
5251
5289
  const resolvedSuccess = status === "pass";
5252
5290
  const showError = resolvedError && errorMessage !== "";
5253
5291
  const interactive = !disabled && !readOnly;
5254
- 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)";
5255
- const bgColor = disabled ? "var(--color-grey-30)" : readOnly ? "var(--sys-color-field-bg-readOnly)" : "var(--sys-color-field-bg-default)";
5292
+ 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)";
5293
+ const bgColor = borderless ? "transparent" : disabled ? "var(--color-grey-30)" : readOnly ? "var(--sys-color-field-bg-readOnly)" : "var(--sys-color-field-bg-default)";
5256
5294
  const textColor = disabled ? "var(--color-grey-65)" : readOnly ? "var(--sys-color-field-text-readOnly)" : "var(--sys-color-field-text-default)";
5257
5295
  return /* @__PURE__ */ jsxRuntime.jsx(
5258
5296
  "div",
@@ -5269,7 +5307,7 @@ var SField = react.forwardRef(function SField2({
5269
5307
  {
5270
5308
  className: "flex shrink-0 items-center font-bold text-(--sys-color-field-text-default)",
5271
5309
  style: {
5272
- height: s.height,
5310
+ height: cssLen(labelHeight) ?? s.height,
5273
5311
  marginRight: s.fieldGap,
5274
5312
  width: cssLen(labelWidth),
5275
5313
  fontSize: s.fontSize,
@@ -5295,14 +5333,14 @@ var SField = react.forwardRef(function SField2({
5295
5333
  {
5296
5334
  className: cn(
5297
5335
  "relative box-border flex min-w-0 items-stretch overflow-hidden border border-solid border-(--field-bc)",
5298
- 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]",
5336
+ 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]",
5299
5337
  disabled && "cursor-not-allowed"
5300
5338
  ),
5301
5339
  style: {
5302
5340
  // @ts-expect-error CSS 변수
5303
5341
  "--field-bc": borderColor,
5304
5342
  // focused/hovered prop이 명시된 경우 강조를 즉시 반영
5305
- ...interactive && focused ? { boxShadow: "0px 0px 4px 0px #0071ff66" } : {},
5343
+ ...interactive && !borderless && focused ? { boxShadow: "0px 0px 4px 0px #0071ff66" } : {},
5306
5344
  ...multiline ? { minHeight: s.height } : { height: s.height },
5307
5345
  "width": cssLen(width),
5308
5346
  "borderRadius": s.radius,
@@ -5347,15 +5385,28 @@ function flattenOptions(options, depth = 1) {
5347
5385
  const out = [];
5348
5386
  for (const o of options) {
5349
5387
  const hasChildren = Array.isArray(o.children) && o.children.length > 0;
5350
- out.push({
5351
- value: String(o.value),
5352
- label: o.label,
5353
- disabled: !!o.disabled,
5354
- depth,
5355
- isGroup: hasChildren,
5356
- raw: o.value
5357
- });
5358
- if (hasChildren) out.push(...flattenOptions(o.children, depth + 1));
5388
+ if (hasChildren) {
5389
+ const childFlat = flattenOptions(o.children, depth + 1);
5390
+ const allChildrenDisabled = childFlat.every((c) => c.disabled);
5391
+ out.push({
5392
+ value: String(o.value),
5393
+ label: o.label,
5394
+ disabled: !!o.disabled || allChildrenDisabled,
5395
+ depth,
5396
+ isGroup: true,
5397
+ raw: o.value
5398
+ });
5399
+ out.push(...childFlat);
5400
+ } else {
5401
+ out.push({
5402
+ value: String(o.value),
5403
+ label: o.label,
5404
+ disabled: !!o.disabled,
5405
+ depth,
5406
+ isGroup: false,
5407
+ raw: o.value
5408
+ });
5409
+ }
5359
5410
  }
5360
5411
  return out;
5361
5412
  }
@@ -5410,6 +5461,9 @@ var SSelect = react.forwardRef(function SSelect2({
5410
5461
  );
5411
5462
  const flat = react.useMemo(() => flattenOptions(options), [options]);
5412
5463
  const selectable = react.useMemo(() => selectableOptions(flat), [flat]);
5464
+ const hasLeaf = react.useMemo(() => flat.some((o) => !o.isGroup), [flat]);
5465
+ const allOptionsDisabled = hasLeaf && selectable.length === 0;
5466
+ const effectiveDisabled = disabled || allOptionsDisabled;
5413
5467
  const showSearch = useSearch && selectable.length >= SEARCH_THRESHOLD;
5414
5468
  const labelByValue = react.useMemo(() => new Map(flat.map((o) => [o.value, o.label])), [flat]);
5415
5469
  const rawByValue = react.useMemo(() => new Map(flat.map((o) => [o.value, o.raw])), [flat]);
@@ -5476,10 +5530,10 @@ var SSelect = react.forwardRef(function SSelect2({
5476
5530
  Ariakit__namespace.Select,
5477
5531
  {
5478
5532
  ref: triggerRef,
5479
- disabled,
5533
+ disabled: effectiveDisabled,
5480
5534
  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",
5481
5535
  style: {
5482
- color: disabled ? "var(--cmp-select-text-disabled)" : isPlaceholder ? "var(--cmp-select-icon-default)" : "var(--cmp-select-text-default)"
5536
+ color: effectiveDisabled ? "var(--cmp-select-text-disabled)" : isPlaceholder ? "var(--cmp-select-icon-default)" : "var(--cmp-select-text-default)"
5483
5537
  },
5484
5538
  children: [
5485
5539
  isHtmlLabel(triggerText) ? /* @__PURE__ */ jsxRuntime.jsx(
@@ -5494,7 +5548,7 @@ var SSelect = react.forwardRef(function SSelect2({
5494
5548
  {
5495
5549
  name: "chevronDown",
5496
5550
  size: 12,
5497
- color: disabled ? "var(--cmp-select-icon-disabled)" : "var(--cmp-select-icon-default)",
5551
+ color: effectiveDisabled ? "var(--cmp-select-icon-disabled)" : "var(--cmp-select-icon-default)",
5498
5552
  className: cn("shrink-0 transition-transform duration-200", open && "rotate-180")
5499
5553
  }
5500
5554
  )
@@ -5508,7 +5562,7 @@ var SSelect = react.forwardRef(function SSelect2({
5508
5562
  portalElement: portalContainer,
5509
5563
  gutter: 4,
5510
5564
  sameWidth: !dropdownWidth,
5511
- 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)] data-[enter]:animate-floating-in-bottom data-[leave]:animate-floating-out-bottom",
5565
+ 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",
5512
5566
  style: {
5513
5567
  maxHeight: dropdownHeight,
5514
5568
  ...dropdownWidth ? { width: dropdownWidth } : {},
@@ -5549,7 +5603,7 @@ var SSelect = react.forwardRef(function SSelect2({
5549
5603
  ),
5550
5604
  hasItems ? /* @__PURE__ */ jsxRuntime.jsx(ItemList, { items: filtered, multi, selected, useSearch: showSearch }) : (
5551
5605
  // 원본 sd-select-listbox__empty (표시할 항목이 없을 때)
5552
- /* @__PURE__ */ jsxRuntime.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." })
5606
+ /* @__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." })
5553
5607
  )
5554
5608
  ]
5555
5609
  }
@@ -5572,7 +5626,7 @@ var SSelect = react.forwardRef(function SSelect2({
5572
5626
  error: error || ruleError !== "",
5573
5627
  status: rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0,
5574
5628
  errorMessage: ruleError !== "" ? ruleError : errorMessage,
5575
- disabled,
5629
+ disabled: effectiveDisabled,
5576
5630
  width,
5577
5631
  className,
5578
5632
  style,
@@ -5607,7 +5661,11 @@ function ItemList({
5607
5661
  {
5608
5662
  className: cn(
5609
5663
  "select-none py-[4px] pr-[12px] text-[12px] leading-[20px] text-[color:var(--cmp-listItem-content-default)]",
5610
- 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"
5664
+ 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",
5665
+ // 하위가 전부 비활성이면(select.config 에서 bubble-up) 어미 그룹도 비활성 처리:
5666
+ // 텍스트는 회색(#888), depth1 그룹은 파란 배경 대신 회색(#EEE)으로 (depth2 는 #F6F6F6 유지)
5667
+ o.disabled && "cursor-not-allowed text-[color:var(--cmp-listItem-content-disabled)]",
5668
+ o.disabled && isDepth1 && "bg-[var(--cmp-listItem-depth1-bg-disabled)]"
5611
5669
  ),
5612
5670
  style: { paddingLeft: padLeft },
5613
5671
  children: o.label
@@ -5621,10 +5679,14 @@ function ItemList({
5621
5679
  {
5622
5680
  value: o.value,
5623
5681
  disabled: o.disabled,
5682
+ accessibleWhenDisabled: true,
5624
5683
  className: cn(
5625
5684
  itemBase,
5626
5685
  isSelected && !multi && "font-bold text-[color:var(--cmp-listItem-content-selected)]",
5627
- activeClass
5686
+ // Ariakit은 disabled 항목도 hover 시 active(data-active-item) 처리하므로,
5687
+ // 비활성 항목에는 hover 하이라이트를 적용하지 않아 회색 비활성 스타일을 유지한다.
5688
+ // (원본 Stencil의 `--focused...:not(--disabled)` 규칙과 동일한 의도)
5689
+ !o.disabled && activeClass
5628
5690
  ),
5629
5691
  style: { paddingTop: 4, paddingBottom: 4, paddingRight: 12, paddingLeft: padLeft },
5630
5692
  render: useSearch ? /* @__PURE__ */ jsxRuntime.jsx(Ariakit__namespace.ComboboxItem, {}) : void 0,
@@ -5634,15 +5696,21 @@ function ItemList({
5634
5696
  "span",
5635
5697
  {
5636
5698
  className: cn(
5637
- "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)]",
5638
- 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"
5699
+ "flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center rounded-[2px] border border-solid",
5700
+ o.disabled ? (
5701
+ // 비활성: 회색 채움(#E1E1E1) + 회색 테두리(#CCCCCC)
5702
+ "cursor-not-allowed border-[color:var(--cmp-checkbox-border-disabled)] bg-[var(--cmp-checkbox-bg-disabled)]"
5703
+ ) : cn(
5704
+ "group-data-[active-item]:border-[color:var(--cmp-checkbox-checked-border-inverse)]",
5705
+ 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"
5706
+ )
5639
5707
  ),
5640
5708
  children: isSelected && /* @__PURE__ */ jsxRuntime.jsx(
5641
5709
  SIcon,
5642
5710
  {
5643
5711
  name: "checkboxCheck",
5644
5712
  size: 12,
5645
- color: "var(--cmp-checkbox-checked-icon-default)"
5713
+ color: o.disabled ? "var(--cmp-checkbox-checked-icon-disabled)" : "var(--cmp-checkbox-checked-icon-default)"
5646
5714
  }
5647
5715
  )
5648
5716
  }
@@ -5933,7 +6001,8 @@ var STable = react.forwardRef(function STable2({
5933
6001
  else onSelectedChange?.([...selected, row]);
5934
6002
  };
5935
6003
  const radiusClass = radius === "full" ? "rounded-none" : radius === "useTop" ? "rounded-b-[var(--cmp-table-radius)] rounded-t-none" : "rounded-[var(--cmp-table-radius)]";
5936
- const cellPadY = dense ? "var(--cmp-table-body-dense-paddingY)" : "var(--cmp-table-body-default-paddingY)";
6004
+ const cellPadY = dense ? "var(--cmp-table-body-paddingY-dense)" : "var(--cmp-table-body-paddingY-default)";
6005
+ const cellPadX = dense ? "var(--cmp-table-body-paddingX-default)" : "var(--cmp-table-body-paddingX-wide)";
5937
6006
  const rowH = dense ? "var(--cmp-table-body-dense-height)" : "var(--cmp-table-body-default-height)";
5938
6007
  const totalColSpan = visibleCols.length + (selectable ? 1 : 0);
5939
6008
  const stickyInfo = (i) => {
@@ -6108,13 +6177,15 @@ var STable = react.forwardRef(function STable2({
6108
6177
  className: cn(
6109
6178
  // 원본 .td: 컬럼 폭에 맞춰 내용 말줄임(overflow hidden + ellipsis) + 행 구분선(border-b)
6110
6179
  // 셀 배경은 흰색으로 채워 뒤 배경이 비치지 않게 하고, hover 시 행 배경(grey_05)을 따른다.
6111
- "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)]",
6180
+ "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)]",
6112
6181
  rowBg,
6113
6182
  "group-hover:bg-[var(--color-grey-05)]",
6114
6183
  stickyShadowClass(i),
6115
6184
  col.tdClass
6116
6185
  ),
6117
6186
  style: {
6187
+ paddingLeft: cellPadX,
6188
+ paddingRight: cellPadX,
6118
6189
  paddingTop: cellPadY,
6119
6190
  paddingBottom: cellPadY,
6120
6191
  textAlign: col.align ?? "left",
@@ -6421,8 +6492,8 @@ var STextarea = react.forwardRef(function STextarea2({
6421
6492
  );
6422
6493
  });
6423
6494
  var PAD2 = {
6424
- sm: { fontSize: 12, stepper: 20, icon: 12 },
6425
- md: { fontSize: 14, stepper: 24, icon: 14 }
6495
+ sm: { fontSize: 12, lineHeight: 20, stepper: 20, icon: 12 },
6496
+ md: { fontSize: 14, lineHeight: 24, stepper: 24, icon: 14 }
6426
6497
  };
6427
6498
  var toNumber = (val) => {
6428
6499
  if (val === null || val === void 0 || val === "") return null;
@@ -6440,6 +6511,38 @@ var formatWithCommas = (value) => {
6440
6511
  const result = isNeg ? "-" + formatted : formatted;
6441
6512
  return decPart !== void 0 && decPart !== "" ? result + "." + decPart : result;
6442
6513
  };
6514
+ var addCommas = (value) => value.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
6515
+ var formatInputWithCommas = (value) => {
6516
+ const isNeg = value.startsWith("-");
6517
+ const unsigned = isNeg ? value.slice(1) : value;
6518
+ const hasDecimal = unsigned.includes(".");
6519
+ const [intPart = "", decPart = ""] = unsigned.split(".");
6520
+ const formattedInt = addCommas(intPart === "" ? "0" : intPart);
6521
+ return `${isNeg ? "-" : ""}${formattedInt}${hasDecimal ? `.${decPart}` : ""}`;
6522
+ };
6523
+ var getDecimalLimit = (useDecimal, maxDecimalLength) => {
6524
+ if (!useDecimal || maxDecimalLength === void 0 || !Number.isFinite(maxDecimalLength)) {
6525
+ return void 0;
6526
+ }
6527
+ return Math.max(0, Math.floor(maxDecimalLength));
6528
+ };
6529
+ var applyDecimalLimit = (value, decimalLimit) => {
6530
+ if (value === null || decimalLimit === void 0) return value;
6531
+ return Number(value.toFixed(decimalLimit));
6532
+ };
6533
+ var getLogicalCaret = (value, caret) => {
6534
+ return value.slice(0, caret ?? value.length).replace(/,/g, "").length;
6535
+ };
6536
+ var getDisplayCaret = (value, logicalCaret) => {
6537
+ if (logicalCaret <= 0) return 0;
6538
+ let seen = 0;
6539
+ for (let i = 0; i < value.length; i += 1) {
6540
+ if (value[i] === ",") continue;
6541
+ seen += 1;
6542
+ if (seen >= logicalCaret) return i + 1;
6543
+ }
6544
+ return value.length;
6545
+ };
6443
6546
  var SNumberInput = react.forwardRef(function SNumberInput2({
6444
6547
  value,
6445
6548
  onValueChange,
@@ -6449,6 +6552,7 @@ var SNumberInput = react.forwardRef(function SNumberInput2({
6449
6552
  step = 1,
6450
6553
  useButton = false,
6451
6554
  useDecimal = false,
6555
+ maxDecimalLength,
6452
6556
  inputPrefix = "",
6453
6557
  inputSuffix = "",
6454
6558
  inputClass,
@@ -6480,7 +6584,8 @@ var SNumberInput = react.forwardRef(function SNumberInput2({
6480
6584
  }, ref) {
6481
6585
  const p = PAD2[size];
6482
6586
  const padX = `var(--cmp-numberInput-${size}-paddingX)`;
6483
- const numValue = toNumber(value);
6587
+ const decimalLimit = getDecimalLimit(useDecimal, maxDecimalLength);
6588
+ const numValue = applyDecimalLimit(toNumber(value), decimalLimit);
6484
6589
  const [display, setDisplay] = react.useState(() => formatWithCommas(numValue));
6485
6590
  const [ruleError, setRuleError] = react.useState("");
6486
6591
  const innerRef = react.useRef(null);
@@ -6490,8 +6595,9 @@ var SNumberInput = react.forwardRef(function SNumberInput2({
6490
6595
  else if (ref) ref.current = el;
6491
6596
  };
6492
6597
  react.useEffect(() => {
6493
- setDisplay(formatWithCommas(toNumber(value)));
6494
- }, [value]);
6598
+ if (document.activeElement === innerRef.current) return;
6599
+ setDisplay(formatWithCommas(applyDecimalLimit(toNumber(value), decimalLimit)));
6600
+ }, [decimalLimit, value]);
6495
6601
  useFormField({
6496
6602
  name,
6497
6603
  validate: () => {
@@ -6503,48 +6609,87 @@ var SNumberInput = react.forwardRef(function SNumberInput2({
6503
6609
  });
6504
6610
  const resolvedError = error || ruleError !== "";
6505
6611
  const resolvedStatus = status ?? (rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0);
6506
- const emit2 = (n) => {
6507
- setDisplay(formatWithCommas(n));
6508
- onValueChange?.(n);
6612
+ const restoreCaret = (nextDisplay, logicalCaret) => {
6613
+ const input = innerRef.current;
6614
+ if (logicalCaret === void 0 || !input || document.activeElement !== input) return;
6615
+ const nextCaret = getDisplayCaret(nextDisplay, logicalCaret);
6616
+ requestAnimationFrame(() => {
6617
+ if (document.activeElement !== input) return;
6618
+ input.setSelectionRange(nextCaret, nextCaret);
6619
+ });
6620
+ };
6621
+ const setDisplayWithCaret = (nextDisplay, logicalCaret) => {
6622
+ setDisplay(nextDisplay);
6623
+ restoreCaret(nextDisplay, logicalCaret);
6624
+ };
6625
+ const resetRejectedInput = (target, logicalCaret) => {
6626
+ target.value = display;
6627
+ restoreCaret(display, Math.min(logicalCaret, display.replace(/,/g, "").length));
6628
+ };
6629
+ const emit2 = (n, logicalCaret) => {
6630
+ const next = applyDecimalLimit(n, decimalLimit);
6631
+ const nextDisplay = formatWithCommas(next);
6632
+ setDisplayWithCaret(nextDisplay, logicalCaret);
6633
+ onValueChange?.(next);
6509
6634
  };
6510
6635
  const incDisabled = disabled || readOnly || numValue !== null && numValue >= max;
6511
6636
  const decDisabled = disabled || readOnly || numValue !== null && numValue <= min;
6512
6637
  const increment = () => {
6513
6638
  if (incDisabled) return;
6514
6639
  const cur = numValue ?? (min === Number.NEGATIVE_INFINITY ? 0 : min);
6515
- const next = Math.min(cur + step, max);
6640
+ const next = applyDecimalLimit(Math.min(cur + step, max), decimalLimit);
6516
6641
  if (next !== cur) emit2(next);
6517
6642
  };
6518
6643
  const decrement = () => {
6519
6644
  if (decDisabled) return;
6520
6645
  const cur = numValue ?? (min === Number.NEGATIVE_INFINITY ? 0 : min);
6521
- const next = Math.max(cur - step, min);
6646
+ const next = applyDecimalLimit(Math.max(cur - step, min), decimalLimit);
6522
6647
  if (next !== cur) emit2(next);
6523
6648
  };
6524
- const handleInput = (raw) => {
6649
+ const handleInput = (event) => {
6650
+ const target = event.currentTarget;
6651
+ const raw = target.value;
6652
+ const logicalCaret = getLogicalCaret(raw, target.selectionStart);
6525
6653
  if (raw === "") {
6526
- setDisplay("");
6654
+ setDisplayWithCaret("", 0);
6527
6655
  onValueChange?.(null);
6528
6656
  return;
6529
6657
  }
6530
6658
  const cleaned = raw.replace(/,/g, "");
6531
6659
  const decimals = (cleaned.match(/\./g) || []).length;
6532
- if (decimals > 1) return;
6660
+ if (decimals > 1) {
6661
+ resetRejectedInput(target, logicalCaret);
6662
+ return;
6663
+ }
6533
6664
  if (cleaned === "-" || cleaned === "." || cleaned === "-.") {
6534
- setDisplay(cleaned);
6665
+ setDisplayWithCaret(cleaned, logicalCaret);
6666
+ return;
6667
+ }
6668
+ if (!useDecimal && cleaned.includes(".")) {
6669
+ resetRejectedInput(target, logicalCaret);
6535
6670
  return;
6536
6671
  }
6537
- if (!useDecimal && cleaned.includes(".")) return;
6672
+ if (decimalLimit !== void 0 && cleaned.includes(".")) {
6673
+ const fraction = cleaned.split(".")[1] ?? "";
6674
+ if (fraction.length > decimalLimit) {
6675
+ resetRejectedInput(target, logicalCaret);
6676
+ return;
6677
+ }
6678
+ }
6538
6679
  if (cleaned.endsWith(".") && decimals === 1) {
6539
6680
  const parsed2 = toNumber(cleaned.slice(0, -1));
6540
6681
  if (parsed2 !== null) {
6541
- setDisplay(formatWithCommas(parsed2) + ".");
6682
+ setDisplayWithCaret(formatInputWithCommas(cleaned), logicalCaret);
6542
6683
  return;
6543
6684
  }
6544
6685
  }
6545
6686
  const parsed = toNumber(cleaned);
6546
- if (parsed === null) return;
6547
- emit2(parsed);
6687
+ if (parsed === null) {
6688
+ resetRejectedInput(target, logicalCaret);
6689
+ return;
6690
+ }
6691
+ setDisplayWithCaret(formatInputWithCommas(cleaned), logicalCaret);
6692
+ onValueChange?.(applyDecimalLimit(parsed, decimalLimit));
6548
6693
  };
6549
6694
  const stepper = (dir) => {
6550
6695
  const off = dir === "inc" ? incDisabled : decDisabled;
@@ -6557,8 +6702,8 @@ var SNumberInput = react.forwardRef(function SNumberInput2({
6557
6702
  "aria-label": dir === "inc" ? "\uC99D\uAC00" : "\uAC10\uC18C",
6558
6703
  onClick: dir === "inc" ? increment : decrement,
6559
6704
  className: cn(
6560
- "flex flex-shrink-0 items-center justify-center",
6561
- off ? "cursor-not-allowed" : "cursor-pointer"
6705
+ "flex flex-shrink-0 items-center justify-center border border-solid border-transparent transition-colors",
6706
+ off ? "cursor-not-allowed" : "cursor-pointer hover:border-[var(--color-border-accentLight)]"
6562
6707
  ),
6563
6708
  style: {
6564
6709
  width: `var(--cmp-numberInput-stepper-${size}-size)`,
@@ -6607,24 +6752,26 @@ var SNumberInput = react.forwardRef(function SNumberInput2({
6607
6752
  style: {
6608
6753
  // 원본 sd-number-input: content gap = padding-x 토큰 (gap 토큰 아님)
6609
6754
  gap: `var(--cmp-numberInput-${size}-paddingX)`,
6610
- padding: `0 ${useButton ? padX : `calc(${padX} * 2)`}`
6755
+ padding: `0 ${useButton ? padX : `calc(${padX} * 2)`}`,
6756
+ fontSize: p.fontSize,
6757
+ lineHeight: `${p.lineHeight}px`
6611
6758
  },
6612
6759
  children: [
6613
6760
  useButton && stepper("dec"),
6614
- inputPrefix !== "" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", style: { fontSize: p.fontSize, color: affixColor }, children: inputPrefix }),
6761
+ inputPrefix !== "" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", style: { color: affixColor }, children: inputPrefix }),
6615
6762
  /* @__PURE__ */ jsxRuntime.jsx(
6616
6763
  "input",
6617
6764
  {
6618
6765
  ref: setRefs,
6619
6766
  name,
6620
6767
  type: "text",
6621
- inputMode: "numeric",
6768
+ inputMode: useDecimal ? "decimal" : "numeric",
6622
6769
  value: display,
6623
6770
  placeholder,
6624
6771
  disabled,
6625
6772
  readOnly,
6626
6773
  autoFocus,
6627
- onChange: (e) => handleInput(e.target.value),
6774
+ onChange: handleInput,
6628
6775
  onKeyDown: (e) => {
6629
6776
  if (e.key === "ArrowUp") {
6630
6777
  e.preventDefault();
@@ -6636,26 +6783,29 @@ var SNumberInput = react.forwardRef(function SNumberInput2({
6636
6783
  },
6637
6784
  onFocus: (e) => onFocus?.(e),
6638
6785
  onBlur: (e) => {
6639
- const n = toNumber(display);
6786
+ const cleaned = display.replace(/,/g, "");
6787
+ const n = toNumber(cleaned);
6640
6788
  const clamped = n === null ? null : Math.min(Math.max(n, min), max);
6641
6789
  if (clamped !== n) emit2(clamped);
6642
- else setDisplay(formatWithCommas(n));
6790
+ else setDisplay(n === null ? "" : formatInputWithCommas(cleaned));
6643
6791
  if (rules && rules.length > 0) setRuleError(runRules(clamped, rules));
6644
6792
  onBlur?.(e);
6645
6793
  },
6646
6794
  className: cn(
6647
- "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",
6795
+ // h-full 대신 라인박스 높이 그대로 두어 prefix/suffix 동일하게 flex 로 수직 센터링
6796
+ // (h-full 이면 input 내부 텍스트 센터링을 브라우저가 수행해 1px 어긋날 수 있음)
6797
+ "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",
6648
6798
  inputClass
6649
6799
  ),
6650
6800
  style: {
6651
- fontSize: p.fontSize,
6801
+ // fontSize/lineHeight 는 컨테이너에서 상속
6652
6802
  textAlign: useButton ? "center" : "right",
6653
6803
  color: disabled ? "var(--cmp-numberInput-text-disabled)" : "var(--cmp-numberInput-text-default)",
6654
6804
  ...inputStyle
6655
6805
  }
6656
6806
  }
6657
6807
  ),
6658
- inputSuffix !== "" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", style: { fontSize: p.fontSize, color: affixColor }, children: inputSuffix }),
6808
+ inputSuffix !== "" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", style: { color: affixColor }, children: inputSuffix }),
6659
6809
  useButton && stepper("inc")
6660
6810
  ]
6661
6811
  }
@@ -6769,7 +6919,7 @@ function SRadioGroup({
6769
6919
  role: "radiogroup",
6770
6920
  className: cn(
6771
6921
  "inline-flex",
6772
- direction === "vertical" ? "flex-col gap-[8px]" : "flex-row gap-[20px]",
6922
+ direction === "vertical" ? "flex-col gap-[var(--cmp-radio-group-gap-vertical)]" : "flex-row gap-[var(--cmp-radio-group-gap-horizontal)]",
6773
6923
  className
6774
6924
  ),
6775
6925
  style,
@@ -6981,7 +7131,7 @@ function SCalendar({
6981
7131
  "span",
6982
7132
  {
6983
7133
  className: cn(
6984
- "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]",
7134
+ "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)]",
6985
7135
  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)]",
6986
7136
  isToday && !disabled && "font-bold"
6987
7137
  ),
@@ -7171,6 +7321,7 @@ function RangeCalendar({
7171
7321
  selectable,
7172
7322
  maxRange,
7173
7323
  onSelect,
7324
+ onPendingStartChange,
7174
7325
  onViewChange
7175
7326
  }) {
7176
7327
  const today = todayStr();
@@ -7233,9 +7384,11 @@ function RangeCalendar({
7233
7384
  setStart(d);
7234
7385
  setEnd(null);
7235
7386
  setHover(null);
7387
+ onPendingStartChange?.(d);
7236
7388
  return;
7237
7389
  }
7238
7390
  setEnd(d);
7391
+ onPendingStartChange?.(null);
7239
7392
  onSelect([start, d]);
7240
7393
  };
7241
7394
  const GRID_COLS = "grid grid-cols-[repeat(7,var(--cmp-datepicker-calendar-day-width))]";
@@ -7370,8 +7523,11 @@ function SDateRangePicker({
7370
7523
  const portalContainer = usePortalContainer();
7371
7524
  const [open, setOpen] = react.useState(false);
7372
7525
  const [ruleError, setRuleError] = react.useState("");
7526
+ const [pendingStart, setPendingStart] = react.useState(null);
7373
7527
  const hasValue = value != null && value[0] !== "" && value[1] !== "";
7374
- const display = hasValue ? `${value[0]} ~ ${value[1]}` : placeholder;
7528
+ const hasDisplay = pendingStart != null || hasValue;
7529
+ const startText = pendingStart ?? (hasValue ? value[0] : "");
7530
+ const endText = pendingStart ? "" : hasValue ? value[1] : "";
7375
7531
  useFormField({
7376
7532
  name,
7377
7533
  validate: () => {
@@ -7385,6 +7541,7 @@ function SDateRangePicker({
7385
7541
  const resolvedStatus = status ?? (rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0);
7386
7542
  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 };
7387
7543
  const select = (r) => {
7544
+ setPendingStart(null);
7388
7545
  onValueChange?.(r);
7389
7546
  if (rules && rules.length > 0) setRuleError(runRules(r, rules));
7390
7547
  setOpen(false);
@@ -7409,61 +7566,80 @@ function SDateRangePicker({
7409
7566
  disabled,
7410
7567
  className,
7411
7568
  style,
7412
- children: /* @__PURE__ */ jsxRuntime.jsxs(RPopover2__namespace.Root, { open, onOpenChange: (o) => !disabled && setOpen(o), children: [
7413
- /* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
7414
- "button",
7415
- {
7416
- type: "button",
7417
- name,
7418
- disabled,
7419
- className: "flex h-full w-full items-center overflow-hidden bg-transparent outline-none disabled:cursor-not-allowed",
7420
- style: { padding: `0 ${dims.padX}px`, gap: dims.gap, borderRadius: dims.radius },
7421
- children: [
7422
- /* @__PURE__ */ jsxRuntime.jsx(
7423
- SIcon,
7424
- {
7425
- name: "date",
7426
- size: dims.icon,
7427
- color: disabled ? "var(--cmp-datepicker-icon-disabled)" : "var(--cmp-datepicker-icon-default)",
7428
- className: "flex-shrink-0"
7429
- }
7430
- ),
7431
- /* @__PURE__ */ jsxRuntime.jsx(
7432
- "span",
7433
- {
7434
- className: "flex-1 truncate text-center",
7435
- style: {
7436
- minWidth: dims.minW,
7437
- fontSize: dims.fontSize,
7438
- lineHeight: `${dims.lineHeight}px`,
7439
- color: disabled ? "var(--cmp-datepicker-text-disabled)" : hasValue ? "var(--cmp-datepicker-text-default)" : "var(--cmp-field-hint-color)"
7440
- },
7441
- children: display
7442
- }
7443
- )
7444
- ]
7445
- }
7446
- ) }),
7447
- /* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
7448
- RPopover2__namespace.Content,
7449
- {
7450
- side: "bottom",
7451
- align: "start",
7452
- sideOffset: 4,
7453
- className: cn("z-50", FLOATING_SLIDE_ANIM),
7454
- children: /* @__PURE__ */ jsxRuntime.jsx(
7455
- RangeCalendar,
7569
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
7570
+ RPopover2__namespace.Root,
7571
+ {
7572
+ open,
7573
+ onOpenChange: (o) => {
7574
+ if (disabled) return;
7575
+ setOpen(o);
7576
+ if (!o) setPendingStart(null);
7577
+ },
7578
+ children: [
7579
+ /* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
7580
+ "button",
7456
7581
  {
7457
- value: value ?? null,
7458
- selectable,
7459
- maxRange,
7460
- onSelect: select,
7461
- onViewChange
7582
+ type: "button",
7583
+ name,
7584
+ disabled,
7585
+ className: "flex h-full w-full items-center overflow-hidden bg-transparent outline-none disabled:cursor-not-allowed",
7586
+ style: { padding: `0 ${dims.padX}px`, gap: dims.gap, borderRadius: dims.radius },
7587
+ children: [
7588
+ /* @__PURE__ */ jsxRuntime.jsx(
7589
+ SIcon,
7590
+ {
7591
+ name: "date",
7592
+ size: dims.icon,
7593
+ color: disabled ? "var(--cmp-datepicker-icon-disabled)" : "var(--cmp-datepicker-icon-default)",
7594
+ className: "flex-shrink-0"
7595
+ }
7596
+ ),
7597
+ /* @__PURE__ */ jsxRuntime.jsx(
7598
+ "span",
7599
+ {
7600
+ className: cn(
7601
+ "flex-1 items-center",
7602
+ hasDisplay ? "flex" : "block truncate text-center"
7603
+ ),
7604
+ style: {
7605
+ minWidth: dims.minW,
7606
+ fontSize: dims.fontSize,
7607
+ lineHeight: `${dims.lineHeight}px`,
7608
+ color: disabled ? "var(--cmp-datepicker-text-disabled)" : hasDisplay ? "var(--cmp-datepicker-text-default)" : "var(--cmp-field-hint-color)"
7609
+ },
7610
+ children: hasDisplay ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7611
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate text-right", children: startText }),
7612
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-[4px]", children: "~" }),
7613
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate text-left", children: endText })
7614
+ ] }) : placeholder
7615
+ }
7616
+ )
7617
+ ]
7462
7618
  }
7463
- )
7464
- }
7465
- ) })
7466
- ] })
7619
+ ) }),
7620
+ /* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
7621
+ RPopover2__namespace.Content,
7622
+ {
7623
+ side: "bottom",
7624
+ align: "start",
7625
+ sideOffset: 4,
7626
+ className: cn("z-50", FLOATING_SLIDE_ANIM),
7627
+ children: /* @__PURE__ */ jsxRuntime.jsx(
7628
+ RangeCalendar,
7629
+ {
7630
+ value: value ?? null,
7631
+ selectable,
7632
+ maxRange,
7633
+ onSelect: select,
7634
+ onPendingStartChange: setPendingStart,
7635
+ onViewChange
7636
+ }
7637
+ )
7638
+ }
7639
+ ) })
7640
+ ]
7641
+ }
7642
+ )
7467
7643
  }
7468
7644
  );
7469
7645
  }
@@ -7472,7 +7648,7 @@ var SChip = react.forwardRef(function SChip2({
7472
7648
  value = "",
7473
7649
  error: errorProp = false,
7474
7650
  disabled = false,
7475
- editable = true,
7651
+ editable = false,
7476
7652
  showRemove = true,
7477
7653
  placeholder = "",
7478
7654
  rules,
@@ -7625,6 +7801,7 @@ function SFilePicker({
7625
7801
  hovered = false,
7626
7802
  inline = false,
7627
7803
  multiple = false,
7804
+ useMultipleListBox = false,
7628
7805
  accept,
7629
7806
  maxFileSize,
7630
7807
  maxTotalSize,
@@ -7650,10 +7827,13 @@ function SFilePicker({
7650
7827
  const autoId = react.useId();
7651
7828
  const resolvedName = name ?? autoId;
7652
7829
  const inputRef = react.useRef(null);
7830
+ const contentBoxRef = react.useRef(null);
7653
7831
  const [ruleError, setRuleError] = react.useState("");
7832
+ const [listOpen, setListOpen] = react.useState(false);
7833
+ const portalContainer = usePortalContainer();
7654
7834
  const files = multiple ? Array.isArray(value) ? value : [] : value && !Array.isArray(value) ? value : null;
7655
- const hasSingle = !multiple && !!files;
7656
- const displayText = hasSingle ? files.name : placeholder;
7835
+ const hasFiles = multiple ? files.length > 0 : !!files;
7836
+ const displayText = !hasFiles ? placeholder : multiple ? files.map((f) => f.name).join(", ") : files.name;
7657
7837
  useFormField({
7658
7838
  name,
7659
7839
  validate: () => {
@@ -7704,10 +7884,12 @@ function SFilePicker({
7704
7884
  e.stopPropagation();
7705
7885
  if (disabled) return;
7706
7886
  onValueChange?.(multiple ? [] : null);
7887
+ setListOpen(false);
7707
7888
  };
7708
7889
  const removeChip = (i) => {
7709
7890
  const next = files.filter((_, idx) => idx !== i);
7710
7891
  onValueChange?.(next);
7892
+ if (next.length === 0) setListOpen(false);
7711
7893
  };
7712
7894
  const open = () => {
7713
7895
  if (!disabled) inputRef.current?.click();
@@ -7717,78 +7899,100 @@ function SFilePicker({
7717
7899
  const padX = size === "md" ? "var(--cmp-filepicker-md-paddingX)" : "var(--cmp-filepicker-sm-paddingX)";
7718
7900
  const iconSize = size === "md" ? 20 : 16;
7719
7901
  const gapCls = size === "md" ? "gap-[var(--cmp-filepicker-md-gap)]" : "gap-[var(--cmp-filepicker-sm-gap)]";
7720
- const content = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex h-full w-full items-center", gapCls), style: { padding: `0 ${padX}` }, children: [
7902
+ const inlinePlaceholder = inline && !disabled && !hasFiles;
7903
+ const showListbox = multiple && useMultipleListBox;
7904
+ const filesArr = multiple ? files : [];
7905
+ const contentInner = /* @__PURE__ */ jsxRuntime.jsxs(
7906
+ "div",
7907
+ {
7908
+ ref: contentBoxRef,
7909
+ className: cn("group/filepicker flex h-full w-full items-center", gapCls),
7910
+ style: { padding: inline ? 0 : `0 ${padX}` },
7911
+ children: [
7912
+ /* @__PURE__ */ jsxRuntime.jsx(
7913
+ "input",
7914
+ {
7915
+ ref: inputRef,
7916
+ type: "file",
7917
+ className: "hidden",
7918
+ disabled,
7919
+ multiple,
7920
+ accept,
7921
+ name: resolvedName,
7922
+ onChange,
7923
+ "aria-label": placeholder
7924
+ }
7925
+ ),
7926
+ /* @__PURE__ */ jsxRuntime.jsxs(
7927
+ "button",
7928
+ {
7929
+ type: "button",
7930
+ disabled,
7931
+ onClick: open,
7932
+ "aria-label": placeholder,
7933
+ className: cn(
7934
+ "flex min-w-0 flex-1 items-center bg-transparent text-left",
7935
+ gapCls,
7936
+ disabled ? "cursor-not-allowed" : "cursor-pointer"
7937
+ ),
7938
+ children: [
7939
+ /* @__PURE__ */ jsxRuntime.jsx(
7940
+ SIcon,
7941
+ {
7942
+ name: "attachFile",
7943
+ size: iconSize,
7944
+ color: disabled ? "var(--cmp-filepicker-icon-disabled)" : "var(--color-grey-65)"
7945
+ }
7946
+ ),
7947
+ /* @__PURE__ */ jsxRuntime.jsx(
7948
+ "span",
7949
+ {
7950
+ className: cn(
7951
+ "min-w-0 flex-1 truncate text-[12px]",
7952
+ inlinePlaceholder && "text-[color:var(--cmp-filepicker-text-placeholder)] transition-colors group-hover/filepicker:text-[color:var(--cmp-filepicker-text-default)]"
7953
+ ),
7954
+ style: inlinePlaceholder ? void 0 : {
7955
+ color: disabled ? "var(--cmp-filepicker-text-disabled)" : hasFiles ? "var(--cmp-filepicker-text-default)" : "var(--cmp-filepicker-text-placeholder)"
7956
+ },
7957
+ children: displayText
7958
+ }
7959
+ )
7960
+ ]
7961
+ }
7962
+ ),
7963
+ showListbox && hasFiles && !disabled && /* @__PURE__ */ jsxRuntime.jsx(
7964
+ Ariakit__namespace.PopoverDisclosure,
7965
+ {
7966
+ render: /* @__PURE__ */ jsxRuntime.jsx(SGhostButton, { icon: "caretDown", size: "xxs", ariaLabel: "toggle file list" }),
7967
+ className: cn("shrink-0 transition-transform duration-150", listOpen && "rotate-180")
7968
+ }
7969
+ ),
7970
+ !disabled && hasFiles && /* @__PURE__ */ jsxRuntime.jsx(SGhostButton, { icon: "close", size: "xxs", ariaLabel: "clear", onClick: clear })
7971
+ ]
7972
+ }
7973
+ );
7974
+ const content = showListbox ? /* @__PURE__ */ jsxRuntime.jsxs(Ariakit__namespace.PopoverProvider, { open: listOpen, setOpen: setListOpen, placement: "bottom-start", children: [
7975
+ contentInner,
7721
7976
  /* @__PURE__ */ jsxRuntime.jsx(
7722
- "input",
7977
+ Ariakit__namespace.Popover,
7723
7978
  {
7724
- ref: inputRef,
7725
- type: "file",
7726
- className: "hidden",
7727
- disabled,
7728
- multiple,
7729
- accept,
7730
- name: resolvedName,
7731
- onChange,
7732
- "aria-label": placeholder
7733
- }
7734
- ),
7735
- /* @__PURE__ */ jsxRuntime.jsxs(
7736
- "button",
7737
- {
7738
- type: "button",
7739
- disabled,
7740
- onClick: open,
7741
- "aria-label": placeholder,
7742
- className: cn(
7743
- "flex min-w-0 flex-1 items-center bg-transparent text-left",
7744
- gapCls,
7745
- disabled ? "cursor-not-allowed" : "cursor-pointer"
7746
- ),
7747
- children: [
7748
- /* @__PURE__ */ jsxRuntime.jsx(
7749
- SIcon,
7750
- {
7751
- name: "attachFile",
7752
- size: iconSize,
7753
- color: disabled ? "var(--cmp-filepicker-icon-disabled)" : "var(--color-grey-65)"
7754
- }
7755
- ),
7756
- /* @__PURE__ */ jsxRuntime.jsx(
7757
- "span",
7758
- {
7759
- className: "min-w-0 flex-1 truncate text-[12px]",
7760
- style: {
7761
- color: disabled ? "var(--cmp-filepicker-text-disabled)" : hasSingle ? "var(--cmp-filepicker-text-default)" : "var(--cmp-filepicker-text-placeholder)"
7762
- },
7763
- children: displayText
7764
- }
7765
- )
7766
- ]
7979
+ portal: true,
7980
+ portalElement: portalContainer,
7981
+ gutter: 4,
7982
+ unmountOnHide: true,
7983
+ getAnchorRect: () => contentBoxRef.current?.getBoundingClientRect() ?? null,
7984
+ style: { minWidth: contentBoxRef.current?.offsetWidth },
7985
+ className: "z-50 box-border flex flex-col items-stretch gap-[8px] rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] p-[8px] shadow-[2px_2px_12px_2px_rgba(0,0,0,0.1)]",
7986
+ children: filesArr.map((f, i) => /* @__PURE__ */ jsxRuntime.jsx(SChip, { value: f.name, editable: false, onRemove: () => removeChip(i) }, i))
7767
7987
  }
7768
- ),
7769
- !disabled && hasSingle && /* @__PURE__ */ jsxRuntime.jsx(SGhostButton, { icon: "close", size: "xxs", ariaLabel: "clear", onClick: clear })
7770
- ] });
7771
- const chips = multiple && files.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-[8px] flex flex-wrap gap-[8px]", children: files.map((f, i) => /* @__PURE__ */ jsxRuntime.jsx(SChip, { value: f.name, editable: false, onRemove: () => removeChip(i) }, i)) });
7772
- if (inline) {
7773
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("inline-flex flex-col", className), style, children: [
7774
- /* @__PURE__ */ jsxRuntime.jsx(
7775
- "div",
7776
- {
7777
- 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)]",
7778
- style: {
7779
- height: "var(--cmp-filepicker-sm-height)",
7780
- width: typeof width === "number" ? `${width}px` : width
7781
- },
7782
- children: content
7783
- }
7784
- ),
7785
- chips
7786
- ] });
7787
- }
7988
+ )
7989
+ ] }) : contentInner;
7990
+ 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)) });
7788
7991
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style, children: [
7789
7992
  /* @__PURE__ */ jsxRuntime.jsx(
7790
7993
  SField,
7791
7994
  {
7995
+ borderless: inline,
7792
7996
  label,
7793
7997
  labelWidth,
7794
7998
  icon,
@@ -7816,6 +8020,7 @@ function SKeyValueTable({
7816
8020
  fields = [],
7817
8021
  search = false,
7818
8022
  radius = "default",
8023
+ dense = false,
7819
8024
  onChange,
7820
8025
  onSearch,
7821
8026
  className,
@@ -7823,6 +8028,8 @@ function SKeyValueTable({
7823
8028
  }) {
7824
8029
  if (fields.length === 0) return null;
7825
8030
  const emit2 = (name, value) => onChange?.({ name, value });
8031
+ const cellHeight = dense ? "var(--cmp-table-body-dense-height)" : "var(--cmp-table-keyValue-height)";
8032
+ const cellPadY = dense ? "var(--cmp-table-body-paddingY-dense)" : "var(--cmp-table-keyValue-body-paddingY)";
7826
8033
  const renderField = (f) => {
7827
8034
  if (f.render) return f.render;
7828
8035
  const opt = f.options ?? {};
@@ -7903,10 +8110,15 @@ function SKeyValueTable({
7903
8110
  rowSpan: f.thRowSpan && f.thRowSpan > 1 ? f.thRowSpan : void 0,
7904
8111
  colSpan: f.thColSpan && f.thColSpan > 1 ? f.thColSpan : void 0,
7905
8112
  className: cn(
7906
- "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-paddingY)] text-left align-middle",
8113
+ "box-border bg-[var(--cmp-table-header-bg)] px-[var(--cmp-table-header-paddingX)] text-left align-middle",
7907
8114
  cellBorder,
7908
8115
  f.thClass
7909
8116
  ),
8117
+ style: {
8118
+ height: cellHeight,
8119
+ paddingTop: cellPadY,
8120
+ paddingBottom: cellPadY
8121
+ },
7910
8122
  children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full w-full items-center justify-between gap-[var(--cmp-table-header-gap)]", children: [
7911
8123
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-[8px]", children: [
7912
8124
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[12px] font-bold leading-[20px] text-[color:var(--sys-color-fg-primary)]", children: f.label }),
@@ -7932,10 +8144,11 @@ function SKeyValueTable({
7932
8144
  rowSpan: f.tdRowSpan && f.tdRowSpan > 1 ? f.tdRowSpan : void 0,
7933
8145
  colSpan: f.tdColSpan && f.tdColSpan > 1 ? f.tdColSpan : void 0,
7934
8146
  className: cn(
7935
- "h-[var(--cmp-table-keyValue-height)] box-border bg-[var(--sys-color-bg-frame)] px-[var(--cmp-table-keyValue-body-paddingX-default)] py-[var(--cmp-table-keyValue-body-paddingY)] align-middle",
8147
+ "box-border bg-[var(--sys-color-bg-frame)] px-[var(--cmp-table-keyValue-body-paddingX-default)] align-middle",
7936
8148
  cellBorder,
7937
8149
  f.tdClass
7938
8150
  ),
8151
+ style: { height: cellHeight, paddingTop: cellPadY, paddingBottom: cellPadY },
7939
8152
  children: renderField(f)
7940
8153
  },
7941
8154
  `td-${r}-${c}`
@@ -8056,9 +8269,9 @@ var POS_ANCHOR = {
8056
8269
  "top-left": { top: 20, left: 20 },
8057
8270
  "top-center": { top: 20, left: "50%" },
8058
8271
  "top-right": { top: 20, right: 20 },
8059
- "bottom-left": { bottom: 20, left: 20 },
8060
- "bottom-center": { bottom: 20, left: "50%" },
8061
- "bottom-right": { bottom: 20, right: 20 }
8272
+ "bottom-left": { bottom: 100, left: 20 },
8273
+ "bottom-center": { bottom: 100, left: "50%" },
8274
+ "bottom-right": { bottom: 100, right: 20 }
8062
8275
  };
8063
8276
  var counter = 0;
8064
8277
  var SToastContainer = react.forwardRef(
@@ -8418,7 +8631,7 @@ var SChipInput = react.forwardRef(function SChipInput2({
8418
8631
  disabledChips = [],
8419
8632
  size = "sm",
8420
8633
  disabled = false,
8421
- placeholder = "\uC785\uB825\uD574 \uC8FC\uC138\uC694.",
8634
+ placeholder = "\uD0DC\uADF8 \uC785\uB825 (Enter\uB85C \uB4F1\uB85D / \uCF64\uB9C8\uB85C \uAD6C\uBD84 / \uB744\uC5B4\uC4F0\uAE30 \uBD88\uAC00)",
8422
8635
  name,
8423
8636
  rules,
8424
8637
  error,
@@ -8569,6 +8782,7 @@ var SChipInput = react.forwardRef(function SChipInput2({
8569
8782
  {
8570
8783
  label,
8571
8784
  labelWidth,
8785
+ labelHeight: `calc(var(--cmp-chipInput-${size}-minHeight) + 2px)`,
8572
8786
  icon,
8573
8787
  labelTooltip,
8574
8788
  labelTooltipProps,
@@ -8639,9 +8853,11 @@ var SChipInput = react.forwardRef(function SChipInput2({
8639
8853
  paddingInline: isFieldFilled ? "var(--cmp-chip-paddingX)" : void 0,
8640
8854
  borderWidth: isFieldFilled ? "var(--cmp-chip-border-width)" : void 0,
8641
8855
  borderStyle: isFieldFilled ? "solid" : void 0,
8642
- borderColor: isFieldFilled ? "transparent" : void 0,
8856
+ // 작성중 필드는 SChip의 editable 수정중(editing) 스타일과 동일하게 —
8857
+ // bg/보더/글자색 모두 focus 토큰을 사용한다.
8858
+ borderColor: isFieldFilled ? "var(--cmp-chip-border-focus)" : void 0,
8643
8859
  borderRadius: isFieldFilled ? "var(--cmp-chip-radius)" : 0,
8644
- background: isFieldFilled ? "var(--cmp-chip-bg-default)" : "transparent",
8860
+ background: isFieldFilled ? "var(--cmp-chip-bg-focus)" : "transparent",
8645
8861
  overflow: "hidden"
8646
8862
  },
8647
8863
  children: [
@@ -8650,7 +8866,7 @@ var SChipInput = react.forwardRef(function SChipInput2({
8650
8866
  {
8651
8867
  "aria-hidden": true,
8652
8868
  className: cn(
8653
- "invisible col-start-1 row-start-1 whitespace-pre font-medium",
8869
+ "invisible col-start-1 row-start-1 whitespace-pre font-normal",
8654
8870
  size === "md" ? "text-14 leading-24" : "text-12 leading-20"
8655
8871
  ),
8656
8872
  children: inputValue !== "" ? inputValue : values.length === 0 ? placeholder : ""
@@ -8663,12 +8879,14 @@ var SChipInput = react.forwardRef(function SChipInput2({
8663
8879
  name: resolvedName,
8664
8880
  size: 1,
8665
8881
  className: cn(
8666
- "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",
8882
+ "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",
8667
8883
  size === "md" ? "text-14 leading-24" : "text-12 leading-20"
8668
8884
  ),
8669
8885
  style: {
8670
8886
  minWidth: "1ch",
8671
- height: "var(--cmp-chip-height)",
8887
+ // height 지정하지 않고 line-height(20/24px)에 맞춰 자동 크기로 둔다.
8888
+ // var(--cmp-chip-height)(24px)로 고정하면 네이티브 <input>이 남는 세로 여백에
8889
+ // 텍스트를 아래로 밀어 넣어, 확정된 chip 텍스트보다 2px 낮게 보인다.
8672
8890
  margin: 0,
8673
8891
  overflow: "hidden",
8674
8892
  textOverflow: "ellipsis"
@@ -8713,7 +8931,7 @@ var SChipInput = react.forwardRef(function SChipInput2({
8713
8931
  showMetaInfo && /* @__PURE__ */ jsxRuntime.jsxs(
8714
8932
  "div",
8715
8933
  {
8716
- className: "s-chip-input__meta flex items-center gap-8",
8934
+ className: "s-chip-input__meta ml-auto flex items-center gap-8",
8717
8935
  onMouseDown: (e) => e.preventDefault(),
8718
8936
  children: [
8719
8937
  /* @__PURE__ */ jsxRuntime.jsx(