sellmate-design-system-react 0.1.7 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/dist/components/SActionModal/SActionModal.cjs +11 -3
  2. package/dist/components/SActionModal/SActionModal.cjs.map +1 -1
  3. package/dist/components/SActionModal/SActionModal.js +11 -3
  4. package/dist/components/SActionModal/SActionModal.js.map +1 -1
  5. package/dist/components/SBarcodeInput/SBarcodeInput.cjs +226 -209
  6. package/dist/components/SBarcodeInput/SBarcodeInput.cjs.map +1 -1
  7. package/dist/components/SBarcodeInput/SBarcodeInput.js +226 -209
  8. package/dist/components/SBarcodeInput/SBarcodeInput.js.map +1 -1
  9. package/dist/components/SCalendar/SCalendar.cjs +9 -1
  10. package/dist/components/SCalendar/SCalendar.cjs.map +1 -1
  11. package/dist/components/SCalendar/SCalendar.js +9 -1
  12. package/dist/components/SCalendar/SCalendar.js.map +1 -1
  13. package/dist/components/SChip/SChip.cjs +9 -1
  14. package/dist/components/SChip/SChip.cjs.map +1 -1
  15. package/dist/components/SChip/SChip.d.ts +1 -1
  16. package/dist/components/SChip/SChip.js +9 -1
  17. package/dist/components/SChip/SChip.js.map +1 -1
  18. package/dist/components/SChipInput/SChipInput.cjs +260 -235
  19. package/dist/components/SChipInput/SChipInput.cjs.map +1 -1
  20. package/dist/components/SChipInput/SChipInput.js +259 -235
  21. package/dist/components/SChipInput/SChipInput.js.map +1 -1
  22. package/dist/components/SCircleProgress/SCircleProgress.cjs +56 -58
  23. package/dist/components/SCircleProgress/SCircleProgress.cjs.map +1 -1
  24. package/dist/components/SCircleProgress/SCircleProgress.js +56 -58
  25. package/dist/components/SCircleProgress/SCircleProgress.js.map +1 -1
  26. package/dist/components/SConfirmModal/SConfirmModal.cjs +9 -1
  27. package/dist/components/SConfirmModal/SConfirmModal.cjs.map +1 -1
  28. package/dist/components/SConfirmModal/SConfirmModal.js +9 -1
  29. package/dist/components/SConfirmModal/SConfirmModal.js.map +1 -1
  30. package/dist/components/SDatePicker/SDatePicker.cjs +247 -221
  31. package/dist/components/SDatePicker/SDatePicker.cjs.map +1 -1
  32. package/dist/components/SDatePicker/SDatePicker.js +247 -221
  33. package/dist/components/SDatePicker/SDatePicker.js.map +1 -1
  34. package/dist/components/SDateRangePicker/SDateRangePicker.cjs +308 -256
  35. package/dist/components/SDateRangePicker/SDateRangePicker.cjs.map +1 -1
  36. package/dist/components/SDateRangePicker/SDateRangePicker.js +308 -256
  37. package/dist/components/SDateRangePicker/SDateRangePicker.js.map +1 -1
  38. package/dist/components/SDropdownButton/SDropdownButton.cjs +51 -4
  39. package/dist/components/SDropdownButton/SDropdownButton.cjs.map +1 -1
  40. package/dist/components/SDropdownButton/SDropdownButton.js +52 -5
  41. package/dist/components/SDropdownButton/SDropdownButton.js.map +1 -1
  42. package/dist/components/SField/SField.cjs +226 -21
  43. package/dist/components/SField/SField.cjs.map +1 -1
  44. package/dist/components/SField/SField.d.ts +11 -0
  45. package/dist/components/SField/SField.js +226 -21
  46. package/dist/components/SField/SField.js.map +1 -1
  47. package/dist/components/SFilePicker/SFilePicker.cjs +306 -278
  48. package/dist/components/SFilePicker/SFilePicker.cjs.map +1 -1
  49. package/dist/components/SFilePicker/SFilePicker.d.ts +4 -2
  50. package/dist/components/SFilePicker/SFilePicker.js +306 -278
  51. package/dist/components/SFilePicker/SFilePicker.js.map +1 -1
  52. package/dist/components/SGhostButton/SGhostButton.cjs +8 -0
  53. package/dist/components/SGhostButton/SGhostButton.cjs.map +1 -1
  54. package/dist/components/SGhostButton/SGhostButton.js +8 -0
  55. package/dist/components/SGhostButton/SGhostButton.js.map +1 -1
  56. package/dist/components/SGuide/SGuide.cjs +12 -1
  57. package/dist/components/SGuide/SGuide.cjs.map +1 -1
  58. package/dist/components/SGuide/SGuide.js +12 -1
  59. package/dist/components/SGuide/SGuide.js.map +1 -1
  60. package/dist/components/SInput/SInput.cjs +226 -209
  61. package/dist/components/SInput/SInput.cjs.map +1 -1
  62. package/dist/components/SInput/SInput.js +226 -209
  63. package/dist/components/SInput/SInput.js.map +1 -1
  64. package/dist/components/SKeyValueTable/SKeyValueTable.cjs +640 -453
  65. package/dist/components/SKeyValueTable/SKeyValueTable.cjs.map +1 -1
  66. package/dist/components/SKeyValueTable/SKeyValueTable.d.ts +3 -1
  67. package/dist/components/SKeyValueTable/SKeyValueTable.js +640 -453
  68. package/dist/components/SKeyValueTable/SKeyValueTable.js.map +1 -1
  69. package/dist/components/SLoadingContainer/SLoadingContainer.cjs +64 -58
  70. package/dist/components/SLoadingContainer/SLoadingContainer.cjs.map +1 -1
  71. package/dist/components/SLoadingContainer/SLoadingContainer.js +64 -58
  72. package/dist/components/SLoadingContainer/SLoadingContainer.js.map +1 -1
  73. package/dist/components/SLoadingContainer/loading.cjs +64 -58
  74. package/dist/components/SLoadingContainer/loading.cjs.map +1 -1
  75. package/dist/components/SLoadingContainer/loading.js +64 -58
  76. package/dist/components/SLoadingContainer/loading.js.map +1 -1
  77. package/dist/components/SLoadingModal/SLoadingModal.cjs +68 -61
  78. package/dist/components/SLoadingModal/SLoadingModal.cjs.map +1 -1
  79. package/dist/components/SLoadingModal/SLoadingModal.js +68 -61
  80. package/dist/components/SLoadingModal/SLoadingModal.js.map +1 -1
  81. package/dist/components/SModalContainer/SModalContainer.cjs +9 -1
  82. package/dist/components/SModalContainer/SModalContainer.cjs.map +1 -1
  83. package/dist/components/SModalContainer/SModalContainer.js +9 -1
  84. package/dist/components/SModalContainer/SModalContainer.js.map +1 -1
  85. package/dist/components/SNumberInput/SNumberInput.cjs +334 -50
  86. package/dist/components/SNumberInput/SNumberInput.cjs.map +1 -1
  87. package/dist/components/SNumberInput/SNumberInput.d.ts +2 -0
  88. package/dist/components/SNumberInput/SNumberInput.js +334 -50
  89. package/dist/components/SNumberInput/SNumberInput.js.map +1 -1
  90. package/dist/components/SPagination/SPagination.cjs +1 -1
  91. package/dist/components/SPagination/SPagination.cjs.map +1 -1
  92. package/dist/components/SPagination/SPagination.js +1 -1
  93. package/dist/components/SPagination/SPagination.js.map +1 -1
  94. package/dist/components/SPopover/SPopover.cjs +20 -3
  95. package/dist/components/SPopover/SPopover.cjs.map +1 -1
  96. package/dist/components/SPopover/SPopover.js +20 -4
  97. package/dist/components/SPopover/SPopover.js.map +1 -1
  98. package/dist/components/SPopup/SPopup.cjs +2 -2
  99. package/dist/components/SPopup/SPopup.cjs.map +1 -1
  100. package/dist/components/SPopup/SPopup.js +2 -2
  101. package/dist/components/SPopup/SPopup.js.map +1 -1
  102. package/dist/components/SPortal/SPortal.cjs +8 -0
  103. package/dist/components/SPortal/SPortal.cjs.map +1 -1
  104. package/dist/components/SPortal/SPortal.js +8 -0
  105. package/dist/components/SPortal/SPortal.js.map +1 -1
  106. package/dist/components/SSelect/SSelect.cjs +76 -32
  107. package/dist/components/SSelect/SSelect.cjs.map +1 -1
  108. package/dist/components/SSelect/SSelect.js +76 -32
  109. package/dist/components/SSelect/SSelect.js.map +1 -1
  110. package/dist/components/STable/STable.cjs +133 -91
  111. package/dist/components/STable/STable.cjs.map +1 -1
  112. package/dist/components/STable/STable.js +133 -91
  113. package/dist/components/STable/STable.js.map +1 -1
  114. package/dist/components/STextLink/STextLink.cjs +137 -3
  115. package/dist/components/STextLink/STextLink.cjs.map +1 -1
  116. package/dist/components/STextLink/STextLink.d.ts +1 -1
  117. package/dist/components/STextLink/STextLink.js +118 -4
  118. package/dist/components/STextLink/STextLink.js.map +1 -1
  119. package/dist/components/STextarea/STextarea.cjs +226 -21
  120. package/dist/components/STextarea/STextarea.cjs.map +1 -1
  121. package/dist/components/STextarea/STextarea.js +226 -21
  122. package/dist/components/STextarea/STextarea.js.map +1 -1
  123. package/dist/components/SToast/SToast.cjs +8 -0
  124. package/dist/components/SToast/SToast.cjs.map +1 -1
  125. package/dist/components/SToast/SToast.js +8 -0
  126. package/dist/components/SToast/SToast.js.map +1 -1
  127. package/dist/components/SToast/SToastContainer.cjs +11 -3
  128. package/dist/components/SToast/SToastContainer.cjs.map +1 -1
  129. package/dist/components/SToast/SToastContainer.js +11 -3
  130. package/dist/components/SToast/SToastContainer.js.map +1 -1
  131. package/dist/components/STooltip/STooltip.cjs +217 -14
  132. package/dist/components/STooltip/STooltip.cjs.map +1 -1
  133. package/dist/components/STooltip/STooltip.js +217 -14
  134. package/dist/components/STooltip/STooltip.js.map +1 -1
  135. package/dist/index.cjs +532 -300
  136. package/dist/index.cjs.map +1 -1
  137. package/dist/index.js +531 -300
  138. package/dist/index.js.map +1 -1
  139. package/dist/lib/floating-anim.cjs +8 -0
  140. package/dist/lib/floating-anim.cjs.map +1 -1
  141. package/dist/lib/floating-anim.d.ts +5 -1
  142. package/dist/lib/floating-anim.js +8 -0
  143. package/dist/lib/floating-anim.js.map +1 -1
  144. package/dist/styles.css +175 -66
  145. package/dist/theme.css +49 -22
  146. package/package.json +1 -1
