sellmate-design-system-react 8.0.0 → 9.0.0-beta.0
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 +492 -116
- 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/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/SDraggableItem/README.md +1 -0
- package/dist/components/SDraggableItem/SDraggableItem.d.ts +3 -0
- package/dist/components/SDrawer/README.md +5 -4
- package/dist/components/SDrawer/SDrawer.d.ts +16 -5
- package/dist/components/SExpansionItem/README.md +1 -0
- package/dist/components/SExpansionItem/SExpansionItem.d.ts +3 -0
- package/dist/components/SGhostButton/README.md +4 -0
- package/dist/components/SGnb/README.md +3 -0
- package/dist/components/SGnb/SGnb.d.ts +15 -0
- package/dist/components/SGuide/README.md +1 -1
- package/dist/components/SGuide/SGuide.d.ts +1 -1
- package/dist/components/SIcon/README.md +2 -0
- package/dist/components/SIcon/icons.gen.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 +3 -2
- package/dist/components/SListItem/SListItem.d.ts +5 -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/STooltip/README.md +2 -0
- package/dist/index.cjs +1750 -232
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1761 -245
- package/dist/index.js.map +1 -1
- package/dist/lib/floating-width.d.ts +22 -0
- package/dist/llms-full.txt +628 -126
- package/dist/llms.txt +498 -118
- package/dist/styles.css +249 -22
- package/dist/theme.css +36 -10
- package/eslint/scale.gen.mjs +1 -1
- package/package.json +8 -4
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { forwardRef, useState, useRef, useEffect, createContext, useContext, use
|
|
|
5
5
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
6
6
|
import { createPortal } from 'react-dom';
|
|
7
7
|
import * as RCheckbox from '@radix-ui/react-checkbox';
|
|
8
|
-
import * as
|
|
8
|
+
import * as RPopover9 from '@radix-ui/react-popover';
|
|
9
9
|
import { createRoot } from 'react-dom/client';
|
|
10
10
|
import * as RTooltip from '@radix-ui/react-tooltip';
|
|
11
11
|
import * as RDropdown from '@radix-ui/react-dropdown-menu';
|
|
@@ -2565,6 +2565,27 @@ var Icon_sidebar = (p) => {
|
|
|
2565
2565
|
}
|
|
2566
2566
|
);
|
|
2567
2567
|
};
|
|
2568
|
+
var Icon_star = (p) => {
|
|
2569
|
+
const { size = 24, ...rest } = p;
|
|
2570
|
+
return /* @__PURE__ */ jsx(
|
|
2571
|
+
"svg",
|
|
2572
|
+
{
|
|
2573
|
+
width: size,
|
|
2574
|
+
height: size,
|
|
2575
|
+
viewBox: "0 0 24 24",
|
|
2576
|
+
fill: "none",
|
|
2577
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2578
|
+
...rest,
|
|
2579
|
+
children: /* @__PURE__ */ jsx(
|
|
2580
|
+
"path",
|
|
2581
|
+
{
|
|
2582
|
+
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",
|
|
2583
|
+
fill: "currentColor"
|
|
2584
|
+
}
|
|
2585
|
+
)
|
|
2586
|
+
}
|
|
2587
|
+
);
|
|
2588
|
+
};
|
|
2568
2589
|
var Icon_store = (p) => {
|
|
2569
2590
|
const { size = 24, ...rest } = p;
|
|
2570
2591
|
return /* @__PURE__ */ jsxs(
|
|
@@ -3059,6 +3080,7 @@ var ICONS = {
|
|
|
3059
3080
|
settingOutline: Icon_settingOutline,
|
|
3060
3081
|
shield: Icon_shield,
|
|
3061
3082
|
sidebar: Icon_sidebar,
|
|
3083
|
+
star: Icon_star,
|
|
3062
3084
|
store: Icon_store,
|
|
3063
3085
|
synchronize: Icon_synchronize,
|
|
3064
3086
|
thumbsDown: Icon_thumbsDown,
|
|
@@ -3163,6 +3185,7 @@ var SDraggableItemView = /* @__PURE__ */ forwardRef(
|
|
|
3163
3185
|
bordered,
|
|
3164
3186
|
selected,
|
|
3165
3187
|
dense,
|
|
3188
|
+
size,
|
|
3166
3189
|
dragging,
|
|
3167
3190
|
disabled,
|
|
3168
3191
|
hovered,
|
|
@@ -3176,6 +3199,8 @@ var SDraggableItemView = /* @__PURE__ */ forwardRef(
|
|
|
3176
3199
|
const supportingTextNode = renderSlot(supportingText, renderState);
|
|
3177
3200
|
const hasSupportingText = supportingTextNode != null && supportingTextNode !== "";
|
|
3178
3201
|
const trailingNode = renderSlot(trailing, renderState);
|
|
3202
|
+
const titleTypo = size === "sm" ? selected ? "typo-item-sm-selected" : "typo-item-sm-default" : selected ? "typo-item-md-selected" : "typo-item-md-default";
|
|
3203
|
+
const paddingYClass = dense ? size === "sm" ? "py-(--cmp-listDraggableItem-paddingY-sm-dense)" : "py-(--cmp-listDraggableItem-paddingY-md-dense)" : size === "sm" ? "py-(--cmp-listDraggableItem-paddingY-sm-normal)" : "py-(--cmp-listDraggableItem-paddingY-md-normal)";
|
|
3179
3204
|
return /* @__PURE__ */ jsxs(
|
|
3180
3205
|
"div",
|
|
3181
3206
|
{
|
|
@@ -3183,16 +3208,19 @@ var SDraggableItemView = /* @__PURE__ */ forwardRef(
|
|
|
3183
3208
|
"aria-disabled": disabled || void 0,
|
|
3184
3209
|
"data-dragging": dragging || void 0,
|
|
3185
3210
|
className: cn(
|
|
3186
|
-
"relative flex w-full items-center gap-(--cmp-listDraggableItem-gap) overflow-hidden px-(--cmp-listDraggableItem-paddingX)
|
|
3187
|
-
|
|
3211
|
+
"relative flex w-full items-center gap-(--cmp-listDraggableItem-gap) overflow-hidden px-(--cmp-listDraggableItem-paddingX)",
|
|
3212
|
+
titleTypo,
|
|
3213
|
+
disabled ? "bg-(--cmp-listDraggableItem-bg-default) text-(--sys-color-disabled-text)" : selected ? "bg-(--cmp-listDraggableItem-bg-selected) text-(--cmp-listDraggableItem-text-selected)" : "bg-(--cmp-listDraggableItem-bg-default) text-(--cmp-listDraggableItem-text-default)",
|
|
3188
3214
|
!disabled && !selected && !dragging && "hover:bg-(--cmp-listDraggableItem-bg-hover)",
|
|
3189
|
-
hasSupportingText && supportingTextPosition === "bottom" ? dense ? "min-h-[52px]
|
|
3190
|
-
|
|
3215
|
+
hasSupportingText && supportingTextPosition === "bottom" ? dense ? "min-h-[52px]" : "min-h-[60px]" : dense ? "h-[32px]" : "h-[40px]",
|
|
3216
|
+
paddingYClass,
|
|
3217
|
+
// 항목 사이 구분선은 리스트가 그린다 — SDraggableList 의 separator (SList.tsx)
|
|
3218
|
+
bordered && cn(
|
|
3191
3219
|
"rounded-(--cmp-listDraggableItem-radius-bordered) border border-(--cmp-listDraggableItem-border-default)",
|
|
3192
3220
|
!disabled && !selected && !dragging && "hover:border-(--cmp-listDraggableItem-bordered-border-hover)",
|
|
3193
3221
|
!disabled && selected && !dragging && "border-(--cmp-listDraggableItem-bordered-border-selected) bg-(--cmp-listDraggableItem-bordered-bg-selected)",
|
|
3194
3222
|
!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)"
|
|
3195
|
-
)
|
|
3223
|
+
),
|
|
3196
3224
|
disabled && "cursor-not-allowed",
|
|
3197
3225
|
className
|
|
3198
3226
|
),
|
|
@@ -3244,7 +3272,7 @@ var SDraggableItemView = /* @__PURE__ */ forwardRef(
|
|
|
3244
3272
|
"span",
|
|
3245
3273
|
{
|
|
3246
3274
|
className: cn(
|
|
3247
|
-
"min-w-0 truncate text-
|
|
3275
|
+
"typo-body-sm-default min-w-0 truncate text-(--sys-color-fg-secondary)",
|
|
3248
3276
|
supportingTextPosition === "right" && "flex-1"
|
|
3249
3277
|
),
|
|
3250
3278
|
children: supportingTextNode
|
|
@@ -3272,6 +3300,7 @@ var SDraggableItemImpl = /* @__PURE__ */ forwardRef(function SDraggableItem({
|
|
|
3272
3300
|
selected = false,
|
|
3273
3301
|
dragging = false,
|
|
3274
3302
|
dense = false,
|
|
3303
|
+
size = "sm",
|
|
3275
3304
|
disabled = false,
|
|
3276
3305
|
dragOverlay = true,
|
|
3277
3306
|
dragOverlayOpacity = 0.75,
|
|
@@ -3343,6 +3372,7 @@ var SDraggableItemImpl = /* @__PURE__ */ forwardRef(function SDraggableItem({
|
|
|
3343
3372
|
bordered,
|
|
3344
3373
|
selected,
|
|
3345
3374
|
dense,
|
|
3375
|
+
size,
|
|
3346
3376
|
dragging: dragging || overlayVisible,
|
|
3347
3377
|
disabled,
|
|
3348
3378
|
hovered,
|
|
@@ -3377,6 +3407,7 @@ var SDraggableItemImpl = /* @__PURE__ */ forwardRef(function SDraggableItem({
|
|
|
3377
3407
|
bordered,
|
|
3378
3408
|
selected,
|
|
3379
3409
|
dense,
|
|
3410
|
+
size,
|
|
3380
3411
|
dragging: true,
|
|
3381
3412
|
disabled,
|
|
3382
3413
|
hovered: true,
|
|
@@ -3391,7 +3422,7 @@ var SDraggableItemImpl = /* @__PURE__ */ forwardRef(function SDraggableItem({
|
|
|
3391
3422
|
] });
|
|
3392
3423
|
});
|
|
3393
3424
|
var SDraggableItem2 = /* @__PURE__ */ withDisplayName(SDraggableItemImpl, "SDraggableItem");
|
|
3394
|
-
var SListImpl = /* @__PURE__ */ forwardRef(function SList({ className, children, useGap = false, usePadding = false, ...rest }, ref) {
|
|
3425
|
+
var SListImpl = /* @__PURE__ */ forwardRef(function SList({ className, children, useGap = false, usePadding = false, separator = false, ...rest }, ref) {
|
|
3395
3426
|
return /* @__PURE__ */ jsx(
|
|
3396
3427
|
"div",
|
|
3397
3428
|
{
|
|
@@ -3399,6 +3430,7 @@ var SListImpl = /* @__PURE__ */ forwardRef(function SList({ className, children,
|
|
|
3399
3430
|
className: cn(
|
|
3400
3431
|
useGap && "flex flex-col gap-(--cmp-list-group-gap)",
|
|
3401
3432
|
usePadding && "p-(--cmp-list-group-padding)",
|
|
3433
|
+
separator && "[&>*]:border-b [&>*]:border-(--cmp-listItem-border-default)",
|
|
3402
3434
|
className
|
|
3403
3435
|
),
|
|
3404
3436
|
...rest,
|
|
@@ -3728,6 +3760,7 @@ var SExpansionItem = /* @__PURE__ */ forwardRef(
|
|
|
3728
3760
|
interaction,
|
|
3729
3761
|
accentStripe = false,
|
|
3730
3762
|
dense = false,
|
|
3763
|
+
size = "sm",
|
|
3731
3764
|
disabled = false,
|
|
3732
3765
|
onToggle,
|
|
3733
3766
|
className,
|
|
@@ -3743,6 +3776,7 @@ var SExpansionItem = /* @__PURE__ */ forwardRef(
|
|
|
3743
3776
|
const hasChevronInteraction = interaction === "chevron";
|
|
3744
3777
|
const showInteractionChevron = hasChevronInteraction && !disabled && (isSelected || hovered);
|
|
3745
3778
|
const interactionChevronColor = isSelected ? "var(--sys-color-fg-brand)" : "var(--sys-color-fg-quaternary)";
|
|
3779
|
+
const titleTypo = size === "sm" ? isExpanded ? "typo-item-sm-selected" : "typo-item-sm-default" : isExpanded ? "typo-item-md-selected" : "typo-item-md-default";
|
|
3746
3780
|
const reportExpandedDescendant = useCallback(
|
|
3747
3781
|
(delta) => {
|
|
3748
3782
|
setExpandedDescendantCount((current) => Math.max(0, current + delta));
|
|
@@ -3768,7 +3802,7 @@ var SExpansionItem = /* @__PURE__ */ forwardRef(
|
|
|
3768
3802
|
ref,
|
|
3769
3803
|
className: cn(
|
|
3770
3804
|
"group/expansion-item relative overflow-hidden bg-(--cmp-listExpansionItem-title-bg-default)",
|
|
3771
|
-
|
|
3805
|
+
// 항목 사이 구분선은 리스트가 그린다 — SList/SExpansionList 의 separator (SList.tsx)
|
|
3772
3806
|
// 보더 색은 시맨틱 토큰(border-default → hover strong → 펼침 accentLight)을 쓴다.
|
|
3773
3807
|
// TODO: expansionItem/bordered/radius 토큰 생성 후 rounded 고정값도 토큰으로 교체한다.
|
|
3774
3808
|
bordered && "rounded-[8px] border border-border-default hover:border-border-strong [&:has(>button:hover)]:border-border-strong",
|
|
@@ -3800,7 +3834,8 @@ var SExpansionItem = /* @__PURE__ */ forwardRef(
|
|
|
3800
3834
|
onToggle?.(next, event);
|
|
3801
3835
|
},
|
|
3802
3836
|
className: cn(
|
|
3803
|
-
"group/expansion-item-button flex w-full cursor-pointer items-center justify-between border-0 text-left text-
|
|
3837
|
+
"group/expansion-item-button flex w-full cursor-pointer items-center justify-between border-0 text-left text-(--cmp-listExpansionItem-title-text-default) focus-visible:outline focus-visible:outline-2 focus-visible:outline-(--sys-color-border-accent) disabled:cursor-not-allowed disabled:text-(--sys-color-disabled-text)",
|
|
3838
|
+
titleTypo,
|
|
3804
3839
|
isExpanded && "border-b border-(--cmp-listExpansionItem-title-border)",
|
|
3805
3840
|
hasChevronInteraction ? "hover:bg-(--sys-color-bg-neutralBright)" : !isExpanded && "hover:bg-(--cmp-listExpansionItem-title-bg-hover)",
|
|
3806
3841
|
hasSupportingText && supportingTextPosition === "bottom" ? dense ? "min-h-[52px] py-(--cmp-listExpansionItem-title-paddingY-dense)" : "min-h-[60px] py-(--cmp-listExpansionItem-title-paddingY-normal)" : dense ? "h-[32px] py-(--cmp-listExpansionItem-title-paddingY-dense)" : "h-[40px] py-(--cmp-listExpansionItem-title-paddingY-normal)",
|
|
@@ -3837,7 +3872,7 @@ var SExpansionItem = /* @__PURE__ */ forwardRef(
|
|
|
3837
3872
|
"span",
|
|
3838
3873
|
{
|
|
3839
3874
|
className: cn(
|
|
3840
|
-
"min-w-0 truncate text-
|
|
3875
|
+
"typo-body-sm-default min-w-0 truncate text-(--sys-color-fg-secondary)",
|
|
3841
3876
|
supportingTextPosition === "right" && "flex-1"
|
|
3842
3877
|
),
|
|
3843
3878
|
children: supportingText
|
|
@@ -3877,10 +3912,11 @@ var SListItemImpl = /* @__PURE__ */ forwardRef(function SListItem({
|
|
|
3877
3912
|
trailing,
|
|
3878
3913
|
bordered = false,
|
|
3879
3914
|
selected = false,
|
|
3880
|
-
clickable =
|
|
3915
|
+
clickable = false,
|
|
3881
3916
|
interaction,
|
|
3882
3917
|
accentStripe = false,
|
|
3883
3918
|
dense = false,
|
|
3919
|
+
size = "sm",
|
|
3884
3920
|
disabled = false,
|
|
3885
3921
|
className,
|
|
3886
3922
|
onMouseEnter,
|
|
@@ -3899,6 +3935,7 @@ var SListItemImpl = /* @__PURE__ */ forwardRef(function SListItem({
|
|
|
3899
3935
|
const hasChevronInteraction = interaction === "chevron";
|
|
3900
3936
|
const showInteractionChevron = hasChevronInteraction && isInteractive && (isSelected || hovered);
|
|
3901
3937
|
const interactionChevronColor = isSelected ? "var(--sys-color-fg-brand)" : "var(--sys-color-fg-quaternary)";
|
|
3938
|
+
const titleTypo = size === "sm" ? isSelected ? "typo-item-sm-selected" : "typo-item-sm-default" : isSelected ? "typo-item-md-selected" : "typo-item-md-default";
|
|
3902
3939
|
const handleMouseEnter = (event) => {
|
|
3903
3940
|
if (isInteractive) setHovered(true);
|
|
3904
3941
|
onMouseEnter?.(event);
|
|
@@ -3915,7 +3952,8 @@ var SListItemImpl = /* @__PURE__ */ forwardRef(function SListItem({
|
|
|
3915
3952
|
onMouseEnter: handleMouseEnter,
|
|
3916
3953
|
onMouseLeave: handleMouseLeave,
|
|
3917
3954
|
className: cn(
|
|
3918
|
-
"group/list-item relative flex w-full items-center justify-between bg-(--cmp-listItem-bg-default) text-left text-
|
|
3955
|
+
"group/list-item relative flex w-full items-center justify-between bg-(--cmp-listItem-bg-default) text-left text-(--cmp-listItem-text-default)",
|
|
3956
|
+
titleTypo,
|
|
3919
3957
|
disabled ? "pointer-events-none cursor-not-allowed text-(--sys-color-disabled-text)" : isSelected ? cn(
|
|
3920
3958
|
"cursor-pointer text-(--cmp-listItem-text-selected)",
|
|
3921
3959
|
"bg-(--cmp-listItem-bg-selected)"
|
|
@@ -3927,10 +3965,10 @@ var SListItemImpl = /* @__PURE__ */ forwardRef(function SListItem({
|
|
|
3927
3965
|
"gap-(--cmp-listItem-gap)",
|
|
3928
3966
|
"pr-(--cmp-listItem-paddingX)",
|
|
3929
3967
|
depth === 2 ? "pl-[36px]" : depth === 3 ? "pl-[56px]" : "pl-[16px]",
|
|
3930
|
-
bordered
|
|
3968
|
+
bordered && cn(
|
|
3931
3969
|
"overflow-hidden rounded-(--cmp-listItem-radius-bordered) border border-(--cmp-listItem-border-default)",
|
|
3932
3970
|
isSelected ? "border-(--cmp-listItem-bordered-border-selected)" : isInteractive && "hover:border-(--cmp-listItem-bordered-border-hover)"
|
|
3933
|
-
)
|
|
3971
|
+
),
|
|
3934
3972
|
className
|
|
3935
3973
|
),
|
|
3936
3974
|
...rest,
|
|
@@ -3956,7 +3994,7 @@ var SListItemImpl = /* @__PURE__ */ forwardRef(function SListItem({
|
|
|
3956
3994
|
"span",
|
|
3957
3995
|
{
|
|
3958
3996
|
className: cn(
|
|
3959
|
-
"min-w-0 truncate text-
|
|
3997
|
+
"typo-body-sm-default min-w-0 truncate text-(--sys-color-fg-secondary)",
|
|
3960
3998
|
supportingTextPosition === "right" && "flex-1"
|
|
3961
3999
|
),
|
|
3962
4000
|
children: supportingTextNode
|
|
@@ -4009,6 +4047,8 @@ var SExpansionListImpl = /* @__PURE__ */ forwardRef(function SExpansionList({ ch
|
|
|
4009
4047
|
const depth2 = child.props.depth ?? 1;
|
|
4010
4048
|
const itemKey2 = String(child.key ?? index);
|
|
4011
4049
|
return cloneElement(child, {
|
|
4050
|
+
// 선택을 리스트가 관리하는 이상 아이템은 클릭 가능해야 한다 — SListItem 의 기본값(false)을 뒤집는다
|
|
4051
|
+
clickable: child.props.clickable ?? true,
|
|
4012
4052
|
selected: selectedKeys[depth2] === itemKey2,
|
|
4013
4053
|
onClick: (event) => {
|
|
4014
4054
|
setSelectedKeys((current) => ({ ...current, [depth2]: itemKey2 }));
|
|
@@ -4314,8 +4354,8 @@ function SGhostButton({
|
|
|
4314
4354
|
}
|
|
4315
4355
|
);
|
|
4316
4356
|
if (!hasTooltip) return btn;
|
|
4317
|
-
return /* @__PURE__ */ jsxs(
|
|
4318
|
-
/* @__PURE__ */ jsx(
|
|
4357
|
+
return /* @__PURE__ */ jsxs(RPopover9.Root, { open, onOpenChange: setOpen, children: [
|
|
4358
|
+
/* @__PURE__ */ jsx(RPopover9.Anchor, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
4319
4359
|
"span",
|
|
4320
4360
|
{
|
|
4321
4361
|
className: cn("inline-flex", anchorClassName),
|
|
@@ -4327,8 +4367,8 @@ function SGhostButton({
|
|
|
4327
4367
|
children: btn
|
|
4328
4368
|
}
|
|
4329
4369
|
) }),
|
|
4330
|
-
/* @__PURE__ */ jsx(
|
|
4331
|
-
|
|
4370
|
+
/* @__PURE__ */ jsx(RPopover9.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
|
|
4371
|
+
RPopover9.Content,
|
|
4332
4372
|
{
|
|
4333
4373
|
side: "top",
|
|
4334
4374
|
sideOffset: 4,
|
|
@@ -4799,7 +4839,7 @@ var STooltipImpl = /* @__PURE__ */ forwardRef(function STooltip({
|
|
|
4799
4839
|
...restContentProps
|
|
4800
4840
|
} = contentProps ?? {};
|
|
4801
4841
|
const contentClass = cn(
|
|
4802
|
-
"z-50 w-fit
|
|
4842
|
+
"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",
|
|
4803
4843
|
FLOATING_SLIDE_ANIM,
|
|
4804
4844
|
className,
|
|
4805
4845
|
contentPropsClassName
|
|
@@ -4811,14 +4851,14 @@ var STooltipImpl = /* @__PURE__ */ forwardRef(function STooltip({
|
|
|
4811
4851
|
...style,
|
|
4812
4852
|
...contentPropsStyle
|
|
4813
4853
|
};
|
|
4814
|
-
return /* @__PURE__ */ jsxs(
|
|
4854
|
+
return /* @__PURE__ */ jsxs(RPopover9.Root, { open, onOpenChange: setOpenState, children: [
|
|
4815
4855
|
isNone ? (
|
|
4816
4856
|
// 트리거 없음: children 을 래퍼 없이 그대로 앵커로 쓴다 (소비자 레이아웃 보존).
|
|
4817
4857
|
// mouse/focus 핸들러가 없으므로 useClose 없이도 자동 닫힘이 발생하지 않는다.
|
|
4818
|
-
/* @__PURE__ */ jsx(
|
|
4858
|
+
/* @__PURE__ */ jsx(RPopover9.Anchor, { asChild: true, children: triggerNode })
|
|
4819
4859
|
) : isHover ? (
|
|
4820
4860
|
// hover: Anchor(위치 기준) + 직접 mouse 핸들러 — 클릭으로 토글되지 않도록 Trigger 미사용
|
|
4821
|
-
/* @__PURE__ */ jsx(
|
|
4861
|
+
/* @__PURE__ */ jsx(RPopover9.Anchor, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
4822
4862
|
"span",
|
|
4823
4863
|
{
|
|
4824
4864
|
className: "inline-flex",
|
|
@@ -4829,9 +4869,9 @@ var STooltipImpl = /* @__PURE__ */ forwardRef(function STooltip({
|
|
|
4829
4869
|
children: triggerNode
|
|
4830
4870
|
}
|
|
4831
4871
|
) })
|
|
4832
|
-
) : /* @__PURE__ */ jsx(
|
|
4833
|
-
/* @__PURE__ */ jsx(
|
|
4834
|
-
|
|
4872
|
+
) : /* @__PURE__ */ jsx(RPopover9.Trigger, { asChild: true, children: triggerNode }),
|
|
4873
|
+
/* @__PURE__ */ jsx(RPopover9.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxs(
|
|
4874
|
+
RPopover9.Content,
|
|
4835
4875
|
{
|
|
4836
4876
|
side: placement,
|
|
4837
4877
|
sideOffset,
|
|
@@ -4865,7 +4905,7 @@ var STooltipImpl = /* @__PURE__ */ forwardRef(function STooltip({
|
|
|
4865
4905
|
}
|
|
4866
4906
|
)
|
|
4867
4907
|
] }),
|
|
4868
|
-
/* @__PURE__ */ jsx(
|
|
4908
|
+
/* @__PURE__ */ jsx(RPopover9.Arrow, { width: 16, height: 12, style: { fill: bg } })
|
|
4869
4909
|
]
|
|
4870
4910
|
}
|
|
4871
4911
|
) })
|
|
@@ -5873,6 +5913,15 @@ var STextLink = /* @__PURE__ */ forwardRef(function STextLink2({
|
|
|
5873
5913
|
/* @__PURE__ */ jsx(RTooltip.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(RTooltip.Content, { side: "top", sideOffset: 4, className: cn("z-50", FLOATING_SLIDE_ANIM), children: /* @__PURE__ */ jsx(STag, { shape: "square", size: "xs", color: "grey", label: text }) }) })
|
|
5874
5914
|
] }) });
|
|
5875
5915
|
});
|
|
5916
|
+
|
|
5917
|
+
// src/lib/floating-width.ts
|
|
5918
|
+
var POPOVER_AVAILABLE_WIDTH = "var(--radix-popover-content-available-width)";
|
|
5919
|
+
var DROPDOWN_AVAILABLE_WIDTH = "var(--radix-dropdown-menu-content-available-width)";
|
|
5920
|
+
function clampToAvailableWidth(value, availableWidth) {
|
|
5921
|
+
if (value == null || value === "") return availableWidth;
|
|
5922
|
+
const css = typeof value === "number" ? `${value}px` : value;
|
|
5923
|
+
return `min(${css}, ${availableWidth})`;
|
|
5924
|
+
}
|
|
5876
5925
|
var SIZE2 = {
|
|
5877
5926
|
xs: { height: 24, paddingX: 8, gap: 6, arrow: 12, fontSize: 12, minWidth: 64, splitMinWidth: 72 },
|
|
5878
5927
|
sm: {
|
|
@@ -5909,6 +5958,7 @@ function splitDivider(color, outline) {
|
|
|
5909
5958
|
};
|
|
5910
5959
|
return (outline ? outlined : solid)[color];
|
|
5911
5960
|
}
|
|
5961
|
+
var VIEWPORT_PADDING = 12;
|
|
5912
5962
|
var itemClass = cn(
|
|
5913
5963
|
"flex min-h-[28px] cursor-pointer select-none items-center gap-[8px] rounded-[2px] px-[12px] py-[4px] text-[12px] leading-[20px] outline-none",
|
|
5914
5964
|
"text-[color:var(--sys-color-fg-secondary)]",
|
|
@@ -5990,12 +6040,16 @@ var SDropdownButtonImpl = /* @__PURE__ */ forwardRef(
|
|
|
5990
6040
|
sideOffset: 4,
|
|
5991
6041
|
align: "start",
|
|
5992
6042
|
alignOffset: split ? splitAlignOffset : 0,
|
|
6043
|
+
collisionPadding: VIEWPORT_PADDING,
|
|
5993
6044
|
className: cn(
|
|
5994
6045
|
"z-50 overflow-hidden rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] shadow-normal-sm",
|
|
5995
|
-
|
|
6046
|
+
// 창보다 넓은 메뉴는 창 폭에 맞춰 줄인다. 트리거 너비를 따르는 하한도 같은 상한으로
|
|
6047
|
+
// 감싸야 한다 — min-width 가 max-width 를 이기기 때문이다.
|
|
6048
|
+
"max-w-[var(--radix-dropdown-menu-content-available-width)]",
|
|
6049
|
+
!split && "min-w-[min(var(--radix-dropdown-menu-trigger-width),var(--radix-dropdown-menu-content-available-width))]",
|
|
5996
6050
|
FLOATING_SLIDE_ANIM
|
|
5997
6051
|
),
|
|
5998
|
-
style: split ? { minWidth: splitWidth } : void 0,
|
|
6052
|
+
style: split ? { minWidth: clampToAvailableWidth(splitWidth, DROPDOWN_AVAILABLE_WIDTH) } : void 0,
|
|
5999
6053
|
children: items.map((it) => /* @__PURE__ */ jsxs(
|
|
6000
6054
|
RDropdown.Item,
|
|
6001
6055
|
{
|
|
@@ -6007,7 +6061,7 @@ var SDropdownButtonImpl = /* @__PURE__ */ forwardRef(
|
|
|
6007
6061
|
/* @__PURE__ */ jsx(
|
|
6008
6062
|
"span",
|
|
6009
6063
|
{
|
|
6010
|
-
className: "min-w-0
|
|
6064
|
+
className: "min-w-0 break-words",
|
|
6011
6065
|
dangerouslySetInnerHTML: { __html: sanitizeInlineHtml(it.label) }
|
|
6012
6066
|
}
|
|
6013
6067
|
)
|
|
@@ -6219,16 +6273,20 @@ function SPopover({
|
|
|
6219
6273
|
const descColor = type === "default" ? "var(--cmp-popover-default-description)" : "var(--cmp-popover-light-description)";
|
|
6220
6274
|
const leftLinkLabelClass = type === "default" ? "text-[color:var(--cmp-popover-default-subAction)]" : "text-[color:var(--cmp-popover-light-subAction)]";
|
|
6221
6275
|
const triggerNode = trigger ?? /* @__PURE__ */ jsx("span", { className: "inline-flex cursor-pointer", "aria-label": ariaLabel, children: /* @__PURE__ */ jsx(SIcon, { name: icon, size: iconSize, color }) });
|
|
6222
|
-
return /* @__PURE__ */ jsxs(
|
|
6223
|
-
/* @__PURE__ */ jsx(
|
|
6224
|
-
/* @__PURE__ */ jsx(
|
|
6225
|
-
|
|
6276
|
+
return /* @__PURE__ */ jsxs(RPopover9.Root, { open: actualOpen, onOpenChange: setOpen, children: [
|
|
6277
|
+
/* @__PURE__ */ jsx(RPopover9.Trigger, { asChild: true, children: triggerNode }),
|
|
6278
|
+
/* @__PURE__ */ jsx(RPopover9.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxs(
|
|
6279
|
+
RPopover9.Content,
|
|
6226
6280
|
{
|
|
6227
6281
|
side: placement,
|
|
6228
6282
|
sideOffset: 8,
|
|
6229
6283
|
className: cn(
|
|
6230
6284
|
// 닫기 버튼이 항상 있으므로 우측은 close clearance(36px) 로 고정
|
|
6231
|
-
"relative z-50 flex
|
|
6285
|
+
"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",
|
|
6286
|
+
// 창보다 넓어지면 창 폭에 맞춘다. 최소 너비도 같은 상한으로 감싼다 —
|
|
6287
|
+
// min-width 가 max-width 를 이기므로 감싸지 않으면 상한이 무력화된다.
|
|
6288
|
+
"max-w-[var(--radix-popover-content-available-width)]",
|
|
6289
|
+
"min-w-[min(160px,var(--radix-popover-content-available-width))]",
|
|
6232
6290
|
FLOATING_SLIDE_ANIM,
|
|
6233
6291
|
menuClassName
|
|
6234
6292
|
),
|
|
@@ -6284,7 +6342,7 @@ function SPopover({
|
|
|
6284
6342
|
]
|
|
6285
6343
|
}
|
|
6286
6344
|
),
|
|
6287
|
-
/* @__PURE__ */ jsx(
|
|
6345
|
+
/* @__PURE__ */ jsx(RPopover9.Arrow, { width: 16, height: 12, style: { fill: bg } })
|
|
6288
6346
|
]
|
|
6289
6347
|
}
|
|
6290
6348
|
) })
|
|
@@ -6313,8 +6371,9 @@ function SPortal({
|
|
|
6313
6371
|
ariaLabel
|
|
6314
6372
|
}) {
|
|
6315
6373
|
const portalContainer = usePortalContainer();
|
|
6374
|
+
const { minWidth: styleMinWidth, maxWidth: styleMaxWidth, ...restStyle } = style ?? {};
|
|
6316
6375
|
return /* @__PURE__ */ jsxs(
|
|
6317
|
-
|
|
6376
|
+
RPopover9.Root,
|
|
6318
6377
|
{
|
|
6319
6378
|
open,
|
|
6320
6379
|
onOpenChange: (next) => {
|
|
@@ -6322,9 +6381,9 @@ function SPortal({
|
|
|
6322
6381
|
if (!next) onClose?.();
|
|
6323
6382
|
},
|
|
6324
6383
|
children: [
|
|
6325
|
-
/* @__PURE__ */ jsx(
|
|
6326
|
-
/* @__PURE__ */ jsx(
|
|
6327
|
-
|
|
6384
|
+
/* @__PURE__ */ jsx(RPopover9.Anchor, { virtualRef: anchorRef }),
|
|
6385
|
+
/* @__PURE__ */ jsx(RPopover9.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
|
|
6386
|
+
RPopover9.Content,
|
|
6328
6387
|
{
|
|
6329
6388
|
side: placement,
|
|
6330
6389
|
align,
|
|
@@ -6351,11 +6410,18 @@ function SPortal({
|
|
|
6351
6410
|
className: cn(
|
|
6352
6411
|
"z-50 overflow-hidden rounded-(--cmp-listBox-radius) bg-(--cmp-listBox-bg) shadow-normal-sm",
|
|
6353
6412
|
maxHeight != null && "overflow-y-auto",
|
|
6354
|
-
|
|
6413
|
+
// 앵커가 창보다 넓을 수 있는 자리(가로 스크롤 안의 트리거 등)에서도 하한이 상한을
|
|
6414
|
+
// 이기지 않도록, 앵커 너비 역시 가용 폭으로 가둔다.
|
|
6415
|
+
fit && "min-w-[min(var(--radix-popover-trigger-width),var(--radix-popover-content-available-width))]",
|
|
6355
6416
|
FLOATING_SLIDE_ANIM,
|
|
6356
6417
|
className
|
|
6357
6418
|
),
|
|
6358
|
-
style: {
|
|
6419
|
+
style: {
|
|
6420
|
+
maxHeight,
|
|
6421
|
+
...restStyle,
|
|
6422
|
+
...styleMinWidth != null ? { minWidth: clampToAvailableWidth(styleMinWidth, POPOVER_AVAILABLE_WIDTH) } : {},
|
|
6423
|
+
maxWidth: clampToAvailableWidth(styleMaxWidth, POPOVER_AVAILABLE_WIDTH)
|
|
6424
|
+
},
|
|
6359
6425
|
children
|
|
6360
6426
|
}
|
|
6361
6427
|
) })
|
|
@@ -6515,16 +6581,18 @@ function SGuide({
|
|
|
6515
6581
|
);
|
|
6516
6582
|
if (isNotion)
|
|
6517
6583
|
return /* @__PURE__ */ jsx("span", { className, style, children: trigger });
|
|
6518
|
-
return /* @__PURE__ */ jsxs(
|
|
6519
|
-
/* @__PURE__ */ jsx(
|
|
6520
|
-
/* @__PURE__ */ jsx(
|
|
6521
|
-
|
|
6584
|
+
return /* @__PURE__ */ jsxs(RPopover9.Root, { open, onOpenChange: setOpen, children: [
|
|
6585
|
+
/* @__PURE__ */ jsx(RPopover9.Trigger, { asChild: true, children: trigger }),
|
|
6586
|
+
/* @__PURE__ */ jsx(RPopover9.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxs(
|
|
6587
|
+
RPopover9.Content,
|
|
6522
6588
|
{
|
|
6523
6589
|
side: "bottom",
|
|
6524
6590
|
align: "start",
|
|
6525
6591
|
sideOffset: 4,
|
|
6526
6592
|
className: cn(
|
|
6527
6593
|
"relative z-50 rounded-[var(--cmp-guide-contents-radius)] bg-[var(--color-white)]",
|
|
6594
|
+
// popupWidth(기본 426px)가 창보다 넓으면 창 폭에 맞춘다 — max-width 가 width 를 이긴다.
|
|
6595
|
+
"max-w-[var(--radix-popover-content-available-width)]",
|
|
6528
6596
|
FLOATING_SLIDE_ANIM
|
|
6529
6597
|
),
|
|
6530
6598
|
style: {
|
|
@@ -7029,6 +7097,8 @@ function SLoadingModal({
|
|
|
7029
7097
|
);
|
|
7030
7098
|
}
|
|
7031
7099
|
var CLOSE_ANIMATION_DURATION2 = 300;
|
|
7100
|
+
var RESIZE_KEY_STEP = { normal: 10, large: 50 };
|
|
7101
|
+
var RESIZE_HIT_WIDTH = "calc(var(--cmp-splitter-border-width) + var(--cmp-splitter-border-padding) * 2)";
|
|
7032
7102
|
function toPx(value, percentBase) {
|
|
7033
7103
|
if (typeof value === "number") return value;
|
|
7034
7104
|
if (typeof value !== "string") return void 0;
|
|
@@ -7066,6 +7136,7 @@ function SDrawer({
|
|
|
7066
7136
|
resizable = false,
|
|
7067
7137
|
minWidth,
|
|
7068
7138
|
maxWidth,
|
|
7139
|
+
onWidthChange,
|
|
7069
7140
|
footerLeft,
|
|
7070
7141
|
button,
|
|
7071
7142
|
children,
|
|
@@ -7078,11 +7149,16 @@ function SDrawer({
|
|
|
7078
7149
|
const [portalContainer, setPortalContainer] = useState(null);
|
|
7079
7150
|
const backdropPointerDownRef = useRef(false);
|
|
7080
7151
|
const contentRef = useRef(null);
|
|
7152
|
+
const panelRef = useRef(null);
|
|
7081
7153
|
const stackRegistrationRef = useRef(null);
|
|
7082
7154
|
const resizeCleanupRef = useRef(null);
|
|
7083
|
-
const resizeStateRef = useRef(null);
|
|
7084
7155
|
const [layerIndex, setLayerIndex] = useState(null);
|
|
7085
7156
|
const [currentWidth, setCurrentWidth] = useState(width);
|
|
7157
|
+
const [resizing, setResizing] = useState(false);
|
|
7158
|
+
const [measuredWidth, setMeasuredWidth] = useState(null);
|
|
7159
|
+
const [viewportWidth, setViewportWidth] = useState(
|
|
7160
|
+
() => typeof window === "undefined" ? void 0 : window.innerWidth
|
|
7161
|
+
);
|
|
7086
7162
|
useEffect(() => {
|
|
7087
7163
|
setCurrentWidth(width);
|
|
7088
7164
|
}, [width]);
|
|
@@ -7098,6 +7174,22 @@ function SDrawer({
|
|
|
7098
7174
|
useEffect(() => {
|
|
7099
7175
|
return () => resizeCleanupRef.current?.();
|
|
7100
7176
|
}, []);
|
|
7177
|
+
useEffect(() => {
|
|
7178
|
+
if (!rendered) return;
|
|
7179
|
+
const sync = () => setViewportWidth(window.innerWidth);
|
|
7180
|
+
sync();
|
|
7181
|
+
window.addEventListener("resize", sync);
|
|
7182
|
+
return () => window.removeEventListener("resize", sync);
|
|
7183
|
+
}, [rendered]);
|
|
7184
|
+
useEffect(() => {
|
|
7185
|
+
const panel = panelRef.current;
|
|
7186
|
+
if (!resizable || !rendered || !panel || typeof ResizeObserver === "undefined") return;
|
|
7187
|
+
const observer = new ResizeObserver(
|
|
7188
|
+
() => setMeasuredWidth(Math.round(panel.getBoundingClientRect().width))
|
|
7189
|
+
);
|
|
7190
|
+
observer.observe(panel);
|
|
7191
|
+
return () => observer.disconnect();
|
|
7192
|
+
}, [resizable, rendered]);
|
|
7101
7193
|
useEffect(() => {
|
|
7102
7194
|
if (!open) {
|
|
7103
7195
|
setEntered(false);
|
|
@@ -7139,41 +7231,80 @@ function SDrawer({
|
|
|
7139
7231
|
}
|
|
7140
7232
|
onOpenChange?.(false);
|
|
7141
7233
|
};
|
|
7234
|
+
const resizeBounds = () => {
|
|
7235
|
+
const limit = viewportWidth;
|
|
7236
|
+
if (limit === void 0) return { min: void 0, max: void 0 };
|
|
7237
|
+
const min = toPx(minWidth, limit);
|
|
7238
|
+
const max = toPx(maxWidth, limit);
|
|
7239
|
+
return {
|
|
7240
|
+
min: min === void 0 ? void 0 : Math.min(min, limit),
|
|
7241
|
+
max: max === void 0 ? limit : Math.min(max, limit)
|
|
7242
|
+
};
|
|
7243
|
+
};
|
|
7244
|
+
const commitWidth = (next, startWidth) => {
|
|
7245
|
+
const { min, max } = resizeBounds();
|
|
7246
|
+
const clamped = Math.round(clamp3(next, min, max));
|
|
7247
|
+
setCurrentWidth(clamped);
|
|
7248
|
+
if (clamped !== Math.round(startWidth)) onWidthChange?.(clamped);
|
|
7249
|
+
};
|
|
7142
7250
|
const handleResizeStart = (event) => {
|
|
7251
|
+
if (typeof document === "undefined") return;
|
|
7252
|
+
const panel = panelRef.current;
|
|
7253
|
+
if (!panel) return;
|
|
7143
7254
|
event.preventDefault();
|
|
7144
7255
|
event.stopPropagation();
|
|
7145
|
-
|
|
7146
|
-
|
|
7147
|
-
|
|
7148
|
-
|
|
7149
|
-
|
|
7150
|
-
|
|
7151
|
-
|
|
7152
|
-
|
|
7256
|
+
event.currentTarget.focus();
|
|
7257
|
+
const startX = event.clientX;
|
|
7258
|
+
const startWidth = panel.getBoundingClientRect().width;
|
|
7259
|
+
const { min, max } = resizeBounds();
|
|
7260
|
+
let latest = startWidth;
|
|
7261
|
+
const { body } = document;
|
|
7262
|
+
const previousCursor = body.style.cursor;
|
|
7263
|
+
const previousUserSelect = body.style.userSelect;
|
|
7153
7264
|
const onMove = (moveEvent) => {
|
|
7154
|
-
|
|
7155
|
-
|
|
7156
|
-
const nextWidth = resizeState.startWidth + resizeState.startX - moveEvent.clientX;
|
|
7157
|
-
setCurrentWidth(clamp3(nextWidth, resizeState.minWidth, resizeState.maxWidth));
|
|
7265
|
+
latest = Math.round(clamp3(startWidth + (startX - moveEvent.clientX), min, max));
|
|
7266
|
+
setCurrentWidth(latest);
|
|
7158
7267
|
};
|
|
7159
|
-
resizeCleanupRef.current?.();
|
|
7160
|
-
const previousCursor = document.body.style.cursor;
|
|
7161
|
-
const previousUserSelect = document.body.style.userSelect;
|
|
7162
7268
|
const cleanupResize = () => {
|
|
7163
|
-
|
|
7164
|
-
|
|
7165
|
-
document.body.style.userSelect = previousUserSelect;
|
|
7269
|
+
body.style.cursor = previousCursor;
|
|
7270
|
+
body.style.userSelect = previousUserSelect;
|
|
7166
7271
|
document.removeEventListener("mousemove", onMove);
|
|
7167
7272
|
document.removeEventListener("mouseup", cleanupResize);
|
|
7168
7273
|
resizeCleanupRef.current = null;
|
|
7274
|
+
setResizing(false);
|
|
7275
|
+
commitWidth(latest, startWidth);
|
|
7169
7276
|
};
|
|
7277
|
+
resizeCleanupRef.current?.();
|
|
7170
7278
|
resizeCleanupRef.current = cleanupResize;
|
|
7171
|
-
|
|
7172
|
-
|
|
7279
|
+
body.style.cursor = "col-resize";
|
|
7280
|
+
body.style.userSelect = "none";
|
|
7173
7281
|
document.addEventListener("mousemove", onMove);
|
|
7174
7282
|
document.addEventListener("mouseup", cleanupResize);
|
|
7283
|
+
setResizing(true);
|
|
7284
|
+
};
|
|
7285
|
+
const handleResizeKeyDown = (event) => {
|
|
7286
|
+
const panel = panelRef.current;
|
|
7287
|
+
if (!panel) return;
|
|
7288
|
+
const startWidth = panel.getBoundingClientRect().width;
|
|
7289
|
+
const { min, max } = resizeBounds();
|
|
7290
|
+
const step = RESIZE_KEY_STEP[event.shiftKey ? "large" : "normal"];
|
|
7291
|
+
let next = null;
|
|
7292
|
+
if (event.key === "ArrowLeft") next = startWidth + step;
|
|
7293
|
+
else if (event.key === "ArrowRight") next = startWidth - step;
|
|
7294
|
+
else if (event.key === "Home" && min !== void 0) next = min;
|
|
7295
|
+
else if (event.key === "End" && max !== void 0) next = max;
|
|
7296
|
+
if (next === null) return;
|
|
7297
|
+
event.preventDefault();
|
|
7298
|
+
commitWidth(next, startWidth);
|
|
7175
7299
|
};
|
|
7176
7300
|
const modalHost = getModalHost();
|
|
7301
|
+
const resizeValueNow = measuredWidth ?? (typeof currentWidth === "number" ? Math.round(currentWidth) : void 0);
|
|
7302
|
+
const { min: resizeMinPx, max: resizeMaxPx } = resizeBounds();
|
|
7303
|
+
const resizeValueMin = resizeMinPx === void 0 ? void 0 : Math.round(resizeMinPx);
|
|
7304
|
+
const resizeValueMax = resizeMaxPx === void 0 ? void 0 : Math.round(resizeMaxPx);
|
|
7305
|
+
const appliedWidth = typeof currentWidth === "number" && viewportWidth !== void 0 ? Math.min(currentWidth, viewportWidth) : currentWidth;
|
|
7306
|
+
const appliedMinWidth = resizeMinPx ?? minWidth;
|
|
7307
|
+
const appliedMaxWidth = resizeMaxPx ?? maxWidth;
|
|
7177
7308
|
return /* @__PURE__ */ jsx(RDialog.Root, { open, onOpenChange, children: /* @__PURE__ */ jsx(RDialog.Portal, { container: modalHost, forceMount: rendered ? true : void 0, children: /* @__PURE__ */ jsxs("div", { className: "pointer-events-none absolute inset-0", style: { zIndex: layerIndex ?? 0 }, children: [
|
|
7178
7309
|
/* @__PURE__ */ jsx(
|
|
7179
7310
|
RDialog.Overlay,
|
|
@@ -7215,6 +7346,7 @@ function SDrawer({
|
|
|
7215
7346
|
/* @__PURE__ */ jsxs(
|
|
7216
7347
|
"div",
|
|
7217
7348
|
{
|
|
7349
|
+
ref: panelRef,
|
|
7218
7350
|
className: cn(
|
|
7219
7351
|
"pointer-events-auto relative flex h-full max-w-full translate-x-full flex-col overflow-hidden bg-[var(--cmp-drawer-bg)] shadow-[var(--shadow-overlay)] transition-transform duration-300 ease-out data-[state=open]:translate-x-0 data-[state=closed]:translate-x-full",
|
|
7220
7352
|
shaking && "animate-drawer-shake",
|
|
@@ -7222,20 +7354,45 @@ function SDrawer({
|
|
|
7222
7354
|
),
|
|
7223
7355
|
"data-s-drawer-panel": true,
|
|
7224
7356
|
"data-state": open && entered ? "open" : "closed",
|
|
7225
|
-
style: {
|
|
7357
|
+
style: {
|
|
7358
|
+
width: appliedWidth,
|
|
7359
|
+
minWidth: appliedMinWidth,
|
|
7360
|
+
maxWidth: appliedMaxWidth,
|
|
7361
|
+
...style
|
|
7362
|
+
},
|
|
7226
7363
|
onAnimationEnd: (event) => {
|
|
7227
7364
|
if (event.animationName === "drawer-shake") setShaking(false);
|
|
7228
7365
|
},
|
|
7229
7366
|
children: [
|
|
7230
|
-
resizable && /* @__PURE__ */ jsx(
|
|
7231
|
-
"
|
|
7367
|
+
resizable && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(
|
|
7368
|
+
"div",
|
|
7232
7369
|
{
|
|
7233
|
-
|
|
7370
|
+
role: "separator",
|
|
7371
|
+
"aria-orientation": "vertical",
|
|
7234
7372
|
"aria-label": "Drawer \uB108\uBE44 \uC870\uC808",
|
|
7235
|
-
|
|
7236
|
-
|
|
7373
|
+
"aria-valuenow": resizeValueNow,
|
|
7374
|
+
"aria-valuemin": resizeValueMin,
|
|
7375
|
+
"aria-valuemax": resizeValueMax,
|
|
7376
|
+
"aria-valuetext": resizeValueNow === void 0 ? void 0 : `${resizeValueNow}px`,
|
|
7377
|
+
tabIndex: 0,
|
|
7378
|
+
onMouseDown: handleResizeStart,
|
|
7379
|
+
onKeyDown: handleResizeKeyDown,
|
|
7380
|
+
className: "group absolute inset-y-0 left-0 z-[1] flex cursor-col-resize touch-none justify-start outline-none",
|
|
7381
|
+
style: { width: RESIZE_HIT_WIDTH },
|
|
7382
|
+
children: /* @__PURE__ */ jsx(
|
|
7383
|
+
"span",
|
|
7384
|
+
{
|
|
7385
|
+
"aria-hidden": true,
|
|
7386
|
+
className: cn(
|
|
7387
|
+
// 평상시엔 자리만 잡고 칠하지 않는다 — 색이 붙는 것 자체가 조절 가능하다는 신호다.
|
|
7388
|
+
"w-(--cmp-splitter-border-width) transition-colors",
|
|
7389
|
+
"group-hover:bg-(--cmp-splitter-border-color) group-focus-visible:bg-(--cmp-splitter-border-color)",
|
|
7390
|
+
resizing && "bg-(--cmp-splitter-border-color)"
|
|
7391
|
+
)
|
|
7392
|
+
}
|
|
7393
|
+
)
|
|
7237
7394
|
}
|
|
7238
|
-
),
|
|
7395
|
+
) }),
|
|
7239
7396
|
/* @__PURE__ */ jsx(
|
|
7240
7397
|
SOverlayHeader,
|
|
7241
7398
|
{
|
|
@@ -7908,8 +8065,11 @@ var SGnb = /* @__PURE__ */ forwardRef(function SGnb2({
|
|
|
7908
8065
|
onLauncherClick,
|
|
7909
8066
|
logo,
|
|
7910
8067
|
topContent,
|
|
8068
|
+
railTop,
|
|
7911
8069
|
railFooter,
|
|
8070
|
+
menuTop,
|
|
7912
8071
|
menuFooter,
|
|
8072
|
+
foldedTop,
|
|
7913
8073
|
foldedFooter,
|
|
7914
8074
|
resizable = false,
|
|
7915
8075
|
menuWidth: menuWidthProp,
|
|
@@ -8418,6 +8578,7 @@ var SGnb = /* @__PURE__ */ forwardRef(function SGnb2({
|
|
|
8418
8578
|
] })
|
|
8419
8579
|
}
|
|
8420
8580
|
),
|
|
8581
|
+
railFolded && foldedTop && /* @__PURE__ */ jsx("div", { className: "mt-[24px] flex shrink-0 items-center justify-center", children: foldedTop }),
|
|
8421
8582
|
/* @__PURE__ */ jsxs(
|
|
8422
8583
|
"div",
|
|
8423
8584
|
{
|
|
@@ -8435,9 +8596,9 @@ var SGnb = /* @__PURE__ */ forwardRef(function SGnb2({
|
|
|
8435
8596
|
transition: `transform ${GNB_FOLD_MS}ms ease-out, ${hideAfterSlide(folded)}`
|
|
8436
8597
|
},
|
|
8437
8598
|
children: [
|
|
8438
|
-
useRail && // 레일 컬럼 — 스크롤되는 아이템 목록(nav)
|
|
8439
|
-
//
|
|
8440
|
-
// 전체 높이에 걸쳐 책임진다(그래야
|
|
8599
|
+
useRail && // 레일 컬럼 — 스크롤되는 아이템 목록(nav)을 가운데 두고 위아래에 고정 슬롯(top/footer)을 붙인다.
|
|
8600
|
+
// 두 슬롯은 내비게이션이 아니므로 nav(landmark) 밖에 두고, 컬럼 폭·구분선·배경은 이 래퍼가
|
|
8601
|
+
// 전체 높이에 걸쳐 책임진다(그래야 슬롯 자리까지 배경·오른쪽 선이 이어진다).
|
|
8441
8602
|
/* @__PURE__ */ jsxs(
|
|
8442
8603
|
"div",
|
|
8443
8604
|
{
|
|
@@ -8448,6 +8609,7 @@ var SGnb = /* @__PURE__ */ forwardRef(function SGnb2({
|
|
|
8448
8609
|
backgroundColor: C.panelBg
|
|
8449
8610
|
},
|
|
8450
8611
|
children: [
|
|
8612
|
+
railTop && /* @__PURE__ */ jsx("div", { className: "shrink-0", children: railTop }),
|
|
8451
8613
|
/* @__PURE__ */ jsx(
|
|
8452
8614
|
"nav",
|
|
8453
8615
|
{
|
|
@@ -8475,6 +8637,7 @@ var SGnb = /* @__PURE__ */ forwardRef(function SGnb2({
|
|
|
8475
8637
|
borderRight: isFull ? rightBorder : void 0
|
|
8476
8638
|
},
|
|
8477
8639
|
children: [
|
|
8640
|
+
menuTop && /* @__PURE__ */ jsx("div", { className: "shrink-0", children: menuTop }),
|
|
8478
8641
|
/* @__PURE__ */ jsx(
|
|
8479
8642
|
"nav",
|
|
8480
8643
|
{
|
|
@@ -8502,10 +8665,10 @@ var SGnb = /* @__PURE__ */ forwardRef(function SGnb2({
|
|
|
8502
8665
|
}
|
|
8503
8666
|
),
|
|
8504
8667
|
header === "fix" && menuResizeHandle,
|
|
8505
|
-
/* @__PURE__ */ jsxs(
|
|
8506
|
-
/* @__PURE__ */ jsx(
|
|
8507
|
-
/* @__PURE__ */ jsx(
|
|
8508
|
-
|
|
8668
|
+
/* @__PURE__ */ jsxs(RPopover9.Root, { open: labelTip !== null, onOpenChange: (open) => !open && setLabelTip(null), children: [
|
|
8669
|
+
/* @__PURE__ */ jsx(RPopover9.Anchor, { virtualRef: labelTipAnchorRef }),
|
|
8670
|
+
/* @__PURE__ */ jsx(RPopover9.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
|
|
8671
|
+
RPopover9.Content,
|
|
8509
8672
|
{
|
|
8510
8673
|
side: "right",
|
|
8511
8674
|
sideOffset: 4,
|
|
@@ -8523,16 +8686,81 @@ var SGnb = /* @__PURE__ */ forwardRef(function SGnb2({
|
|
|
8523
8686
|
}
|
|
8524
8687
|
);
|
|
8525
8688
|
});
|
|
8689
|
+
var SPageHeader = /* @__PURE__ */ withDisplayName(
|
|
8690
|
+
forwardRef(function SPageHeader2({ title, subText, fix = false, onBack, slot, scrolled = false, className, style, ...rest }, ref) {
|
|
8691
|
+
const hasBack = onBack != null;
|
|
8692
|
+
return /* @__PURE__ */ jsxs(
|
|
8693
|
+
"header",
|
|
8694
|
+
{
|
|
8695
|
+
ref,
|
|
8696
|
+
className: cn(
|
|
8697
|
+
"relative z-10 box-border flex shrink-0 items-center gap-(--cmp-pageHeader-gap) px-(--cmp-pageHeader-paddingX)",
|
|
8698
|
+
fix ? "h-(--cmp-pageHeader-bar-height) border-b border-(--cmp-pageHeader-bar-border) bg-(--cmp-pageHeader-bar-bg) py-(--cmp-pageHeader-bar-paddingY)" : cn(
|
|
8699
|
+
// 배경은 항상 투명 — 페이지 배경을 따라갈지는 fix 가 정하지 scrolled 가 정하지 않는다.
|
|
8700
|
+
// 스크롤되면 그림자만 더해 콘텐츠 위에 뜬 것처럼 보이게 한다.
|
|
8701
|
+
"bg-transparent pt-(--cmp-pageHeader-plain-paddingTop) pb-(--cmp-pageHeader-plain-paddingBottom)",
|
|
8702
|
+
scrolled && "shadow-floating"
|
|
8703
|
+
),
|
|
8704
|
+
className
|
|
8705
|
+
),
|
|
8706
|
+
style,
|
|
8707
|
+
...rest,
|
|
8708
|
+
children: [
|
|
8709
|
+
hasBack && /* @__PURE__ */ jsx(
|
|
8710
|
+
SGhostButton,
|
|
8711
|
+
{
|
|
8712
|
+
icon: "chevronLeft",
|
|
8713
|
+
size: "xs",
|
|
8714
|
+
ariaLabel: "\uB4A4\uB85C\uAC00\uAE30",
|
|
8715
|
+
onClick: onBack,
|
|
8716
|
+
className: "shrink-0"
|
|
8717
|
+
}
|
|
8718
|
+
),
|
|
8719
|
+
/* @__PURE__ */ jsxs(
|
|
8720
|
+
"div",
|
|
8721
|
+
{
|
|
8722
|
+
className: cn(
|
|
8723
|
+
"flex min-w-0 flex-1 items-center",
|
|
8724
|
+
fix ? "flex-row gap-(--cmp-pageHeader-gap)" : "flex-col items-start gap-(--cmp-pageHeader-plain-title-gap)",
|
|
8725
|
+
!hasBack && "pl-(--cmp-pageHeader-title-paddingLeft)"
|
|
8726
|
+
),
|
|
8727
|
+
children: [
|
|
8728
|
+
/* @__PURE__ */ jsx("span", { className: "typo-heading-lg min-w-0 truncate text-(--cmp-pageHeader-title-text)", children: title }),
|
|
8729
|
+
subText && /* @__PURE__ */ jsx("span", { className: "typo-body-md-default min-w-0 truncate text-(--cmp-pageHeader-subtitle-text)", children: subText })
|
|
8730
|
+
]
|
|
8731
|
+
}
|
|
8732
|
+
),
|
|
8733
|
+
slot && /* @__PURE__ */ jsx("div", { className: "ml-auto flex shrink-0 items-center", children: slot })
|
|
8734
|
+
]
|
|
8735
|
+
}
|
|
8736
|
+
);
|
|
8737
|
+
}),
|
|
8738
|
+
"SPageHeader"
|
|
8739
|
+
);
|
|
8526
8740
|
var MIN_CONTENT_WIDTH = `calc(var(${SLAYOUT_MIN_WIDTH_VAR}, 0px) - 100cqw + 100%)`;
|
|
8527
8741
|
var BACKGROUND_CLASS = {
|
|
8528
8742
|
frame: `bg-[var(--sys-color-bg-frame)] ${SCROLLBAR_TRACK_BORDER_CLASS} ${SCROLLBAR_TRACK_BG_CLASS}`,
|
|
8529
8743
|
neutral: `bg-[var(--sys-color-bg-neutralLight)] ${SCROLLBAR_TRACK_BORDER_CLASS} ${SCROLLBAR_TRACK_BG_WHITE_CLASS}`,
|
|
8530
8744
|
screen: `bg-[var(--sys-color-bg-screen)] ${SCROLLBAR_TRACK_BORDER_CLASS} ${SCROLLBAR_TRACK_BG_CLASS}`
|
|
8531
8745
|
};
|
|
8532
|
-
var SPage = /* @__PURE__ */ forwardRef(function SPage2({
|
|
8746
|
+
var SPage = /* @__PURE__ */ forwardRef(function SPage2({
|
|
8747
|
+
background = "frame",
|
|
8748
|
+
scrollEndSpacing = true,
|
|
8749
|
+
header,
|
|
8750
|
+
className,
|
|
8751
|
+
style,
|
|
8752
|
+
children,
|
|
8753
|
+
onScroll,
|
|
8754
|
+
...rest
|
|
8755
|
+
}, ref) {
|
|
8533
8756
|
const layout = useContext(SLayoutContext);
|
|
8534
8757
|
const gridStyle = layout?.header === "full" ? { gridArea: "page" } : void 0;
|
|
8535
|
-
|
|
8758
|
+
const [scrolled, setScrolled] = useState(false);
|
|
8759
|
+
const handleScroll = (e) => {
|
|
8760
|
+
onScroll?.(e);
|
|
8761
|
+
if (header != null && !header.fix) setScrolled(e.currentTarget.scrollTop > 0);
|
|
8762
|
+
};
|
|
8763
|
+
const main = /* @__PURE__ */ jsx(
|
|
8536
8764
|
"main",
|
|
8537
8765
|
{
|
|
8538
8766
|
ref,
|
|
@@ -8543,11 +8771,29 @@ var SPage = /* @__PURE__ */ forwardRef(function SPage2({ background = "frame", s
|
|
|
8543
8771
|
BACKGROUND_CLASS[background],
|
|
8544
8772
|
className
|
|
8545
8773
|
),
|
|
8546
|
-
style: { ...gridStyle, ...style },
|
|
8774
|
+
style: header == null ? { ...gridStyle, ...style } : style,
|
|
8775
|
+
onScroll: handleScroll,
|
|
8547
8776
|
...rest,
|
|
8548
8777
|
children: /* @__PURE__ */ jsx("div", { style: { minWidth: MIN_CONTENT_WIDTH }, children })
|
|
8549
8778
|
}
|
|
8550
8779
|
);
|
|
8780
|
+
if (header == null) return main;
|
|
8781
|
+
return (
|
|
8782
|
+
// fix 가 아닌 헤더는 자기 배경이 투명이라(SPageHeader.tsx) 이 배경이 그대로 비친다 —
|
|
8783
|
+
// 그래서 SPage 의 background 를 main 뿐 아니라 여기에도 칠한다(스크롤바 관련 클래스는
|
|
8784
|
+
// 스크롤 요소가 아닌 여기서는 그냥 무시된다). fix 헤더는 자체 흰 배경이 덮으므로 무관하다.
|
|
8785
|
+
/* @__PURE__ */ jsxs(
|
|
8786
|
+
"div",
|
|
8787
|
+
{
|
|
8788
|
+
className: cn("flex min-h-0 min-w-0 flex-1 flex-col", BACKGROUND_CLASS[background]),
|
|
8789
|
+
style: gridStyle,
|
|
8790
|
+
children: [
|
|
8791
|
+
/* @__PURE__ */ jsx(SPageHeader, { ...header, scrolled }),
|
|
8792
|
+
main
|
|
8793
|
+
]
|
|
8794
|
+
}
|
|
8795
|
+
)
|
|
8796
|
+
);
|
|
8551
8797
|
});
|
|
8552
8798
|
|
|
8553
8799
|
// src/components/SPage/page.config.ts
|
|
@@ -10921,7 +11167,7 @@ var SInput = /* @__PURE__ */ forwardRef(function SInput2({
|
|
|
10921
11167
|
lineHeight: `${f.lineHeight}px`
|
|
10922
11168
|
},
|
|
10923
11169
|
children: [
|
|
10924
|
-
prefix != null && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: prefix }),
|
|
11170
|
+
prefix != null && /* @__PURE__ */ jsx("span", { className: "flex flex-shrink-0 items-center", children: prefix }),
|
|
10925
11171
|
/* @__PURE__ */ jsx(
|
|
10926
11172
|
"input",
|
|
10927
11173
|
{
|
|
@@ -10953,7 +11199,7 @@ var SInput = /* @__PURE__ */ forwardRef(function SInput2({
|
|
|
10953
11199
|
...rest
|
|
10954
11200
|
}
|
|
10955
11201
|
),
|
|
10956
|
-
suffix != null && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: suffix }),
|
|
11202
|
+
suffix != null && /* @__PURE__ */ jsx("span", { className: "flex flex-shrink-0 items-center", children: suffix }),
|
|
10957
11203
|
clearable && hasValue && !disabled && !readOnly && /* @__PURE__ */ jsx(
|
|
10958
11204
|
SGhostButton,
|
|
10959
11205
|
{
|
|
@@ -11851,8 +12097,8 @@ function SDatePicker({
|
|
|
11851
12097
|
disabled,
|
|
11852
12098
|
className,
|
|
11853
12099
|
style,
|
|
11854
|
-
children: /* @__PURE__ */ jsxs(
|
|
11855
|
-
/* @__PURE__ */ jsx(
|
|
12100
|
+
children: /* @__PURE__ */ jsxs(RPopover9.Root, { open, onOpenChange: (o) => !disabled && setOpen(o), children: [
|
|
12101
|
+
/* @__PURE__ */ jsx(RPopover9.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
11856
12102
|
"button",
|
|
11857
12103
|
{
|
|
11858
12104
|
type: "button",
|
|
@@ -11888,13 +12134,16 @@ function SDatePicker({
|
|
|
11888
12134
|
]
|
|
11889
12135
|
}
|
|
11890
12136
|
) }),
|
|
11891
|
-
/* @__PURE__ */ jsx(
|
|
11892
|
-
|
|
12137
|
+
/* @__PURE__ */ jsx(RPopover9.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
|
|
12138
|
+
RPopover9.Content,
|
|
11893
12139
|
{
|
|
11894
12140
|
side: "bottom",
|
|
11895
12141
|
align: "start",
|
|
11896
12142
|
sideOffset: 4,
|
|
11897
|
-
className: cn(
|
|
12143
|
+
className: cn(
|
|
12144
|
+
"z-50 max-w-[var(--radix-popover-content-available-width)]",
|
|
12145
|
+
FLOATING_SLIDE_ANIM
|
|
12146
|
+
),
|
|
11898
12147
|
children: /* @__PURE__ */ jsx(
|
|
11899
12148
|
SCalendar,
|
|
11900
12149
|
{
|
|
@@ -12042,78 +12291,81 @@ function RangeCalendar({
|
|
|
12042
12291
|
}
|
|
12043
12292
|
};
|
|
12044
12293
|
const GRID_COLS = "grid grid-cols-[repeat(7,var(--cmp-datepicker-calendar-day-width))]";
|
|
12045
|
-
const renderPanel = (gy, gm, isLeft) =>
|
|
12046
|
-
|
|
12047
|
-
|
|
12048
|
-
|
|
12049
|
-
|
|
12050
|
-
|
|
12051
|
-
|
|
12052
|
-
|
|
12053
|
-
|
|
12054
|
-
|
|
12055
|
-
|
|
12056
|
-
|
|
12057
|
-
|
|
12058
|
-
|
|
12059
|
-
"
|
|
12060
|
-
|
|
12294
|
+
const renderPanel = (gy, gm, isLeft) => (
|
|
12295
|
+
// 좁은 창에서 눌려 격자가 깨지지 않도록, 줄이는 대신 부모가 가로 스크롤하게 둔다.
|
|
12296
|
+
/* @__PURE__ */ jsxs("div", { className: "flex shrink-0 flex-col gap-[var(--cmp-datepicker-calendar-gap)]", children: [
|
|
12297
|
+
/* @__PURE__ */ jsxs("div", { className: "flex w-full items-center gap-[var(--cmp-datepicker-calendar-gap)]", children: [
|
|
12298
|
+
/* @__PURE__ */ jsx(
|
|
12299
|
+
SGhostButton,
|
|
12300
|
+
{
|
|
12301
|
+
icon: "chevronLeft",
|
|
12302
|
+
size: "xxs",
|
|
12303
|
+
ariaLabel: "prevMonth",
|
|
12304
|
+
onClick: goPrevMonth,
|
|
12305
|
+
className: cn(!isLeft && "invisible pointer-events-none")
|
|
12306
|
+
}
|
|
12307
|
+
),
|
|
12308
|
+
/* @__PURE__ */ jsxs("span", { className: "inline-flex min-w-[40px] flex-1 items-center justify-center text-center text-[14px] font-medium leading-[24px]", children: [
|
|
12309
|
+
gy,
|
|
12310
|
+
".",
|
|
12311
|
+
String(gm).padStart(2, "0")
|
|
12312
|
+
] }),
|
|
12313
|
+
/* @__PURE__ */ jsx(
|
|
12314
|
+
SGhostButton,
|
|
12315
|
+
{
|
|
12316
|
+
icon: "chevronRight",
|
|
12317
|
+
size: "xxs",
|
|
12318
|
+
ariaLabel: "nextMonth",
|
|
12319
|
+
onClick: goNextMonth,
|
|
12320
|
+
className: cn(isLeft && "invisible pointer-events-none")
|
|
12321
|
+
}
|
|
12322
|
+
)
|
|
12061
12323
|
] }),
|
|
12062
|
-
/* @__PURE__ */ jsx(
|
|
12063
|
-
|
|
12064
|
-
{
|
|
12065
|
-
icon: "chevronRight",
|
|
12066
|
-
size: "xxs",
|
|
12067
|
-
ariaLabel: "nextMonth",
|
|
12068
|
-
onClick: goNextMonth,
|
|
12069
|
-
className: cn(isLeft && "invisible pointer-events-none")
|
|
12070
|
-
}
|
|
12071
|
-
)
|
|
12072
|
-
] }),
|
|
12073
|
-
/* @__PURE__ */ jsx("div", { className: GRID_COLS, children: WEEK_LABELS.map((l) => /* @__PURE__ */ jsx(
|
|
12074
|
-
"span",
|
|
12075
|
-
{
|
|
12076
|
-
className: "flex h-[20px] items-center justify-center text-[12px] font-normal text-[color:var(--cmp-datepicker-calendar-week-color)]",
|
|
12077
|
-
children: l
|
|
12078
|
-
},
|
|
12079
|
-
l
|
|
12080
|
-
)) }),
|
|
12081
|
-
/* @__PURE__ */ jsx("div", { className: cn(GRID_COLS, "gap-y-[var(--cmp-datepicker-calendar-grid-rowGap)]"), children: monthCells(gy, gm).map((cell) => {
|
|
12082
|
-
const isEdge = cell.inCurrentMonth && (cell.date === rStart || complete && cell.date === rEnd);
|
|
12083
|
-
const between = cell.inCurrentMonth && inRange(cell.date);
|
|
12084
|
-
const disabled = cell.inCurrentMonth && isDisabled(cell.date);
|
|
12085
|
-
const isToday = cell.inCurrentMonth && today === cell.date;
|
|
12086
|
-
let cellBg;
|
|
12087
|
-
if (between) cellBg = RANGE_BG;
|
|
12088
|
-
else if (cell.inCurrentMonth && hasRange && cell.date === rStart)
|
|
12089
|
-
cellBg = `linear-gradient(to right, transparent 50%, ${RANGE_BG} 50%)`;
|
|
12090
|
-
else if (cell.inCurrentMonth && hasRange && cell.date === rEnd) cellBg = RANGE_BG;
|
|
12091
|
-
return /* @__PURE__ */ jsx(
|
|
12092
|
-
"div",
|
|
12324
|
+
/* @__PURE__ */ jsx("div", { className: GRID_COLS, children: WEEK_LABELS.map((l) => /* @__PURE__ */ jsx(
|
|
12325
|
+
"span",
|
|
12093
12326
|
{
|
|
12094
|
-
className: "flex h-[
|
|
12095
|
-
|
|
12096
|
-
children: /* @__PURE__ */ jsx(
|
|
12097
|
-
"button",
|
|
12098
|
-
{
|
|
12099
|
-
type: "button",
|
|
12100
|
-
disabled: !cell.inCurrentMonth || disabled,
|
|
12101
|
-
onMouseEnter: () => setHover(cell.date),
|
|
12102
|
-
onClick: () => cell.inCurrentMonth && click(cell.date),
|
|
12103
|
-
className: cn(
|
|
12104
|
-
"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]",
|
|
12105
|
-
!cell.inCurrentMonth ? "invisible pointer-events-none" : disabled ? "cursor-not-allowed" : "cursor-pointer",
|
|
12106
|
-
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)]",
|
|
12107
|
-
isToday && !disabled && "font-bold"
|
|
12108
|
-
),
|
|
12109
|
-
children: cell.inCurrentMonth ? cell.day : ""
|
|
12110
|
-
}
|
|
12111
|
-
)
|
|
12327
|
+
className: "flex h-[20px] items-center justify-center text-[12px] font-normal text-[color:var(--cmp-datepicker-calendar-week-color)]",
|
|
12328
|
+
children: l
|
|
12112
12329
|
},
|
|
12113
|
-
|
|
12114
|
-
)
|
|
12115
|
-
|
|
12116
|
-
|
|
12330
|
+
l
|
|
12331
|
+
)) }),
|
|
12332
|
+
/* @__PURE__ */ jsx("div", { className: cn(GRID_COLS, "gap-y-[var(--cmp-datepicker-calendar-grid-rowGap)]"), children: monthCells(gy, gm).map((cell) => {
|
|
12333
|
+
const isEdge = cell.inCurrentMonth && (cell.date === rStart || complete && cell.date === rEnd);
|
|
12334
|
+
const between = cell.inCurrentMonth && inRange(cell.date);
|
|
12335
|
+
const disabled = cell.inCurrentMonth && isDisabled(cell.date);
|
|
12336
|
+
const isToday = cell.inCurrentMonth && today === cell.date;
|
|
12337
|
+
let cellBg;
|
|
12338
|
+
if (between) cellBg = RANGE_BG;
|
|
12339
|
+
else if (cell.inCurrentMonth && hasRange && cell.date === rStart)
|
|
12340
|
+
cellBg = `linear-gradient(to right, transparent 50%, ${RANGE_BG} 50%)`;
|
|
12341
|
+
else if (cell.inCurrentMonth && hasRange && cell.date === rEnd) cellBg = RANGE_BG;
|
|
12342
|
+
return /* @__PURE__ */ jsx(
|
|
12343
|
+
"div",
|
|
12344
|
+
{
|
|
12345
|
+
className: "flex h-[var(--cmp-datepicker-calendar-range-height)] w-[var(--cmp-datepicker-calendar-day-width)] items-center justify-center",
|
|
12346
|
+
style: { background: cellBg },
|
|
12347
|
+
children: /* @__PURE__ */ jsx(
|
|
12348
|
+
"button",
|
|
12349
|
+
{
|
|
12350
|
+
type: "button",
|
|
12351
|
+
disabled: !cell.inCurrentMonth || disabled,
|
|
12352
|
+
onMouseEnter: () => setHover(cell.date),
|
|
12353
|
+
onClick: () => cell.inCurrentMonth && click(cell.date),
|
|
12354
|
+
className: cn(
|
|
12355
|
+
"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]",
|
|
12356
|
+
!cell.inCurrentMonth ? "invisible pointer-events-none" : disabled ? "cursor-not-allowed" : "cursor-pointer",
|
|
12357
|
+
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)]",
|
|
12358
|
+
isToday && !disabled && "font-bold"
|
|
12359
|
+
),
|
|
12360
|
+
children: cell.inCurrentMonth ? cell.day : ""
|
|
12361
|
+
}
|
|
12362
|
+
)
|
|
12363
|
+
},
|
|
12364
|
+
cell.date
|
|
12365
|
+
);
|
|
12366
|
+
}) })
|
|
12367
|
+
] })
|
|
12368
|
+
);
|
|
12117
12369
|
const renderTimeSection = (which, date, suffix) => {
|
|
12118
12370
|
const active = !!date;
|
|
12119
12371
|
const [yy = "", mm = "", dd = ""] = date ? date.split("-") : [];
|
|
@@ -12181,8 +12433,11 @@ function RangeCalendar({
|
|
|
12181
12433
|
"div",
|
|
12182
12434
|
{
|
|
12183
12435
|
className: cn(
|
|
12184
|
-
"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",
|
|
12185
|
-
|
|
12436
|
+
"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",
|
|
12437
|
+
// 높이는 고정이 아니라 하한이다 — 5주/6주 달을 오갈 때의 높이 흔들림만 막으면 되고,
|
|
12438
|
+
// 창이 좁아 패널이 가로 스크롤될 때는 스크롤바 높이만큼 늘어날 수 있어야 한다.
|
|
12439
|
+
// (단일 달 SCalendar 도 min-h 를 쓴다)
|
|
12440
|
+
useTimePicker ? "h-auto" : "min-h-[364px]"
|
|
12186
12441
|
),
|
|
12187
12442
|
children: [
|
|
12188
12443
|
/* @__PURE__ */ jsxs("div", { className: "relative flex items-center justify-center", children: [
|
|
@@ -12201,11 +12456,20 @@ function RangeCalendar({
|
|
|
12201
12456
|
}
|
|
12202
12457
|
)
|
|
12203
12458
|
] }),
|
|
12204
|
-
/* @__PURE__ */ jsxs(
|
|
12205
|
-
|
|
12206
|
-
|
|
12207
|
-
|
|
12208
|
-
|
|
12459
|
+
/* @__PURE__ */ jsxs(
|
|
12460
|
+
"div",
|
|
12461
|
+
{
|
|
12462
|
+
className: cn(
|
|
12463
|
+
"flex max-w-full gap-[var(--cmp-datepicker-calendar-range-panelGap)] overflow-x-auto",
|
|
12464
|
+
SCROLLBAR_CLASS
|
|
12465
|
+
),
|
|
12466
|
+
children: [
|
|
12467
|
+
renderPanel(y, m, true),
|
|
12468
|
+
/* @__PURE__ */ jsx(SDivider, { vertical: true }),
|
|
12469
|
+
renderPanel(nextMonthYM.year, nextMonthYM.month, false)
|
|
12470
|
+
]
|
|
12471
|
+
}
|
|
12472
|
+
),
|
|
12209
12473
|
useTimePicker && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
12210
12474
|
/* @__PURE__ */ jsx(SDivider, {}),
|
|
12211
12475
|
/* @__PURE__ */ jsxs("div", { className: "flex gap-[var(--cmp-datepicker-calendar-time-gap)]", children: [
|
|
@@ -12264,7 +12528,25 @@ function SDateRangePicker({
|
|
|
12264
12528
|
});
|
|
12265
12529
|
const resolvedError = error || ruleError !== "";
|
|
12266
12530
|
const resolvedStatus = status ?? (rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0);
|
|
12267
|
-
const dims = size === "md" ? {
|
|
12531
|
+
const dims = size === "md" ? {
|
|
12532
|
+
padX: 16,
|
|
12533
|
+
gap: 12,
|
|
12534
|
+
icon: 20,
|
|
12535
|
+
minW: 104,
|
|
12536
|
+
fieldMinW: 260,
|
|
12537
|
+
fontSize: 14,
|
|
12538
|
+
lineHeight: 24,
|
|
12539
|
+
radius: 6
|
|
12540
|
+
} : {
|
|
12541
|
+
padX: 12,
|
|
12542
|
+
gap: 8,
|
|
12543
|
+
icon: 16,
|
|
12544
|
+
minW: 80,
|
|
12545
|
+
fieldMinW: 216,
|
|
12546
|
+
fontSize: 12,
|
|
12547
|
+
lineHeight: 20,
|
|
12548
|
+
radius: 4
|
|
12549
|
+
};
|
|
12268
12550
|
const select = (r) => {
|
|
12269
12551
|
setPendingStart(null);
|
|
12270
12552
|
onValueChange?.(r);
|
|
@@ -12290,11 +12572,12 @@ function SDateRangePicker({
|
|
|
12290
12572
|
focused: open,
|
|
12291
12573
|
errorMessage: ruleError !== "" ? ruleError : errorMessage,
|
|
12292
12574
|
width,
|
|
12575
|
+
minWidth: dims.fieldMinW,
|
|
12293
12576
|
disabled,
|
|
12294
12577
|
className,
|
|
12295
12578
|
style,
|
|
12296
12579
|
children: /* @__PURE__ */ jsxs(
|
|
12297
|
-
|
|
12580
|
+
RPopover9.Root,
|
|
12298
12581
|
{
|
|
12299
12582
|
open,
|
|
12300
12583
|
onOpenChange: (o) => {
|
|
@@ -12303,7 +12586,7 @@ function SDateRangePicker({
|
|
|
12303
12586
|
if (!o) setPendingStart(null);
|
|
12304
12587
|
},
|
|
12305
12588
|
children: [
|
|
12306
|
-
/* @__PURE__ */ jsx(
|
|
12589
|
+
/* @__PURE__ */ jsx(RPopover9.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
12307
12590
|
"button",
|
|
12308
12591
|
{
|
|
12309
12592
|
type: "button",
|
|
@@ -12344,13 +12627,16 @@ function SDateRangePicker({
|
|
|
12344
12627
|
]
|
|
12345
12628
|
}
|
|
12346
12629
|
) }),
|
|
12347
|
-
/* @__PURE__ */ jsx(
|
|
12348
|
-
|
|
12630
|
+
/* @__PURE__ */ jsx(RPopover9.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
|
|
12631
|
+
RPopover9.Content,
|
|
12349
12632
|
{
|
|
12350
12633
|
side: "bottom",
|
|
12351
12634
|
align: "start",
|
|
12352
12635
|
sideOffset: 4,
|
|
12353
|
-
className: cn(
|
|
12636
|
+
className: cn(
|
|
12637
|
+
"z-50 max-w-[var(--radix-popover-content-available-width)]",
|
|
12638
|
+
FLOATING_SLIDE_ANIM
|
|
12639
|
+
),
|
|
12354
12640
|
children: /* @__PURE__ */ jsx(
|
|
12355
12641
|
RangeCalendar,
|
|
12356
12642
|
{
|
|
@@ -13338,7 +13624,7 @@ function SRadioButton({
|
|
|
13338
13624
|
disabled: od,
|
|
13339
13625
|
onClick: () => !od && !selected && onValueChange?.(o.value),
|
|
13340
13626
|
className: cn(
|
|
13341
|
-
"relative box-border inline-flex items-center justify-center whitespace-nowrap border border-solid text-[12px] font-medium leading-[20px] transition-colors",
|
|
13627
|
+
"relative box-border grow inline-flex items-center justify-center whitespace-nowrap border border-solid text-[12px] font-medium leading-[20px] transition-colors",
|
|
13342
13628
|
i === 0 ? "rounded-l-[var(--cmp-radioButton-radius)]" : "-ml-px",
|
|
13343
13629
|
i === options.length - 1 ? "rounded-r-[var(--cmp-radioButton-radius)]" : "",
|
|
13344
13630
|
selected ? "z-10" : "",
|
|
@@ -13360,66 +13646,1290 @@ function SRadioButton({
|
|
|
13360
13646
|
}
|
|
13361
13647
|
);
|
|
13362
13648
|
}
|
|
13363
|
-
var
|
|
13364
|
-
|
|
13649
|
+
var CHIPFILTER_LISTBOX_WIDTH = 240;
|
|
13650
|
+
var CHIPFILTER_DATE_PRESET_LISTBOX_WIDTH = 246;
|
|
13651
|
+
var CHIPFILTER = {
|
|
13652
|
+
barBg: "var(--cmp-chipFilter-bar-bg)",
|
|
13653
|
+
barBorder: "var(--cmp-chipFilter-bar-border)",
|
|
13654
|
+
barPaddingX: "var(--cmp-chipFilter-bar-paddingX)",
|
|
13655
|
+
barPaddingY: "var(--cmp-chipFilter-bar-paddingY)",
|
|
13656
|
+
barGap: "var(--cmp-chipFilter-bar-gap)",
|
|
13657
|
+
dividerHeight: "var(--cmp-chipFilter-divider-height)",
|
|
13658
|
+
chipHeight: "var(--cmp-chipFilter-chip-height)",
|
|
13659
|
+
chipRadius: "var(--cmp-chipFilter-chip-radius)",
|
|
13660
|
+
chipGap: "var(--cmp-chipFilter-chip-gap)",
|
|
13661
|
+
chipDefaultBg: "var(--cmp-chipFilter-chip-default-bg)",
|
|
13662
|
+
chipDefaultBorder: "var(--cmp-chipFilter-chip-default-border)",
|
|
13663
|
+
chipDefaultText: "var(--cmp-chipFilter-chip-default-text)",
|
|
13664
|
+
chipActiveBorder: "var(--cmp-chipFilter-chip-active-border)",
|
|
13665
|
+
chipWarningBorder: "var(--cmp-chipFilter-chip-warning-border)",
|
|
13666
|
+
chipAppliedBg: "var(--cmp-chipFilter-chip-applied-bg)",
|
|
13667
|
+
chipAppliedBorder: "var(--cmp-chipFilter-chip-applied-border)",
|
|
13668
|
+
chipAppliedLabel: "var(--cmp-chipFilter-chip-applied-text-label)",
|
|
13669
|
+
chipAppliedValue: "var(--color-brilliantblue-80)",
|
|
13670
|
+
chipDisabledBg: "var(--cmp-chipFilter-chip-disabled-bg)",
|
|
13671
|
+
chipDisabledBorder: "var(--cmp-chipFilter-chip-disabled-border)",
|
|
13672
|
+
chipDisabledText: "var(--cmp-chipFilter-chip-disabled-text)",
|
|
13673
|
+
addBorder: "var(--cmp-chipFilter-addButton-border-default)",
|
|
13674
|
+
addBorderDisabled: "var(--cmp-chipFilter-addButton-border-disabled)",
|
|
13675
|
+
addText: "var(--cmp-chipFilter-addButton-text-default)",
|
|
13676
|
+
addTextDisabled: "var(--cmp-chipFilter-addButton-text-disabled)",
|
|
13677
|
+
listboxBg: "var(--cmp-chipFilter-listbox-bg)",
|
|
13678
|
+
listboxBorder: "var(--cmp-chipFilter-listbox-border-color)",
|
|
13679
|
+
listboxRadius: "var(--cmp-chipFilter-listbox-radius)",
|
|
13680
|
+
listboxLabel: "var(--cmp-chipFilter-listbox-top-label-color)",
|
|
13681
|
+
listboxBottomDividerHeight: "var(--cmp-chipFilter-listbox-bottom-divider-height)",
|
|
13682
|
+
itemPaddingLeft: "var(--cmp-chipFilter-item-paddingLeft)",
|
|
13683
|
+
itemPaddingRight: "var(--cmp-chipFilter-item-paddingRight)",
|
|
13684
|
+
itemPaddingY: "var(--cmp-chipFilter-item-paddingY)",
|
|
13685
|
+
itemMultiPaddingX: "var(--cmp-chipFilter-item-multi-paddingX)",
|
|
13686
|
+
itemTextDefault: "var(--cmp-chipFilter-item-text-default)",
|
|
13687
|
+
itemTextSelected: "var(--cmp-chipFilter-item-text-selected)"
|
|
13688
|
+
};
|
|
13689
|
+
var isKeywordValue = (value) => typeof value === "object" && value != null && !Array.isArray(value) && "keywords" in value;
|
|
13690
|
+
var keywordEntries = (value) => {
|
|
13691
|
+
if (isKeywordValue(value)) return value.keywords;
|
|
13692
|
+
if (Array.isArray(value)) {
|
|
13693
|
+
return value.filter((v) => typeof v === "string");
|
|
13694
|
+
}
|
|
13695
|
+
return [];
|
|
13696
|
+
};
|
|
13697
|
+
var isEmptyValue = (value) => {
|
|
13698
|
+
if (value == null) return true;
|
|
13699
|
+
if (Array.isArray(value)) return value.length === 0 || value.every((v) => v == null || v === "");
|
|
13700
|
+
if (isKeywordValue(value)) return value.keywords.length === 0;
|
|
13701
|
+
return value === "";
|
|
13702
|
+
};
|
|
13703
|
+
var normalizeValues = (value) => value ?? {};
|
|
13704
|
+
var toArrayValue = (value) => Array.isArray(value) ? value.filter(
|
|
13705
|
+
(v) => typeof v === "string" || typeof v === "number"
|
|
13706
|
+
) : [];
|
|
13707
|
+
var todayIso = () => {
|
|
13708
|
+
const d = /* @__PURE__ */ new Date();
|
|
13709
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
13710
|
+
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
|
13711
|
+
};
|
|
13712
|
+
var isInlineDateField = (field) => field.type === "date" && field.radioButton === true && (field.presets?.length ?? 0) > 0;
|
|
13713
|
+
var resolveFieldDefault = (field) => {
|
|
13714
|
+
if (field.defaultValue !== void 0) return field.defaultValue;
|
|
13715
|
+
if (isInlineDateField(field)) return todayIso();
|
|
13716
|
+
if (!field.required) return void 0;
|
|
13717
|
+
if (field.type === "single") return field.options?.[0]?.value;
|
|
13718
|
+
if (field.type === "date") return todayIso();
|
|
13719
|
+
return void 0;
|
|
13720
|
+
};
|
|
13721
|
+
var valuesEqual = (a, b) => {
|
|
13722
|
+
if (isKeywordValue(a) || isKeywordValue(b)) {
|
|
13723
|
+
return isKeywordValue(a) && isKeywordValue(b) && a.mode === b.mode && valuesEqual(a.keywords, b.keywords);
|
|
13724
|
+
}
|
|
13725
|
+
if (Array.isArray(a) || Array.isArray(b)) {
|
|
13726
|
+
return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((v, i) => v === b[i]);
|
|
13727
|
+
}
|
|
13728
|
+
return a === b;
|
|
13729
|
+
};
|
|
13730
|
+
var valuesMapEqual = (a, b) => {
|
|
13731
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)]);
|
|
13732
|
+
for (const key of keys) {
|
|
13733
|
+
if (!valuesEqual(a[key], b[key])) return false;
|
|
13734
|
+
}
|
|
13735
|
+
return true;
|
|
13736
|
+
};
|
|
13737
|
+
var isAtDefaultValue = (field, value) => {
|
|
13738
|
+
const def = resolveFieldDefault(field);
|
|
13739
|
+
return def !== void 0 && valuesEqual(value, def);
|
|
13740
|
+
};
|
|
13741
|
+
var isInlineField = (field) => isInlineDateField(field) || field.type === "custom";
|
|
13742
|
+
var isGroupedFields = (fields) => fields.length > 0 && "fields" in fields[0];
|
|
13743
|
+
var isGroupSatisfied = (group, values) => {
|
|
13744
|
+
if (!group.rule) return true;
|
|
13745
|
+
const keys = group.fields.map((f) => f.key);
|
|
13746
|
+
if (group.rule.type === "requireKey") return !isEmptyValue(values[group.rule.key]);
|
|
13747
|
+
if (group.rule.type === "requireAll") return keys.every((k) => !isEmptyValue(values[k]));
|
|
13748
|
+
if (group.rule.type === "requireAny") return keys.some((k) => !isEmptyValue(values[k]));
|
|
13749
|
+
return true;
|
|
13750
|
+
};
|
|
13751
|
+
var koreanParticle = (word, consonant, vowel) => {
|
|
13752
|
+
const code = word.charCodeAt(word.length - 1);
|
|
13753
|
+
if (code < 44032 || code > 55203) return consonant;
|
|
13754
|
+
return (code - 44032) % 28 === 0 ? vowel : consonant;
|
|
13755
|
+
};
|
|
13756
|
+
var defaultGroupTooltipMessage = (rule, fields) => {
|
|
13757
|
+
if (rule.type === "requireAll") return "\uD56D\uBAA9\uC744 \uBAA8\uB450 \uC120\uD0DD\uD574 \uC8FC\uC138\uC694.";
|
|
13758
|
+
if (rule.type === "requireAny") {
|
|
13759
|
+
const name = rule.dataGroupName;
|
|
13760
|
+
if (!name) return "\uCD5C\uC18C 1\uAC1C\uC758 \uD544\uD130\uB97C \uC120\uD0DD\uD574\uC8FC\uC138\uC694.";
|
|
13761
|
+
return `\uCD5C\uC18C 1\uAC1C\uC758 ${name}${koreanParticle(name, "\uC744", "\uB97C")} \uC120\uD0DD\uD574\uC8FC\uC138\uC694.`;
|
|
13762
|
+
}
|
|
13763
|
+
const label = fields.find((f) => f.key === rule.key)?.label ?? "\uD56D\uBAA9";
|
|
13764
|
+
return `${label}${koreanParticle(label, "\uC744", "\uB97C")} \uC120\uD0DD\uD574 \uC8FC\uC138\uC694.`;
|
|
13765
|
+
};
|
|
13766
|
+
var matchPresetId = (presets, value) => {
|
|
13767
|
+
if (isEmptyValue(value)) return null;
|
|
13768
|
+
for (const preset of presets) {
|
|
13769
|
+
if (preset.custom || !preset.resolve) continue;
|
|
13770
|
+
const resolved = preset.resolve();
|
|
13771
|
+
if (Array.isArray(resolved) && Array.isArray(value)) {
|
|
13772
|
+
if (resolved[0] === value[0] && resolved[1] === value[1]) return preset.value;
|
|
13773
|
+
} else if (!Array.isArray(resolved) && !Array.isArray(value) && resolved === value) {
|
|
13774
|
+
return preset.value;
|
|
13775
|
+
}
|
|
13776
|
+
}
|
|
13777
|
+
return presets.find((preset) => preset.custom)?.value ?? null;
|
|
13778
|
+
};
|
|
13779
|
+
var optionLabel = (field, value) => field.options?.find((option) => option.value === value)?.label ?? String(value);
|
|
13780
|
+
var formatValueList = (labels) => {
|
|
13781
|
+
if (labels.length <= 1) return labels[0] ?? "";
|
|
13782
|
+
return `${labels[0]} \uC678 ${labels.length - 1}\uAC1C`;
|
|
13783
|
+
};
|
|
13784
|
+
var displayValue = (field, value) => {
|
|
13785
|
+
if (isEmptyValue(value)) return "";
|
|
13786
|
+
if (field.type === "multi")
|
|
13787
|
+
return formatValueList(toArrayValue(value).map((v) => optionLabel(field, v)));
|
|
13788
|
+
if (field.type === "single") return optionLabel(field, value);
|
|
13789
|
+
if (field.type === "date")
|
|
13790
|
+
return Array.isArray(value) ? `${value[0]} ~ ${value[1]}` : String(value);
|
|
13791
|
+
if (field.type === "keyword") return formatValueList(keywordEntries(value));
|
|
13792
|
+
return String(value);
|
|
13793
|
+
};
|
|
13794
|
+
var chipDisplayValue = (field, value) => {
|
|
13795
|
+
const text = displayValue(field, value);
|
|
13796
|
+
if (field.type !== "date" || isEmptyValue(value)) return text;
|
|
13797
|
+
const presets = field.presets ?? [];
|
|
13798
|
+
if (presets.length === 0) return text;
|
|
13799
|
+
const preset = presets.find((p) => p.value === matchPresetId(presets, value));
|
|
13800
|
+
return preset && !preset.custom ? `${preset.label}(${text})` : text;
|
|
13801
|
+
};
|
|
13802
|
+
var SChipFilter = /* @__PURE__ */ forwardRef(function SChipFilter2({
|
|
13803
|
+
fields: fieldsProp = [],
|
|
13804
|
+
value,
|
|
13365
13805
|
onValueChange,
|
|
13366
|
-
|
|
13367
|
-
|
|
13368
|
-
|
|
13369
|
-
|
|
13370
|
-
|
|
13371
|
-
|
|
13806
|
+
onFilterChange,
|
|
13807
|
+
onSearch,
|
|
13808
|
+
activeKeys,
|
|
13809
|
+
onActiveKeysChange,
|
|
13810
|
+
onReset,
|
|
13811
|
+
onAddFilter,
|
|
13812
|
+
label = "\uAC80\uC0C9 \uD544\uD130",
|
|
13813
|
+
showLabel = false,
|
|
13814
|
+
showAddButton = true,
|
|
13815
|
+
showReset = true,
|
|
13372
13816
|
disabled = false,
|
|
13373
|
-
placeholder = "\uD0DC\uADF8 \uC785\uB825 (Enter\uB85C \uB4F1\uB85D / \uCF64\uB9C8\uB85C \uAD6C\uBD84 / \uB744\uC5B4\uC4F0\uAE30 \uBD88\uAC00)",
|
|
13374
|
-
name,
|
|
13375
|
-
rules,
|
|
13376
|
-
error,
|
|
13377
|
-
useReset = false,
|
|
13378
|
-
maxCount,
|
|
13379
|
-
metaPlacement = "end",
|
|
13380
|
-
duplicateLabel,
|
|
13381
|
-
suggestions = [],
|
|
13382
|
-
loadingSuggestions = false,
|
|
13383
|
-
recommendedItems = [],
|
|
13384
|
-
loadingRecommendedItems = false,
|
|
13385
|
-
dropdownMinWidth = 200,
|
|
13386
|
-
label,
|
|
13387
|
-
labelWidth,
|
|
13388
|
-
hint,
|
|
13389
|
-
errorMessage,
|
|
13390
|
-
width,
|
|
13391
|
-
status,
|
|
13392
|
-
icon,
|
|
13393
|
-
iconColor,
|
|
13394
|
-
labelTooltip,
|
|
13395
|
-
labelTooltipProps,
|
|
13396
13817
|
className,
|
|
13397
13818
|
style
|
|
13398
13819
|
}, ref) {
|
|
13399
|
-
const
|
|
13400
|
-
const
|
|
13401
|
-
|
|
13402
|
-
|
|
13403
|
-
|
|
13404
|
-
const
|
|
13405
|
-
const
|
|
13406
|
-
const
|
|
13407
|
-
const
|
|
13408
|
-
|
|
13409
|
-
|
|
13410
|
-
const
|
|
13411
|
-
|
|
13412
|
-
const
|
|
13413
|
-
|
|
13414
|
-
|
|
13415
|
-
|
|
13416
|
-
|
|
13417
|
-
const
|
|
13418
|
-
|
|
13419
|
-
|
|
13420
|
-
|
|
13421
|
-
|
|
13422
|
-
|
|
13820
|
+
const usingGroupedFields = isGroupedFields(fieldsProp);
|
|
13821
|
+
const groups = useMemo(
|
|
13822
|
+
() => usingGroupedFields ? fieldsProp : [{ fields: fieldsProp }],
|
|
13823
|
+
[usingGroupedFields, fieldsProp]
|
|
13824
|
+
);
|
|
13825
|
+
const fields = useMemo(() => groups.flatMap((group) => group.fields), [groups]);
|
|
13826
|
+
const values = normalizeValues(value);
|
|
13827
|
+
const portalContainer = usePortalContainer();
|
|
13828
|
+
const [internalActiveKeys, setInternalActiveKeys] = useState(
|
|
13829
|
+
() => fields.filter((field) => field.defaultActive !== false).map((field) => field.key)
|
|
13830
|
+
);
|
|
13831
|
+
const [openKey, setOpenKey] = useState(null);
|
|
13832
|
+
const [addOpen, setAddOpen] = useState(false);
|
|
13833
|
+
const triggerRefs = useRef(/* @__PURE__ */ new Map());
|
|
13834
|
+
const initializedDefaultsRef = useRef(/* @__PURE__ */ new Set());
|
|
13835
|
+
const prevOpenKeyRef = useRef(null);
|
|
13836
|
+
const valuesRef = useRef(values);
|
|
13837
|
+
valuesRef.current = values;
|
|
13838
|
+
const lastSearchedValuesRef = useRef(values);
|
|
13839
|
+
const invalidGroups = useMemo(() => {
|
|
13840
|
+
const invalid = /* @__PURE__ */ new Set();
|
|
13841
|
+
groups.forEach((group, groupIndex) => {
|
|
13842
|
+
if (!isGroupSatisfied(group, values)) invalid.add(groupIndex);
|
|
13843
|
+
});
|
|
13844
|
+
return invalid;
|
|
13845
|
+
}, [groups, values]);
|
|
13846
|
+
const isGroupsValid = useCallback(
|
|
13847
|
+
(current) => groups.every((group) => isGroupSatisfied(group, current)),
|
|
13848
|
+
[groups]
|
|
13849
|
+
);
|
|
13850
|
+
const runSearch = useCallback(
|
|
13851
|
+
(next) => {
|
|
13852
|
+
if (valuesMapEqual(lastSearchedValuesRef.current, next)) return;
|
|
13853
|
+
if (!isGroupsValid(next)) return;
|
|
13854
|
+
lastSearchedValuesRef.current = next;
|
|
13855
|
+
onSearch?.(next);
|
|
13856
|
+
},
|
|
13857
|
+
[isGroupsValid, onSearch]
|
|
13858
|
+
);
|
|
13859
|
+
useEffect(() => {
|
|
13860
|
+
const prevKey = prevOpenKeyRef.current;
|
|
13861
|
+
if (prevKey != null && prevKey !== openKey) {
|
|
13862
|
+
runSearch(valuesRef.current);
|
|
13863
|
+
}
|
|
13864
|
+
prevOpenKeyRef.current = openKey;
|
|
13865
|
+
}, [openKey, runSearch]);
|
|
13866
|
+
useEffect(() => {
|
|
13867
|
+
if (activeKeys) return;
|
|
13868
|
+
setInternalActiveKeys((current) => {
|
|
13869
|
+
const known = new Set(fields.map((field) => field.key));
|
|
13870
|
+
const kept = current.filter((key) => known.has(key));
|
|
13871
|
+
const additions = fields.filter((field) => field.defaultActive !== false && !kept.includes(field.key)).map((field) => field.key);
|
|
13872
|
+
return [...kept, ...additions];
|
|
13873
|
+
});
|
|
13874
|
+
}, [activeKeys, fields]);
|
|
13875
|
+
useEffect(() => {
|
|
13876
|
+
const patch = {};
|
|
13877
|
+
let changed = false;
|
|
13878
|
+
fields.forEach((field) => {
|
|
13879
|
+
if (initializedDefaultsRef.current.has(field.key)) return;
|
|
13880
|
+
if (!isEmptyValue(values[field.key])) {
|
|
13881
|
+
initializedDefaultsRef.current.add(field.key);
|
|
13882
|
+
return;
|
|
13883
|
+
}
|
|
13884
|
+
const def = resolveFieldDefault(field);
|
|
13885
|
+
if (def === void 0) return;
|
|
13886
|
+
patch[field.key] = def;
|
|
13887
|
+
initializedDefaultsRef.current.add(field.key);
|
|
13888
|
+
changed = true;
|
|
13889
|
+
});
|
|
13890
|
+
if (changed) onValueChange?.({ ...values, ...patch });
|
|
13891
|
+
}, [fields, values, onValueChange]);
|
|
13892
|
+
const resolvedActiveKeys = activeKeys ?? internalActiveKeys;
|
|
13893
|
+
const activeFields = fields.filter((field) => resolvedActiveKeys.includes(field.key));
|
|
13894
|
+
const inactiveFields = fields.filter((field) => !resolvedActiveKeys.includes(field.key));
|
|
13895
|
+
const groupIndexByKey = /* @__PURE__ */ new Map();
|
|
13896
|
+
groups.forEach((group, groupIndex) => {
|
|
13897
|
+
group.fields.forEach((field) => groupIndexByKey.set(field.key, groupIndex));
|
|
13898
|
+
});
|
|
13899
|
+
const hasValue = fields.some((field) => !isEmptyValue(values[field.key]));
|
|
13900
|
+
const hasRightActions = showAddButton || showReset;
|
|
13901
|
+
const currentOpenField = fields.find((field) => field.key === openKey);
|
|
13902
|
+
const editorPopoverStyle = useMemo(() => {
|
|
13903
|
+
if (currentOpenField?.type === "keyword") {
|
|
13904
|
+
return { width: CHIPFILTER_LISTBOX_WIDTH };
|
|
13905
|
+
}
|
|
13906
|
+
if (currentOpenField?.type === "date" && (currentOpenField.presets?.length ?? 0) > 0) {
|
|
13907
|
+
return { width: CHIPFILTER_DATE_PRESET_LISTBOX_WIDTH };
|
|
13908
|
+
}
|
|
13909
|
+
return { width: CHIPFILTER_LISTBOX_WIDTH };
|
|
13910
|
+
}, [currentOpenField?.type, currentOpenField?.presets?.length]);
|
|
13911
|
+
const setActive = (next) => {
|
|
13912
|
+
if (!activeKeys) setInternalActiveKeys(next);
|
|
13913
|
+
onActiveKeysChange?.(next);
|
|
13914
|
+
};
|
|
13915
|
+
const emitValue = (key, nextValue) => {
|
|
13916
|
+
const next = { ...values, [key]: nextValue };
|
|
13917
|
+
onValueChange?.(next);
|
|
13918
|
+
onFilterChange?.({ key, value: nextValue, values: next });
|
|
13919
|
+
return next;
|
|
13920
|
+
};
|
|
13921
|
+
const emitValueAndSearch = (key, nextValue) => {
|
|
13922
|
+
runSearch(emitValue(key, nextValue));
|
|
13923
|
+
};
|
|
13924
|
+
const clearValue = (key) => {
|
|
13925
|
+
const field = fields.find((f) => f.key === key);
|
|
13926
|
+
const def = field ? resolveFieldDefault(field) : void 0;
|
|
13927
|
+
runSearch(emitValue(key, def !== void 0 ? def : null));
|
|
13928
|
+
};
|
|
13929
|
+
const reset = useCallback(() => {
|
|
13930
|
+
const next = fields.reduce((acc, field) => {
|
|
13931
|
+
const def = resolveFieldDefault(field);
|
|
13932
|
+
acc[field.key] = def !== void 0 ? def : null;
|
|
13933
|
+
return acc;
|
|
13934
|
+
}, {});
|
|
13935
|
+
onValueChange?.(next);
|
|
13936
|
+
runSearch(next);
|
|
13937
|
+
onReset?.();
|
|
13938
|
+
}, [fields, onReset, onValueChange, runSearch]);
|
|
13939
|
+
const open = useCallback(
|
|
13940
|
+
(key) => {
|
|
13941
|
+
const field = fields.find((f) => f.key === key);
|
|
13942
|
+
if (!field || isInlineField(field)) return;
|
|
13943
|
+
setOpenKey(key);
|
|
13944
|
+
},
|
|
13945
|
+
[fields]
|
|
13946
|
+
);
|
|
13947
|
+
const validate = useCallback(() => invalidGroups.size === 0, [invalidGroups]);
|
|
13948
|
+
useImperativeHandle(ref, () => ({ open, reset, validate }), [open, reset, validate]);
|
|
13949
|
+
const addField = (key) => {
|
|
13950
|
+
const next = [...resolvedActiveKeys, key];
|
|
13951
|
+
setActive(next);
|
|
13952
|
+
onAddFilter?.(key);
|
|
13953
|
+
setAddOpen(false);
|
|
13954
|
+
const field = fields.find((f) => f.key === key);
|
|
13955
|
+
if (field && !isInlineField(field)) requestAnimationFrame(() => setOpenKey(key));
|
|
13956
|
+
};
|
|
13957
|
+
const rootStyle = useMemo(
|
|
13958
|
+
() => ({
|
|
13959
|
+
"--chipfilter-bar-bg": CHIPFILTER.barBg,
|
|
13960
|
+
"--chipfilter-bar-border": CHIPFILTER.barBorder,
|
|
13961
|
+
"--chipfilter-bar-padding-x": CHIPFILTER.barPaddingX,
|
|
13962
|
+
"--chipfilter-bar-padding-y": CHIPFILTER.barPaddingY,
|
|
13963
|
+
"--chipfilter-bar-gap": CHIPFILTER.barGap,
|
|
13964
|
+
"--chipfilter-divider-height": CHIPFILTER.dividerHeight,
|
|
13965
|
+
...style
|
|
13966
|
+
}),
|
|
13967
|
+
[style]
|
|
13968
|
+
);
|
|
13969
|
+
return /* @__PURE__ */ jsxs(
|
|
13970
|
+
"div",
|
|
13971
|
+
{
|
|
13972
|
+
className: cn(
|
|
13973
|
+
"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)]",
|
|
13974
|
+
className
|
|
13975
|
+
),
|
|
13976
|
+
style: { ...rootStyle, borderColor: "var(--chipfilter-bar-border)" },
|
|
13977
|
+
children: [
|
|
13978
|
+
showLabel && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
13979
|
+
/* @__PURE__ */ jsx(STag, { className: "shrink-0", shape: "square", size: "sm", color: "darkblue", label }),
|
|
13980
|
+
/* @__PURE__ */ jsx(Divider, { top: true })
|
|
13981
|
+
] }),
|
|
13982
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-wrap items-center gap-[var(--cmp-chipFilter-chip-group)]", children: [
|
|
13983
|
+
(() => {
|
|
13984
|
+
const nodes = [];
|
|
13985
|
+
let runBuffer = [];
|
|
13986
|
+
let runGroupIndex = null;
|
|
13987
|
+
const flushRun = () => {
|
|
13988
|
+
if (runBuffer.length === 0) return;
|
|
13989
|
+
const group = runGroupIndex != null ? groups[runGroupIndex] : void 0;
|
|
13990
|
+
const message = usingGroupedFields && group?.rule ? group.tooltipMessage ?? defaultGroupTooltipMessage(group.rule, group.fields) : void 0;
|
|
13991
|
+
if (message) {
|
|
13992
|
+
nodes.push(
|
|
13993
|
+
/* @__PURE__ */ jsx(
|
|
13994
|
+
GroupTooltip,
|
|
13995
|
+
{
|
|
13996
|
+
message,
|
|
13997
|
+
open: invalidGroups.has(runGroupIndex),
|
|
13998
|
+
children: runBuffer
|
|
13999
|
+
},
|
|
14000
|
+
`group-${runGroupIndex}`
|
|
14001
|
+
)
|
|
14002
|
+
);
|
|
14003
|
+
} else {
|
|
14004
|
+
nodes.push(...runBuffer);
|
|
14005
|
+
}
|
|
14006
|
+
runBuffer = [];
|
|
14007
|
+
};
|
|
14008
|
+
activeFields.forEach((field, index) => {
|
|
14009
|
+
const inline = isInlineField(field);
|
|
14010
|
+
const groupIndex = groupIndexByKey.get(field.key) ?? 0;
|
|
14011
|
+
const warning = field.warning || invalidGroups.has(groupIndex);
|
|
14012
|
+
const prevField = index > 0 ? activeFields[index - 1] : null;
|
|
14013
|
+
const prevGroupIndex = prevField ? groupIndexByKey.get(prevField.key) ?? 0 : null;
|
|
14014
|
+
const needsLeadingDivider = index === 0 ? false : inline || prevField != null && isInlineField(prevField) || groupIndex !== prevGroupIndex;
|
|
14015
|
+
if (groupIndex !== runGroupIndex) {
|
|
14016
|
+
flushRun();
|
|
14017
|
+
runGroupIndex = groupIndex;
|
|
14018
|
+
}
|
|
14019
|
+
const showClear = !isAtDefaultValue(field, values[field.key]);
|
|
14020
|
+
const node = isInlineDateField(field) ? /* @__PURE__ */ jsx(
|
|
14021
|
+
InlineDatePresetFilter,
|
|
14022
|
+
{
|
|
14023
|
+
field,
|
|
14024
|
+
value: values[field.key],
|
|
14025
|
+
disabled: disabled || field.disabled,
|
|
14026
|
+
warning,
|
|
14027
|
+
showClear,
|
|
14028
|
+
onValueChange: (next) => emitValueAndSearch(field.key, next),
|
|
14029
|
+
onClear: () => clearValue(field.key)
|
|
14030
|
+
},
|
|
14031
|
+
field.key
|
|
14032
|
+
) : field.type === "custom" ? /* @__PURE__ */ jsx(Fragment$1, { children: field.render?.({
|
|
14033
|
+
value: values[field.key],
|
|
14034
|
+
disabled: disabled || field.disabled,
|
|
14035
|
+
warning,
|
|
14036
|
+
onValueChange: (next) => emitValueAndSearch(field.key, next)
|
|
14037
|
+
}) }, field.key) : /* @__PURE__ */ jsx(
|
|
14038
|
+
FilterChip,
|
|
14039
|
+
{
|
|
14040
|
+
field,
|
|
14041
|
+
valueText: chipDisplayValue(field, values[field.key]),
|
|
14042
|
+
active: openKey === field.key,
|
|
14043
|
+
applied: !isEmptyValue(values[field.key]),
|
|
14044
|
+
disabled: disabled || field.disabled,
|
|
14045
|
+
warning,
|
|
14046
|
+
showClear,
|
|
14047
|
+
refCallback: (node2) => triggerRefs.current.set(field.key, node2),
|
|
14048
|
+
onOpen: () => setOpenKey(openKey === field.key ? null : field.key),
|
|
14049
|
+
onClear: () => clearValue(field.key)
|
|
14050
|
+
},
|
|
14051
|
+
field.key
|
|
14052
|
+
);
|
|
14053
|
+
runBuffer.push(
|
|
14054
|
+
needsLeadingDivider ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
14055
|
+
/* @__PURE__ */ jsx(Divider, { inset: true }),
|
|
14056
|
+
node
|
|
14057
|
+
] }, `${field.key}-wrap`) : node
|
|
14058
|
+
);
|
|
14059
|
+
});
|
|
14060
|
+
flushRun();
|
|
14061
|
+
return nodes;
|
|
14062
|
+
})(),
|
|
14063
|
+
(() => {
|
|
14064
|
+
const lastField = activeFields[activeFields.length - 1];
|
|
14065
|
+
const needsTrailingDivider = lastField != null && isInlineField(lastField) && !hasRightActions;
|
|
14066
|
+
return needsTrailingDivider ? /* @__PURE__ */ jsx(Divider, { inset: true }) : null;
|
|
14067
|
+
})(),
|
|
14068
|
+
hasRightActions && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
14069
|
+
/* @__PURE__ */ jsx(Divider, { inset: true }),
|
|
14070
|
+
showAddButton && /* @__PURE__ */ jsxs(RPopover9.Root, { open: addOpen, onOpenChange: setAddOpen, children: [
|
|
14071
|
+
/* @__PURE__ */ jsx(RPopover9.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
14072
|
+
"button",
|
|
14073
|
+
{
|
|
14074
|
+
type: "button",
|
|
14075
|
+
disabled: disabled || inactiveFields.length === 0,
|
|
14076
|
+
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",
|
|
14077
|
+
style: {
|
|
14078
|
+
minHeight: "var(--cmp-chipFilter-addButton-height)" ,
|
|
14079
|
+
borderRadius: "var(--cmp-chipFilter-addButton-radius)" ,
|
|
14080
|
+
borderColor: disabled || inactiveFields.length === 0 ? CHIPFILTER.addBorderDisabled : CHIPFILTER.addBorder,
|
|
14081
|
+
color: disabled || inactiveFields.length === 0 ? CHIPFILTER.addTextDisabled : CHIPFILTER.addText
|
|
14082
|
+
},
|
|
14083
|
+
children: [
|
|
14084
|
+
/* @__PURE__ */ jsx(
|
|
14085
|
+
SIcon,
|
|
14086
|
+
{
|
|
14087
|
+
name: "add",
|
|
14088
|
+
size: 12,
|
|
14089
|
+
color: disabled || inactiveFields.length === 0 ? CHIPFILTER.addTextDisabled : CHIPFILTER.addText
|
|
14090
|
+
}
|
|
14091
|
+
),
|
|
14092
|
+
/* @__PURE__ */ jsx("span", { children: "\uD544\uD130 \uCD94\uAC00" })
|
|
14093
|
+
]
|
|
14094
|
+
}
|
|
14095
|
+
) }),
|
|
14096
|
+
/* @__PURE__ */ jsx(RPopover9.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
|
|
14097
|
+
RPopover9.Content,
|
|
14098
|
+
{
|
|
14099
|
+
side: "bottom",
|
|
14100
|
+
align: "start",
|
|
14101
|
+
sideOffset: 4,
|
|
14102
|
+
className: cn("z-50 min-w-[180px]", FLOATING_SLIDE_ANIM),
|
|
14103
|
+
children: /* @__PURE__ */ jsx(ListBox, { children: inactiveFields.length > 0 ? inactiveFields.map((field) => /* @__PURE__ */ jsx(MenuItem, { onClick: () => addField(field.key), children: field.label }, field.key)) : /* @__PURE__ */ jsx(EmptyItem, { children: "\uCD94\uAC00\uD560 \uD544\uD130\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4." }) })
|
|
14104
|
+
}
|
|
14105
|
+
) })
|
|
14106
|
+
] }),
|
|
14107
|
+
showReset && /* @__PURE__ */ jsxs(
|
|
14108
|
+
"button",
|
|
14109
|
+
{
|
|
14110
|
+
type: "button",
|
|
14111
|
+
disabled: disabled || !hasValue,
|
|
14112
|
+
onClick: reset,
|
|
14113
|
+
className: cn(
|
|
14114
|
+
"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",
|
|
14115
|
+
// 부모 flex gap(6px)은 칩 사이 간격 기준이라, 필터 추가 버튼과의 12px 간격을 맞추려면
|
|
14116
|
+
// 부족한 만큼(12px - gap)을 추가로 띄운다. 필터 추가가 없을 땐 divider와 이미 12px이라 불필요.
|
|
14117
|
+
showAddButton && "ml-[calc(12px-var(--cmp-chipFilter-chip-group))]"
|
|
14118
|
+
),
|
|
14119
|
+
style: {
|
|
14120
|
+
color: disabled || !hasValue ? "var(--cmp-textLink-content-disabled)" : "var(--cmp-textLink-content-default)"
|
|
14121
|
+
},
|
|
14122
|
+
children: [
|
|
14123
|
+
/* @__PURE__ */ jsx(
|
|
14124
|
+
SIcon,
|
|
14125
|
+
{
|
|
14126
|
+
name: "reset",
|
|
14127
|
+
size: 16,
|
|
14128
|
+
color: disabled || !hasValue ? "var(--cmp-textLink-icon-disabled)" : "var(--cmp-textLink-icon-default)"
|
|
14129
|
+
}
|
|
14130
|
+
),
|
|
14131
|
+
/* @__PURE__ */ jsx("span", { children: "\uAC80\uC0C9 \uCD08\uAE30\uD654" })
|
|
14132
|
+
]
|
|
14133
|
+
}
|
|
14134
|
+
)
|
|
14135
|
+
] })
|
|
14136
|
+
] }),
|
|
14137
|
+
/* @__PURE__ */ jsxs(RPopover9.Root, { open: openKey != null, onOpenChange: (next) => !next && setOpenKey(null), children: [
|
|
14138
|
+
/* @__PURE__ */ jsx(
|
|
14139
|
+
RPopover9.Anchor,
|
|
14140
|
+
{
|
|
14141
|
+
virtualRef: {
|
|
14142
|
+
current: openKey ? triggerRefs.current.get(openKey) : null
|
|
14143
|
+
}
|
|
14144
|
+
}
|
|
14145
|
+
),
|
|
14146
|
+
/* @__PURE__ */ jsx(RPopover9.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
|
|
14147
|
+
RPopover9.Content,
|
|
14148
|
+
{
|
|
14149
|
+
side: "bottom",
|
|
14150
|
+
align: "start",
|
|
14151
|
+
sideOffset: 4,
|
|
14152
|
+
onOpenAutoFocus: (event) => event.preventDefault(),
|
|
14153
|
+
className: cn("z-50", FLOATING_SLIDE_ANIM),
|
|
14154
|
+
style: editorPopoverStyle,
|
|
14155
|
+
children: currentOpenField && /* @__PURE__ */ jsx(
|
|
14156
|
+
EditorPanel,
|
|
14157
|
+
{
|
|
14158
|
+
field: currentOpenField,
|
|
14159
|
+
value: values[currentOpenField.key],
|
|
14160
|
+
disabled: disabled || currentOpenField.disabled,
|
|
14161
|
+
onValueChange: (next) => emitValue(currentOpenField.key, next),
|
|
14162
|
+
onClose: () => setOpenKey(null)
|
|
14163
|
+
}
|
|
14164
|
+
)
|
|
14165
|
+
}
|
|
14166
|
+
) })
|
|
14167
|
+
] })
|
|
14168
|
+
]
|
|
14169
|
+
}
|
|
14170
|
+
);
|
|
14171
|
+
});
|
|
14172
|
+
function Divider({ inset, top } = {}) {
|
|
14173
|
+
return /* @__PURE__ */ jsx(
|
|
14174
|
+
"span",
|
|
14175
|
+
{
|
|
14176
|
+
"aria-hidden": true,
|
|
14177
|
+
className: cn(
|
|
14178
|
+
"inline-flex w-px shrink-0 bg-[var(--chipfilter-bar-border)]",
|
|
14179
|
+
top ? "mt-[2px] self-start" : "my-auto",
|
|
14180
|
+
inset && "mx-[calc(12px-var(--cmp-chipFilter-chip-group))]"
|
|
14181
|
+
),
|
|
14182
|
+
style: { height: "var(--chipfilter-divider-height)" }
|
|
14183
|
+
}
|
|
14184
|
+
);
|
|
14185
|
+
}
|
|
14186
|
+
function GroupTooltip({
|
|
14187
|
+
message,
|
|
14188
|
+
open,
|
|
14189
|
+
children
|
|
14190
|
+
}) {
|
|
14191
|
+
return /* @__PURE__ */ jsx(STooltip2, { trigger: "none", open, placement: "top", tooltipType: "warning", message: [message], children: /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-[var(--cmp-chipFilter-chip-group)]", children }) });
|
|
14192
|
+
}
|
|
14193
|
+
function FilterChip({
|
|
14194
|
+
field,
|
|
14195
|
+
valueText,
|
|
14196
|
+
active,
|
|
14197
|
+
applied,
|
|
14198
|
+
disabled,
|
|
14199
|
+
warning,
|
|
14200
|
+
showClear,
|
|
14201
|
+
refCallback,
|
|
14202
|
+
onOpen,
|
|
14203
|
+
onClear
|
|
14204
|
+
}) {
|
|
14205
|
+
const border = disabled ? CHIPFILTER.chipDisabledBorder : warning ? CHIPFILTER.chipWarningBorder : applied ? active ? "var(--color-blue-strong)" : CHIPFILTER.chipAppliedBorder : active ? CHIPFILTER.chipActiveBorder : CHIPFILTER.chipDefaultBorder;
|
|
14206
|
+
const background = disabled ? CHIPFILTER.chipDisabledBg : applied ? CHIPFILTER.chipAppliedBg : CHIPFILTER.chipDefaultBg;
|
|
14207
|
+
const textColor = disabled ? CHIPFILTER.chipDisabledText : CHIPFILTER.chipDefaultText;
|
|
14208
|
+
return /* @__PURE__ */ jsxs(
|
|
14209
|
+
"button",
|
|
14210
|
+
{
|
|
14211
|
+
ref: refCallback,
|
|
14212
|
+
type: "button",
|
|
14213
|
+
disabled,
|
|
14214
|
+
"aria-expanded": active,
|
|
14215
|
+
onPointerDown: (event) => event.stopPropagation(),
|
|
14216
|
+
onClick: onOpen,
|
|
14217
|
+
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",
|
|
14218
|
+
style: {
|
|
14219
|
+
minHeight: CHIPFILTER.chipHeight,
|
|
14220
|
+
gap: CHIPFILTER.chipGap,
|
|
14221
|
+
borderRadius: CHIPFILTER.chipRadius,
|
|
14222
|
+
borderColor: border,
|
|
14223
|
+
background,
|
|
14224
|
+
color: textColor
|
|
14225
|
+
},
|
|
14226
|
+
children: [
|
|
14227
|
+
field.required && /* @__PURE__ */ jsx(
|
|
14228
|
+
SIcon,
|
|
14229
|
+
{
|
|
14230
|
+
name: "asterisk",
|
|
14231
|
+
size: 12,
|
|
14232
|
+
color: disabled ? CHIPFILTER.chipDisabledText : "var(--cmp-tag-darkblue-content)"
|
|
14233
|
+
}
|
|
14234
|
+
),
|
|
14235
|
+
applied ? /* @__PURE__ */ jsxs("span", { className: "inline-flex min-w-0 items-center gap-[4px] truncate", children: [
|
|
14236
|
+
/* @__PURE__ */ jsx(
|
|
14237
|
+
"span",
|
|
14238
|
+
{
|
|
14239
|
+
className: "font-bold",
|
|
14240
|
+
style: { color: disabled ? CHIPFILTER.chipDisabledText : CHIPFILTER.chipAppliedLabel },
|
|
14241
|
+
children: field.label
|
|
14242
|
+
}
|
|
14243
|
+
),
|
|
14244
|
+
/* @__PURE__ */ jsx(
|
|
14245
|
+
"span",
|
|
14246
|
+
{
|
|
14247
|
+
style: { color: disabled ? CHIPFILTER.chipDisabledText : CHIPFILTER.chipAppliedLabel },
|
|
14248
|
+
children: ":"
|
|
14249
|
+
}
|
|
14250
|
+
),
|
|
14251
|
+
/* @__PURE__ */ jsx(
|
|
14252
|
+
"span",
|
|
14253
|
+
{
|
|
14254
|
+
className: "min-w-0 truncate font-bold",
|
|
14255
|
+
style: { color: disabled ? CHIPFILTER.chipDisabledText : CHIPFILTER.chipAppliedValue },
|
|
14256
|
+
children: valueText
|
|
14257
|
+
}
|
|
14258
|
+
)
|
|
14259
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
14260
|
+
/* @__PURE__ */ jsx("span", { className: cn("min-w-0 truncate", active && "font-bold"), children: field.label }),
|
|
14261
|
+
/* @__PURE__ */ jsx(
|
|
14262
|
+
SIcon,
|
|
14263
|
+
{
|
|
14264
|
+
name: "caretDown",
|
|
14265
|
+
size: 12,
|
|
14266
|
+
color: disabled ? CHIPFILTER.chipDisabledText : CHIPFILTER.chipDefaultText
|
|
14267
|
+
}
|
|
14268
|
+
)
|
|
14269
|
+
] }),
|
|
14270
|
+
applied && !disabled && showClear && /* @__PURE__ */ jsx(
|
|
14271
|
+
"span",
|
|
14272
|
+
{
|
|
14273
|
+
role: "button",
|
|
14274
|
+
tabIndex: 0,
|
|
14275
|
+
"aria-label": `${field.label} \uD544\uD130 \uC9C0\uC6B0\uAE30`,
|
|
14276
|
+
className: "inline-flex size-[16px] items-center justify-center rounded-[var(--cmp-ghostButton-radius-sm)]",
|
|
14277
|
+
onClick: (event) => {
|
|
14278
|
+
event.preventDefault();
|
|
14279
|
+
event.stopPropagation();
|
|
14280
|
+
onClear();
|
|
14281
|
+
},
|
|
14282
|
+
onKeyDown: (event) => {
|
|
14283
|
+
if (event.key !== "Enter" && event.key !== " ") return;
|
|
14284
|
+
event.preventDefault();
|
|
14285
|
+
event.stopPropagation();
|
|
14286
|
+
onClear();
|
|
14287
|
+
},
|
|
14288
|
+
children: /* @__PURE__ */ jsx(SIcon, { name: "close", size: 12, color: "var(--cmp-ghostButton-default-content)" })
|
|
14289
|
+
}
|
|
14290
|
+
)
|
|
14291
|
+
]
|
|
14292
|
+
}
|
|
14293
|
+
);
|
|
14294
|
+
}
|
|
14295
|
+
function EditorPanel({
|
|
14296
|
+
field,
|
|
14297
|
+
value,
|
|
14298
|
+
disabled,
|
|
14299
|
+
onValueChange,
|
|
14300
|
+
onClose
|
|
14301
|
+
}) {
|
|
14302
|
+
const wrapsInPaddedTop = field.type === "date";
|
|
14303
|
+
const isMulti = field.type === "multi";
|
|
14304
|
+
const selectableValues = isMulti ? (field.options ?? []).filter((option) => !option.disabled).map((option) => option.value) : [];
|
|
14305
|
+
const selectedValues = isMulti ? toArrayValue(value) : [];
|
|
14306
|
+
const allSelected = isMulti && selectableValues.length > 0 && selectableValues.every((v) => selectedValues.includes(v));
|
|
14307
|
+
const toggleSelectAll = () => {
|
|
14308
|
+
onValueChange(
|
|
14309
|
+
allSelected ? selectedValues.filter((v) => !selectableValues.includes(v)) : [...selectedValues, ...selectableValues.filter((v) => !selectedValues.includes(v))]
|
|
14310
|
+
);
|
|
14311
|
+
};
|
|
14312
|
+
return /* @__PURE__ */ jsxs(ListBox, { children: [
|
|
14313
|
+
wrapsInPaddedTop ? /* @__PURE__ */ 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__ */ jsx(
|
|
14314
|
+
FilterEditor,
|
|
14315
|
+
{
|
|
14316
|
+
field,
|
|
14317
|
+
value,
|
|
14318
|
+
disabled,
|
|
14319
|
+
onValueChange
|
|
14320
|
+
}
|
|
14321
|
+
) }) : /* @__PURE__ */ jsx(
|
|
14322
|
+
FilterEditor,
|
|
14323
|
+
{
|
|
14324
|
+
field,
|
|
14325
|
+
value,
|
|
14326
|
+
disabled,
|
|
14327
|
+
onValueChange
|
|
14328
|
+
}
|
|
14329
|
+
),
|
|
14330
|
+
/* @__PURE__ */ jsxs(
|
|
14331
|
+
"div",
|
|
14332
|
+
{
|
|
14333
|
+
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)]",
|
|
14334
|
+
style: { borderColor: CHIPFILTER.listboxBorder },
|
|
14335
|
+
children: [
|
|
14336
|
+
isMulti && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
14337
|
+
/* @__PURE__ */ jsx(
|
|
14338
|
+
STextLink,
|
|
14339
|
+
{
|
|
14340
|
+
size: "sm",
|
|
14341
|
+
label: allSelected ? "\uC120\uD0DD \uD574\uC81C" : "\uC804\uCCB4 \uC120\uD0DD",
|
|
14342
|
+
labelClass: "font-bold",
|
|
14343
|
+
disabled,
|
|
14344
|
+
onClick: toggleSelectAll,
|
|
14345
|
+
style: { color: "var(--sys-color-fg-secondary)" }
|
|
14346
|
+
}
|
|
14347
|
+
),
|
|
14348
|
+
/* @__PURE__ */ jsx(
|
|
14349
|
+
"span",
|
|
14350
|
+
{
|
|
14351
|
+
"aria-hidden": true,
|
|
14352
|
+
className: "inline-flex w-px shrink-0",
|
|
14353
|
+
style: {
|
|
14354
|
+
height: CHIPFILTER.listboxBottomDividerHeight,
|
|
14355
|
+
background: CHIPFILTER.listboxBorder
|
|
14356
|
+
}
|
|
14357
|
+
}
|
|
14358
|
+
)
|
|
14359
|
+
] }),
|
|
14360
|
+
/* @__PURE__ */ jsx(
|
|
14361
|
+
STextLink,
|
|
14362
|
+
{
|
|
14363
|
+
size: "sm",
|
|
14364
|
+
label: "\uAC80\uC0C9",
|
|
14365
|
+
labelClass: "font-bold",
|
|
14366
|
+
onClick: onClose,
|
|
14367
|
+
style: { color: CHIPFILTER.chipAppliedValue }
|
|
14368
|
+
}
|
|
14369
|
+
)
|
|
14370
|
+
]
|
|
14371
|
+
}
|
|
14372
|
+
)
|
|
14373
|
+
] });
|
|
14374
|
+
}
|
|
14375
|
+
function FilterEditor({
|
|
14376
|
+
field,
|
|
14377
|
+
value,
|
|
14378
|
+
disabled,
|
|
14379
|
+
onValueChange
|
|
14380
|
+
}) {
|
|
14381
|
+
if (field.type === "date") {
|
|
14382
|
+
return /* @__PURE__ */ jsx(
|
|
14383
|
+
DatePresetEditor,
|
|
14384
|
+
{
|
|
14385
|
+
field,
|
|
14386
|
+
value,
|
|
14387
|
+
disabled,
|
|
14388
|
+
onValueChange
|
|
14389
|
+
}
|
|
14390
|
+
);
|
|
14391
|
+
}
|
|
14392
|
+
if (field.type === "keyword") {
|
|
14393
|
+
return /* @__PURE__ */ jsx(
|
|
14394
|
+
KeywordEditor,
|
|
14395
|
+
{
|
|
14396
|
+
field,
|
|
14397
|
+
value: isKeywordValue(value) ? value : keywordEntries(value),
|
|
14398
|
+
disabled,
|
|
14399
|
+
onValueChange
|
|
14400
|
+
}
|
|
14401
|
+
);
|
|
14402
|
+
}
|
|
14403
|
+
return /* @__PURE__ */ jsx(
|
|
14404
|
+
OptionList,
|
|
14405
|
+
{
|
|
14406
|
+
field,
|
|
14407
|
+
value: field.type === "multi" ? toArrayValue(value) : value,
|
|
14408
|
+
multiple: field.type === "multi",
|
|
14409
|
+
disabled,
|
|
14410
|
+
onValueChange
|
|
14411
|
+
}
|
|
14412
|
+
);
|
|
14413
|
+
}
|
|
14414
|
+
function DatePresetEditor({
|
|
14415
|
+
field,
|
|
14416
|
+
value,
|
|
14417
|
+
disabled,
|
|
14418
|
+
onValueChange
|
|
14419
|
+
}) {
|
|
14420
|
+
const presets = field.presets ?? [];
|
|
14421
|
+
const [selectedId, setSelectedId] = useState(() => matchPresetId(presets, value));
|
|
14422
|
+
const syncedInitialValueRef = useRef(!isEmptyValue(value));
|
|
14423
|
+
useEffect(() => {
|
|
14424
|
+
if (syncedInitialValueRef.current || isEmptyValue(value)) return;
|
|
14425
|
+
syncedInitialValueRef.current = true;
|
|
14426
|
+
setSelectedId(matchPresetId(presets, value));
|
|
14427
|
+
}, [value, presets]);
|
|
14428
|
+
const selectedPreset = presets.find((preset) => preset.value === selectedId);
|
|
14429
|
+
const selectPreset = (preset) => {
|
|
14430
|
+
setSelectedId(preset.value);
|
|
14431
|
+
if (!preset.custom) onValueChange(preset.resolve ? preset.resolve() : null);
|
|
14432
|
+
};
|
|
14433
|
+
if (presets.length === 0) {
|
|
14434
|
+
return /* @__PURE__ */ jsx(
|
|
14435
|
+
SDatePicker,
|
|
14436
|
+
{
|
|
14437
|
+
value: typeof value === "string" ? value : null,
|
|
14438
|
+
onValueChange,
|
|
14439
|
+
selectable: field.selectable,
|
|
14440
|
+
disabled,
|
|
14441
|
+
placeholder: field.placeholder
|
|
14442
|
+
}
|
|
14443
|
+
);
|
|
14444
|
+
}
|
|
14445
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-[var(--cmp-chipFilter-listbox-top-gap)]", children: [
|
|
14446
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-col gap-[8px]", children: presets.map((preset) => /* @__PURE__ */ jsx(
|
|
14447
|
+
SRadio,
|
|
14448
|
+
{
|
|
14449
|
+
val: preset.value,
|
|
14450
|
+
value: selectedId,
|
|
14451
|
+
label: preset.label,
|
|
14452
|
+
disabled,
|
|
14453
|
+
onValueChange: () => selectPreset(preset)
|
|
14454
|
+
},
|
|
14455
|
+
preset.value
|
|
14456
|
+
)) }),
|
|
14457
|
+
selectedPreset?.custom && /* @__PURE__ */ jsx(
|
|
14458
|
+
SDateRangePicker,
|
|
14459
|
+
{
|
|
14460
|
+
value: Array.isArray(value) && value.length === 2 ? value : null,
|
|
14461
|
+
onValueChange,
|
|
14462
|
+
selectable: field.selectable,
|
|
14463
|
+
maxRange: field.maxRange,
|
|
14464
|
+
disabled
|
|
14465
|
+
}
|
|
14466
|
+
)
|
|
14467
|
+
] });
|
|
14468
|
+
}
|
|
14469
|
+
function InlineDatePresetFilter({
|
|
14470
|
+
field,
|
|
14471
|
+
value,
|
|
14472
|
+
disabled,
|
|
14473
|
+
warning,
|
|
14474
|
+
showClear,
|
|
14475
|
+
onValueChange,
|
|
14476
|
+
onClear
|
|
14477
|
+
}) {
|
|
14478
|
+
const presets = (field.presets ?? []).filter((preset) => !preset.custom);
|
|
14479
|
+
const [selectedId, setSelectedId] = useState(() => matchPresetId(presets, value));
|
|
14480
|
+
const syncedInitialValueRef = useRef(!isEmptyValue(value));
|
|
14481
|
+
useEffect(() => {
|
|
14482
|
+
if (syncedInitialValueRef.current || isEmptyValue(value)) return;
|
|
14483
|
+
syncedInitialValueRef.current = true;
|
|
14484
|
+
setSelectedId(matchPresetId(presets, value));
|
|
14485
|
+
}, [value, presets]);
|
|
14486
|
+
const applied = !isEmptyValue(value);
|
|
14487
|
+
const rangeValue = Array.isArray(value) ? value : typeof value === "string" && value !== "" ? [value, value] : null;
|
|
14488
|
+
const [pickerOpen, setPickerOpen] = useState(false);
|
|
14489
|
+
const portalContainer = usePortalContainer();
|
|
14490
|
+
const selectPreset = (id) => {
|
|
14491
|
+
const preset = presets.find((p) => p.value === id);
|
|
14492
|
+
if (!preset) return;
|
|
14493
|
+
setSelectedId(preset.value);
|
|
14494
|
+
onValueChange(preset.resolve ? preset.resolve() : null);
|
|
14495
|
+
};
|
|
14496
|
+
const badge = applied && /* @__PURE__ */ jsxs(
|
|
14497
|
+
"span",
|
|
14498
|
+
{
|
|
14499
|
+
className: "inline-flex shrink-0 items-center gap-[4px] whitespace-nowrap border border-solid px-[var(--cmp-chipFilter-chip-paddingX)] text-[12px] leading-[20px]",
|
|
14500
|
+
style: {
|
|
14501
|
+
minHeight: CHIPFILTER.chipHeight,
|
|
14502
|
+
borderRadius: CHIPFILTER.chipRadius,
|
|
14503
|
+
borderColor: warning ? CHIPFILTER.chipWarningBorder : CHIPFILTER.chipAppliedBorder,
|
|
14504
|
+
background: CHIPFILTER.chipAppliedBg,
|
|
14505
|
+
color: CHIPFILTER.chipAppliedLabel,
|
|
14506
|
+
cursor: rangeValue ? "pointer" : void 0
|
|
14507
|
+
},
|
|
14508
|
+
children: [
|
|
14509
|
+
/* @__PURE__ */ jsxs("span", { className: "font-bold", children: [
|
|
14510
|
+
field.label,
|
|
14511
|
+
":"
|
|
14512
|
+
] }),
|
|
14513
|
+
/* @__PURE__ */ jsx("span", { className: "font-bold", style: { color: CHIPFILTER.chipAppliedValue }, children: displayValue(field, value) }),
|
|
14514
|
+
!disabled && showClear && /* @__PURE__ */ jsx(
|
|
14515
|
+
"span",
|
|
14516
|
+
{
|
|
14517
|
+
role: "button",
|
|
14518
|
+
tabIndex: 0,
|
|
14519
|
+
"aria-label": `${field.label} \uD544\uD130 \uC9C0\uC6B0\uAE30`,
|
|
14520
|
+
className: "inline-flex size-[16px] items-center justify-center rounded-[var(--cmp-ghostButton-radius-sm)]",
|
|
14521
|
+
onClick: (event) => {
|
|
14522
|
+
event.stopPropagation();
|
|
14523
|
+
onClear();
|
|
14524
|
+
},
|
|
14525
|
+
onKeyDown: (event) => {
|
|
14526
|
+
if (event.key !== "Enter" && event.key !== " ") return;
|
|
14527
|
+
event.preventDefault();
|
|
14528
|
+
event.stopPropagation();
|
|
14529
|
+
onClear();
|
|
14530
|
+
},
|
|
14531
|
+
children: /* @__PURE__ */ jsx(SIcon, { name: "close", size: 12, color: "var(--cmp-ghostButton-default-content)" })
|
|
14532
|
+
}
|
|
14533
|
+
)
|
|
14534
|
+
]
|
|
14535
|
+
}
|
|
14536
|
+
);
|
|
14537
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-[8px]", children: [
|
|
14538
|
+
/* @__PURE__ */ jsx(
|
|
14539
|
+
SRadioButton,
|
|
14540
|
+
{
|
|
14541
|
+
size: "xs",
|
|
14542
|
+
options: presets.map((preset) => ({ value: preset.value, label: preset.label })),
|
|
14543
|
+
value: selectedId,
|
|
14544
|
+
disabled,
|
|
14545
|
+
onValueChange: (next) => selectPreset(String(next))
|
|
14546
|
+
}
|
|
14547
|
+
),
|
|
14548
|
+
applied && (rangeValue ? (
|
|
14549
|
+
// 뱃지 모양은 그대로 두고, 눌렀을 때 캘린더가 열려 기간을 직접 다시 고를 수 있게 한다.
|
|
14550
|
+
// 직접 고르면 프리셋 선택은 해제된다.
|
|
14551
|
+
/* @__PURE__ */ jsxs(RPopover9.Root, { open: pickerOpen, onOpenChange: setPickerOpen, children: [
|
|
14552
|
+
/* @__PURE__ */ jsx(RPopover9.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
14553
|
+
"button",
|
|
14554
|
+
{
|
|
14555
|
+
type: "button",
|
|
14556
|
+
disabled,
|
|
14557
|
+
className: "border-none bg-transparent p-0 outline-none disabled:cursor-not-allowed",
|
|
14558
|
+
children: badge
|
|
14559
|
+
}
|
|
14560
|
+
) }),
|
|
14561
|
+
/* @__PURE__ */ jsx(RPopover9.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
|
|
14562
|
+
RPopover9.Content,
|
|
14563
|
+
{
|
|
14564
|
+
side: "bottom",
|
|
14565
|
+
align: "start",
|
|
14566
|
+
sideOffset: 4,
|
|
14567
|
+
className: cn("z-50", FLOATING_SLIDE_ANIM),
|
|
14568
|
+
children: /* @__PURE__ */ jsx(
|
|
14569
|
+
RangeCalendar,
|
|
14570
|
+
{
|
|
14571
|
+
value: rangeValue,
|
|
14572
|
+
selectable: field.selectable,
|
|
14573
|
+
maxRange: field.maxRange,
|
|
14574
|
+
onSelect: (range) => {
|
|
14575
|
+
setSelectedId(null);
|
|
14576
|
+
onValueChange(range);
|
|
14577
|
+
setPickerOpen(false);
|
|
14578
|
+
}
|
|
14579
|
+
}
|
|
14580
|
+
)
|
|
14581
|
+
}
|
|
14582
|
+
) })
|
|
14583
|
+
] })
|
|
14584
|
+
) : badge)
|
|
14585
|
+
] });
|
|
14586
|
+
}
|
|
14587
|
+
var MATCH_MODE_OPTIONS = [
|
|
14588
|
+
{ value: "contains", label: "\uD3EC\uD568" },
|
|
14589
|
+
{ value: "exact", label: "\uC77C\uCE58" }
|
|
14590
|
+
];
|
|
14591
|
+
var EXCLUDE_MATCH_MODE_OPTION = {
|
|
14592
|
+
value: "excludes",
|
|
14593
|
+
label: "\uBBF8\uD3EC\uD568"
|
|
14594
|
+
};
|
|
14595
|
+
function KeywordEditor({
|
|
14596
|
+
field,
|
|
14597
|
+
value,
|
|
14598
|
+
disabled,
|
|
14599
|
+
onValueChange
|
|
14600
|
+
}) {
|
|
14601
|
+
const entries3 = keywordEntries(value);
|
|
14602
|
+
const [draft, setDraft] = useState("");
|
|
14603
|
+
const [mode, setMode] = useState(
|
|
14604
|
+
isKeywordValue(value) ? value.mode : "contains"
|
|
14605
|
+
);
|
|
14606
|
+
const emit3 = (nextEntries) => {
|
|
14607
|
+
onValueChange(field.matchModes ? { keywords: nextEntries, mode } : nextEntries);
|
|
14608
|
+
};
|
|
14609
|
+
const addEntry = (raw) => {
|
|
14610
|
+
const next = raw.trim();
|
|
14611
|
+
if (next === "" || entries3.includes(next)) return;
|
|
14612
|
+
emit3([...entries3, next]);
|
|
14613
|
+
setDraft("");
|
|
14614
|
+
};
|
|
14615
|
+
const removeEntry = (entry) => {
|
|
14616
|
+
emit3(entries3.filter((e) => e !== entry));
|
|
14617
|
+
};
|
|
14618
|
+
const onKeyDown = (event) => {
|
|
14619
|
+
if (event.key === "Enter") {
|
|
14620
|
+
if (event.nativeEvent.isComposing) return;
|
|
14621
|
+
event.preventDefault();
|
|
14622
|
+
addEntry(draft);
|
|
14623
|
+
}
|
|
14624
|
+
};
|
|
14625
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
14626
|
+
/* @__PURE__ */ 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: [
|
|
14627
|
+
field.matchModes && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
14628
|
+
/* @__PURE__ */ jsx(
|
|
14629
|
+
"span",
|
|
14630
|
+
{
|
|
14631
|
+
className: "shrink-0 whitespace-nowrap text-[12px] font-medium leading-[20px]",
|
|
14632
|
+
style: { color: CHIPFILTER.listboxLabel },
|
|
14633
|
+
children: "\uAC80\uC0C9 \uC870\uAC74 :"
|
|
14634
|
+
}
|
|
14635
|
+
),
|
|
14636
|
+
/* @__PURE__ */ jsx(
|
|
14637
|
+
SRadioButton,
|
|
14638
|
+
{
|
|
14639
|
+
size: "xs",
|
|
14640
|
+
style: { width: 150 },
|
|
14641
|
+
options: field.excludeMode ? [...MATCH_MODE_OPTIONS, EXCLUDE_MATCH_MODE_OPTION] : MATCH_MODE_OPTIONS,
|
|
14642
|
+
value: mode,
|
|
14643
|
+
disabled,
|
|
14644
|
+
onValueChange: (next) => setMode(next)
|
|
14645
|
+
}
|
|
14646
|
+
)
|
|
14647
|
+
] }),
|
|
14648
|
+
/* @__PURE__ */ 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: [
|
|
14649
|
+
/* @__PURE__ */ jsx(SIcon, { name: "search", size: 16, color: "var(--sys-color-field-icon-default)" }),
|
|
14650
|
+
/* @__PURE__ */ jsx(
|
|
14651
|
+
"input",
|
|
14652
|
+
{
|
|
14653
|
+
value: draft,
|
|
14654
|
+
disabled,
|
|
14655
|
+
placeholder: field.placeholder ?? "\uC785\uB825 \uD6C4 Enter\uB85C \uCD94\uAC00",
|
|
14656
|
+
onChange: (event) => setDraft(event.target.value),
|
|
14657
|
+
onKeyDown,
|
|
14658
|
+
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"
|
|
14659
|
+
}
|
|
14660
|
+
)
|
|
14661
|
+
] })
|
|
14662
|
+
] }),
|
|
14663
|
+
entries3.length > 0 && /* @__PURE__ */ jsx(
|
|
14664
|
+
"div",
|
|
14665
|
+
{
|
|
14666
|
+
className: "max-h-[220px] overflow-auto border-t border-solid py-[var(--cmp-chipFilter-listbox-list-paddingY)]",
|
|
14667
|
+
style: { borderColor: CHIPFILTER.listboxBorder },
|
|
14668
|
+
children: entries3.map((entry) => /* @__PURE__ */ jsx(
|
|
14669
|
+
KeywordEntryRow,
|
|
14670
|
+
{
|
|
14671
|
+
label: optionLabel(field, entry),
|
|
14672
|
+
disabled,
|
|
14673
|
+
onRemove: () => removeEntry(entry)
|
|
14674
|
+
},
|
|
14675
|
+
entry
|
|
14676
|
+
))
|
|
14677
|
+
}
|
|
14678
|
+
)
|
|
14679
|
+
] });
|
|
14680
|
+
}
|
|
14681
|
+
function KeywordEntryRow({
|
|
14682
|
+
label,
|
|
14683
|
+
disabled,
|
|
14684
|
+
onRemove
|
|
14685
|
+
}) {
|
|
14686
|
+
return /* @__PURE__ */ jsxs(
|
|
14687
|
+
"div",
|
|
14688
|
+
{
|
|
14689
|
+
className: "group flex w-full items-center justify-between gap-[8px] text-[12px] leading-[20px]",
|
|
14690
|
+
style: {
|
|
14691
|
+
paddingTop: CHIPFILTER.itemPaddingY,
|
|
14692
|
+
paddingBottom: CHIPFILTER.itemPaddingY,
|
|
14693
|
+
paddingLeft: CHIPFILTER.itemPaddingLeft,
|
|
14694
|
+
paddingRight: CHIPFILTER.itemPaddingRight,
|
|
14695
|
+
color: disabled ? CHIPFILTER.chipDisabledText : CHIPFILTER.itemTextDefault
|
|
14696
|
+
},
|
|
14697
|
+
children: [
|
|
14698
|
+
/* @__PURE__ */ jsx("span", { className: cn("min-w-0 truncate", !disabled && "group-hover:font-bold"), children: label }),
|
|
14699
|
+
!disabled && /* @__PURE__ */ jsx(
|
|
14700
|
+
"button",
|
|
14701
|
+
{
|
|
14702
|
+
type: "button",
|
|
14703
|
+
"aria-label": `${label} \uC0AD\uC81C`,
|
|
14704
|
+
className: "invisible inline-flex size-[16px] shrink-0 cursor-pointer items-center justify-center group-hover:visible",
|
|
14705
|
+
onClick: onRemove,
|
|
14706
|
+
children: /* @__PURE__ */ jsx(SIcon, { name: "close", size: 12, color: "var(--cmp-ghostButton-default-content)" })
|
|
14707
|
+
}
|
|
14708
|
+
)
|
|
14709
|
+
]
|
|
14710
|
+
}
|
|
14711
|
+
);
|
|
14712
|
+
}
|
|
14713
|
+
var OPTION_SEARCH_THRESHOLD = 11;
|
|
14714
|
+
function OptionList({
|
|
14715
|
+
field,
|
|
14716
|
+
value,
|
|
14717
|
+
multiple,
|
|
14718
|
+
disabled,
|
|
14719
|
+
onValueChange
|
|
14720
|
+
}) {
|
|
14721
|
+
const selected = multiple ? toArrayValue(value) : [];
|
|
14722
|
+
const singleValue = !multiple && (typeof value === "string" || typeof value === "number") ? value : null;
|
|
14723
|
+
const [search, setSearch] = useState("");
|
|
14724
|
+
const options = field.options ?? [];
|
|
14725
|
+
const showSearch = options.length >= OPTION_SEARCH_THRESHOLD;
|
|
14726
|
+
const filteredOptions = useMemo(() => {
|
|
14727
|
+
if (!showSearch || search.trim() === "") return options;
|
|
14728
|
+
const query = search.trim().toLowerCase();
|
|
14729
|
+
return options.filter((option) => option.label.toLowerCase().includes(query));
|
|
14730
|
+
}, [options, search, showSearch]);
|
|
14731
|
+
if (options.length === 0) return /* @__PURE__ */ jsx(EmptyItem, { children: "\uD45C\uC2DC\uD560 \uD56D\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4." });
|
|
14732
|
+
return /* @__PURE__ */ jsxs(
|
|
14733
|
+
"div",
|
|
14734
|
+
{
|
|
14735
|
+
className: cn(
|
|
14736
|
+
"max-h-[240px] overflow-auto",
|
|
14737
|
+
!showSearch && "pt-[var(--cmp-chipFilter-listbox-list-paddingY)]",
|
|
14738
|
+
"pb-[var(--cmp-chipFilter-listbox-list-paddingY)]"
|
|
14739
|
+
),
|
|
14740
|
+
children: [
|
|
14741
|
+
showSearch && /* @__PURE__ */ jsx(
|
|
14742
|
+
"div",
|
|
14743
|
+
{
|
|
14744
|
+
className: "sticky top-0 z-[1] border-b border-solid px-[8px] pb-[4px] pt-[var(--cmp-chipFilter-listbox-list-paddingY)]",
|
|
14745
|
+
style: { background: CHIPFILTER.listboxBg, borderColor: CHIPFILTER.listboxBorder },
|
|
14746
|
+
children: /* @__PURE__ */ 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: [
|
|
14747
|
+
/* @__PURE__ */ jsx(SIcon, { name: "search", size: 16, color: "var(--sys-color-field-icon-default)" }),
|
|
14748
|
+
/* @__PURE__ */ jsx(
|
|
14749
|
+
"input",
|
|
14750
|
+
{
|
|
14751
|
+
value: search,
|
|
14752
|
+
disabled,
|
|
14753
|
+
placeholder: "\uAC80\uC0C9",
|
|
14754
|
+
onChange: (event) => setSearch(event.target.value),
|
|
14755
|
+
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"
|
|
14756
|
+
}
|
|
14757
|
+
),
|
|
14758
|
+
search !== "" && !disabled && /* @__PURE__ */ jsx(
|
|
14759
|
+
SGhostButton,
|
|
14760
|
+
{
|
|
14761
|
+
icon: "close",
|
|
14762
|
+
size: "xxs",
|
|
14763
|
+
ariaLabel: "\uAC80\uC0C9\uC5B4 \uC9C0\uC6B0\uAE30",
|
|
14764
|
+
className: "flex-shrink-0",
|
|
14765
|
+
onClick: () => setSearch("")
|
|
14766
|
+
}
|
|
14767
|
+
)
|
|
14768
|
+
] })
|
|
14769
|
+
}
|
|
14770
|
+
),
|
|
14771
|
+
showSearch && filteredOptions.length === 0 && /* @__PURE__ */ jsx(EmptyItem, { children: "\uAC80\uC0C9 \uACB0\uACFC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4." }),
|
|
14772
|
+
filteredOptions.map((option) => {
|
|
14773
|
+
const checked = multiple ? selected.includes(option.value) : singleValue === option.value;
|
|
14774
|
+
return /* @__PURE__ */ jsxs(
|
|
14775
|
+
MenuItem,
|
|
14776
|
+
{
|
|
14777
|
+
selected: checked,
|
|
14778
|
+
disabled: disabled || option.disabled,
|
|
14779
|
+
multi: multiple,
|
|
14780
|
+
onClick: () => {
|
|
14781
|
+
if (multiple) {
|
|
14782
|
+
const next = checked ? selected.filter((v) => v !== option.value) : [...selected, option.value];
|
|
14783
|
+
onValueChange(next);
|
|
14784
|
+
} else {
|
|
14785
|
+
onValueChange(option.value);
|
|
14786
|
+
}
|
|
14787
|
+
},
|
|
14788
|
+
children: [
|
|
14789
|
+
multiple && /* @__PURE__ */ jsx(OptionCheckbox, { checked }),
|
|
14790
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: option.label })
|
|
14791
|
+
]
|
|
14792
|
+
},
|
|
14793
|
+
String(option.value)
|
|
14794
|
+
);
|
|
14795
|
+
})
|
|
14796
|
+
]
|
|
14797
|
+
}
|
|
14798
|
+
);
|
|
14799
|
+
}
|
|
14800
|
+
function OptionCheckbox({ checked }) {
|
|
14801
|
+
return /* @__PURE__ */ jsx(
|
|
14802
|
+
"span",
|
|
14803
|
+
{
|
|
14804
|
+
className: cn(
|
|
14805
|
+
"inline-flex size-[16px] shrink-0 items-center justify-center rounded-[2px] border border-solid",
|
|
14806
|
+
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)]"
|
|
14807
|
+
),
|
|
14808
|
+
children: checked && /* @__PURE__ */ jsx(SIcon, { name: "checkboxCheck", size: 12, color: "var(--cmp-checkbox-checked-icon-default)" })
|
|
14809
|
+
}
|
|
14810
|
+
);
|
|
14811
|
+
}
|
|
14812
|
+
function ListBox({ children }) {
|
|
14813
|
+
return /* @__PURE__ */ jsx(
|
|
14814
|
+
"div",
|
|
14815
|
+
{
|
|
14816
|
+
className: "overflow-hidden border border-solid shadow-[var(--shadow-overlay)]",
|
|
14817
|
+
style: {
|
|
14818
|
+
borderRadius: CHIPFILTER.listboxRadius,
|
|
14819
|
+
background: CHIPFILTER.listboxBg,
|
|
14820
|
+
borderColor: CHIPFILTER.listboxBorder
|
|
14821
|
+
},
|
|
14822
|
+
children
|
|
14823
|
+
}
|
|
14824
|
+
);
|
|
14825
|
+
}
|
|
14826
|
+
function MenuItem({
|
|
14827
|
+
children,
|
|
14828
|
+
selected,
|
|
14829
|
+
disabled,
|
|
14830
|
+
multi,
|
|
14831
|
+
onMouseEnter,
|
|
14832
|
+
onClick
|
|
14833
|
+
}) {
|
|
14834
|
+
return /* @__PURE__ */ jsx(
|
|
14835
|
+
"button",
|
|
14836
|
+
{
|
|
14837
|
+
type: "button",
|
|
14838
|
+
disabled,
|
|
14839
|
+
onMouseEnter,
|
|
14840
|
+
onClick,
|
|
14841
|
+
className: cn(
|
|
14842
|
+
"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",
|
|
14843
|
+
selected ? "font-bold" : "font-normal",
|
|
14844
|
+
!disabled && "hover:font-bold"
|
|
14845
|
+
),
|
|
14846
|
+
style: {
|
|
14847
|
+
paddingTop: CHIPFILTER.itemPaddingY,
|
|
14848
|
+
paddingBottom: CHIPFILTER.itemPaddingY,
|
|
14849
|
+
paddingLeft: multi ? CHIPFILTER.itemMultiPaddingX : CHIPFILTER.itemPaddingLeft,
|
|
14850
|
+
paddingRight: multi ? CHIPFILTER.itemMultiPaddingX : CHIPFILTER.itemPaddingRight,
|
|
14851
|
+
color: disabled ? CHIPFILTER.chipDisabledText : selected ? CHIPFILTER.itemTextSelected : CHIPFILTER.itemTextDefault
|
|
14852
|
+
},
|
|
14853
|
+
children
|
|
14854
|
+
}
|
|
14855
|
+
);
|
|
14856
|
+
}
|
|
14857
|
+
function EmptyItem({ children }) {
|
|
14858
|
+
return /* @__PURE__ */ jsx(
|
|
14859
|
+
"div",
|
|
14860
|
+
{
|
|
14861
|
+
className: "text-[12px] leading-[20px]",
|
|
14862
|
+
style: {
|
|
14863
|
+
paddingTop: CHIPFILTER.itemPaddingY,
|
|
14864
|
+
paddingBottom: CHIPFILTER.itemPaddingY,
|
|
14865
|
+
paddingLeft: CHIPFILTER.itemPaddingLeft,
|
|
14866
|
+
paddingRight: CHIPFILTER.itemPaddingRight,
|
|
14867
|
+
color: CHIPFILTER.chipDisabledText
|
|
14868
|
+
},
|
|
14869
|
+
children
|
|
14870
|
+
}
|
|
14871
|
+
);
|
|
14872
|
+
}
|
|
14873
|
+
var SChipInput = /* @__PURE__ */ forwardRef(function SChipInput2({
|
|
14874
|
+
values = [],
|
|
14875
|
+
onValueChange,
|
|
14876
|
+
onInput,
|
|
14877
|
+
onFocus,
|
|
14878
|
+
onBlur,
|
|
14879
|
+
errors = [],
|
|
14880
|
+
disabledChips = [],
|
|
14881
|
+
size = "sm",
|
|
14882
|
+
disabled = false,
|
|
14883
|
+
placeholder = "\uD0DC\uADF8 \uC785\uB825 (Enter\uB85C \uB4F1\uB85D / \uCF64\uB9C8\uB85C \uAD6C\uBD84 / \uB744\uC5B4\uC4F0\uAE30 \uBD88\uAC00)",
|
|
14884
|
+
name,
|
|
14885
|
+
rules,
|
|
14886
|
+
error,
|
|
14887
|
+
useReset = false,
|
|
14888
|
+
maxCount,
|
|
14889
|
+
metaPlacement = "end",
|
|
14890
|
+
duplicateLabel,
|
|
14891
|
+
suggestions = [],
|
|
14892
|
+
loadingSuggestions = false,
|
|
14893
|
+
recommendedItems = [],
|
|
14894
|
+
loadingRecommendedItems = false,
|
|
14895
|
+
dropdownMinWidth = 200,
|
|
14896
|
+
label,
|
|
14897
|
+
labelWidth,
|
|
14898
|
+
hint,
|
|
14899
|
+
errorMessage,
|
|
14900
|
+
width,
|
|
14901
|
+
status,
|
|
14902
|
+
icon,
|
|
14903
|
+
iconColor,
|
|
14904
|
+
labelTooltip,
|
|
14905
|
+
labelTooltipProps,
|
|
14906
|
+
className,
|
|
14907
|
+
style
|
|
14908
|
+
}, ref) {
|
|
14909
|
+
const autoId = useId();
|
|
14910
|
+
const resolvedName = name ?? autoId;
|
|
14911
|
+
const [inputValue, setInputValue] = useState("");
|
|
14912
|
+
const [focused, setFocused] = useState(false);
|
|
14913
|
+
const [hovered, setHovered] = useState(false);
|
|
14914
|
+
const [activeIndex, setActiveIndex] = useState(-1);
|
|
14915
|
+
const [suppressSuggestions, setSuppressSuggestions] = useState(false);
|
|
14916
|
+
const [suppressRecommendations, setSuppressRecommendations] = useState(false);
|
|
14917
|
+
const inputRef = useRef(null);
|
|
14918
|
+
const containerRef = useRef(null);
|
|
14919
|
+
const inputShellRef = useRef(null);
|
|
14920
|
+
const isComposingRef = useRef(false);
|
|
14921
|
+
useImperativeHandle(ref, () => ({ focus: () => inputRef.current?.focus() }), []);
|
|
14922
|
+
const chipError = (i) => {
|
|
14923
|
+
if (values.indexOf(values[i]) !== i) return true;
|
|
14924
|
+
if (typeof errors === "function") return errors(values[i] ?? "");
|
|
14925
|
+
return errors[i] ?? false;
|
|
14926
|
+
};
|
|
14927
|
+
const chipDisabled = (i) => {
|
|
14928
|
+
if (disabled) return true;
|
|
14929
|
+
if (typeof disabledChips === "function") return disabledChips(values[i] ?? "");
|
|
14930
|
+
return disabledChips[i] ?? false;
|
|
14931
|
+
};
|
|
14932
|
+
const duplicateMessage = useMemo(() => {
|
|
13423
14933
|
const seen = /* @__PURE__ */ new Set();
|
|
13424
14934
|
for (const v of values) {
|
|
13425
14935
|
if (seen.has(v))
|
|
@@ -14083,7 +15593,7 @@ function TimeSelector({
|
|
|
14083
15593
|
const renderColumn = (type) => {
|
|
14084
15594
|
const isHour = type === "hour";
|
|
14085
15595
|
const val = isHour ? displayHour : minute;
|
|
14086
|
-
const
|
|
15596
|
+
const displayValue2 = editingPart === type ? inputDraft[type] ?? "" : String(val).padStart(2, "0");
|
|
14087
15597
|
return /* @__PURE__ */ jsxs(
|
|
14088
15598
|
"div",
|
|
14089
15599
|
{
|
|
@@ -14104,7 +15614,7 @@ function TimeSelector({
|
|
|
14104
15614
|
{
|
|
14105
15615
|
"aria-label": isHour ? "\uC2DC" : "\uBD84",
|
|
14106
15616
|
inputMode: "numeric",
|
|
14107
|
-
value:
|
|
15617
|
+
value: displayValue2,
|
|
14108
15618
|
placeholder: "-",
|
|
14109
15619
|
onFocus: () => beginEdit(type, val),
|
|
14110
15620
|
onBlur: () => endEdit(type),
|
|
@@ -14299,8 +15809,8 @@ function STimePicker({
|
|
|
14299
15809
|
disabled,
|
|
14300
15810
|
className,
|
|
14301
15811
|
style,
|
|
14302
|
-
children: /* @__PURE__ */ jsxs(
|
|
14303
|
-
/* @__PURE__ */ jsx(
|
|
15812
|
+
children: /* @__PURE__ */ jsxs(RPopover9.Root, { open, onOpenChange: commitOpen, children: [
|
|
15813
|
+
/* @__PURE__ */ jsx(RPopover9.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
14304
15814
|
"div",
|
|
14305
15815
|
{
|
|
14306
15816
|
ref: triggerRef,
|
|
@@ -14360,14 +15870,17 @@ function STimePicker({
|
|
|
14360
15870
|
]
|
|
14361
15871
|
}
|
|
14362
15872
|
) }),
|
|
14363
|
-
/* @__PURE__ */ jsx(
|
|
14364
|
-
|
|
15873
|
+
/* @__PURE__ */ jsx(RPopover9.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
|
|
15874
|
+
RPopover9.Content,
|
|
14365
15875
|
{
|
|
14366
15876
|
side: "bottom",
|
|
14367
15877
|
align: "start",
|
|
14368
15878
|
sideOffset: 4,
|
|
14369
15879
|
alignOffset: popoverAlignOffset,
|
|
14370
|
-
className: cn(
|
|
15880
|
+
className: cn(
|
|
15881
|
+
"z-50 max-w-[var(--radix-popover-content-available-width)]",
|
|
15882
|
+
FLOATING_SLIDE_ANIM
|
|
15883
|
+
),
|
|
14371
15884
|
children: /* @__PURE__ */ jsx(
|
|
14372
15885
|
TimeSelector,
|
|
14373
15886
|
{
|
|
@@ -14526,7 +16039,7 @@ function RangeTimeSelector({
|
|
|
14526
16039
|
const { minute } = getParts(side);
|
|
14527
16040
|
const val = isHour ? getDisplayHour(side) : minute;
|
|
14528
16041
|
const currentEditingKey = getEditingKey(side, kind);
|
|
14529
|
-
const
|
|
16042
|
+
const displayValue2 = editingKey === currentEditingKey ? inputDraft[currentEditingKey] ?? "" : String(val).padStart(2, "0");
|
|
14530
16043
|
return /* @__PURE__ */ jsxs(
|
|
14531
16044
|
"div",
|
|
14532
16045
|
{
|
|
@@ -14547,7 +16060,7 @@ function RangeTimeSelector({
|
|
|
14547
16060
|
{
|
|
14548
16061
|
"aria-label": `${side === "start" ? "\uC2DC\uC791" : "\uC885\uB8CC"} ${isHour ? "\uC2DC" : "\uBD84"}`,
|
|
14549
16062
|
inputMode: "numeric",
|
|
14550
|
-
value:
|
|
16063
|
+
value: displayValue2,
|
|
14551
16064
|
placeholder: "-",
|
|
14552
16065
|
onFocus: () => beginEdit(side, kind, val),
|
|
14553
16066
|
onBlur: () => endEdit(side, kind),
|
|
@@ -14758,8 +16271,8 @@ function STimeRangePicker({
|
|
|
14758
16271
|
disabled,
|
|
14759
16272
|
className,
|
|
14760
16273
|
style,
|
|
14761
|
-
children: /* @__PURE__ */ jsxs(
|
|
14762
|
-
/* @__PURE__ */ jsx(
|
|
16274
|
+
children: /* @__PURE__ */ jsxs(RPopover9.Root, { open, onOpenChange: commitOpen, children: [
|
|
16275
|
+
/* @__PURE__ */ jsx(RPopover9.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
14763
16276
|
"div",
|
|
14764
16277
|
{
|
|
14765
16278
|
ref: triggerRef,
|
|
@@ -14819,14 +16332,17 @@ function STimeRangePicker({
|
|
|
14819
16332
|
]
|
|
14820
16333
|
}
|
|
14821
16334
|
) }),
|
|
14822
|
-
/* @__PURE__ */ jsx(
|
|
14823
|
-
|
|
16335
|
+
/* @__PURE__ */ jsx(RPopover9.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
|
|
16336
|
+
RPopover9.Content,
|
|
14824
16337
|
{
|
|
14825
16338
|
side: "bottom",
|
|
14826
16339
|
align: "start",
|
|
14827
16340
|
sideOffset: 4,
|
|
14828
16341
|
alignOffset: popoverAlignOffset,
|
|
14829
|
-
className: cn(
|
|
16342
|
+
className: cn(
|
|
16343
|
+
"z-50 max-w-[var(--radix-popover-content-available-width)]",
|
|
16344
|
+
FLOATING_SLIDE_ANIM
|
|
16345
|
+
),
|
|
14830
16346
|
children: /* @__PURE__ */ jsx(
|
|
14831
16347
|
RangeTimeSelector,
|
|
14832
16348
|
{
|
|
@@ -14844,6 +16360,6 @@ function STimeRangePicker({
|
|
|
14844
16360
|
);
|
|
14845
16361
|
}
|
|
14846
16362
|
|
|
14847
|
-
export { BADGE_COLORS, BUTTON_COLORS, BUTTON_SIZES, COLOR_KEYS, GNB_COLORS, GNB_COMMON, GNB_FOLD_MS, GNB_FULL_LOGO_WIDTH, GNB_HEADER, GNB_MENU, GNB_MENU_WIDTH, GNB_RAIL, GNB_RAIL_WIDTH, ICONS, PAGE_BACKGROUNDS, SActionModal, SBadge, SBarcodeInput, SButton, SCROLL_AREA_AXES, SCalendar, SCallout, SCard, SCheckbox, SChip2 as SChip, SChipInput, SCircleProgress, SConfirmModal, SDatePicker, SDateRangePicker, SDivider, SDraggableGroup, SDraggableItem2 as SDraggableItem, SDraggableList, SDraggableProvider, SDrawer, SDropdownButton2 as SDropdownButton, SExpansionItem, SExpansionList2 as SExpansionList, SField, SFilePicker, SForm, SGhostButton, SGnb, SGuide, SIcon, SInput, SKeyValueTable, SLAYOUT_MIN_WIDTH, SLayout, SLayoutContext, SLinearProgress, SList2 as SList, SListItem2 as SListItem, SLoadingContainer, SLoadingModal, SLoadingViewport, SModal, SModalOutlet, SNumberInput, SPage, SPagination, SPopover, SPopup, SPortal, SRadio, SRadioButton, SRadioGroup, SSPLITTER_UNITS, SScrollArea, SSectionHeaderCard2 as SSectionHeaderCard, SSelect2 as SSelect, SSplitter2 as SSplitter, SStepper, SSwitch, STEPPER_SIZES, STable, STableBar, STabs, STag, STextLink, STextarea, STimePicker, STimeRangePicker, SToast, SToastContainer, SToggle, STooltip2 as STooltip, STree2 as STree, STreeItem2 as STreeItem, TAG_COLORS, TAG_SHAPES, TAG_SIZES, TIMEPICKER_SIZES, TIMEPICKER_SIZE_CONFIG, buttonPreset, cn, findGnbAncestors, findGnbRailValue, isColorKey, loading, resolveColor, useSLayout };
|
|
16363
|
+
export { BADGE_COLORS, BUTTON_COLORS, BUTTON_SIZES, COLOR_KEYS, GNB_COLORS, GNB_COMMON, GNB_FOLD_MS, GNB_FULL_LOGO_WIDTH, GNB_HEADER, GNB_MENU, GNB_MENU_WIDTH, GNB_RAIL, GNB_RAIL_WIDTH, ICONS, PAGE_BACKGROUNDS, RangeCalendar, SActionModal, SBadge, SBarcodeInput, SButton, SCROLL_AREA_AXES, SCalendar, SCallout, SCard, SCheckbox, SChip2 as SChip, SChipFilter, SChipInput, SCircleProgress, SConfirmModal, SDatePicker, SDateRangePicker, SDivider, SDraggableGroup, SDraggableItem2 as SDraggableItem, SDraggableList, SDraggableProvider, SDrawer, SDropdownButton2 as SDropdownButton, SExpansionItem, SExpansionList2 as SExpansionList, SField, SFilePicker, SForm, SGhostButton, SGnb, SGuide, SIcon, SInput, SKeyValueTable, SLAYOUT_MIN_WIDTH, SLayout, SLayoutContext, SLinearProgress, SList2 as SList, SListItem2 as SListItem, SLoadingContainer, SLoadingModal, SLoadingViewport, SModal, SModalOutlet, SNumberInput, SPage, SPagination, SPopover, SPopup, SPortal, SRadio, SRadioButton, SRadioGroup, SSPLITTER_UNITS, SScrollArea, SSectionHeaderCard2 as SSectionHeaderCard, SSelect2 as SSelect, SSplitter2 as SSplitter, SStepper, SSwitch, STEPPER_SIZES, STable, STableBar, STabs, STag, STextLink, STextarea, STimePicker, STimeRangePicker, SToast, SToastContainer, SToggle, STooltip2 as STooltip, STree2 as STree, STreeItem2 as STreeItem, TAG_COLORS, TAG_SHAPES, TAG_SIZES, TIMEPICKER_SIZES, TIMEPICKER_SIZE_CONFIG, buttonPreset, cn, findGnbAncestors, findGnbRailValue, isColorKey, loading, resolveColor, useSLayout };
|
|
14848
16364
|
//# sourceMappingURL=index.js.map
|
|
14849
16365
|
//# sourceMappingURL=index.js.map
|