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.
- package/dist/components/SActionModal/SActionModal.cjs +1 -1
- package/dist/components/SActionModal/SActionModal.cjs.map +1 -1
- package/dist/components/SActionModal/SActionModal.js +1 -1
- package/dist/components/SActionModal/SActionModal.js.map +1 -1
- package/dist/components/SBarcodeInput/SBarcodeInput.cjs +217 -208
- package/dist/components/SBarcodeInput/SBarcodeInput.cjs.map +1 -1
- package/dist/components/SBarcodeInput/SBarcodeInput.js +217 -208
- package/dist/components/SBarcodeInput/SBarcodeInput.js.map +1 -1
- package/dist/components/SCalendar/SCalendar.cjs +1 -1
- package/dist/components/SCalendar/SCalendar.cjs.map +1 -1
- package/dist/components/SCalendar/SCalendar.js +1 -1
- package/dist/components/SCalendar/SCalendar.js.map +1 -1
- package/dist/components/SChip/SChip.cjs +1 -1
- package/dist/components/SChip/SChip.cjs.map +1 -1
- package/dist/components/SChip/SChip.d.ts +1 -1
- package/dist/components/SChip/SChip.js +1 -1
- package/dist/components/SChip/SChip.js.map +1 -1
- package/dist/components/SChipInput/SChipInput.cjs +234 -220
- package/dist/components/SChipInput/SChipInput.cjs.map +1 -1
- package/dist/components/SChipInput/SChipInput.js +234 -220
- package/dist/components/SChipInput/SChipInput.js.map +1 -1
- package/dist/components/SCircleProgress/SCircleProgress.cjs +31 -14
- package/dist/components/SCircleProgress/SCircleProgress.cjs.map +1 -1
- package/dist/components/SCircleProgress/SCircleProgress.d.ts +2 -0
- package/dist/components/SCircleProgress/SCircleProgress.js +31 -14
- package/dist/components/SCircleProgress/SCircleProgress.js.map +1 -1
- package/dist/components/SDatePicker/SDatePicker.cjs +222 -213
- package/dist/components/SDatePicker/SDatePicker.cjs.map +1 -1
- package/dist/components/SDatePicker/SDatePicker.js +222 -213
- package/dist/components/SDatePicker/SDatePicker.js.map +1 -1
- package/dist/components/SDateRangePicker/SDateRangePicker.cjs +297 -262
- package/dist/components/SDateRangePicker/SDateRangePicker.cjs.map +1 -1
- package/dist/components/SDateRangePicker/SDateRangePicker.js +297 -262
- package/dist/components/SDateRangePicker/SDateRangePicker.js.map +1 -1
- package/dist/components/SDropdownButton/SDropdownButton.cjs +4 -4
- package/dist/components/SDropdownButton/SDropdownButton.cjs.map +1 -1
- package/dist/components/SDropdownButton/SDropdownButton.js +4 -4
- package/dist/components/SDropdownButton/SDropdownButton.js.map +1 -1
- package/dist/components/SField/SField.cjs +217 -20
- package/dist/components/SField/SField.cjs.map +1 -1
- package/dist/components/SField/SField.d.ts +11 -0
- package/dist/components/SField/SField.js +217 -20
- package/dist/components/SField/SField.js.map +1 -1
- package/dist/components/SFilePicker/SFilePicker.cjs +315 -276
- package/dist/components/SFilePicker/SFilePicker.cjs.map +1 -1
- package/dist/components/SFilePicker/SFilePicker.d.ts +4 -2
- package/dist/components/SFilePicker/SFilePicker.js +314 -276
- package/dist/components/SFilePicker/SFilePicker.js.map +1 -1
- package/dist/components/SInput/SInput.cjs +217 -208
- package/dist/components/SInput/SInput.cjs.map +1 -1
- package/dist/components/SInput/SInput.js +217 -208
- package/dist/components/SInput/SInput.js.map +1 -1
- package/dist/components/SKeyValueTable/SKeyValueTable.cjs +631 -450
- package/dist/components/SKeyValueTable/SKeyValueTable.cjs.map +1 -1
- package/dist/components/SKeyValueTable/SKeyValueTable.d.ts +3 -1
- package/dist/components/SKeyValueTable/SKeyValueTable.js +631 -450
- package/dist/components/SKeyValueTable/SKeyValueTable.js.map +1 -1
- package/dist/components/SLoadingContainer/SLoadingContainer.cjs +39 -14
- package/dist/components/SLoadingContainer/SLoadingContainer.cjs.map +1 -1
- package/dist/components/SLoadingContainer/SLoadingContainer.js +39 -14
- package/dist/components/SLoadingContainer/SLoadingContainer.js.map +1 -1
- package/dist/components/SLoadingContainer/loading.cjs +39 -14
- package/dist/components/SLoadingContainer/loading.cjs.map +1 -1
- package/dist/components/SLoadingContainer/loading.js +39 -14
- package/dist/components/SLoadingContainer/loading.js.map +1 -1
- package/dist/components/SLoadingModal/SLoadingModal.cjs +37 -16
- package/dist/components/SLoadingModal/SLoadingModal.cjs.map +1 -1
- package/dist/components/SLoadingModal/SLoadingModal.d.ts +3 -1
- package/dist/components/SLoadingModal/SLoadingModal.js +37 -16
- package/dist/components/SLoadingModal/SLoadingModal.js.map +1 -1
- package/dist/components/SNumberInput/SNumberInput.cjs +325 -49
- package/dist/components/SNumberInput/SNumberInput.cjs.map +1 -1
- package/dist/components/SNumberInput/SNumberInput.d.ts +2 -0
- package/dist/components/SNumberInput/SNumberInput.js +325 -49
- package/dist/components/SNumberInput/SNumberInput.js.map +1 -1
- package/dist/components/SPagination/SPagination.cjs +1 -1
- package/dist/components/SPagination/SPagination.cjs.map +1 -1
- package/dist/components/SPagination/SPagination.js +1 -1
- package/dist/components/SPagination/SPagination.js.map +1 -1
- package/dist/components/SRadio/SRadioGroup.cjs +1 -1
- package/dist/components/SRadio/SRadioGroup.cjs.map +1 -1
- package/dist/components/SRadio/SRadioGroup.js +1 -1
- package/dist/components/SRadio/SRadioGroup.js.map +1 -1
- package/dist/components/SSelect/SSelect.cjs +71 -32
- package/dist/components/SSelect/SSelect.cjs.map +1 -1
- package/dist/components/SSelect/SSelect.js +71 -32
- package/dist/components/SSelect/SSelect.js.map +1 -1
- package/dist/components/STable/STable.cjs +108 -49
- package/dist/components/STable/STable.cjs.map +1 -1
- package/dist/components/STable/STable.js +108 -49
- package/dist/components/STable/STable.js.map +1 -1
- package/dist/components/STextarea/STextarea.cjs +217 -20
- package/dist/components/STextarea/STextarea.cjs.map +1 -1
- package/dist/components/STextarea/STextarea.js +217 -20
- package/dist/components/STextarea/STextarea.js.map +1 -1
- package/dist/components/SToast/SToastContainer.cjs +3 -3
- package/dist/components/SToast/SToastContainer.cjs.map +1 -1
- package/dist/components/SToast/SToastContainer.js +3 -3
- package/dist/components/SToast/SToastContainer.js.map +1 -1
- package/dist/components/STooltip/STooltip.cjs +208 -13
- package/dist/components/STooltip/STooltip.cjs.map +1 -1
- package/dist/components/STooltip/STooltip.js +208 -13
- package/dist/components/STooltip/STooltip.js.map +1 -1
- package/dist/index.cjs +439 -221
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +439 -221
- package/dist/index.js.map +1 -1
- package/dist/styles.css +113 -48
- package/dist/theme.css +49 -23
- 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
|
|
8
|
+
var RPopover2 = require('@radix-ui/react-popover');
|
|
9
9
|
var Ariakit = require('@ariakit/react');
|
|
10
10
|
var RCheckbox = require('@radix-ui/react-checkbox');
|
|
11
11
|
|
|
@@ -27,7 +27,7 @@ function _interopNamespace(e) {
|
|
|
27
27
|
return Object.freeze(n);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
var
|
|
30
|
+
var RPopover2__namespace = /*#__PURE__*/_interopNamespace(RPopover2);
|
|
31
31
|
var Ariakit__namespace = /*#__PURE__*/_interopNamespace(Ariakit);
|
|
32
32
|
var RCheckbox__namespace = /*#__PURE__*/_interopNamespace(RCheckbox);
|
|
33
33
|
|
|
@@ -2901,11 +2901,200 @@ PortalContainerContext.Provider;
|
|
|
2901
2901
|
function usePortalContainer() {
|
|
2902
2902
|
return react.useContext(PortalContainerContext) ?? void 0;
|
|
2903
2903
|
}
|
|
2904
|
+
|
|
2905
|
+
// src/components/STag/tag.config.ts
|
|
2906
|
+
var TAG_SIZE_CONFIG = {
|
|
2907
|
+
xs: {
|
|
2908
|
+
height: 20,
|
|
2909
|
+
paddingX: 8,
|
|
2910
|
+
gap: 4,
|
|
2911
|
+
radius: 6,
|
|
2912
|
+
iconSize: 12,
|
|
2913
|
+
fontSize: 11,
|
|
2914
|
+
fontWeight: 500,
|
|
2915
|
+
lineHeight: 18
|
|
2916
|
+
},
|
|
2917
|
+
sm: {
|
|
2918
|
+
height: 24,
|
|
2919
|
+
paddingX: 8,
|
|
2920
|
+
gap: 4,
|
|
2921
|
+
radius: 6,
|
|
2922
|
+
iconSize: 16,
|
|
2923
|
+
fontSize: 12,
|
|
2924
|
+
fontWeight: 700,
|
|
2925
|
+
lineHeight: 20
|
|
2926
|
+
},
|
|
2927
|
+
md: {
|
|
2928
|
+
height: 28,
|
|
2929
|
+
paddingX: 12,
|
|
2930
|
+
gap: 6,
|
|
2931
|
+
radius: 8,
|
|
2932
|
+
iconSize: 16,
|
|
2933
|
+
fontSize: 14,
|
|
2934
|
+
fontWeight: 700,
|
|
2935
|
+
lineHeight: 24
|
|
2936
|
+
}
|
|
2937
|
+
};
|
|
2938
|
+
var STag = react.forwardRef(function STag2({
|
|
2939
|
+
shape = "square",
|
|
2940
|
+
size = "sm",
|
|
2941
|
+
color = "grey",
|
|
2942
|
+
label = "",
|
|
2943
|
+
icon,
|
|
2944
|
+
iconLeft = true,
|
|
2945
|
+
width,
|
|
2946
|
+
className,
|
|
2947
|
+
style,
|
|
2948
|
+
...rest
|
|
2949
|
+
}, ref) {
|
|
2950
|
+
const s = TAG_SIZE_CONFIG[size];
|
|
2951
|
+
const contentColor = `var(--cmp-tag-${color}-content)`;
|
|
2952
|
+
const iconNode = icon ? /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: icon, size: s.iconSize, color: contentColor }) : null;
|
|
2953
|
+
const resolvedWidth = typeof width === "number" ? `${width}px` : width;
|
|
2954
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2955
|
+
"span",
|
|
2956
|
+
{
|
|
2957
|
+
ref,
|
|
2958
|
+
"aria-label": label || "tag",
|
|
2959
|
+
className: cn(
|
|
2960
|
+
"box-border inline-flex w-fit select-none items-center justify-center whitespace-nowrap",
|
|
2961
|
+
className
|
|
2962
|
+
),
|
|
2963
|
+
style: {
|
|
2964
|
+
minHeight: s.height,
|
|
2965
|
+
padding: `0 ${s.paddingX}px`,
|
|
2966
|
+
gap: s.gap,
|
|
2967
|
+
borderRadius: shape === "pill" ? 999 : s.radius,
|
|
2968
|
+
fontSize: s.fontSize,
|
|
2969
|
+
fontWeight: s.fontWeight,
|
|
2970
|
+
lineHeight: `${s.lineHeight}px`,
|
|
2971
|
+
background: `var(--cmp-tag-${color}-bg)`,
|
|
2972
|
+
color: contentColor,
|
|
2973
|
+
...resolvedWidth != null ? { width: resolvedWidth } : {},
|
|
2974
|
+
...style
|
|
2975
|
+
},
|
|
2976
|
+
...rest,
|
|
2977
|
+
children: [
|
|
2978
|
+
icon && iconLeft && iconNode,
|
|
2979
|
+
label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex min-w-0 items-center justify-center", children: label }),
|
|
2980
|
+
icon && !iconLeft && iconNode
|
|
2981
|
+
]
|
|
2982
|
+
}
|
|
2983
|
+
);
|
|
2984
|
+
});
|
|
2985
|
+
var SIZE = {
|
|
2986
|
+
xxs: { icon: 12, radius: "sm" },
|
|
2987
|
+
xs: { icon: 16, radius: "sm" },
|
|
2988
|
+
sm: { icon: 20, radius: "sm" },
|
|
2989
|
+
md: { icon: 24, radius: "md" },
|
|
2990
|
+
lg: { icon: 32, radius: "md" }
|
|
2991
|
+
};
|
|
2992
|
+
var TOOLTIP_HIDE_DELAY_MS = 100;
|
|
2993
|
+
function SGhostButton({
|
|
2994
|
+
icon,
|
|
2995
|
+
size = "sm",
|
|
2996
|
+
intent = "default",
|
|
2997
|
+
ariaLabel = "",
|
|
2998
|
+
tooltipText,
|
|
2999
|
+
disabled = false,
|
|
3000
|
+
onClick,
|
|
3001
|
+
className,
|
|
3002
|
+
style
|
|
3003
|
+
}) {
|
|
3004
|
+
const portalContainer = usePortalContainer();
|
|
3005
|
+
const [open, setOpen] = react.useState(false);
|
|
3006
|
+
const hideTimer = react.useRef(void 0);
|
|
3007
|
+
const cancelHide = () => {
|
|
3008
|
+
if (hideTimer.current) {
|
|
3009
|
+
clearTimeout(hideTimer.current);
|
|
3010
|
+
hideTimer.current = void 0;
|
|
3011
|
+
}
|
|
3012
|
+
};
|
|
3013
|
+
const openNow = () => {
|
|
3014
|
+
cancelHide();
|
|
3015
|
+
setOpen(true);
|
|
3016
|
+
};
|
|
3017
|
+
const startHide = () => {
|
|
3018
|
+
cancelHide();
|
|
3019
|
+
hideTimer.current = setTimeout(() => setOpen(false), TOOLTIP_HIDE_DELAY_MS);
|
|
3020
|
+
};
|
|
3021
|
+
const s = SIZE[size];
|
|
3022
|
+
const contentColor = disabled ? intent === "inverse" ? "var(--cmp-ghostButton-inverse-disabled)" : "var(--cmp-ghostButton-icon-disabled)" : `var(--cmp-ghostButton-${intent}-content)`;
|
|
3023
|
+
const btn = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3024
|
+
"button",
|
|
3025
|
+
{
|
|
3026
|
+
type: "button",
|
|
3027
|
+
disabled,
|
|
3028
|
+
"aria-disabled": disabled ? "true" : void 0,
|
|
3029
|
+
"aria-label": ariaLabel.trim() || void 0,
|
|
3030
|
+
tabIndex: disabled ? -1 : void 0,
|
|
3031
|
+
onClick: (e) => {
|
|
3032
|
+
if (disabled) {
|
|
3033
|
+
e.preventDefault();
|
|
3034
|
+
return;
|
|
3035
|
+
}
|
|
3036
|
+
onClick?.(e);
|
|
3037
|
+
},
|
|
3038
|
+
className: cn(
|
|
3039
|
+
"group relative box-border inline-flex items-center justify-center border-none bg-transparent p-0 transition-shadow",
|
|
3040
|
+
disabled ? "cursor-not-allowed" : "cursor-pointer",
|
|
3041
|
+
"focus-visible:outline-none focus-visible:shadow-[0_0_0_2px_var(--cmp-ghostButton-action-hover-bg)]",
|
|
3042
|
+
className
|
|
3043
|
+
),
|
|
3044
|
+
style: {
|
|
3045
|
+
width: `var(--cmp-ghostButton-${size}-size)`,
|
|
3046
|
+
height: `var(--cmp-ghostButton-${size}-size)`,
|
|
3047
|
+
borderRadius: `var(--cmp-ghostButton-radius-${s.radius})`,
|
|
3048
|
+
...style
|
|
3049
|
+
},
|
|
3050
|
+
children: [
|
|
3051
|
+
!disabled && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3052
|
+
"span",
|
|
3053
|
+
{
|
|
3054
|
+
"aria-hidden": true,
|
|
3055
|
+
className: "pointer-events-none absolute inset-0 rounded-[inherit] opacity-0 transition-opacity duration-200 group-hover:opacity-5",
|
|
3056
|
+
style: { background: `var(--cmp-ghostButton-${intent}-hover-bg)` }
|
|
3057
|
+
}
|
|
3058
|
+
),
|
|
3059
|
+
/* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: icon, size: s.icon, color: contentColor })
|
|
3060
|
+
]
|
|
3061
|
+
}
|
|
3062
|
+
);
|
|
3063
|
+
const text = (tooltipText ?? "").trim();
|
|
3064
|
+
if (text === "") return btn;
|
|
3065
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(RPopover2__namespace.Root, { open, onOpenChange: setOpen, children: [
|
|
3066
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Anchor, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3067
|
+
"span",
|
|
3068
|
+
{
|
|
3069
|
+
className: "inline-flex",
|
|
3070
|
+
onMouseEnter: openNow,
|
|
3071
|
+
onMouseLeave: startHide,
|
|
3072
|
+
onFocus: openNow,
|
|
3073
|
+
onBlur: startHide,
|
|
3074
|
+
children: btn
|
|
3075
|
+
}
|
|
3076
|
+
) }),
|
|
3077
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3078
|
+
RPopover2__namespace.Content,
|
|
3079
|
+
{
|
|
3080
|
+
side: "top",
|
|
3081
|
+
sideOffset: 4,
|
|
3082
|
+
className: cn("z-50", FLOATING_SLIDE_ANIM),
|
|
3083
|
+
"aria-hidden": true,
|
|
3084
|
+
onOpenAutoFocus: (e) => e.preventDefault(),
|
|
3085
|
+
onMouseEnter: cancelHide,
|
|
3086
|
+
onMouseLeave: startHide,
|
|
3087
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(STag, { shape: "square", size: "xs", color: "grey", label: text })
|
|
3088
|
+
}
|
|
3089
|
+
) })
|
|
3090
|
+
] });
|
|
3091
|
+
}
|
|
2904
3092
|
var HIDE_DELAY_MS = 100;
|
|
2905
3093
|
function useBody(content, message = []) {
|
|
2906
3094
|
if (content != null) return content;
|
|
2907
3095
|
if (message.length === 0) return null;
|
|
2908
|
-
|
|
3096
|
+
const singleLine = message.length === 1;
|
|
3097
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: message.map((line, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: singleLine ? "leading-[24px]" : void 0, children: line }, i)) });
|
|
2909
3098
|
}
|
|
2910
3099
|
var STooltip = react.forwardRef(function STooltip2({
|
|
2911
3100
|
content,
|
|
@@ -2973,10 +3162,10 @@ var STooltip = react.forwardRef(function STooltip2({
|
|
|
2973
3162
|
fontWeight: tooltipType === "default" ? 500 : 700,
|
|
2974
3163
|
...style
|
|
2975
3164
|
};
|
|
2976
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3165
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(RPopover2__namespace.Root, { open, onOpenChange: setOpen, children: [
|
|
2977
3166
|
isHover ? (
|
|
2978
3167
|
// hover: Anchor(위치 기준) + 직접 mouse 핸들러 — 클릭으로 토글되지 않도록 Trigger 미사용
|
|
2979
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3168
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Anchor, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2980
3169
|
"span",
|
|
2981
3170
|
{
|
|
2982
3171
|
className: "inline-flex",
|
|
@@ -2987,9 +3176,9 @@ var STooltip = react.forwardRef(function STooltip2({
|
|
|
2987
3176
|
children: triggerNode
|
|
2988
3177
|
}
|
|
2989
3178
|
) })
|
|
2990
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2991
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2992
|
-
|
|
3179
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Trigger, { asChild: true, children: triggerNode }),
|
|
3180
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3181
|
+
RPopover2__namespace.Content,
|
|
2993
3182
|
{
|
|
2994
3183
|
side: placement,
|
|
2995
3184
|
sideOffset: 8,
|
|
@@ -3008,15 +3197,21 @@ var STooltip = react.forwardRef(function STooltip2({
|
|
|
3008
3197
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-[12px]", children: [
|
|
3009
3198
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children: body }),
|
|
3010
3199
|
useClose && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3011
|
-
|
|
3200
|
+
SGhostButton,
|
|
3012
3201
|
{
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3202
|
+
icon: "close",
|
|
3203
|
+
size: "xs",
|
|
3204
|
+
intent: tooltipType === "default" ? "inverse" : "default",
|
|
3205
|
+
ariaLabel: "\uB2EB\uAE30",
|
|
3206
|
+
className: "shrink-0",
|
|
3207
|
+
onClick: () => {
|
|
3208
|
+
cancelHide();
|
|
3209
|
+
setOpen(false);
|
|
3210
|
+
}
|
|
3016
3211
|
}
|
|
3017
3212
|
)
|
|
3018
3213
|
] }),
|
|
3019
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3214
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Arrow, { width: 16, height: 12, style: { fill: bg } })
|
|
3020
3215
|
]
|
|
3021
3216
|
}
|
|
3022
3217
|
) })
|
|
@@ -3216,8 +3411,8 @@ function useFormField(field) {
|
|
|
3216
3411
|
}, [ctx, name]);
|
|
3217
3412
|
}
|
|
3218
3413
|
var FIELD_SIZE = {
|
|
3219
|
-
sm: { height: 28, radius: 4, fieldGap: 12, labelGap: 6, fontSize: 12, lineHeight: 20, icon:
|
|
3220
|
-
md: { height: 36, radius: 6, fieldGap: 16, labelGap: 8, fontSize: 14, lineHeight: 24, icon:
|
|
3414
|
+
sm: { height: 28, radius: 4, fieldGap: 12, labelGap: 6, fontSize: 12, lineHeight: 20, icon: 16 },
|
|
3415
|
+
md: { height: 36, radius: 6, fieldGap: 16, labelGap: 8, fontSize: 14, lineHeight: 24, icon: 16 }
|
|
3221
3416
|
};
|
|
3222
3417
|
var ALIGN = {
|
|
3223
3418
|
start: "flex-start",
|
|
@@ -3232,6 +3427,7 @@ var SField = react.forwardRef(function SField2({
|
|
|
3232
3427
|
labelTooltip = "",
|
|
3233
3428
|
labelTooltipProps,
|
|
3234
3429
|
labelWidth,
|
|
3430
|
+
labelHeight,
|
|
3235
3431
|
size = "sm",
|
|
3236
3432
|
addonLabel = "",
|
|
3237
3433
|
addonAlign = "start",
|
|
@@ -3246,6 +3442,7 @@ var SField = react.forwardRef(function SField2({
|
|
|
3246
3442
|
readOnly = false,
|
|
3247
3443
|
width,
|
|
3248
3444
|
multiline = false,
|
|
3445
|
+
borderless = false,
|
|
3249
3446
|
children,
|
|
3250
3447
|
className,
|
|
3251
3448
|
style,
|
|
@@ -3279,8 +3476,8 @@ var SField = react.forwardRef(function SField2({
|
|
|
3279
3476
|
const resolvedSuccess = status === "pass";
|
|
3280
3477
|
const showError = resolvedError && errorMessage !== "";
|
|
3281
3478
|
const interactive = !disabled && !readOnly;
|
|
3282
|
-
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)";
|
|
3283
|
-
const bgColor = disabled ? "var(--color-grey-30)" : readOnly ? "var(--sys-color-field-bg-readOnly)" : "var(--sys-color-field-bg-default)";
|
|
3479
|
+
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)";
|
|
3480
|
+
const bgColor = borderless ? "transparent" : disabled ? "var(--color-grey-30)" : readOnly ? "var(--sys-color-field-bg-readOnly)" : "var(--sys-color-field-bg-default)";
|
|
3284
3481
|
const textColor = disabled ? "var(--color-grey-65)" : readOnly ? "var(--sys-color-field-text-readOnly)" : "var(--sys-color-field-text-default)";
|
|
3285
3482
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3286
3483
|
"div",
|
|
@@ -3297,266 +3494,78 @@ var SField = react.forwardRef(function SField2({
|
|
|
3297
3494
|
{
|
|
3298
3495
|
className: "flex shrink-0 items-center font-bold text-(--sys-color-field-text-default)",
|
|
3299
3496
|
style: {
|
|
3300
|
-
height: s.height,
|
|
3497
|
+
height: cssLen(labelHeight) ?? s.height,
|
|
3301
3498
|
marginRight: s.fieldGap,
|
|
3302
3499
|
width: cssLen(labelWidth),
|
|
3303
|
-
fontSize: s.fontSize,
|
|
3304
|
-
lineHeight: `${s.lineHeight}px`
|
|
3305
|
-
},
|
|
3306
|
-
children: [
|
|
3307
|
-
icon && /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: icon, size: s.icon, style: { marginRight: s.labelGap } }),
|
|
3308
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 overflow-hidden text-ellipsis whitespace-nowrap", children: label }),
|
|
3309
|
-
(labelTooltip !== "" || labelTooltipProps) && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", style: { marginLeft: s.labelGap }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3310
|
-
STooltip,
|
|
3311
|
-
{
|
|
3312
|
-
message: labelTooltip !== "" ? [labelTooltip] : void 0,
|
|
3313
|
-
iconSize: s.icon,
|
|
3314
|
-
...labelTooltipProps
|
|
3315
|
-
}
|
|
3316
|
-
) })
|
|
3317
|
-
]
|
|
3318
|
-
}
|
|
3319
|
-
),
|
|
3320
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [
|
|
3321
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3322
|
-
"div",
|
|
3323
|
-
{
|
|
3324
|
-
className: cn(
|
|
3325
|
-
"relative box-border flex min-w-0 items-stretch overflow-hidden border border-solid border-(--field-bc)",
|
|
3326
|
-
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]",
|
|
3327
|
-
disabled && "cursor-not-allowed"
|
|
3328
|
-
),
|
|
3329
|
-
style: {
|
|
3330
|
-
// @ts-expect-error CSS 변수
|
|
3331
|
-
"--field-bc": borderColor,
|
|
3332
|
-
// focused/hovered prop이 명시된 경우 강조를 즉시 반영
|
|
3333
|
-
...interactive && focused ? { boxShadow: "0px 0px 4px 0px #0071ff66" } : {},
|
|
3334
|
-
...multiline ? { minHeight: s.height } : { height: s.height },
|
|
3335
|
-
"width": cssLen(width),
|
|
3336
|
-
"borderRadius": s.radius,
|
|
3337
|
-
"background": bgColor,
|
|
3338
|
-
"color": textColor
|
|
3339
|
-
},
|
|
3340
|
-
"data-focused": focused || void 0,
|
|
3341
|
-
"data-hovered": hovered || void 0,
|
|
3342
|
-
children: [
|
|
3343
|
-
effectiveAddonLabel !== "" && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3344
|
-
"div",
|
|
3345
|
-
{
|
|
3346
|
-
className: "flex shrink-0 items-center gap-(--cmp-field-addonLabel-gap) whitespace-nowrap border-r border-solid px-(--cmp-field-addonLabel-paddingX) text-12 font-medium leading-20",
|
|
3347
|
-
style: {
|
|
3348
|
-
// 원본 sd-field: labelWidth가 addon 폭(--sd-field-addon-width)에도 적용됨
|
|
3349
|
-
width: cssLen(labelWidth),
|
|
3350
|
-
justifyContent: ALIGN[addonAlign],
|
|
3351
|
-
background: "var(--cmp-field-addonLabel-bg)",
|
|
3352
|
-
borderRightColor: disabled ? "var(--cmp-field-addonLabel-border-disabled)" : "var(--cmp-field-addonLabel-border-default)",
|
|
3353
|
-
borderTopLeftRadius: s.radius - 1,
|
|
3354
|
-
borderBottomLeftRadius: s.radius - 1
|
|
3355
|
-
},
|
|
3356
|
-
children: [
|
|
3357
|
-
icon && !label && /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: icon, size: s.icon }),
|
|
3358
|
-
effectiveAddonLabel
|
|
3359
|
-
]
|
|
3360
|
-
}
|
|
3361
|
-
),
|
|
3362
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-w-0 flex-1", children })
|
|
3363
|
-
]
|
|
3364
|
-
}
|
|
3365
|
-
),
|
|
3366
|
-
showError ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-(--cmp-field-contents-gap) text-12 font-normal leading-20 text-(--cmp-field-errorMessage-color)", children: errorMessage }) : hint !== "" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-(--cmp-field-contents-gap) text-12 font-normal leading-20 text-(--cmp-field-hint-color)", children: hint }) : null
|
|
3367
|
-
] })
|
|
3368
|
-
] })
|
|
3369
|
-
}
|
|
3370
|
-
);
|
|
3371
|
-
});
|
|
3372
|
-
|
|
3373
|
-
// src/components/STag/tag.config.ts
|
|
3374
|
-
var TAG_SIZE_CONFIG = {
|
|
3375
|
-
xs: {
|
|
3376
|
-
height: 20,
|
|
3377
|
-
paddingX: 8,
|
|
3378
|
-
gap: 4,
|
|
3379
|
-
radius: 6,
|
|
3380
|
-
iconSize: 12,
|
|
3381
|
-
fontSize: 11,
|
|
3382
|
-
fontWeight: 500,
|
|
3383
|
-
lineHeight: 18
|
|
3384
|
-
},
|
|
3385
|
-
sm: {
|
|
3386
|
-
height: 24,
|
|
3387
|
-
paddingX: 8,
|
|
3388
|
-
gap: 4,
|
|
3389
|
-
radius: 6,
|
|
3390
|
-
iconSize: 16,
|
|
3391
|
-
fontSize: 12,
|
|
3392
|
-
fontWeight: 700,
|
|
3393
|
-
lineHeight: 20
|
|
3394
|
-
},
|
|
3395
|
-
md: {
|
|
3396
|
-
height: 28,
|
|
3397
|
-
paddingX: 12,
|
|
3398
|
-
gap: 6,
|
|
3399
|
-
radius: 8,
|
|
3400
|
-
iconSize: 16,
|
|
3401
|
-
fontSize: 14,
|
|
3402
|
-
fontWeight: 700,
|
|
3403
|
-
lineHeight: 24
|
|
3404
|
-
}
|
|
3405
|
-
};
|
|
3406
|
-
var STag = react.forwardRef(function STag2({
|
|
3407
|
-
shape = "square",
|
|
3408
|
-
size = "sm",
|
|
3409
|
-
color = "grey",
|
|
3410
|
-
label = "",
|
|
3411
|
-
icon,
|
|
3412
|
-
iconLeft = true,
|
|
3413
|
-
width,
|
|
3414
|
-
className,
|
|
3415
|
-
style,
|
|
3416
|
-
...rest
|
|
3417
|
-
}, ref) {
|
|
3418
|
-
const s = TAG_SIZE_CONFIG[size];
|
|
3419
|
-
const contentColor = `var(--cmp-tag-${color}-content)`;
|
|
3420
|
-
const iconNode = icon ? /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: icon, size: s.iconSize, color: contentColor }) : null;
|
|
3421
|
-
const resolvedWidth = typeof width === "number" ? `${width}px` : width;
|
|
3422
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3423
|
-
"span",
|
|
3424
|
-
{
|
|
3425
|
-
ref,
|
|
3426
|
-
"aria-label": label || "tag",
|
|
3427
|
-
className: cn(
|
|
3428
|
-
"box-border inline-flex w-fit select-none items-center justify-center whitespace-nowrap",
|
|
3429
|
-
className
|
|
3430
|
-
),
|
|
3431
|
-
style: {
|
|
3432
|
-
minHeight: s.height,
|
|
3433
|
-
padding: `0 ${s.paddingX}px`,
|
|
3434
|
-
gap: s.gap,
|
|
3435
|
-
borderRadius: shape === "pill" ? 999 : s.radius,
|
|
3436
|
-
fontSize: s.fontSize,
|
|
3437
|
-
fontWeight: s.fontWeight,
|
|
3438
|
-
lineHeight: `${s.lineHeight}px`,
|
|
3439
|
-
background: `var(--cmp-tag-${color}-bg)`,
|
|
3440
|
-
color: contentColor,
|
|
3441
|
-
...resolvedWidth != null ? { width: resolvedWidth } : {},
|
|
3442
|
-
...style
|
|
3443
|
-
},
|
|
3444
|
-
...rest,
|
|
3445
|
-
children: [
|
|
3446
|
-
icon && iconLeft && iconNode,
|
|
3447
|
-
label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex min-w-0 items-center justify-center", children: label }),
|
|
3448
|
-
icon && !iconLeft && iconNode
|
|
3449
|
-
]
|
|
3450
|
-
}
|
|
3451
|
-
);
|
|
3452
|
-
});
|
|
3453
|
-
var SIZE = {
|
|
3454
|
-
xxs: { icon: 12, radius: "sm" },
|
|
3455
|
-
xs: { icon: 16, radius: "sm" },
|
|
3456
|
-
sm: { icon: 20, radius: "sm" },
|
|
3457
|
-
md: { icon: 24, radius: "md" },
|
|
3458
|
-
lg: { icon: 32, radius: "md" }
|
|
3459
|
-
};
|
|
3460
|
-
var TOOLTIP_HIDE_DELAY_MS = 100;
|
|
3461
|
-
function SGhostButton({
|
|
3462
|
-
icon,
|
|
3463
|
-
size = "sm",
|
|
3464
|
-
intent = "default",
|
|
3465
|
-
ariaLabel = "",
|
|
3466
|
-
tooltipText,
|
|
3467
|
-
disabled = false,
|
|
3468
|
-
onClick,
|
|
3469
|
-
className,
|
|
3470
|
-
style
|
|
3471
|
-
}) {
|
|
3472
|
-
const portalContainer = usePortalContainer();
|
|
3473
|
-
const [open, setOpen] = react.useState(false);
|
|
3474
|
-
const hideTimer = react.useRef(void 0);
|
|
3475
|
-
const cancelHide = () => {
|
|
3476
|
-
if (hideTimer.current) {
|
|
3477
|
-
clearTimeout(hideTimer.current);
|
|
3478
|
-
hideTimer.current = void 0;
|
|
3479
|
-
}
|
|
3480
|
-
};
|
|
3481
|
-
const openNow = () => {
|
|
3482
|
-
cancelHide();
|
|
3483
|
-
setOpen(true);
|
|
3484
|
-
};
|
|
3485
|
-
const startHide = () => {
|
|
3486
|
-
cancelHide();
|
|
3487
|
-
hideTimer.current = setTimeout(() => setOpen(false), TOOLTIP_HIDE_DELAY_MS);
|
|
3488
|
-
};
|
|
3489
|
-
const s = SIZE[size];
|
|
3490
|
-
const contentColor = disabled ? intent === "inverse" ? "var(--cmp-ghostButton-inverse-disabled)" : "var(--cmp-ghostButton-icon-disabled)" : `var(--cmp-ghostButton-${intent}-content)`;
|
|
3491
|
-
const btn = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3492
|
-
"button",
|
|
3493
|
-
{
|
|
3494
|
-
type: "button",
|
|
3495
|
-
disabled,
|
|
3496
|
-
"aria-disabled": disabled ? "true" : void 0,
|
|
3497
|
-
"aria-label": ariaLabel.trim() || void 0,
|
|
3498
|
-
tabIndex: disabled ? -1 : void 0,
|
|
3499
|
-
onClick: (e) => {
|
|
3500
|
-
if (disabled) {
|
|
3501
|
-
e.preventDefault();
|
|
3502
|
-
return;
|
|
3503
|
-
}
|
|
3504
|
-
onClick?.(e);
|
|
3505
|
-
},
|
|
3506
|
-
className: cn(
|
|
3507
|
-
"group relative box-border inline-flex items-center justify-center border-none bg-transparent p-0 transition-shadow",
|
|
3508
|
-
disabled ? "cursor-not-allowed" : "cursor-pointer",
|
|
3509
|
-
"focus-visible:outline-none focus-visible:shadow-[0_0_0_2px_var(--cmp-ghostButton-action-hover-bg)]",
|
|
3510
|
-
className
|
|
3511
|
-
),
|
|
3512
|
-
style: {
|
|
3513
|
-
width: `var(--cmp-ghostButton-${size}-size)`,
|
|
3514
|
-
height: `var(--cmp-ghostButton-${size}-size)`,
|
|
3515
|
-
borderRadius: `var(--cmp-ghostButton-radius-${s.radius})`,
|
|
3516
|
-
...style
|
|
3517
|
-
},
|
|
3518
|
-
children: [
|
|
3519
|
-
!disabled && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3520
|
-
"span",
|
|
3521
|
-
{
|
|
3522
|
-
"aria-hidden": true,
|
|
3523
|
-
className: "pointer-events-none absolute inset-0 rounded-[inherit] opacity-0 transition-opacity duration-200 group-hover:opacity-5",
|
|
3524
|
-
style: { background: `var(--cmp-ghostButton-${intent}-hover-bg)` }
|
|
3500
|
+
fontSize: s.fontSize,
|
|
3501
|
+
lineHeight: `${s.lineHeight}px`
|
|
3502
|
+
},
|
|
3503
|
+
children: [
|
|
3504
|
+
icon && /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: icon, size: s.icon, style: { marginRight: s.labelGap } }),
|
|
3505
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 overflow-hidden text-ellipsis whitespace-nowrap", children: label }),
|
|
3506
|
+
(labelTooltip !== "" || labelTooltipProps) && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", style: { marginLeft: s.labelGap }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3507
|
+
STooltip,
|
|
3508
|
+
{
|
|
3509
|
+
message: labelTooltip !== "" ? [labelTooltip] : void 0,
|
|
3510
|
+
iconSize: s.icon,
|
|
3511
|
+
...labelTooltipProps
|
|
3512
|
+
}
|
|
3513
|
+
) })
|
|
3514
|
+
]
|
|
3525
3515
|
}
|
|
3526
3516
|
),
|
|
3527
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3528
|
-
|
|
3517
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [
|
|
3518
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3519
|
+
"div",
|
|
3520
|
+
{
|
|
3521
|
+
className: cn(
|
|
3522
|
+
"relative box-border flex min-w-0 items-stretch overflow-hidden border border-solid border-(--field-bc)",
|
|
3523
|
+
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]",
|
|
3524
|
+
disabled && "cursor-not-allowed"
|
|
3525
|
+
),
|
|
3526
|
+
style: {
|
|
3527
|
+
// @ts-expect-error CSS 변수
|
|
3528
|
+
"--field-bc": borderColor,
|
|
3529
|
+
// focused/hovered prop이 명시된 경우 강조를 즉시 반영
|
|
3530
|
+
...interactive && !borderless && focused ? { boxShadow: "0px 0px 4px 0px #0071ff66" } : {},
|
|
3531
|
+
...multiline ? { minHeight: s.height } : { height: s.height },
|
|
3532
|
+
"width": cssLen(width),
|
|
3533
|
+
"borderRadius": s.radius,
|
|
3534
|
+
"background": bgColor,
|
|
3535
|
+
"color": textColor
|
|
3536
|
+
},
|
|
3537
|
+
"data-focused": focused || void 0,
|
|
3538
|
+
"data-hovered": hovered || void 0,
|
|
3539
|
+
children: [
|
|
3540
|
+
effectiveAddonLabel !== "" && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3541
|
+
"div",
|
|
3542
|
+
{
|
|
3543
|
+
className: "flex shrink-0 items-center gap-(--cmp-field-addonLabel-gap) whitespace-nowrap border-r border-solid px-(--cmp-field-addonLabel-paddingX) text-12 font-medium leading-20",
|
|
3544
|
+
style: {
|
|
3545
|
+
// 원본 sd-field: labelWidth가 addon 폭(--sd-field-addon-width)에도 적용됨
|
|
3546
|
+
width: cssLen(labelWidth),
|
|
3547
|
+
justifyContent: ALIGN[addonAlign],
|
|
3548
|
+
background: "var(--cmp-field-addonLabel-bg)",
|
|
3549
|
+
borderRightColor: disabled ? "var(--cmp-field-addonLabel-border-disabled)" : "var(--cmp-field-addonLabel-border-default)",
|
|
3550
|
+
borderTopLeftRadius: s.radius - 1,
|
|
3551
|
+
borderBottomLeftRadius: s.radius - 1
|
|
3552
|
+
},
|
|
3553
|
+
children: [
|
|
3554
|
+
icon && !label && /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: icon, size: s.icon }),
|
|
3555
|
+
effectiveAddonLabel
|
|
3556
|
+
]
|
|
3557
|
+
}
|
|
3558
|
+
),
|
|
3559
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-w-0 flex-1", children })
|
|
3560
|
+
]
|
|
3561
|
+
}
|
|
3562
|
+
),
|
|
3563
|
+
showError ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-(--cmp-field-contents-gap) text-12 font-normal leading-20 text-(--cmp-field-errorMessage-color)", children: errorMessage }) : hint !== "" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-(--cmp-field-contents-gap) text-12 font-normal leading-20 text-(--cmp-field-hint-color)", children: hint }) : null
|
|
3564
|
+
] })
|
|
3565
|
+
] })
|
|
3529
3566
|
}
|
|
3530
3567
|
);
|
|
3531
|
-
|
|
3532
|
-
if (text === "") return btn;
|
|
3533
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(RPopover__namespace.Root, { open, onOpenChange: setOpen, children: [
|
|
3534
|
-
/* @__PURE__ */ jsxRuntime.jsx(RPopover__namespace.Anchor, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3535
|
-
"span",
|
|
3536
|
-
{
|
|
3537
|
-
className: "inline-flex",
|
|
3538
|
-
onMouseEnter: openNow,
|
|
3539
|
-
onMouseLeave: startHide,
|
|
3540
|
-
onFocus: openNow,
|
|
3541
|
-
onBlur: startHide,
|
|
3542
|
-
children: btn
|
|
3543
|
-
}
|
|
3544
|
-
) }),
|
|
3545
|
-
/* @__PURE__ */ jsxRuntime.jsx(RPopover__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3546
|
-
RPopover__namespace.Content,
|
|
3547
|
-
{
|
|
3548
|
-
side: "top",
|
|
3549
|
-
sideOffset: 4,
|
|
3550
|
-
className: cn("z-50", FLOATING_SLIDE_ANIM),
|
|
3551
|
-
"aria-hidden": true,
|
|
3552
|
-
onOpenAutoFocus: (e) => e.preventDefault(),
|
|
3553
|
-
onMouseEnter: cancelHide,
|
|
3554
|
-
onMouseLeave: startHide,
|
|
3555
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(STag, { shape: "square", size: "xs", color: "grey", label: text })
|
|
3556
|
-
}
|
|
3557
|
-
) })
|
|
3558
|
-
] });
|
|
3559
|
-
}
|
|
3568
|
+
});
|
|
3560
3569
|
var FONT = {
|
|
3561
3570
|
sm: { fontSize: 12, lineHeight: 20, paddingX: "var(--cmp-textinput-sm-paddingX)" },
|
|
3562
3571
|
md: { fontSize: 14, lineHeight: 24, paddingX: "var(--cmp-textinput-md-paddingX)" }
|
|
@@ -3811,8 +3820,8 @@ var STextarea = react.forwardRef(function STextarea2({
|
|
|
3811
3820
|
);
|
|
3812
3821
|
});
|
|
3813
3822
|
var PAD2 = {
|
|
3814
|
-
sm: { fontSize: 12, stepper: 20, icon: 12 },
|
|
3815
|
-
md: { fontSize: 14, stepper: 24, icon: 14 }
|
|
3823
|
+
sm: { fontSize: 12, lineHeight: 20, stepper: 20, icon: 12 },
|
|
3824
|
+
md: { fontSize: 14, lineHeight: 24, stepper: 24, icon: 14 }
|
|
3816
3825
|
};
|
|
3817
3826
|
var toNumber = (val) => {
|
|
3818
3827
|
if (val === null || val === void 0 || val === "") return null;
|
|
@@ -3830,6 +3839,38 @@ var formatWithCommas = (value) => {
|
|
|
3830
3839
|
const result = isNeg ? "-" + formatted : formatted;
|
|
3831
3840
|
return decPart !== void 0 && decPart !== "" ? result + "." + decPart : result;
|
|
3832
3841
|
};
|
|
3842
|
+
var addCommas = (value) => value.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
3843
|
+
var formatInputWithCommas = (value) => {
|
|
3844
|
+
const isNeg = value.startsWith("-");
|
|
3845
|
+
const unsigned = isNeg ? value.slice(1) : value;
|
|
3846
|
+
const hasDecimal = unsigned.includes(".");
|
|
3847
|
+
const [intPart = "", decPart = ""] = unsigned.split(".");
|
|
3848
|
+
const formattedInt = addCommas(intPart === "" ? "0" : intPart);
|
|
3849
|
+
return `${isNeg ? "-" : ""}${formattedInt}${hasDecimal ? `.${decPart}` : ""}`;
|
|
3850
|
+
};
|
|
3851
|
+
var getDecimalLimit = (useDecimal, maxDecimalLength) => {
|
|
3852
|
+
if (!useDecimal || maxDecimalLength === void 0 || !Number.isFinite(maxDecimalLength)) {
|
|
3853
|
+
return void 0;
|
|
3854
|
+
}
|
|
3855
|
+
return Math.max(0, Math.floor(maxDecimalLength));
|
|
3856
|
+
};
|
|
3857
|
+
var applyDecimalLimit = (value, decimalLimit) => {
|
|
3858
|
+
if (value === null || decimalLimit === void 0) return value;
|
|
3859
|
+
return Number(value.toFixed(decimalLimit));
|
|
3860
|
+
};
|
|
3861
|
+
var getLogicalCaret = (value, caret) => {
|
|
3862
|
+
return value.slice(0, caret ?? value.length).replace(/,/g, "").length;
|
|
3863
|
+
};
|
|
3864
|
+
var getDisplayCaret = (value, logicalCaret) => {
|
|
3865
|
+
if (logicalCaret <= 0) return 0;
|
|
3866
|
+
let seen = 0;
|
|
3867
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
3868
|
+
if (value[i] === ",") continue;
|
|
3869
|
+
seen += 1;
|
|
3870
|
+
if (seen >= logicalCaret) return i + 1;
|
|
3871
|
+
}
|
|
3872
|
+
return value.length;
|
|
3873
|
+
};
|
|
3833
3874
|
var SNumberInput = react.forwardRef(function SNumberInput2({
|
|
3834
3875
|
value,
|
|
3835
3876
|
onValueChange,
|
|
@@ -3839,6 +3880,7 @@ var SNumberInput = react.forwardRef(function SNumberInput2({
|
|
|
3839
3880
|
step = 1,
|
|
3840
3881
|
useButton = false,
|
|
3841
3882
|
useDecimal = false,
|
|
3883
|
+
maxDecimalLength,
|
|
3842
3884
|
inputPrefix = "",
|
|
3843
3885
|
inputSuffix = "",
|
|
3844
3886
|
inputClass,
|
|
@@ -3870,7 +3912,8 @@ var SNumberInput = react.forwardRef(function SNumberInput2({
|
|
|
3870
3912
|
}, ref) {
|
|
3871
3913
|
const p = PAD2[size];
|
|
3872
3914
|
const padX = `var(--cmp-numberInput-${size}-paddingX)`;
|
|
3873
|
-
const
|
|
3915
|
+
const decimalLimit = getDecimalLimit(useDecimal, maxDecimalLength);
|
|
3916
|
+
const numValue = applyDecimalLimit(toNumber(value), decimalLimit);
|
|
3874
3917
|
const [display, setDisplay] = react.useState(() => formatWithCommas(numValue));
|
|
3875
3918
|
const [ruleError, setRuleError] = react.useState("");
|
|
3876
3919
|
const innerRef = react.useRef(null);
|
|
@@ -3880,8 +3923,9 @@ var SNumberInput = react.forwardRef(function SNumberInput2({
|
|
|
3880
3923
|
else if (ref) ref.current = el;
|
|
3881
3924
|
};
|
|
3882
3925
|
react.useEffect(() => {
|
|
3883
|
-
|
|
3884
|
-
|
|
3926
|
+
if (document.activeElement === innerRef.current) return;
|
|
3927
|
+
setDisplay(formatWithCommas(applyDecimalLimit(toNumber(value), decimalLimit)));
|
|
3928
|
+
}, [decimalLimit, value]);
|
|
3885
3929
|
useFormField({
|
|
3886
3930
|
name,
|
|
3887
3931
|
validate: () => {
|
|
@@ -3893,48 +3937,87 @@ var SNumberInput = react.forwardRef(function SNumberInput2({
|
|
|
3893
3937
|
});
|
|
3894
3938
|
const resolvedError = error || ruleError !== "";
|
|
3895
3939
|
const resolvedStatus = status ?? (rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0);
|
|
3896
|
-
const
|
|
3897
|
-
|
|
3898
|
-
|
|
3940
|
+
const restoreCaret = (nextDisplay, logicalCaret) => {
|
|
3941
|
+
const input = innerRef.current;
|
|
3942
|
+
if (logicalCaret === void 0 || !input || document.activeElement !== input) return;
|
|
3943
|
+
const nextCaret = getDisplayCaret(nextDisplay, logicalCaret);
|
|
3944
|
+
requestAnimationFrame(() => {
|
|
3945
|
+
if (document.activeElement !== input) return;
|
|
3946
|
+
input.setSelectionRange(nextCaret, nextCaret);
|
|
3947
|
+
});
|
|
3948
|
+
};
|
|
3949
|
+
const setDisplayWithCaret = (nextDisplay, logicalCaret) => {
|
|
3950
|
+
setDisplay(nextDisplay);
|
|
3951
|
+
restoreCaret(nextDisplay, logicalCaret);
|
|
3952
|
+
};
|
|
3953
|
+
const resetRejectedInput = (target, logicalCaret) => {
|
|
3954
|
+
target.value = display;
|
|
3955
|
+
restoreCaret(display, Math.min(logicalCaret, display.replace(/,/g, "").length));
|
|
3956
|
+
};
|
|
3957
|
+
const emit = (n, logicalCaret) => {
|
|
3958
|
+
const next = applyDecimalLimit(n, decimalLimit);
|
|
3959
|
+
const nextDisplay = formatWithCommas(next);
|
|
3960
|
+
setDisplayWithCaret(nextDisplay, logicalCaret);
|
|
3961
|
+
onValueChange?.(next);
|
|
3899
3962
|
};
|
|
3900
3963
|
const incDisabled = disabled || readOnly || numValue !== null && numValue >= max;
|
|
3901
3964
|
const decDisabled = disabled || readOnly || numValue !== null && numValue <= min;
|
|
3902
3965
|
const increment = () => {
|
|
3903
3966
|
if (incDisabled) return;
|
|
3904
3967
|
const cur = numValue ?? (min === Number.NEGATIVE_INFINITY ? 0 : min);
|
|
3905
|
-
const next = Math.min(cur + step, max);
|
|
3968
|
+
const next = applyDecimalLimit(Math.min(cur + step, max), decimalLimit);
|
|
3906
3969
|
if (next !== cur) emit(next);
|
|
3907
3970
|
};
|
|
3908
3971
|
const decrement = () => {
|
|
3909
3972
|
if (decDisabled) return;
|
|
3910
3973
|
const cur = numValue ?? (min === Number.NEGATIVE_INFINITY ? 0 : min);
|
|
3911
|
-
const next = Math.max(cur - step, min);
|
|
3974
|
+
const next = applyDecimalLimit(Math.max(cur - step, min), decimalLimit);
|
|
3912
3975
|
if (next !== cur) emit(next);
|
|
3913
3976
|
};
|
|
3914
|
-
const handleInput = (
|
|
3977
|
+
const handleInput = (event) => {
|
|
3978
|
+
const target = event.currentTarget;
|
|
3979
|
+
const raw = target.value;
|
|
3980
|
+
const logicalCaret = getLogicalCaret(raw, target.selectionStart);
|
|
3915
3981
|
if (raw === "") {
|
|
3916
|
-
|
|
3982
|
+
setDisplayWithCaret("", 0);
|
|
3917
3983
|
onValueChange?.(null);
|
|
3918
3984
|
return;
|
|
3919
3985
|
}
|
|
3920
3986
|
const cleaned = raw.replace(/,/g, "");
|
|
3921
3987
|
const decimals = (cleaned.match(/\./g) || []).length;
|
|
3922
|
-
if (decimals > 1)
|
|
3988
|
+
if (decimals > 1) {
|
|
3989
|
+
resetRejectedInput(target, logicalCaret);
|
|
3990
|
+
return;
|
|
3991
|
+
}
|
|
3923
3992
|
if (cleaned === "-" || cleaned === "." || cleaned === "-.") {
|
|
3924
|
-
|
|
3993
|
+
setDisplayWithCaret(cleaned, logicalCaret);
|
|
3994
|
+
return;
|
|
3995
|
+
}
|
|
3996
|
+
if (!useDecimal && cleaned.includes(".")) {
|
|
3997
|
+
resetRejectedInput(target, logicalCaret);
|
|
3925
3998
|
return;
|
|
3926
3999
|
}
|
|
3927
|
-
if (
|
|
4000
|
+
if (decimalLimit !== void 0 && cleaned.includes(".")) {
|
|
4001
|
+
const fraction = cleaned.split(".")[1] ?? "";
|
|
4002
|
+
if (fraction.length > decimalLimit) {
|
|
4003
|
+
resetRejectedInput(target, logicalCaret);
|
|
4004
|
+
return;
|
|
4005
|
+
}
|
|
4006
|
+
}
|
|
3928
4007
|
if (cleaned.endsWith(".") && decimals === 1) {
|
|
3929
4008
|
const parsed2 = toNumber(cleaned.slice(0, -1));
|
|
3930
4009
|
if (parsed2 !== null) {
|
|
3931
|
-
|
|
4010
|
+
setDisplayWithCaret(formatInputWithCommas(cleaned), logicalCaret);
|
|
3932
4011
|
return;
|
|
3933
4012
|
}
|
|
3934
4013
|
}
|
|
3935
4014
|
const parsed = toNumber(cleaned);
|
|
3936
|
-
if (parsed === null)
|
|
3937
|
-
|
|
4015
|
+
if (parsed === null) {
|
|
4016
|
+
resetRejectedInput(target, logicalCaret);
|
|
4017
|
+
return;
|
|
4018
|
+
}
|
|
4019
|
+
setDisplayWithCaret(formatInputWithCommas(cleaned), logicalCaret);
|
|
4020
|
+
onValueChange?.(applyDecimalLimit(parsed, decimalLimit));
|
|
3938
4021
|
};
|
|
3939
4022
|
const stepper = (dir) => {
|
|
3940
4023
|
const off = dir === "inc" ? incDisabled : decDisabled;
|
|
@@ -3947,8 +4030,8 @@ var SNumberInput = react.forwardRef(function SNumberInput2({
|
|
|
3947
4030
|
"aria-label": dir === "inc" ? "\uC99D\uAC00" : "\uAC10\uC18C",
|
|
3948
4031
|
onClick: dir === "inc" ? increment : decrement,
|
|
3949
4032
|
className: cn(
|
|
3950
|
-
"flex flex-shrink-0 items-center justify-center",
|
|
3951
|
-
off ? "cursor-not-allowed" : "cursor-pointer"
|
|
4033
|
+
"flex flex-shrink-0 items-center justify-center border border-solid border-transparent transition-colors",
|
|
4034
|
+
off ? "cursor-not-allowed" : "cursor-pointer hover:border-[var(--color-border-accentLight)]"
|
|
3952
4035
|
),
|
|
3953
4036
|
style: {
|
|
3954
4037
|
width: `var(--cmp-numberInput-stepper-${size}-size)`,
|
|
@@ -3997,24 +4080,26 @@ var SNumberInput = react.forwardRef(function SNumberInput2({
|
|
|
3997
4080
|
style: {
|
|
3998
4081
|
// 원본 sd-number-input: content gap = padding-x 토큰 (gap 토큰 아님)
|
|
3999
4082
|
gap: `var(--cmp-numberInput-${size}-paddingX)`,
|
|
4000
|
-
padding: `0 ${useButton ? padX : `calc(${padX} * 2)`}
|
|
4083
|
+
padding: `0 ${useButton ? padX : `calc(${padX} * 2)`}`,
|
|
4084
|
+
fontSize: p.fontSize,
|
|
4085
|
+
lineHeight: `${p.lineHeight}px`
|
|
4001
4086
|
},
|
|
4002
4087
|
children: [
|
|
4003
4088
|
useButton && stepper("dec"),
|
|
4004
|
-
inputPrefix !== "" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", style: {
|
|
4089
|
+
inputPrefix !== "" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", style: { color: affixColor }, children: inputPrefix }),
|
|
4005
4090
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4006
4091
|
"input",
|
|
4007
4092
|
{
|
|
4008
4093
|
ref: setRefs,
|
|
4009
4094
|
name,
|
|
4010
4095
|
type: "text",
|
|
4011
|
-
inputMode: "numeric",
|
|
4096
|
+
inputMode: useDecimal ? "decimal" : "numeric",
|
|
4012
4097
|
value: display,
|
|
4013
4098
|
placeholder,
|
|
4014
4099
|
disabled,
|
|
4015
4100
|
readOnly,
|
|
4016
4101
|
autoFocus,
|
|
4017
|
-
onChange:
|
|
4102
|
+
onChange: handleInput,
|
|
4018
4103
|
onKeyDown: (e) => {
|
|
4019
4104
|
if (e.key === "ArrowUp") {
|
|
4020
4105
|
e.preventDefault();
|
|
@@ -4026,26 +4111,29 @@ var SNumberInput = react.forwardRef(function SNumberInput2({
|
|
|
4026
4111
|
},
|
|
4027
4112
|
onFocus: (e) => onFocus?.(e),
|
|
4028
4113
|
onBlur: (e) => {
|
|
4029
|
-
const
|
|
4114
|
+
const cleaned = display.replace(/,/g, "");
|
|
4115
|
+
const n = toNumber(cleaned);
|
|
4030
4116
|
const clamped = n === null ? null : Math.min(Math.max(n, min), max);
|
|
4031
4117
|
if (clamped !== n) emit(clamped);
|
|
4032
|
-
else setDisplay(
|
|
4118
|
+
else setDisplay(n === null ? "" : formatInputWithCommas(cleaned));
|
|
4033
4119
|
if (rules && rules.length > 0) setRuleError(runRules(clamped, rules));
|
|
4034
4120
|
onBlur?.(e);
|
|
4035
4121
|
},
|
|
4036
4122
|
className: cn(
|
|
4037
|
-
|
|
4123
|
+
// h-full 대신 라인박스 높이 그대로 두어 prefix/suffix 와 동일하게 flex 로 수직 센터링
|
|
4124
|
+
// (h-full 이면 input 내부 텍스트 센터링을 브라우저가 수행해 1px 어긋날 수 있음)
|
|
4125
|
+
"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",
|
|
4038
4126
|
inputClass
|
|
4039
4127
|
),
|
|
4040
4128
|
style: {
|
|
4041
|
-
fontSize
|
|
4129
|
+
// fontSize/lineHeight 는 컨테이너에서 상속
|
|
4042
4130
|
textAlign: useButton ? "center" : "right",
|
|
4043
4131
|
color: disabled ? "var(--cmp-numberInput-text-disabled)" : "var(--cmp-numberInput-text-default)",
|
|
4044
4132
|
...inputStyle
|
|
4045
4133
|
}
|
|
4046
4134
|
}
|
|
4047
4135
|
),
|
|
4048
|
-
inputSuffix !== "" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", style: {
|
|
4136
|
+
inputSuffix !== "" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", style: { color: affixColor }, children: inputSuffix }),
|
|
4049
4137
|
useButton && stepper("inc")
|
|
4050
4138
|
]
|
|
4051
4139
|
}
|
|
@@ -4059,15 +4147,28 @@ function flattenOptions(options, depth = 1) {
|
|
|
4059
4147
|
const out = [];
|
|
4060
4148
|
for (const o of options) {
|
|
4061
4149
|
const hasChildren = Array.isArray(o.children) && o.children.length > 0;
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4150
|
+
if (hasChildren) {
|
|
4151
|
+
const childFlat = flattenOptions(o.children, depth + 1);
|
|
4152
|
+
const allChildrenDisabled = childFlat.every((c) => c.disabled);
|
|
4153
|
+
out.push({
|
|
4154
|
+
value: String(o.value),
|
|
4155
|
+
label: o.label,
|
|
4156
|
+
disabled: !!o.disabled || allChildrenDisabled,
|
|
4157
|
+
depth,
|
|
4158
|
+
isGroup: true,
|
|
4159
|
+
raw: o.value
|
|
4160
|
+
});
|
|
4161
|
+
out.push(...childFlat);
|
|
4162
|
+
} else {
|
|
4163
|
+
out.push({
|
|
4164
|
+
value: String(o.value),
|
|
4165
|
+
label: o.label,
|
|
4166
|
+
disabled: !!o.disabled,
|
|
4167
|
+
depth,
|
|
4168
|
+
isGroup: false,
|
|
4169
|
+
raw: o.value
|
|
4170
|
+
});
|
|
4171
|
+
}
|
|
4071
4172
|
}
|
|
4072
4173
|
return out;
|
|
4073
4174
|
}
|
|
@@ -4191,6 +4292,9 @@ var SSelect = react.forwardRef(function SSelect2({
|
|
|
4191
4292
|
);
|
|
4192
4293
|
const flat = react.useMemo(() => flattenOptions(options), [options]);
|
|
4193
4294
|
const selectable = react.useMemo(() => selectableOptions(flat), [flat]);
|
|
4295
|
+
const hasLeaf = react.useMemo(() => flat.some((o) => !o.isGroup), [flat]);
|
|
4296
|
+
const allOptionsDisabled = hasLeaf && selectable.length === 0;
|
|
4297
|
+
const effectiveDisabled = disabled || allOptionsDisabled;
|
|
4194
4298
|
const showSearch = useSearch && selectable.length >= SEARCH_THRESHOLD;
|
|
4195
4299
|
const labelByValue = react.useMemo(() => new Map(flat.map((o) => [o.value, o.label])), [flat]);
|
|
4196
4300
|
const rawByValue = react.useMemo(() => new Map(flat.map((o) => [o.value, o.raw])), [flat]);
|
|
@@ -4257,10 +4361,10 @@ var SSelect = react.forwardRef(function SSelect2({
|
|
|
4257
4361
|
Ariakit__namespace.Select,
|
|
4258
4362
|
{
|
|
4259
4363
|
ref: triggerRef,
|
|
4260
|
-
disabled,
|
|
4364
|
+
disabled: effectiveDisabled,
|
|
4261
4365
|
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",
|
|
4262
4366
|
style: {
|
|
4263
|
-
color:
|
|
4367
|
+
color: effectiveDisabled ? "var(--cmp-select-text-disabled)" : isPlaceholder ? "var(--cmp-select-icon-default)" : "var(--cmp-select-text-default)"
|
|
4264
4368
|
},
|
|
4265
4369
|
children: [
|
|
4266
4370
|
isHtmlLabel(triggerText) ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -4275,7 +4379,7 @@ var SSelect = react.forwardRef(function SSelect2({
|
|
|
4275
4379
|
{
|
|
4276
4380
|
name: "chevronDown",
|
|
4277
4381
|
size: 12,
|
|
4278
|
-
color:
|
|
4382
|
+
color: effectiveDisabled ? "var(--cmp-select-icon-disabled)" : "var(--cmp-select-icon-default)",
|
|
4279
4383
|
className: cn("shrink-0 transition-transform duration-200", open && "rotate-180")
|
|
4280
4384
|
}
|
|
4281
4385
|
)
|
|
@@ -4289,7 +4393,7 @@ var SSelect = react.forwardRef(function SSelect2({
|
|
|
4289
4393
|
portalElement: portalContainer,
|
|
4290
4394
|
gutter: 4,
|
|
4291
4395
|
sameWidth: !dropdownWidth,
|
|
4292
|
-
className: "z-50 overflow-auto rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)]
|
|
4396
|
+
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",
|
|
4293
4397
|
style: {
|
|
4294
4398
|
maxHeight: dropdownHeight,
|
|
4295
4399
|
...dropdownWidth ? { width: dropdownWidth } : {},
|
|
@@ -4330,7 +4434,7 @@ var SSelect = react.forwardRef(function SSelect2({
|
|
|
4330
4434
|
),
|
|
4331
4435
|
hasItems ? /* @__PURE__ */ jsxRuntime.jsx(ItemList, { items: filtered, multi, selected, useSearch: showSearch }) : (
|
|
4332
4436
|
// 원본 sd-select-listbox__empty (표시할 항목이 없을 때)
|
|
4333
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-[12px] py-[12px] text-
|
|
4437
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-[12px] py-[12px] text-left text-[12px] leading-[20px] text-[color:var(--cmp-listItem-content-disabled)]", children: "\uD45C\uC2DC\uD560 \uD56D\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4." })
|
|
4334
4438
|
)
|
|
4335
4439
|
]
|
|
4336
4440
|
}
|
|
@@ -4353,7 +4457,7 @@ var SSelect = react.forwardRef(function SSelect2({
|
|
|
4353
4457
|
error: error || ruleError !== "",
|
|
4354
4458
|
status: rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0,
|
|
4355
4459
|
errorMessage: ruleError !== "" ? ruleError : errorMessage,
|
|
4356
|
-
disabled,
|
|
4460
|
+
disabled: effectiveDisabled,
|
|
4357
4461
|
width,
|
|
4358
4462
|
className,
|
|
4359
4463
|
style,
|
|
@@ -4388,7 +4492,11 @@ function ItemList({
|
|
|
4388
4492
|
{
|
|
4389
4493
|
className: cn(
|
|
4390
4494
|
"select-none py-[4px] pr-[12px] text-[12px] leading-[20px] text-[color:var(--cmp-listItem-content-default)]",
|
|
4391
|
-
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"
|
|
4495
|
+
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",
|
|
4496
|
+
// 하위가 전부 비활성이면(select.config 에서 bubble-up) 어미 그룹도 비활성 처리:
|
|
4497
|
+
// 텍스트는 회색(#888), depth1 그룹은 파란 배경 대신 회색(#EEE)으로 (depth2 는 #F6F6F6 유지)
|
|
4498
|
+
o.disabled && "cursor-not-allowed text-[color:var(--cmp-listItem-content-disabled)]",
|
|
4499
|
+
o.disabled && isDepth1 && "bg-[var(--cmp-listItem-depth1-bg-disabled)]"
|
|
4392
4500
|
),
|
|
4393
4501
|
style: { paddingLeft: padLeft },
|
|
4394
4502
|
children: o.label
|
|
@@ -4402,10 +4510,14 @@ function ItemList({
|
|
|
4402
4510
|
{
|
|
4403
4511
|
value: o.value,
|
|
4404
4512
|
disabled: o.disabled,
|
|
4513
|
+
accessibleWhenDisabled: true,
|
|
4405
4514
|
className: cn(
|
|
4406
4515
|
itemBase,
|
|
4407
4516
|
isSelected && !multi && "font-bold text-[color:var(--cmp-listItem-content-selected)]",
|
|
4408
|
-
|
|
4517
|
+
// Ariakit은 disabled 항목도 hover 시 active(data-active-item) 처리하므로,
|
|
4518
|
+
// 비활성 항목에는 hover 하이라이트를 적용하지 않아 회색 비활성 스타일을 유지한다.
|
|
4519
|
+
// (원본 Stencil의 `--focused...:not(--disabled)` 규칙과 동일한 의도)
|
|
4520
|
+
!o.disabled && activeClass
|
|
4409
4521
|
),
|
|
4410
4522
|
style: { paddingTop: 4, paddingBottom: 4, paddingRight: 12, paddingLeft: padLeft },
|
|
4411
4523
|
render: useSearch ? /* @__PURE__ */ jsxRuntime.jsx(Ariakit__namespace.ComboboxItem, {}) : void 0,
|
|
@@ -4415,15 +4527,21 @@ function ItemList({
|
|
|
4415
4527
|
"span",
|
|
4416
4528
|
{
|
|
4417
4529
|
className: cn(
|
|
4418
|
-
"flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center rounded-[2px] border border-solid
|
|
4419
|
-
|
|
4530
|
+
"flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center rounded-[2px] border border-solid",
|
|
4531
|
+
o.disabled ? (
|
|
4532
|
+
// 비활성: 회색 채움(#E1E1E1) + 회색 테두리(#CCCCCC)
|
|
4533
|
+
"cursor-not-allowed border-[color:var(--cmp-checkbox-border-disabled)] bg-[var(--cmp-checkbox-bg-disabled)]"
|
|
4534
|
+
) : cn(
|
|
4535
|
+
"group-data-[active-item]:border-[color:var(--cmp-checkbox-checked-border-inverse)]",
|
|
4536
|
+
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"
|
|
4537
|
+
)
|
|
4420
4538
|
),
|
|
4421
4539
|
children: isSelected && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4422
4540
|
SIcon,
|
|
4423
4541
|
{
|
|
4424
4542
|
name: "checkboxCheck",
|
|
4425
4543
|
size: 12,
|
|
4426
|
-
color: "var(--cmp-checkbox-checked-icon-default)"
|
|
4544
|
+
color: o.disabled ? "var(--cmp-checkbox-checked-icon-disabled)" : "var(--cmp-checkbox-checked-icon-default)"
|
|
4427
4545
|
}
|
|
4428
4546
|
)
|
|
4429
4547
|
}
|
|
@@ -4547,7 +4665,7 @@ function SRadioGroup({
|
|
|
4547
4665
|
role: "radiogroup",
|
|
4548
4666
|
className: cn(
|
|
4549
4667
|
"inline-flex",
|
|
4550
|
-
direction === "vertical" ? "flex-col gap-[
|
|
4668
|
+
direction === "vertical" ? "flex-col gap-[var(--cmp-radio-group-gap-vertical)]" : "flex-row gap-[var(--cmp-radio-group-gap-horizontal)]",
|
|
4551
4669
|
className
|
|
4552
4670
|
),
|
|
4553
4671
|
style,
|
|
@@ -4829,7 +4947,7 @@ function SCalendar({
|
|
|
4829
4947
|
"span",
|
|
4830
4948
|
{
|
|
4831
4949
|
className: cn(
|
|
4832
|
-
"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]",
|
|
4950
|
+
"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)]",
|
|
4833
4951
|
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)]",
|
|
4834
4952
|
isToday && !disabled && "font-bold"
|
|
4835
4953
|
),
|
|
@@ -4954,8 +5072,8 @@ function SDatePicker({
|
|
|
4954
5072
|
disabled,
|
|
4955
5073
|
className,
|
|
4956
5074
|
style,
|
|
4957
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4958
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5075
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(RPopover2__namespace.Root, { open, onOpenChange: (o) => !disabled && setOpen(o), children: [
|
|
5076
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4959
5077
|
"button",
|
|
4960
5078
|
{
|
|
4961
5079
|
type: "button",
|
|
@@ -4991,8 +5109,8 @@ function SDatePicker({
|
|
|
4991
5109
|
]
|
|
4992
5110
|
}
|
|
4993
5111
|
) }),
|
|
4994
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4995
|
-
|
|
5112
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5113
|
+
RPopover2__namespace.Content,
|
|
4996
5114
|
{
|
|
4997
5115
|
side: "bottom",
|
|
4998
5116
|
align: "start",
|
|
@@ -5019,6 +5137,7 @@ function RangeCalendar({
|
|
|
5019
5137
|
selectable,
|
|
5020
5138
|
maxRange,
|
|
5021
5139
|
onSelect,
|
|
5140
|
+
onPendingStartChange,
|
|
5022
5141
|
onViewChange
|
|
5023
5142
|
}) {
|
|
5024
5143
|
const today = todayStr();
|
|
@@ -5081,9 +5200,11 @@ function RangeCalendar({
|
|
|
5081
5200
|
setStart(d);
|
|
5082
5201
|
setEnd(null);
|
|
5083
5202
|
setHover(null);
|
|
5203
|
+
onPendingStartChange?.(d);
|
|
5084
5204
|
return;
|
|
5085
5205
|
}
|
|
5086
5206
|
setEnd(d);
|
|
5207
|
+
onPendingStartChange?.(null);
|
|
5087
5208
|
onSelect([start, d]);
|
|
5088
5209
|
};
|
|
5089
5210
|
const GRID_COLS = "grid grid-cols-[repeat(7,var(--cmp-datepicker-calendar-day-width))]";
|
|
@@ -5218,8 +5339,11 @@ function SDateRangePicker({
|
|
|
5218
5339
|
const portalContainer = usePortalContainer();
|
|
5219
5340
|
const [open, setOpen] = react.useState(false);
|
|
5220
5341
|
const [ruleError, setRuleError] = react.useState("");
|
|
5342
|
+
const [pendingStart, setPendingStart] = react.useState(null);
|
|
5221
5343
|
const hasValue = value != null && value[0] !== "" && value[1] !== "";
|
|
5222
|
-
const
|
|
5344
|
+
const hasDisplay = pendingStart != null || hasValue;
|
|
5345
|
+
const startText = pendingStart ?? (hasValue ? value[0] : "");
|
|
5346
|
+
const endText = pendingStart ? "" : hasValue ? value[1] : "";
|
|
5223
5347
|
useFormField({
|
|
5224
5348
|
name,
|
|
5225
5349
|
validate: () => {
|
|
@@ -5233,6 +5357,7 @@ function SDateRangePicker({
|
|
|
5233
5357
|
const resolvedStatus = status ?? (rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0);
|
|
5234
5358
|
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 };
|
|
5235
5359
|
const select = (r) => {
|
|
5360
|
+
setPendingStart(null);
|
|
5236
5361
|
onValueChange?.(r);
|
|
5237
5362
|
if (rules && rules.length > 0) setRuleError(runRules(r, rules));
|
|
5238
5363
|
setOpen(false);
|
|
@@ -5257,61 +5382,80 @@ function SDateRangePicker({
|
|
|
5257
5382
|
disabled,
|
|
5258
5383
|
className,
|
|
5259
5384
|
style,
|
|
5260
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
|
|
5265
|
-
|
|
5266
|
-
|
|
5267
|
-
|
|
5268
|
-
|
|
5269
|
-
|
|
5270
|
-
|
|
5271
|
-
|
|
5272
|
-
{
|
|
5273
|
-
name: "date",
|
|
5274
|
-
size: dims.icon,
|
|
5275
|
-
color: disabled ? "var(--cmp-datepicker-icon-disabled)" : "var(--cmp-datepicker-icon-default)",
|
|
5276
|
-
className: "flex-shrink-0"
|
|
5277
|
-
}
|
|
5278
|
-
),
|
|
5279
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5280
|
-
"span",
|
|
5281
|
-
{
|
|
5282
|
-
className: "flex-1 truncate text-center",
|
|
5283
|
-
style: {
|
|
5284
|
-
minWidth: dims.minW,
|
|
5285
|
-
fontSize: dims.fontSize,
|
|
5286
|
-
lineHeight: `${dims.lineHeight}px`,
|
|
5287
|
-
color: disabled ? "var(--cmp-datepicker-text-disabled)" : hasValue ? "var(--cmp-datepicker-text-default)" : "var(--cmp-field-hint-color)"
|
|
5288
|
-
},
|
|
5289
|
-
children: display
|
|
5290
|
-
}
|
|
5291
|
-
)
|
|
5292
|
-
]
|
|
5293
|
-
}
|
|
5294
|
-
) }),
|
|
5295
|
-
/* @__PURE__ */ jsxRuntime.jsx(RPopover__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5296
|
-
RPopover__namespace.Content,
|
|
5297
|
-
{
|
|
5298
|
-
side: "bottom",
|
|
5299
|
-
align: "start",
|
|
5300
|
-
sideOffset: 4,
|
|
5301
|
-
className: cn("z-50", FLOATING_SLIDE_ANIM),
|
|
5302
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5303
|
-
RangeCalendar,
|
|
5385
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5386
|
+
RPopover2__namespace.Root,
|
|
5387
|
+
{
|
|
5388
|
+
open,
|
|
5389
|
+
onOpenChange: (o) => {
|
|
5390
|
+
if (disabled) return;
|
|
5391
|
+
setOpen(o);
|
|
5392
|
+
if (!o) setPendingStart(null);
|
|
5393
|
+
},
|
|
5394
|
+
children: [
|
|
5395
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5396
|
+
"button",
|
|
5304
5397
|
{
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
|
|
5309
|
-
|
|
5398
|
+
type: "button",
|
|
5399
|
+
name,
|
|
5400
|
+
disabled,
|
|
5401
|
+
className: "flex h-full w-full items-center overflow-hidden bg-transparent outline-none disabled:cursor-not-allowed",
|
|
5402
|
+
style: { padding: `0 ${dims.padX}px`, gap: dims.gap, borderRadius: dims.radius },
|
|
5403
|
+
children: [
|
|
5404
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5405
|
+
SIcon,
|
|
5406
|
+
{
|
|
5407
|
+
name: "date",
|
|
5408
|
+
size: dims.icon,
|
|
5409
|
+
color: disabled ? "var(--cmp-datepicker-icon-disabled)" : "var(--cmp-datepicker-icon-default)",
|
|
5410
|
+
className: "flex-shrink-0"
|
|
5411
|
+
}
|
|
5412
|
+
),
|
|
5413
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5414
|
+
"span",
|
|
5415
|
+
{
|
|
5416
|
+
className: cn(
|
|
5417
|
+
"flex-1 items-center",
|
|
5418
|
+
hasDisplay ? "flex" : "block truncate text-center"
|
|
5419
|
+
),
|
|
5420
|
+
style: {
|
|
5421
|
+
minWidth: dims.minW,
|
|
5422
|
+
fontSize: dims.fontSize,
|
|
5423
|
+
lineHeight: `${dims.lineHeight}px`,
|
|
5424
|
+
color: disabled ? "var(--cmp-datepicker-text-disabled)" : hasDisplay ? "var(--cmp-datepicker-text-default)" : "var(--cmp-field-hint-color)"
|
|
5425
|
+
},
|
|
5426
|
+
children: hasDisplay ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5427
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate text-right", children: startText }),
|
|
5428
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-[4px]", children: "~" }),
|
|
5429
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate text-left", children: endText })
|
|
5430
|
+
] }) : placeholder
|
|
5431
|
+
}
|
|
5432
|
+
)
|
|
5433
|
+
]
|
|
5310
5434
|
}
|
|
5311
|
-
)
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
|
|
5435
|
+
) }),
|
|
5436
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5437
|
+
RPopover2__namespace.Content,
|
|
5438
|
+
{
|
|
5439
|
+
side: "bottom",
|
|
5440
|
+
align: "start",
|
|
5441
|
+
sideOffset: 4,
|
|
5442
|
+
className: cn("z-50", FLOATING_SLIDE_ANIM),
|
|
5443
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5444
|
+
RangeCalendar,
|
|
5445
|
+
{
|
|
5446
|
+
value: value ?? null,
|
|
5447
|
+
selectable,
|
|
5448
|
+
maxRange,
|
|
5449
|
+
onSelect: select,
|
|
5450
|
+
onPendingStartChange: setPendingStart,
|
|
5451
|
+
onViewChange
|
|
5452
|
+
}
|
|
5453
|
+
)
|
|
5454
|
+
}
|
|
5455
|
+
) })
|
|
5456
|
+
]
|
|
5457
|
+
}
|
|
5458
|
+
)
|
|
5315
5459
|
}
|
|
5316
5460
|
);
|
|
5317
5461
|
}
|
|
@@ -5320,7 +5464,7 @@ var SChip = react.forwardRef(function SChip2({
|
|
|
5320
5464
|
value = "",
|
|
5321
5465
|
error: errorProp = false,
|
|
5322
5466
|
disabled = false,
|
|
5323
|
-
editable =
|
|
5467
|
+
editable = false,
|
|
5324
5468
|
showRemove = true,
|
|
5325
5469
|
placeholder = "",
|
|
5326
5470
|
rules,
|
|
@@ -5473,6 +5617,7 @@ function SFilePicker({
|
|
|
5473
5617
|
hovered = false,
|
|
5474
5618
|
inline = false,
|
|
5475
5619
|
multiple = false,
|
|
5620
|
+
useMultipleListBox = false,
|
|
5476
5621
|
accept,
|
|
5477
5622
|
maxFileSize,
|
|
5478
5623
|
maxTotalSize,
|
|
@@ -5498,10 +5643,13 @@ function SFilePicker({
|
|
|
5498
5643
|
const autoId = react.useId();
|
|
5499
5644
|
const resolvedName = name ?? autoId;
|
|
5500
5645
|
const inputRef = react.useRef(null);
|
|
5646
|
+
const contentBoxRef = react.useRef(null);
|
|
5501
5647
|
const [ruleError, setRuleError] = react.useState("");
|
|
5648
|
+
const [listOpen, setListOpen] = react.useState(false);
|
|
5649
|
+
const portalContainer = usePortalContainer();
|
|
5502
5650
|
const files = multiple ? Array.isArray(value) ? value : [] : value && !Array.isArray(value) ? value : null;
|
|
5503
|
-
const
|
|
5504
|
-
const displayText =
|
|
5651
|
+
const hasFiles = multiple ? files.length > 0 : !!files;
|
|
5652
|
+
const displayText = !hasFiles ? placeholder : multiple ? files.map((f) => f.name).join(", ") : files.name;
|
|
5505
5653
|
useFormField({
|
|
5506
5654
|
name,
|
|
5507
5655
|
validate: () => {
|
|
@@ -5552,10 +5700,12 @@ function SFilePicker({
|
|
|
5552
5700
|
e.stopPropagation();
|
|
5553
5701
|
if (disabled) return;
|
|
5554
5702
|
onValueChange?.(multiple ? [] : null);
|
|
5703
|
+
setListOpen(false);
|
|
5555
5704
|
};
|
|
5556
5705
|
const removeChip = (i) => {
|
|
5557
5706
|
const next = files.filter((_, idx) => idx !== i);
|
|
5558
5707
|
onValueChange?.(next);
|
|
5708
|
+
if (next.length === 0) setListOpen(false);
|
|
5559
5709
|
};
|
|
5560
5710
|
const open = () => {
|
|
5561
5711
|
if (!disabled) inputRef.current?.click();
|
|
@@ -5565,78 +5715,100 @@ function SFilePicker({
|
|
|
5565
5715
|
const padX = size === "md" ? "var(--cmp-filepicker-md-paddingX)" : "var(--cmp-filepicker-sm-paddingX)";
|
|
5566
5716
|
const iconSize = size === "md" ? 20 : 16;
|
|
5567
5717
|
const gapCls = size === "md" ? "gap-[var(--cmp-filepicker-md-gap)]" : "gap-[var(--cmp-filepicker-sm-gap)]";
|
|
5568
|
-
const
|
|
5718
|
+
const inlinePlaceholder = inline && !disabled && !hasFiles;
|
|
5719
|
+
const showListbox = multiple && useMultipleListBox;
|
|
5720
|
+
const filesArr = multiple ? files : [];
|
|
5721
|
+
const contentInner = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5722
|
+
"div",
|
|
5723
|
+
{
|
|
5724
|
+
ref: contentBoxRef,
|
|
5725
|
+
className: cn("group/filepicker flex h-full w-full items-center", gapCls),
|
|
5726
|
+
style: { padding: inline ? 0 : `0 ${padX}` },
|
|
5727
|
+
children: [
|
|
5728
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5729
|
+
"input",
|
|
5730
|
+
{
|
|
5731
|
+
ref: inputRef,
|
|
5732
|
+
type: "file",
|
|
5733
|
+
className: "hidden",
|
|
5734
|
+
disabled,
|
|
5735
|
+
multiple,
|
|
5736
|
+
accept,
|
|
5737
|
+
name: resolvedName,
|
|
5738
|
+
onChange,
|
|
5739
|
+
"aria-label": placeholder
|
|
5740
|
+
}
|
|
5741
|
+
),
|
|
5742
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
5743
|
+
"button",
|
|
5744
|
+
{
|
|
5745
|
+
type: "button",
|
|
5746
|
+
disabled,
|
|
5747
|
+
onClick: open,
|
|
5748
|
+
"aria-label": placeholder,
|
|
5749
|
+
className: cn(
|
|
5750
|
+
"flex min-w-0 flex-1 items-center bg-transparent text-left",
|
|
5751
|
+
gapCls,
|
|
5752
|
+
disabled ? "cursor-not-allowed" : "cursor-pointer"
|
|
5753
|
+
),
|
|
5754
|
+
children: [
|
|
5755
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5756
|
+
SIcon,
|
|
5757
|
+
{
|
|
5758
|
+
name: "attachFile",
|
|
5759
|
+
size: iconSize,
|
|
5760
|
+
color: disabled ? "var(--cmp-filepicker-icon-disabled)" : "var(--color-grey-65)"
|
|
5761
|
+
}
|
|
5762
|
+
),
|
|
5763
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5764
|
+
"span",
|
|
5765
|
+
{
|
|
5766
|
+
className: cn(
|
|
5767
|
+
"min-w-0 flex-1 truncate text-[12px]",
|
|
5768
|
+
inlinePlaceholder && "text-[color:var(--cmp-filepicker-text-placeholder)] transition-colors group-hover/filepicker:text-[color:var(--cmp-filepicker-text-default)]"
|
|
5769
|
+
),
|
|
5770
|
+
style: inlinePlaceholder ? void 0 : {
|
|
5771
|
+
color: disabled ? "var(--cmp-filepicker-text-disabled)" : hasFiles ? "var(--cmp-filepicker-text-default)" : "var(--cmp-filepicker-text-placeholder)"
|
|
5772
|
+
},
|
|
5773
|
+
children: displayText
|
|
5774
|
+
}
|
|
5775
|
+
)
|
|
5776
|
+
]
|
|
5777
|
+
}
|
|
5778
|
+
),
|
|
5779
|
+
showListbox && hasFiles && !disabled && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5780
|
+
Ariakit__namespace.PopoverDisclosure,
|
|
5781
|
+
{
|
|
5782
|
+
render: /* @__PURE__ */ jsxRuntime.jsx(SGhostButton, { icon: "caretDown", size: "xxs", ariaLabel: "toggle file list" }),
|
|
5783
|
+
className: cn("shrink-0 transition-transform duration-150", listOpen && "rotate-180")
|
|
5784
|
+
}
|
|
5785
|
+
),
|
|
5786
|
+
!disabled && hasFiles && /* @__PURE__ */ jsxRuntime.jsx(SGhostButton, { icon: "close", size: "xxs", ariaLabel: "clear", onClick: clear })
|
|
5787
|
+
]
|
|
5788
|
+
}
|
|
5789
|
+
);
|
|
5790
|
+
const content = showListbox ? /* @__PURE__ */ jsxRuntime.jsxs(Ariakit__namespace.PopoverProvider, { open: listOpen, setOpen: setListOpen, placement: "bottom-start", children: [
|
|
5791
|
+
contentInner,
|
|
5569
5792
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5570
|
-
|
|
5571
|
-
{
|
|
5572
|
-
ref: inputRef,
|
|
5573
|
-
type: "file",
|
|
5574
|
-
className: "hidden",
|
|
5575
|
-
disabled,
|
|
5576
|
-
multiple,
|
|
5577
|
-
accept,
|
|
5578
|
-
name: resolvedName,
|
|
5579
|
-
onChange,
|
|
5580
|
-
"aria-label": placeholder
|
|
5581
|
-
}
|
|
5582
|
-
),
|
|
5583
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
5584
|
-
"button",
|
|
5793
|
+
Ariakit__namespace.Popover,
|
|
5585
5794
|
{
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
),
|
|
5595
|
-
children: [
|
|
5596
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5597
|
-
SIcon,
|
|
5598
|
-
{
|
|
5599
|
-
name: "attachFile",
|
|
5600
|
-
size: iconSize,
|
|
5601
|
-
color: disabled ? "var(--cmp-filepicker-icon-disabled)" : "var(--color-grey-65)"
|
|
5602
|
-
}
|
|
5603
|
-
),
|
|
5604
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5605
|
-
"span",
|
|
5606
|
-
{
|
|
5607
|
-
className: "min-w-0 flex-1 truncate text-[12px]",
|
|
5608
|
-
style: {
|
|
5609
|
-
color: disabled ? "var(--cmp-filepicker-text-disabled)" : hasSingle ? "var(--cmp-filepicker-text-default)" : "var(--cmp-filepicker-text-placeholder)"
|
|
5610
|
-
},
|
|
5611
|
-
children: displayText
|
|
5612
|
-
}
|
|
5613
|
-
)
|
|
5614
|
-
]
|
|
5795
|
+
portal: true,
|
|
5796
|
+
portalElement: portalContainer,
|
|
5797
|
+
gutter: 4,
|
|
5798
|
+
unmountOnHide: true,
|
|
5799
|
+
getAnchorRect: () => contentBoxRef.current?.getBoundingClientRect() ?? null,
|
|
5800
|
+
style: { minWidth: contentBoxRef.current?.offsetWidth },
|
|
5801
|
+
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)]",
|
|
5802
|
+
children: filesArr.map((f, i) => /* @__PURE__ */ jsxRuntime.jsx(SChip, { value: f.name, editable: false, onRemove: () => removeChip(i) }, i))
|
|
5615
5803
|
}
|
|
5616
|
-
)
|
|
5617
|
-
|
|
5618
|
-
] });
|
|
5619
|
-
const chips = multiple && files.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-[8px] flex flex-wrap gap-[8px]", children: files.map((f, i) => /* @__PURE__ */ jsxRuntime.jsx(SChip, { value: f.name, editable: false, onRemove: () => removeChip(i) }, i)) });
|
|
5620
|
-
if (inline) {
|
|
5621
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("inline-flex flex-col", className), style, children: [
|
|
5622
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5623
|
-
"div",
|
|
5624
|
-
{
|
|
5625
|
-
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)]",
|
|
5626
|
-
style: {
|
|
5627
|
-
height: "var(--cmp-filepicker-sm-height)",
|
|
5628
|
-
width: typeof width === "number" ? `${width}px` : width
|
|
5629
|
-
},
|
|
5630
|
-
children: content
|
|
5631
|
-
}
|
|
5632
|
-
),
|
|
5633
|
-
chips
|
|
5634
|
-
] });
|
|
5635
|
-
}
|
|
5804
|
+
)
|
|
5805
|
+
] }) : contentInner;
|
|
5806
|
+
const chips = multiple && !useMultipleListBox && filesArr.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-[8px] flex flex-wrap gap-[8px]", children: filesArr.map((f, i) => /* @__PURE__ */ jsxRuntime.jsx(SChip, { value: f.name, editable: false, onRemove: () => removeChip(i) }, i)) });
|
|
5636
5807
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style, children: [
|
|
5637
5808
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5638
5809
|
SField,
|
|
5639
5810
|
{
|
|
5811
|
+
borderless: inline,
|
|
5640
5812
|
label,
|
|
5641
5813
|
labelWidth,
|
|
5642
5814
|
icon,
|
|
@@ -5664,6 +5836,7 @@ function SKeyValueTable({
|
|
|
5664
5836
|
fields = [],
|
|
5665
5837
|
search = false,
|
|
5666
5838
|
radius = "default",
|
|
5839
|
+
dense = false,
|
|
5667
5840
|
onChange,
|
|
5668
5841
|
onSearch,
|
|
5669
5842
|
className,
|
|
@@ -5671,6 +5844,8 @@ function SKeyValueTable({
|
|
|
5671
5844
|
}) {
|
|
5672
5845
|
if (fields.length === 0) return null;
|
|
5673
5846
|
const emit = (name, value) => onChange?.({ name, value });
|
|
5847
|
+
const cellHeight = dense ? "var(--cmp-table-body-dense-height)" : "var(--cmp-table-keyValue-height)";
|
|
5848
|
+
const cellPadY = dense ? "var(--cmp-table-body-paddingY-dense)" : "var(--cmp-table-keyValue-body-paddingY)";
|
|
5674
5849
|
const renderField = (f) => {
|
|
5675
5850
|
if (f.render) return f.render;
|
|
5676
5851
|
const opt = f.options ?? {};
|
|
@@ -5751,10 +5926,15 @@ function SKeyValueTable({
|
|
|
5751
5926
|
rowSpan: f.thRowSpan && f.thRowSpan > 1 ? f.thRowSpan : void 0,
|
|
5752
5927
|
colSpan: f.thColSpan && f.thColSpan > 1 ? f.thColSpan : void 0,
|
|
5753
5928
|
className: cn(
|
|
5754
|
-
"
|
|
5929
|
+
"box-border bg-[var(--cmp-table-header-bg)] px-[var(--cmp-table-header-paddingX)] text-left align-middle",
|
|
5755
5930
|
cellBorder,
|
|
5756
5931
|
f.thClass
|
|
5757
5932
|
),
|
|
5933
|
+
style: {
|
|
5934
|
+
height: cellHeight,
|
|
5935
|
+
paddingTop: cellPadY,
|
|
5936
|
+
paddingBottom: cellPadY
|
|
5937
|
+
},
|
|
5758
5938
|
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full w-full items-center justify-between gap-[var(--cmp-table-header-gap)]", children: [
|
|
5759
5939
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-[8px]", children: [
|
|
5760
5940
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[12px] font-bold leading-[20px] text-[color:var(--sys-color-fg-primary)]", children: f.label }),
|
|
@@ -5780,10 +5960,11 @@ function SKeyValueTable({
|
|
|
5780
5960
|
rowSpan: f.tdRowSpan && f.tdRowSpan > 1 ? f.tdRowSpan : void 0,
|
|
5781
5961
|
colSpan: f.tdColSpan && f.tdColSpan > 1 ? f.tdColSpan : void 0,
|
|
5782
5962
|
className: cn(
|
|
5783
|
-
"
|
|
5963
|
+
"box-border bg-[var(--sys-color-bg-frame)] px-[var(--cmp-table-keyValue-body-paddingX-default)] align-middle",
|
|
5784
5964
|
cellBorder,
|
|
5785
5965
|
f.tdClass
|
|
5786
5966
|
),
|
|
5967
|
+
style: { height: cellHeight, paddingTop: cellPadY, paddingBottom: cellPadY },
|
|
5787
5968
|
children: renderField(f)
|
|
5788
5969
|
},
|
|
5789
5970
|
`td-${r}-${c}`
|