@@ -5,7 +5,7 @@ var react = require('react');
5
5
  var clsx = require('clsx');
6
6
  var tailwindMerge = require('tailwind-merge');
7
7
  var jsxRuntime = require('react/jsx-runtime');
8
- var RPopover = require('@radix-ui/react-popover');
8
+ var RPopover2 = require('@radix-ui/react-popover');
9
9
 
10
10
  function _interopNamespace(e) {
11
11
  if (e && e.__esModule) return e;
@@ -25,7 +25,7 @@ function _interopNamespace(e) {
25
25
  return Object.freeze(n);
26
26
  }
27
27
 
28
- var RPopover__namespace = /*#__PURE__*/_interopNamespace(RPopover);
28
+ var RPopover2__namespace = /*#__PURE__*/_interopNamespace(RPopover2);
29
29
 
30
30
  var twMerge = tailwindMerge.extendTailwindMerge({
31
31
  extend: {
@@ -2876,12 +2876,20 @@ var SIcon = react.forwardRef(function SIcon2({ name, size = 24, color, rotate, l
2876
2876
  // src/lib/floating-anim.ts
2877
2877
  var FLOATING_SLIDE_ANIM = [
2878
2878
  "data-[state=open]:data-[side=top]:animate-floating-in-top",
2879
+ "data-[state=delayed-open]:data-[side=top]:animate-floating-in-top",
2880
+ "data-[state=instant-open]:data-[side=top]:animate-floating-in-top",
2879
2881
  "data-[state=closed]:data-[side=top]:animate-floating-out-top",
2880
2882
  "data-[state=open]:data-[side=bottom]:animate-floating-in-bottom",
2883
+ "data-[state=delayed-open]:data-[side=bottom]:animate-floating-in-bottom",
2884
+ "data-[state=instant-open]:data-[side=bottom]:animate-floating-in-bottom",
2881
2885
  "data-[state=closed]:data-[side=bottom]:animate-floating-out-bottom",
2882
2886
  "data-[state=open]:data-[side=left]:animate-floating-in-left",
2887
+ "data-[state=delayed-open]:data-[side=left]:animate-floating-in-left",
2888
+ "data-[state=instant-open]:data-[side=left]:animate-floating-in-left",
2883
2889
  "data-[state=closed]:data-[side=left]:animate-floating-out-left",
2884
2890
  "data-[state=open]:data-[side=right]:animate-floating-in-right",
2891
+ "data-[state=delayed-open]:data-[side=right]:animate-floating-in-right",
2892
+ "data-[state=instant-open]:data-[side=right]:animate-floating-in-right",
2885
2893
  "data-[state=closed]:data-[side=right]:animate-floating-out-right"
2886
2894
  ].join(" ");
2887
2895
  var PortalContainerContext = react.createContext(null);
@@ -2889,11 +2897,200 @@ PortalContainerContext.Provider;
2889
2897
  function usePortalContainer() {
2890
2898
  return react.useContext(PortalContainerContext) ?? void 0;
2891
2899
  }
2900
+
2901
+ // src/components/STag/tag.config.ts
2902
+ var TAG_SIZE_CONFIG = {
2903
+ xs: {
2904
+ height: 20,
2905
+ paddingX: 8,
2906
+ gap: 4,
2907
+ radius: 6,
2908
+ iconSize: 12,
2909
+ fontSize: 11,
2910
+ fontWeight: 500,
2911
+ lineHeight: 18
2912
+ },
2913
+ sm: {
2914
+ height: 24,
2915
+ paddingX: 8,
2916
+ gap: 4,
2917
+ radius: 6,
2918
+ iconSize: 16,
2919
+ fontSize: 12,
2920
+ fontWeight: 700,
2921
+ lineHeight: 20
2922
+ },
2923
+ md: {
2924
+ height: 28,
2925
+ paddingX: 12,
2926
+ gap: 6,
2927
+ radius: 8,
2928
+ iconSize: 16,
2929
+ fontSize: 14,
2930
+ fontWeight: 700,
2931
+ lineHeight: 24
2932
+ }
2933
+ };
2934
+ var STag = react.forwardRef(function STag2({
2935
+ shape = "square",
2936
+ size = "sm",
2937
+ color = "grey",
2938
+ label = "",
2939
+ icon,
2940
+ iconLeft = true,
2941
+ width,
2942
+ className,
2943
+ style,
2944
+ ...rest
2945
+ }, ref) {
2946
+ const s = TAG_SIZE_CONFIG[size];
2947
+ const contentColor = `var(--cmp-tag-${color}-content)`;
2948
+ const iconNode = icon ? /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: icon, size: s.iconSize, color: contentColor }) : null;
2949
+ const resolvedWidth = typeof width === "number" ? `${width}px` : width;
2950
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2951
+ "span",
2952
+ {
2953
+ ref,
2954
+ "aria-label": label || "tag",
2955
+ className: cn(
2956
+ "box-border inline-flex w-fit select-none items-center justify-center whitespace-nowrap",
2957
+ className
2958
+ ),
2959
+ style: {
2960
+ minHeight: s.height,
2961
+ padding: `0 ${s.paddingX}px`,
2962
+ gap: s.gap,
2963
+ borderRadius: shape === "pill" ? 999 : s.radius,
2964
+ fontSize: s.fontSize,
2965
+ fontWeight: s.fontWeight,
2966
+ lineHeight: `${s.lineHeight}px`,
2967
+ background: `var(--cmp-tag-${color}-bg)`,
2968
+ color: contentColor,
2969
+ ...resolvedWidth != null ? { width: resolvedWidth } : {},
2970
+ ...style
2971
+ },
2972
+ ...rest,
2973
+ children: [
2974
+ icon && iconLeft && iconNode,
2975
+ label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex min-w-0 items-center justify-center", children: label }),
2976
+ icon && !iconLeft && iconNode
2977
+ ]
2978
+ }
2979
+ );
2980
+ });
2981
+ var SIZE = {
2982
+ xxs: { icon: 12, radius: "sm" },
2983
+ xs: { icon: 16, radius: "sm" },
2984
+ sm: { icon: 20, radius: "sm" },
2985
+ md: { icon: 24, radius: "md" },
2986
+ lg: { icon: 32, radius: "md" }
2987
+ };
2988
+ var TOOLTIP_HIDE_DELAY_MS = 100;
2989
+ function SGhostButton({
2990
+ icon,
2991
+ size = "sm",
2992
+ intent = "default",
2993
+ ariaLabel = "",
2994
+ tooltipText,
2995
+ disabled = false,
2996
+ onClick,
2997
+ className,
2998
+ style
2999
+ }) {
3000
+ const portalContainer = usePortalContainer();
3001
+ const [open, setOpen] = react.useState(false);
3002
+ const hideTimer = react.useRef(void 0);
3003
+ const cancelHide = () => {
3004
+ if (hideTimer.current) {
3005
+ clearTimeout(hideTimer.current);
3006
+ hideTimer.current = void 0;
3007
+ }
3008
+ };
3009
+ const openNow = () => {
3010
+ cancelHide();
3011
+ setOpen(true);
3012
+ };
3013
+ const startHide = () => {
3014
+ cancelHide();
3015
+ hideTimer.current = setTimeout(() => setOpen(false), TOOLTIP_HIDE_DELAY_MS);
3016
+ };
3017
+ const s = SIZE[size];
3018
+ const contentColor = disabled ? intent === "inverse" ? "var(--cmp-ghostButton-inverse-disabled)" : "var(--cmp-ghostButton-icon-disabled)" : `var(--cmp-ghostButton-${intent}-content)`;
3019
+ const btn = /* @__PURE__ */ jsxRuntime.jsxs(
3020
+ "button",
3021
+ {
3022
+ type: "button",
3023
+ disabled,
3024
+ "aria-disabled": disabled ? "true" : void 0,
3025
+ "aria-label": ariaLabel.trim() || void 0,
3026
+ tabIndex: disabled ? -1 : void 0,
3027
+ onClick: (e) => {
3028
+ if (disabled) {
3029
+ e.preventDefault();
3030
+ return;
3031
+ }
3032
+ onClick?.(e);
3033
+ },
3034
+ className: cn(
3035
+ "group relative box-border inline-flex items-center justify-center border-none bg-transparent p-0 transition-shadow",
3036
+ disabled ? "cursor-not-allowed" : "cursor-pointer",
3037
+ "focus-visible:outline-none focus-visible:shadow-[0_0_0_2px_var(--cmp-ghostButton-action-hover-bg)]",
3038
+ className
3039
+ ),
3040
+ style: {
3041
+ width: `var(--cmp-ghostButton-${size}-size)`,
3042
+ height: `var(--cmp-ghostButton-${size}-size)`,
3043
+ borderRadius: `var(--cmp-ghostButton-radius-${s.radius})`,
3044
+ ...style
3045
+ },
3046
+ children: [
3047
+ !disabled && /* @__PURE__ */ jsxRuntime.jsx(
3048
+ "span",
3049
+ {
3050
+ "aria-hidden": true,
3051
+ className: "pointer-events-none absolute inset-0 rounded-[inherit] opacity-0 transition-opacity duration-200 group-hover:opacity-5",
3052
+ style: { background: `var(--cmp-ghostButton-${intent}-hover-bg)` }
3053
+ }
3054
+ ),
3055
+ /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: icon, size: s.icon, color: contentColor })
3056
+ ]
3057
+ }
3058
+ );
3059
+ const text = (tooltipText ?? "").trim();
3060
+ if (text === "") return btn;
3061
+ return /* @__PURE__ */ jsxRuntime.jsxs(RPopover2__namespace.Root, { open, onOpenChange: setOpen, children: [
3062
+ /* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Anchor, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
3063
+ "span",
3064
+ {
3065
+ className: "inline-flex",
3066
+ onMouseEnter: openNow,
3067
+ onMouseLeave: startHide,
3068
+ onFocus: openNow,
3069
+ onBlur: startHide,
3070
+ children: btn
3071
+ }
3072
+ ) }),
3073
+ /* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
3074
+ RPopover2__namespace.Content,
3075
+ {
3076
+ side: "top",
3077
+ sideOffset: 4,
3078
+ className: cn("z-50", FLOATING_SLIDE_ANIM),
3079
+ "aria-hidden": true,
3080
+ onOpenAutoFocus: (e) => e.preventDefault(),
3081
+ onMouseEnter: cancelHide,
3082
+ onMouseLeave: startHide,
3083
+ children: /* @__PURE__ */ jsxRuntime.jsx(STag, { shape: "square", size: "xs", color: "grey", label: text })
3084
+ }
3085
+ ) })
3086
+ ] });
3087
+ }
2892
3088
  var HIDE_DELAY_MS = 100;
