sellmate-design-system-react 9.0.0-beta.0 → 9.0.0-beta.3
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/AGENTS.md +20 -2
- package/dist/components/SCircleProgress/README.md +3 -0
- package/dist/components/SCircleProgress/SCircleProgress.d.ts +7 -1
- package/dist/components/SDatePicker/README.md +4 -3
- package/dist/components/SDatePicker/SDatePicker.d.ts +6 -3
- package/dist/components/SDatePicker/index.d.ts +1 -1
- package/dist/components/SIcon/README.md +2 -0
- package/dist/components/SImage/README.md +44 -0
- package/dist/components/SImage/SImage.d.ts +41 -0
- package/dist/components/SImage/index.d.ts +1 -0
- package/dist/components/SToggle/README.md +1 -0
- package/dist/components/SToggle/SToggle.d.ts +4 -1
- package/dist/index.cjs +486 -119
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +485 -120
- package/dist/index.js.map +1 -1
- package/dist/llms-full.txt +70 -6
- package/dist/llms.txt +24 -5
- package/dist/styles.css +94 -11
- package/dist/theme.css +26 -5
- package/eslint/scale.gen.mjs +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -3141,6 +3141,209 @@ var SIcon = /* @__PURE__ */ react.forwardRef(function SIcon2({ name, size = 24,
|
|
|
3141
3141
|
}
|
|
3142
3142
|
);
|
|
3143
3143
|
});
|
|
3144
|
+
var VIEWBOX = 80;
|
|
3145
|
+
var RADIUS = 34;
|
|
3146
|
+
var STROKE = 12;
|
|
3147
|
+
var CIRCUMFERENCE = 2 * Math.PI * RADIUS;
|
|
3148
|
+
var COLOR_MAP = {
|
|
3149
|
+
primary: { arc: "var(--cmp-progress-color-active)", track: "var(--cmp-progress-color-track)" },
|
|
3150
|
+
// inverse: 어두운 배경용 — arc 흰색, track 은 흰색 40%(회색 링)
|
|
3151
|
+
inverse: { arc: "var(--color-white)", track: "rgba(255,255,255,0.4)" },
|
|
3152
|
+
error: { arc: "var(--color-red-75)", track: "var(--cmp-progress-color-track)" },
|
|
3153
|
+
complete: { arc: "#01BB4B", track: "var(--cmp-progress-color-track)" },
|
|
3154
|
+
// neutral: 콘텐츠가 아직 없는 자리를 채우는 용도 — arc 도 회색이라 진행률보다 "대기"로 읽힌다
|
|
3155
|
+
neutral: { arc: "var(--color-grey-35)", track: "var(--cmp-progress-color-track)" }
|
|
3156
|
+
};
|
|
3157
|
+
var DEFAULT_SIZE = 80;
|
|
3158
|
+
var clamp = (v) => Number.isFinite(v) ? Math.max(0, Math.min(100, v)) : 0;
|
|
3159
|
+
var SCircleProgress = /* @__PURE__ */ react.forwardRef(
|
|
3160
|
+
function SCircleProgress2({
|
|
3161
|
+
value = 0,
|
|
3162
|
+
type = "primary",
|
|
3163
|
+
indeterminate = false,
|
|
3164
|
+
size = DEFAULT_SIZE,
|
|
3165
|
+
label,
|
|
3166
|
+
innerValue = false,
|
|
3167
|
+
className,
|
|
3168
|
+
style
|
|
3169
|
+
}, ref) {
|
|
3170
|
+
const v = clamp(value);
|
|
3171
|
+
const dimension = typeof size === "number" ? `${size}px` : size;
|
|
3172
|
+
const colors = COLOR_MAP[type];
|
|
3173
|
+
const c = VIEWBOX / 2;
|
|
3174
|
+
const percentColor = v === 0 ? "var(--sys-color-fg-tertiary, #888888)" : colors.arc;
|
|
3175
|
+
const filled = v / 100 * CIRCUMFERENCE;
|
|
3176
|
+
const showPercent = !indeterminate;
|
|
3177
|
+
const percentNode = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3178
|
+
"span",
|
|
3179
|
+
{
|
|
3180
|
+
className: cn(
|
|
3181
|
+
"text-center text-[16px] font-bold",
|
|
3182
|
+
innerValue ? (
|
|
3183
|
+
// leading-[normal]: 26px leading 은 폰트 content(19px) 위아래로 홀수(7px)만큼 남아
|
|
3184
|
+
// 3px/4px 로 쪼개지고 글자가 링 중심보다 위로 뜬다. (leading-normal 은 1.5 라 동일 문제)
|
|
3185
|
+
"absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 leading-[normal]"
|
|
3186
|
+
) : "leading-[26px]"
|
|
3187
|
+
),
|
|
3188
|
+
style: { color: percentColor },
|
|
3189
|
+
children: [
|
|
3190
|
+
Math.round(v),
|
|
3191
|
+
"%"
|
|
3192
|
+
]
|
|
3193
|
+
}
|
|
3194
|
+
);
|
|
3195
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3196
|
+
"div",
|
|
3197
|
+
{
|
|
3198
|
+
ref,
|
|
3199
|
+
className: cn(
|
|
3200
|
+
"inline-flex flex-col items-center gap-[var(--cmp-progress-circular-gap)]",
|
|
3201
|
+
className
|
|
3202
|
+
),
|
|
3203
|
+
style,
|
|
3204
|
+
children: [
|
|
3205
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(innerValue && "relative"), children: [
|
|
3206
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3207
|
+
"svg",
|
|
3208
|
+
{
|
|
3209
|
+
viewBox: `0 0 ${VIEWBOX} ${VIEWBOX}`,
|
|
3210
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
3211
|
+
className: cn(indeterminate && "origin-center animate-circle-spin"),
|
|
3212
|
+
style: { width: dimension, height: dimension },
|
|
3213
|
+
children: [
|
|
3214
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3215
|
+
"circle",
|
|
3216
|
+
{
|
|
3217
|
+
cx: c,
|
|
3218
|
+
cy: c,
|
|
3219
|
+
r: RADIUS,
|
|
3220
|
+
fill: "none",
|
|
3221
|
+
strokeWidth: STROKE,
|
|
3222
|
+
style: { stroke: colors.track }
|
|
3223
|
+
}
|
|
3224
|
+
),
|
|
3225
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3226
|
+
"circle",
|
|
3227
|
+
{
|
|
3228
|
+
cx: c,
|
|
3229
|
+
cy: c,
|
|
3230
|
+
r: RADIUS,
|
|
3231
|
+
fill: "none",
|
|
3232
|
+
strokeWidth: STROKE,
|
|
3233
|
+
strokeLinecap: "round",
|
|
3234
|
+
className: cn(
|
|
3235
|
+
"origin-center",
|
|
3236
|
+
indeterminate ? "animate-circle-arc" : "-rotate-90 transition-[stroke-dasharray] duration-[400ms] ease-linear"
|
|
3237
|
+
),
|
|
3238
|
+
style: {
|
|
3239
|
+
stroke: colors.arc,
|
|
3240
|
+
...indeterminate ? {} : { strokeDasharray: `${filled} ${CIRCUMFERENCE}`, strokeDashoffset: 0 }
|
|
3241
|
+
}
|
|
3242
|
+
}
|
|
3243
|
+
)
|
|
3244
|
+
]
|
|
3245
|
+
}
|
|
3246
|
+
),
|
|
3247
|
+
showPercent && innerValue && percentNode
|
|
3248
|
+
] }),
|
|
3249
|
+
showPercent && !innerValue && percentNode,
|
|
3250
|
+
label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-center text-[12px] font-normal leading-[20px] text-[color:var(--cmp-progress-color-label)]", children: label })
|
|
3251
|
+
]
|
|
3252
|
+
}
|
|
3253
|
+
);
|
|
3254
|
+
}
|
|
3255
|
+
);
|
|
3256
|
+
var IMAGE_FITS = ["cover", "contain", "fill", "none", "scale-down"];
|
|
3257
|
+
var EMPTY_ICON_SIZE = "60cqh";
|
|
3258
|
+
var SPINNER_SIZE = "45cqh";
|
|
3259
|
+
var SImage = /* @__PURE__ */ react.forwardRef(function SImage2({
|
|
3260
|
+
src,
|
|
3261
|
+
alt = "",
|
|
3262
|
+
ratio = 1,
|
|
3263
|
+
fit = "cover",
|
|
3264
|
+
position = "50% 50%",
|
|
3265
|
+
loading: loading2 = "lazy",
|
|
3266
|
+
loadingShowDelay = 0,
|
|
3267
|
+
noSpinner = false,
|
|
3268
|
+
loadingSlot,
|
|
3269
|
+
errorSlot,
|
|
3270
|
+
imgProps,
|
|
3271
|
+
onLoad,
|
|
3272
|
+
onError,
|
|
3273
|
+
className,
|
|
3274
|
+
style,
|
|
3275
|
+
...rest
|
|
3276
|
+
}, ref) {
|
|
3277
|
+
const [status, setStatus] = react.useState("loading");
|
|
3278
|
+
const [spinnerVisible, setSpinnerVisible] = react.useState(loadingShowDelay <= 0);
|
|
3279
|
+
const [trackedSrc, setTrackedSrc] = react.useState(src);
|
|
3280
|
+
const imgRef = react.useRef(null);
|
|
3281
|
+
if (src !== trackedSrc) {
|
|
3282
|
+
setTrackedSrc(src);
|
|
3283
|
+
setStatus("loading");
|
|
3284
|
+
}
|
|
3285
|
+
react.useEffect(() => {
|
|
3286
|
+
if (!src) return;
|
|
3287
|
+
const node = imgRef.current;
|
|
3288
|
+
if (node?.complete && node.naturalWidth > 0) {
|
|
3289
|
+
setStatus((current) => current === "loading" ? "loaded" : current);
|
|
3290
|
+
}
|
|
3291
|
+
}, [src]);
|
|
3292
|
+
react.useEffect(() => {
|
|
3293
|
+
if (status !== "loading" || loadingShowDelay <= 0) {
|
|
3294
|
+
setSpinnerVisible(status === "loading");
|
|
3295
|
+
return;
|
|
3296
|
+
}
|
|
3297
|
+
setSpinnerVisible(false);
|
|
3298
|
+
const timer = setTimeout(() => setSpinnerVisible(true), loadingShowDelay);
|
|
3299
|
+
return () => clearTimeout(timer);
|
|
3300
|
+
}, [status, loadingShowDelay, src]);
|
|
3301
|
+
const isEmpty = !src;
|
|
3302
|
+
const showFallback = isEmpty || status === "error";
|
|
3303
|
+
const showSpinner = !isEmpty && status === "loading" && !noSpinner && spinnerVisible;
|
|
3304
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3305
|
+
"div",
|
|
3306
|
+
{
|
|
3307
|
+
ref,
|
|
3308
|
+
className: cn("relative overflow-hidden bg-(--cmp-image-bg)", className),
|
|
3309
|
+
style: { containerType: "size", aspectRatio: ratio, ...style },
|
|
3310
|
+
...rest,
|
|
3311
|
+
children: [
|
|
3312
|
+
!isEmpty && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3313
|
+
"img",
|
|
3314
|
+
{
|
|
3315
|
+
...imgProps,
|
|
3316
|
+
ref: imgRef,
|
|
3317
|
+
src,
|
|
3318
|
+
alt,
|
|
3319
|
+
loading: loading2,
|
|
3320
|
+
onLoad: () => {
|
|
3321
|
+
setStatus("loaded");
|
|
3322
|
+
onLoad?.(src);
|
|
3323
|
+
},
|
|
3324
|
+
onError: (event) => {
|
|
3325
|
+
setStatus("error");
|
|
3326
|
+
onError?.(event);
|
|
3327
|
+
},
|
|
3328
|
+
className: cn(
|
|
3329
|
+
"h-full w-full",
|
|
3330
|
+
// 로딩 중에도 자리를 지켜야 브라우저가 계속 받아온다 — 숨기되 없애지 않는다
|
|
3331
|
+
status === "loaded" ? "visible" : "invisible",
|
|
3332
|
+
imgProps?.className
|
|
3333
|
+
),
|
|
3334
|
+
style: {
|
|
3335
|
+
objectFit: fit,
|
|
3336
|
+
objectPosition: position,
|
|
3337
|
+
...imgProps?.style
|
|
3338
|
+
}
|
|
3339
|
+
}
|
|
3340
|
+
),
|
|
3341
|
+
showFallback && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inset-0 flex items-center justify-center", children: errorSlot ?? /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "image", size: EMPTY_ICON_SIZE, color: "var(--cmp-image-icon)" }) }),
|
|
3342
|
+
showSpinner && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inset-0 flex items-center justify-center", children: loadingSlot ?? /* @__PURE__ */ jsxRuntime.jsx(SCircleProgress, { indeterminate: true, type: "neutral", size: SPINNER_SIZE }) })
|
|
3343
|
+
]
|
|
3344
|
+
}
|
|
3345
|
+
);
|
|
3346
|
+
});
|
|
3144
3347
|
var BADGE_COLORS = [
|
|
3145
3348
|
"red",
|
|
3146
3349
|
"orange",
|
|
@@ -5582,14 +5785,14 @@ var SCallout = /* @__PURE__ */ react.forwardRef(function SCallout2({ type = "def
|
|
|
5582
5785
|
);
|
|
5583
5786
|
});
|
|
5584
5787
|
var FILL_COLOR = {
|
|
5585
|
-
primary: "var(--cmp-progress-active
|
|
5586
|
-
error: "var(--cmp-progress-error
|
|
5587
|
-
complete: "var(--cmp-progress-success
|
|
5788
|
+
primary: "var(--cmp-progress-color-active)",
|
|
5789
|
+
error: "var(--cmp-progress-color-error)",
|
|
5790
|
+
complete: "var(--cmp-progress-color-success)"
|
|
5588
5791
|
};
|
|
5589
|
-
var
|
|
5792
|
+
var clamp2 = (v) => Number.isFinite(v) ? Math.max(0, Math.min(100, v)) : 0;
|
|
5590
5793
|
var SLinearProgress = /* @__PURE__ */ react.forwardRef(
|
|
5591
5794
|
function SLinearProgress2({ value = 0, type = "primary", indeterminate = false, label, className, style }, ref) {
|
|
5592
|
-
const v =
|
|
5795
|
+
const v = clamp2(value);
|
|
5593
5796
|
const fill = FILL_COLOR[type];
|
|
5594
5797
|
const valueColor = v === 0 ? "var(--sys-color-fg-tertiary, #888888)" : fill;
|
|
5595
5798
|
const valueText = `${Math.round(v)}%`;
|
|
@@ -5636,115 +5839,6 @@ var SLinearProgress = /* @__PURE__ */ react.forwardRef(
|
|
|
5636
5839
|
);
|
|
5637
5840
|
}
|
|
5638
5841
|
);
|
|
5639
|
-
var VIEWBOX = 80;
|
|
5640
|
-
var RADIUS = 34;
|
|
5641
|
-
var STROKE = 12;
|
|
5642
|
-
var CIRCUMFERENCE = 2 * Math.PI * RADIUS;
|
|
5643
|
-
var COLOR_MAP = {
|
|
5644
|
-
primary: { arc: "var(--cmp-progress-active-color)", track: "var(--cmp-progress-color-track)" },
|
|
5645
|
-
// inverse: 어두운 배경용 — arc 흰색, track 은 흰색 40%(회색 링)
|
|
5646
|
-
inverse: { arc: "var(--color-white)", track: "rgba(255,255,255,0.4)" },
|
|
5647
|
-
error: { arc: "var(--color-red-75)", track: "var(--cmp-progress-color-track)" },
|
|
5648
|
-
complete: { arc: "#01BB4B", track: "var(--cmp-progress-color-track)" }
|
|
5649
|
-
};
|
|
5650
|
-
var clamp2 = (v) => Number.isFinite(v) ? Math.max(0, Math.min(100, v)) : 0;
|
|
5651
|
-
var SCircleProgress = /* @__PURE__ */ react.forwardRef(
|
|
5652
|
-
function SCircleProgress2({
|
|
5653
|
-
value = 0,
|
|
5654
|
-
type = "primary",
|
|
5655
|
-
indeterminate = false,
|
|
5656
|
-
label,
|
|
5657
|
-
innerValue = false,
|
|
5658
|
-
className,
|
|
5659
|
-
style
|
|
5660
|
-
}, ref) {
|
|
5661
|
-
const v = clamp2(value);
|
|
5662
|
-
const colors = COLOR_MAP[type];
|
|
5663
|
-
const c = VIEWBOX / 2;
|
|
5664
|
-
const percentColor = v === 0 ? "var(--sys-color-fg-tertiary, #888888)" : colors.arc;
|
|
5665
|
-
const filled = v / 100 * CIRCUMFERENCE;
|
|
5666
|
-
const showPercent = !indeterminate;
|
|
5667
|
-
const percentNode = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5668
|
-
"span",
|
|
5669
|
-
{
|
|
5670
|
-
className: cn(
|
|
5671
|
-
"text-center text-[16px] font-bold",
|
|
5672
|
-
innerValue ? (
|
|
5673
|
-
// leading-[normal]: 26px leading 은 폰트 content(19px) 위아래로 홀수(7px)만큼 남아
|
|
5674
|
-
// 3px/4px 로 쪼개지고 글자가 링 중심보다 위로 뜬다. (leading-normal 은 1.5 라 동일 문제)
|
|
5675
|
-
"absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 leading-[normal]"
|
|
5676
|
-
) : "leading-[26px]"
|
|
5677
|
-
),
|
|
5678
|
-
style: { color: percentColor },
|
|
5679
|
-
children: [
|
|
5680
|
-
Math.round(v),
|
|
5681
|
-
"%"
|
|
5682
|
-
]
|
|
5683
|
-
}
|
|
5684
|
-
);
|
|
5685
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5686
|
-
"div",
|
|
5687
|
-
{
|
|
5688
|
-
ref,
|
|
5689
|
-
className: cn(
|
|
5690
|
-
"inline-flex flex-col items-center gap-[var(--cmp-progress-circular-gap)]",
|
|
5691
|
-
className
|
|
5692
|
-
),
|
|
5693
|
-
style,
|
|
5694
|
-
children: [
|
|
5695
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(innerValue && "relative"), children: [
|
|
5696
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
5697
|
-
"svg",
|
|
5698
|
-
{
|
|
5699
|
-
viewBox: `0 0 ${VIEWBOX} ${VIEWBOX}`,
|
|
5700
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
5701
|
-
className: cn(
|
|
5702
|
-
"h-[80px] w-[80px]",
|
|
5703
|
-
indeterminate && "origin-center animate-circle-spin"
|
|
5704
|
-
),
|
|
5705
|
-
children: [
|
|
5706
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5707
|
-
"circle",
|
|
5708
|
-
{
|
|
5709
|
-
cx: c,
|
|
5710
|
-
cy: c,
|
|
5711
|
-
r: RADIUS,
|
|
5712
|
-
fill: "none",
|
|
5713
|
-
strokeWidth: STROKE,
|
|
5714
|
-
style: { stroke: colors.track }
|
|
5715
|
-
}
|
|
5716
|
-
),
|
|
5717
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5718
|
-
"circle",
|
|
5719
|
-
{
|
|
5720
|
-
cx: c,
|
|
5721
|
-
cy: c,
|
|
5722
|
-
r: RADIUS,
|
|
5723
|
-
fill: "none",
|
|
5724
|
-
strokeWidth: STROKE,
|
|
5725
|
-
strokeLinecap: "round",
|
|
5726
|
-
className: cn(
|
|
5727
|
-
"origin-center",
|
|
5728
|
-
indeterminate ? "animate-circle-arc" : "-rotate-90 transition-[stroke-dasharray] duration-[400ms] ease-linear"
|
|
5729
|
-
),
|
|
5730
|
-
style: {
|
|
5731
|
-
stroke: colors.arc,
|
|
5732
|
-
...indeterminate ? {} : { strokeDasharray: `${filled} ${CIRCUMFERENCE}`, strokeDashoffset: 0 }
|
|
5733
|
-
}
|
|
5734
|
-
}
|
|
5735
|
-
)
|
|
5736
|
-
]
|
|
5737
|
-
}
|
|
5738
|
-
),
|
|
5739
|
-
showPercent && innerValue && percentNode
|
|
5740
|
-
] }),
|
|
5741
|
-
showPercent && !innerValue && percentNode,
|
|
5742
|
-
label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-center text-[12px] font-normal leading-[20px] text-[color:var(--cmp-progress-color-label)]", children: label })
|
|
5743
|
-
]
|
|
5744
|
-
}
|
|
5745
|
-
);
|
|
5746
|
-
}
|
|
5747
|
-
);
|
|
5748
5842
|
|
|
5749
5843
|
// src/lib/global-overlay.ts
|
|
5750
5844
|
var GLOBAL_OVERLAY_ATTR = "data-s-global-overlay";
|
|
@@ -6230,10 +6324,15 @@ function SSwitch({
|
|
|
6230
6324
|
}
|
|
6231
6325
|
);
|
|
6232
6326
|
}
|
|
6327
|
+
var SIZE_CLASSES = {
|
|
6328
|
+
xs: "h-[24px] px-[8px] text-[12px] font-normal leading-[20px]",
|
|
6329
|
+
sm: "h-[28px] px-[12px] text-[14px] font-medium leading-[24px]"
|
|
6330
|
+
};
|
|
6233
6331
|
function SToggle({
|
|
6234
6332
|
value = false,
|
|
6235
6333
|
label = "",
|
|
6236
6334
|
disabled = false,
|
|
6335
|
+
size = "sm",
|
|
6237
6336
|
onValueChange,
|
|
6238
6337
|
className,
|
|
6239
6338
|
style
|
|
@@ -6249,7 +6348,8 @@ function SToggle({
|
|
|
6249
6348
|
"aria-pressed": value,
|
|
6250
6349
|
onClick: () => !disabled && onValueChange?.(!value),
|
|
6251
6350
|
className: cn(
|
|
6252
|
-
"box-border inline-flex
|
|
6351
|
+
"box-border inline-flex items-center justify-center whitespace-nowrap rounded-full border border-solid transition-colors",
|
|
6352
|
+
SIZE_CLASSES[size],
|
|
6253
6353
|
disabled ? "cursor-not-allowed" : "cursor-pointer",
|
|
6254
6354
|
// 미선택(off) hover 시 파란 채움 + 흰 글자
|
|
6255
6355
|
!disabled && !value && "hover:!bg-[var(--cmp-toggle-bg-hover)] hover:!text-[color:var(--cmp-toggle-content-hover)] hover:!border-[color:var(--cmp-toggle-bg-hover)]",
|
|
@@ -12056,12 +12156,244 @@ function SCalendar({
|
|
|
12056
12156
|
}
|
|
12057
12157
|
);
|
|
12058
12158
|
}
|
|
12159
|
+
var DATEPICKER_MODE_LIST_HEIGHT = 240;
|
|
12160
|
+
var DATEPICKER_MODE_ITEM_HEIGHT = 28;
|
|
12161
|
+
var YEAR_LIST_EDGE_BUFFER = 24;
|
|
12162
|
+
var YEAR_LIST_EXPAND_SIZE = 80;
|
|
12163
|
+
var MONTHS = Array.from({ length: 12 }, (_, i) => i + 1);
|
|
12164
|
+
var getTodayParts = () => {
|
|
12165
|
+
const today = /* @__PURE__ */ new Date();
|
|
12166
|
+
return {
|
|
12167
|
+
year: today.getFullYear(),
|
|
12168
|
+
month: today.getMonth() + 1
|
|
12169
|
+
};
|
|
12170
|
+
};
|
|
12171
|
+
var parseYear = (value) => {
|
|
12172
|
+
const year = Number(value?.slice(0, 4));
|
|
12173
|
+
return Number.isFinite(year) && year > 0 ? year : void 0;
|
|
12174
|
+
};
|
|
12175
|
+
var parseMonth = (value) => {
|
|
12176
|
+
const month = Number(value?.slice(5, 7));
|
|
12177
|
+
return Number.isFinite(month) && month >= 1 && month <= 12 ? month : void 0;
|
|
12178
|
+
};
|
|
12179
|
+
var formatMonthValue = (year, month) => `${year}-${String(month).padStart(2, "0")}`;
|
|
12180
|
+
var isYearDisabled = (year, selectable) => {
|
|
12181
|
+
if (!selectable) return false;
|
|
12182
|
+
const [start, end] = selectable;
|
|
12183
|
+
if (start !== "" && year < Number(start.slice(0, 4))) return true;
|
|
12184
|
+
if (end !== "" && year > Number(end.slice(0, 4))) return true;
|
|
12185
|
+
return false;
|
|
12186
|
+
};
|
|
12187
|
+
var isMonthDisabled = (year, month, selectable) => {
|
|
12188
|
+
if (!selectable) return false;
|
|
12189
|
+
const value = formatMonthValue(year, month);
|
|
12190
|
+
const [start, end] = selectable;
|
|
12191
|
+
if (start !== "" && value < start.slice(0, 7)) return true;
|
|
12192
|
+
if (end !== "" && value > end.slice(0, 7)) return true;
|
|
12193
|
+
return false;
|
|
12194
|
+
};
|
|
12195
|
+
function YearWheel({ value, anchorYear, selectable, onCommit }) {
|
|
12196
|
+
const listRef = react.useRef(null);
|
|
12197
|
+
const syncingScrollRef = react.useRef(false);
|
|
12198
|
+
const anchorYearRef = react.useRef(anchorYear);
|
|
12199
|
+
const [range, setRange] = react.useState(() => ({
|
|
12200
|
+
start: anchorYear - YEAR_LIST_EXPAND_SIZE,
|
|
12201
|
+
end: anchorYear + YEAR_LIST_EXPAND_SIZE
|
|
12202
|
+
}));
|
|
12203
|
+
const rangeStartRef = react.useRef(range.start);
|
|
12204
|
+
rangeStartRef.current = range.start;
|
|
12205
|
+
const years = Array.from({ length: range.end - range.start + 1 }, (_, i) => range.start + i);
|
|
12206
|
+
react.useLayoutEffect(() => {
|
|
12207
|
+
const list = listRef.current;
|
|
12208
|
+
if (!list) return;
|
|
12209
|
+
const index = anchorYearRef.current - rangeStartRef.current;
|
|
12210
|
+
syncingScrollRef.current = true;
|
|
12211
|
+
list.scrollTop = index * DATEPICKER_MODE_ITEM_HEIGHT;
|
|
12212
|
+
requestAnimationFrame(() => {
|
|
12213
|
+
syncingScrollRef.current = false;
|
|
12214
|
+
});
|
|
12215
|
+
}, []);
|
|
12216
|
+
const handleScroll = () => {
|
|
12217
|
+
const list = listRef.current;
|
|
12218
|
+
if (!list) return;
|
|
12219
|
+
if (syncingScrollRef.current) return;
|
|
12220
|
+
if (list.scrollTop < DATEPICKER_MODE_ITEM_HEIGHT * YEAR_LIST_EDGE_BUFFER) {
|
|
12221
|
+
const previousHeight = list.scrollHeight;
|
|
12222
|
+
setRange((current) => ({
|
|
12223
|
+
start: current.start - YEAR_LIST_EXPAND_SIZE,
|
|
12224
|
+
end: current.end
|
|
12225
|
+
}));
|
|
12226
|
+
requestAnimationFrame(() => {
|
|
12227
|
+
if (!listRef.current) return;
|
|
12228
|
+
syncingScrollRef.current = true;
|
|
12229
|
+
listRef.current.scrollTop += listRef.current.scrollHeight - previousHeight;
|
|
12230
|
+
requestAnimationFrame(() => {
|
|
12231
|
+
syncingScrollRef.current = false;
|
|
12232
|
+
});
|
|
12233
|
+
});
|
|
12234
|
+
return;
|
|
12235
|
+
}
|
|
12236
|
+
if (list.scrollHeight - list.scrollTop - list.clientHeight < DATEPICKER_MODE_ITEM_HEIGHT * YEAR_LIST_EDGE_BUFFER) {
|
|
12237
|
+
setRange((current) => ({
|
|
12238
|
+
start: current.start,
|
|
12239
|
+
end: current.end + YEAR_LIST_EXPAND_SIZE
|
|
12240
|
+
}));
|
|
12241
|
+
}
|
|
12242
|
+
};
|
|
12243
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full w-full overflow-hidden bg-[var(--cmp-datepicker-mode-bg)]", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12244
|
+
"div",
|
|
12245
|
+
{
|
|
12246
|
+
ref: listRef,
|
|
12247
|
+
role: "listbox",
|
|
12248
|
+
"aria-label": "year",
|
|
12249
|
+
className: "h-full overflow-y-auto overscroll-contain [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
12250
|
+
style: {
|
|
12251
|
+
paddingTop: `calc((${DATEPICKER_MODE_LIST_HEIGHT}px - ${DATEPICKER_MODE_ITEM_HEIGHT}px) / 2)`,
|
|
12252
|
+
paddingBottom: `calc((${DATEPICKER_MODE_LIST_HEIGHT}px - ${DATEPICKER_MODE_ITEM_HEIGHT}px) / 2)`
|
|
12253
|
+
},
|
|
12254
|
+
onScroll: handleScroll,
|
|
12255
|
+
children: years.map((year) => {
|
|
12256
|
+
const selected = year === value;
|
|
12257
|
+
const disabled = isYearDisabled(year, selectable);
|
|
12258
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
12259
|
+
"button",
|
|
12260
|
+
{
|
|
12261
|
+
type: "button",
|
|
12262
|
+
role: "option",
|
|
12263
|
+
"aria-selected": selected,
|
|
12264
|
+
disabled,
|
|
12265
|
+
className: cn(
|
|
12266
|
+
"flex w-full items-center justify-center gap-[var(--cmp-datepicker-mode-item-gap)] border-0 px-[var(--cmp-datepicker-mode-item-paddingX)] py-[var(--cmp-datepicker-mode-item-paddingY)] text-center font-base text-12 leading-[20px]",
|
|
12267
|
+
disabled && "cursor-not-allowed bg-[var(--cmp-datepicker-mode-item-bg-default)] font-medium text-[color:var(--cmp-datepicker-mode-item-content-disabled)]",
|
|
12268
|
+
!disabled && !selected && "cursor-pointer bg-[var(--cmp-datepicker-mode-item-bg-default)] font-medium text-[color:var(--cmp-datepicker-mode-item-content-default)] hover:bg-[var(--cmp-datepicker-mode-item-bg-hover)] hover:text-[color:var(--cmp-datepicker-mode-item-content-hover)]",
|
|
12269
|
+
!disabled && selected && "cursor-pointer bg-[var(--cmp-datepicker-mode-item-bg-default)] font-bold text-[color:var(--cmp-datepicker-mode-item-content-selected)]"
|
|
12270
|
+
),
|
|
12271
|
+
onClick: () => !disabled && onCommit(year),
|
|
12272
|
+
children: year
|
|
12273
|
+
},
|
|
12274
|
+
year
|
|
12275
|
+
);
|
|
12276
|
+
})
|
|
12277
|
+
}
|
|
12278
|
+
) });
|
|
12279
|
+
}
|
|
12280
|
+
function MonthWheel({ year, value, selectable, onCommit }) {
|
|
12281
|
+
const listRef = react.useRef(null);
|
|
12282
|
+
const initialValueRef = react.useRef(value);
|
|
12283
|
+
react.useLayoutEffect(() => {
|
|
12284
|
+
const list = listRef.current;
|
|
12285
|
+
if (!list) return;
|
|
12286
|
+
list.scrollTop = Math.max(
|
|
12287
|
+
0,
|
|
12288
|
+
(initialValueRef.current - 1) * DATEPICKER_MODE_ITEM_HEIGHT - (list.clientHeight - DATEPICKER_MODE_ITEM_HEIGHT) / 2
|
|
12289
|
+
);
|
|
12290
|
+
}, []);
|
|
12291
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full w-full overflow-hidden bg-[var(--cmp-datepicker-mode-bg)]", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12292
|
+
"div",
|
|
12293
|
+
{
|
|
12294
|
+
ref: listRef,
|
|
12295
|
+
role: "listbox",
|
|
12296
|
+
"aria-label": "month",
|
|
12297
|
+
className: "h-full overflow-y-auto overscroll-contain [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
12298
|
+
children: MONTHS.map((month) => {
|
|
12299
|
+
const selected = month === value;
|
|
12300
|
+
const disabled = isMonthDisabled(year, month, selectable);
|
|
12301
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12302
|
+
"button",
|
|
12303
|
+
{
|
|
12304
|
+
type: "button",
|
|
12305
|
+
role: "option",
|
|
12306
|
+
"aria-selected": selected,
|
|
12307
|
+
disabled,
|
|
12308
|
+
className: cn(
|
|
12309
|
+
"flex w-full items-center justify-center gap-[var(--cmp-datepicker-mode-item-gap)] border-0 px-[var(--cmp-datepicker-mode-item-paddingX)] py-[var(--cmp-datepicker-mode-item-paddingY)] text-center font-base text-12 leading-[20px]",
|
|
12310
|
+
disabled && "cursor-not-allowed bg-[var(--cmp-datepicker-mode-item-bg-default)] font-medium text-[color:var(--cmp-datepicker-mode-item-content-disabled)]",
|
|
12311
|
+
!disabled && !selected && "cursor-pointer bg-[var(--cmp-datepicker-mode-item-bg-default)] font-medium text-[color:var(--cmp-datepicker-mode-item-content-default)] hover:bg-[var(--cmp-datepicker-mode-item-bg-hover)] hover:text-[color:var(--cmp-datepicker-mode-item-content-hover)]",
|
|
12312
|
+
!disabled && selected && "cursor-pointer bg-[var(--cmp-datepicker-mode-item-bg-default)] font-bold text-[color:var(--cmp-datepicker-mode-item-content-selected)]"
|
|
12313
|
+
),
|
|
12314
|
+
onClick: () => !disabled && onCommit(month),
|
|
12315
|
+
children: [
|
|
12316
|
+
month,
|
|
12317
|
+
"\uC6D4"
|
|
12318
|
+
]
|
|
12319
|
+
},
|
|
12320
|
+
month
|
|
12321
|
+
);
|
|
12322
|
+
})
|
|
12323
|
+
}
|
|
12324
|
+
) });
|
|
12325
|
+
}
|
|
12326
|
+
function DatePickerListbox({
|
|
12327
|
+
mode,
|
|
12328
|
+
value,
|
|
12329
|
+
selectable,
|
|
12330
|
+
onValueChange,
|
|
12331
|
+
onClose
|
|
12332
|
+
}) {
|
|
12333
|
+
const today = getTodayParts();
|
|
12334
|
+
const [year, setYear] = react.useState(() => parseYear(value) ?? today.year);
|
|
12335
|
+
const [month, setMonth] = react.useState(() => parseMonth(value) ?? today.month);
|
|
12336
|
+
const commitYear = (nextYear) => {
|
|
12337
|
+
setYear(nextYear);
|
|
12338
|
+
if (mode === "year") {
|
|
12339
|
+
onValueChange?.(String(nextYear));
|
|
12340
|
+
onClose();
|
|
12341
|
+
return;
|
|
12342
|
+
}
|
|
12343
|
+
onValueChange?.(formatMonthValue(nextYear, month));
|
|
12344
|
+
};
|
|
12345
|
+
const commitMonth = (nextMonth) => {
|
|
12346
|
+
setMonth(nextMonth);
|
|
12347
|
+
onValueChange?.(formatMonthValue(year, nextMonth));
|
|
12348
|
+
onClose();
|
|
12349
|
+
};
|
|
12350
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12351
|
+
"div",
|
|
12352
|
+
{
|
|
12353
|
+
className: cn(
|
|
12354
|
+
"inline-flex h-[240px] overflow-hidden rounded-[var(--cmp-datepicker-mode-radius)] bg-[var(--cmp-datepicker-mode-bg)] shadow-normal-sm",
|
|
12355
|
+
mode === "month" ? "gap-[var(--cmp-datepicker-mode-yearMonth-gap)]" : "w-[var(--cmp-datepicker-mode-year-width)]"
|
|
12356
|
+
),
|
|
12357
|
+
children: [
|
|
12358
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12359
|
+
"div",
|
|
12360
|
+
{
|
|
12361
|
+
className: cn(
|
|
12362
|
+
"min-w-0",
|
|
12363
|
+
mode === "month" ? "w-[var(--cmp-datepicker-mode-yearMonth-column-width)]" : "w-full"
|
|
12364
|
+
),
|
|
12365
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12366
|
+
YearWheel,
|
|
12367
|
+
{
|
|
12368
|
+
value: year,
|
|
12369
|
+
anchorYear: today.year,
|
|
12370
|
+
selectable,
|
|
12371
|
+
onCommit: commitYear
|
|
12372
|
+
}
|
|
12373
|
+
)
|
|
12374
|
+
}
|
|
12375
|
+
),
|
|
12376
|
+
mode === "month" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
12377
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12378
|
+
"div",
|
|
12379
|
+
{
|
|
12380
|
+
"aria-hidden": true,
|
|
12381
|
+
className: "w-[var(--border-width-1)] self-stretch bg-[var(--sys-color-divider-default)]"
|
|
12382
|
+
}
|
|
12383
|
+
),
|
|
12384
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 w-[var(--cmp-datepicker-mode-yearMonth-column-width)]", children: /* @__PURE__ */ jsxRuntime.jsx(MonthWheel, { year, value: month, selectable, onCommit: commitMonth }) })
|
|
12385
|
+
] })
|
|
12386
|
+
]
|
|
12387
|
+
}
|
|
12388
|
+
);
|
|
12389
|
+
}
|
|
12059
12390
|
function SDatePicker({
|
|
12060
12391
|
value,
|
|
12061
12392
|
onValueChange,
|
|
12062
12393
|
onViewChange,
|
|
12394
|
+
mode = "date",
|
|
12063
12395
|
size = "sm",
|
|
12064
|
-
placeholder
|
|
12396
|
+
placeholder,
|
|
12065
12397
|
selectable,
|
|
12066
12398
|
disabled = false,
|
|
12067
12399
|
width,
|
|
@@ -12087,6 +12419,7 @@ function SDatePicker({
|
|
|
12087
12419
|
const [focused, setFocused] = react.useState(false);
|
|
12088
12420
|
const [ruleError, setRuleError] = react.useState("");
|
|
12089
12421
|
const hasValue = value != null && value !== "";
|
|
12422
|
+
const resolvedPlaceholder = placeholder ?? (mode === "year" ? "YYYY" : mode === "month" ? "YYYY-MM" : "YYYY-MM-DD");
|
|
12090
12423
|
useFormField({
|
|
12091
12424
|
name,
|
|
12092
12425
|
validate: () => {
|
|
@@ -12098,12 +12431,34 @@ function SDatePicker({
|
|
|
12098
12431
|
});
|
|
12099
12432
|
const resolvedError = error || ruleError !== "";
|
|
12100
12433
|
const resolvedStatus = status ?? (rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0);
|
|
12101
|
-
const dims = size === "md" ? {
|
|
12434
|
+
const dims = size === "md" ? {
|
|
12435
|
+
padX: 16,
|
|
12436
|
+
gap: 12,
|
|
12437
|
+
icon: 20,
|
|
12438
|
+
minW: 104,
|
|
12439
|
+
fieldMinW: 168,
|
|
12440
|
+
fontSize: 14,
|
|
12441
|
+
lineHeight: 24,
|
|
12442
|
+
radius: 6
|
|
12443
|
+
} : {
|
|
12444
|
+
padX: 12,
|
|
12445
|
+
gap: 8,
|
|
12446
|
+
icon: 16,
|
|
12447
|
+
minW: 80,
|
|
12448
|
+
fieldMinW: 128,
|
|
12449
|
+
fontSize: 12,
|
|
12450
|
+
lineHeight: 20,
|
|
12451
|
+
radius: 4
|
|
12452
|
+
};
|
|
12102
12453
|
const select = (date) => {
|
|
12103
12454
|
onValueChange?.(date);
|
|
12104
12455
|
if (rules && rules.length > 0) setRuleError(runRules(date, rules));
|
|
12105
12456
|
setOpen(false);
|
|
12106
12457
|
};
|
|
12458
|
+
const selectListboxValue = (nextValue) => {
|
|
12459
|
+
onValueChange?.(nextValue);
|
|
12460
|
+
if (rules && rules.length > 0) setRuleError(runRules(nextValue, rules));
|
|
12461
|
+
};
|
|
12107
12462
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
12108
12463
|
SField,
|
|
12109
12464
|
{
|
|
@@ -12122,6 +12477,7 @@ function SDatePicker({
|
|
|
12122
12477
|
focused: focused || open,
|
|
12123
12478
|
errorMessage: ruleError !== "" ? ruleError : errorMessage,
|
|
12124
12479
|
width,
|
|
12480
|
+
minWidth: dims.fieldMinW,
|
|
12125
12481
|
disabled,
|
|
12126
12482
|
className,
|
|
12127
12483
|
style,
|
|
@@ -12156,7 +12512,7 @@ function SDatePicker({
|
|
|
12156
12512
|
lineHeight: `${dims.lineHeight}px`,
|
|
12157
12513
|
color: disabled ? "var(--cmp-datepicker-text-disabled)" : hasValue ? "var(--cmp-datepicker-text-default)" : "var(--cmp-field-hint-color)"
|
|
12158
12514
|
},
|
|
12159
|
-
children: hasValue ? value :
|
|
12515
|
+
children: hasValue ? value : resolvedPlaceholder
|
|
12160
12516
|
}
|
|
12161
12517
|
)
|
|
12162
12518
|
]
|
|
@@ -12172,7 +12528,7 @@ function SDatePicker({
|
|
|
12172
12528
|
"z-50 max-w-[var(--radix-popover-content-available-width)]",
|
|
12173
12529
|
FLOATING_SLIDE_ANIM
|
|
12174
12530
|
),
|
|
12175
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12531
|
+
children: mode === "date" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
12176
12532
|
SCalendar,
|
|
12177
12533
|
{
|
|
12178
12534
|
value: value ?? void 0,
|
|
@@ -12181,6 +12537,15 @@ function SDatePicker({
|
|
|
12181
12537
|
onValueChange: select,
|
|
12182
12538
|
onViewChange
|
|
12183
12539
|
}
|
|
12540
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
12541
|
+
DatePickerListbox,
|
|
12542
|
+
{
|
|
12543
|
+
mode,
|
|
12544
|
+
value,
|
|
12545
|
+
selectable,
|
|
12546
|
+
onValueChange: selectListboxValue,
|
|
12547
|
+
onClose: () => setOpen(false)
|
|
12548
|
+
}
|
|
12184
12549
|
)
|
|
12185
12550
|
}
|
|
12186
12551
|
) })
|
|
@@ -16402,6 +16767,7 @@ exports.GNB_MENU_WIDTH = GNB_MENU_WIDTH;
|
|
|
16402
16767
|
exports.GNB_RAIL = GNB_RAIL;
|
|
16403
16768
|
exports.GNB_RAIL_WIDTH = GNB_RAIL_WIDTH;
|
|
16404
16769
|
exports.ICONS = ICONS;
|
|
16770
|
+
exports.IMAGE_FITS = IMAGE_FITS;
|
|
16405
16771
|
exports.PAGE_BACKGROUNDS = PAGE_BACKGROUNDS;
|
|
16406
16772
|
exports.RangeCalendar = RangeCalendar;
|
|
16407
16773
|
exports.SActionModal = SActionModal;
|
|
@@ -16436,6 +16802,7 @@ exports.SGhostButton = SGhostButton;
|
|
|
16436
16802
|
exports.SGnb = SGnb;
|
|
16437
16803
|
exports.SGuide = SGuide;
|
|
16438
16804
|
exports.SIcon = SIcon;
|
|
16805
|
+
exports.SImage = SImage;
|
|
16439
16806
|
exports.SInput = SInput;
|
|
16440
16807
|
exports.SKeyValueTable = SKeyValueTable;
|
|
16441
16808
|
exports.SLAYOUT_MIN_WIDTH = SLAYOUT_MIN_WIDTH;
|