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.js CHANGED
@@ -3300,20 +3300,46 @@ var COLOR_MAP = {
3300
3300
  };
3301
3301
  var clamp2 = (v) => Number.isFinite(v) ? Math.max(0, Math.min(100, v)) : 0;
3302
3302
  var SCircleProgress = forwardRef(
3303
- function SCircleProgress2({ value = 0, type = "primary", indeterminate = false, label, className, style }, ref) {
3303
+ function SCircleProgress2({
3304
+ value = 0,
3305
+ type = "primary",
3306
+ indeterminate = false,
3307
+ label,
3308
+ innerValue = false,
3309
+ className,
3310
+ style
3311
+ }, ref) {
3304
3312
  const v = clamp2(value);
3305
3313
  const colors = COLOR_MAP[type];
3306
3314
  const c = VIEWBOX / 2;
3307
3315
  const percentColor = v === 0 ? "var(--sys-color-fg-tertiary, #888888)" : colors.arc;
3308
3316
  const filled = v / 100 * CIRCUMFERENCE;
3317
+ const showPercent = !indeterminate;
3318
+ const percentNode = /* @__PURE__ */ jsxs(
3319
+ "span",
3320
+ {
3321
+ className: cn(
3322
+ "text-center text-[16px] font-bold leading-[26px]",
3323
+ innerValue && "absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2"
3324
+ ),
3325
+ style: { color: percentColor },
3326
+ children: [
3327
+ Math.round(v),
3328
+ "%"
3329
+ ]
3330
+ }
3331
+ );
3309
3332
  return /* @__PURE__ */ jsxs(
3310
3333
  "div",
3311
3334
  {
3312
3335
  ref,
3313
- className: cn("inline-flex flex-col items-center gap-[8px]", className),
3336
+ className: cn(
3337
+ "inline-flex flex-col items-center gap-[var(--cmp-progress-circular-gap)]",
3338
+ className
3339
+ ),
3314
3340
  style,
3315
3341
  children: [
3316
- /* @__PURE__ */ jsxs("div", { className: "relative h-[80px] w-[80px]", children: [
3342
+ /* @__PURE__ */ jsxs("div", { className: cn(innerValue && "relative"), children: [
3317
3343
  /* @__PURE__ */ jsxs(
3318
3344
  "svg",
3319
3345
  {
@@ -3357,18 +3383,9 @@ var SCircleProgress = forwardRef(
3357
3383
  ]
3358
3384
  }
3359
3385
  ),
3360
- !indeterminate && /* @__PURE__ */ jsxs(
3361
- "span",
3362
- {
3363
- className: "absolute inset-0 flex items-center justify-center text-[16px] font-bold leading-[26px]",
3364
- style: { color: percentColor },
3365
- children: [
3366
- Math.round(v),
3367
- "%"
3368
- ]
3369
- }
3370
- )
3386
+ showPercent && innerValue && percentNode
3371
3387
  ] }),
3388
+ showPercent && !innerValue && percentNode,
3372
3389
  label && /* @__PURE__ */ jsx("span", { className: "text-center text-[12px] font-normal leading-[20px] text-[color:var(--cmp-progress-color-label)]", children: label })
3373
3390
  ]
3374
3391
  }
@@ -3379,6 +3396,14 @@ var SLoadingContainer = forwardRef(
3379
3396
  function SLoadingContainer2({ open = false, message, zIndex = 1200, className, style }, ref) {
3380
3397
  const [mounted2, setMounted] = useState(false);
3381
3398
  useEffect(() => setMounted(true), []);
3399
+ useEffect(() => {
3400
+ if (!open) return;
3401
+ const prev = document.body.style.overflow;
3402
+ document.body.style.overflow = "hidden";
3403
+ return () => {
3404
+ document.body.style.overflow = prev;
3405
+ };
3406
+ }, [open]);
3382
3407
  const innerRef = useRef(null);
3383
3408
  const setRef = useCallback(
3384
3409
  (node) => {
@@ -3647,15 +3672,15 @@ var sanitizeInlineHtml = (value) => {
3647
3672
  return template.innerHTML;
3648
3673
  };
3649
3674
  var SIZE = {
3650
- xs: { height: 24, paddingX: 8, gap: 6, arrow: 12, fontSize: 12, minWidth: 44, splitMinWidth: 60 },
3675
+ xs: { height: 24, paddingX: 8, gap: 6, arrow: 12, fontSize: 12, minWidth: 64, splitMinWidth: 72 },
3651
3676
  sm: {
3652
3677
  height: 28,
3653
3678
  paddingX: 12,
3654
3679
  gap: 8,
3655
3680
  arrow: 12,
3656
3681
  fontSize: 12,
3657
- minWidth: 70,
3658
- splitMinWidth: 76
3682
+ minWidth: 72,
3683
+ splitMinWidth: 88
3659
3684
  },
3660
3685
  md: {
3661
3686
  height: 36,
@@ -3763,7 +3788,7 @@ var SDropdownButton = forwardRef(
3763
3788
  align: "start",
3764
3789
  alignOffset: split ? splitAlignOffset : 0,
3765
3790
  className: cn(
3766
- "z-50 overflow-hidden rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] py-[4px] shadow-normal-sm",
3791
+ "z-50 overflow-hidden rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] shadow-normal-sm",
3767
3792
  !split && "min-w-[var(--radix-dropdown-menu-trigger-width)]",
3768
3793
  FLOATING_SLIDE_ANIM
3769
3794
  ),
@@ -4060,7 +4085,8 @@ var HIDE_DELAY_MS = 100;
4060
4085
  function useBody(content, message = []) {
4061
4086
  if (content != null) return content;
4062
4087
  if (message.length === 0) return null;
4063
- return /* @__PURE__ */ jsx(Fragment, { children: message.map((line, i) => /* @__PURE__ */ jsx("div", { children: line }, i)) });
4088
+ const singleLine = message.length === 1;
4089
+ return /* @__PURE__ */ jsx(Fragment, { children: message.map((line, i) => /* @__PURE__ */ jsx("div", { className: singleLine ? "leading-[24px]" : void 0, children: line }, i)) });
4064
4090
  }
4065
4091
  var STooltip = forwardRef(function STooltip2({
4066
4092
  content,
@@ -4163,11 +4189,17 @@ var STooltip = forwardRef(function STooltip2({
4163
4189
  /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-[12px]", children: [
4164
4190
  /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: body }),
4165
4191
  useClose && /* @__PURE__ */ jsx(
4166
- RPopover2.Close,
4192
+ SGhostButton,
4167
4193
  {
4168
- "aria-label": "\uB2EB\uAE30",
4169
- className: "shrink-0 cursor-pointer opacity-70 hover:opacity-100",
4170
- children: /* @__PURE__ */ jsx(SIcon, { name: "close", size: 16, color: fg })
4194
+ icon: "close",
4195
+ size: "xs",
4196
+ intent: tooltipType === "default" ? "inverse" : "default",
4197
+ ariaLabel: "\uB2EB\uAE30",
4198
+ className: "shrink-0",
4199
+ onClick: () => {
4200
+ cancelHide();
4201
+ setOpen(false);
4202
+ }
4171
4203
  }
4172
4204
  )
4173
4205
  ] }),
@@ -4732,7 +4764,7 @@ function SActionModal({
4732
4764
  showClose: true,
4733
4765
  width,
4734
4766
  height,
4735
- className: "w-fit min-w-[480px]",
4767
+ className: "w-fit min-w-[480px] min-h-[320px]",
4736
4768
  children: /* @__PURE__ */ jsxs("div", { className: "flex h-full min-h-[320px] flex-col", children: [
4737
4769
  /* @__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 }) }),
4738
4770
  /* @__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 }),
@@ -4764,7 +4796,7 @@ function SActionModal({
4764
4796
  );
4765
4797
  }
4766
4798
  var DEFAULT_MESSAGE = {
4767
- loading: "",
4799
+ loading: "\uC791\uC5C5 \uC9C4\uD589\uC911...",
4768
4800
  error: "\uC791\uC5C5\uC5D0 \uC2E4\uD328\uD558\uC600\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD574 \uC8FC\uC138\uC694."
4769
4801
  };
4770
4802
  var DEFAULT_BUTTON_LABEL = {
@@ -4774,6 +4806,7 @@ var DEFAULT_BUTTON_LABEL = {
4774
4806
  function SLoadingModal({
4775
4807
  open,
4776
4808
  onOpenChange,
4809
+ onClose,
4777
4810
  persistent,
4778
4811
  state: state2 = "loading",
4779
4812
  progress,
@@ -4786,11 +4819,14 @@ function SLoadingModal({
4786
4819
  }) {
4787
4820
  const resolvedMessage = message ?? DEFAULT_MESSAGE[state2];
4788
4821
  const lines = Array.isArray(resolvedMessage) ? resolvedMessage : resolvedMessage ? [resolvedMessage] : [];
4822
+ const showButton = useButton || state2 === "error";
4789
4823
  return /* @__PURE__ */ jsx(
4790
4824
  SModalContainer,
4791
4825
  {
4792
4826
  open,
4793
4827
  onOpenChange,
4828
+ onClose,
4829
+ showClose: state2 === "error",
4794
4830
  persistent,
4795
4831
  ariaTitle: lines[0] || "\uB85C\uB529 \uC911",
4796
4832
  width,
@@ -4805,7 +4841,7 @@ function SLoadingModal({
4805
4841
  },
4806
4842
  i
4807
4843
  )) }),
4808
- useButton && /* @__PURE__ */ jsx(
4844
+ showButton && /* @__PURE__ */ jsx(
4809
4845
  SButton,
4810
4846
  {
4811
4847
  color: "neutral",
@@ -5036,7 +5072,7 @@ function SPagination({
5036
5072
  style,
5037
5073
  children: [
5038
5074
  /* @__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 }),
5039
- 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: [
5075
+ 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: [
5040
5076
  /* @__PURE__ */ jsx("span", { className: "font-bold text-[color:var(--cmp-pagination-item-content-selected)]", children: currentPage }),
5041
5077
  /* @__PURE__ */ jsx("span", { children: "/" }),
5042
5078
  /* @__PURE__ */ jsx("span", { children: lastPage })
@@ -5160,8 +5196,8 @@ function useFormField(field) {
5160
5196
  }, [ctx, name]);
5161
5197
  }
5162
5198
  var FIELD_SIZE = {
5163
- sm: { height: 28, radius: 4, fieldGap: 12, labelGap: 6, fontSize: 12, lineHeight: 20, icon: 12 },
5164
- md: { height: 36, radius: 6, fieldGap: 16, labelGap: 8, fontSize: 14, lineHeight: 24, icon: 12 }
5199
+ sm: { height: 28, radius: 4, fieldGap: 12, labelGap: 6, fontSize: 12, lineHeight: 20, icon: 16 },
5200
+ md: { height: 36, radius: 6, fieldGap: 16, labelGap: 8, fontSize: 14, lineHeight: 24, icon: 16 }
5165
5201
  };
5166
5202
  var ALIGN = {
5167
5203
  start: "flex-start",
@@ -5176,6 +5212,7 @@ var SField = forwardRef(function SField2({
5176
5212
  labelTooltip = "",
5177
5213
  labelTooltipProps,
5178
5214
  labelWidth,
5215
+ labelHeight,
5179
5216
  size = "sm",
5180
5217
  addonLabel = "",
5181
5218
  addonAlign = "start",
@@ -5190,6 +5227,7 @@ var SField = forwardRef(function SField2({
5190
5227
  readOnly = false,
5191
5228
  width,
5192
5229
  multiline = false,
5230
+ borderless = false,
5193
5231
  children,
5194
5232
  className,
5195
5233
  style,
@@ -5223,8 +5261,8 @@ var SField = forwardRef(function SField2({
5223
5261
  const resolvedSuccess = status === "pass";
5224
5262
  const showError = resolvedError && errorMessage !== "";
5225
5263
  const interactive = !disabled && !readOnly;
5226
- 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)";
5227
- const bgColor = disabled ? "var(--color-grey-30)" : readOnly ? "var(--sys-color-field-bg-readOnly)" : "var(--sys-color-field-bg-default)";
5264
+ 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)";
5265
+ const bgColor = borderless ? "transparent" : disabled ? "var(--color-grey-30)" : readOnly ? "var(--sys-color-field-bg-readOnly)" : "var(--sys-color-field-bg-default)";
5228
5266
  const textColor = disabled ? "var(--color-grey-65)" : readOnly ? "var(--sys-color-field-text-readOnly)" : "var(--sys-color-field-text-default)";
5229
5267
  return /* @__PURE__ */ jsx(
5230
5268
  "div",
@@ -5241,7 +5279,7 @@ var SField = forwardRef(function SField2({
5241
5279
  {
5242
5280
  className: "flex shrink-0 items-center font-bold text-(--sys-color-field-text-default)",
5243
5281
  style: {
5244
- height: s.height,
5282
+ height: cssLen(labelHeight) ?? s.height,
5245
5283
  marginRight: s.fieldGap,
5246
5284
  width: cssLen(labelWidth),
5247
5285
  fontSize: s.fontSize,
@@ -5267,14 +5305,14 @@ var SField = forwardRef(function SField2({
5267
5305
  {
5268
5306
  className: cn(
5269
5307
  "relative box-border flex min-w-0 items-stretch overflow-hidden border border-solid border-(--field-bc)",
5270
- 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]",
5308
+ 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]",
5271
5309
  disabled && "cursor-not-allowed"
5272
5310
  ),
5273
5311
  style: {
5274
5312
  // @ts-expect-error CSS 변수
5275
5313
  "--field-bc": borderColor,
5276
5314
  // focused/hovered prop이 명시된 경우 강조를 즉시 반영
5277
- ...interactive && focused ? { boxShadow: "0px 0px 4px 0px #0071ff66" } : {},
5315
+ ...interactive && !borderless && focused ? { boxShadow: "0px 0px 4px 0px #0071ff66" } : {},
5278
5316
  ...multiline ? { minHeight: s.height } : { height: s.height },
5279
5317
  "width": cssLen(width),
5280
5318
  "borderRadius": s.radius,
@@ -5319,15 +5357,28 @@ function flattenOptions(options, depth = 1) {
5319
5357
  const out = [];
5320
5358
  for (const o of options) {
5321
5359
  const hasChildren = Array.isArray(o.children) && o.children.length > 0;
5322
- out.push({
5323
- value: String(o.value),
5324
- label: o.label,
5325
- disabled: !!o.disabled,
5326
- depth,
5327
- isGroup: hasChildren,
5328
- raw: o.value
5329
- });
5330
- if (hasChildren) out.push(...flattenOptions(o.children, depth + 1));
5360
+ if (hasChildren) {
5361
+ const childFlat = flattenOptions(o.children, depth + 1);
5362
+ const allChildrenDisabled = childFlat.every((c) => c.disabled);
5363
+ out.push({
5364
+ value: String(o.value),
5365
+ label: o.label,
5366
+ disabled: !!o.disabled || allChildrenDisabled,
5367
+ depth,
5368
+ isGroup: true,
5369
+ raw: o.value
5370
+ });
5371
+ out.push(...childFlat);
5372
+ } else {
5373
+ out.push({
5374
+ value: String(o.value),
5375
+ label: o.label,
5376
+ disabled: !!o.disabled,
5377
+ depth,
5378
+ isGroup: false,
5379
+ raw: o.value
5380
+ });
5381
+ }
5331
5382
  }
5332
5383
  return out;
5333
5384
  }
@@ -5382,6 +5433,9 @@ var SSelect = forwardRef(function SSelect2({
5382
5433
  );
5383
5434
  const flat = useMemo(() => flattenOptions(options), [options]);
5384
5435
  const selectable = useMemo(() => selectableOptions(flat), [flat]);
5436
+ const hasLeaf = useMemo(() => flat.some((o) => !o.isGroup), [flat]);
5437
+ const allOptionsDisabled = hasLeaf && selectable.length === 0;
5438
+ const effectiveDisabled = disabled || allOptionsDisabled;
5385
5439
  const showSearch = useSearch && selectable.length >= SEARCH_THRESHOLD;
5386
5440
  const labelByValue = useMemo(() => new Map(flat.map((o) => [o.value, o.label])), [flat]);
5387
5441
  const rawByValue = useMemo(() => new Map(flat.map((o) => [o.value, o.raw])), [flat]);
@@ -5448,10 +5502,10 @@ var SSelect = forwardRef(function SSelect2({
5448
5502
  Ariakit.Select,
5449
5503
  {
5450
5504
  ref: triggerRef,
5451
- disabled,
5505
+ disabled: effectiveDisabled,
5452
5506
  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",
5453
5507
  style: {
5454
- color: disabled ? "var(--cmp-select-text-disabled)" : isPlaceholder ? "var(--cmp-select-icon-default)" : "var(--cmp-select-text-default)"
5508
+ color: effectiveDisabled ? "var(--cmp-select-text-disabled)" : isPlaceholder ? "var(--cmp-select-icon-default)" : "var(--cmp-select-text-default)"
5455
5509
  },
5456
5510
  children: [
5457
5511
  isHtmlLabel(triggerText) ? /* @__PURE__ */ jsx(
@@ -5466,7 +5520,7 @@ var SSelect = forwardRef(function SSelect2({
5466
5520
  {
5467
5521
  name: "chevronDown",
5468
5522
  size: 12,
5469
- color: disabled ? "var(--cmp-select-icon-disabled)" : "var(--cmp-select-icon-default)",
5523
+ color: effectiveDisabled ? "var(--cmp-select-icon-disabled)" : "var(--cmp-select-icon-default)",
5470
5524
  className: cn("shrink-0 transition-transform duration-200", open && "rotate-180")
5471
5525
  }
5472
5526
  )
@@ -5480,7 +5534,7 @@ var SSelect = forwardRef(function SSelect2({
5480
5534
  portalElement: portalContainer,
5481
5535
  gutter: 4,
5482
5536
  sameWidth: !dropdownWidth,
5483
- 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",
5537
+ className: "z-50 overflow-auto rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] shadow-[2px_2px_12px_2px_rgba(0,0,0,0.1)] data-[enter]:animate-floating-in-bottom data-[leave]:animate-floating-out-bottom",
5484
5538
  style: {
5485
5539
  maxHeight: dropdownHeight,
5486
5540
  ...dropdownWidth ? { width: dropdownWidth } : {},
@@ -5521,7 +5575,7 @@ var SSelect = forwardRef(function SSelect2({
5521
5575
  ),
5522
5576
  hasItems ? /* @__PURE__ */ jsx(ItemList, { items: filtered, multi, selected, useSearch: showSearch }) : (
5523
5577
  // 원본 sd-select-listbox__empty (표시할 항목이 없을 때)
5524
- /* @__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." })
5578
+ /* @__PURE__ */ jsx("div", { className: "px-[12px] py-[12px] text-left text-[12px] leading-[20px] text-[color:var(--cmp-listItem-content-disabled)]", children: "\uD45C\uC2DC\uD560 \uD56D\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4." })
5525
5579
  )
5526
5580
  ]
5527
5581
  }
@@ -5544,7 +5598,7 @@ var SSelect = forwardRef(function SSelect2({
5544
5598
  error: error || ruleError !== "",
5545
5599
  status: rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0,
5546
5600
  errorMessage: ruleError !== "" ? ruleError : errorMessage,
5547
- disabled,
5601
+ disabled: effectiveDisabled,
5548
5602
  width,
5549
5603
  className,
5550
5604
  style,
@@ -5579,7 +5633,11 @@ function ItemList({
5579
5633
  {
5580
5634
  className: cn(
5581
5635
  "select-none py-[4px] pr-[12px] text-[12px] leading-[20px] text-[color:var(--cmp-listItem-content-default)]",
5582
- 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"
5636
+ isDepth1 ? "border-t border-solid border-[color:var(--cmp-listItem-depth1-border-color)] bg-[var(--cmp-listItem-depth1-bg-default)] font-bold" : "bg-[var(--cmp-listItem-depth2-middle-bg)] font-medium",
5637
+ // 하위가 전부 비활성이면(select.config 에서 bubble-up) 어미 그룹도 비활성 처리:
5638
+ // 텍스트는 회색(#888), depth1 그룹은 파란 배경 대신 회색(#EEE)으로 (depth2 는 #F6F6F6 유지)
5639
+ o.disabled && "cursor-not-allowed text-[color:var(--cmp-listItem-content-disabled)]",
5640
+ o.disabled && isDepth1 && "bg-[var(--cmp-listItem-depth1-bg-disabled)]"
5583
5641
  ),
5584
5642
  style: { paddingLeft: padLeft },
5585
5643
  children: o.label
@@ -5593,10 +5651,14 @@ function ItemList({
5593
5651
  {
5594
5652
  value: o.value,
5595
5653
  disabled: o.disabled,
5654
+ accessibleWhenDisabled: true,
5596
5655
  className: cn(
5597
5656
  itemBase,
5598
5657
  isSelected && !multi && "font-bold text-[color:var(--cmp-listItem-content-selected)]",
5599
- activeClass
5658
+ // Ariakit은 disabled 항목도 hover 시 active(data-active-item) 처리하므로,
5659
+ // 비활성 항목에는 hover 하이라이트를 적용하지 않아 회색 비활성 스타일을 유지한다.
5660
+ // (원본 Stencil의 `--focused...:not(--disabled)` 규칙과 동일한 의도)
5661
+ !o.disabled && activeClass
5600
5662
  ),
5601
5663
  style: { paddingTop: 4, paddingBottom: 4, paddingRight: 12, paddingLeft: padLeft },
5602
5664
  render: useSearch ? /* @__PURE__ */ jsx(Ariakit.ComboboxItem, {}) : void 0,
@@ -5606,15 +5668,21 @@ function ItemList({
5606
5668
  "span",
5607
5669
  {
5608
5670
  className: cn(
5609
- "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)]",
5610
- 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"
5671
+ "flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center rounded-[2px] border border-solid",
5672
+ o.disabled ? (
5673
+ // 비활성: 회색 채움(#E1E1E1) + 회색 테두리(#CCCCCC)
5674
+ "cursor-not-allowed border-[color:var(--cmp-checkbox-border-disabled)] bg-[var(--cmp-checkbox-bg-disabled)]"
5675
+ ) : cn(
5676
+ "group-data-[active-item]:border-[color:var(--cmp-checkbox-checked-border-inverse)]",
5677
+ isSelected ? "border-[color:var(--cmp-checkbox-checked-bg-default)] bg-[var(--cmp-checkbox-checked-bg-default)] group-data-[active-item]:bg-transparent" : "border-[color:var(--cmp-checkbox-unchecked-border-default)] bg-transparent"
5678
+ )
5611
5679
  ),
5612
5680
  children: isSelected && /* @__PURE__ */ jsx(
5613
5681
  SIcon,
5614
5682
  {
5615
5683
  name: "checkboxCheck",
5616
5684
  size: 12,
5617
- color: "var(--cmp-checkbox-checked-icon-default)"
5685
+ color: o.disabled ? "var(--cmp-checkbox-checked-icon-disabled)" : "var(--cmp-checkbox-checked-icon-default)"
5618
5686
  }
5619
5687
  )
5620
5688
  }
@@ -5905,7 +5973,8 @@ var STable = forwardRef(function STable2({
5905
5973
  else onSelectedChange?.([...selected, row]);
5906
5974
  };
5907
5975
  const radiusClass = radius === "full" ? "rounded-none" : radius === "useTop" ? "rounded-b-[var(--cmp-table-radius)] rounded-t-none" : "rounded-[var(--cmp-table-radius)]";
5908
- const cellPadY = dense ? "var(--cmp-table-body-dense-paddingY)" : "var(--cmp-table-body-default-paddingY)";
5976
+ const cellPadY = dense ? "var(--cmp-table-body-paddingY-dense)" : "var(--cmp-table-body-paddingY-default)";
5977
+ const cellPadX = dense ? "var(--cmp-table-body-paddingX-default)" : "var(--cmp-table-body-paddingX-wide)";
5909
5978
  const rowH = dense ? "var(--cmp-table-body-dense-height)" : "var(--cmp-table-body-default-height)";
5910
5979
  const totalColSpan = visibleCols.length + (selectable ? 1 : 0);
5911
5980
  const stickyInfo = (i) => {
@@ -6080,13 +6149,15 @@ var STable = forwardRef(function STable2({
6080
6149
  className: cn(
6081
6150
  // 원본 .td: 컬럼 폭에 맞춰 내용 말줄임(overflow hidden + ellipsis) + 행 구분선(border-b)
6082
6151
  // 셀 배경은 흰색으로 채워 뒤 배경이 비치지 않게 하고, hover 시 행 배경(grey_05)을 따른다.
6083
- "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)]",
6152
+ "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)]",
6084
6153
  rowBg,
6085
6154
  "group-hover:bg-[var(--color-grey-05)]",
6086
6155
  stickyShadowClass(i),
6087
6156
  col.tdClass
6088
6157
  ),
6089
6158
  style: {
6159
+ paddingLeft: cellPadX,
6160
+ paddingRight: cellPadX,
6090
6161
  paddingTop: cellPadY,
6091
6162
  paddingBottom: cellPadY,
6092
6163
  textAlign: col.align ?? "left",
@@ -6393,8 +6464,8 @@ var STextarea = forwardRef(function STextarea2({
6393
6464
  );
6394
6465
  });
6395
6466
  var PAD2 = {
6396
- sm: { fontSize: 12, stepper: 20, icon: 12 },
6397
- md: { fontSize: 14, stepper: 24, icon: 14 }
6467
+ sm: { fontSize: 12, lineHeight: 20, stepper: 20, icon: 12 },
6468
+ md: { fontSize: 14, lineHeight: 24, stepper: 24, icon: 14 }
6398
6469
  };
6399
6470
  var toNumber = (val) => {
6400
6471
  if (val === null || val === void 0 || val === "") return null;
@@ -6412,6 +6483,38 @@ var formatWithCommas = (value) => {
6412
6483
  const result = isNeg ? "-" + formatted : formatted;
6413
6484
  return decPart !== void 0 && decPart !== "" ? result + "." + decPart : result;
6414
6485
  };
6486
+ var addCommas = (value) => value.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
6487
+ var formatInputWithCommas = (value) => {
6488
+ const isNeg = value.startsWith("-");
6489
+ const unsigned = isNeg ? value.slice(1) : value;
6490
+ const hasDecimal = unsigned.includes(".");
6491
+ const [intPart = "", decPart = ""] = unsigned.split(".");
6492
+ const formattedInt = addCommas(intPart === "" ? "0" : intPart);
6493
+ return `${isNeg ? "-" : ""}${formattedInt}${hasDecimal ? `.${decPart}` : ""}`;
6494
+ };
6495
+ var getDecimalLimit = (useDecimal, maxDecimalLength) => {
6496
+ if (!useDecimal || maxDecimalLength === void 0 || !Number.isFinite(maxDecimalLength)) {
6497
+ return void 0;
6498
+ }
6499
+ return Math.max(0, Math.floor(maxDecimalLength));
6500
+ };
6501
+ var applyDecimalLimit = (value, decimalLimit) => {
6502
+ if (value === null || decimalLimit === void 0) return value;
6503
+ return Number(value.toFixed(decimalLimit));
6504
+ };
6505
+ var getLogicalCaret = (value, caret) => {
6506
+ return value.slice(0, caret ?? value.length).replace(/,/g, "").length;
6507
+ };
6508
+ var getDisplayCaret = (value, logicalCaret) => {
6509
+ if (logicalCaret <= 0) return 0;
6510
+ let seen = 0;
6511
+ for (let i = 0; i < value.length; i += 1) {
6512
+ if (value[i] === ",") continue;
6513
+ seen += 1;
6514
+ if (seen >= logicalCaret) return i + 1;
6515
+ }
6516
+ return value.length;
6517
+ };
6415
6518
  var SNumberInput = forwardRef(function SNumberInput2({
6416
6519
  value,
6417
6520
  onValueChange,
@@ -6421,6 +6524,7 @@ var SNumberInput = forwardRef(function SNumberInput2({
6421
6524
  step = 1,
6422
6525
  useButton = false,
6423
6526
  useDecimal = false,
6527
+ maxDecimalLength,
6424
6528
  inputPrefix = "",
6425
6529
  inputSuffix = "",
6426
6530
  inputClass,
@@ -6452,7 +6556,8 @@ var SNumberInput = forwardRef(function SNumberInput2({
6452
6556
  }, ref) {
6453
6557
  const p = PAD2[size];
6454
6558
  const padX = `var(--cmp-numberInput-${size}-paddingX)`;
6455
- const numValue = toNumber(value);
6559
+ const decimalLimit = getDecimalLimit(useDecimal, maxDecimalLength);
6560
+ const numValue = applyDecimalLimit(toNumber(value), decimalLimit);
6456
6561
  const [display, setDisplay] = useState(() => formatWithCommas(numValue));
6457
6562
  const [ruleError, setRuleError] = useState("");
6458
6563
  const innerRef = useRef(null);
@@ -6462,8 +6567,9 @@ var SNumberInput = forwardRef(function SNumberInput2({
6462
6567
  else if (ref) ref.current = el;
6463
6568
  };
6464
6569
  useEffect(() => {
6465
- setDisplay(formatWithCommas(toNumber(value)));
6466
- }, [value]);
6570
+ if (document.activeElement === innerRef.current) return;
6571
+ setDisplay(formatWithCommas(applyDecimalLimit(toNumber(value), decimalLimit)));
6572
+ }, [decimalLimit, value]);
6467
6573
  useFormField({
6468
6574
  name,
6469
6575
  validate: () => {
@@ -6475,48 +6581,87 @@ var SNumberInput = forwardRef(function SNumberInput2({
6475
6581
  });
6476
6582
  const resolvedError = error || ruleError !== "";
6477
6583
  const resolvedStatus = status ?? (rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0);
6478
- const emit2 = (n) => {
6479
- setDisplay(formatWithCommas(n));
6480
- onValueChange?.(n);
6584
+ const restoreCaret = (nextDisplay, logicalCaret) => {
6585
+ const input = innerRef.current;
6586
+ if (logicalCaret === void 0 || !input || document.activeElement !== input) return;
6587
+ const nextCaret = getDisplayCaret(nextDisplay, logicalCaret);
6588
+ requestAnimationFrame(() => {
6589
+ if (document.activeElement !== input) return;
6590
+ input.setSelectionRange(nextCaret, nextCaret);
6591
+ });
6592
+ };
6593
+ const setDisplayWithCaret = (nextDisplay, logicalCaret) => {
6594
+ setDisplay(nextDisplay);
6595
+ restoreCaret(nextDisplay, logicalCaret);
6596
+ };
6597
+ const resetRejectedInput = (target, logicalCaret) => {
6598
+ target.value = display;
6599
+ restoreCaret(display, Math.min(logicalCaret, display.replace(/,/g, "").length));
6600
+ };
6601
+ const emit2 = (n, logicalCaret) => {
6602
+ const next = applyDecimalLimit(n, decimalLimit);
6603
+ const nextDisplay = formatWithCommas(next);
6604
+ setDisplayWithCaret(nextDisplay, logicalCaret);
6605
+ onValueChange?.(next);
6481
6606
  };
6482
6607
  const incDisabled = disabled || readOnly || numValue !== null && numValue >= max;
6483
6608
  const decDisabled = disabled || readOnly || numValue !== null && numValue <= min;
6484
6609
  const increment = () => {
6485
6610
  if (incDisabled) return;
6486
6611
  const cur = numValue ?? (min === Number.NEGATIVE_INFINITY ? 0 : min);
6487
- const next = Math.min(cur + step, max);
6612
+ const next = applyDecimalLimit(Math.min(cur + step, max), decimalLimit);
6488
6613
  if (next !== cur) emit2(next);
6489
6614
  };
6490
6615
  const decrement = () => {
6491
6616
  if (decDisabled) return;
6492
6617
  const cur = numValue ?? (min === Number.NEGATIVE_INFINITY ? 0 : min);
6493
- const next = Math.max(cur - step, min);
6618
+ const next = applyDecimalLimit(Math.max(cur - step, min), decimalLimit);
6494
6619
  if (next !== cur) emit2(next);
6495
6620
  };
6496
- const handleInput = (raw) => {
6621
+ const handleInput = (event) => {
6622
+ const target = event.currentTarget;
6623
+ const raw = target.value;
6624
+ const logicalCaret = getLogicalCaret(raw, target.selectionStart);
6497
6625
  if (raw === "") {
6498
- setDisplay("");
6626
+ setDisplayWithCaret("", 0);
6499
6627
  onValueChange?.(null);
6500
6628
  return;
6501
6629
  }
6502
6630
  const cleaned = raw.replace(/,/g, "");
6503
6631
  const decimals = (cleaned.match(/\./g) || []).length;
6504
- if (decimals > 1) return;
6632
+ if (decimals > 1) {
6633
+ resetRejectedInput(target, logicalCaret);
6634
+ return;
6635
+ }
6505
6636
  if (cleaned === "-" || cleaned === "." || cleaned === "-.") {
6506
- setDisplay(cleaned);
6637
+ setDisplayWithCaret(cleaned, logicalCaret);
6638
+ return;
6639
+ }
6640
+ if (!useDecimal && cleaned.includes(".")) {
6641
+ resetRejectedInput(target, logicalCaret);
6507
6642
  return;
6508
6643
  }
6509
- if (!useDecimal && cleaned.includes(".")) return;
6644
+ if (decimalLimit !== void 0 && cleaned.includes(".")) {
6645
+ const fraction = cleaned.split(".")[1] ?? "";
6646
+ if (fraction.length > decimalLimit) {
6647
+ resetRejectedInput(target, logicalCaret);
6648
+ return;
6649
+ }
6650
+ }
6510
6651
  if (cleaned.endsWith(".") && decimals === 1) {
6511
6652
  const parsed2 = toNumber(cleaned.slice(0, -1));
6512
6653
  if (parsed2 !== null) {
6513
- setDisplay(formatWithCommas(parsed2) + ".");
6654
+ setDisplayWithCaret(formatInputWithCommas(cleaned), logicalCaret);
6514
6655
  return;
6515
6656
  }
6516
6657
  }
6517
6658
  const parsed = toNumber(cleaned);
6518
- if (parsed === null) return;
6519
- emit2(parsed);
6659
+ if (parsed === null) {
6660
+ resetRejectedInput(target, logicalCaret);
6661
+ return;
6662
+ }
6663
+ setDisplayWithCaret(formatInputWithCommas(cleaned), logicalCaret);
6664
+ onValueChange?.(applyDecimalLimit(parsed, decimalLimit));
6520
6665
  };
6521
6666
  const stepper = (dir) => {
6522
6667
  const off = dir === "inc" ? incDisabled : decDisabled;
@@ -6529,8 +6674,8 @@ var SNumberInput = forwardRef(function SNumberInput2({
6529
6674
  "aria-label": dir === "inc" ? "\uC99D\uAC00" : "\uAC10\uC18C",
6530
6675
  onClick: dir === "inc" ? increment : decrement,
6531
6676
  className: cn(
6532
- "flex flex-shrink-0 items-center justify-center",
6533
- off ? "cursor-not-allowed" : "cursor-pointer"
6677
+ "flex flex-shrink-0 items-center justify-center border border-solid border-transparent transition-colors",
6678
+ off ? "cursor-not-allowed" : "cursor-pointer hover:border-[var(--color-border-accentLight)]"
6534
6679
  ),
6535
6680
  style: {
6536
6681
  width: `var(--cmp-numberInput-stepper-${size}-size)`,
@@ -6579,24 +6724,26 @@ var SNumberInput = forwardRef(function SNumberInput2({
6579
6724
  style: {
6580
6725
  // 원본 sd-number-input: content gap = padding-x 토큰 (gap 토큰 아님)
6581
6726
  gap: `var(--cmp-numberInput-${size}-paddingX)`,
6582
- padding: `0 ${useButton ? padX : `calc(${padX} * 2)`}`
6727
+ padding: `0 ${useButton ? padX : `calc(${padX} * 2)`}`,
6728
+ fontSize: p.fontSize,
6729
+ lineHeight: `${p.lineHeight}px`
6583
6730
  },
6584
6731
  children: [
6585
6732
  useButton && stepper("dec"),
6586
- inputPrefix !== "" && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", style: { fontSize: p.fontSize, color: affixColor }, children: inputPrefix }),
6733
+ inputPrefix !== "" && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", style: { color: affixColor }, children: inputPrefix }),
6587
6734
  /* @__PURE__ */ jsx(
6588
6735
  "input",
6589
6736
  {
6590
6737
  ref: setRefs,
6591
6738
  name,
6592
6739
  type: "text",
6593
- inputMode: "numeric",
6740
+ inputMode: useDecimal ? "decimal" : "numeric",
6594
6741
  value: display,
6595
6742
  placeholder,
6596
6743
  disabled,
6597
6744
  readOnly,
6598
6745
  autoFocus,
6599
- onChange: (e) => handleInput(e.target.value),
6746
+ onChange: handleInput,
6600
6747
  onKeyDown: (e) => {
6601
6748
  if (e.key === "ArrowUp") {
6602
6749
  e.preventDefault();
@@ -6608,26 +6755,29 @@ var SNumberInput = forwardRef(function SNumberInput2({
6608
6755
  },
6609
6756
  onFocus: (e) => onFocus?.(e),
6610
6757
  onBlur: (e) => {
6611
- const n = toNumber(display);
6758
+ const cleaned = display.replace(/,/g, "");
6759
+ const n = toNumber(cleaned);
6612
6760
  const clamped = n === null ? null : Math.min(Math.max(n, min), max);
6613
6761
  if (clamped !== n) emit2(clamped);
6614
- else setDisplay(formatWithCommas(n));
6762
+ else setDisplay(n === null ? "" : formatInputWithCommas(cleaned));
6615
6763
  if (rules && rules.length > 0) setRuleError(runRules(clamped, rules));
6616
6764
  onBlur?.(e);
6617
6765
  },
6618
6766
  className: cn(
6619
- "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",
6767
+ // h-full 대신 라인박스 높이 그대로 두어 prefix/suffix 동일하게 flex 로 수직 센터링
6768
+ // (h-full 이면 input 내부 텍스트 센터링을 브라우저가 수행해 1px 어긋날 수 있음)
6769
+ "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",
6620
6770
  inputClass
6621
6771
  ),
6622
6772
  style: {
6623
- fontSize: p.fontSize,
6773
+ // fontSize/lineHeight 는 컨테이너에서 상속
6624
6774
  textAlign: useButton ? "center" : "right",
6625
6775
  color: disabled ? "var(--cmp-numberInput-text-disabled)" : "var(--cmp-numberInput-text-default)",
6626
6776
  ...inputStyle
6627
6777
  }
6628
6778
  }
6629
6779
  ),
6630
- inputSuffix !== "" && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", style: { fontSize: p.fontSize, color: affixColor }, children: inputSuffix }),
6780
+ inputSuffix !== "" && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", style: { color: affixColor }, children: inputSuffix }),
6631
6781
  useButton && stepper("inc")
6632
6782
  ]
6633
6783
  }
@@ -6741,7 +6891,7 @@ function SRadioGroup({
6741
6891
  role: "radiogroup",
6742
6892
  className: cn(
6743
6893
  "inline-flex",
6744
- direction === "vertical" ? "flex-col gap-[8px]" : "flex-row gap-[20px]",
6894
+ direction === "vertical" ? "flex-col gap-[var(--cmp-radio-group-gap-vertical)]" : "flex-row gap-[var(--cmp-radio-group-gap-horizontal)]",
6745
6895
  className
6746
6896
  ),
6747
6897
  style,
@@ -6953,7 +7103,7 @@ function SCalendar({
6953
7103
  "span",
6954
7104
  {
6955
7105
  className: cn(
6956
- "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]",
7106
+ "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)]",
6957
7107
  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)]",
6958
7108
  isToday && !disabled && "font-bold"
6959
7109
  ),
@@ -7143,6 +7293,7 @@ function RangeCalendar({
7143
7293
  selectable,
7144
7294
  maxRange,
7145
7295
  onSelect,
7296
+ onPendingStartChange,
7146
7297
  onViewChange
7147
7298
  }) {
7148
7299
  const today = todayStr();
@@ -7205,9 +7356,11 @@ function RangeCalendar({
7205
7356
  setStart(d);
7206
7357
  setEnd(null);
7207
7358
  setHover(null);
7359
+ onPendingStartChange?.(d);
7208
7360
  return;
7209
7361
  }
7210
7362
  setEnd(d);
7363
+ onPendingStartChange?.(null);
7211
7364
  onSelect([start, d]);
7212
7365
  };
7213
7366
  const GRID_COLS = "grid grid-cols-[repeat(7,var(--cmp-datepicker-calendar-day-width))]";
@@ -7342,8 +7495,11 @@ function SDateRangePicker({
7342
7495
  const portalContainer = usePortalContainer();
7343
7496
  const [open, setOpen] = useState(false);
7344
7497
  const [ruleError, setRuleError] = useState("");
7498
+ const [pendingStart, setPendingStart] = useState(null);
7345
7499
  const hasValue = value != null && value[0] !== "" && value[1] !== "";
7346
- const display = hasValue ? `${value[0]} ~ ${value[1]}` : placeholder;
7500
+ const hasDisplay = pendingStart != null || hasValue;
7501
+ const startText = pendingStart ?? (hasValue ? value[0] : "");
7502
+ const endText = pendingStart ? "" : hasValue ? value[1] : "";
7347
7503
  useFormField({
7348
7504
  name,
7349
7505
  validate: () => {
@@ -7357,6 +7513,7 @@ function SDateRangePicker({
7357
7513
  const resolvedStatus = status ?? (rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0);
7358
7514
  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 };
7359
7515
  const select = (r) => {
7516
+ setPendingStart(null);
7360
7517
  onValueChange?.(r);
7361
7518
  if (rules && rules.length > 0) setRuleError(runRules(r, rules));
7362
7519
  setOpen(false);
@@ -7381,61 +7538,80 @@ function SDateRangePicker({
7381
7538
  disabled,
7382
7539
  className,
7383
7540
  style,
7384
- children: /* @__PURE__ */ jsxs(RPopover2.Root, { open, onOpenChange: (o) => !disabled && setOpen(o), children: [
7385
- /* @__PURE__ */ jsx(RPopover2.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
7386
- "button",
7387
- {
7388
- type: "button",
7389
- name,
7390
- disabled,
7391
- className: "flex h-full w-full items-center overflow-hidden bg-transparent outline-none disabled:cursor-not-allowed",
7392
- style: { padding: `0 ${dims.padX}px`, gap: dims.gap, borderRadius: dims.radius },
7393
- children: [
7394
- /* @__PURE__ */ jsx(
7395
- SIcon,
7396
- {
7397
- name: "date",
7398
- size: dims.icon,
7399
- color: disabled ? "var(--cmp-datepicker-icon-disabled)" : "var(--cmp-datepicker-icon-default)",
7400
- className: "flex-shrink-0"
7401
- }
7402
- ),
7403
- /* @__PURE__ */ jsx(
7404
- "span",
7405
- {
7406
- className: "flex-1 truncate text-center",
7407
- style: {
7408
- minWidth: dims.minW,
7409
- fontSize: dims.fontSize,
7410
- lineHeight: `${dims.lineHeight}px`,
7411
- color: disabled ? "var(--cmp-datepicker-text-disabled)" : hasValue ? "var(--cmp-datepicker-text-default)" : "var(--cmp-field-hint-color)"
7412
- },
7413
- children: display
7414
- }
7415
- )
7416
- ]
7417
- }
7418
- ) }),
7419
- /* @__PURE__ */ jsx(RPopover2.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
7420
- RPopover2.Content,
7421
- {
7422
- side: "bottom",
7423
- align: "start",
7424
- sideOffset: 4,
7425
- className: cn("z-50", FLOATING_SLIDE_ANIM),
7426
- children: /* @__PURE__ */ jsx(
7427
- RangeCalendar,
7541
+ children: /* @__PURE__ */ jsxs(
7542
+ RPopover2.Root,
7543
+ {
7544
+ open,
7545
+ onOpenChange: (o) => {
7546
+ if (disabled) return;
7547
+ setOpen(o);
7548
+ if (!o) setPendingStart(null);
7549
+ },
7550
+ children: [
7551
+ /* @__PURE__ */ jsx(RPopover2.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
7552
+ "button",
7428
7553
  {
7429
- value: value ?? null,
7430
- selectable,
7431
- maxRange,
7432
- onSelect: select,
7433
- onViewChange
7554
+ type: "button",
7555
+ name,
7556
+ disabled,
7557
+ className: "flex h-full w-full items-center overflow-hidden bg-transparent outline-none disabled:cursor-not-allowed",
7558
+ style: { padding: `0 ${dims.padX}px`, gap: dims.gap, borderRadius: dims.radius },
7559
+ children: [
7560
+ /* @__PURE__ */ jsx(
7561
+ SIcon,
7562
+ {
7563
+ name: "date",
7564
+ size: dims.icon,
7565
+ color: disabled ? "var(--cmp-datepicker-icon-disabled)" : "var(--cmp-datepicker-icon-default)",
7566
+ className: "flex-shrink-0"
7567
+ }
7568
+ ),
7569
+ /* @__PURE__ */ jsx(
7570
+ "span",
7571
+ {
7572
+ className: cn(
7573
+ "flex-1 items-center",
7574
+ hasDisplay ? "flex" : "block truncate text-center"
7575
+ ),
7576
+ style: {
7577
+ minWidth: dims.minW,
7578
+ fontSize: dims.fontSize,
7579
+ lineHeight: `${dims.lineHeight}px`,
7580
+ color: disabled ? "var(--cmp-datepicker-text-disabled)" : hasDisplay ? "var(--cmp-datepicker-text-default)" : "var(--cmp-field-hint-color)"
7581
+ },
7582
+ children: hasDisplay ? /* @__PURE__ */ jsxs(Fragment, { children: [
7583
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-right", children: startText }),
7584
+ /* @__PURE__ */ jsx("span", { className: "px-[4px]", children: "~" }),
7585
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-left", children: endText })
7586
+ ] }) : placeholder
7587
+ }
7588
+ )
7589
+ ]
7434
7590
  }
7435
- )
7436
- }
7437
- ) })
7438
- ] })
7591
+ ) }),
7592
+ /* @__PURE__ */ jsx(RPopover2.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
7593
+ RPopover2.Content,
7594
+ {
7595
+ side: "bottom",
7596
+ align: "start",
7597
+ sideOffset: 4,
7598
+ className: cn("z-50", FLOATING_SLIDE_ANIM),
7599
+ children: /* @__PURE__ */ jsx(
7600
+ RangeCalendar,
7601
+ {
7602
+ value: value ?? null,
7603
+ selectable,
7604
+ maxRange,
7605
+ onSelect: select,
7606
+ onPendingStartChange: setPendingStart,
7607
+ onViewChange
7608
+ }
7609
+ )
7610
+ }
7611
+ ) })
7612
+ ]
7613
+ }
7614
+ )
7439
7615
  }
7440
7616
  );
7441
7617
  }
@@ -7444,7 +7620,7 @@ var SChip = forwardRef(function SChip2({
7444
7620
  value = "",
7445
7621
  error: errorProp = false,
7446
7622
  disabled = false,
7447
- editable = true,
7623
+ editable = false,
7448
7624
  showRemove = true,
7449
7625
  placeholder = "",
7450
7626
  rules,
@@ -7597,6 +7773,7 @@ function SFilePicker({
7597
7773
  hovered = false,
7598
7774
  inline = false,
7599
7775
  multiple = false,
7776
+ useMultipleListBox = false,
7600
7777
  accept,
7601
7778
  maxFileSize,
7602
7779
  maxTotalSize,
@@ -7622,10 +7799,13 @@ function SFilePicker({
7622
7799
  const autoId = useId();
7623
7800
  const resolvedName = name ?? autoId;
7624
7801
  const inputRef = useRef(null);
7802
+ const contentBoxRef = useRef(null);
7625
7803
  const [ruleError, setRuleError] = useState("");
7804
+ const [listOpen, setListOpen] = useState(false);
7805
+ const portalContainer = usePortalContainer();
7626
7806
  const files = multiple ? Array.isArray(value) ? value : [] : value && !Array.isArray(value) ? value : null;
7627
- const hasSingle = !multiple && !!files;
7628
- const displayText = hasSingle ? files.name : placeholder;
7807
+ const hasFiles = multiple ? files.length > 0 : !!files;
7808
+ const displayText = !hasFiles ? placeholder : multiple ? files.map((f) => f.name).join(", ") : files.name;
7629
7809
  useFormField({
7630
7810
  name,
7631
7811
  validate: () => {
@@ -7676,10 +7856,12 @@ function SFilePicker({
7676
7856
  e.stopPropagation();
7677
7857
  if (disabled) return;
7678
7858
  onValueChange?.(multiple ? [] : null);
7859
+ setListOpen(false);
7679
7860
  };
7680
7861
  const removeChip = (i) => {
7681
7862
  const next = files.filter((_, idx) => idx !== i);
7682
7863
  onValueChange?.(next);
7864
+ if (next.length === 0) setListOpen(false);
7683
7865
  };
7684
7866
  const open = () => {
7685
7867
  if (!disabled) inputRef.current?.click();
@@ -7689,78 +7871,100 @@ function SFilePicker({
7689
7871
  const padX = size === "md" ? "var(--cmp-filepicker-md-paddingX)" : "var(--cmp-filepicker-sm-paddingX)";
7690
7872
  const iconSize = size === "md" ? 20 : 16;
7691
7873
  const gapCls = size === "md" ? "gap-[var(--cmp-filepicker-md-gap)]" : "gap-[var(--cmp-filepicker-sm-gap)]";
7692
- const content = /* @__PURE__ */ jsxs("div", { className: cn("flex h-full w-full items-center", gapCls), style: { padding: `0 ${padX}` }, children: [
7874
+ const inlinePlaceholder = inline && !disabled && !hasFiles;
7875
+ const showListbox = multiple && useMultipleListBox;
7876
+ const filesArr = multiple ? files : [];
7877
+ const contentInner = /* @__PURE__ */ jsxs(
7878
+ "div",
7879
+ {
7880
+ ref: contentBoxRef,
7881
+ className: cn("group/filepicker flex h-full w-full items-center", gapCls),
7882
+ style: { padding: inline ? 0 : `0 ${padX}` },
7883
+ children: [
7884
+ /* @__PURE__ */ jsx(
7885
+ "input",
7886
+ {
7887
+ ref: inputRef,
7888
+ type: "file",
7889
+ className: "hidden",
7890
+ disabled,
7891
+ multiple,
7892
+ accept,
7893
+ name: resolvedName,
7894
+ onChange,
7895
+ "aria-label": placeholder
7896
+ }
7897
+ ),
7898
+ /* @__PURE__ */ jsxs(
7899
+ "button",
7900
+ {
7901
+ type: "button",
7902
+ disabled,
7903
+ onClick: open,
7904
+ "aria-label": placeholder,
7905
+ className: cn(
7906
+ "flex min-w-0 flex-1 items-center bg-transparent text-left",
7907
+ gapCls,
7908
+ disabled ? "cursor-not-allowed" : "cursor-pointer"
7909
+ ),
7910
+ children: [
7911
+ /* @__PURE__ */ jsx(
7912
+ SIcon,
7913
+ {
7914
+ name: "attachFile",
7915
+ size: iconSize,
7916
+ color: disabled ? "var(--cmp-filepicker-icon-disabled)" : "var(--color-grey-65)"
7917
+ }
7918
+ ),
7919
+ /* @__PURE__ */ jsx(
7920
+ "span",
7921
+ {
7922
+ className: cn(
7923
+ "min-w-0 flex-1 truncate text-[12px]",
7924
+ inlinePlaceholder && "text-[color:var(--cmp-filepicker-text-placeholder)] transition-colors group-hover/filepicker:text-[color:var(--cmp-filepicker-text-default)]"
7925
+ ),
7926
+ style: inlinePlaceholder ? void 0 : {
7927
+ color: disabled ? "var(--cmp-filepicker-text-disabled)" : hasFiles ? "var(--cmp-filepicker-text-default)" : "var(--cmp-filepicker-text-placeholder)"
7928
+ },
7929
+ children: displayText
7930
+ }
7931
+ )
7932
+ ]
7933
+ }
7934
+ ),
7935
+ showListbox && hasFiles && !disabled && /* @__PURE__ */ jsx(
7936
+ Ariakit.PopoverDisclosure,
7937
+ {
7938
+ render: /* @__PURE__ */ jsx(SGhostButton, { icon: "caretDown", size: "xxs", ariaLabel: "toggle file list" }),
7939
+ className: cn("shrink-0 transition-transform duration-150", listOpen && "rotate-180")
7940
+ }
7941
+ ),
7942
+ !disabled && hasFiles && /* @__PURE__ */ jsx(SGhostButton, { icon: "close", size: "xxs", ariaLabel: "clear", onClick: clear })
7943
+ ]
7944
+ }
7945
+ );
7946
+ const content = showListbox ? /* @__PURE__ */ jsxs(Ariakit.PopoverProvider, { open: listOpen, setOpen: setListOpen, placement: "bottom-start", children: [
7947
+ contentInner,
7693
7948
  /* @__PURE__ */ jsx(
7694
- "input",
7949
+ Ariakit.Popover,
7695
7950
  {
7696
- ref: inputRef,
7697
- type: "file",
7698
- className: "hidden",
7699
- disabled,
7700
- multiple,
7701
- accept,
7702
- name: resolvedName,
7703
- onChange,
7704
- "aria-label": placeholder
7705
- }
7706
- ),
7707
- /* @__PURE__ */ jsxs(
7708
- "button",
7709
- {
7710
- type: "button",
7711
- disabled,
7712
- onClick: open,
7713
- "aria-label": placeholder,
7714
- className: cn(
7715
- "flex min-w-0 flex-1 items-center bg-transparent text-left",
7716
- gapCls,
7717
- disabled ? "cursor-not-allowed" : "cursor-pointer"
7718
- ),
7719
- children: [
7720
- /* @__PURE__ */ jsx(
7721
- SIcon,
7722
- {
7723
- name: "attachFile",
7724
- size: iconSize,
7725
- color: disabled ? "var(--cmp-filepicker-icon-disabled)" : "var(--color-grey-65)"
7726
- }
7727
- ),
7728
- /* @__PURE__ */ jsx(
7729
- "span",
7730
- {
7731
- className: "min-w-0 flex-1 truncate text-[12px]",
7732
- style: {
7733
- color: disabled ? "var(--cmp-filepicker-text-disabled)" : hasSingle ? "var(--cmp-filepicker-text-default)" : "var(--cmp-filepicker-text-placeholder)"
7734
- },
7735
- children: displayText
7736
- }
7737
- )
7738
- ]
7951
+ portal: true,
7952
+ portalElement: portalContainer,
7953
+ gutter: 4,
7954
+ unmountOnHide: true,
7955
+ getAnchorRect: () => contentBoxRef.current?.getBoundingClientRect() ?? null,
7956
+ style: { minWidth: contentBoxRef.current?.offsetWidth },
7957
+ className: "z-50 box-border flex flex-col items-stretch gap-[8px] rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] p-[8px] shadow-[2px_2px_12px_2px_rgba(0,0,0,0.1)]",
7958
+ children: filesArr.map((f, i) => /* @__PURE__ */ jsx(SChip, { value: f.name, editable: false, onRemove: () => removeChip(i) }, i))
7739
7959
  }
7740
- ),
7741
- !disabled && hasSingle && /* @__PURE__ */ jsx(SGhostButton, { icon: "close", size: "xxs", ariaLabel: "clear", onClick: clear })
7742
- ] });
7743
- 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)) });
7744
- if (inline) {
7745
- return /* @__PURE__ */ jsxs("div", { className: cn("inline-flex flex-col", className), style, children: [
7746
- /* @__PURE__ */ jsx(
7747
- "div",
7748
- {
7749
- 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)]",
7750
- style: {
7751
- height: "var(--cmp-filepicker-sm-height)",
7752
- width: typeof width === "number" ? `${width}px` : width
7753
- },
7754
- children: content
7755
- }
7756
- ),
7757
- chips
7758
- ] });
7759
- }
7960
+ )
7961
+ ] }) : contentInner;
7962
+ const chips = multiple && !useMultipleListBox && filesArr.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-[8px] flex flex-wrap gap-[8px]", children: filesArr.map((f, i) => /* @__PURE__ */ jsx(SChip, { value: f.name, editable: false, onRemove: () => removeChip(i) }, i)) });
7760
7963
  return /* @__PURE__ */ jsxs("div", { className, style, children: [
7761
7964
  /* @__PURE__ */ jsx(
7762
7965
  SField,
7763
7966
  {
7967
+ borderless: inline,
7764
7968
  label,
7765
7969
  labelWidth,
7766
7970
  icon,
@@ -7788,6 +7992,7 @@ function SKeyValueTable({
7788
7992
  fields = [],
7789
7993
  search = false,
7790
7994
  radius = "default",
7995
+ dense = false,
7791
7996
  onChange,
7792
7997
  onSearch,
7793
7998
  className,
@@ -7795,6 +8000,8 @@ function SKeyValueTable({
7795
8000
  }) {
7796
8001
  if (fields.length === 0) return null;
7797
8002
  const emit2 = (name, value) => onChange?.({ name, value });
8003
+ const cellHeight = dense ? "var(--cmp-table-body-dense-height)" : "var(--cmp-table-keyValue-height)";
8004
+ const cellPadY = dense ? "var(--cmp-table-body-paddingY-dense)" : "var(--cmp-table-keyValue-body-paddingY)";
7798
8005
  const renderField = (f) => {
7799
8006
  if (f.render) return f.render;
7800
8007
  const opt = f.options ?? {};
@@ -7875,10 +8082,15 @@ function SKeyValueTable({
7875
8082
  rowSpan: f.thRowSpan && f.thRowSpan > 1 ? f.thRowSpan : void 0,
7876
8083
  colSpan: f.thColSpan && f.thColSpan > 1 ? f.thColSpan : void 0,
7877
8084
  className: cn(
7878
- "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",
8085
+ "box-border bg-[var(--cmp-table-header-bg)] px-[var(--cmp-table-header-paddingX)] text-left align-middle",
7879
8086
  cellBorder,
7880
8087
  f.thClass
7881
8088
  ),
8089
+ style: {
8090
+ height: cellHeight,
8091
+ paddingTop: cellPadY,
8092
+ paddingBottom: cellPadY
8093
+ },
7882
8094
  children: /* @__PURE__ */ jsxs("div", { className: "flex h-full w-full items-center justify-between gap-[var(--cmp-table-header-gap)]", children: [
7883
8095
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-[8px]", children: [
7884
8096
  /* @__PURE__ */ jsx("span", { className: "text-[12px] font-bold leading-[20px] text-[color:var(--sys-color-fg-primary)]", children: f.label }),
@@ -7904,10 +8116,11 @@ function SKeyValueTable({
7904
8116
  rowSpan: f.tdRowSpan && f.tdRowSpan > 1 ? f.tdRowSpan : void 0,
7905
8117
  colSpan: f.tdColSpan && f.tdColSpan > 1 ? f.tdColSpan : void 0,
7906
8118
  className: cn(
7907
- "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",
8119
+ "box-border bg-[var(--sys-color-bg-frame)] px-[var(--cmp-table-keyValue-body-paddingX-default)] align-middle",
7908
8120
  cellBorder,
7909
8121
  f.tdClass
7910
8122
  ),
8123
+ style: { height: cellHeight, paddingTop: cellPadY, paddingBottom: cellPadY },
7911
8124
  children: renderField(f)
7912
8125
  },
7913
8126
  `td-${r}-${c}`
@@ -8028,9 +8241,9 @@ var POS_ANCHOR = {
8028
8241
  "top-left": { top: 20, left: 20 },
8029
8242
  "top-center": { top: 20, left: "50%" },
8030
8243
  "top-right": { top: 20, right: 20 },
8031
- "bottom-left": { bottom: 20, left: 20 },
8032
- "bottom-center": { bottom: 20, left: "50%" },
8033
- "bottom-right": { bottom: 20, right: 20 }
8244
+ "bottom-left": { bottom: 100, left: 20 },
8245
+ "bottom-center": { bottom: 100, left: "50%" },
8246
+ "bottom-right": { bottom: 100, right: 20 }
8034
8247
  };
8035
8248
  var counter = 0;
8036
8249
  var SToastContainer = forwardRef(
@@ -8390,7 +8603,7 @@ var SChipInput = forwardRef(function SChipInput2({
8390
8603
  disabledChips = [],
8391
8604
  size = "sm",
8392
8605
  disabled = false,
8393
- placeholder = "\uC785\uB825\uD574 \uC8FC\uC138\uC694.",
8606
+ placeholder = "\uD0DC\uADF8 \uC785\uB825 (Enter\uB85C \uB4F1\uB85D / \uCF64\uB9C8\uB85C \uAD6C\uBD84 / \uB744\uC5B4\uC4F0\uAE30 \uBD88\uAC00)",
8394
8607
  name,
8395
8608
  rules,
8396
8609
  error,
@@ -8541,6 +8754,7 @@ var SChipInput = forwardRef(function SChipInput2({
8541
8754
  {
8542
8755
  label,
8543
8756
  labelWidth,
8757
+ labelHeight: `calc(var(--cmp-chipInput-${size}-minHeight) + 2px)`,
8544
8758
  icon,
8545
8759
  labelTooltip,
8546
8760
  labelTooltipProps,
@@ -8611,9 +8825,11 @@ var SChipInput = forwardRef(function SChipInput2({
8611
8825
  paddingInline: isFieldFilled ? "var(--cmp-chip-paddingX)" : void 0,
8612
8826
  borderWidth: isFieldFilled ? "var(--cmp-chip-border-width)" : void 0,
8613
8827
  borderStyle: isFieldFilled ? "solid" : void 0,
8614
- borderColor: isFieldFilled ? "transparent" : void 0,
8828
+ // 작성중 필드는 SChip의 editable 수정중(editing) 스타일과 동일하게 —
8829
+ // bg/보더/글자색 모두 focus 토큰을 사용한다.
8830
+ borderColor: isFieldFilled ? "var(--cmp-chip-border-focus)" : void 0,
8615
8831
  borderRadius: isFieldFilled ? "var(--cmp-chip-radius)" : 0,
8616
- background: isFieldFilled ? "var(--cmp-chip-bg-default)" : "transparent",
8832
+ background: isFieldFilled ? "var(--cmp-chip-bg-focus)" : "transparent",
8617
8833
  overflow: "hidden"
8618
8834
  },
8619
8835
  children: [
@@ -8622,7 +8838,7 @@ var SChipInput = forwardRef(function SChipInput2({
8622
8838
  {
8623
8839
  "aria-hidden": true,
8624
8840
  className: cn(
8625
- "invisible col-start-1 row-start-1 whitespace-pre font-medium",
8841
+ "invisible col-start-1 row-start-1 whitespace-pre font-normal",
8626
8842
  size === "md" ? "text-14 leading-24" : "text-12 leading-20"
8627
8843
  ),
8628
8844
  children: inputValue !== "" ? inputValue : values.length === 0 ? placeholder : ""
@@ -8635,12 +8851,14 @@ var SChipInput = forwardRef(function SChipInput2({
8635
8851
  name: resolvedName,
8636
8852
  size: 1,
8637
8853
  className: cn(
8638
- "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",
8854
+ "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",
8639
8855
  size === "md" ? "text-14 leading-24" : "text-12 leading-20"
8640
8856
  ),
8641
8857
  style: {
8642
8858
  minWidth: "1ch",
8643
- height: "var(--cmp-chip-height)",
8859
+ // height 지정하지 않고 line-height(20/24px)에 맞춰 자동 크기로 둔다.
8860
+ // var(--cmp-chip-height)(24px)로 고정하면 네이티브 <input>이 남는 세로 여백에
8861
+ // 텍스트를 아래로 밀어 넣어, 확정된 chip 텍스트보다 2px 낮게 보인다.
8644
8862
  margin: 0,
8645
8863
  overflow: "hidden",
8646
8864
  textOverflow: "ellipsis"
@@ -8685,7 +8903,7 @@ var SChipInput = forwardRef(function SChipInput2({
8685
8903
  showMetaInfo && /* @__PURE__ */ jsxs(
8686
8904
  "div",
8687
8905
  {
8688
- className: "s-chip-input__meta flex items-center gap-8",
8906
+ className: "s-chip-input__meta ml-auto flex items-center gap-8",
8689
8907
  onMouseDown: (e) => e.preventDefault(),
8690
8908
  children: [
8691
8909
  /* @__PURE__ */ jsx(