2893
3089
  function useBody(content, message = []) {
2894
3090
  if (content != null) return content;
2895
3091
  if (message.length === 0) return null;
2896
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: message.map((line, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { children: line }, i)) });
3092
+ const singleLine = message.length === 1;
3093
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: message.map((line, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: singleLine ? "leading-[24px]" : void 0, children: line }, i)) });
2897
3094
  }
2898
3095
  var STooltip = react.forwardRef(function STooltip2({
2899
3096
  content,
@@ -2951,7 +3148,7 @@ var STooltip = react.forwardRef(function STooltip2({
2951
3148
  if (disabled || body == null) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: triggerNode });
2952
3149
  const isHover = trigger === "hover";
2953
3150
  const contentClass = cn(
2954
- "z-50 max-w-xs rounded-[6px] px-[16px] py-[12px] text-[12px] leading-[20px]",
3151
+ "z-50 max-w-xs rounded-[6px] px-[16px] py-[12px] text-[12px] leading-[20px] shadow-[2px_2px_12px_2px_rgba(0,0,0,0.1)]",
2955
3152
  FLOATING_SLIDE_ANIM,
2956
3153
  className
2957
3154
  );
@@ -2961,10 +3158,10 @@ var STooltip = react.forwardRef(function STooltip2({
2961
3158
  fontWeight: tooltipType === "default" ? 500 : 700,
2962
3159
  ...style
2963
3160
  };
2964
- return /* @__PURE__ */ jsxRuntime.jsxs(RPopover__namespace.Root, { open, onOpenChange: setOpen, children: [
3161
+ return /* @__PURE__ */ jsxRuntime.jsxs(RPopover2__namespace.Root, { open, onOpenChange: setOpen, children: [
2965
3162
  isHover ? (
2966
3163
  // hover: Anchor(위치 기준) + 직접 mouse 핸들러 — 클릭으로 토글되지 않도록 Trigger 미사용
2967
- /* @__PURE__ */ jsxRuntime.jsx(RPopover__namespace.Anchor, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
3164
+ /* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Anchor, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
2968
3165
  "span",
2969
3166
  {
2970
3167
  className: "inline-flex",
@@ -2975,9 +3172,9 @@ var STooltip = react.forwardRef(function STooltip2({
2975
3172
  children: triggerNode
2976
3173
  }
2977
3174
  ) })
2978
- ) : /* @__PURE__ */ jsxRuntime.jsx(RPopover__namespace.Trigger, { asChild: true, children: triggerNode }),
2979
- /* @__PURE__ */ jsxRuntime.jsx(RPopover__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsxs(
2980
- RPopover__namespace.Content,
3175
+ ) : /* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Trigger, { asChild: true, children: triggerNode }),
3176
+ /* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsxs(
3177
+ RPopover2__namespace.Content,
2981
3178
  {
2982
3179
  side: placement,
2983
3180
  sideOffset: 8,
@@ -2996,15 +3193,21 @@ var STooltip = react.forwardRef(function STooltip2({
2996
3193
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-[12px]", children: [
2997
3194
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children: body }),
2998
3195
  useClose && /* @__PURE__ */ jsxRuntime.jsx(
2999
- RPopover__namespace.Close,
3196
+ SGhostButton,
3000
3197
  {
3001
- "aria-label": "\uB2EB\uAE30",
3002
- className: "shrink-0 cursor-pointer opacity-70 hover:opacity-100",
3003
- children: /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "close", size: 16, color: fg })
3198
+ icon: "close",
3199
+ size: "xs",
3200
+ intent: tooltipType === "default" ? "inverse" : "default",
3201
+ ariaLabel: "\uB2EB\uAE30",
3202
+ className: "shrink-0",
3203
+ onClick: () => {
3204
+ cancelHide();
3205
+ setOpen(false);
3206
+ }
3004
3207
  }
3005
3208
  )
3006
3209
  ] }),
3007
- /* @__PURE__ */ jsxRuntime.jsx(RPopover__namespace.Arrow, { width: 16, height: 12, style: { fill: bg } })
3210
+ /* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Arrow, { width: 16, height: 12, style: { fill: bg } })
3008
3211
  ]
3009
3212
  }
3010
3213
  ) })
@@ -3038,8 +3241,8 @@ function useFormField(field) {
3038
3241
  }, [ctx, name]);
3039
3242
  }
3040
3243
  var FIELD_SIZE = {
3041
- sm: { height: 28, radius: 4, fieldGap: 12, labelGap: 6, fontSize: 12, lineHeight: 20, icon: 12 },
3042
- md: { height: 36, radius: 6, fieldGap: 16, labelGap: 8, fontSize: 14, lineHeight: 24, icon: 12 }
3244
+ sm: { height: 28, radius: 4, fieldGap: 12, labelGap: 6, fontSize: 12, lineHeight: 20, icon: 16 },
3245
+ md: { height: 36, radius: 6, fieldGap: 16, labelGap: 8, fontSize: 14, lineHeight: 24, icon: 16 }
3043
3246
  };
3044
3247
  var ALIGN = {
3045
3248
  start: "flex-start",
@@ -3054,6 +3257,7 @@ var SField = react.forwardRef(function SField2({
3054
3257
  labelTooltip = "",
3055
3258
  labelTooltipProps,
3056
3259
  labelWidth,
3260
+ labelHeight,
3057
3261
  size = "sm",
3058
3262
  addonLabel = "",
3059
3263
  addonAlign = "start",
@@ -3068,6 +3272,7 @@ var SField = react.forwardRef(function SField2({
3068
3272
  readOnly = false,
3069
3273
  width,
3070
3274
  multiline = false,
3275
+ borderless = false,
3071
3276
  children,
3072
3277
  className,
3073
3278
  style,
@@ -3101,8 +3306,8 @@ var SField = react.forwardRef(function SField2({
3101
3306
  const resolvedSuccess = status === "pass";
3102
3307
  const showError = resolvedError && errorMessage !== "";
3103
3308
  const interactive = !disabled && !readOnly;
3104
- 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)";
3105
- const bgColor = disabled ? "var(--color-grey-30)" : readOnly ? "var(--sys-color-field-bg-readOnly)" : "var(--sys-color-field-bg-default)";
3309
+ 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)";
3310
+ const bgColor = borderless ? "transparent" : disabled ? "var(--color-grey-30)" : readOnly ? "var(--sys-color-field-bg-readOnly)" : "var(--sys-color-field-bg-default)";
3106
3311
  const textColor = disabled ? "var(--color-grey-65)" : readOnly ? "var(--sys-color-field-text-readOnly)" : "var(--sys-color-field-text-default)";
3107
3312
  return /* @__PURE__ */ jsxRuntime.jsx(
3108
3313
  "div",
@@ -3119,7 +3324,7 @@ var SField = react.forwardRef(function SField2({
3119
3324
  {
3120
3325
  className: "flex shrink-0 items-center font-bold text-(--sys-color-field-text-default)",
3121
3326
  style: {
3122
- height: s.height,
3327
+ height: cssLen(labelHeight) ?? s.height,
3123
3328
  marginRight: s.fieldGap,
3124
3329
  width: cssLen(labelWidth),
3125
3330
  fontSize: s.fontSize,
@@ -3145,14 +3350,14 @@ var SField = react.forwardRef(function SField2({
3145
3350
  {
3146
3351
  className: cn(
3147
3352
  "relative box-border flex min-w-0 items-stretch overflow-hidden border border-solid border-(--field-bc)",
3148
- 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]",
3353
+ 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]",
3149
3354
  disabled && "cursor-not-allowed"
3150
3355
  ),
3151
3356
  style: {
3152
3357
  // @ts-expect-error CSS 변수
3153
3358
  "--field-bc": borderColor,
3154
3359
  // focused/hovered prop이 명시된 경우 강조를 즉시 반영
3155
- ...interactive && focused ? { boxShadow: "0px 0px 4px 0px #0071ff66" } : {},
3360
+ ...interactive && !borderless && focused ? { boxShadow: "0px 0px 4px 0px #0071ff66" } : {},
3156
3361
  ...multiline ? { minHeight: s.height } : { height: s.height },
3157
3362
  "width": cssLen(width),
3158
3363
  "borderRadius": s.radius,
@@ -3192,8 +3397,8 @@ var SField = react.forwardRef(function SField2({
3192
3397
  );
3193
3398
  });
3194
3399
  var PAD = {
3195
- sm: { fontSize: 12, stepper: 20, icon: 12 },
3196
- md: { fontSize: 14, stepper: 24, icon: 14 }
3400
+ sm: { fontSize: 12, lineHeight: 20, stepper: 20, icon: 12 },
3401
+ md: { fontSize: 14, lineHeight: 24, stepper: 24, icon: 14 }
3197
3402
  };
3198
3403
  var toNumber = (val) => {
3199
3404
  if (val === null || val === void 0 || val === "") return null;
@@ -3211,6 +3416,38 @@ var formatWithCommas = (value) => {
3211
3416
  const result = isNeg ? "-" + formatted : formatted;
3212
3417
  return decPart !== void 0 && decPart !== "" ? result + "." + decPart : result;
3213
3418
  };
3419
+ var addCommas = (value) => value.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
3420
+ var formatInputWithCommas = (value) => {
3421
+ const isNeg = value.startsWith("-");
3422
+ const unsigned = isNeg ? value.slice(1) : value;
3423
+ const hasDecimal = unsigned.includes(".");
3424
+ const [intPart = "", decPart = ""] = unsigned.split(".");
3425
+ const formattedInt = addCommas(intPart === "" ? "0" : intPart);
3426
+ return `${isNeg ? "-" : ""}${formattedInt}${hasDecimal ? `.${decPart}` : ""}`;
3427
+ };
3428
+ var getDecimalLimit = (useDecimal, maxDecimalLength) => {
3429
+ if (!useDecimal || maxDecimalLength === void 0 || !Number.isFinite(maxDecimalLength)) {
3430
+ return void 0;
3431
+ }
3432
+ return Math.max(0, Math.floor(maxDecimalLength));
3433
+ };
3434
+ var applyDecimalLimit = (value, decimalLimit) => {
3435
+ if (value === null || decimalLimit === void 0) return value;
3436
+ return Number(value.toFixed(decimalLimit));
3437
+ };
3438
+ var getLogicalCaret = (value, caret) => {
3439
+ return value.slice(0, caret ?? value.length).replace(/,/g, "").length;
3440
+ };
3441
+ var getDisplayCaret = (value, logicalCaret) => {
3442
+ if (logicalCaret <= 0) return 0;
3443
+ let seen = 0;
3444
+ for (let i = 0; i < value.length; i += 1) {
3445
+ if (value[i] === ",") continue;
3446
+ seen += 1;
3447
+ if (seen >= logicalCaret) return i + 1;
3448
+ }
3449
+ return value.length;
3450
+ };
3214
3451
  var SNumberInput = react.forwardRef(function SNumberInput2({
3215
3452
  value,
3216
3453
  onValueChange,
@@ -3220,6 +3457,7 @@ var SNumberInput = react.forwardRef(function SNumberInput2({
3220
3457
  step = 1,
3221
3458
  useButton = false,
3222
3459
  useDecimal = false,
3460
+ maxDecimalLength,
3223
3461
  inputPrefix = "",
3224
3462
  inputSuffix = "",
3225
3463
  inputClass,
@@ -3251,7 +3489,8 @@ var SNumberInput = react.forwardRef(function SNumberInput2({
3251
3489
  }, ref) {
3252
3490
  const p = PAD[size];
3253
3491
  const padX = `var(--cmp-numberInput-${size}-paddingX)`;
3254
- const numValue = toNumber(value);
3492
+ const decimalLimit = getDecimalLimit(useDecimal, maxDecimalLength);
3493
+ const numValue = applyDecimalLimit(toNumber(value), decimalLimit);
3255
3494
  const [display, setDisplay] = react.useState(() => formatWithCommas(numValue));
3256
3495
  const [ruleError, setRuleError] = react.useState("");
3257
3496
  const innerRef = react.useRef(null);
@@ -3261,8 +3500,9 @@ var SNumberInput = react.forwardRef(function SNumberInput2({
3261
3500
  else if (ref) ref.current = el;
3262
3501
  };
3263
3502
  react.useEffect(() => {
3264
- setDisplay(formatWithCommas(toNumber(value)));
3265
- }, [value]);
3503
+ if (document.activeElement === innerRef.current) return;
3504
+ setDisplay(formatWithCommas(applyDecimalLimit(toNumber(value), decimalLimit)));
3505
+ }, [decimalLimit, value]);
3266
3506
  useFormField({
3267
3507
  name,
3268
3508
  validate: () => {
@@ -3274,48 +3514,87 @@ var SNumberInput = react.forwardRef(function SNumberInput2({
3274
3514
  });
3275
3515
  const resolvedError = error || ruleError !== "";
3276
3516
  const resolvedStatus = status ?? (rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0);
3277
- const emit = (n) => {
3278
- setDisplay(formatWithCommas(n));
3279
- onValueChange?.(n);
3517
+ const restoreCaret = (nextDisplay, logicalCaret) => {
3518
+ const input = innerRef.current;
3519
+ if (logicalCaret === void 0 || !input || document.activeElement !== input) return;
3520
+ const nextCaret = getDisplayCaret(nextDisplay, logicalCaret);
3521
+ requestAnimationFrame(() => {
3522
+ if (document.activeElement !== input) return;
3523
+ input.setSelectionRange(nextCaret, nextCaret);
3524
+ });
3525
+ };
3526
+ const setDisplayWithCaret = (nextDisplay, logicalCaret) => {
3527
+ setDisplay(nextDisplay);
3528
+ restoreCaret(nextDisplay, logicalCaret);
3529
+ };
3530
+ const resetRejectedInput = (target, logicalCaret) => {
3531
+ target.value = display;
3532
+ restoreCaret(display, Math.min(logicalCaret, display.replace(/,/g, "").length));
3533
+ };
3534
+ const emit = (n, logicalCaret) => {
3535
+ const next = applyDecimalLimit(n, decimalLimit);
3536
+ const nextDisplay = formatWithCommas(next);
3537
+ setDisplayWithCaret(nextDisplay, logicalCaret);
3538
+ onValueChange?.(next);
3280
3539
  };
3281
3540
  const incDisabled = disabled || readOnly || numValue !== null && numValue >= max;
3282
3541
  const decDisabled = disabled || readOnly || numValue !== null && numValue <= min;
3283
3542
  const increment = () => {
3284
3543
  if (incDisabled) return;
3285
3544
  const cur = numValue ?? (min === Number.NEGATIVE_INFINITY ? 0 : min);
3286
- const next = Math.min(cur + step, max);
3545
+ const next = applyDecimalLimit(Math.min(cur + step, max), decimalLimit);
3287
3546
  if (next !== cur) emit(next);
3288
3547
  };
3289
3548
  const decrement = () => {
3290
3549
  if (decDisabled) return;
3291
3550
  const cur = numValue ?? (min === Number.NEGATIVE_INFINITY ? 0 : min);
3292
- const next = Math.max(cur - step, min);
3551
+ const next = applyDecimalLimit(Math.max(cur - step, min), decimalLimit);
3293
3552
  if (next !== cur) emit(next);
3294
3553
  };
3295
- const handleInput = (raw) => {
3554
+ const handleInput = (event) => {
3555
+ const target = event.currentTarget;
3556
+ const raw = target.value;
3557
+ const logicalCaret = getLogicalCaret(raw, target.selectionStart);
3296
3558
  if (raw === "") {
3297
- setDisplay("");
3559
+ setDisplayWithCaret("", 0);
3298
3560
  onValueChange?.(null);
3299
3561
  return;
3300
3562
  }
3301
3563
  const cleaned = raw.replace(/,/g, "");
3302
3564
  const decimals = (cleaned.match(/\./g) || []).length;
3303
- if (decimals > 1) return;
3565
+ if (decimals > 1) {
3566
+ resetRejectedInput(target, logicalCaret);
3567
+ return;
3568
+ }
3304
3569
  if (cleaned === "-" || cleaned === "." || cleaned === "-.") {
3305
- setDisplay(cleaned);
3570
+ setDisplayWithCaret(cleaned, logicalCaret);
3306
3571
  return;
3307
3572
  }
3308
- if (!useDecimal && cleaned.includes(".")) return;
3573
+ if (!useDecimal && cleaned.includes(".")) {
3574
+ resetRejectedInput(target, logicalCaret);
3575
+ return;
3576
+ }
3577
+ if (decimalLimit !== void 0 && cleaned.includes(".")) {
3578
+ const fraction = cleaned.split(".")[1] ?? "";
3579
+ if (fraction.length > decimalLimit) {
3580
+ resetRejectedInput(target, logicalCaret);
3581
+ return;
3582
+ }
3583
+ }
3309
3584
  if (cleaned.endsWith(".") && decimals === 1) {
3310
3585
  const parsed2 = toNumber(cleaned.slice(0, -1));
3311
3586
  if (parsed2 !== null) {
3312
- setDisplay(formatWithCommas(parsed2) + ".");
3587
+ setDisplayWithCaret(formatInputWithCommas(cleaned), logicalCaret);
3313
3588
  return;
3314
3589
  }
3315
3590
  }
3316
3591
  const parsed = toNumber(cleaned);
3317
- if (parsed === null) return;
3318
- emit(parsed);
3592
+ if (parsed === null) {
3593
+ resetRejectedInput(target, logicalCaret);
3594
+ return;
3595
+ }
3596
+ setDisplayWithCaret(formatInputWithCommas(cleaned), logicalCaret);
3597
+ onValueChange?.(applyDecimalLimit(parsed, decimalLimit));
3319
3598
  };
3320
3599
  const stepper = (dir) => {
3321
3600
  const off = dir === "inc" ? incDisabled : decDisabled;
@@ -3328,8 +3607,8 @@ var SNumberInput = react.forwardRef(function SNumberInput2({
3328
3607
  "aria-label": dir === "inc" ? "\uC99D\uAC00" : "\uAC10\uC18C",
3329
3608
  onClick: dir === "inc" ? increment : decrement,
3330
3609
  className: cn(
3331
- "flex flex-shrink-0 items-center justify-center",
3332
- off ? "cursor-not-allowed" : "cursor-pointer"
3610
+ "flex flex-shrink-0 items-center justify-center border border-solid border-transparent transition-colors",
3611
+ off ? "cursor-not-allowed" : "cursor-pointer hover:border-[var(--color-border-accentLight)]"
3333
3612
  ),
3334
3613
  style: {
3335
3614
  width: `var(--cmp-numberInput-stepper-${size}-size)`,
@@ -3378,24 +3657,26 @@ var SNumberInput = react.forwardRef(function SNumberInput2({
3378
3657
  style: {
3379
3658
  // 원본 sd-number-input: content gap = padding-x 토큰 (gap 토큰 아님)
3380
3659
  gap: `var(--cmp-numberInput-${size}-paddingX)`,
3381
- padding: `0 ${useButton ? padX : `calc(${padX} * 2)`}`
3660
+ padding: `0 ${useButton ? padX : `calc(${padX} * 2)`}`,
3661
+ fontSize: p.fontSize,
3662
+ lineHeight: `${p.lineHeight}px`
3382
3663
  },
3383
3664
  children: [
3384
3665
  useButton && stepper("dec"),
3385
- inputPrefix !== "" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", style: { fontSize: p.fontSize, color: affixColor }, children: inputPrefix }),
3666
+ inputPrefix !== "" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", style: { color: affixColor }, children: inputPrefix }),
3386
3667
  /* @__PURE__ */ jsxRuntime.jsx(
3387
3668
  "input",
3388
3669
  {
3389
3670
  ref: setRefs,
3390
3671
  name,
3391
3672
  type: "text",
3392
- inputMode: "numeric",
3673
+ inputMode: useDecimal ? "decimal" : "numeric",
3393
3674
  value: display,
3394
3675
  placeholder,
3395
3676
  disabled,
3396
3677
  readOnly,
3397
3678
  autoFocus,
3398
- onChange: (e) => handleInput(e.target.value),
3679
+ onChange: handleInput,
3399
3680
  onKeyDown: (e) => {
3400
3681
  if (e.key === "ArrowUp") {
3401
3682
  e.preventDefault();
@@ -3407,26 +3688,29 @@ var SNumberInput = react.forwardRef(function SNumberInput2({
3407
3688
  },
3408
3689
  onFocus: (e) => onFocus?.(e),
3409
3690
  onBlur: (e) => {
3410
- const n = toNumber(display);
3691
+ const cleaned = display.replace(/,/g, "");
3692
+ const n = toNumber(cleaned);
3411
3693
  const clamped = n === null ? null : Math.min(Math.max(n, min), max);
3412
3694
  if (clamped !== n) emit(clamped);
3413
- else setDisplay(formatWithCommas(n));
3695
+ else setDisplay(n === null ? "" : formatInputWithCommas(cleaned));
3414
3696
  if (rules && rules.length > 0) setRuleError(runRules(clamped, rules));
3415
3697
  onBlur?.(e);
3416
3698
  },
3417
3699
  className: cn(
3418
- "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",
3700
+ // h-full 대신 라인박스 높이 그대로 두어 prefix/suffix 동일하게 flex 로 수직 센터링
3701
+ // (h-full 이면 input 내부 텍스트 센터링을 브라우저가 수행해 1px 어긋날 수 있음)
3702
+ "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",
3419
3703
  inputClass
3420
3704
  ),
3421
3705
  style: {
3422
- fontSize: p.fontSize,
3706
+ // fontSize/lineHeight 는 컨테이너에서 상속
3423
3707
  textAlign: useButton ? "center" : "right",
3424
3708
  color: disabled ? "var(--cmp-numberInput-text-disabled)" : "var(--cmp-numberInput-text-default)",
3425
3709
  ...inputStyle
3426
3710
  }
3427
3711
  }
3428
3712
  ),
3429
- inputSuffix !== "" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", style: { fontSize: p.fontSize, color: affixColor }, children: inputSuffix }),
3713
+ inputSuffix !== "" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", style: { color: affixColor }, children: inputSuffix }),
3430
3714
  useButton && stepper("inc")
3431
3715
  ]
3432
3716
  }