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