sellmate-design-system-react 8.1.0 → 9.0.0-beta.2
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 +176 -111
- package/README.md +38 -8
- package/dist/components/SChipFilter/README.md +69 -0
- package/dist/components/SChipFilter/SChipFilter.d.ts +160 -0
- package/dist/components/SChipFilter/index.d.ts +1 -0
- package/dist/components/SCircleProgress/README.md +3 -0
- package/dist/components/SCircleProgress/SCircleProgress.d.ts +7 -1
- package/dist/components/SDatePicker/README.md +2 -0
- package/dist/components/SDateRangePicker/README.md +21 -0
- package/dist/components/SDateRangePicker/SDateRangePicker.d.ts +16 -0
- package/dist/components/SDateRangePicker/index.d.ts +1 -1
- package/dist/components/SGhostButton/README.md +4 -0
- package/dist/components/SGuide/README.md +1 -1
- package/dist/components/SGuide/SGuide.d.ts +1 -1
- package/dist/components/SIcon/README.md +4 -0
- package/dist/components/SIcon/icons.gen.d.ts +1 -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/SList/README.md +1 -0
- package/dist/components/SList/SList.d.ts +2 -0
- package/dist/components/SListItem/README.md +2 -2
- package/dist/components/SListItem/SListItem.d.ts +2 -2
- package/dist/components/SPage/README.md +21 -0
- package/dist/components/SPage/SPage.d.ts +10 -0
- package/dist/components/SPage/SPageHeader.d.ts +32 -0
- package/dist/components/SPage/index.d.ts +1 -0
- package/dist/components/SPortal/README.md +1 -1
- package/dist/components/SPortal/SPortal.d.ts +7 -1
- package/dist/components/SRadio/README.md +2 -0
- package/dist/components/SRadioButton/README.md +13 -0
- package/dist/components/SSelect/README.md +2 -2
- package/dist/components/SSelect/SSelect.d.ts +2 -2
- package/dist/components/STag/README.md +2 -0
- package/dist/components/STextLink/README.md +2 -0
- package/dist/components/SToggle/README.md +1 -0
- package/dist/components/SToggle/SToggle.d.ts +4 -1
- package/dist/components/STooltip/README.md +2 -0
- package/dist/index.cjs +1830 -319
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1826 -319
- package/dist/index.js.map +1 -1
- package/dist/lib/floating-width.d.ts +22 -0
- package/dist/llms-full.txt +343 -118
- package/dist/llms.txt +180 -114
- package/dist/styles.css +218 -16
- package/dist/theme.css +12 -5
- package/eslint/scale.gen.mjs +1 -1
- package/package.json +7 -4
package/dist/index.cjs
CHANGED
|
@@ -7,7 +7,7 @@ var react = require('react');
|
|
|
7
7
|
var jsxRuntime = require('react/jsx-runtime');
|
|
8
8
|
var reactDom = require('react-dom');
|
|
9
9
|
var RCheckbox = require('@radix-ui/react-checkbox');
|
|
10
|
-
var
|
|
10
|
+
var RPopover9 = require('@radix-ui/react-popover');
|
|
11
11
|
var client = require('react-dom/client');
|
|
12
12
|
var RTooltip = require('@radix-ui/react-tooltip');
|
|
13
13
|
var RDropdown = require('@radix-ui/react-dropdown-menu');
|
|
@@ -34,7 +34,7 @@ function _interopNamespace(e) {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
var RCheckbox__namespace = /*#__PURE__*/_interopNamespace(RCheckbox);
|
|
37
|
-
var
|
|
37
|
+
var RPopover9__namespace = /*#__PURE__*/_interopNamespace(RPopover9);
|
|
38
38
|
var RTooltip__namespace = /*#__PURE__*/_interopNamespace(RTooltip);
|
|
39
39
|
var RDropdown__namespace = /*#__PURE__*/_interopNamespace(RDropdown);
|
|
40
40
|
var RSwitch__namespace = /*#__PURE__*/_interopNamespace(RSwitch);
|
|
@@ -2593,6 +2593,27 @@ var Icon_sidebar = (p) => {
|
|
|
2593
2593
|
}
|
|
2594
2594
|
);
|
|
2595
2595
|
};
|
|
2596
|
+
var Icon_star = (p) => {
|
|
2597
|
+
const { size = 24, ...rest } = p;
|
|
2598
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2599
|
+
"svg",
|
|
2600
|
+
{
|
|
2601
|
+
width: size,
|
|
2602
|
+
height: size,
|
|
2603
|
+
viewBox: "0 0 24 24",
|
|
2604
|
+
fill: "none",
|
|
2605
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2606
|
+
...rest,
|
|
2607
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2608
|
+
"path",
|
|
2609
|
+
{
|
|
2610
|
+
d: "M12.3358 3.45335C12.0755 2.84888 11.2185 2.84888 10.9582 3.45335L8.78136 8.50811C8.67278 8.76024 8.43512 8.93291 8.16178 8.95826L2.68175 9.46652C2.02642 9.5273 1.76157 10.3424 2.25602 10.7768L6.39071 14.409C6.59695 14.5902 6.68773 14.8696 6.62737 15.1374L5.41733 20.5063C5.27263 21.1483 5.966 21.6521 6.5319 21.3161L11.2641 18.5062C11.5001 18.366 11.7939 18.366 12.0299 18.5062L16.7621 21.3161C17.328 21.6521 18.0214 21.1483 17.8767 20.5063L16.6666 15.1374C16.6063 14.8696 16.6971 14.5902 16.9033 14.409L21.038 10.7768C21.5324 10.3424 21.2676 9.5273 20.6123 9.46652L15.1322 8.95826C14.8589 8.93291 14.6212 8.76024 14.5126 8.50811L12.3358 3.45335Z",
|
|
2611
|
+
fill: "currentColor"
|
|
2612
|
+
}
|
|
2613
|
+
)
|
|
2614
|
+
}
|
|
2615
|
+
);
|
|
2616
|
+
};
|
|
2596
2617
|
var Icon_store = (p) => {
|
|
2597
2618
|
const { size = 24, ...rest } = p;
|
|
2598
2619
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -3087,6 +3108,7 @@ var ICONS = {
|
|
|
3087
3108
|
settingOutline: Icon_settingOutline,
|
|
3088
3109
|
shield: Icon_shield,
|
|
3089
3110
|
sidebar: Icon_sidebar,
|
|
3111
|
+
star: Icon_star,
|
|
3090
3112
|
store: Icon_store,
|
|
3091
3113
|
synchronize: Icon_synchronize,
|
|
3092
3114
|
thumbsDown: Icon_thumbsDown,
|
|
@@ -3119,6 +3141,209 @@ var SIcon = /* @__PURE__ */ react.forwardRef(function SIcon2({ name, size = 24,
|
|
|
3119
3141
|
}
|
|
3120
3142
|
);
|
|
3121
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
|
+
});
|
|
3122
3347
|
var BADGE_COLORS = [
|
|
3123
3348
|
"red",
|
|
3124
3349
|
"orange",
|
|
@@ -3220,12 +3445,13 @@ var SDraggableItemView = /* @__PURE__ */ react.forwardRef(
|
|
|
3220
3445
|
!disabled && !selected && !dragging && "hover:bg-(--cmp-listDraggableItem-bg-hover)",
|
|
3221
3446
|
hasSupportingText && supportingTextPosition === "bottom" ? dense ? "min-h-[52px]" : "min-h-[60px]" : dense ? "h-[32px]" : "h-[40px]",
|
|
3222
3447
|
paddingYClass,
|
|
3223
|
-
|
|
3448
|
+
// 항목 사이 구분선은 리스트가 그린다 — SDraggableList 의 separator (SList.tsx)
|
|
3449
|
+
bordered && cn(
|
|
3224
3450
|
"rounded-(--cmp-listDraggableItem-radius-bordered) border border-(--cmp-listDraggableItem-border-default)",
|
|
3225
3451
|
!disabled && !selected && !dragging && "hover:border-(--cmp-listDraggableItem-bordered-border-hover)",
|
|
3226
3452
|
!disabled && selected && !dragging && "border-(--cmp-listDraggableItem-bordered-border-selected) bg-(--cmp-listDraggableItem-bordered-bg-selected)",
|
|
3227
3453
|
!disabled && selected && dragging && "border-[length:var(--cmp-listDraggableItem-bordered-dragging-border-width)] border-(--cmp-listDraggableItem-bordered-dragging-border-color) bg-(--cmp-listDraggableItem-bordered-dragging-bg)"
|
|
3228
|
-
)
|
|
3454
|
+
),
|
|
3229
3455
|
disabled && "cursor-not-allowed",
|
|
3230
3456
|
className
|
|
3231
3457
|
),
|
|
@@ -3427,7 +3653,7 @@ var SDraggableItemImpl = /* @__PURE__ */ react.forwardRef(function SDraggableIte
|
|
|
3427
3653
|
] });
|
|
3428
3654
|
});
|
|
3429
3655
|
var SDraggableItem2 = /* @__PURE__ */ withDisplayName(SDraggableItemImpl, "SDraggableItem");
|
|
3430
|
-
var SListImpl = /* @__PURE__ */ react.forwardRef(function SList({ className, children, useGap = false, usePadding = false, ...rest }, ref) {
|
|
3656
|
+
var SListImpl = /* @__PURE__ */ react.forwardRef(function SList({ className, children, useGap = false, usePadding = false, separator = false, ...rest }, ref) {
|
|
3431
3657
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3432
3658
|
"div",
|
|
3433
3659
|
{
|
|
@@ -3435,6 +3661,7 @@ var SListImpl = /* @__PURE__ */ react.forwardRef(function SList({ className, chi
|
|
|
3435
3661
|
className: cn(
|
|
3436
3662
|
useGap && "flex flex-col gap-(--cmp-list-group-gap)",
|
|
3437
3663
|
usePadding && "p-(--cmp-list-group-padding)",
|
|
3664
|
+
separator && "[&>*]:border-b [&>*]:border-(--cmp-listItem-border-default)",
|
|
3438
3665
|
className
|
|
3439
3666
|
),
|
|
3440
3667
|
...rest,
|
|
@@ -3806,7 +4033,7 @@ var SExpansionItem = /* @__PURE__ */ react.forwardRef(
|
|
|
3806
4033
|
ref,
|
|
3807
4034
|
className: cn(
|
|
3808
4035
|
"group/expansion-item relative overflow-hidden bg-(--cmp-listExpansionItem-title-bg-default)",
|
|
3809
|
-
|
|
4036
|
+
// 항목 사이 구분선은 리스트가 그린다 — SList/SExpansionList 의 separator (SList.tsx)
|
|
3810
4037
|
// 보더 색은 시맨틱 토큰(border-default → hover strong → 펼침 accentLight)을 쓴다.
|
|
3811
4038
|
// TODO: expansionItem/bordered/radius 토큰 생성 후 rounded 고정값도 토큰으로 교체한다.
|
|
3812
4039
|
bordered && "rounded-[8px] border border-border-default hover:border-border-strong [&:has(>button:hover)]:border-border-strong",
|
|
@@ -3916,7 +4143,7 @@ var SListItemImpl = /* @__PURE__ */ react.forwardRef(function SListItem({
|
|
|
3916
4143
|
trailing,
|
|
3917
4144
|
bordered = false,
|
|
3918
4145
|
selected = false,
|
|
3919
|
-
clickable =
|
|
4146
|
+
clickable = false,
|
|
3920
4147
|
interaction,
|
|
3921
4148
|
accentStripe = false,
|
|
3922
4149
|
dense = false,
|
|
@@ -3969,10 +4196,10 @@ var SListItemImpl = /* @__PURE__ */ react.forwardRef(function SListItem({
|
|
|
3969
4196
|
"gap-(--cmp-listItem-gap)",
|
|
3970
4197
|
"pr-(--cmp-listItem-paddingX)",
|
|
3971
4198
|
depth === 2 ? "pl-[36px]" : depth === 3 ? "pl-[56px]" : "pl-[16px]",
|
|
3972
|
-
bordered
|
|
4199
|
+
bordered && cn(
|
|
3973
4200
|
"overflow-hidden rounded-(--cmp-listItem-radius-bordered) border border-(--cmp-listItem-border-default)",
|
|
3974
4201
|
isSelected ? "border-(--cmp-listItem-bordered-border-selected)" : isInteractive && "hover:border-(--cmp-listItem-bordered-border-hover)"
|
|
3975
|
-
)
|
|
4202
|
+
),
|
|
3976
4203
|
className
|
|
3977
4204
|
),
|
|
3978
4205
|
...rest,
|
|
@@ -4051,6 +4278,8 @@ var SExpansionListImpl = /* @__PURE__ */ react.forwardRef(function SExpansionLis
|
|
|
4051
4278
|
const depth2 = child.props.depth ?? 1;
|
|
4052
4279
|
const itemKey2 = String(child.key ?? index);
|
|
4053
4280
|
return react.cloneElement(child, {
|
|
4281
|
+
// 선택을 리스트가 관리하는 이상 아이템은 클릭 가능해야 한다 — SListItem 의 기본값(false)을 뒤집는다
|
|
4282
|
+
clickable: child.props.clickable ?? true,
|
|
4054
4283
|
selected: selectedKeys[depth2] === itemKey2,
|
|
4055
4284
|
onClick: (event) => {
|
|
4056
4285
|
setSelectedKeys((current) => ({ ...current, [depth2]: itemKey2 }));
|
|
@@ -4356,8 +4585,8 @@ function SGhostButton({
|
|
|
4356
4585
|
}
|
|
4357
4586
|
);
|
|
4358
4587
|
if (!hasTooltip) return btn;
|
|
4359
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4360
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4588
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(RPopover9__namespace.Root, { open, onOpenChange: setOpen, children: [
|
|
4589
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Anchor, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4361
4590
|
"span",
|
|
4362
4591
|
{
|
|
4363
4592
|
className: cn("inline-flex", anchorClassName),
|
|
@@ -4369,8 +4598,8 @@ function SGhostButton({
|
|
|
4369
4598
|
children: btn
|
|
4370
4599
|
}
|
|
4371
4600
|
) }),
|
|
4372
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4373
|
-
|
|
4601
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4602
|
+
RPopover9__namespace.Content,
|
|
4374
4603
|
{
|
|
4375
4604
|
side: "top",
|
|
4376
4605
|
sideOffset: 4,
|
|
@@ -4841,7 +5070,7 @@ var STooltipImpl = /* @__PURE__ */ react.forwardRef(function STooltip({
|
|
|
4841
5070
|
...restContentProps
|
|
4842
5071
|
} = contentProps ?? {};
|
|
4843
5072
|
const contentClass = cn(
|
|
4844
|
-
"z-50 w-fit
|
|
5073
|
+
"z-50 w-fit max-w-[var(--radix-popover-content-available-width)] rounded-[6px] px-[16px] py-[12px] text-[12px] leading-[20px] shadow-normal-sm",
|
|
4845
5074
|
FLOATING_SLIDE_ANIM,
|
|
4846
5075
|
className,
|
|
4847
5076
|
contentPropsClassName
|
|
@@ -4853,14 +5082,14 @@ var STooltipImpl = /* @__PURE__ */ react.forwardRef(function STooltip({
|
|
|
4853
5082
|
...style,
|
|
4854
5083
|
...contentPropsStyle
|
|
4855
5084
|
};
|
|
4856
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5085
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(RPopover9__namespace.Root, { open, onOpenChange: setOpenState, children: [
|
|
4857
5086
|
isNone ? (
|
|
4858
5087
|
// 트리거 없음: children 을 래퍼 없이 그대로 앵커로 쓴다 (소비자 레이아웃 보존).
|
|
4859
5088
|
// mouse/focus 핸들러가 없으므로 useClose 없이도 자동 닫힘이 발생하지 않는다.
|
|
4860
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5089
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Anchor, { asChild: true, children: triggerNode })
|
|
4861
5090
|
) : isHover ? (
|
|
4862
5091
|
// hover: Anchor(위치 기준) + 직접 mouse 핸들러 — 클릭으로 토글되지 않도록 Trigger 미사용
|
|
4863
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5092
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Anchor, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4864
5093
|
"span",
|
|
4865
5094
|
{
|
|
4866
5095
|
className: "inline-flex",
|
|
@@ -4871,9 +5100,9 @@ var STooltipImpl = /* @__PURE__ */ react.forwardRef(function STooltip({
|
|
|
4871
5100
|
children: triggerNode
|
|
4872
5101
|
}
|
|
4873
5102
|
) })
|
|
4874
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
4875
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4876
|
-
|
|
5103
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Trigger, { asChild: true, children: triggerNode }),
|
|
5104
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5105
|
+
RPopover9__namespace.Content,
|
|
4877
5106
|
{
|
|
4878
5107
|
side: placement,
|
|
4879
5108
|
sideOffset,
|
|
@@ -4907,7 +5136,7 @@ var STooltipImpl = /* @__PURE__ */ react.forwardRef(function STooltip({
|
|
|
4907
5136
|
}
|
|
4908
5137
|
)
|
|
4909
5138
|
] }),
|
|
4910
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5139
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Arrow, { width: 16, height: 12, style: { fill: bg } })
|
|
4911
5140
|
]
|
|
4912
5141
|
}
|
|
4913
5142
|
) })
|
|
@@ -5556,14 +5785,14 @@ var SCallout = /* @__PURE__ */ react.forwardRef(function SCallout2({ type = "def
|
|
|
5556
5785
|
);
|
|
5557
5786
|
});
|
|
5558
5787
|
var FILL_COLOR = {
|
|
5559
|
-
primary: "var(--cmp-progress-active
|
|
5560
|
-
error: "var(--cmp-progress-error
|
|
5561
|
-
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)"
|
|
5562
5791
|
};
|
|
5563
|
-
var
|
|
5792
|
+
var clamp2 = (v) => Number.isFinite(v) ? Math.max(0, Math.min(100, v)) : 0;
|
|
5564
5793
|
var SLinearProgress = /* @__PURE__ */ react.forwardRef(
|
|
5565
5794
|
function SLinearProgress2({ value = 0, type = "primary", indeterminate = false, label, className, style }, ref) {
|
|
5566
|
-
const v =
|
|
5795
|
+
const v = clamp2(value);
|
|
5567
5796
|
const fill = FILL_COLOR[type];
|
|
5568
5797
|
const valueColor = v === 0 ? "var(--sys-color-fg-tertiary, #888888)" : fill;
|
|
5569
5798
|
const valueText = `${Math.round(v)}%`;
|
|
@@ -5610,169 +5839,60 @@ var SLinearProgress = /* @__PURE__ */ react.forwardRef(
|
|
|
5610
5839
|
);
|
|
5611
5840
|
}
|
|
5612
5841
|
);
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
var
|
|
5616
|
-
var
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
const
|
|
5636
|
-
const
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
{
|
|
5644
|
-
className: cn(
|
|
5645
|
-
"text-center text-[16px] font-bold",
|
|
5646
|
-
innerValue ? (
|
|
5647
|
-
// leading-[normal]: 26px leading 은 폰트 content(19px) 위아래로 홀수(7px)만큼 남아
|
|
5648
|
-
// 3px/4px 로 쪼개지고 글자가 링 중심보다 위로 뜬다. (leading-normal 은 1.5 라 동일 문제)
|
|
5649
|
-
"absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 leading-[normal]"
|
|
5650
|
-
) : "leading-[26px]"
|
|
5651
|
-
),
|
|
5652
|
-
style: { color: percentColor },
|
|
5653
|
-
children: [
|
|
5654
|
-
Math.round(v),
|
|
5655
|
-
"%"
|
|
5656
|
-
]
|
|
5657
|
-
}
|
|
5842
|
+
|
|
5843
|
+
// src/lib/global-overlay.ts
|
|
5844
|
+
var GLOBAL_OVERLAY_ATTR = "data-s-global-overlay";
|
|
5845
|
+
var globalOverlayProps = { [GLOBAL_OVERLAY_ATTR]: "" };
|
|
5846
|
+
function isFromGlobalOverlay(event) {
|
|
5847
|
+
const detail = event.detail;
|
|
5848
|
+
const target = detail?.originalEvent?.target ?? event.target;
|
|
5849
|
+
const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
|
|
5850
|
+
return !!element?.closest(`[${GLOBAL_OVERLAY_ATTR}]`);
|
|
5851
|
+
}
|
|
5852
|
+
var SLoadingContainer = /* @__PURE__ */ react.forwardRef(
|
|
5853
|
+
function SLoadingContainer2({ open = false, message, zIndex = Z_INDEX.loading, className, style }, ref) {
|
|
5854
|
+
const [mounted2, setMounted] = react.useState(false);
|
|
5855
|
+
react.useEffect(() => setMounted(true), []);
|
|
5856
|
+
react.useEffect(() => {
|
|
5857
|
+
if (!open) return;
|
|
5858
|
+
const prev = document.body.style.overflow;
|
|
5859
|
+
document.body.style.overflow = "hidden";
|
|
5860
|
+
return () => {
|
|
5861
|
+
document.body.style.overflow = prev;
|
|
5862
|
+
};
|
|
5863
|
+
}, [open]);
|
|
5864
|
+
const innerRef = react.useRef(null);
|
|
5865
|
+
const setRef = react.useCallback(
|
|
5866
|
+
(node) => {
|
|
5867
|
+
innerRef.current = node;
|
|
5868
|
+
if (typeof ref === "function") ref(node);
|
|
5869
|
+
else if (ref) ref.current = node;
|
|
5870
|
+
},
|
|
5871
|
+
[ref]
|
|
5658
5872
|
);
|
|
5659
|
-
|
|
5873
|
+
react.useEffect(() => {
|
|
5874
|
+
const el = innerRef.current;
|
|
5875
|
+
if (!el) return;
|
|
5876
|
+
const stop = (e) => e.stopPropagation();
|
|
5877
|
+
el.addEventListener("pointerdown", stop);
|
|
5878
|
+
el.addEventListener("mousedown", stop);
|
|
5879
|
+
return () => {
|
|
5880
|
+
el.removeEventListener("pointerdown", stop);
|
|
5881
|
+
el.removeEventListener("mousedown", stop);
|
|
5882
|
+
};
|
|
5883
|
+
}, [mounted2]);
|
|
5884
|
+
const overlay = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5660
5885
|
"div",
|
|
5661
5886
|
{
|
|
5662
|
-
ref,
|
|
5887
|
+
ref: setRef,
|
|
5888
|
+
...globalOverlayProps,
|
|
5889
|
+
"aria-hidden": !open,
|
|
5663
5890
|
className: cn(
|
|
5664
|
-
"
|
|
5891
|
+
"fixed inset-0 flex items-center justify-center transition-opacity duration-200",
|
|
5892
|
+
open ? "pointer-events-auto visible opacity-100" : "pointer-events-none invisible opacity-0",
|
|
5665
5893
|
className
|
|
5666
5894
|
),
|
|
5667
|
-
style,
|
|
5668
|
-
children: [
|
|
5669
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(innerValue && "relative"), children: [
|
|
5670
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
5671
|
-
"svg",
|
|
5672
|
-
{
|
|
5673
|
-
viewBox: `0 0 ${VIEWBOX} ${VIEWBOX}`,
|
|
5674
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
5675
|
-
className: cn(
|
|
5676
|
-
"h-[80px] w-[80px]",
|
|
5677
|
-
indeterminate && "origin-center animate-circle-spin"
|
|
5678
|
-
),
|
|
5679
|
-
children: [
|
|
5680
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5681
|
-
"circle",
|
|
5682
|
-
{
|
|
5683
|
-
cx: c,
|
|
5684
|
-
cy: c,
|
|
5685
|
-
r: RADIUS,
|
|
5686
|
-
fill: "none",
|
|
5687
|
-
strokeWidth: STROKE,
|
|
5688
|
-
style: { stroke: colors.track }
|
|
5689
|
-
}
|
|
5690
|
-
),
|
|
5691
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5692
|
-
"circle",
|
|
5693
|
-
{
|
|
5694
|
-
cx: c,
|
|
5695
|
-
cy: c,
|
|
5696
|
-
r: RADIUS,
|
|
5697
|
-
fill: "none",
|
|
5698
|
-
strokeWidth: STROKE,
|
|
5699
|
-
strokeLinecap: "round",
|
|
5700
|
-
className: cn(
|
|
5701
|
-
"origin-center",
|
|
5702
|
-
indeterminate ? "animate-circle-arc" : "-rotate-90 transition-[stroke-dasharray] duration-[400ms] ease-linear"
|
|
5703
|
-
),
|
|
5704
|
-
style: {
|
|
5705
|
-
stroke: colors.arc,
|
|
5706
|
-
...indeterminate ? {} : { strokeDasharray: `${filled} ${CIRCUMFERENCE}`, strokeDashoffset: 0 }
|
|
5707
|
-
}
|
|
5708
|
-
}
|
|
5709
|
-
)
|
|
5710
|
-
]
|
|
5711
|
-
}
|
|
5712
|
-
),
|
|
5713
|
-
showPercent && innerValue && percentNode
|
|
5714
|
-
] }),
|
|
5715
|
-
showPercent && !innerValue && percentNode,
|
|
5716
|
-
label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-center text-[12px] font-normal leading-[20px] text-[color:var(--cmp-progress-color-label)]", children: label })
|
|
5717
|
-
]
|
|
5718
|
-
}
|
|
5719
|
-
);
|
|
5720
|
-
}
|
|
5721
|
-
);
|
|
5722
|
-
|
|
5723
|
-
// src/lib/global-overlay.ts
|
|
5724
|
-
var GLOBAL_OVERLAY_ATTR = "data-s-global-overlay";
|
|
5725
|
-
var globalOverlayProps = { [GLOBAL_OVERLAY_ATTR]: "" };
|
|
5726
|
-
function isFromGlobalOverlay(event) {
|
|
5727
|
-
const detail = event.detail;
|
|
5728
|
-
const target = detail?.originalEvent?.target ?? event.target;
|
|
5729
|
-
const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
|
|
5730
|
-
return !!element?.closest(`[${GLOBAL_OVERLAY_ATTR}]`);
|
|
5731
|
-
}
|
|
5732
|
-
var SLoadingContainer = /* @__PURE__ */ react.forwardRef(
|
|
5733
|
-
function SLoadingContainer2({ open = false, message, zIndex = Z_INDEX.loading, className, style }, ref) {
|
|
5734
|
-
const [mounted2, setMounted] = react.useState(false);
|
|
5735
|
-
react.useEffect(() => setMounted(true), []);
|
|
5736
|
-
react.useEffect(() => {
|
|
5737
|
-
if (!open) return;
|
|
5738
|
-
const prev = document.body.style.overflow;
|
|
5739
|
-
document.body.style.overflow = "hidden";
|
|
5740
|
-
return () => {
|
|
5741
|
-
document.body.style.overflow = prev;
|
|
5742
|
-
};
|
|
5743
|
-
}, [open]);
|
|
5744
|
-
const innerRef = react.useRef(null);
|
|
5745
|
-
const setRef = react.useCallback(
|
|
5746
|
-
(node) => {
|
|
5747
|
-
innerRef.current = node;
|
|
5748
|
-
if (typeof ref === "function") ref(node);
|
|
5749
|
-
else if (ref) ref.current = node;
|
|
5750
|
-
},
|
|
5751
|
-
[ref]
|
|
5752
|
-
);
|
|
5753
|
-
react.useEffect(() => {
|
|
5754
|
-
const el = innerRef.current;
|
|
5755
|
-
if (!el) return;
|
|
5756
|
-
const stop = (e) => e.stopPropagation();
|
|
5757
|
-
el.addEventListener("pointerdown", stop);
|
|
5758
|
-
el.addEventListener("mousedown", stop);
|
|
5759
|
-
return () => {
|
|
5760
|
-
el.removeEventListener("pointerdown", stop);
|
|
5761
|
-
el.removeEventListener("mousedown", stop);
|
|
5762
|
-
};
|
|
5763
|
-
}, [mounted2]);
|
|
5764
|
-
const overlay = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5765
|
-
"div",
|
|
5766
|
-
{
|
|
5767
|
-
ref: setRef,
|
|
5768
|
-
...globalOverlayProps,
|
|
5769
|
-
"aria-hidden": !open,
|
|
5770
|
-
className: cn(
|
|
5771
|
-
"fixed inset-0 flex items-center justify-center transition-opacity duration-200",
|
|
5772
|
-
open ? "pointer-events-auto visible opacity-100" : "pointer-events-none invisible opacity-0",
|
|
5773
|
-
className
|
|
5774
|
-
),
|
|
5775
|
-
style: { zIndex, ...style },
|
|
5895
|
+
style: { zIndex, ...style },
|
|
5776
5896
|
children: [
|
|
5777
5897
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 bg-black/40" }),
|
|
5778
5898
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex flex-col items-center gap-[16px]", children: [
|
|
@@ -5915,6 +6035,15 @@ var STextLink = /* @__PURE__ */ react.forwardRef(function STextLink2({
|
|
|
5915
6035
|
/* @__PURE__ */ jsxRuntime.jsx(RTooltip__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(RTooltip__namespace.Content, { side: "top", sideOffset: 4, className: cn("z-50", FLOATING_SLIDE_ANIM), children: /* @__PURE__ */ jsxRuntime.jsx(STag, { shape: "square", size: "xs", color: "grey", label: text }) }) })
|
|
5916
6036
|
] }) });
|
|
5917
6037
|
});
|
|
6038
|
+
|
|
6039
|
+
// src/lib/floating-width.ts
|
|
6040
|
+
var POPOVER_AVAILABLE_WIDTH = "var(--radix-popover-content-available-width)";
|
|
6041
|
+
var DROPDOWN_AVAILABLE_WIDTH = "var(--radix-dropdown-menu-content-available-width)";
|
|
6042
|
+
function clampToAvailableWidth(value, availableWidth) {
|
|
6043
|
+
if (value == null || value === "") return availableWidth;
|
|
6044
|
+
const css = typeof value === "number" ? `${value}px` : value;
|
|
6045
|
+
return `min(${css}, ${availableWidth})`;
|
|
6046
|
+
}
|
|
5918
6047
|
var SIZE2 = {
|
|
5919
6048
|
xs: { height: 24, paddingX: 8, gap: 6, arrow: 12, fontSize: 12, minWidth: 64, splitMinWidth: 72 },
|
|
5920
6049
|
sm: {
|
|
@@ -5951,6 +6080,7 @@ function splitDivider(color, outline) {
|
|
|
5951
6080
|
};
|
|
5952
6081
|
return (outline ? outlined : solid)[color];
|
|
5953
6082
|
}
|
|
6083
|
+
var VIEWPORT_PADDING = 12;
|
|
5954
6084
|
var itemClass = cn(
|
|
5955
6085
|
"flex min-h-[28px] cursor-pointer select-none items-center gap-[8px] rounded-[2px] px-[12px] py-[4px] text-[12px] leading-[20px] outline-none",
|
|
5956
6086
|
"text-[color:var(--sys-color-fg-secondary)]",
|
|
@@ -6032,12 +6162,16 @@ var SDropdownButtonImpl = /* @__PURE__ */ react.forwardRef(
|
|
|
6032
6162
|
sideOffset: 4,
|
|
6033
6163
|
align: "start",
|
|
6034
6164
|
alignOffset: split ? splitAlignOffset : 0,
|
|
6165
|
+
collisionPadding: VIEWPORT_PADDING,
|
|
6035
6166
|
className: cn(
|
|
6036
6167
|
"z-50 overflow-hidden rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] shadow-normal-sm",
|
|
6037
|
-
|
|
6168
|
+
// 창보다 넓은 메뉴는 창 폭에 맞춰 줄인다. 트리거 너비를 따르는 하한도 같은 상한으로
|
|
6169
|
+
// 감싸야 한다 — min-width 가 max-width 를 이기기 때문이다.
|
|
6170
|
+
"max-w-[var(--radix-dropdown-menu-content-available-width)]",
|
|
6171
|
+
!split && "min-w-[min(var(--radix-dropdown-menu-trigger-width),var(--radix-dropdown-menu-content-available-width))]",
|
|
6038
6172
|
FLOATING_SLIDE_ANIM
|
|
6039
6173
|
),
|
|
6040
|
-
style: split ? { minWidth: splitWidth } : void 0,
|
|
6174
|
+
style: split ? { minWidth: clampToAvailableWidth(splitWidth, DROPDOWN_AVAILABLE_WIDTH) } : void 0,
|
|
6041
6175
|
children: items.map((it) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6042
6176
|
RDropdown__namespace.Item,
|
|
6043
6177
|
{
|
|
@@ -6049,7 +6183,7 @@ var SDropdownButtonImpl = /* @__PURE__ */ react.forwardRef(
|
|
|
6049
6183
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6050
6184
|
"span",
|
|
6051
6185
|
{
|
|
6052
|
-
className: "min-w-0
|
|
6186
|
+
className: "min-w-0 break-words",
|
|
6053
6187
|
dangerouslySetInnerHTML: { __html: sanitizeInlineHtml(it.label) }
|
|
6054
6188
|
}
|
|
6055
6189
|
)
|
|
@@ -6190,10 +6324,15 @@ function SSwitch({
|
|
|
6190
6324
|
}
|
|
6191
6325
|
);
|
|
6192
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
|
+
};
|
|
6193
6331
|
function SToggle({
|
|
6194
6332
|
value = false,
|
|
6195
6333
|
label = "",
|
|
6196
6334
|
disabled = false,
|
|
6335
|
+
size = "sm",
|
|
6197
6336
|
onValueChange,
|
|
6198
6337
|
className,
|
|
6199
6338
|
style
|
|
@@ -6209,7 +6348,8 @@ function SToggle({
|
|
|
6209
6348
|
"aria-pressed": value,
|
|
6210
6349
|
onClick: () => !disabled && onValueChange?.(!value),
|
|
6211
6350
|
className: cn(
|
|
6212
|
-
"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],
|
|
6213
6353
|
disabled ? "cursor-not-allowed" : "cursor-pointer",
|
|
6214
6354
|
// 미선택(off) hover 시 파란 채움 + 흰 글자
|
|
6215
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)]",
|
|
@@ -6261,16 +6401,20 @@ function SPopover({
|
|
|
6261
6401
|
const descColor = type === "default" ? "var(--cmp-popover-default-description)" : "var(--cmp-popover-light-description)";
|
|
6262
6402
|
const leftLinkLabelClass = type === "default" ? "text-[color:var(--cmp-popover-default-subAction)]" : "text-[color:var(--cmp-popover-light-subAction)]";
|
|
6263
6403
|
const triggerNode = trigger ?? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex cursor-pointer", "aria-label": ariaLabel, children: /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: icon, size: iconSize, color }) });
|
|
6264
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6265
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6266
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6267
|
-
|
|
6404
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(RPopover9__namespace.Root, { open: actualOpen, onOpenChange: setOpen, children: [
|
|
6405
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Trigger, { asChild: true, children: triggerNode }),
|
|
6406
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6407
|
+
RPopover9__namespace.Content,
|
|
6268
6408
|
{
|
|
6269
6409
|
side: placement,
|
|
6270
6410
|
sideOffset: 8,
|
|
6271
6411
|
className: cn(
|
|
6272
6412
|
// 닫기 버튼이 항상 있으므로 우측은 close clearance(36px) 로 고정
|
|
6273
|
-
"relative z-50 flex
|
|
6413
|
+
"relative z-50 flex flex-col gap-[var(--cmp-popover-gap)] rounded-[var(--cmp-popover-radius)] py-[var(--cmp-popover-paddingY)] px-[var(--cmp-popover-paddingX)] text-[12px] leading-[20px] shadow-normal-sm",
|
|
6414
|
+
// 창보다 넓어지면 창 폭에 맞춘다. 최소 너비도 같은 상한으로 감싼다 —
|
|
6415
|
+
// min-width 가 max-width 를 이기므로 감싸지 않으면 상한이 무력화된다.
|
|
6416
|
+
"max-w-[var(--radix-popover-content-available-width)]",
|
|
6417
|
+
"min-w-[min(160px,var(--radix-popover-content-available-width))]",
|
|
6274
6418
|
FLOATING_SLIDE_ANIM,
|
|
6275
6419
|
menuClassName
|
|
6276
6420
|
),
|
|
@@ -6326,7 +6470,7 @@ function SPopover({
|
|
|
6326
6470
|
]
|
|
6327
6471
|
}
|
|
6328
6472
|
),
|
|
6329
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6473
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Arrow, { width: 16, height: 12, style: { fill: bg } })
|
|
6330
6474
|
]
|
|
6331
6475
|
}
|
|
6332
6476
|
) })
|
|
@@ -6355,8 +6499,9 @@ function SPortal({
|
|
|
6355
6499
|
ariaLabel
|
|
6356
6500
|
}) {
|
|
6357
6501
|
const portalContainer = usePortalContainer();
|
|
6502
|
+
const { minWidth: styleMinWidth, maxWidth: styleMaxWidth, ...restStyle } = style ?? {};
|
|
6358
6503
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6359
|
-
|
|
6504
|
+
RPopover9__namespace.Root,
|
|
6360
6505
|
{
|
|
6361
6506
|
open,
|
|
6362
6507
|
onOpenChange: (next) => {
|
|
@@ -6364,9 +6509,9 @@ function SPortal({
|
|
|
6364
6509
|
if (!next) onClose?.();
|
|
6365
6510
|
},
|
|
6366
6511
|
children: [
|
|
6367
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6368
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6369
|
-
|
|
6512
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Anchor, { virtualRef: anchorRef }),
|
|
6513
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6514
|
+
RPopover9__namespace.Content,
|
|
6370
6515
|
{
|
|
6371
6516
|
side: placement,
|
|
6372
6517
|
align,
|
|
@@ -6393,11 +6538,18 @@ function SPortal({
|
|
|
6393
6538
|
className: cn(
|
|
6394
6539
|
"z-50 overflow-hidden rounded-(--cmp-listBox-radius) bg-(--cmp-listBox-bg) shadow-normal-sm",
|
|
6395
6540
|
maxHeight != null && "overflow-y-auto",
|
|
6396
|
-
|
|
6541
|
+
// 앵커가 창보다 넓을 수 있는 자리(가로 스크롤 안의 트리거 등)에서도 하한이 상한을
|
|
6542
|
+
// 이기지 않도록, 앵커 너비 역시 가용 폭으로 가둔다.
|
|
6543
|
+
fit && "min-w-[min(var(--radix-popover-trigger-width),var(--radix-popover-content-available-width))]",
|
|
6397
6544
|
FLOATING_SLIDE_ANIM,
|
|
6398
6545
|
className
|
|
6399
6546
|
),
|
|
6400
|
-
style: {
|
|
6547
|
+
style: {
|
|
6548
|
+
maxHeight,
|
|
6549
|
+
...restStyle,
|
|
6550
|
+
...styleMinWidth != null ? { minWidth: clampToAvailableWidth(styleMinWidth, POPOVER_AVAILABLE_WIDTH) } : {},
|
|
6551
|
+
maxWidth: clampToAvailableWidth(styleMaxWidth, POPOVER_AVAILABLE_WIDTH)
|
|
6552
|
+
},
|
|
6401
6553
|
children
|
|
6402
6554
|
}
|
|
6403
6555
|
) })
|
|
@@ -6557,16 +6709,18 @@ function SGuide({
|
|
|
6557
6709
|
);
|
|
6558
6710
|
if (isNotion)
|
|
6559
6711
|
return /* @__PURE__ */ jsxRuntime.jsx("span", { className, style, children: trigger });
|
|
6560
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6561
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6562
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6563
|
-
|
|
6712
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(RPopover9__namespace.Root, { open, onOpenChange: setOpen, children: [
|
|
6713
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Trigger, { asChild: true, children: trigger }),
|
|
6714
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6715
|
+
RPopover9__namespace.Content,
|
|
6564
6716
|
{
|
|
6565
6717
|
side: "bottom",
|
|
6566
6718
|
align: "start",
|
|
6567
6719
|
sideOffset: 4,
|
|
6568
6720
|
className: cn(
|
|
6569
6721
|
"relative z-50 rounded-[var(--cmp-guide-contents-radius)] bg-[var(--color-white)]",
|
|
6722
|
+
// popupWidth(기본 426px)가 창보다 넓으면 창 폭에 맞춘다 — max-width 가 width 를 이긴다.
|
|
6723
|
+
"max-w-[var(--radix-popover-content-available-width)]",
|
|
6570
6724
|
FLOATING_SLIDE_ANIM
|
|
6571
6725
|
),
|
|
6572
6726
|
style: {
|
|
@@ -8639,10 +8793,10 @@ var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
|
|
|
8639
8793
|
}
|
|
8640
8794
|
),
|
|
8641
8795
|
header === "fix" && menuResizeHandle,
|
|
8642
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
8643
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8644
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8645
|
-
|
|
8796
|
+
/* @__PURE__ */ jsxRuntime.jsxs(RPopover9__namespace.Root, { open: labelTip !== null, onOpenChange: (open) => !open && setLabelTip(null), children: [
|
|
8797
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Anchor, { virtualRef: labelTipAnchorRef }),
|
|
8798
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
8799
|
+
RPopover9__namespace.Content,
|
|
8646
8800
|
{
|
|
8647
8801
|
side: "right",
|
|
8648
8802
|
sideOffset: 4,
|
|
@@ -8660,16 +8814,81 @@ var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
|
|
|
8660
8814
|
}
|
|
8661
8815
|
);
|
|
8662
8816
|
});
|
|
8817
|
+
var SPageHeader = /* @__PURE__ */ withDisplayName(
|
|
8818
|
+
react.forwardRef(function SPageHeader2({ title, subText, fix = false, onBack, slot, scrolled = false, className, style, ...rest }, ref) {
|
|
8819
|
+
const hasBack = onBack != null;
|
|
8820
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8821
|
+
"header",
|
|
8822
|
+
{
|
|
8823
|
+
ref,
|
|
8824
|
+
className: cn(
|
|
8825
|
+
"relative z-10 box-border flex shrink-0 items-center gap-(--cmp-pageHeader-gap) px-(--cmp-pageHeader-paddingX)",
|
|
8826
|
+
fix ? "h-(--cmp-pageHeader-bar-height) border-b border-(--cmp-pageHeader-bar-border) bg-(--cmp-pageHeader-bar-bg) py-(--cmp-pageHeader-bar-paddingY)" : cn(
|
|
8827
|
+
// 배경은 항상 투명 — 페이지 배경을 따라갈지는 fix 가 정하지 scrolled 가 정하지 않는다.
|
|
8828
|
+
// 스크롤되면 그림자만 더해 콘텐츠 위에 뜬 것처럼 보이게 한다.
|
|
8829
|
+
"bg-transparent pt-(--cmp-pageHeader-plain-paddingTop) pb-(--cmp-pageHeader-plain-paddingBottom)",
|
|
8830
|
+
scrolled && "shadow-floating"
|
|
8831
|
+
),
|
|
8832
|
+
className
|
|
8833
|
+
),
|
|
8834
|
+
style,
|
|
8835
|
+
...rest,
|
|
8836
|
+
children: [
|
|
8837
|
+
hasBack && /* @__PURE__ */ jsxRuntime.jsx(
|
|
8838
|
+
SGhostButton,
|
|
8839
|
+
{
|
|
8840
|
+
icon: "chevronLeft",
|
|
8841
|
+
size: "xs",
|
|
8842
|
+
ariaLabel: "\uB4A4\uB85C\uAC00\uAE30",
|
|
8843
|
+
onClick: onBack,
|
|
8844
|
+
className: "shrink-0"
|
|
8845
|
+
}
|
|
8846
|
+
),
|
|
8847
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
8848
|
+
"div",
|
|
8849
|
+
{
|
|
8850
|
+
className: cn(
|
|
8851
|
+
"flex min-w-0 flex-1 items-center",
|
|
8852
|
+
fix ? "flex-row gap-(--cmp-pageHeader-gap)" : "flex-col items-start gap-(--cmp-pageHeader-plain-title-gap)",
|
|
8853
|
+
!hasBack && "pl-(--cmp-pageHeader-title-paddingLeft)"
|
|
8854
|
+
),
|
|
8855
|
+
children: [
|
|
8856
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "typo-heading-lg min-w-0 truncate text-(--cmp-pageHeader-title-text)", children: title }),
|
|
8857
|
+
subText && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "typo-body-md-default min-w-0 truncate text-(--cmp-pageHeader-subtitle-text)", children: subText })
|
|
8858
|
+
]
|
|
8859
|
+
}
|
|
8860
|
+
),
|
|
8861
|
+
slot && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-auto flex shrink-0 items-center", children: slot })
|
|
8862
|
+
]
|
|
8863
|
+
}
|
|
8864
|
+
);
|
|
8865
|
+
}),
|
|
8866
|
+
"SPageHeader"
|
|
8867
|
+
);
|
|
8663
8868
|
var MIN_CONTENT_WIDTH = `calc(var(${SLAYOUT_MIN_WIDTH_VAR}, 0px) - 100cqw + 100%)`;
|
|
8664
8869
|
var BACKGROUND_CLASS = {
|
|
8665
8870
|
frame: `bg-[var(--sys-color-bg-frame)] ${SCROLLBAR_TRACK_BORDER_CLASS} ${SCROLLBAR_TRACK_BG_CLASS}`,
|
|
8666
8871
|
neutral: `bg-[var(--sys-color-bg-neutralLight)] ${SCROLLBAR_TRACK_BORDER_CLASS} ${SCROLLBAR_TRACK_BG_WHITE_CLASS}`,
|
|
8667
8872
|
screen: `bg-[var(--sys-color-bg-screen)] ${SCROLLBAR_TRACK_BORDER_CLASS} ${SCROLLBAR_TRACK_BG_CLASS}`
|
|
8668
8873
|
};
|
|
8669
|
-
var SPage = /* @__PURE__ */ react.forwardRef(function SPage2({
|
|
8874
|
+
var SPage = /* @__PURE__ */ react.forwardRef(function SPage2({
|
|
8875
|
+
background = "frame",
|
|
8876
|
+
scrollEndSpacing = true,
|
|
8877
|
+
header,
|
|
8878
|
+
className,
|
|
8879
|
+
style,
|
|
8880
|
+
children,
|
|
8881
|
+
onScroll,
|
|
8882
|
+
...rest
|
|
8883
|
+
}, ref) {
|
|
8670
8884
|
const layout = react.useContext(SLayoutContext);
|
|
8671
8885
|
const gridStyle = layout?.header === "full" ? { gridArea: "page" } : void 0;
|
|
8672
|
-
|
|
8886
|
+
const [scrolled, setScrolled] = react.useState(false);
|
|
8887
|
+
const handleScroll = (e) => {
|
|
8888
|
+
onScroll?.(e);
|
|
8889
|
+
if (header != null && !header.fix) setScrolled(e.currentTarget.scrollTop > 0);
|
|
8890
|
+
};
|
|
8891
|
+
const main = /* @__PURE__ */ jsxRuntime.jsx(
|
|
8673
8892
|
"main",
|
|
8674
8893
|
{
|
|
8675
8894
|
ref,
|
|
@@ -8680,11 +8899,29 @@ var SPage = /* @__PURE__ */ react.forwardRef(function SPage2({ background = "fra
|
|
|
8680
8899
|
BACKGROUND_CLASS[background],
|
|
8681
8900
|
className
|
|
8682
8901
|
),
|
|
8683
|
-
style: { ...gridStyle, ...style },
|
|
8902
|
+
style: header == null ? { ...gridStyle, ...style } : style,
|
|
8903
|
+
onScroll: handleScroll,
|
|
8684
8904
|
...rest,
|
|
8685
8905
|
children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { minWidth: MIN_CONTENT_WIDTH }, children })
|
|
8686
8906
|
}
|
|
8687
8907
|
);
|
|
8908
|
+
if (header == null) return main;
|
|
8909
|
+
return (
|
|
8910
|
+
// fix 가 아닌 헤더는 자기 배경이 투명이라(SPageHeader.tsx) 이 배경이 그대로 비친다 —
|
|
8911
|
+
// 그래서 SPage 의 background 를 main 뿐 아니라 여기에도 칠한다(스크롤바 관련 클래스는
|
|
8912
|
+
// 스크롤 요소가 아닌 여기서는 그냥 무시된다). fix 헤더는 자체 흰 배경이 덮으므로 무관하다.
|
|
8913
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
8914
|
+
"div",
|
|
8915
|
+
{
|
|
8916
|
+
className: cn("flex min-h-0 min-w-0 flex-1 flex-col", BACKGROUND_CLASS[background]),
|
|
8917
|
+
style: gridStyle,
|
|
8918
|
+
children: [
|
|
8919
|
+
/* @__PURE__ */ jsxRuntime.jsx(SPageHeader, { ...header, scrolled }),
|
|
8920
|
+
main
|
|
8921
|
+
]
|
|
8922
|
+
}
|
|
8923
|
+
)
|
|
8924
|
+
);
|
|
8688
8925
|
});
|
|
8689
8926
|
|
|
8690
8927
|
// src/components/SPage/page.config.ts
|
|
@@ -11058,7 +11295,7 @@ var SInput = /* @__PURE__ */ react.forwardRef(function SInput2({
|
|
|
11058
11295
|
lineHeight: `${f.lineHeight}px`
|
|
11059
11296
|
},
|
|
11060
11297
|
children: [
|
|
11061
|
-
prefix != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", children: prefix }),
|
|
11298
|
+
prefix != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex flex-shrink-0 items-center", children: prefix }),
|
|
11062
11299
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11063
11300
|
"input",
|
|
11064
11301
|
{
|
|
@@ -11090,7 +11327,7 @@ var SInput = /* @__PURE__ */ react.forwardRef(function SInput2({
|
|
|
11090
11327
|
...rest
|
|
11091
11328
|
}
|
|
11092
11329
|
),
|
|
11093
|
-
suffix != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", children: suffix }),
|
|
11330
|
+
suffix != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex flex-shrink-0 items-center", children: suffix }),
|
|
11094
11331
|
clearable && hasValue && !disabled && !readOnly && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11095
11332
|
SGhostButton,
|
|
11096
11333
|
{
|
|
@@ -11988,8 +12225,8 @@ function SDatePicker({
|
|
|
11988
12225
|
disabled,
|
|
11989
12226
|
className,
|
|
11990
12227
|
style,
|
|
11991
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11992
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12228
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(RPopover9__namespace.Root, { open, onOpenChange: (o) => !disabled && setOpen(o), children: [
|
|
12229
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11993
12230
|
"button",
|
|
11994
12231
|
{
|
|
11995
12232
|
type: "button",
|
|
@@ -12025,13 +12262,16 @@ function SDatePicker({
|
|
|
12025
12262
|
]
|
|
12026
12263
|
}
|
|
12027
12264
|
) }),
|
|
12028
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12029
|
-
|
|
12265
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12266
|
+
RPopover9__namespace.Content,
|
|
12030
12267
|
{
|
|
12031
12268
|
side: "bottom",
|
|
12032
12269
|
align: "start",
|
|
12033
12270
|
sideOffset: 4,
|
|
12034
|
-
className: cn(
|
|
12271
|
+
className: cn(
|
|
12272
|
+
"z-50 max-w-[var(--radix-popover-content-available-width)]",
|
|
12273
|
+
FLOATING_SLIDE_ANIM
|
|
12274
|
+
),
|
|
12035
12275
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12036
12276
|
SCalendar,
|
|
12037
12277
|
{
|
|
@@ -12179,78 +12419,81 @@ function RangeCalendar({
|
|
|
12179
12419
|
}
|
|
12180
12420
|
};
|
|
12181
12421
|
const GRID_COLS = "grid grid-cols-[repeat(7,var(--cmp-datepicker-calendar-day-width))]";
|
|
12182
|
-
const renderPanel = (gy, gm, isLeft) =>
|
|
12183
|
-
|
|
12184
|
-
|
|
12185
|
-
|
|
12186
|
-
|
|
12187
|
-
|
|
12188
|
-
|
|
12189
|
-
|
|
12190
|
-
|
|
12191
|
-
|
|
12192
|
-
|
|
12193
|
-
|
|
12194
|
-
|
|
12195
|
-
|
|
12196
|
-
|
|
12197
|
-
|
|
12422
|
+
const renderPanel = (gy, gm, isLeft) => (
|
|
12423
|
+
// 좁은 창에서 눌려 격자가 깨지지 않도록, 줄이는 대신 부모가 가로 스크롤하게 둔다.
|
|
12424
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 flex-col gap-[var(--cmp-datepicker-calendar-gap)]", children: [
|
|
12425
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-center gap-[var(--cmp-datepicker-calendar-gap)]", children: [
|
|
12426
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12427
|
+
SGhostButton,
|
|
12428
|
+
{
|
|
12429
|
+
icon: "chevronLeft",
|
|
12430
|
+
size: "xxs",
|
|
12431
|
+
ariaLabel: "prevMonth",
|
|
12432
|
+
onClick: goPrevMonth,
|
|
12433
|
+
className: cn(!isLeft && "invisible pointer-events-none")
|
|
12434
|
+
}
|
|
12435
|
+
),
|
|
12436
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex min-w-[40px] flex-1 items-center justify-center text-center text-[14px] font-medium leading-[24px]", children: [
|
|
12437
|
+
gy,
|
|
12438
|
+
".",
|
|
12439
|
+
String(gm).padStart(2, "0")
|
|
12440
|
+
] }),
|
|
12441
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12442
|
+
SGhostButton,
|
|
12443
|
+
{
|
|
12444
|
+
icon: "chevronRight",
|
|
12445
|
+
size: "xxs",
|
|
12446
|
+
ariaLabel: "nextMonth",
|
|
12447
|
+
onClick: goNextMonth,
|
|
12448
|
+
className: cn(isLeft && "invisible pointer-events-none")
|
|
12449
|
+
}
|
|
12450
|
+
)
|
|
12198
12451
|
] }),
|
|
12199
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12200
|
-
|
|
12201
|
-
{
|
|
12202
|
-
icon: "chevronRight",
|
|
12203
|
-
size: "xxs",
|
|
12204
|
-
ariaLabel: "nextMonth",
|
|
12205
|
-
onClick: goNextMonth,
|
|
12206
|
-
className: cn(isLeft && "invisible pointer-events-none")
|
|
12207
|
-
}
|
|
12208
|
-
)
|
|
12209
|
-
] }),
|
|
12210
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: GRID_COLS, children: WEEK_LABELS.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
12211
|
-
"span",
|
|
12212
|
-
{
|
|
12213
|
-
className: "flex h-[20px] items-center justify-center text-[12px] font-normal text-[color:var(--cmp-datepicker-calendar-week-color)]",
|
|
12214
|
-
children: l
|
|
12215
|
-
},
|
|
12216
|
-
l
|
|
12217
|
-
)) }),
|
|
12218
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(GRID_COLS, "gap-y-[var(--cmp-datepicker-calendar-grid-rowGap)]"), children: monthCells(gy, gm).map((cell) => {
|
|
12219
|
-
const isEdge = cell.inCurrentMonth && (cell.date === rStart || complete && cell.date === rEnd);
|
|
12220
|
-
const between = cell.inCurrentMonth && inRange(cell.date);
|
|
12221
|
-
const disabled = cell.inCurrentMonth && isDisabled(cell.date);
|
|
12222
|
-
const isToday = cell.inCurrentMonth && today === cell.date;
|
|
12223
|
-
let cellBg;
|
|
12224
|
-
if (between) cellBg = RANGE_BG;
|
|
12225
|
-
else if (cell.inCurrentMonth && hasRange && cell.date === rStart)
|
|
12226
|
-
cellBg = `linear-gradient(to right, transparent 50%, ${RANGE_BG} 50%)`;
|
|
12227
|
-
else if (cell.inCurrentMonth && hasRange && cell.date === rEnd) cellBg = RANGE_BG;
|
|
12228
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
12229
|
-
"div",
|
|
12452
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: GRID_COLS, children: WEEK_LABELS.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
12453
|
+
"span",
|
|
12230
12454
|
{
|
|
12231
|
-
className: "flex h-[
|
|
12232
|
-
|
|
12233
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12234
|
-
"button",
|
|
12235
|
-
{
|
|
12236
|
-
type: "button",
|
|
12237
|
-
disabled: !cell.inCurrentMonth || disabled,
|
|
12238
|
-
onMouseEnter: () => setHover(cell.date),
|
|
12239
|
-
onClick: () => cell.inCurrentMonth && click(cell.date),
|
|
12240
|
-
className: cn(
|
|
12241
|
-
"relative z-[1] 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 bg-transparent text-[14px]",
|
|
12242
|
-
!cell.inCurrentMonth ? "invisible pointer-events-none" : disabled ? "cursor-not-allowed" : "cursor-pointer",
|
|
12243
|
-
isEdge ? "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)] hover:text-[color:var(--cmp-datepicker-calendar-day-hover-text)]",
|
|
12244
|
-
isToday && !disabled && "font-bold"
|
|
12245
|
-
),
|
|
12246
|
-
children: cell.inCurrentMonth ? cell.day : ""
|
|
12247
|
-
}
|
|
12248
|
-
)
|
|
12455
|
+
className: "flex h-[20px] items-center justify-center text-[12px] font-normal text-[color:var(--cmp-datepicker-calendar-week-color)]",
|
|
12456
|
+
children: l
|
|
12249
12457
|
},
|
|
12250
|
-
|
|
12251
|
-
)
|
|
12252
|
-
|
|
12253
|
-
|
|
12458
|
+
l
|
|
12459
|
+
)) }),
|
|
12460
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(GRID_COLS, "gap-y-[var(--cmp-datepicker-calendar-grid-rowGap)]"), children: monthCells(gy, gm).map((cell) => {
|
|
12461
|
+
const isEdge = cell.inCurrentMonth && (cell.date === rStart || complete && cell.date === rEnd);
|
|
12462
|
+
const between = cell.inCurrentMonth && inRange(cell.date);
|
|
12463
|
+
const disabled = cell.inCurrentMonth && isDisabled(cell.date);
|
|
12464
|
+
const isToday = cell.inCurrentMonth && today === cell.date;
|
|
12465
|
+
let cellBg;
|
|
12466
|
+
if (between) cellBg = RANGE_BG;
|
|
12467
|
+
else if (cell.inCurrentMonth && hasRange && cell.date === rStart)
|
|
12468
|
+
cellBg = `linear-gradient(to right, transparent 50%, ${RANGE_BG} 50%)`;
|
|
12469
|
+
else if (cell.inCurrentMonth && hasRange && cell.date === rEnd) cellBg = RANGE_BG;
|
|
12470
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
12471
|
+
"div",
|
|
12472
|
+
{
|
|
12473
|
+
className: "flex h-[var(--cmp-datepicker-calendar-range-height)] w-[var(--cmp-datepicker-calendar-day-width)] items-center justify-center",
|
|
12474
|
+
style: { background: cellBg },
|
|
12475
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12476
|
+
"button",
|
|
12477
|
+
{
|
|
12478
|
+
type: "button",
|
|
12479
|
+
disabled: !cell.inCurrentMonth || disabled,
|
|
12480
|
+
onMouseEnter: () => setHover(cell.date),
|
|
12481
|
+
onClick: () => cell.inCurrentMonth && click(cell.date),
|
|
12482
|
+
className: cn(
|
|
12483
|
+
"relative z-[1] 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 bg-transparent text-[14px]",
|
|
12484
|
+
!cell.inCurrentMonth ? "invisible pointer-events-none" : disabled ? "cursor-not-allowed" : "cursor-pointer",
|
|
12485
|
+
isEdge ? "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)] hover:text-[color:var(--cmp-datepicker-calendar-day-hover-text)]",
|
|
12486
|
+
isToday && !disabled && "font-bold"
|
|
12487
|
+
),
|
|
12488
|
+
children: cell.inCurrentMonth ? cell.day : ""
|
|
12489
|
+
}
|
|
12490
|
+
)
|
|
12491
|
+
},
|
|
12492
|
+
cell.date
|
|
12493
|
+
);
|
|
12494
|
+
}) })
|
|
12495
|
+
] })
|
|
12496
|
+
);
|
|
12254
12497
|
const renderTimeSection = (which, date, suffix) => {
|
|
12255
12498
|
const active = !!date;
|
|
12256
12499
|
const [yy = "", mm = "", dd = ""] = date ? date.split("-") : [];
|
|
@@ -12318,8 +12561,11 @@ function RangeCalendar({
|
|
|
12318
12561
|
"div",
|
|
12319
12562
|
{
|
|
12320
12563
|
className: cn(
|
|
12321
|
-
"inline-flex flex-col gap-[var(--cmp-datepicker-calendar-gap)] rounded-[var(--cmp-datepicker-calendar-radius)] bg-[var(--cmp-datepicker-calendar-bg)] p-[var(--cmp-datepicker-calendar-paddingXY)] shadow-[2px_2px_12px_2px_rgba(0,0,0,0.2)] select-none",
|
|
12322
|
-
|
|
12564
|
+
"inline-flex max-w-full flex-col gap-[var(--cmp-datepicker-calendar-gap)] rounded-[var(--cmp-datepicker-calendar-radius)] bg-[var(--cmp-datepicker-calendar-bg)] p-[var(--cmp-datepicker-calendar-paddingXY)] shadow-[2px_2px_12px_2px_rgba(0,0,0,0.2)] select-none",
|
|
12565
|
+
// 높이는 고정이 아니라 하한이다 — 5주/6주 달을 오갈 때의 높이 흔들림만 막으면 되고,
|
|
12566
|
+
// 창이 좁아 패널이 가로 스크롤될 때는 스크롤바 높이만큼 늘어날 수 있어야 한다.
|
|
12567
|
+
// (단일 달 SCalendar 도 min-h 를 쓴다)
|
|
12568
|
+
useTimePicker ? "h-auto" : "min-h-[364px]"
|
|
12323
12569
|
),
|
|
12324
12570
|
children: [
|
|
12325
12571
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex items-center justify-center", children: [
|
|
@@ -12338,11 +12584,20 @@ function RangeCalendar({
|
|
|
12338
12584
|
}
|
|
12339
12585
|
)
|
|
12340
12586
|
] }),
|
|
12341
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
12342
|
-
|
|
12343
|
-
|
|
12344
|
-
|
|
12345
|
-
|
|
12587
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
12588
|
+
"div",
|
|
12589
|
+
{
|
|
12590
|
+
className: cn(
|
|
12591
|
+
"flex max-w-full gap-[var(--cmp-datepicker-calendar-range-panelGap)] overflow-x-auto",
|
|
12592
|
+
SCROLLBAR_CLASS
|
|
12593
|
+
),
|
|
12594
|
+
children: [
|
|
12595
|
+
renderPanel(y, m, true),
|
|
12596
|
+
/* @__PURE__ */ jsxRuntime.jsx(SDivider, { vertical: true }),
|
|
12597
|
+
renderPanel(nextMonthYM.year, nextMonthYM.month, false)
|
|
12598
|
+
]
|
|
12599
|
+
}
|
|
12600
|
+
),
|
|
12346
12601
|
useTimePicker && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
12347
12602
|
/* @__PURE__ */ jsxRuntime.jsx(SDivider, {}),
|
|
12348
12603
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-[var(--cmp-datepicker-calendar-time-gap)]", children: [
|
|
@@ -12401,7 +12656,25 @@ function SDateRangePicker({
|
|
|
12401
12656
|
});
|
|
12402
12657
|
const resolvedError = error || ruleError !== "";
|
|
12403
12658
|
const resolvedStatus = status ?? (rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0);
|
|
12404
|
-
const dims = size === "md" ? {
|
|
12659
|
+
const dims = size === "md" ? {
|
|
12660
|
+
padX: 16,
|
|
12661
|
+
gap: 12,
|
|
12662
|
+
icon: 20,
|
|
12663
|
+
minW: 104,
|
|
12664
|
+
fieldMinW: 260,
|
|
12665
|
+
fontSize: 14,
|
|
12666
|
+
lineHeight: 24,
|
|
12667
|
+
radius: 6
|
|
12668
|
+
} : {
|
|
12669
|
+
padX: 12,
|
|
12670
|
+
gap: 8,
|
|
12671
|
+
icon: 16,
|
|
12672
|
+
minW: 80,
|
|
12673
|
+
fieldMinW: 216,
|
|
12674
|
+
fontSize: 12,
|
|
12675
|
+
lineHeight: 20,
|
|
12676
|
+
radius: 4
|
|
12677
|
+
};
|
|
12405
12678
|
const select = (r) => {
|
|
12406
12679
|
setPendingStart(null);
|
|
12407
12680
|
onValueChange?.(r);
|
|
@@ -12427,11 +12700,12 @@ function SDateRangePicker({
|
|
|
12427
12700
|
focused: open,
|
|
12428
12701
|
errorMessage: ruleError !== "" ? ruleError : errorMessage,
|
|
12429
12702
|
width,
|
|
12703
|
+
minWidth: dims.fieldMinW,
|
|
12430
12704
|
disabled,
|
|
12431
12705
|
className,
|
|
12432
12706
|
style,
|
|
12433
12707
|
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12434
|
-
|
|
12708
|
+
RPopover9__namespace.Root,
|
|
12435
12709
|
{
|
|
12436
12710
|
open,
|
|
12437
12711
|
onOpenChange: (o) => {
|
|
@@ -12440,7 +12714,7 @@ function SDateRangePicker({
|
|
|
12440
12714
|
if (!o) setPendingStart(null);
|
|
12441
12715
|
},
|
|
12442
12716
|
children: [
|
|
12443
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12717
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12444
12718
|
"button",
|
|
12445
12719
|
{
|
|
12446
12720
|
type: "button",
|
|
@@ -12481,13 +12755,16 @@ function SDateRangePicker({
|
|
|
12481
12755
|
]
|
|
12482
12756
|
}
|
|
12483
12757
|
) }),
|
|
12484
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12485
|
-
|
|
12758
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12759
|
+
RPopover9__namespace.Content,
|
|
12486
12760
|
{
|
|
12487
12761
|
side: "bottom",
|
|
12488
12762
|
align: "start",
|
|
12489
12763
|
sideOffset: 4,
|
|
12490
|
-
className: cn(
|
|
12764
|
+
className: cn(
|
|
12765
|
+
"z-50 max-w-[var(--radix-popover-content-available-width)]",
|
|
12766
|
+
FLOATING_SLIDE_ANIM
|
|
12767
|
+
),
|
|
12491
12768
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12492
12769
|
RangeCalendar,
|
|
12493
12770
|
{
|
|
@@ -13475,7 +13752,7 @@ function SRadioButton({
|
|
|
13475
13752
|
disabled: od,
|
|
13476
13753
|
onClick: () => !od && !selected && onValueChange?.(o.value),
|
|
13477
13754
|
className: cn(
|
|
13478
|
-
"relative box-border inline-flex items-center justify-center whitespace-nowrap border border-solid text-[12px] font-medium leading-[20px] transition-colors",
|
|
13755
|
+
"relative box-border grow inline-flex items-center justify-center whitespace-nowrap border border-solid text-[12px] font-medium leading-[20px] transition-colors",
|
|
13479
13756
|
i === 0 ? "rounded-l-[var(--cmp-radioButton-radius)]" : "-ml-px",
|
|
13480
13757
|
i === options.length - 1 ? "rounded-r-[var(--cmp-radioButton-radius)]" : "",
|
|
13481
13758
|
selected ? "z-10" : "",
|
|
@@ -13497,12 +13774,1236 @@ function SRadioButton({
|
|
|
13497
13774
|
}
|
|
13498
13775
|
);
|
|
13499
13776
|
}
|
|
13500
|
-
var
|
|
13501
|
-
|
|
13777
|
+
var CHIPFILTER_LISTBOX_WIDTH = 240;
|
|
13778
|
+
var CHIPFILTER_DATE_PRESET_LISTBOX_WIDTH = 246;
|
|
13779
|
+
var CHIPFILTER = {
|
|
13780
|
+
barBg: "var(--cmp-chipFilter-bar-bg)",
|
|
13781
|
+
barBorder: "var(--cmp-chipFilter-bar-border)",
|
|
13782
|
+
barPaddingX: "var(--cmp-chipFilter-bar-paddingX)",
|
|
13783
|
+
barPaddingY: "var(--cmp-chipFilter-bar-paddingY)",
|
|
13784
|
+
barGap: "var(--cmp-chipFilter-bar-gap)",
|
|
13785
|
+
dividerHeight: "var(--cmp-chipFilter-divider-height)",
|
|
13786
|
+
chipHeight: "var(--cmp-chipFilter-chip-height)",
|
|
13787
|
+
chipRadius: "var(--cmp-chipFilter-chip-radius)",
|
|
13788
|
+
chipGap: "var(--cmp-chipFilter-chip-gap)",
|
|
13789
|
+
chipDefaultBg: "var(--cmp-chipFilter-chip-default-bg)",
|
|
13790
|
+
chipDefaultBorder: "var(--cmp-chipFilter-chip-default-border)",
|
|
13791
|
+
chipDefaultText: "var(--cmp-chipFilter-chip-default-text)",
|
|
13792
|
+
chipActiveBorder: "var(--cmp-chipFilter-chip-active-border)",
|
|
13793
|
+
chipWarningBorder: "var(--cmp-chipFilter-chip-warning-border)",
|
|
13794
|
+
chipAppliedBg: "var(--cmp-chipFilter-chip-applied-bg)",
|
|
13795
|
+
chipAppliedBorder: "var(--cmp-chipFilter-chip-applied-border)",
|
|
13796
|
+
chipAppliedLabel: "var(--cmp-chipFilter-chip-applied-text-label)",
|
|
13797
|
+
chipAppliedValue: "var(--color-brilliantblue-80)",
|
|
13798
|
+
chipDisabledBg: "var(--cmp-chipFilter-chip-disabled-bg)",
|
|
13799
|
+
chipDisabledBorder: "var(--cmp-chipFilter-chip-disabled-border)",
|
|
13800
|
+
chipDisabledText: "var(--cmp-chipFilter-chip-disabled-text)",
|
|
13801
|
+
addBorder: "var(--cmp-chipFilter-addButton-border-default)",
|
|
13802
|
+
addBorderDisabled: "var(--cmp-chipFilter-addButton-border-disabled)",
|
|
13803
|
+
addText: "var(--cmp-chipFilter-addButton-text-default)",
|
|
13804
|
+
addTextDisabled: "var(--cmp-chipFilter-addButton-text-disabled)",
|
|
13805
|
+
listboxBg: "var(--cmp-chipFilter-listbox-bg)",
|
|
13806
|
+
listboxBorder: "var(--cmp-chipFilter-listbox-border-color)",
|
|
13807
|
+
listboxRadius: "var(--cmp-chipFilter-listbox-radius)",
|
|
13808
|
+
listboxLabel: "var(--cmp-chipFilter-listbox-top-label-color)",
|
|
13809
|
+
listboxBottomDividerHeight: "var(--cmp-chipFilter-listbox-bottom-divider-height)",
|
|
13810
|
+
itemPaddingLeft: "var(--cmp-chipFilter-item-paddingLeft)",
|
|
13811
|
+
itemPaddingRight: "var(--cmp-chipFilter-item-paddingRight)",
|
|
13812
|
+
itemPaddingY: "var(--cmp-chipFilter-item-paddingY)",
|
|
13813
|
+
itemMultiPaddingX: "var(--cmp-chipFilter-item-multi-paddingX)",
|
|
13814
|
+
itemTextDefault: "var(--cmp-chipFilter-item-text-default)",
|
|
13815
|
+
itemTextSelected: "var(--cmp-chipFilter-item-text-selected)"
|
|
13816
|
+
};
|
|
13817
|
+
var isKeywordValue = (value) => typeof value === "object" && value != null && !Array.isArray(value) && "keywords" in value;
|
|
13818
|
+
var keywordEntries = (value) => {
|
|
13819
|
+
if (isKeywordValue(value)) return value.keywords;
|
|
13820
|
+
if (Array.isArray(value)) {
|
|
13821
|
+
return value.filter((v) => typeof v === "string");
|
|
13822
|
+
}
|
|
13823
|
+
return [];
|
|
13824
|
+
};
|
|
13825
|
+
var isEmptyValue = (value) => {
|
|
13826
|
+
if (value == null) return true;
|
|
13827
|
+
if (Array.isArray(value)) return value.length === 0 || value.every((v) => v == null || v === "");
|
|
13828
|
+
if (isKeywordValue(value)) return value.keywords.length === 0;
|
|
13829
|
+
return value === "";
|
|
13830
|
+
};
|
|
13831
|
+
var normalizeValues = (value) => value ?? {};
|
|
13832
|
+
var toArrayValue = (value) => Array.isArray(value) ? value.filter(
|
|
13833
|
+
(v) => typeof v === "string" || typeof v === "number"
|
|
13834
|
+
) : [];
|
|
13835
|
+
var todayIso = () => {
|
|
13836
|
+
const d = /* @__PURE__ */ new Date();
|
|
13837
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
13838
|
+
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
|
13839
|
+
};
|
|
13840
|
+
var isInlineDateField = (field) => field.type === "date" && field.radioButton === true && (field.presets?.length ?? 0) > 0;
|
|
13841
|
+
var resolveFieldDefault = (field) => {
|
|
13842
|
+
if (field.defaultValue !== void 0) return field.defaultValue;
|
|
13843
|
+
if (isInlineDateField(field)) return todayIso();
|
|
13844
|
+
if (!field.required) return void 0;
|
|
13845
|
+
if (field.type === "single") return field.options?.[0]?.value;
|
|
13846
|
+
if (field.type === "date") return todayIso();
|
|
13847
|
+
return void 0;
|
|
13848
|
+
};
|
|
13849
|
+
var valuesEqual = (a, b) => {
|
|
13850
|
+
if (isKeywordValue(a) || isKeywordValue(b)) {
|
|
13851
|
+
return isKeywordValue(a) && isKeywordValue(b) && a.mode === b.mode && valuesEqual(a.keywords, b.keywords);
|
|
13852
|
+
}
|
|
13853
|
+
if (Array.isArray(a) || Array.isArray(b)) {
|
|
13854
|
+
return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((v, i) => v === b[i]);
|
|
13855
|
+
}
|
|
13856
|
+
return a === b;
|
|
13857
|
+
};
|
|
13858
|
+
var valuesMapEqual = (a, b) => {
|
|
13859
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)]);
|
|
13860
|
+
for (const key of keys) {
|
|
13861
|
+
if (!valuesEqual(a[key], b[key])) return false;
|
|
13862
|
+
}
|
|
13863
|
+
return true;
|
|
13864
|
+
};
|
|
13865
|
+
var isAtDefaultValue = (field, value) => {
|
|
13866
|
+
const def = resolveFieldDefault(field);
|
|
13867
|
+
return def !== void 0 && valuesEqual(value, def);
|
|
13868
|
+
};
|
|
13869
|
+
var isInlineField = (field) => isInlineDateField(field) || field.type === "custom";
|
|
13870
|
+
var isGroupedFields = (fields) => fields.length > 0 && "fields" in fields[0];
|
|
13871
|
+
var isGroupSatisfied = (group, values) => {
|
|
13872
|
+
if (!group.rule) return true;
|
|
13873
|
+
const keys = group.fields.map((f) => f.key);
|
|
13874
|
+
if (group.rule.type === "requireKey") return !isEmptyValue(values[group.rule.key]);
|
|
13875
|
+
if (group.rule.type === "requireAll") return keys.every((k) => !isEmptyValue(values[k]));
|
|
13876
|
+
if (group.rule.type === "requireAny") return keys.some((k) => !isEmptyValue(values[k]));
|
|
13877
|
+
return true;
|
|
13878
|
+
};
|
|
13879
|
+
var koreanParticle = (word, consonant, vowel) => {
|
|
13880
|
+
const code = word.charCodeAt(word.length - 1);
|
|
13881
|
+
if (code < 44032 || code > 55203) return consonant;
|
|
13882
|
+
return (code - 44032) % 28 === 0 ? vowel : consonant;
|
|
13883
|
+
};
|
|
13884
|
+
var defaultGroupTooltipMessage = (rule, fields) => {
|
|
13885
|
+
if (rule.type === "requireAll") return "\uD56D\uBAA9\uC744 \uBAA8\uB450 \uC120\uD0DD\uD574 \uC8FC\uC138\uC694.";
|
|
13886
|
+
if (rule.type === "requireAny") {
|
|
13887
|
+
const name = rule.dataGroupName;
|
|
13888
|
+
if (!name) return "\uCD5C\uC18C 1\uAC1C\uC758 \uD544\uD130\uB97C \uC120\uD0DD\uD574\uC8FC\uC138\uC694.";
|
|
13889
|
+
return `\uCD5C\uC18C 1\uAC1C\uC758 ${name}${koreanParticle(name, "\uC744", "\uB97C")} \uC120\uD0DD\uD574\uC8FC\uC138\uC694.`;
|
|
13890
|
+
}
|
|
13891
|
+
const label = fields.find((f) => f.key === rule.key)?.label ?? "\uD56D\uBAA9";
|
|
13892
|
+
return `${label}${koreanParticle(label, "\uC744", "\uB97C")} \uC120\uD0DD\uD574 \uC8FC\uC138\uC694.`;
|
|
13893
|
+
};
|
|
13894
|
+
var matchPresetId = (presets, value) => {
|
|
13895
|
+
if (isEmptyValue(value)) return null;
|
|
13896
|
+
for (const preset of presets) {
|
|
13897
|
+
if (preset.custom || !preset.resolve) continue;
|
|
13898
|
+
const resolved = preset.resolve();
|
|
13899
|
+
if (Array.isArray(resolved) && Array.isArray(value)) {
|
|
13900
|
+
if (resolved[0] === value[0] && resolved[1] === value[1]) return preset.value;
|
|
13901
|
+
} else if (!Array.isArray(resolved) && !Array.isArray(value) && resolved === value) {
|
|
13902
|
+
return preset.value;
|
|
13903
|
+
}
|
|
13904
|
+
}
|
|
13905
|
+
return presets.find((preset) => preset.custom)?.value ?? null;
|
|
13906
|
+
};
|
|
13907
|
+
var optionLabel = (field, value) => field.options?.find((option) => option.value === value)?.label ?? String(value);
|
|
13908
|
+
var formatValueList = (labels) => {
|
|
13909
|
+
if (labels.length <= 1) return labels[0] ?? "";
|
|
13910
|
+
return `${labels[0]} \uC678 ${labels.length - 1}\uAC1C`;
|
|
13911
|
+
};
|
|
13912
|
+
var displayValue = (field, value) => {
|
|
13913
|
+
if (isEmptyValue(value)) return "";
|
|
13914
|
+
if (field.type === "multi")
|
|
13915
|
+
return formatValueList(toArrayValue(value).map((v) => optionLabel(field, v)));
|
|
13916
|
+
if (field.type === "single") return optionLabel(field, value);
|
|
13917
|
+
if (field.type === "date")
|
|
13918
|
+
return Array.isArray(value) ? `${value[0]} ~ ${value[1]}` : String(value);
|
|
13919
|
+
if (field.type === "keyword") return formatValueList(keywordEntries(value));
|
|
13920
|
+
return String(value);
|
|
13921
|
+
};
|
|
13922
|
+
var chipDisplayValue = (field, value) => {
|
|
13923
|
+
const text = displayValue(field, value);
|
|
13924
|
+
if (field.type !== "date" || isEmptyValue(value)) return text;
|
|
13925
|
+
const presets = field.presets ?? [];
|
|
13926
|
+
if (presets.length === 0) return text;
|
|
13927
|
+
const preset = presets.find((p) => p.value === matchPresetId(presets, value));
|
|
13928
|
+
return preset && !preset.custom ? `${preset.label}(${text})` : text;
|
|
13929
|
+
};
|
|
13930
|
+
var SChipFilter = /* @__PURE__ */ react.forwardRef(function SChipFilter2({
|
|
13931
|
+
fields: fieldsProp = [],
|
|
13932
|
+
value,
|
|
13502
13933
|
onValueChange,
|
|
13503
|
-
|
|
13504
|
-
|
|
13505
|
-
|
|
13934
|
+
onFilterChange,
|
|
13935
|
+
onSearch,
|
|
13936
|
+
activeKeys,
|
|
13937
|
+
onActiveKeysChange,
|
|
13938
|
+
onReset,
|
|
13939
|
+
onAddFilter,
|
|
13940
|
+
label = "\uAC80\uC0C9 \uD544\uD130",
|
|
13941
|
+
showLabel = false,
|
|
13942
|
+
showAddButton = true,
|
|
13943
|
+
showReset = true,
|
|
13944
|
+
disabled = false,
|
|
13945
|
+
className,
|
|
13946
|
+
style
|
|
13947
|
+
}, ref) {
|
|
13948
|
+
const usingGroupedFields = isGroupedFields(fieldsProp);
|
|
13949
|
+
const groups = react.useMemo(
|
|
13950
|
+
() => usingGroupedFields ? fieldsProp : [{ fields: fieldsProp }],
|
|
13951
|
+
[usingGroupedFields, fieldsProp]
|
|
13952
|
+
);
|
|
13953
|
+
const fields = react.useMemo(() => groups.flatMap((group) => group.fields), [groups]);
|
|
13954
|
+
const values = normalizeValues(value);
|
|
13955
|
+
const portalContainer = usePortalContainer();
|
|
13956
|
+
const [internalActiveKeys, setInternalActiveKeys] = react.useState(
|
|
13957
|
+
() => fields.filter((field) => field.defaultActive !== false).map((field) => field.key)
|
|
13958
|
+
);
|
|
13959
|
+
const [openKey, setOpenKey] = react.useState(null);
|
|
13960
|
+
const [addOpen, setAddOpen] = react.useState(false);
|
|
13961
|
+
const triggerRefs = react.useRef(/* @__PURE__ */ new Map());
|
|
13962
|
+
const initializedDefaultsRef = react.useRef(/* @__PURE__ */ new Set());
|
|
13963
|
+
const prevOpenKeyRef = react.useRef(null);
|
|
13964
|
+
const valuesRef = react.useRef(values);
|
|
13965
|
+
valuesRef.current = values;
|
|
13966
|
+
const lastSearchedValuesRef = react.useRef(values);
|
|
13967
|
+
const invalidGroups = react.useMemo(() => {
|
|
13968
|
+
const invalid = /* @__PURE__ */ new Set();
|
|
13969
|
+
groups.forEach((group, groupIndex) => {
|
|
13970
|
+
if (!isGroupSatisfied(group, values)) invalid.add(groupIndex);
|
|
13971
|
+
});
|
|
13972
|
+
return invalid;
|
|
13973
|
+
}, [groups, values]);
|
|
13974
|
+
const isGroupsValid = react.useCallback(
|
|
13975
|
+
(current) => groups.every((group) => isGroupSatisfied(group, current)),
|
|
13976
|
+
[groups]
|
|
13977
|
+
);
|
|
13978
|
+
const runSearch = react.useCallback(
|
|
13979
|
+
(next) => {
|
|
13980
|
+
if (valuesMapEqual(lastSearchedValuesRef.current, next)) return;
|
|
13981
|
+
if (!isGroupsValid(next)) return;
|
|
13982
|
+
lastSearchedValuesRef.current = next;
|
|
13983
|
+
onSearch?.(next);
|
|
13984
|
+
},
|
|
13985
|
+
[isGroupsValid, onSearch]
|
|
13986
|
+
);
|
|
13987
|
+
react.useEffect(() => {
|
|
13988
|
+
const prevKey = prevOpenKeyRef.current;
|
|
13989
|
+
if (prevKey != null && prevKey !== openKey) {
|
|
13990
|
+
runSearch(valuesRef.current);
|
|
13991
|
+
}
|
|
13992
|
+
prevOpenKeyRef.current = openKey;
|
|
13993
|
+
}, [openKey, runSearch]);
|
|
13994
|
+
react.useEffect(() => {
|
|
13995
|
+
if (activeKeys) return;
|
|
13996
|
+
setInternalActiveKeys((current) => {
|
|
13997
|
+
const known = new Set(fields.map((field) => field.key));
|
|
13998
|
+
const kept = current.filter((key) => known.has(key));
|
|
13999
|
+
const additions = fields.filter((field) => field.defaultActive !== false && !kept.includes(field.key)).map((field) => field.key);
|
|
14000
|
+
return [...kept, ...additions];
|
|
14001
|
+
});
|
|
14002
|
+
}, [activeKeys, fields]);
|
|
14003
|
+
react.useEffect(() => {
|
|
14004
|
+
const patch = {};
|
|
14005
|
+
let changed = false;
|
|
14006
|
+
fields.forEach((field) => {
|
|
14007
|
+
if (initializedDefaultsRef.current.has(field.key)) return;
|
|
14008
|
+
if (!isEmptyValue(values[field.key])) {
|
|
14009
|
+
initializedDefaultsRef.current.add(field.key);
|
|
14010
|
+
return;
|
|
14011
|
+
}
|
|
14012
|
+
const def = resolveFieldDefault(field);
|
|
14013
|
+
if (def === void 0) return;
|
|
14014
|
+
patch[field.key] = def;
|
|
14015
|
+
initializedDefaultsRef.current.add(field.key);
|
|
14016
|
+
changed = true;
|
|
14017
|
+
});
|
|
14018
|
+
if (changed) onValueChange?.({ ...values, ...patch });
|
|
14019
|
+
}, [fields, values, onValueChange]);
|
|
14020
|
+
const resolvedActiveKeys = activeKeys ?? internalActiveKeys;
|
|
14021
|
+
const activeFields = fields.filter((field) => resolvedActiveKeys.includes(field.key));
|
|
14022
|
+
const inactiveFields = fields.filter((field) => !resolvedActiveKeys.includes(field.key));
|
|
14023
|
+
const groupIndexByKey = /* @__PURE__ */ new Map();
|
|
14024
|
+
groups.forEach((group, groupIndex) => {
|
|
14025
|
+
group.fields.forEach((field) => groupIndexByKey.set(field.key, groupIndex));
|
|
14026
|
+
});
|
|
14027
|
+
const hasValue = fields.some((field) => !isEmptyValue(values[field.key]));
|
|
14028
|
+
const hasRightActions = showAddButton || showReset;
|
|
14029
|
+
const currentOpenField = fields.find((field) => field.key === openKey);
|
|
14030
|
+
const editorPopoverStyle = react.useMemo(() => {
|
|
14031
|
+
if (currentOpenField?.type === "keyword") {
|
|
14032
|
+
return { width: CHIPFILTER_LISTBOX_WIDTH };
|
|
14033
|
+
}
|
|
14034
|
+
if (currentOpenField?.type === "date" && (currentOpenField.presets?.length ?? 0) > 0) {
|
|
14035
|
+
return { width: CHIPFILTER_DATE_PRESET_LISTBOX_WIDTH };
|
|
14036
|
+
}
|
|
14037
|
+
return { width: CHIPFILTER_LISTBOX_WIDTH };
|
|
14038
|
+
}, [currentOpenField?.type, currentOpenField?.presets?.length]);
|
|
14039
|
+
const setActive = (next) => {
|
|
14040
|
+
if (!activeKeys) setInternalActiveKeys(next);
|
|
14041
|
+
onActiveKeysChange?.(next);
|
|
14042
|
+
};
|
|
14043
|
+
const emitValue = (key, nextValue) => {
|
|
14044
|
+
const next = { ...values, [key]: nextValue };
|
|
14045
|
+
onValueChange?.(next);
|
|
14046
|
+
onFilterChange?.({ key, value: nextValue, values: next });
|
|
14047
|
+
return next;
|
|
14048
|
+
};
|
|
14049
|
+
const emitValueAndSearch = (key, nextValue) => {
|
|
14050
|
+
runSearch(emitValue(key, nextValue));
|
|
14051
|
+
};
|
|
14052
|
+
const clearValue = (key) => {
|
|
14053
|
+
const field = fields.find((f) => f.key === key);
|
|
14054
|
+
const def = field ? resolveFieldDefault(field) : void 0;
|
|
14055
|
+
runSearch(emitValue(key, def !== void 0 ? def : null));
|
|
14056
|
+
};
|
|
14057
|
+
const reset = react.useCallback(() => {
|
|
14058
|
+
const next = fields.reduce((acc, field) => {
|
|
14059
|
+
const def = resolveFieldDefault(field);
|
|
14060
|
+
acc[field.key] = def !== void 0 ? def : null;
|
|
14061
|
+
return acc;
|
|
14062
|
+
}, {});
|
|
14063
|
+
onValueChange?.(next);
|
|
14064
|
+
runSearch(next);
|
|
14065
|
+
onReset?.();
|
|
14066
|
+
}, [fields, onReset, onValueChange, runSearch]);
|
|
14067
|
+
const open = react.useCallback(
|
|
14068
|
+
(key) => {
|
|
14069
|
+
const field = fields.find((f) => f.key === key);
|
|
14070
|
+
if (!field || isInlineField(field)) return;
|
|
14071
|
+
setOpenKey(key);
|
|
14072
|
+
},
|
|
14073
|
+
[fields]
|
|
14074
|
+
);
|
|
14075
|
+
const validate = react.useCallback(() => invalidGroups.size === 0, [invalidGroups]);
|
|
14076
|
+
react.useImperativeHandle(ref, () => ({ open, reset, validate }), [open, reset, validate]);
|
|
14077
|
+
const addField = (key) => {
|
|
14078
|
+
const next = [...resolvedActiveKeys, key];
|
|
14079
|
+
setActive(next);
|
|
14080
|
+
onAddFilter?.(key);
|
|
14081
|
+
setAddOpen(false);
|
|
14082
|
+
const field = fields.find((f) => f.key === key);
|
|
14083
|
+
if (field && !isInlineField(field)) requestAnimationFrame(() => setOpenKey(key));
|
|
14084
|
+
};
|
|
14085
|
+
const rootStyle = react.useMemo(
|
|
14086
|
+
() => ({
|
|
14087
|
+
"--chipfilter-bar-bg": CHIPFILTER.barBg,
|
|
14088
|
+
"--chipfilter-bar-border": CHIPFILTER.barBorder,
|
|
14089
|
+
"--chipfilter-bar-padding-x": CHIPFILTER.barPaddingX,
|
|
14090
|
+
"--chipfilter-bar-padding-y": CHIPFILTER.barPaddingY,
|
|
14091
|
+
"--chipfilter-bar-gap": CHIPFILTER.barGap,
|
|
14092
|
+
"--chipfilter-divider-height": CHIPFILTER.dividerHeight,
|
|
14093
|
+
...style
|
|
14094
|
+
}),
|
|
14095
|
+
[style]
|
|
14096
|
+
);
|
|
14097
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14098
|
+
"div",
|
|
14099
|
+
{
|
|
14100
|
+
className: cn(
|
|
14101
|
+
"flex w-full items-start gap-[var(--chipfilter-bar-gap)] border-b border-solid bg-[var(--chipfilter-bar-bg)] px-[var(--chipfilter-bar-padding-x)] py-[var(--chipfilter-bar-padding-y)]",
|
|
14102
|
+
className
|
|
14103
|
+
),
|
|
14104
|
+
style: { ...rootStyle, borderColor: "var(--chipfilter-bar-border)" },
|
|
14105
|
+
children: [
|
|
14106
|
+
showLabel && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
14107
|
+
/* @__PURE__ */ jsxRuntime.jsx(STag, { className: "shrink-0", shape: "square", size: "sm", color: "darkblue", label }),
|
|
14108
|
+
/* @__PURE__ */ jsxRuntime.jsx(Divider, { top: true })
|
|
14109
|
+
] }),
|
|
14110
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-wrap items-center gap-[var(--cmp-chipFilter-chip-group)]", children: [
|
|
14111
|
+
(() => {
|
|
14112
|
+
const nodes = [];
|
|
14113
|
+
let runBuffer = [];
|
|
14114
|
+
let runGroupIndex = null;
|
|
14115
|
+
const flushRun = () => {
|
|
14116
|
+
if (runBuffer.length === 0) return;
|
|
14117
|
+
const group = runGroupIndex != null ? groups[runGroupIndex] : void 0;
|
|
14118
|
+
const message = usingGroupedFields && group?.rule ? group.tooltipMessage ?? defaultGroupTooltipMessage(group.rule, group.fields) : void 0;
|
|
14119
|
+
if (message) {
|
|
14120
|
+
nodes.push(
|
|
14121
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14122
|
+
GroupTooltip,
|
|
14123
|
+
{
|
|
14124
|
+
message,
|
|
14125
|
+
open: invalidGroups.has(runGroupIndex),
|
|
14126
|
+
children: runBuffer
|
|
14127
|
+
},
|
|
14128
|
+
`group-${runGroupIndex}`
|
|
14129
|
+
)
|
|
14130
|
+
);
|
|
14131
|
+
} else {
|
|
14132
|
+
nodes.push(...runBuffer);
|
|
14133
|
+
}
|
|
14134
|
+
runBuffer = [];
|
|
14135
|
+
};
|
|
14136
|
+
activeFields.forEach((field, index) => {
|
|
14137
|
+
const inline = isInlineField(field);
|
|
14138
|
+
const groupIndex = groupIndexByKey.get(field.key) ?? 0;
|
|
14139
|
+
const warning = field.warning || invalidGroups.has(groupIndex);
|
|
14140
|
+
const prevField = index > 0 ? activeFields[index - 1] : null;
|
|
14141
|
+
const prevGroupIndex = prevField ? groupIndexByKey.get(prevField.key) ?? 0 : null;
|
|
14142
|
+
const needsLeadingDivider = index === 0 ? false : inline || prevField != null && isInlineField(prevField) || groupIndex !== prevGroupIndex;
|
|
14143
|
+
if (groupIndex !== runGroupIndex) {
|
|
14144
|
+
flushRun();
|
|
14145
|
+
runGroupIndex = groupIndex;
|
|
14146
|
+
}
|
|
14147
|
+
const showClear = !isAtDefaultValue(field, values[field.key]);
|
|
14148
|
+
const node = isInlineDateField(field) ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
14149
|
+
InlineDatePresetFilter,
|
|
14150
|
+
{
|
|
14151
|
+
field,
|
|
14152
|
+
value: values[field.key],
|
|
14153
|
+
disabled: disabled || field.disabled,
|
|
14154
|
+
warning,
|
|
14155
|
+
showClear,
|
|
14156
|
+
onValueChange: (next) => emitValueAndSearch(field.key, next),
|
|
14157
|
+
onClear: () => clearValue(field.key)
|
|
14158
|
+
},
|
|
14159
|
+
field.key
|
|
14160
|
+
) : field.type === "custom" ? /* @__PURE__ */ jsxRuntime.jsx(react.Fragment, { children: field.render?.({
|
|
14161
|
+
value: values[field.key],
|
|
14162
|
+
disabled: disabled || field.disabled,
|
|
14163
|
+
warning,
|
|
14164
|
+
onValueChange: (next) => emitValueAndSearch(field.key, next)
|
|
14165
|
+
}) }, field.key) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
14166
|
+
FilterChip,
|
|
14167
|
+
{
|
|
14168
|
+
field,
|
|
14169
|
+
valueText: chipDisplayValue(field, values[field.key]),
|
|
14170
|
+
active: openKey === field.key,
|
|
14171
|
+
applied: !isEmptyValue(values[field.key]),
|
|
14172
|
+
disabled: disabled || field.disabled,
|
|
14173
|
+
warning,
|
|
14174
|
+
showClear,
|
|
14175
|
+
refCallback: (node2) => triggerRefs.current.set(field.key, node2),
|
|
14176
|
+
onOpen: () => setOpenKey(openKey === field.key ? null : field.key),
|
|
14177
|
+
onClear: () => clearValue(field.key)
|
|
14178
|
+
},
|
|
14179
|
+
field.key
|
|
14180
|
+
);
|
|
14181
|
+
runBuffer.push(
|
|
14182
|
+
needsLeadingDivider ? /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, { children: [
|
|
14183
|
+
/* @__PURE__ */ jsxRuntime.jsx(Divider, { inset: true }),
|
|
14184
|
+
node
|
|
14185
|
+
] }, `${field.key}-wrap`) : node
|
|
14186
|
+
);
|
|
14187
|
+
});
|
|
14188
|
+
flushRun();
|
|
14189
|
+
return nodes;
|
|
14190
|
+
})(),
|
|
14191
|
+
(() => {
|
|
14192
|
+
const lastField = activeFields[activeFields.length - 1];
|
|
14193
|
+
const needsTrailingDivider = lastField != null && isInlineField(lastField) && !hasRightActions;
|
|
14194
|
+
return needsTrailingDivider ? /* @__PURE__ */ jsxRuntime.jsx(Divider, { inset: true }) : null;
|
|
14195
|
+
})(),
|
|
14196
|
+
hasRightActions && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
14197
|
+
/* @__PURE__ */ jsxRuntime.jsx(Divider, { inset: true }),
|
|
14198
|
+
showAddButton && /* @__PURE__ */ jsxRuntime.jsxs(RPopover9__namespace.Root, { open: addOpen, onOpenChange: setAddOpen, children: [
|
|
14199
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14200
|
+
"button",
|
|
14201
|
+
{
|
|
14202
|
+
type: "button",
|
|
14203
|
+
disabled: disabled || inactiveFields.length === 0,
|
|
14204
|
+
className: "inline-flex shrink-0 cursor-pointer items-center justify-center gap-[var(--cmp-chipFilter-addButton-gap)] whitespace-nowrap border border-solid bg-[var(--cmp-chipFilter-addButton-bg)] px-[var(--cmp-chipFilter-addButton-paddingX)] text-[12px] font-medium leading-[20px] outline-none disabled:cursor-not-allowed",
|
|
14205
|
+
style: {
|
|
14206
|
+
minHeight: "var(--cmp-chipFilter-addButton-height)" ,
|
|
14207
|
+
borderRadius: "var(--cmp-chipFilter-addButton-radius)" ,
|
|
14208
|
+
borderColor: disabled || inactiveFields.length === 0 ? CHIPFILTER.addBorderDisabled : CHIPFILTER.addBorder,
|
|
14209
|
+
color: disabled || inactiveFields.length === 0 ? CHIPFILTER.addTextDisabled : CHIPFILTER.addText
|
|
14210
|
+
},
|
|
14211
|
+
children: [
|
|
14212
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14213
|
+
SIcon,
|
|
14214
|
+
{
|
|
14215
|
+
name: "add",
|
|
14216
|
+
size: 12,
|
|
14217
|
+
color: disabled || inactiveFields.length === 0 ? CHIPFILTER.addTextDisabled : CHIPFILTER.addText
|
|
14218
|
+
}
|
|
14219
|
+
),
|
|
14220
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "\uD544\uD130 \uCD94\uAC00" })
|
|
14221
|
+
]
|
|
14222
|
+
}
|
|
14223
|
+
) }),
|
|
14224
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14225
|
+
RPopover9__namespace.Content,
|
|
14226
|
+
{
|
|
14227
|
+
side: "bottom",
|
|
14228
|
+
align: "start",
|
|
14229
|
+
sideOffset: 4,
|
|
14230
|
+
className: cn("z-50 min-w-[180px]", FLOATING_SLIDE_ANIM),
|
|
14231
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ListBox, { children: inactiveFields.length > 0 ? inactiveFields.map((field) => /* @__PURE__ */ jsxRuntime.jsx(MenuItem, { onClick: () => addField(field.key), children: field.label }, field.key)) : /* @__PURE__ */ jsxRuntime.jsx(EmptyItem, { children: "\uCD94\uAC00\uD560 \uD544\uD130\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4." }) })
|
|
14232
|
+
}
|
|
14233
|
+
) })
|
|
14234
|
+
] }),
|
|
14235
|
+
showReset && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14236
|
+
"button",
|
|
14237
|
+
{
|
|
14238
|
+
type: "button",
|
|
14239
|
+
disabled: disabled || !hasValue,
|
|
14240
|
+
onClick: reset,
|
|
14241
|
+
className: cn(
|
|
14242
|
+
"inline-flex shrink-0 cursor-pointer items-center gap-[4px] border-none bg-transparent p-0 text-[12px] font-medium leading-[20px] disabled:cursor-not-allowed",
|
|
14243
|
+
// 부모 flex gap(6px)은 칩 사이 간격 기준이라, 필터 추가 버튼과의 12px 간격을 맞추려면
|
|
14244
|
+
// 부족한 만큼(12px - gap)을 추가로 띄운다. 필터 추가가 없을 땐 divider와 이미 12px이라 불필요.
|
|
14245
|
+
showAddButton && "ml-[calc(12px-var(--cmp-chipFilter-chip-group))]"
|
|
14246
|
+
),
|
|
14247
|
+
style: {
|
|
14248
|
+
color: disabled || !hasValue ? "var(--cmp-textLink-content-disabled)" : "var(--cmp-textLink-content-default)"
|
|
14249
|
+
},
|
|
14250
|
+
children: [
|
|
14251
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14252
|
+
SIcon,
|
|
14253
|
+
{
|
|
14254
|
+
name: "reset",
|
|
14255
|
+
size: 16,
|
|
14256
|
+
color: disabled || !hasValue ? "var(--cmp-textLink-icon-disabled)" : "var(--cmp-textLink-icon-default)"
|
|
14257
|
+
}
|
|
14258
|
+
),
|
|
14259
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "\uAC80\uC0C9 \uCD08\uAE30\uD654" })
|
|
14260
|
+
]
|
|
14261
|
+
}
|
|
14262
|
+
)
|
|
14263
|
+
] })
|
|
14264
|
+
] }),
|
|
14265
|
+
/* @__PURE__ */ jsxRuntime.jsxs(RPopover9__namespace.Root, { open: openKey != null, onOpenChange: (next) => !next && setOpenKey(null), children: [
|
|
14266
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14267
|
+
RPopover9__namespace.Anchor,
|
|
14268
|
+
{
|
|
14269
|
+
virtualRef: {
|
|
14270
|
+
current: openKey ? triggerRefs.current.get(openKey) : null
|
|
14271
|
+
}
|
|
14272
|
+
}
|
|
14273
|
+
),
|
|
14274
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14275
|
+
RPopover9__namespace.Content,
|
|
14276
|
+
{
|
|
14277
|
+
side: "bottom",
|
|
14278
|
+
align: "start",
|
|
14279
|
+
sideOffset: 4,
|
|
14280
|
+
onOpenAutoFocus: (event) => event.preventDefault(),
|
|
14281
|
+
className: cn("z-50", FLOATING_SLIDE_ANIM),
|
|
14282
|
+
style: editorPopoverStyle,
|
|
14283
|
+
children: currentOpenField && /* @__PURE__ */ jsxRuntime.jsx(
|
|
14284
|
+
EditorPanel,
|
|
14285
|
+
{
|
|
14286
|
+
field: currentOpenField,
|
|
14287
|
+
value: values[currentOpenField.key],
|
|
14288
|
+
disabled: disabled || currentOpenField.disabled,
|
|
14289
|
+
onValueChange: (next) => emitValue(currentOpenField.key, next),
|
|
14290
|
+
onClose: () => setOpenKey(null)
|
|
14291
|
+
}
|
|
14292
|
+
)
|
|
14293
|
+
}
|
|
14294
|
+
) })
|
|
14295
|
+
] })
|
|
14296
|
+
]
|
|
14297
|
+
}
|
|
14298
|
+
);
|
|
14299
|
+
});
|
|
14300
|
+
function Divider({ inset, top } = {}) {
|
|
14301
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
14302
|
+
"span",
|
|
14303
|
+
{
|
|
14304
|
+
"aria-hidden": true,
|
|
14305
|
+
className: cn(
|
|
14306
|
+
"inline-flex w-px shrink-0 bg-[var(--chipfilter-bar-border)]",
|
|
14307
|
+
top ? "mt-[2px] self-start" : "my-auto",
|
|
14308
|
+
inset && "mx-[calc(12px-var(--cmp-chipFilter-chip-group))]"
|
|
14309
|
+
),
|
|
14310
|
+
style: { height: "var(--chipfilter-divider-height)" }
|
|
14311
|
+
}
|
|
14312
|
+
);
|
|
14313
|
+
}
|
|
14314
|
+
function GroupTooltip({
|
|
14315
|
+
message,
|
|
14316
|
+
open,
|
|
14317
|
+
children
|
|
14318
|
+
}) {
|
|
14319
|
+
return /* @__PURE__ */ jsxRuntime.jsx(STooltip2, { trigger: "none", open, placement: "top", tooltipType: "warning", message: [message], children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-[var(--cmp-chipFilter-chip-group)]", children }) });
|
|
14320
|
+
}
|
|
14321
|
+
function FilterChip({
|
|
14322
|
+
field,
|
|
14323
|
+
valueText,
|
|
14324
|
+
active,
|
|
14325
|
+
applied,
|
|
14326
|
+
disabled,
|
|
14327
|
+
warning,
|
|
14328
|
+
showClear,
|
|
14329
|
+
refCallback,
|
|
14330
|
+
onOpen,
|
|
14331
|
+
onClear
|
|
14332
|
+
}) {
|
|
14333
|
+
const border = disabled ? CHIPFILTER.chipDisabledBorder : warning ? CHIPFILTER.chipWarningBorder : applied ? active ? "var(--color-blue-strong)" : CHIPFILTER.chipAppliedBorder : active ? CHIPFILTER.chipActiveBorder : CHIPFILTER.chipDefaultBorder;
|
|
14334
|
+
const background = disabled ? CHIPFILTER.chipDisabledBg : applied ? CHIPFILTER.chipAppliedBg : CHIPFILTER.chipDefaultBg;
|
|
14335
|
+
const textColor = disabled ? CHIPFILTER.chipDisabledText : CHIPFILTER.chipDefaultText;
|
|
14336
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14337
|
+
"button",
|
|
14338
|
+
{
|
|
14339
|
+
ref: refCallback,
|
|
14340
|
+
type: "button",
|
|
14341
|
+
disabled,
|
|
14342
|
+
"aria-expanded": active,
|
|
14343
|
+
onPointerDown: (event) => event.stopPropagation(),
|
|
14344
|
+
onClick: onOpen,
|
|
14345
|
+
className: "group/chip-filter inline-flex max-w-full shrink-0 cursor-pointer items-center justify-center whitespace-nowrap border border-solid px-[var(--cmp-chipFilter-chip-paddingX)] text-[12px] leading-[20px] outline-none disabled:cursor-not-allowed",
|
|
14346
|
+
style: {
|
|
14347
|
+
minHeight: CHIPFILTER.chipHeight,
|
|
14348
|
+
gap: CHIPFILTER.chipGap,
|
|
14349
|
+
borderRadius: CHIPFILTER.chipRadius,
|
|
14350
|
+
borderColor: border,
|
|
14351
|
+
background,
|
|
14352
|
+
color: textColor
|
|
14353
|
+
},
|
|
14354
|
+
children: [
|
|
14355
|
+
field.required && /* @__PURE__ */ jsxRuntime.jsx(
|
|
14356
|
+
SIcon,
|
|
14357
|
+
{
|
|
14358
|
+
name: "asterisk",
|
|
14359
|
+
size: 12,
|
|
14360
|
+
color: disabled ? CHIPFILTER.chipDisabledText : "var(--cmp-tag-darkblue-content)"
|
|
14361
|
+
}
|
|
14362
|
+
),
|
|
14363
|
+
applied ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex min-w-0 items-center gap-[4px] truncate", children: [
|
|
14364
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14365
|
+
"span",
|
|
14366
|
+
{
|
|
14367
|
+
className: "font-bold",
|
|
14368
|
+
style: { color: disabled ? CHIPFILTER.chipDisabledText : CHIPFILTER.chipAppliedLabel },
|
|
14369
|
+
children: field.label
|
|
14370
|
+
}
|
|
14371
|
+
),
|
|
14372
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14373
|
+
"span",
|
|
14374
|
+
{
|
|
14375
|
+
style: { color: disabled ? CHIPFILTER.chipDisabledText : CHIPFILTER.chipAppliedLabel },
|
|
14376
|
+
children: ":"
|
|
14377
|
+
}
|
|
14378
|
+
),
|
|
14379
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14380
|
+
"span",
|
|
14381
|
+
{
|
|
14382
|
+
className: "min-w-0 truncate font-bold",
|
|
14383
|
+
style: { color: disabled ? CHIPFILTER.chipDisabledText : CHIPFILTER.chipAppliedValue },
|
|
14384
|
+
children: valueText
|
|
14385
|
+
}
|
|
14386
|
+
)
|
|
14387
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
14388
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("min-w-0 truncate", active && "font-bold"), children: field.label }),
|
|
14389
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14390
|
+
SIcon,
|
|
14391
|
+
{
|
|
14392
|
+
name: "caretDown",
|
|
14393
|
+
size: 12,
|
|
14394
|
+
color: disabled ? CHIPFILTER.chipDisabledText : CHIPFILTER.chipDefaultText
|
|
14395
|
+
}
|
|
14396
|
+
)
|
|
14397
|
+
] }),
|
|
14398
|
+
applied && !disabled && showClear && /* @__PURE__ */ jsxRuntime.jsx(
|
|
14399
|
+
"span",
|
|
14400
|
+
{
|
|
14401
|
+
role: "button",
|
|
14402
|
+
tabIndex: 0,
|
|
14403
|
+
"aria-label": `${field.label} \uD544\uD130 \uC9C0\uC6B0\uAE30`,
|
|
14404
|
+
className: "inline-flex size-[16px] items-center justify-center rounded-[var(--cmp-ghostButton-radius-sm)]",
|
|
14405
|
+
onClick: (event) => {
|
|
14406
|
+
event.preventDefault();
|
|
14407
|
+
event.stopPropagation();
|
|
14408
|
+
onClear();
|
|
14409
|
+
},
|
|
14410
|
+
onKeyDown: (event) => {
|
|
14411
|
+
if (event.key !== "Enter" && event.key !== " ") return;
|
|
14412
|
+
event.preventDefault();
|
|
14413
|
+
event.stopPropagation();
|
|
14414
|
+
onClear();
|
|
14415
|
+
},
|
|
14416
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "close", size: 12, color: "var(--cmp-ghostButton-default-content)" })
|
|
14417
|
+
}
|
|
14418
|
+
)
|
|
14419
|
+
]
|
|
14420
|
+
}
|
|
14421
|
+
);
|
|
14422
|
+
}
|
|
14423
|
+
function EditorPanel({
|
|
14424
|
+
field,
|
|
14425
|
+
value,
|
|
14426
|
+
disabled,
|
|
14427
|
+
onValueChange,
|
|
14428
|
+
onClose
|
|
14429
|
+
}) {
|
|
14430
|
+
const wrapsInPaddedTop = field.type === "date";
|
|
14431
|
+
const isMulti = field.type === "multi";
|
|
14432
|
+
const selectableValues = isMulti ? (field.options ?? []).filter((option) => !option.disabled).map((option) => option.value) : [];
|
|
14433
|
+
const selectedValues = isMulti ? toArrayValue(value) : [];
|
|
14434
|
+
const allSelected = isMulti && selectableValues.length > 0 && selectableValues.every((v) => selectedValues.includes(v));
|
|
14435
|
+
const toggleSelectAll = () => {
|
|
14436
|
+
onValueChange(
|
|
14437
|
+
allSelected ? selectedValues.filter((v) => !selectableValues.includes(v)) : [...selectedValues, ...selectableValues.filter((v) => !selectedValues.includes(v))]
|
|
14438
|
+
);
|
|
14439
|
+
};
|
|
14440
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(ListBox, { children: [
|
|
14441
|
+
wrapsInPaddedTop ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-[var(--cmp-chipFilter-listbox-top-gap)] px-[var(--cmp-chipFilter-listbox-top-paddingX)] py-[var(--cmp-chipFilter-listbox-top-paddingY)]", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14442
|
+
FilterEditor,
|
|
14443
|
+
{
|
|
14444
|
+
field,
|
|
14445
|
+
value,
|
|
14446
|
+
disabled,
|
|
14447
|
+
onValueChange
|
|
14448
|
+
}
|
|
14449
|
+
) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
14450
|
+
FilterEditor,
|
|
14451
|
+
{
|
|
14452
|
+
field,
|
|
14453
|
+
value,
|
|
14454
|
+
disabled,
|
|
14455
|
+
onValueChange
|
|
14456
|
+
}
|
|
14457
|
+
),
|
|
14458
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
14459
|
+
"div",
|
|
14460
|
+
{
|
|
14461
|
+
className: "flex items-center justify-end gap-[var(--cmp-chipFilter-listbox-bottom-gap)] border-t border-solid px-[var(--cmp-chipFilter-listbox-bottom-paddingX)] py-[var(--cmp-chipFilter-listbox-bottom-paddingY)]",
|
|
14462
|
+
style: { borderColor: CHIPFILTER.listboxBorder },
|
|
14463
|
+
children: [
|
|
14464
|
+
isMulti && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
14465
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14466
|
+
STextLink,
|
|
14467
|
+
{
|
|
14468
|
+
size: "sm",
|
|
14469
|
+
label: allSelected ? "\uC120\uD0DD \uD574\uC81C" : "\uC804\uCCB4 \uC120\uD0DD",
|
|
14470
|
+
labelClass: "font-bold",
|
|
14471
|
+
disabled,
|
|
14472
|
+
onClick: toggleSelectAll,
|
|
14473
|
+
style: { color: "var(--sys-color-fg-secondary)" }
|
|
14474
|
+
}
|
|
14475
|
+
),
|
|
14476
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14477
|
+
"span",
|
|
14478
|
+
{
|
|
14479
|
+
"aria-hidden": true,
|
|
14480
|
+
className: "inline-flex w-px shrink-0",
|
|
14481
|
+
style: {
|
|
14482
|
+
height: CHIPFILTER.listboxBottomDividerHeight,
|
|
14483
|
+
background: CHIPFILTER.listboxBorder
|
|
14484
|
+
}
|
|
14485
|
+
}
|
|
14486
|
+
)
|
|
14487
|
+
] }),
|
|
14488
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14489
|
+
STextLink,
|
|
14490
|
+
{
|
|
14491
|
+
size: "sm",
|
|
14492
|
+
label: "\uAC80\uC0C9",
|
|
14493
|
+
labelClass: "font-bold",
|
|
14494
|
+
onClick: onClose,
|
|
14495
|
+
style: { color: CHIPFILTER.chipAppliedValue }
|
|
14496
|
+
}
|
|
14497
|
+
)
|
|
14498
|
+
]
|
|
14499
|
+
}
|
|
14500
|
+
)
|
|
14501
|
+
] });
|
|
14502
|
+
}
|
|
14503
|
+
function FilterEditor({
|
|
14504
|
+
field,
|
|
14505
|
+
value,
|
|
14506
|
+
disabled,
|
|
14507
|
+
onValueChange
|
|
14508
|
+
}) {
|
|
14509
|
+
if (field.type === "date") {
|
|
14510
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
14511
|
+
DatePresetEditor,
|
|
14512
|
+
{
|
|
14513
|
+
field,
|
|
14514
|
+
value,
|
|
14515
|
+
disabled,
|
|
14516
|
+
onValueChange
|
|
14517
|
+
}
|
|
14518
|
+
);
|
|
14519
|
+
}
|
|
14520
|
+
if (field.type === "keyword") {
|
|
14521
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
14522
|
+
KeywordEditor,
|
|
14523
|
+
{
|
|
14524
|
+
field,
|
|
14525
|
+
value: isKeywordValue(value) ? value : keywordEntries(value),
|
|
14526
|
+
disabled,
|
|
14527
|
+
onValueChange
|
|
14528
|
+
}
|
|
14529
|
+
);
|
|
14530
|
+
}
|
|
14531
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
14532
|
+
OptionList,
|
|
14533
|
+
{
|
|
14534
|
+
field,
|
|
14535
|
+
value: field.type === "multi" ? toArrayValue(value) : value,
|
|
14536
|
+
multiple: field.type === "multi",
|
|
14537
|
+
disabled,
|
|
14538
|
+
onValueChange
|
|
14539
|
+
}
|
|
14540
|
+
);
|
|
14541
|
+
}
|
|
14542
|
+
function DatePresetEditor({
|
|
14543
|
+
field,
|
|
14544
|
+
value,
|
|
14545
|
+
disabled,
|
|
14546
|
+
onValueChange
|
|
14547
|
+
}) {
|
|
14548
|
+
const presets = field.presets ?? [];
|
|
14549
|
+
const [selectedId, setSelectedId] = react.useState(() => matchPresetId(presets, value));
|
|
14550
|
+
const syncedInitialValueRef = react.useRef(!isEmptyValue(value));
|
|
14551
|
+
react.useEffect(() => {
|
|
14552
|
+
if (syncedInitialValueRef.current || isEmptyValue(value)) return;
|
|
14553
|
+
syncedInitialValueRef.current = true;
|
|
14554
|
+
setSelectedId(matchPresetId(presets, value));
|
|
14555
|
+
}, [value, presets]);
|
|
14556
|
+
const selectedPreset = presets.find((preset) => preset.value === selectedId);
|
|
14557
|
+
const selectPreset = (preset) => {
|
|
14558
|
+
setSelectedId(preset.value);
|
|
14559
|
+
if (!preset.custom) onValueChange(preset.resolve ? preset.resolve() : null);
|
|
14560
|
+
};
|
|
14561
|
+
if (presets.length === 0) {
|
|
14562
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
14563
|
+
SDatePicker,
|
|
14564
|
+
{
|
|
14565
|
+
value: typeof value === "string" ? value : null,
|
|
14566
|
+
onValueChange,
|
|
14567
|
+
selectable: field.selectable,
|
|
14568
|
+
disabled,
|
|
14569
|
+
placeholder: field.placeholder
|
|
14570
|
+
}
|
|
14571
|
+
);
|
|
14572
|
+
}
|
|
14573
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-[var(--cmp-chipFilter-listbox-top-gap)]", children: [
|
|
14574
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-[8px]", children: presets.map((preset) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
14575
|
+
SRadio,
|
|
14576
|
+
{
|
|
14577
|
+
val: preset.value,
|
|
14578
|
+
value: selectedId,
|
|
14579
|
+
label: preset.label,
|
|
14580
|
+
disabled,
|
|
14581
|
+
onValueChange: () => selectPreset(preset)
|
|
14582
|
+
},
|
|
14583
|
+
preset.value
|
|
14584
|
+
)) }),
|
|
14585
|
+
selectedPreset?.custom && /* @__PURE__ */ jsxRuntime.jsx(
|
|
14586
|
+
SDateRangePicker,
|
|
14587
|
+
{
|
|
14588
|
+
value: Array.isArray(value) && value.length === 2 ? value : null,
|
|
14589
|
+
onValueChange,
|
|
14590
|
+
selectable: field.selectable,
|
|
14591
|
+
maxRange: field.maxRange,
|
|
14592
|
+
disabled
|
|
14593
|
+
}
|
|
14594
|
+
)
|
|
14595
|
+
] });
|
|
14596
|
+
}
|
|
14597
|
+
function InlineDatePresetFilter({
|
|
14598
|
+
field,
|
|
14599
|
+
value,
|
|
14600
|
+
disabled,
|
|
14601
|
+
warning,
|
|
14602
|
+
showClear,
|
|
14603
|
+
onValueChange,
|
|
14604
|
+
onClear
|
|
14605
|
+
}) {
|
|
14606
|
+
const presets = (field.presets ?? []).filter((preset) => !preset.custom);
|
|
14607
|
+
const [selectedId, setSelectedId] = react.useState(() => matchPresetId(presets, value));
|
|
14608
|
+
const syncedInitialValueRef = react.useRef(!isEmptyValue(value));
|
|
14609
|
+
react.useEffect(() => {
|
|
14610
|
+
if (syncedInitialValueRef.current || isEmptyValue(value)) return;
|
|
14611
|
+
syncedInitialValueRef.current = true;
|
|
14612
|
+
setSelectedId(matchPresetId(presets, value));
|
|
14613
|
+
}, [value, presets]);
|
|
14614
|
+
const applied = !isEmptyValue(value);
|
|
14615
|
+
const rangeValue = Array.isArray(value) ? value : typeof value === "string" && value !== "" ? [value, value] : null;
|
|
14616
|
+
const [pickerOpen, setPickerOpen] = react.useState(false);
|
|
14617
|
+
const portalContainer = usePortalContainer();
|
|
14618
|
+
const selectPreset = (id) => {
|
|
14619
|
+
const preset = presets.find((p) => p.value === id);
|
|
14620
|
+
if (!preset) return;
|
|
14621
|
+
setSelectedId(preset.value);
|
|
14622
|
+
onValueChange(preset.resolve ? preset.resolve() : null);
|
|
14623
|
+
};
|
|
14624
|
+
const badge = applied && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14625
|
+
"span",
|
|
14626
|
+
{
|
|
14627
|
+
className: "inline-flex shrink-0 items-center gap-[4px] whitespace-nowrap border border-solid px-[var(--cmp-chipFilter-chip-paddingX)] text-[12px] leading-[20px]",
|
|
14628
|
+
style: {
|
|
14629
|
+
minHeight: CHIPFILTER.chipHeight,
|
|
14630
|
+
borderRadius: CHIPFILTER.chipRadius,
|
|
14631
|
+
borderColor: warning ? CHIPFILTER.chipWarningBorder : CHIPFILTER.chipAppliedBorder,
|
|
14632
|
+
background: CHIPFILTER.chipAppliedBg,
|
|
14633
|
+
color: CHIPFILTER.chipAppliedLabel,
|
|
14634
|
+
cursor: rangeValue ? "pointer" : void 0
|
|
14635
|
+
},
|
|
14636
|
+
children: [
|
|
14637
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-bold", children: [
|
|
14638
|
+
field.label,
|
|
14639
|
+
":"
|
|
14640
|
+
] }),
|
|
14641
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-bold", style: { color: CHIPFILTER.chipAppliedValue }, children: displayValue(field, value) }),
|
|
14642
|
+
!disabled && showClear && /* @__PURE__ */ jsxRuntime.jsx(
|
|
14643
|
+
"span",
|
|
14644
|
+
{
|
|
14645
|
+
role: "button",
|
|
14646
|
+
tabIndex: 0,
|
|
14647
|
+
"aria-label": `${field.label} \uD544\uD130 \uC9C0\uC6B0\uAE30`,
|
|
14648
|
+
className: "inline-flex size-[16px] items-center justify-center rounded-[var(--cmp-ghostButton-radius-sm)]",
|
|
14649
|
+
onClick: (event) => {
|
|
14650
|
+
event.stopPropagation();
|
|
14651
|
+
onClear();
|
|
14652
|
+
},
|
|
14653
|
+
onKeyDown: (event) => {
|
|
14654
|
+
if (event.key !== "Enter" && event.key !== " ") return;
|
|
14655
|
+
event.preventDefault();
|
|
14656
|
+
event.stopPropagation();
|
|
14657
|
+
onClear();
|
|
14658
|
+
},
|
|
14659
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "close", size: 12, color: "var(--cmp-ghostButton-default-content)" })
|
|
14660
|
+
}
|
|
14661
|
+
)
|
|
14662
|
+
]
|
|
14663
|
+
}
|
|
14664
|
+
);
|
|
14665
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-[8px]", children: [
|
|
14666
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14667
|
+
SRadioButton,
|
|
14668
|
+
{
|
|
14669
|
+
size: "xs",
|
|
14670
|
+
options: presets.map((preset) => ({ value: preset.value, label: preset.label })),
|
|
14671
|
+
value: selectedId,
|
|
14672
|
+
disabled,
|
|
14673
|
+
onValueChange: (next) => selectPreset(String(next))
|
|
14674
|
+
}
|
|
14675
|
+
),
|
|
14676
|
+
applied && (rangeValue ? (
|
|
14677
|
+
// 뱃지 모양은 그대로 두고, 눌렀을 때 캘린더가 열려 기간을 직접 다시 고를 수 있게 한다.
|
|
14678
|
+
// 직접 고르면 프리셋 선택은 해제된다.
|
|
14679
|
+
/* @__PURE__ */ jsxRuntime.jsxs(RPopover9__namespace.Root, { open: pickerOpen, onOpenChange: setPickerOpen, children: [
|
|
14680
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14681
|
+
"button",
|
|
14682
|
+
{
|
|
14683
|
+
type: "button",
|
|
14684
|
+
disabled,
|
|
14685
|
+
className: "border-none bg-transparent p-0 outline-none disabled:cursor-not-allowed",
|
|
14686
|
+
children: badge
|
|
14687
|
+
}
|
|
14688
|
+
) }),
|
|
14689
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14690
|
+
RPopover9__namespace.Content,
|
|
14691
|
+
{
|
|
14692
|
+
side: "bottom",
|
|
14693
|
+
align: "start",
|
|
14694
|
+
sideOffset: 4,
|
|
14695
|
+
className: cn("z-50", FLOATING_SLIDE_ANIM),
|
|
14696
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14697
|
+
RangeCalendar,
|
|
14698
|
+
{
|
|
14699
|
+
value: rangeValue,
|
|
14700
|
+
selectable: field.selectable,
|
|
14701
|
+
maxRange: field.maxRange,
|
|
14702
|
+
onSelect: (range) => {
|
|
14703
|
+
setSelectedId(null);
|
|
14704
|
+
onValueChange(range);
|
|
14705
|
+
setPickerOpen(false);
|
|
14706
|
+
}
|
|
14707
|
+
}
|
|
14708
|
+
)
|
|
14709
|
+
}
|
|
14710
|
+
) })
|
|
14711
|
+
] })
|
|
14712
|
+
) : badge)
|
|
14713
|
+
] });
|
|
14714
|
+
}
|
|
14715
|
+
var MATCH_MODE_OPTIONS = [
|
|
14716
|
+
{ value: "contains", label: "\uD3EC\uD568" },
|
|
14717
|
+
{ value: "exact", label: "\uC77C\uCE58" }
|
|
14718
|
+
];
|
|
14719
|
+
var EXCLUDE_MATCH_MODE_OPTION = {
|
|
14720
|
+
value: "excludes",
|
|
14721
|
+
label: "\uBBF8\uD3EC\uD568"
|
|
14722
|
+
};
|
|
14723
|
+
function KeywordEditor({
|
|
14724
|
+
field,
|
|
14725
|
+
value,
|
|
14726
|
+
disabled,
|
|
14727
|
+
onValueChange
|
|
14728
|
+
}) {
|
|
14729
|
+
const entries3 = keywordEntries(value);
|
|
14730
|
+
const [draft, setDraft] = react.useState("");
|
|
14731
|
+
const [mode, setMode] = react.useState(
|
|
14732
|
+
isKeywordValue(value) ? value.mode : "contains"
|
|
14733
|
+
);
|
|
14734
|
+
const emit3 = (nextEntries) => {
|
|
14735
|
+
onValueChange(field.matchModes ? { keywords: nextEntries, mode } : nextEntries);
|
|
14736
|
+
};
|
|
14737
|
+
const addEntry = (raw) => {
|
|
14738
|
+
const next = raw.trim();
|
|
14739
|
+
if (next === "" || entries3.includes(next)) return;
|
|
14740
|
+
emit3([...entries3, next]);
|
|
14741
|
+
setDraft("");
|
|
14742
|
+
};
|
|
14743
|
+
const removeEntry = (entry) => {
|
|
14744
|
+
emit3(entries3.filter((e) => e !== entry));
|
|
14745
|
+
};
|
|
14746
|
+
const onKeyDown = (event) => {
|
|
14747
|
+
if (event.key === "Enter") {
|
|
14748
|
+
if (event.nativeEvent.isComposing) return;
|
|
14749
|
+
event.preventDefault();
|
|
14750
|
+
addEntry(draft);
|
|
14751
|
+
}
|
|
14752
|
+
};
|
|
14753
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
14754
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-[var(--cmp-chipFilter-listbox-top-gap)] px-[var(--cmp-chipFilter-listbox-top-paddingX)] py-[var(--cmp-chipFilter-listbox-top-paddingY)]", children: [
|
|
14755
|
+
field.matchModes && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
14756
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14757
|
+
"span",
|
|
14758
|
+
{
|
|
14759
|
+
className: "shrink-0 whitespace-nowrap text-[12px] font-medium leading-[20px]",
|
|
14760
|
+
style: { color: CHIPFILTER.listboxLabel },
|
|
14761
|
+
children: "\uAC80\uC0C9 \uC870\uAC74 :"
|
|
14762
|
+
}
|
|
14763
|
+
),
|
|
14764
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14765
|
+
SRadioButton,
|
|
14766
|
+
{
|
|
14767
|
+
size: "xs",
|
|
14768
|
+
style: { width: 150 },
|
|
14769
|
+
options: field.excludeMode ? [...MATCH_MODE_OPTIONS, EXCLUDE_MATCH_MODE_OPTION] : MATCH_MODE_OPTIONS,
|
|
14770
|
+
value: mode,
|
|
14771
|
+
disabled,
|
|
14772
|
+
onValueChange: (next) => setMode(next)
|
|
14773
|
+
}
|
|
14774
|
+
)
|
|
14775
|
+
] }),
|
|
14776
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-[6px] rounded-[4px] border border-solid border-[color:var(--sys-color-field-border-default)] bg-[var(--sys-color-field-bg-default)] px-[8px] py-[4px] focus-within:border-[color:var(--sys-color-field-border-focus)]", children: [
|
|
14777
|
+
/* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "search", size: 16, color: "var(--sys-color-field-icon-default)" }),
|
|
14778
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14779
|
+
"input",
|
|
14780
|
+
{
|
|
14781
|
+
value: draft,
|
|
14782
|
+
disabled,
|
|
14783
|
+
placeholder: field.placeholder ?? "\uC785\uB825 \uD6C4 Enter\uB85C \uCD94\uAC00",
|
|
14784
|
+
onChange: (event) => setDraft(event.target.value),
|
|
14785
|
+
onKeyDown,
|
|
14786
|
+
className: "min-w-0 flex-1 border-none bg-transparent text-[12px] leading-[20px] text-[color:var(--sys-color-field-text-default)] outline-none placeholder:text-[color:var(--sys-color-field-text-placeholder)] disabled:cursor-not-allowed"
|
|
14787
|
+
}
|
|
14788
|
+
)
|
|
14789
|
+
] })
|
|
14790
|
+
] }),
|
|
14791
|
+
entries3.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
14792
|
+
"div",
|
|
14793
|
+
{
|
|
14794
|
+
className: "max-h-[220px] overflow-auto border-t border-solid py-[var(--cmp-chipFilter-listbox-list-paddingY)]",
|
|
14795
|
+
style: { borderColor: CHIPFILTER.listboxBorder },
|
|
14796
|
+
children: entries3.map((entry) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
14797
|
+
KeywordEntryRow,
|
|
14798
|
+
{
|
|
14799
|
+
label: optionLabel(field, entry),
|
|
14800
|
+
disabled,
|
|
14801
|
+
onRemove: () => removeEntry(entry)
|
|
14802
|
+
},
|
|
14803
|
+
entry
|
|
14804
|
+
))
|
|
14805
|
+
}
|
|
14806
|
+
)
|
|
14807
|
+
] });
|
|
14808
|
+
}
|
|
14809
|
+
function KeywordEntryRow({
|
|
14810
|
+
label,
|
|
14811
|
+
disabled,
|
|
14812
|
+
onRemove
|
|
14813
|
+
}) {
|
|
14814
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14815
|
+
"div",
|
|
14816
|
+
{
|
|
14817
|
+
className: "group flex w-full items-center justify-between gap-[8px] text-[12px] leading-[20px]",
|
|
14818
|
+
style: {
|
|
14819
|
+
paddingTop: CHIPFILTER.itemPaddingY,
|
|
14820
|
+
paddingBottom: CHIPFILTER.itemPaddingY,
|
|
14821
|
+
paddingLeft: CHIPFILTER.itemPaddingLeft,
|
|
14822
|
+
paddingRight: CHIPFILTER.itemPaddingRight,
|
|
14823
|
+
color: disabled ? CHIPFILTER.chipDisabledText : CHIPFILTER.itemTextDefault
|
|
14824
|
+
},
|
|
14825
|
+
children: [
|
|
14826
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("min-w-0 truncate", !disabled && "group-hover:font-bold"), children: label }),
|
|
14827
|
+
!disabled && /* @__PURE__ */ jsxRuntime.jsx(
|
|
14828
|
+
"button",
|
|
14829
|
+
{
|
|
14830
|
+
type: "button",
|
|
14831
|
+
"aria-label": `${label} \uC0AD\uC81C`,
|
|
14832
|
+
className: "invisible inline-flex size-[16px] shrink-0 cursor-pointer items-center justify-center group-hover:visible",
|
|
14833
|
+
onClick: onRemove,
|
|
14834
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "close", size: 12, color: "var(--cmp-ghostButton-default-content)" })
|
|
14835
|
+
}
|
|
14836
|
+
)
|
|
14837
|
+
]
|
|
14838
|
+
}
|
|
14839
|
+
);
|
|
14840
|
+
}
|
|
14841
|
+
var OPTION_SEARCH_THRESHOLD = 11;
|
|
14842
|
+
function OptionList({
|
|
14843
|
+
field,
|
|
14844
|
+
value,
|
|
14845
|
+
multiple,
|
|
14846
|
+
disabled,
|
|
14847
|
+
onValueChange
|
|
14848
|
+
}) {
|
|
14849
|
+
const selected = multiple ? toArrayValue(value) : [];
|
|
14850
|
+
const singleValue = !multiple && (typeof value === "string" || typeof value === "number") ? value : null;
|
|
14851
|
+
const [search, setSearch] = react.useState("");
|
|
14852
|
+
const options = field.options ?? [];
|
|
14853
|
+
const showSearch = options.length >= OPTION_SEARCH_THRESHOLD;
|
|
14854
|
+
const filteredOptions = react.useMemo(() => {
|
|
14855
|
+
if (!showSearch || search.trim() === "") return options;
|
|
14856
|
+
const query = search.trim().toLowerCase();
|
|
14857
|
+
return options.filter((option) => option.label.toLowerCase().includes(query));
|
|
14858
|
+
}, [options, search, showSearch]);
|
|
14859
|
+
if (options.length === 0) return /* @__PURE__ */ jsxRuntime.jsx(EmptyItem, { children: "\uD45C\uC2DC\uD560 \uD56D\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4." });
|
|
14860
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14861
|
+
"div",
|
|
14862
|
+
{
|
|
14863
|
+
className: cn(
|
|
14864
|
+
"max-h-[240px] overflow-auto",
|
|
14865
|
+
!showSearch && "pt-[var(--cmp-chipFilter-listbox-list-paddingY)]",
|
|
14866
|
+
"pb-[var(--cmp-chipFilter-listbox-list-paddingY)]"
|
|
14867
|
+
),
|
|
14868
|
+
children: [
|
|
14869
|
+
showSearch && /* @__PURE__ */ jsxRuntime.jsx(
|
|
14870
|
+
"div",
|
|
14871
|
+
{
|
|
14872
|
+
className: "sticky top-0 z-[1] border-b border-solid px-[8px] pb-[4px] pt-[var(--cmp-chipFilter-listbox-list-paddingY)]",
|
|
14873
|
+
style: { background: CHIPFILTER.listboxBg, borderColor: CHIPFILTER.listboxBorder },
|
|
14874
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-[6px] rounded-[4px] border border-solid border-[color:var(--sys-color-field-border-default)] bg-[var(--sys-color-field-bg-default)] px-[8px] py-[4px] focus-within:border-[color:var(--sys-color-field-border-focus)]", children: [
|
|
14875
|
+
/* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "search", size: 16, color: "var(--sys-color-field-icon-default)" }),
|
|
14876
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14877
|
+
"input",
|
|
14878
|
+
{
|
|
14879
|
+
value: search,
|
|
14880
|
+
disabled,
|
|
14881
|
+
placeholder: "\uAC80\uC0C9",
|
|
14882
|
+
onChange: (event) => setSearch(event.target.value),
|
|
14883
|
+
className: "min-w-0 flex-1 border-none bg-transparent text-[12px] leading-[20px] text-[color:var(--sys-color-field-text-default)] outline-none placeholder:text-[color:var(--sys-color-field-text-placeholder)] disabled:cursor-not-allowed"
|
|
14884
|
+
}
|
|
14885
|
+
),
|
|
14886
|
+
search !== "" && !disabled && /* @__PURE__ */ jsxRuntime.jsx(
|
|
14887
|
+
SGhostButton,
|
|
14888
|
+
{
|
|
14889
|
+
icon: "close",
|
|
14890
|
+
size: "xxs",
|
|
14891
|
+
ariaLabel: "\uAC80\uC0C9\uC5B4 \uC9C0\uC6B0\uAE30",
|
|
14892
|
+
className: "flex-shrink-0",
|
|
14893
|
+
onClick: () => setSearch("")
|
|
14894
|
+
}
|
|
14895
|
+
)
|
|
14896
|
+
] })
|
|
14897
|
+
}
|
|
14898
|
+
),
|
|
14899
|
+
showSearch && filteredOptions.length === 0 && /* @__PURE__ */ jsxRuntime.jsx(EmptyItem, { children: "\uAC80\uC0C9 \uACB0\uACFC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4." }),
|
|
14900
|
+
filteredOptions.map((option) => {
|
|
14901
|
+
const checked = multiple ? selected.includes(option.value) : singleValue === option.value;
|
|
14902
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14903
|
+
MenuItem,
|
|
14904
|
+
{
|
|
14905
|
+
selected: checked,
|
|
14906
|
+
disabled: disabled || option.disabled,
|
|
14907
|
+
multi: multiple,
|
|
14908
|
+
onClick: () => {
|
|
14909
|
+
if (multiple) {
|
|
14910
|
+
const next = checked ? selected.filter((v) => v !== option.value) : [...selected, option.value];
|
|
14911
|
+
onValueChange(next);
|
|
14912
|
+
} else {
|
|
14913
|
+
onValueChange(option.value);
|
|
14914
|
+
}
|
|
14915
|
+
},
|
|
14916
|
+
children: [
|
|
14917
|
+
multiple && /* @__PURE__ */ jsxRuntime.jsx(OptionCheckbox, { checked }),
|
|
14918
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate", children: option.label })
|
|
14919
|
+
]
|
|
14920
|
+
},
|
|
14921
|
+
String(option.value)
|
|
14922
|
+
);
|
|
14923
|
+
})
|
|
14924
|
+
]
|
|
14925
|
+
}
|
|
14926
|
+
);
|
|
14927
|
+
}
|
|
14928
|
+
function OptionCheckbox({ checked }) {
|
|
14929
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
14930
|
+
"span",
|
|
14931
|
+
{
|
|
14932
|
+
className: cn(
|
|
14933
|
+
"inline-flex size-[16px] shrink-0 items-center justify-center rounded-[2px] border border-solid",
|
|
14934
|
+
checked ? "border-[color:var(--cmp-checkbox-checked-bg-default)] bg-[var(--cmp-checkbox-checked-bg-default)]" : "border-[color:var(--cmp-checkbox-unchecked-border-default)] bg-[var(--cmp-checkbox-unchecked-bg-default)]"
|
|
14935
|
+
),
|
|
14936
|
+
children: checked && /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "checkboxCheck", size: 12, color: "var(--cmp-checkbox-checked-icon-default)" })
|
|
14937
|
+
}
|
|
14938
|
+
);
|
|
14939
|
+
}
|
|
14940
|
+
function ListBox({ children }) {
|
|
14941
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
14942
|
+
"div",
|
|
14943
|
+
{
|
|
14944
|
+
className: "overflow-hidden border border-solid shadow-[var(--shadow-overlay)]",
|
|
14945
|
+
style: {
|
|
14946
|
+
borderRadius: CHIPFILTER.listboxRadius,
|
|
14947
|
+
background: CHIPFILTER.listboxBg,
|
|
14948
|
+
borderColor: CHIPFILTER.listboxBorder
|
|
14949
|
+
},
|
|
14950
|
+
children
|
|
14951
|
+
}
|
|
14952
|
+
);
|
|
14953
|
+
}
|
|
14954
|
+
function MenuItem({
|
|
14955
|
+
children,
|
|
14956
|
+
selected,
|
|
14957
|
+
disabled,
|
|
14958
|
+
multi,
|
|
14959
|
+
onMouseEnter,
|
|
14960
|
+
onClick
|
|
14961
|
+
}) {
|
|
14962
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
14963
|
+
"button",
|
|
14964
|
+
{
|
|
14965
|
+
type: "button",
|
|
14966
|
+
disabled,
|
|
14967
|
+
onMouseEnter,
|
|
14968
|
+
onClick,
|
|
14969
|
+
className: cn(
|
|
14970
|
+
"flex w-full min-w-0 cursor-pointer items-center gap-[8px] border-none bg-transparent text-left text-[12px] leading-[20px] outline-none disabled:cursor-not-allowed",
|
|
14971
|
+
selected ? "font-bold" : "font-normal",
|
|
14972
|
+
!disabled && "hover:font-bold"
|
|
14973
|
+
),
|
|
14974
|
+
style: {
|
|
14975
|
+
paddingTop: CHIPFILTER.itemPaddingY,
|
|
14976
|
+
paddingBottom: CHIPFILTER.itemPaddingY,
|
|
14977
|
+
paddingLeft: multi ? CHIPFILTER.itemMultiPaddingX : CHIPFILTER.itemPaddingLeft,
|
|
14978
|
+
paddingRight: multi ? CHIPFILTER.itemMultiPaddingX : CHIPFILTER.itemPaddingRight,
|
|
14979
|
+
color: disabled ? CHIPFILTER.chipDisabledText : selected ? CHIPFILTER.itemTextSelected : CHIPFILTER.itemTextDefault
|
|
14980
|
+
},
|
|
14981
|
+
children
|
|
14982
|
+
}
|
|
14983
|
+
);
|
|
14984
|
+
}
|
|
14985
|
+
function EmptyItem({ children }) {
|
|
14986
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
14987
|
+
"div",
|
|
14988
|
+
{
|
|
14989
|
+
className: "text-[12px] leading-[20px]",
|
|
14990
|
+
style: {
|
|
14991
|
+
paddingTop: CHIPFILTER.itemPaddingY,
|
|
14992
|
+
paddingBottom: CHIPFILTER.itemPaddingY,
|
|
14993
|
+
paddingLeft: CHIPFILTER.itemPaddingLeft,
|
|
14994
|
+
paddingRight: CHIPFILTER.itemPaddingRight,
|
|
14995
|
+
color: CHIPFILTER.chipDisabledText
|
|
14996
|
+
},
|
|
14997
|
+
children
|
|
14998
|
+
}
|
|
14999
|
+
);
|
|
15000
|
+
}
|
|
15001
|
+
var SChipInput = /* @__PURE__ */ react.forwardRef(function SChipInput2({
|
|
15002
|
+
values = [],
|
|
15003
|
+
onValueChange,
|
|
15004
|
+
onInput,
|
|
15005
|
+
onFocus,
|
|
15006
|
+
onBlur,
|
|
13506
15007
|
errors = [],
|
|
13507
15008
|
disabledChips = [],
|
|
13508
15009
|
size = "sm",
|
|
@@ -14220,7 +15721,7 @@ function TimeSelector({
|
|
|
14220
15721
|
const renderColumn = (type) => {
|
|
14221
15722
|
const isHour = type === "hour";
|
|
14222
15723
|
const val = isHour ? displayHour : minute;
|
|
14223
|
-
const
|
|
15724
|
+
const displayValue2 = editingPart === type ? inputDraft[type] ?? "" : String(val).padStart(2, "0");
|
|
14224
15725
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14225
15726
|
"div",
|
|
14226
15727
|
{
|
|
@@ -14241,7 +15742,7 @@ function TimeSelector({
|
|
|
14241
15742
|
{
|
|
14242
15743
|
"aria-label": isHour ? "\uC2DC" : "\uBD84",
|
|
14243
15744
|
inputMode: "numeric",
|
|
14244
|
-
value:
|
|
15745
|
+
value: displayValue2,
|
|
14245
15746
|
placeholder: "-",
|
|
14246
15747
|
onFocus: () => beginEdit(type, val),
|
|
14247
15748
|
onBlur: () => endEdit(type),
|
|
@@ -14436,8 +15937,8 @@ function STimePicker({
|
|
|
14436
15937
|
disabled,
|
|
14437
15938
|
className,
|
|
14438
15939
|
style,
|
|
14439
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14440
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
15940
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(RPopover9__namespace.Root, { open, onOpenChange: commitOpen, children: [
|
|
15941
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14441
15942
|
"div",
|
|
14442
15943
|
{
|
|
14443
15944
|
ref: triggerRef,
|
|
@@ -14497,14 +15998,17 @@ function STimePicker({
|
|
|
14497
15998
|
]
|
|
14498
15999
|
}
|
|
14499
16000
|
) }),
|
|
14500
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14501
|
-
|
|
16001
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
16002
|
+
RPopover9__namespace.Content,
|
|
14502
16003
|
{
|
|
14503
16004
|
side: "bottom",
|
|
14504
16005
|
align: "start",
|
|
14505
16006
|
sideOffset: 4,
|
|
14506
16007
|
alignOffset: popoverAlignOffset,
|
|
14507
|
-
className: cn(
|
|
16008
|
+
className: cn(
|
|
16009
|
+
"z-50 max-w-[var(--radix-popover-content-available-width)]",
|
|
16010
|
+
FLOATING_SLIDE_ANIM
|
|
16011
|
+
),
|
|
14508
16012
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14509
16013
|
TimeSelector,
|
|
14510
16014
|
{
|
|
@@ -14663,7 +16167,7 @@ function RangeTimeSelector({
|
|
|
14663
16167
|
const { minute } = getParts(side);
|
|
14664
16168
|
const val = isHour ? getDisplayHour(side) : minute;
|
|
14665
16169
|
const currentEditingKey = getEditingKey(side, kind);
|
|
14666
|
-
const
|
|
16170
|
+
const displayValue2 = editingKey === currentEditingKey ? inputDraft[currentEditingKey] ?? "" : String(val).padStart(2, "0");
|
|
14667
16171
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14668
16172
|
"div",
|
|
14669
16173
|
{
|
|
@@ -14684,7 +16188,7 @@ function RangeTimeSelector({
|
|
|
14684
16188
|
{
|
|
14685
16189
|
"aria-label": `${side === "start" ? "\uC2DC\uC791" : "\uC885\uB8CC"} ${isHour ? "\uC2DC" : "\uBD84"}`,
|
|
14686
16190
|
inputMode: "numeric",
|
|
14687
|
-
value:
|
|
16191
|
+
value: displayValue2,
|
|
14688
16192
|
placeholder: "-",
|
|
14689
16193
|
onFocus: () => beginEdit(side, kind, val),
|
|
14690
16194
|
onBlur: () => endEdit(side, kind),
|
|
@@ -14895,8 +16399,8 @@ function STimeRangePicker({
|
|
|
14895
16399
|
disabled,
|
|
14896
16400
|
className,
|
|
14897
16401
|
style,
|
|
14898
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14899
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
16402
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(RPopover9__namespace.Root, { open, onOpenChange: commitOpen, children: [
|
|
16403
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14900
16404
|
"div",
|
|
14901
16405
|
{
|
|
14902
16406
|
ref: triggerRef,
|
|
@@ -14956,14 +16460,17 @@ function STimeRangePicker({
|
|
|
14956
16460
|
]
|
|
14957
16461
|
}
|
|
14958
16462
|
) }),
|
|
14959
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14960
|
-
|
|
16463
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
16464
|
+
RPopover9__namespace.Content,
|
|
14961
16465
|
{
|
|
14962
16466
|
side: "bottom",
|
|
14963
16467
|
align: "start",
|
|
14964
16468
|
sideOffset: 4,
|
|
14965
16469
|
alignOffset: popoverAlignOffset,
|
|
14966
|
-
className: cn(
|
|
16470
|
+
className: cn(
|
|
16471
|
+
"z-50 max-w-[var(--radix-popover-content-available-width)]",
|
|
16472
|
+
FLOATING_SLIDE_ANIM
|
|
16473
|
+
),
|
|
14967
16474
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14968
16475
|
RangeTimeSelector,
|
|
14969
16476
|
{
|
|
@@ -14995,7 +16502,9 @@ exports.GNB_MENU_WIDTH = GNB_MENU_WIDTH;
|
|
|
14995
16502
|
exports.GNB_RAIL = GNB_RAIL;
|
|
14996
16503
|
exports.GNB_RAIL_WIDTH = GNB_RAIL_WIDTH;
|
|
14997
16504
|
exports.ICONS = ICONS;
|
|
16505
|
+
exports.IMAGE_FITS = IMAGE_FITS;
|
|
14998
16506
|
exports.PAGE_BACKGROUNDS = PAGE_BACKGROUNDS;
|
|
16507
|
+
exports.RangeCalendar = RangeCalendar;
|
|
14999
16508
|
exports.SActionModal = SActionModal;
|
|
15000
16509
|
exports.SBadge = SBadge;
|
|
15001
16510
|
exports.SBarcodeInput = SBarcodeInput;
|
|
@@ -15006,6 +16515,7 @@ exports.SCallout = SCallout;
|
|
|
15006
16515
|
exports.SCard = SCard;
|
|
15007
16516
|
exports.SCheckbox = SCheckbox;
|
|
15008
16517
|
exports.SChip = SChip2;
|
|
16518
|
+
exports.SChipFilter = SChipFilter;
|
|
15009
16519
|
exports.SChipInput = SChipInput;
|
|
15010
16520
|
exports.SCircleProgress = SCircleProgress;
|
|
15011
16521
|
exports.SConfirmModal = SConfirmModal;
|
|
@@ -15027,6 +16537,7 @@ exports.SGhostButton = SGhostButton;
|
|
|
15027
16537
|
exports.SGnb = SGnb;
|
|
15028
16538
|
exports.SGuide = SGuide;
|
|
15029
16539
|
exports.SIcon = SIcon;
|
|
16540
|
+
exports.SImage = SImage;
|
|
15030
16541
|
exports.SInput = SInput;
|
|
15031
16542
|
exports.SKeyValueTable = SKeyValueTable;
|
|
15032
16543
|
exports.SLAYOUT_MIN_WIDTH = SLAYOUT_MIN_WIDTH;
|