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.cjs
CHANGED
|
@@ -7,7 +7,7 @@ var react = require('react');
|
|
|
7
7
|
var jsxRuntime = require('react/jsx-runtime');
|
|
8
8
|
var reactDom = require('react-dom');
|
|
9
9
|
var RCheckbox = require('@radix-ui/react-checkbox');
|
|
10
|
-
var
|
|
10
|
+
var RPopover9 = require('@radix-ui/react-popover');
|
|
11
11
|
var client = require('react-dom/client');
|
|
12
12
|
var RTooltip = require('@radix-ui/react-tooltip');
|
|
13
13
|
var RDropdown = require('@radix-ui/react-dropdown-menu');
|
|
@@ -34,7 +34,7 @@ function _interopNamespace(e) {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
var RCheckbox__namespace = /*#__PURE__*/_interopNamespace(RCheckbox);
|
|
37
|
-
var
|
|
37
|
+
var RPopover9__namespace = /*#__PURE__*/_interopNamespace(RPopover9);
|
|
38
38
|
var RTooltip__namespace = /*#__PURE__*/_interopNamespace(RTooltip);
|
|
39
39
|
var RDropdown__namespace = /*#__PURE__*/_interopNamespace(RDropdown);
|
|
40
40
|
var RSwitch__namespace = /*#__PURE__*/_interopNamespace(RSwitch);
|
|
@@ -2593,6 +2593,27 @@ var Icon_sidebar = (p) => {
|
|
|
2593
2593
|
}
|
|
2594
2594
|
);
|
|
2595
2595
|
};
|
|
2596
|
+
var Icon_star = (p) => {
|
|
2597
|
+
const { size = 24, ...rest } = p;
|
|
2598
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2599
|
+
"svg",
|
|
2600
|
+
{
|
|
2601
|
+
width: size,
|
|
2602
|
+
height: size,
|
|
2603
|
+
viewBox: "0 0 24 24",
|
|
2604
|
+
fill: "none",
|
|
2605
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2606
|
+
...rest,
|
|
2607
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2608
|
+
"path",
|
|
2609
|
+
{
|
|
2610
|
+
d: "M12.3358 3.45335C12.0755 2.84888 11.2185 2.84888 10.9582 3.45335L8.78136 8.50811C8.67278 8.76024 8.43512 8.93291 8.16178 8.95826L2.68175 9.46652C2.02642 9.5273 1.76157 10.3424 2.25602 10.7768L6.39071 14.409C6.59695 14.5902 6.68773 14.8696 6.62737 15.1374L5.41733 20.5063C5.27263 21.1483 5.966 21.6521 6.5319 21.3161L11.2641 18.5062C11.5001 18.366 11.7939 18.366 12.0299 18.5062L16.7621 21.3161C17.328 21.6521 18.0214 21.1483 17.8767 20.5063L16.6666 15.1374C16.6063 14.8696 16.6971 14.5902 16.9033 14.409L21.038 10.7768C21.5324 10.3424 21.2676 9.5273 20.6123 9.46652L15.1322 8.95826C14.8589 8.93291 14.6212 8.76024 14.5126 8.50811L12.3358 3.45335Z",
|
|
2611
|
+
fill: "currentColor"
|
|
2612
|
+
}
|
|
2613
|
+
)
|
|
2614
|
+
}
|
|
2615
|
+
);
|
|
2616
|
+
};
|
|
2596
2617
|
var Icon_store = (p) => {
|
|
2597
2618
|
const { size = 24, ...rest } = p;
|
|
2598
2619
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -3087,6 +3108,7 @@ var ICONS = {
|
|
|
3087
3108
|
settingOutline: Icon_settingOutline,
|
|
3088
3109
|
shield: Icon_shield,
|
|
3089
3110
|
sidebar: Icon_sidebar,
|
|
3111
|
+
star: Icon_star,
|
|
3090
3112
|
store: Icon_store,
|
|
3091
3113
|
synchronize: Icon_synchronize,
|
|
3092
3114
|
thumbsDown: Icon_thumbsDown,
|
|
@@ -3191,6 +3213,7 @@ var SDraggableItemView = /* @__PURE__ */ react.forwardRef(
|
|
|
3191
3213
|
bordered,
|
|
3192
3214
|
selected,
|
|
3193
3215
|
dense,
|
|
3216
|
+
size,
|
|
3194
3217
|
dragging,
|
|
3195
3218
|
disabled,
|
|
3196
3219
|
hovered,
|
|
@@ -3204,6 +3227,8 @@ var SDraggableItemView = /* @__PURE__ */ react.forwardRef(
|
|
|
3204
3227
|
const supportingTextNode = renderSlot(supportingText, renderState);
|
|
3205
3228
|
const hasSupportingText = supportingTextNode != null && supportingTextNode !== "";
|
|
3206
3229
|
const trailingNode = renderSlot(trailing, renderState);
|
|
3230
|
+
const titleTypo = size === "sm" ? selected ? "typo-item-sm-selected" : "typo-item-sm-default" : selected ? "typo-item-md-selected" : "typo-item-md-default";
|
|
3231
|
+
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)";
|
|
3207
3232
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3208
3233
|
"div",
|
|
3209
3234
|
{
|
|
@@ -3211,16 +3236,19 @@ var SDraggableItemView = /* @__PURE__ */ react.forwardRef(
|
|
|
3211
3236
|
"aria-disabled": disabled || void 0,
|
|
3212
3237
|
"data-dragging": dragging || void 0,
|
|
3213
3238
|
className: cn(
|
|
3214
|
-
"relative flex w-full items-center gap-(--cmp-listDraggableItem-gap) overflow-hidden px-(--cmp-listDraggableItem-paddingX)
|
|
3215
|
-
|
|
3239
|
+
"relative flex w-full items-center gap-(--cmp-listDraggableItem-gap) overflow-hidden px-(--cmp-listDraggableItem-paddingX)",
|
|
3240
|
+
titleTypo,
|
|
3241
|
+
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)",
|
|
3216
3242
|
!disabled && !selected && !dragging && "hover:bg-(--cmp-listDraggableItem-bg-hover)",
|
|
3217
|
-
hasSupportingText && supportingTextPosition === "bottom" ? dense ? "min-h-[52px]
|
|
3218
|
-
|
|
3243
|
+
hasSupportingText && supportingTextPosition === "bottom" ? dense ? "min-h-[52px]" : "min-h-[60px]" : dense ? "h-[32px]" : "h-[40px]",
|
|
3244
|
+
paddingYClass,
|
|
3245
|
+
// 항목 사이 구분선은 리스트가 그린다 — SDraggableList 의 separator (SList.tsx)
|
|
3246
|
+
bordered && cn(
|
|
3219
3247
|
"rounded-(--cmp-listDraggableItem-radius-bordered) border border-(--cmp-listDraggableItem-border-default)",
|
|
3220
3248
|
!disabled && !selected && !dragging && "hover:border-(--cmp-listDraggableItem-bordered-border-hover)",
|
|
3221
3249
|
!disabled && selected && !dragging && "border-(--cmp-listDraggableItem-bordered-border-selected) bg-(--cmp-listDraggableItem-bordered-bg-selected)",
|
|
3222
3250
|
!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)"
|
|
3223
|
-
)
|
|
3251
|
+
),
|
|
3224
3252
|
disabled && "cursor-not-allowed",
|
|
3225
3253
|
className
|
|
3226
3254
|
),
|
|
@@ -3272,7 +3300,7 @@ var SDraggableItemView = /* @__PURE__ */ react.forwardRef(
|
|
|
3272
3300
|
"span",
|
|
3273
3301
|
{
|
|
3274
3302
|
className: cn(
|
|
3275
|
-
"min-w-0 truncate text-
|
|
3303
|
+
"typo-body-sm-default min-w-0 truncate text-(--sys-color-fg-secondary)",
|
|
3276
3304
|
supportingTextPosition === "right" && "flex-1"
|
|
3277
3305
|
),
|
|
3278
3306
|
children: supportingTextNode
|
|
@@ -3300,6 +3328,7 @@ var SDraggableItemImpl = /* @__PURE__ */ react.forwardRef(function SDraggableIte
|
|
|
3300
3328
|
selected = false,
|
|
3301
3329
|
dragging = false,
|
|
3302
3330
|
dense = false,
|
|
3331
|
+
size = "sm",
|
|
3303
3332
|
disabled = false,
|
|
3304
3333
|
dragOverlay = true,
|
|
3305
3334
|
dragOverlayOpacity = 0.75,
|
|
@@ -3371,6 +3400,7 @@ var SDraggableItemImpl = /* @__PURE__ */ react.forwardRef(function SDraggableIte
|
|
|
3371
3400
|
bordered,
|
|
3372
3401
|
selected,
|
|
3373
3402
|
dense,
|
|
3403
|
+
size,
|
|
3374
3404
|
dragging: dragging || overlayVisible,
|
|
3375
3405
|
disabled,
|
|
3376
3406
|
hovered,
|
|
@@ -3405,6 +3435,7 @@ var SDraggableItemImpl = /* @__PURE__ */ react.forwardRef(function SDraggableIte
|
|
|
3405
3435
|
bordered,
|
|
3406
3436
|
selected,
|
|
3407
3437
|
dense,
|
|
3438
|
+
size,
|
|
3408
3439
|
dragging: true,
|
|
3409
3440
|
disabled,
|
|
3410
3441
|
hovered: true,
|
|
@@ -3419,7 +3450,7 @@ var SDraggableItemImpl = /* @__PURE__ */ react.forwardRef(function SDraggableIte
|
|
|
3419
3450
|
] });
|
|
3420
3451
|
});
|
|
3421
3452
|
var SDraggableItem2 = /* @__PURE__ */ withDisplayName(SDraggableItemImpl, "SDraggableItem");
|
|
3422
|
-
var SListImpl = /* @__PURE__ */ react.forwardRef(function SList({ className, children, useGap = false, usePadding = false, ...rest }, ref) {
|
|
3453
|
+
var SListImpl = /* @__PURE__ */ react.forwardRef(function SList({ className, children, useGap = false, usePadding = false, separator = false, ...rest }, ref) {
|
|
3423
3454
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3424
3455
|
"div",
|
|
3425
3456
|
{
|
|
@@ -3427,6 +3458,7 @@ var SListImpl = /* @__PURE__ */ react.forwardRef(function SList({ className, chi
|
|
|
3427
3458
|
className: cn(
|
|
3428
3459
|
useGap && "flex flex-col gap-(--cmp-list-group-gap)",
|
|
3429
3460
|
usePadding && "p-(--cmp-list-group-padding)",
|
|
3461
|
+
separator && "[&>*]:border-b [&>*]:border-(--cmp-listItem-border-default)",
|
|
3430
3462
|
className
|
|
3431
3463
|
),
|
|
3432
3464
|
...rest,
|
|
@@ -3756,6 +3788,7 @@ var SExpansionItem = /* @__PURE__ */ react.forwardRef(
|
|
|
3756
3788
|
interaction,
|
|
3757
3789
|
accentStripe = false,
|
|
3758
3790
|
dense = false,
|
|
3791
|
+
size = "sm",
|
|
3759
3792
|
disabled = false,
|
|
3760
3793
|
onToggle,
|
|
3761
3794
|
className,
|
|
@@ -3771,6 +3804,7 @@ var SExpansionItem = /* @__PURE__ */ react.forwardRef(
|
|
|
3771
3804
|
const hasChevronInteraction = interaction === "chevron";
|
|
3772
3805
|
const showInteractionChevron = hasChevronInteraction && !disabled && (isSelected || hovered);
|
|
3773
3806
|
const interactionChevronColor = isSelected ? "var(--sys-color-fg-brand)" : "var(--sys-color-fg-quaternary)";
|
|
3807
|
+
const titleTypo = size === "sm" ? isExpanded ? "typo-item-sm-selected" : "typo-item-sm-default" : isExpanded ? "typo-item-md-selected" : "typo-item-md-default";
|
|
3774
3808
|
const reportExpandedDescendant = react.useCallback(
|
|
3775
3809
|
(delta) => {
|
|
3776
3810
|
setExpandedDescendantCount((current) => Math.max(0, current + delta));
|
|
@@ -3796,7 +3830,7 @@ var SExpansionItem = /* @__PURE__ */ react.forwardRef(
|
|
|
3796
3830
|
ref,
|
|
3797
3831
|
className: cn(
|
|
3798
3832
|
"group/expansion-item relative overflow-hidden bg-(--cmp-listExpansionItem-title-bg-default)",
|
|
3799
|
-
|
|
3833
|
+
// 항목 사이 구분선은 리스트가 그린다 — SList/SExpansionList 의 separator (SList.tsx)
|
|
3800
3834
|
// 보더 색은 시맨틱 토큰(border-default → hover strong → 펼침 accentLight)을 쓴다.
|
|
3801
3835
|
// TODO: expansionItem/bordered/radius 토큰 생성 후 rounded 고정값도 토큰으로 교체한다.
|
|
3802
3836
|
bordered && "rounded-[8px] border border-border-default hover:border-border-strong [&:has(>button:hover)]:border-border-strong",
|
|
@@ -3828,7 +3862,8 @@ var SExpansionItem = /* @__PURE__ */ react.forwardRef(
|
|
|
3828
3862
|
onToggle?.(next, event);
|
|
3829
3863
|
},
|
|
3830
3864
|
className: cn(
|
|
3831
|
-
"group/expansion-item-button flex w-full cursor-pointer items-center justify-between border-0 text-left text-
|
|
3865
|
+
"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)",
|
|
3866
|
+
titleTypo,
|
|
3832
3867
|
isExpanded && "border-b border-(--cmp-listExpansionItem-title-border)",
|
|
3833
3868
|
hasChevronInteraction ? "hover:bg-(--sys-color-bg-neutralBright)" : !isExpanded && "hover:bg-(--cmp-listExpansionItem-title-bg-hover)",
|
|
3834
3869
|
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)",
|
|
@@ -3865,7 +3900,7 @@ var SExpansionItem = /* @__PURE__ */ react.forwardRef(
|
|
|
3865
3900
|
"span",
|
|
3866
3901
|
{
|
|
3867
3902
|
className: cn(
|
|
3868
|
-
"min-w-0 truncate text-
|
|
3903
|
+
"typo-body-sm-default min-w-0 truncate text-(--sys-color-fg-secondary)",
|
|
3869
3904
|
supportingTextPosition === "right" && "flex-1"
|
|
3870
3905
|
),
|
|
3871
3906
|
children: supportingText
|
|
@@ -3905,10 +3940,11 @@ var SListItemImpl = /* @__PURE__ */ react.forwardRef(function SListItem({
|
|
|
3905
3940
|
trailing,
|
|
3906
3941
|
bordered = false,
|
|
3907
3942
|
selected = false,
|
|
3908
|
-
clickable =
|
|
3943
|
+
clickable = false,
|
|
3909
3944
|
interaction,
|
|
3910
3945
|
accentStripe = false,
|
|
3911
3946
|
dense = false,
|
|
3947
|
+
size = "sm",
|
|
3912
3948
|
disabled = false,
|
|
3913
3949
|
className,
|
|
3914
3950
|
onMouseEnter,
|
|
@@ -3927,6 +3963,7 @@ var SListItemImpl = /* @__PURE__ */ react.forwardRef(function SListItem({
|
|
|
3927
3963
|
const hasChevronInteraction = interaction === "chevron";
|
|
3928
3964
|
const showInteractionChevron = hasChevronInteraction && isInteractive && (isSelected || hovered);
|
|
3929
3965
|
const interactionChevronColor = isSelected ? "var(--sys-color-fg-brand)" : "var(--sys-color-fg-quaternary)";
|
|
3966
|
+
const titleTypo = size === "sm" ? isSelected ? "typo-item-sm-selected" : "typo-item-sm-default" : isSelected ? "typo-item-md-selected" : "typo-item-md-default";
|
|
3930
3967
|
const handleMouseEnter = (event) => {
|
|
3931
3968
|
if (isInteractive) setHovered(true);
|
|
3932
3969
|
onMouseEnter?.(event);
|
|
@@ -3943,7 +3980,8 @@ var SListItemImpl = /* @__PURE__ */ react.forwardRef(function SListItem({
|
|
|
3943
3980
|
onMouseEnter: handleMouseEnter,
|
|
3944
3981
|
onMouseLeave: handleMouseLeave,
|
|
3945
3982
|
className: cn(
|
|
3946
|
-
"group/list-item relative flex w-full items-center justify-between bg-(--cmp-listItem-bg-default) text-left text-
|
|
3983
|
+
"group/list-item relative flex w-full items-center justify-between bg-(--cmp-listItem-bg-default) text-left text-(--cmp-listItem-text-default)",
|
|
3984
|
+
titleTypo,
|
|
3947
3985
|
disabled ? "pointer-events-none cursor-not-allowed text-(--sys-color-disabled-text)" : isSelected ? cn(
|
|
3948
3986
|
"cursor-pointer text-(--cmp-listItem-text-selected)",
|
|
3949
3987
|
"bg-(--cmp-listItem-bg-selected)"
|
|
@@ -3955,10 +3993,10 @@ var SListItemImpl = /* @__PURE__ */ react.forwardRef(function SListItem({
|
|
|
3955
3993
|
"gap-(--cmp-listItem-gap)",
|
|
3956
3994
|
"pr-(--cmp-listItem-paddingX)",
|
|
3957
3995
|
depth === 2 ? "pl-[36px]" : depth === 3 ? "pl-[56px]" : "pl-[16px]",
|
|
3958
|
-
bordered
|
|
3996
|
+
bordered && cn(
|
|
3959
3997
|
"overflow-hidden rounded-(--cmp-listItem-radius-bordered) border border-(--cmp-listItem-border-default)",
|
|
3960
3998
|
isSelected ? "border-(--cmp-listItem-bordered-border-selected)" : isInteractive && "hover:border-(--cmp-listItem-bordered-border-hover)"
|
|
3961
|
-
)
|
|
3999
|
+
),
|
|
3962
4000
|
className
|
|
3963
4001
|
),
|
|
3964
4002
|
...rest,
|
|
@@ -3984,7 +4022,7 @@ var SListItemImpl = /* @__PURE__ */ react.forwardRef(function SListItem({
|
|
|
3984
4022
|
"span",
|
|
3985
4023
|
{
|
|
3986
4024
|
className: cn(
|
|
3987
|
-
"min-w-0 truncate text-
|
|
4025
|
+
"typo-body-sm-default min-w-0 truncate text-(--sys-color-fg-secondary)",
|
|
3988
4026
|
supportingTextPosition === "right" && "flex-1"
|
|
3989
4027
|
),
|
|
3990
4028
|
children: supportingTextNode
|
|
@@ -4037,6 +4075,8 @@ var SExpansionListImpl = /* @__PURE__ */ react.forwardRef(function SExpansionLis
|
|
|
4037
4075
|
const depth2 = child.props.depth ?? 1;
|
|
4038
4076
|
const itemKey2 = String(child.key ?? index);
|
|
4039
4077
|
return react.cloneElement(child, {
|
|
4078
|
+
// 선택을 리스트가 관리하는 이상 아이템은 클릭 가능해야 한다 — SListItem 의 기본값(false)을 뒤집는다
|
|
4079
|
+
clickable: child.props.clickable ?? true,
|
|
4040
4080
|
selected: selectedKeys[depth2] === itemKey2,
|
|
4041
4081
|
onClick: (event) => {
|
|
4042
4082
|
setSelectedKeys((current) => ({ ...current, [depth2]: itemKey2 }));
|
|
@@ -4342,8 +4382,8 @@ function SGhostButton({
|
|
|
4342
4382
|
}
|
|
4343
4383
|
);
|
|
4344
4384
|
if (!hasTooltip) return btn;
|
|
4345
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4346
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4385
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(RPopover9__namespace.Root, { open, onOpenChange: setOpen, children: [
|
|
4386
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Anchor, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4347
4387
|
"span",
|
|
4348
4388
|
{
|
|
4349
4389
|
className: cn("inline-flex", anchorClassName),
|
|
@@ -4355,8 +4395,8 @@ function SGhostButton({
|
|
|
4355
4395
|
children: btn
|
|
4356
4396
|
}
|
|
4357
4397
|
) }),
|
|
4358
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4359
|
-
|
|
4398
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4399
|
+
RPopover9__namespace.Content,
|
|
4360
4400
|
{
|
|
4361
4401
|
side: "top",
|
|
4362
4402
|
sideOffset: 4,
|
|
@@ -4827,7 +4867,7 @@ var STooltipImpl = /* @__PURE__ */ react.forwardRef(function STooltip({
|
|
|
4827
4867
|
...restContentProps
|
|
4828
4868
|
} = contentProps ?? {};
|
|
4829
4869
|
const contentClass = cn(
|
|
4830
|
-
"z-50 w-fit
|
|
4870
|
+
"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",
|
|
4831
4871
|
FLOATING_SLIDE_ANIM,
|
|
4832
4872
|
className,
|
|
4833
4873
|
contentPropsClassName
|
|
@@ -4839,14 +4879,14 @@ var STooltipImpl = /* @__PURE__ */ react.forwardRef(function STooltip({
|
|
|
4839
4879
|
...style,
|
|
4840
4880
|
...contentPropsStyle
|
|
4841
4881
|
};
|
|
4842
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4882
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(RPopover9__namespace.Root, { open, onOpenChange: setOpenState, children: [
|
|
4843
4883
|
isNone ? (
|
|
4844
4884
|
// 트리거 없음: children 을 래퍼 없이 그대로 앵커로 쓴다 (소비자 레이아웃 보존).
|
|
4845
4885
|
// mouse/focus 핸들러가 없으므로 useClose 없이도 자동 닫힘이 발생하지 않는다.
|
|
4846
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4886
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Anchor, { asChild: true, children: triggerNode })
|
|
4847
4887
|
) : isHover ? (
|
|
4848
4888
|
// hover: Anchor(위치 기준) + 직접 mouse 핸들러 — 클릭으로 토글되지 않도록 Trigger 미사용
|
|
4849
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4889
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Anchor, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4850
4890
|
"span",
|
|
4851
4891
|
{
|
|
4852
4892
|
className: "inline-flex",
|
|
@@ -4857,9 +4897,9 @@ var STooltipImpl = /* @__PURE__ */ react.forwardRef(function STooltip({
|
|
|
4857
4897
|
children: triggerNode
|
|
4858
4898
|
}
|
|
4859
4899
|
) })
|
|
4860
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
4861
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4862
|
-
|
|
4900
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Trigger, { asChild: true, children: triggerNode }),
|
|
4901
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4902
|
+
RPopover9__namespace.Content,
|
|
4863
4903
|
{
|
|
4864
4904
|
side: placement,
|
|
4865
4905
|
sideOffset,
|
|
@@ -4893,7 +4933,7 @@ var STooltipImpl = /* @__PURE__ */ react.forwardRef(function STooltip({
|
|
|
4893
4933
|
}
|
|
4894
4934
|
)
|
|
4895
4935
|
] }),
|
|
4896
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4936
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Arrow, { width: 16, height: 12, style: { fill: bg } })
|
|
4897
4937
|
]
|
|
4898
4938
|
}
|
|
4899
4939
|
) })
|
|
@@ -5901,6 +5941,15 @@ var STextLink = /* @__PURE__ */ react.forwardRef(function STextLink2({
|
|
|
5901
5941
|
/* @__PURE__ */ jsxRuntime.jsx(RTooltip__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(RTooltip__namespace.Content, { side: "top", sideOffset: 4, className: cn("z-50", FLOATING_SLIDE_ANIM), children: /* @__PURE__ */ jsxRuntime.jsx(STag, { shape: "square", size: "xs", color: "grey", label: text }) }) })
|
|
5902
5942
|
] }) });
|
|
5903
5943
|
});
|
|
5944
|
+
|
|
5945
|
+
// src/lib/floating-width.ts
|
|
5946
|
+
var POPOVER_AVAILABLE_WIDTH = "var(--radix-popover-content-available-width)";
|
|
5947
|
+
var DROPDOWN_AVAILABLE_WIDTH = "var(--radix-dropdown-menu-content-available-width)";
|
|
5948
|
+
function clampToAvailableWidth(value, availableWidth) {
|
|
5949
|
+
if (value == null || value === "") return availableWidth;
|
|
5950
|
+
const css = typeof value === "number" ? `${value}px` : value;
|
|
5951
|
+
return `min(${css}, ${availableWidth})`;
|
|
5952
|
+
}
|
|
5904
5953
|
var SIZE2 = {
|
|
5905
5954
|
xs: { height: 24, paddingX: 8, gap: 6, arrow: 12, fontSize: 12, minWidth: 64, splitMinWidth: 72 },
|
|
5906
5955
|
sm: {
|
|
@@ -5937,6 +5986,7 @@ function splitDivider(color, outline) {
|
|
|
5937
5986
|
};
|
|
5938
5987
|
return (outline ? outlined : solid)[color];
|
|
5939
5988
|
}
|
|
5989
|
+
var VIEWPORT_PADDING = 12;
|
|
5940
5990
|
var itemClass = cn(
|
|
5941
5991
|
"flex min-h-[28px] cursor-pointer select-none items-center gap-[8px] rounded-[2px] px-[12px] py-[4px] text-[12px] leading-[20px] outline-none",
|
|
5942
5992
|
"text-[color:var(--sys-color-fg-secondary)]",
|
|
@@ -6018,12 +6068,16 @@ var SDropdownButtonImpl = /* @__PURE__ */ react.forwardRef(
|
|
|
6018
6068
|
sideOffset: 4,
|
|
6019
6069
|
align: "start",
|
|
6020
6070
|
alignOffset: split ? splitAlignOffset : 0,
|
|
6071
|
+
collisionPadding: VIEWPORT_PADDING,
|
|
6021
6072
|
className: cn(
|
|
6022
6073
|
"z-50 overflow-hidden rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] shadow-normal-sm",
|
|
6023
|
-
|
|
6074
|
+
// 창보다 넓은 메뉴는 창 폭에 맞춰 줄인다. 트리거 너비를 따르는 하한도 같은 상한으로
|
|
6075
|
+
// 감싸야 한다 — min-width 가 max-width 를 이기기 때문이다.
|
|
6076
|
+
"max-w-[var(--radix-dropdown-menu-content-available-width)]",
|
|
6077
|
+
!split && "min-w-[min(var(--radix-dropdown-menu-trigger-width),var(--radix-dropdown-menu-content-available-width))]",
|
|
6024
6078
|
FLOATING_SLIDE_ANIM
|
|
6025
6079
|
),
|
|
6026
|
-
style: split ? { minWidth: splitWidth } : void 0,
|
|
6080
|
+
style: split ? { minWidth: clampToAvailableWidth(splitWidth, DROPDOWN_AVAILABLE_WIDTH) } : void 0,
|
|
6027
6081
|
children: items.map((it) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6028
6082
|
RDropdown__namespace.Item,
|
|
6029
6083
|
{
|
|
@@ -6035,7 +6089,7 @@ var SDropdownButtonImpl = /* @__PURE__ */ react.forwardRef(
|
|
|
6035
6089
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6036
6090
|
"span",
|
|
6037
6091
|
{
|
|
6038
|
-
className: "min-w-0
|
|
6092
|
+
className: "min-w-0 break-words",
|
|
6039
6093
|
dangerouslySetInnerHTML: { __html: sanitizeInlineHtml(it.label) }
|
|
6040
6094
|
}
|
|
6041
6095
|
)
|
|
@@ -6247,16 +6301,20 @@ function SPopover({
|
|
|
6247
6301
|
const descColor = type === "default" ? "var(--cmp-popover-default-description)" : "var(--cmp-popover-light-description)";
|
|
6248
6302
|
const leftLinkLabelClass = type === "default" ? "text-[color:var(--cmp-popover-default-subAction)]" : "text-[color:var(--cmp-popover-light-subAction)]";
|
|
6249
6303
|
const triggerNode = trigger ?? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex cursor-pointer", "aria-label": ariaLabel, children: /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: icon, size: iconSize, color }) });
|
|
6250
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6251
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6252
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6253
|
-
|
|
6304
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(RPopover9__namespace.Root, { open: actualOpen, onOpenChange: setOpen, children: [
|
|
6305
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Trigger, { asChild: true, children: triggerNode }),
|
|
6306
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6307
|
+
RPopover9__namespace.Content,
|
|
6254
6308
|
{
|
|
6255
6309
|
side: placement,
|
|
6256
6310
|
sideOffset: 8,
|
|
6257
6311
|
className: cn(
|
|
6258
6312
|
// 닫기 버튼이 항상 있으므로 우측은 close clearance(36px) 로 고정
|
|
6259
|
-
"relative z-50 flex
|
|
6313
|
+
"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",
|
|
6314
|
+
// 창보다 넓어지면 창 폭에 맞춘다. 최소 너비도 같은 상한으로 감싼다 —
|
|
6315
|
+
// min-width 가 max-width 를 이기므로 감싸지 않으면 상한이 무력화된다.
|
|
6316
|
+
"max-w-[var(--radix-popover-content-available-width)]",
|
|
6317
|
+
"min-w-[min(160px,var(--radix-popover-content-available-width))]",
|
|
6260
6318
|
FLOATING_SLIDE_ANIM,
|
|
6261
6319
|
menuClassName
|
|
6262
6320
|
),
|
|
@@ -6312,7 +6370,7 @@ function SPopover({
|
|
|
6312
6370
|
]
|
|
6313
6371
|
}
|
|
6314
6372
|
),
|
|
6315
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6373
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Arrow, { width: 16, height: 12, style: { fill: bg } })
|
|
6316
6374
|
]
|
|
6317
6375
|
}
|
|
6318
6376
|
) })
|
|
@@ -6341,8 +6399,9 @@ function SPortal({
|
|
|
6341
6399
|
ariaLabel
|
|
6342
6400
|
}) {
|
|
6343
6401
|
const portalContainer = usePortalContainer();
|
|
6402
|
+
const { minWidth: styleMinWidth, maxWidth: styleMaxWidth, ...restStyle } = style ?? {};
|
|
6344
6403
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6345
|
-
|
|
6404
|
+
RPopover9__namespace.Root,
|
|
6346
6405
|
{
|
|
6347
6406
|
open,
|
|
6348
6407
|
onOpenChange: (next) => {
|
|
@@ -6350,9 +6409,9 @@ function SPortal({
|
|
|
6350
6409
|
if (!next) onClose?.();
|
|
6351
6410
|
},
|
|
6352
6411
|
children: [
|
|
6353
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6354
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6355
|
-
|
|
6412
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Anchor, { virtualRef: anchorRef }),
|
|
6413
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6414
|
+
RPopover9__namespace.Content,
|
|
6356
6415
|
{
|
|
6357
6416
|
side: placement,
|
|
6358
6417
|
align,
|
|
@@ -6379,11 +6438,18 @@ function SPortal({
|
|
|
6379
6438
|
className: cn(
|
|
6380
6439
|
"z-50 overflow-hidden rounded-(--cmp-listBox-radius) bg-(--cmp-listBox-bg) shadow-normal-sm",
|
|
6381
6440
|
maxHeight != null && "overflow-y-auto",
|
|
6382
|
-
|
|
6441
|
+
// 앵커가 창보다 넓을 수 있는 자리(가로 스크롤 안의 트리거 등)에서도 하한이 상한을
|
|
6442
|
+
// 이기지 않도록, 앵커 너비 역시 가용 폭으로 가둔다.
|
|
6443
|
+
fit && "min-w-[min(var(--radix-popover-trigger-width),var(--radix-popover-content-available-width))]",
|
|
6383
6444
|
FLOATING_SLIDE_ANIM,
|
|
6384
6445
|
className
|
|
6385
6446
|
),
|
|
6386
|
-
style: {
|
|
6447
|
+
style: {
|
|
6448
|
+
maxHeight,
|
|
6449
|
+
...restStyle,
|
|
6450
|
+
...styleMinWidth != null ? { minWidth: clampToAvailableWidth(styleMinWidth, POPOVER_AVAILABLE_WIDTH) } : {},
|
|
6451
|
+
maxWidth: clampToAvailableWidth(styleMaxWidth, POPOVER_AVAILABLE_WIDTH)
|
|
6452
|
+
},
|
|
6387
6453
|
children
|
|
6388
6454
|
}
|
|
6389
6455
|
) })
|
|
@@ -6543,16 +6609,18 @@ function SGuide({
|
|
|
6543
6609
|
);
|
|
6544
6610
|
if (isNotion)
|
|
6545
6611
|
return /* @__PURE__ */ jsxRuntime.jsx("span", { className, style, children: trigger });
|
|
6546
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6547
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6548
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6549
|
-
|
|
6612
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(RPopover9__namespace.Root, { open, onOpenChange: setOpen, children: [
|
|
6613
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Trigger, { asChild: true, children: trigger }),
|
|
6614
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6615
|
+
RPopover9__namespace.Content,
|
|
6550
6616
|
{
|
|
6551
6617
|
side: "bottom",
|
|
6552
6618
|
align: "start",
|
|
6553
6619
|
sideOffset: 4,
|
|
6554
6620
|
className: cn(
|
|
6555
6621
|
"relative z-50 rounded-[var(--cmp-guide-contents-radius)] bg-[var(--color-white)]",
|
|
6622
|
+
// popupWidth(기본 426px)가 창보다 넓으면 창 폭에 맞춘다 — max-width 가 width 를 이긴다.
|
|
6623
|
+
"max-w-[var(--radix-popover-content-available-width)]",
|
|
6556
6624
|
FLOATING_SLIDE_ANIM
|
|
6557
6625
|
),
|
|
6558
6626
|
style: {
|
|
@@ -7057,6 +7125,8 @@ function SLoadingModal({
|
|
|
7057
7125
|
);
|
|
7058
7126
|
}
|
|
7059
7127
|
var CLOSE_ANIMATION_DURATION2 = 300;
|
|
7128
|
+
var RESIZE_KEY_STEP = { normal: 10, large: 50 };
|
|
7129
|
+
var RESIZE_HIT_WIDTH = "calc(var(--cmp-splitter-border-width) + var(--cmp-splitter-border-padding) * 2)";
|
|
7060
7130
|
function toPx(value, percentBase) {
|
|
7061
7131
|
if (typeof value === "number") return value;
|
|
7062
7132
|
if (typeof value !== "string") return void 0;
|
|
@@ -7094,6 +7164,7 @@ function SDrawer({
|
|
|
7094
7164
|
resizable = false,
|
|
7095
7165
|
minWidth,
|
|
7096
7166
|
maxWidth,
|
|
7167
|
+
onWidthChange,
|
|
7097
7168
|
footerLeft,
|
|
7098
7169
|
button,
|
|
7099
7170
|
children,
|
|
@@ -7106,11 +7177,16 @@ function SDrawer({
|
|
|
7106
7177
|
const [portalContainer, setPortalContainer] = react.useState(null);
|
|
7107
7178
|
const backdropPointerDownRef = react.useRef(false);
|
|
7108
7179
|
const contentRef = react.useRef(null);
|
|
7180
|
+
const panelRef = react.useRef(null);
|
|
7109
7181
|
const stackRegistrationRef = react.useRef(null);
|
|
7110
7182
|
const resizeCleanupRef = react.useRef(null);
|
|
7111
|
-
const resizeStateRef = react.useRef(null);
|
|
7112
7183
|
const [layerIndex, setLayerIndex] = react.useState(null);
|
|
7113
7184
|
const [currentWidth, setCurrentWidth] = react.useState(width);
|
|
7185
|
+
const [resizing, setResizing] = react.useState(false);
|
|
7186
|
+
const [measuredWidth, setMeasuredWidth] = react.useState(null);
|
|
7187
|
+
const [viewportWidth, setViewportWidth] = react.useState(
|
|
7188
|
+
() => typeof window === "undefined" ? void 0 : window.innerWidth
|
|
7189
|
+
);
|
|
7114
7190
|
react.useEffect(() => {
|
|
7115
7191
|
setCurrentWidth(width);
|
|
7116
7192
|
}, [width]);
|
|
@@ -7126,6 +7202,22 @@ function SDrawer({
|
|
|
7126
7202
|
react.useEffect(() => {
|
|
7127
7203
|
return () => resizeCleanupRef.current?.();
|
|
7128
7204
|
}, []);
|
|
7205
|
+
react.useEffect(() => {
|
|
7206
|
+
if (!rendered) return;
|
|
7207
|
+
const sync = () => setViewportWidth(window.innerWidth);
|
|
7208
|
+
sync();
|
|
7209
|
+
window.addEventListener("resize", sync);
|
|
7210
|
+
return () => window.removeEventListener("resize", sync);
|
|
7211
|
+
}, [rendered]);
|
|
7212
|
+
react.useEffect(() => {
|
|
7213
|
+
const panel = panelRef.current;
|
|
7214
|
+
if (!resizable || !rendered || !panel || typeof ResizeObserver === "undefined") return;
|
|
7215
|
+
const observer = new ResizeObserver(
|
|
7216
|
+
() => setMeasuredWidth(Math.round(panel.getBoundingClientRect().width))
|
|
7217
|
+
);
|
|
7218
|
+
observer.observe(panel);
|
|
7219
|
+
return () => observer.disconnect();
|
|
7220
|
+
}, [resizable, rendered]);
|
|
7129
7221
|
react.useEffect(() => {
|
|
7130
7222
|
if (!open) {
|
|
7131
7223
|
setEntered(false);
|
|
@@ -7167,41 +7259,80 @@ function SDrawer({
|
|
|
7167
7259
|
}
|
|
7168
7260
|
onOpenChange?.(false);
|
|
7169
7261
|
};
|
|
7262
|
+
const resizeBounds = () => {
|
|
7263
|
+
const limit = viewportWidth;
|
|
7264
|
+
if (limit === void 0) return { min: void 0, max: void 0 };
|
|
7265
|
+
const min = toPx(minWidth, limit);
|
|
7266
|
+
const max = toPx(maxWidth, limit);
|
|
7267
|
+
return {
|
|
7268
|
+
min: min === void 0 ? void 0 : Math.min(min, limit),
|
|
7269
|
+
max: max === void 0 ? limit : Math.min(max, limit)
|
|
7270
|
+
};
|
|
7271
|
+
};
|
|
7272
|
+
const commitWidth = (next, startWidth) => {
|
|
7273
|
+
const { min, max } = resizeBounds();
|
|
7274
|
+
const clamped = Math.round(clamp3(next, min, max));
|
|
7275
|
+
setCurrentWidth(clamped);
|
|
7276
|
+
if (clamped !== Math.round(startWidth)) onWidthChange?.(clamped);
|
|
7277
|
+
};
|
|
7170
7278
|
const handleResizeStart = (event) => {
|
|
7279
|
+
if (typeof document === "undefined") return;
|
|
7280
|
+
const panel = panelRef.current;
|
|
7281
|
+
if (!panel) return;
|
|
7171
7282
|
event.preventDefault();
|
|
7172
7283
|
event.stopPropagation();
|
|
7173
|
-
|
|
7174
|
-
|
|
7175
|
-
|
|
7176
|
-
|
|
7177
|
-
|
|
7178
|
-
|
|
7179
|
-
|
|
7180
|
-
|
|
7284
|
+
event.currentTarget.focus();
|
|
7285
|
+
const startX = event.clientX;
|
|
7286
|
+
const startWidth = panel.getBoundingClientRect().width;
|
|
7287
|
+
const { min, max } = resizeBounds();
|
|
7288
|
+
let latest = startWidth;
|
|
7289
|
+
const { body } = document;
|
|
7290
|
+
const previousCursor = body.style.cursor;
|
|
7291
|
+
const previousUserSelect = body.style.userSelect;
|
|
7181
7292
|
const onMove = (moveEvent) => {
|
|
7182
|
-
|
|
7183
|
-
|
|
7184
|
-
const nextWidth = resizeState.startWidth + resizeState.startX - moveEvent.clientX;
|
|
7185
|
-
setCurrentWidth(clamp3(nextWidth, resizeState.minWidth, resizeState.maxWidth));
|
|
7293
|
+
latest = Math.round(clamp3(startWidth + (startX - moveEvent.clientX), min, max));
|
|
7294
|
+
setCurrentWidth(latest);
|
|
7186
7295
|
};
|
|
7187
|
-
resizeCleanupRef.current?.();
|
|
7188
|
-
const previousCursor = document.body.style.cursor;
|
|
7189
|
-
const previousUserSelect = document.body.style.userSelect;
|
|
7190
7296
|
const cleanupResize = () => {
|
|
7191
|
-
|
|
7192
|
-
|
|
7193
|
-
document.body.style.userSelect = previousUserSelect;
|
|
7297
|
+
body.style.cursor = previousCursor;
|
|
7298
|
+
body.style.userSelect = previousUserSelect;
|
|
7194
7299
|
document.removeEventListener("mousemove", onMove);
|
|
7195
7300
|
document.removeEventListener("mouseup", cleanupResize);
|
|
7196
7301
|
resizeCleanupRef.current = null;
|
|
7302
|
+
setResizing(false);
|
|
7303
|
+
commitWidth(latest, startWidth);
|
|
7197
7304
|
};
|
|
7305
|
+
resizeCleanupRef.current?.();
|
|
7198
7306
|
resizeCleanupRef.current = cleanupResize;
|
|
7199
|
-
|
|
7200
|
-
|
|
7307
|
+
body.style.cursor = "col-resize";
|
|
7308
|
+
body.style.userSelect = "none";
|
|
7201
7309
|
document.addEventListener("mousemove", onMove);
|
|
7202
7310
|
document.addEventListener("mouseup", cleanupResize);
|
|
7311
|
+
setResizing(true);
|
|
7312
|
+
};
|
|
7313
|
+
const handleResizeKeyDown = (event) => {
|
|
7314
|
+
const panel = panelRef.current;
|
|
7315
|
+
if (!panel) return;
|
|
7316
|
+
const startWidth = panel.getBoundingClientRect().width;
|
|
7317
|
+
const { min, max } = resizeBounds();
|
|
7318
|
+
const step = RESIZE_KEY_STEP[event.shiftKey ? "large" : "normal"];
|
|
7319
|
+
let next = null;
|
|
7320
|
+
if (event.key === "ArrowLeft") next = startWidth + step;
|
|
7321
|
+
else if (event.key === "ArrowRight") next = startWidth - step;
|
|
7322
|
+
else if (event.key === "Home" && min !== void 0) next = min;
|
|
7323
|
+
else if (event.key === "End" && max !== void 0) next = max;
|
|
7324
|
+
if (next === null) return;
|
|
7325
|
+
event.preventDefault();
|
|
7326
|
+
commitWidth(next, startWidth);
|
|
7203
7327
|
};
|
|
7204
7328
|
const modalHost = getModalHost();
|
|
7329
|
+
const resizeValueNow = measuredWidth ?? (typeof currentWidth === "number" ? Math.round(currentWidth) : void 0);
|
|
7330
|
+
const { min: resizeMinPx, max: resizeMaxPx } = resizeBounds();
|
|
7331
|
+
const resizeValueMin = resizeMinPx === void 0 ? void 0 : Math.round(resizeMinPx);
|
|
7332
|
+
const resizeValueMax = resizeMaxPx === void 0 ? void 0 : Math.round(resizeMaxPx);
|
|
7333
|
+
const appliedWidth = typeof currentWidth === "number" && viewportWidth !== void 0 ? Math.min(currentWidth, viewportWidth) : currentWidth;
|
|
7334
|
+
const appliedMinWidth = resizeMinPx ?? minWidth;
|
|
7335
|
+
const appliedMaxWidth = resizeMaxPx ?? maxWidth;
|
|
7205
7336
|
return /* @__PURE__ */ jsxRuntime.jsx(RDialog__namespace.Root, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsx(RDialog__namespace.Portal, { container: modalHost, forceMount: rendered ? true : void 0, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pointer-events-none absolute inset-0", style: { zIndex: layerIndex ?? 0 }, children: [
|
|
7206
7337
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7207
7338
|
RDialog__namespace.Overlay,
|
|
@@ -7243,6 +7374,7 @@ function SDrawer({
|
|
|
7243
7374
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
7244
7375
|
"div",
|
|
7245
7376
|
{
|
|
7377
|
+
ref: panelRef,
|
|
7246
7378
|
className: cn(
|
|
7247
7379
|
"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",
|
|
7248
7380
|
shaking && "animate-drawer-shake",
|
|
@@ -7250,20 +7382,45 @@ function SDrawer({
|
|
|
7250
7382
|
),
|
|
7251
7383
|
"data-s-drawer-panel": true,
|
|
7252
7384
|
"data-state": open && entered ? "open" : "closed",
|
|
7253
|
-
style: {
|
|
7385
|
+
style: {
|
|
7386
|
+
width: appliedWidth,
|
|
7387
|
+
minWidth: appliedMinWidth,
|
|
7388
|
+
maxWidth: appliedMaxWidth,
|
|
7389
|
+
...style
|
|
7390
|
+
},
|
|
7254
7391
|
onAnimationEnd: (event) => {
|
|
7255
7392
|
if (event.animationName === "drawer-shake") setShaking(false);
|
|
7256
7393
|
},
|
|
7257
7394
|
children: [
|
|
7258
|
-
resizable && /* @__PURE__ */ jsxRuntime.jsx(
|
|
7259
|
-
"
|
|
7395
|
+
resizable && /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7396
|
+
"div",
|
|
7260
7397
|
{
|
|
7261
|
-
|
|
7398
|
+
role: "separator",
|
|
7399
|
+
"aria-orientation": "vertical",
|
|
7262
7400
|
"aria-label": "Drawer \uB108\uBE44 \uC870\uC808",
|
|
7263
|
-
|
|
7264
|
-
|
|
7401
|
+
"aria-valuenow": resizeValueNow,
|
|
7402
|
+
"aria-valuemin": resizeValueMin,
|
|
7403
|
+
"aria-valuemax": resizeValueMax,
|
|
7404
|
+
"aria-valuetext": resizeValueNow === void 0 ? void 0 : `${resizeValueNow}px`,
|
|
7405
|
+
tabIndex: 0,
|
|
7406
|
+
onMouseDown: handleResizeStart,
|
|
7407
|
+
onKeyDown: handleResizeKeyDown,
|
|
7408
|
+
className: "group absolute inset-y-0 left-0 z-[1] flex cursor-col-resize touch-none justify-start outline-none",
|
|
7409
|
+
style: { width: RESIZE_HIT_WIDTH },
|
|
7410
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7411
|
+
"span",
|
|
7412
|
+
{
|
|
7413
|
+
"aria-hidden": true,
|
|
7414
|
+
className: cn(
|
|
7415
|
+
// 평상시엔 자리만 잡고 칠하지 않는다 — 색이 붙는 것 자체가 조절 가능하다는 신호다.
|
|
7416
|
+
"w-(--cmp-splitter-border-width) transition-colors",
|
|
7417
|
+
"group-hover:bg-(--cmp-splitter-border-color) group-focus-visible:bg-(--cmp-splitter-border-color)",
|
|
7418
|
+
resizing && "bg-(--cmp-splitter-border-color)"
|
|
7419
|
+
)
|
|
7420
|
+
}
|
|
7421
|
+
)
|
|
7265
7422
|
}
|
|
7266
|
-
),
|
|
7423
|
+
) }),
|
|
7267
7424
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7268
7425
|
SOverlayHeader,
|
|
7269
7426
|
{
|
|
@@ -7936,8 +8093,11 @@ var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
|
|
|
7936
8093
|
onLauncherClick,
|
|
7937
8094
|
logo,
|
|
7938
8095
|
topContent,
|
|
8096
|
+
railTop,
|
|
7939
8097
|
railFooter,
|
|
8098
|
+
menuTop,
|
|
7940
8099
|
menuFooter,
|
|
8100
|
+
foldedTop,
|
|
7941
8101
|
foldedFooter,
|
|
7942
8102
|
resizable = false,
|
|
7943
8103
|
menuWidth: menuWidthProp,
|
|
@@ -8446,6 +8606,7 @@ var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
|
|
|
8446
8606
|
] })
|
|
8447
8607
|
}
|
|
8448
8608
|
),
|
|
8609
|
+
railFolded && foldedTop && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-[24px] flex shrink-0 items-center justify-center", children: foldedTop }),
|
|
8449
8610
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
8450
8611
|
"div",
|
|
8451
8612
|
{
|
|
@@ -8463,9 +8624,9 @@ var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
|
|
|
8463
8624
|
transition: `transform ${GNB_FOLD_MS}ms ease-out, ${hideAfterSlide(folded)}`
|
|
8464
8625
|
},
|
|
8465
8626
|
children: [
|
|
8466
|
-
useRail && // 레일 컬럼 — 스크롤되는 아이템 목록(nav)
|
|
8467
|
-
//
|
|
8468
|
-
// 전체 높이에 걸쳐 책임진다(그래야
|
|
8627
|
+
useRail && // 레일 컬럼 — 스크롤되는 아이템 목록(nav)을 가운데 두고 위아래에 고정 슬롯(top/footer)을 붙인다.
|
|
8628
|
+
// 두 슬롯은 내비게이션이 아니므로 nav(landmark) 밖에 두고, 컬럼 폭·구분선·배경은 이 래퍼가
|
|
8629
|
+
// 전체 높이에 걸쳐 책임진다(그래야 슬롯 자리까지 배경·오른쪽 선이 이어진다).
|
|
8469
8630
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
8470
8631
|
"div",
|
|
8471
8632
|
{
|
|
@@ -8476,6 +8637,7 @@ var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
|
|
|
8476
8637
|
backgroundColor: C.panelBg
|
|
8477
8638
|
},
|
|
8478
8639
|
children: [
|
|
8640
|
+
railTop && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: railTop }),
|
|
8479
8641
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8480
8642
|
"nav",
|
|
8481
8643
|
{
|
|
@@ -8503,6 +8665,7 @@ var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
|
|
|
8503
8665
|
borderRight: isFull ? rightBorder : void 0
|
|
8504
8666
|
},
|
|
8505
8667
|
children: [
|
|
8668
|
+
menuTop && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: menuTop }),
|
|
8506
8669
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8507
8670
|
"nav",
|
|
8508
8671
|
{
|
|
@@ -8530,10 +8693,10 @@ var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
|
|
|
8530
8693
|
}
|
|
8531
8694
|
),
|
|
8532
8695
|
header === "fix" && menuResizeHandle,
|
|
8533
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
8534
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8535
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8536
|
-
|
|
8696
|
+
/* @__PURE__ */ jsxRuntime.jsxs(RPopover9__namespace.Root, { open: labelTip !== null, onOpenChange: (open) => !open && setLabelTip(null), children: [
|
|
8697
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Anchor, { virtualRef: labelTipAnchorRef }),
|
|
8698
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
8699
|
+
RPopover9__namespace.Content,
|
|
8537
8700
|
{
|
|
8538
8701
|
side: "right",
|
|
8539
8702
|
sideOffset: 4,
|
|
@@ -8551,16 +8714,81 @@ var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
|
|
|
8551
8714
|
}
|
|
8552
8715
|
);
|
|
8553
8716
|
});
|
|
8717
|
+
var SPageHeader = /* @__PURE__ */ withDisplayName(
|
|
8718
|
+
react.forwardRef(function SPageHeader2({ title, subText, fix = false, onBack, slot, scrolled = false, className, style, ...rest }, ref) {
|
|
8719
|
+
const hasBack = onBack != null;
|
|
8720
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8721
|
+
"header",
|
|
8722
|
+
{
|
|
8723
|
+
ref,
|
|
8724
|
+
className: cn(
|
|
8725
|
+
"relative z-10 box-border flex shrink-0 items-center gap-(--cmp-pageHeader-gap) px-(--cmp-pageHeader-paddingX)",
|
|
8726
|
+
fix ? "h-(--cmp-pageHeader-bar-height) border-b border-(--cmp-pageHeader-bar-border) bg-(--cmp-pageHeader-bar-bg) py-(--cmp-pageHeader-bar-paddingY)" : cn(
|
|
8727
|
+
// 배경은 항상 투명 — 페이지 배경을 따라갈지는 fix 가 정하지 scrolled 가 정하지 않는다.
|
|
8728
|
+
// 스크롤되면 그림자만 더해 콘텐츠 위에 뜬 것처럼 보이게 한다.
|
|
8729
|
+
"bg-transparent pt-(--cmp-pageHeader-plain-paddingTop) pb-(--cmp-pageHeader-plain-paddingBottom)",
|
|
8730
|
+
scrolled && "shadow-floating"
|
|
8731
|
+
),
|
|
8732
|
+
className
|
|
8733
|
+
),
|
|
8734
|
+
style,
|
|
8735
|
+
...rest,
|
|
8736
|
+
children: [
|
|
8737
|
+
hasBack && /* @__PURE__ */ jsxRuntime.jsx(
|
|
8738
|
+
SGhostButton,
|
|
8739
|
+
{
|
|
8740
|
+
icon: "chevronLeft",
|
|
8741
|
+
size: "xs",
|
|
8742
|
+
ariaLabel: "\uB4A4\uB85C\uAC00\uAE30",
|
|
8743
|
+
onClick: onBack,
|
|
8744
|
+
className: "shrink-0"
|
|
8745
|
+
}
|
|
8746
|
+
),
|
|
8747
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
8748
|
+
"div",
|
|
8749
|
+
{
|
|
8750
|
+
className: cn(
|
|
8751
|
+
"flex min-w-0 flex-1 items-center",
|
|
8752
|
+
fix ? "flex-row gap-(--cmp-pageHeader-gap)" : "flex-col items-start gap-(--cmp-pageHeader-plain-title-gap)",
|
|
8753
|
+
!hasBack && "pl-(--cmp-pageHeader-title-paddingLeft)"
|
|
8754
|
+
),
|
|
8755
|
+
children: [
|
|
8756
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "typo-heading-lg min-w-0 truncate text-(--cmp-pageHeader-title-text)", children: title }),
|
|
8757
|
+
subText && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "typo-body-md-default min-w-0 truncate text-(--cmp-pageHeader-subtitle-text)", children: subText })
|
|
8758
|
+
]
|
|
8759
|
+
}
|
|
8760
|
+
),
|
|
8761
|
+
slot && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-auto flex shrink-0 items-center", children: slot })
|
|
8762
|
+
]
|
|
8763
|
+
}
|
|
8764
|
+
);
|
|
8765
|
+
}),
|
|
8766
|
+
"SPageHeader"
|
|
8767
|
+
);
|
|
8554
8768
|
var MIN_CONTENT_WIDTH = `calc(var(${SLAYOUT_MIN_WIDTH_VAR}, 0px) - 100cqw + 100%)`;
|
|
8555
8769
|
var BACKGROUND_CLASS = {
|
|
8556
8770
|
frame: `bg-[var(--sys-color-bg-frame)] ${SCROLLBAR_TRACK_BORDER_CLASS} ${SCROLLBAR_TRACK_BG_CLASS}`,
|
|
8557
8771
|
neutral: `bg-[var(--sys-color-bg-neutralLight)] ${SCROLLBAR_TRACK_BORDER_CLASS} ${SCROLLBAR_TRACK_BG_WHITE_CLASS}`,
|
|
8558
8772
|
screen: `bg-[var(--sys-color-bg-screen)] ${SCROLLBAR_TRACK_BORDER_CLASS} ${SCROLLBAR_TRACK_BG_CLASS}`
|
|
8559
8773
|
};
|
|
8560
|
-
var SPage = /* @__PURE__ */ react.forwardRef(function SPage2({
|
|
8774
|
+
var SPage = /* @__PURE__ */ react.forwardRef(function SPage2({
|
|
8775
|
+
background = "frame",
|
|
8776
|
+
scrollEndSpacing = true,
|
|
8777
|
+
header,
|
|
8778
|
+
className,
|
|
8779
|
+
style,
|
|
8780
|
+
children,
|
|
8781
|
+
onScroll,
|
|
8782
|
+
...rest
|
|
8783
|
+
}, ref) {
|
|
8561
8784
|
const layout = react.useContext(SLayoutContext);
|
|
8562
8785
|
const gridStyle = layout?.header === "full" ? { gridArea: "page" } : void 0;
|
|
8563
|
-
|
|
8786
|
+
const [scrolled, setScrolled] = react.useState(false);
|
|
8787
|
+
const handleScroll = (e) => {
|
|
8788
|
+
onScroll?.(e);
|
|
8789
|
+
if (header != null && !header.fix) setScrolled(e.currentTarget.scrollTop > 0);
|
|
8790
|
+
};
|
|
8791
|
+
const main = /* @__PURE__ */ jsxRuntime.jsx(
|
|
8564
8792
|
"main",
|
|
8565
8793
|
{
|
|
8566
8794
|
ref,
|
|
@@ -8571,11 +8799,29 @@ var SPage = /* @__PURE__ */ react.forwardRef(function SPage2({ background = "fra
|
|
|
8571
8799
|
BACKGROUND_CLASS[background],
|
|
8572
8800
|
className
|
|
8573
8801
|
),
|
|
8574
|
-
style: { ...gridStyle, ...style },
|
|
8802
|
+
style: header == null ? { ...gridStyle, ...style } : style,
|
|
8803
|
+
onScroll: handleScroll,
|
|
8575
8804
|
...rest,
|
|
8576
8805
|
children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { minWidth: MIN_CONTENT_WIDTH }, children })
|
|
8577
8806
|
}
|
|
8578
8807
|
);
|
|
8808
|
+
if (header == null) return main;
|
|
8809
|
+
return (
|
|
8810
|
+
// fix 가 아닌 헤더는 자기 배경이 투명이라(SPageHeader.tsx) 이 배경이 그대로 비친다 —
|
|
8811
|
+
// 그래서 SPage 의 background 를 main 뿐 아니라 여기에도 칠한다(스크롤바 관련 클래스는
|
|
8812
|
+
// 스크롤 요소가 아닌 여기서는 그냥 무시된다). fix 헤더는 자체 흰 배경이 덮으므로 무관하다.
|
|
8813
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
8814
|
+
"div",
|
|
8815
|
+
{
|
|
8816
|
+
className: cn("flex min-h-0 min-w-0 flex-1 flex-col", BACKGROUND_CLASS[background]),
|
|
8817
|
+
style: gridStyle,
|
|
8818
|
+
children: [
|
|
8819
|
+
/* @__PURE__ */ jsxRuntime.jsx(SPageHeader, { ...header, scrolled }),
|
|
8820
|
+
main
|
|
8821
|
+
]
|
|
8822
|
+
}
|
|
8823
|
+
)
|
|
8824
|
+
);
|
|
8579
8825
|
});
|
|
8580
8826
|
|
|
8581
8827
|
// src/components/SPage/page.config.ts
|
|
@@ -10949,7 +11195,7 @@ var SInput = /* @__PURE__ */ react.forwardRef(function SInput2({
|
|
|
10949
11195
|
lineHeight: `${f.lineHeight}px`
|
|
10950
11196
|
},
|
|
10951
11197
|
children: [
|
|
10952
|
-
prefix != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", children: prefix }),
|
|
11198
|
+
prefix != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex flex-shrink-0 items-center", children: prefix }),
|
|
10953
11199
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10954
11200
|
"input",
|
|
10955
11201
|
{
|
|
@@ -10981,7 +11227,7 @@ var SInput = /* @__PURE__ */ react.forwardRef(function SInput2({
|
|
|
10981
11227
|
...rest
|
|
10982
11228
|
}
|
|
10983
11229
|
),
|
|
10984
|
-
suffix != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", children: suffix }),
|
|
11230
|
+
suffix != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex flex-shrink-0 items-center", children: suffix }),
|
|
10985
11231
|
clearable && hasValue && !disabled && !readOnly && /* @__PURE__ */ jsxRuntime.jsx(
|
|
10986
11232
|
SGhostButton,
|
|
10987
11233
|
{
|
|
@@ -11879,8 +12125,8 @@ function SDatePicker({
|
|
|
11879
12125
|
disabled,
|
|
11880
12126
|
className,
|
|
11881
12127
|
style,
|
|
11882
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11883
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12128
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(RPopover9__namespace.Root, { open, onOpenChange: (o) => !disabled && setOpen(o), children: [
|
|
12129
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11884
12130
|
"button",
|
|
11885
12131
|
{
|
|
11886
12132
|
type: "button",
|
|
@@ -11916,13 +12162,16 @@ function SDatePicker({
|
|
|
11916
12162
|
]
|
|
11917
12163
|
}
|
|
11918
12164
|
) }),
|
|
11919
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11920
|
-
|
|
12165
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12166
|
+
RPopover9__namespace.Content,
|
|
11921
12167
|
{
|
|
11922
12168
|
side: "bottom",
|
|
11923
12169
|
align: "start",
|
|
11924
12170
|
sideOffset: 4,
|
|
11925
|
-
className: cn(
|
|
12171
|
+
className: cn(
|
|
12172
|
+
"z-50 max-w-[var(--radix-popover-content-available-width)]",
|
|
12173
|
+
FLOATING_SLIDE_ANIM
|
|
12174
|
+
),
|
|
11926
12175
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
11927
12176
|
SCalendar,
|
|
11928
12177
|
{
|
|
@@ -12070,78 +12319,81 @@ function RangeCalendar({
|
|
|
12070
12319
|
}
|
|
12071
12320
|
};
|
|
12072
12321
|
const GRID_COLS = "grid grid-cols-[repeat(7,var(--cmp-datepicker-calendar-day-width))]";
|
|
12073
|
-
const renderPanel = (gy, gm, isLeft) =>
|
|
12074
|
-
|
|
12075
|
-
|
|
12076
|
-
|
|
12077
|
-
|
|
12078
|
-
|
|
12079
|
-
|
|
12080
|
-
|
|
12081
|
-
|
|
12082
|
-
|
|
12083
|
-
|
|
12084
|
-
|
|
12085
|
-
|
|
12086
|
-
|
|
12087
|
-
|
|
12088
|
-
|
|
12322
|
+
const renderPanel = (gy, gm, isLeft) => (
|
|
12323
|
+
// 좁은 창에서 눌려 격자가 깨지지 않도록, 줄이는 대신 부모가 가로 스크롤하게 둔다.
|
|
12324
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 flex-col gap-[var(--cmp-datepicker-calendar-gap)]", children: [
|
|
12325
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-center gap-[var(--cmp-datepicker-calendar-gap)]", children: [
|
|
12326
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12327
|
+
SGhostButton,
|
|
12328
|
+
{
|
|
12329
|
+
icon: "chevronLeft",
|
|
12330
|
+
size: "xxs",
|
|
12331
|
+
ariaLabel: "prevMonth",
|
|
12332
|
+
onClick: goPrevMonth,
|
|
12333
|
+
className: cn(!isLeft && "invisible pointer-events-none")
|
|
12334
|
+
}
|
|
12335
|
+
),
|
|
12336
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex min-w-[40px] flex-1 items-center justify-center text-center text-[14px] font-medium leading-[24px]", children: [
|
|
12337
|
+
gy,
|
|
12338
|
+
".",
|
|
12339
|
+
String(gm).padStart(2, "0")
|
|
12340
|
+
] }),
|
|
12341
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12342
|
+
SGhostButton,
|
|
12343
|
+
{
|
|
12344
|
+
icon: "chevronRight",
|
|
12345
|
+
size: "xxs",
|
|
12346
|
+
ariaLabel: "nextMonth",
|
|
12347
|
+
onClick: goNextMonth,
|
|
12348
|
+
className: cn(isLeft && "invisible pointer-events-none")
|
|
12349
|
+
}
|
|
12350
|
+
)
|
|
12089
12351
|
] }),
|
|
12090
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12091
|
-
|
|
12092
|
-
{
|
|
12093
|
-
icon: "chevronRight",
|
|
12094
|
-
size: "xxs",
|
|
12095
|
-
ariaLabel: "nextMonth",
|
|
12096
|
-
onClick: goNextMonth,
|
|
12097
|
-
className: cn(isLeft && "invisible pointer-events-none")
|
|
12098
|
-
}
|
|
12099
|
-
)
|
|
12100
|
-
] }),
|
|
12101
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: GRID_COLS, children: WEEK_LABELS.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
12102
|
-
"span",
|
|
12103
|
-
{
|
|
12104
|
-
className: "flex h-[20px] items-center justify-center text-[12px] font-normal text-[color:var(--cmp-datepicker-calendar-week-color)]",
|
|
12105
|
-
children: l
|
|
12106
|
-
},
|
|
12107
|
-
l
|
|
12108
|
-
)) }),
|
|
12109
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(GRID_COLS, "gap-y-[var(--cmp-datepicker-calendar-grid-rowGap)]"), children: monthCells(gy, gm).map((cell) => {
|
|
12110
|
-
const isEdge = cell.inCurrentMonth && (cell.date === rStart || complete && cell.date === rEnd);
|
|
12111
|
-
const between = cell.inCurrentMonth && inRange(cell.date);
|
|
12112
|
-
const disabled = cell.inCurrentMonth && isDisabled(cell.date);
|
|
12113
|
-
const isToday = cell.inCurrentMonth && today === cell.date;
|
|
12114
|
-
let cellBg;
|
|
12115
|
-
if (between) cellBg = RANGE_BG;
|
|
12116
|
-
else if (cell.inCurrentMonth && hasRange && cell.date === rStart)
|
|
12117
|
-
cellBg = `linear-gradient(to right, transparent 50%, ${RANGE_BG} 50%)`;
|
|
12118
|
-
else if (cell.inCurrentMonth && hasRange && cell.date === rEnd) cellBg = RANGE_BG;
|
|
12119
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
12120
|
-
"div",
|
|
12352
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: GRID_COLS, children: WEEK_LABELS.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
12353
|
+
"span",
|
|
12121
12354
|
{
|
|
12122
|
-
className: "flex h-[
|
|
12123
|
-
|
|
12124
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12125
|
-
"button",
|
|
12126
|
-
{
|
|
12127
|
-
type: "button",
|
|
12128
|
-
disabled: !cell.inCurrentMonth || disabled,
|
|
12129
|
-
onMouseEnter: () => setHover(cell.date),
|
|
12130
|
-
onClick: () => cell.inCurrentMonth && click(cell.date),
|
|
12131
|
-
className: cn(
|
|
12132
|
-
"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]",
|
|
12133
|
-
!cell.inCurrentMonth ? "invisible pointer-events-none" : disabled ? "cursor-not-allowed" : "cursor-pointer",
|
|
12134
|
-
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)]",
|
|
12135
|
-
isToday && !disabled && "font-bold"
|
|
12136
|
-
),
|
|
12137
|
-
children: cell.inCurrentMonth ? cell.day : ""
|
|
12138
|
-
}
|
|
12139
|
-
)
|
|
12355
|
+
className: "flex h-[20px] items-center justify-center text-[12px] font-normal text-[color:var(--cmp-datepicker-calendar-week-color)]",
|
|
12356
|
+
children: l
|
|
12140
12357
|
},
|
|
12141
|
-
|
|
12142
|
-
)
|
|
12143
|
-
|
|
12144
|
-
|
|
12358
|
+
l
|
|
12359
|
+
)) }),
|
|
12360
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(GRID_COLS, "gap-y-[var(--cmp-datepicker-calendar-grid-rowGap)]"), children: monthCells(gy, gm).map((cell) => {
|
|
12361
|
+
const isEdge = cell.inCurrentMonth && (cell.date === rStart || complete && cell.date === rEnd);
|
|
12362
|
+
const between = cell.inCurrentMonth && inRange(cell.date);
|
|
12363
|
+
const disabled = cell.inCurrentMonth && isDisabled(cell.date);
|
|
12364
|
+
const isToday = cell.inCurrentMonth && today === cell.date;
|
|
12365
|
+
let cellBg;
|
|
12366
|
+
if (between) cellBg = RANGE_BG;
|
|
12367
|
+
else if (cell.inCurrentMonth && hasRange && cell.date === rStart)
|
|
12368
|
+
cellBg = `linear-gradient(to right, transparent 50%, ${RANGE_BG} 50%)`;
|
|
12369
|
+
else if (cell.inCurrentMonth && hasRange && cell.date === rEnd) cellBg = RANGE_BG;
|
|
12370
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
12371
|
+
"div",
|
|
12372
|
+
{
|
|
12373
|
+
className: "flex h-[var(--cmp-datepicker-calendar-range-height)] w-[var(--cmp-datepicker-calendar-day-width)] items-center justify-center",
|
|
12374
|
+
style: { background: cellBg },
|
|
12375
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12376
|
+
"button",
|
|
12377
|
+
{
|
|
12378
|
+
type: "button",
|
|
12379
|
+
disabled: !cell.inCurrentMonth || disabled,
|
|
12380
|
+
onMouseEnter: () => setHover(cell.date),
|
|
12381
|
+
onClick: () => cell.inCurrentMonth && click(cell.date),
|
|
12382
|
+
className: cn(
|
|
12383
|
+
"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]",
|
|
12384
|
+
!cell.inCurrentMonth ? "invisible pointer-events-none" : disabled ? "cursor-not-allowed" : "cursor-pointer",
|
|
12385
|
+
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)]",
|
|
12386
|
+
isToday && !disabled && "font-bold"
|
|
12387
|
+
),
|
|
12388
|
+
children: cell.inCurrentMonth ? cell.day : ""
|
|
12389
|
+
}
|
|
12390
|
+
)
|
|
12391
|
+
},
|
|
12392
|
+
cell.date
|
|
12393
|
+
);
|
|
12394
|
+
}) })
|
|
12395
|
+
] })
|
|
12396
|
+
);
|
|
12145
12397
|
const renderTimeSection = (which, date, suffix) => {
|
|
12146
12398
|
const active = !!date;
|
|
12147
12399
|
const [yy = "", mm = "", dd = ""] = date ? date.split("-") : [];
|
|
@@ -12209,8 +12461,11 @@ function RangeCalendar({
|
|
|
12209
12461
|
"div",
|
|
12210
12462
|
{
|
|
12211
12463
|
className: cn(
|
|
12212
|
-
"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",
|
|
12213
|
-
|
|
12464
|
+
"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",
|
|
12465
|
+
// 높이는 고정이 아니라 하한이다 — 5주/6주 달을 오갈 때의 높이 흔들림만 막으면 되고,
|
|
12466
|
+
// 창이 좁아 패널이 가로 스크롤될 때는 스크롤바 높이만큼 늘어날 수 있어야 한다.
|
|
12467
|
+
// (단일 달 SCalendar 도 min-h 를 쓴다)
|
|
12468
|
+
useTimePicker ? "h-auto" : "min-h-[364px]"
|
|
12214
12469
|
),
|
|
12215
12470
|
children: [
|
|
12216
12471
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex items-center justify-center", children: [
|
|
@@ -12229,11 +12484,20 @@ function RangeCalendar({
|
|
|
12229
12484
|
}
|
|
12230
12485
|
)
|
|
12231
12486
|
] }),
|
|
12232
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
12233
|
-
|
|
12234
|
-
|
|
12235
|
-
|
|
12236
|
-
|
|
12487
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
12488
|
+
"div",
|
|
12489
|
+
{
|
|
12490
|
+
className: cn(
|
|
12491
|
+
"flex max-w-full gap-[var(--cmp-datepicker-calendar-range-panelGap)] overflow-x-auto",
|
|
12492
|
+
SCROLLBAR_CLASS
|
|
12493
|
+
),
|
|
12494
|
+
children: [
|
|
12495
|
+
renderPanel(y, m, true),
|
|
12496
|
+
/* @__PURE__ */ jsxRuntime.jsx(SDivider, { vertical: true }),
|
|
12497
|
+
renderPanel(nextMonthYM.year, nextMonthYM.month, false)
|
|
12498
|
+
]
|
|
12499
|
+
}
|
|
12500
|
+
),
|
|
12237
12501
|
useTimePicker && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
12238
12502
|
/* @__PURE__ */ jsxRuntime.jsx(SDivider, {}),
|
|
12239
12503
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-[var(--cmp-datepicker-calendar-time-gap)]", children: [
|
|
@@ -12292,7 +12556,25 @@ function SDateRangePicker({
|
|
|
12292
12556
|
});
|
|
12293
12557
|
const resolvedError = error || ruleError !== "";
|
|
12294
12558
|
const resolvedStatus = status ?? (rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0);
|
|
12295
|
-
const dims = size === "md" ? {
|
|
12559
|
+
const dims = size === "md" ? {
|
|
12560
|
+
padX: 16,
|
|
12561
|
+
gap: 12,
|
|
12562
|
+
icon: 20,
|
|
12563
|
+
minW: 104,
|
|
12564
|
+
fieldMinW: 260,
|
|
12565
|
+
fontSize: 14,
|
|
12566
|
+
lineHeight: 24,
|
|
12567
|
+
radius: 6
|
|
12568
|
+
} : {
|
|
12569
|
+
padX: 12,
|
|
12570
|
+
gap: 8,
|
|
12571
|
+
icon: 16,
|
|
12572
|
+
minW: 80,
|
|
12573
|
+
fieldMinW: 216,
|
|
12574
|
+
fontSize: 12,
|
|
12575
|
+
lineHeight: 20,
|
|
12576
|
+
radius: 4
|
|
12577
|
+
};
|
|
12296
12578
|
const select = (r) => {
|
|
12297
12579
|
setPendingStart(null);
|
|
12298
12580
|
onValueChange?.(r);
|
|
@@ -12318,11 +12600,12 @@ function SDateRangePicker({
|
|
|
12318
12600
|
focused: open,
|
|
12319
12601
|
errorMessage: ruleError !== "" ? ruleError : errorMessage,
|
|
12320
12602
|
width,
|
|
12603
|
+
minWidth: dims.fieldMinW,
|
|
12321
12604
|
disabled,
|
|
12322
12605
|
className,
|
|
12323
12606
|
style,
|
|
12324
12607
|
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12325
|
-
|
|
12608
|
+
RPopover9__namespace.Root,
|
|
12326
12609
|
{
|
|
12327
12610
|
open,
|
|
12328
12611
|
onOpenChange: (o) => {
|
|
@@ -12331,7 +12614,7 @@ function SDateRangePicker({
|
|
|
12331
12614
|
if (!o) setPendingStart(null);
|
|
12332
12615
|
},
|
|
12333
12616
|
children: [
|
|
12334
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12617
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12335
12618
|
"button",
|
|
12336
12619
|
{
|
|
12337
12620
|
type: "button",
|
|
@@ -12372,13 +12655,16 @@ function SDateRangePicker({
|
|
|
12372
12655
|
]
|
|
12373
12656
|
}
|
|
12374
12657
|
) }),
|
|
12375
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12376
|
-
|
|
12658
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12659
|
+
RPopover9__namespace.Content,
|
|
12377
12660
|
{
|
|
12378
12661
|
side: "bottom",
|
|
12379
12662
|
align: "start",
|
|
12380
12663
|
sideOffset: 4,
|
|
12381
|
-
className: cn(
|
|
12664
|
+
className: cn(
|
|
12665
|
+
"z-50 max-w-[var(--radix-popover-content-available-width)]",
|
|
12666
|
+
FLOATING_SLIDE_ANIM
|
|
12667
|
+
),
|
|
12382
12668
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12383
12669
|
RangeCalendar,
|
|
12384
12670
|
{
|
|
@@ -13366,7 +13652,7 @@ function SRadioButton({
|
|
|
13366
13652
|
disabled: od,
|
|
13367
13653
|
onClick: () => !od && !selected && onValueChange?.(o.value),
|
|
13368
13654
|
className: cn(
|
|
13369
|
-
"relative box-border inline-flex items-center justify-center whitespace-nowrap border border-solid text-[12px] font-medium leading-[20px] transition-colors",
|
|
13655
|
+
"relative box-border grow inline-flex items-center justify-center whitespace-nowrap border border-solid text-[12px] font-medium leading-[20px] transition-colors",
|
|
13370
13656
|
i === 0 ? "rounded-l-[var(--cmp-radioButton-radius)]" : "-ml-px",
|
|
13371
13657
|
i === options.length - 1 ? "rounded-r-[var(--cmp-radioButton-radius)]" : "",
|
|
13372
13658
|
selected ? "z-10" : "",
|
|
@@ -13388,53 +13674,1277 @@ function SRadioButton({
|
|
|
13388
13674
|
}
|
|
13389
13675
|
);
|
|
13390
13676
|
}
|
|
13391
|
-
var
|
|
13392
|
-
|
|
13677
|
+
var CHIPFILTER_LISTBOX_WIDTH = 240;
|
|
13678
|
+
var CHIPFILTER_DATE_PRESET_LISTBOX_WIDTH = 246;
|
|
13679
|
+
var CHIPFILTER = {
|
|
13680
|
+
barBg: "var(--cmp-chipFilter-bar-bg)",
|
|
13681
|
+
barBorder: "var(--cmp-chipFilter-bar-border)",
|
|
13682
|
+
barPaddingX: "var(--cmp-chipFilter-bar-paddingX)",
|
|
13683
|
+
barPaddingY: "var(--cmp-chipFilter-bar-paddingY)",
|
|
13684
|
+
barGap: "var(--cmp-chipFilter-bar-gap)",
|
|
13685
|
+
dividerHeight: "var(--cmp-chipFilter-divider-height)",
|
|
13686
|
+
chipHeight: "var(--cmp-chipFilter-chip-height)",
|
|
13687
|
+
chipRadius: "var(--cmp-chipFilter-chip-radius)",
|
|
13688
|
+
chipGap: "var(--cmp-chipFilter-chip-gap)",
|
|
13689
|
+
chipDefaultBg: "var(--cmp-chipFilter-chip-default-bg)",
|
|
13690
|
+
chipDefaultBorder: "var(--cmp-chipFilter-chip-default-border)",
|
|
13691
|
+
chipDefaultText: "var(--cmp-chipFilter-chip-default-text)",
|
|
13692
|
+
chipActiveBorder: "var(--cmp-chipFilter-chip-active-border)",
|
|
13693
|
+
chipWarningBorder: "var(--cmp-chipFilter-chip-warning-border)",
|
|
13694
|
+
chipAppliedBg: "var(--cmp-chipFilter-chip-applied-bg)",
|
|
13695
|
+
chipAppliedBorder: "var(--cmp-chipFilter-chip-applied-border)",
|
|
13696
|
+
chipAppliedLabel: "var(--cmp-chipFilter-chip-applied-text-label)",
|
|
13697
|
+
chipAppliedValue: "var(--color-brilliantblue-80)",
|
|
13698
|
+
chipDisabledBg: "var(--cmp-chipFilter-chip-disabled-bg)",
|
|
13699
|
+
chipDisabledBorder: "var(--cmp-chipFilter-chip-disabled-border)",
|
|
13700
|
+
chipDisabledText: "var(--cmp-chipFilter-chip-disabled-text)",
|
|
13701
|
+
addBorder: "var(--cmp-chipFilter-addButton-border-default)",
|
|
13702
|
+
addBorderDisabled: "var(--cmp-chipFilter-addButton-border-disabled)",
|
|
13703
|
+
addText: "var(--cmp-chipFilter-addButton-text-default)",
|
|
13704
|
+
addTextDisabled: "var(--cmp-chipFilter-addButton-text-disabled)",
|
|
13705
|
+
listboxBg: "var(--cmp-chipFilter-listbox-bg)",
|
|
13706
|
+
listboxBorder: "var(--cmp-chipFilter-listbox-border-color)",
|
|
13707
|
+
listboxRadius: "var(--cmp-chipFilter-listbox-radius)",
|
|
13708
|
+
listboxLabel: "var(--cmp-chipFilter-listbox-top-label-color)",
|
|
13709
|
+
listboxBottomDividerHeight: "var(--cmp-chipFilter-listbox-bottom-divider-height)",
|
|
13710
|
+
itemPaddingLeft: "var(--cmp-chipFilter-item-paddingLeft)",
|
|
13711
|
+
itemPaddingRight: "var(--cmp-chipFilter-item-paddingRight)",
|
|
13712
|
+
itemPaddingY: "var(--cmp-chipFilter-item-paddingY)",
|
|
13713
|
+
itemMultiPaddingX: "var(--cmp-chipFilter-item-multi-paddingX)",
|
|
13714
|
+
itemTextDefault: "var(--cmp-chipFilter-item-text-default)",
|
|
13715
|
+
itemTextSelected: "var(--cmp-chipFilter-item-text-selected)"
|
|
13716
|
+
};
|
|
13717
|
+
var isKeywordValue = (value) => typeof value === "object" && value != null && !Array.isArray(value) && "keywords" in value;
|
|
13718
|
+
var keywordEntries = (value) => {
|
|
13719
|
+
if (isKeywordValue(value)) return value.keywords;
|
|
13720
|
+
if (Array.isArray(value)) {
|
|
13721
|
+
return value.filter((v) => typeof v === "string");
|
|
13722
|
+
}
|
|
13723
|
+
return [];
|
|
13724
|
+
};
|
|
13725
|
+
var isEmptyValue = (value) => {
|
|
13726
|
+
if (value == null) return true;
|
|
13727
|
+
if (Array.isArray(value)) return value.length === 0 || value.every((v) => v == null || v === "");
|
|
13728
|
+
if (isKeywordValue(value)) return value.keywords.length === 0;
|
|
13729
|
+
return value === "";
|
|
13730
|
+
};
|
|
13731
|
+
var normalizeValues = (value) => value ?? {};
|
|
13732
|
+
var toArrayValue = (value) => Array.isArray(value) ? value.filter(
|
|
13733
|
+
(v) => typeof v === "string" || typeof v === "number"
|
|
13734
|
+
) : [];
|
|
13735
|
+
var todayIso = () => {
|
|
13736
|
+
const d = /* @__PURE__ */ new Date();
|
|
13737
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
13738
|
+
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
|
13739
|
+
};
|
|
13740
|
+
var isInlineDateField = (field) => field.type === "date" && field.radioButton === true && (field.presets?.length ?? 0) > 0;
|
|
13741
|
+
var resolveFieldDefault = (field) => {
|
|
13742
|
+
if (field.defaultValue !== void 0) return field.defaultValue;
|
|
13743
|
+
if (isInlineDateField(field)) return todayIso();
|
|
13744
|
+
if (!field.required) return void 0;
|
|
13745
|
+
if (field.type === "single") return field.options?.[0]?.value;
|
|
13746
|
+
if (field.type === "date") return todayIso();
|
|
13747
|
+
return void 0;
|
|
13748
|
+
};
|
|
13749
|
+
var valuesEqual = (a, b) => {
|
|
13750
|
+
if (isKeywordValue(a) || isKeywordValue(b)) {
|
|
13751
|
+
return isKeywordValue(a) && isKeywordValue(b) && a.mode === b.mode && valuesEqual(a.keywords, b.keywords);
|
|
13752
|
+
}
|
|
13753
|
+
if (Array.isArray(a) || Array.isArray(b)) {
|
|
13754
|
+
return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((v, i) => v === b[i]);
|
|
13755
|
+
}
|
|
13756
|
+
return a === b;
|
|
13757
|
+
};
|
|
13758
|
+
var valuesMapEqual = (a, b) => {
|
|
13759
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)]);
|
|
13760
|
+
for (const key of keys) {
|
|
13761
|
+
if (!valuesEqual(a[key], b[key])) return false;
|
|
13762
|
+
}
|
|
13763
|
+
return true;
|
|
13764
|
+
};
|
|
13765
|
+
var isAtDefaultValue = (field, value) => {
|
|
13766
|
+
const def = resolveFieldDefault(field);
|
|
13767
|
+
return def !== void 0 && valuesEqual(value, def);
|
|
13768
|
+
};
|
|
13769
|
+
var isInlineField = (field) => isInlineDateField(field) || field.type === "custom";
|
|
13770
|
+
var isGroupedFields = (fields) => fields.length > 0 && "fields" in fields[0];
|
|
13771
|
+
var isGroupSatisfied = (group, values) => {
|
|
13772
|
+
if (!group.rule) return true;
|
|
13773
|
+
const keys = group.fields.map((f) => f.key);
|
|
13774
|
+
if (group.rule.type === "requireKey") return !isEmptyValue(values[group.rule.key]);
|
|
13775
|
+
if (group.rule.type === "requireAll") return keys.every((k) => !isEmptyValue(values[k]));
|
|
13776
|
+
if (group.rule.type === "requireAny") return keys.some((k) => !isEmptyValue(values[k]));
|
|
13777
|
+
return true;
|
|
13778
|
+
};
|
|
13779
|
+
var koreanParticle = (word, consonant, vowel) => {
|
|
13780
|
+
const code = word.charCodeAt(word.length - 1);
|
|
13781
|
+
if (code < 44032 || code > 55203) return consonant;
|
|
13782
|
+
return (code - 44032) % 28 === 0 ? vowel : consonant;
|
|
13783
|
+
};
|
|
13784
|
+
var defaultGroupTooltipMessage = (rule, fields) => {
|
|
13785
|
+
if (rule.type === "requireAll") return "\uD56D\uBAA9\uC744 \uBAA8\uB450 \uC120\uD0DD\uD574 \uC8FC\uC138\uC694.";
|
|
13786
|
+
if (rule.type === "requireAny") {
|
|
13787
|
+
const name = rule.dataGroupName;
|
|
13788
|
+
if (!name) return "\uCD5C\uC18C 1\uAC1C\uC758 \uD544\uD130\uB97C \uC120\uD0DD\uD574\uC8FC\uC138\uC694.";
|
|
13789
|
+
return `\uCD5C\uC18C 1\uAC1C\uC758 ${name}${koreanParticle(name, "\uC744", "\uB97C")} \uC120\uD0DD\uD574\uC8FC\uC138\uC694.`;
|
|
13790
|
+
}
|
|
13791
|
+
const label = fields.find((f) => f.key === rule.key)?.label ?? "\uD56D\uBAA9";
|
|
13792
|
+
return `${label}${koreanParticle(label, "\uC744", "\uB97C")} \uC120\uD0DD\uD574 \uC8FC\uC138\uC694.`;
|
|
13793
|
+
};
|
|
13794
|
+
var matchPresetId = (presets, value) => {
|
|
13795
|
+
if (isEmptyValue(value)) return null;
|
|
13796
|
+
for (const preset of presets) {
|
|
13797
|
+
if (preset.custom || !preset.resolve) continue;
|
|
13798
|
+
const resolved = preset.resolve();
|
|
13799
|
+
if (Array.isArray(resolved) && Array.isArray(value)) {
|
|
13800
|
+
if (resolved[0] === value[0] && resolved[1] === value[1]) return preset.value;
|
|
13801
|
+
} else if (!Array.isArray(resolved) && !Array.isArray(value) && resolved === value) {
|
|
13802
|
+
return preset.value;
|
|
13803
|
+
}
|
|
13804
|
+
}
|
|
13805
|
+
return presets.find((preset) => preset.custom)?.value ?? null;
|
|
13806
|
+
};
|
|
13807
|
+
var optionLabel = (field, value) => field.options?.find((option) => option.value === value)?.label ?? String(value);
|
|
13808
|
+
var formatValueList = (labels) => {
|
|
13809
|
+
if (labels.length <= 1) return labels[0] ?? "";
|
|
13810
|
+
return `${labels[0]} \uC678 ${labels.length - 1}\uAC1C`;
|
|
13811
|
+
};
|
|
13812
|
+
var displayValue = (field, value) => {
|
|
13813
|
+
if (isEmptyValue(value)) return "";
|
|
13814
|
+
if (field.type === "multi")
|
|
13815
|
+
return formatValueList(toArrayValue(value).map((v) => optionLabel(field, v)));
|
|
13816
|
+
if (field.type === "single") return optionLabel(field, value);
|
|
13817
|
+
if (field.type === "date")
|
|
13818
|
+
return Array.isArray(value) ? `${value[0]} ~ ${value[1]}` : String(value);
|
|
13819
|
+
if (field.type === "keyword") return formatValueList(keywordEntries(value));
|
|
13820
|
+
return String(value);
|
|
13821
|
+
};
|
|
13822
|
+
var chipDisplayValue = (field, value) => {
|
|
13823
|
+
const text = displayValue(field, value);
|
|
13824
|
+
if (field.type !== "date" || isEmptyValue(value)) return text;
|
|
13825
|
+
const presets = field.presets ?? [];
|
|
13826
|
+
if (presets.length === 0) return text;
|
|
13827
|
+
const preset = presets.find((p) => p.value === matchPresetId(presets, value));
|
|
13828
|
+
return preset && !preset.custom ? `${preset.label}(${text})` : text;
|
|
13829
|
+
};
|
|
13830
|
+
var SChipFilter = /* @__PURE__ */ react.forwardRef(function SChipFilter2({
|
|
13831
|
+
fields: fieldsProp = [],
|
|
13832
|
+
value,
|
|
13393
13833
|
onValueChange,
|
|
13394
|
-
|
|
13395
|
-
|
|
13396
|
-
|
|
13397
|
-
|
|
13398
|
-
|
|
13399
|
-
|
|
13834
|
+
onFilterChange,
|
|
13835
|
+
onSearch,
|
|
13836
|
+
activeKeys,
|
|
13837
|
+
onActiveKeysChange,
|
|
13838
|
+
onReset,
|
|
13839
|
+
onAddFilter,
|
|
13840
|
+
label = "\uAC80\uC0C9 \uD544\uD130",
|
|
13841
|
+
showLabel = false,
|
|
13842
|
+
showAddButton = true,
|
|
13843
|
+
showReset = true,
|
|
13400
13844
|
disabled = false,
|
|
13401
|
-
placeholder = "\uD0DC\uADF8 \uC785\uB825 (Enter\uB85C \uB4F1\uB85D / \uCF64\uB9C8\uB85C \uAD6C\uBD84 / \uB744\uC5B4\uC4F0\uAE30 \uBD88\uAC00)",
|
|
13402
|
-
name,
|
|
13403
|
-
rules,
|
|
13404
|
-
error,
|
|
13405
|
-
useReset = false,
|
|
13406
|
-
maxCount,
|
|
13407
|
-
metaPlacement = "end",
|
|
13408
|
-
duplicateLabel,
|
|
13409
|
-
suggestions = [],
|
|
13410
|
-
loadingSuggestions = false,
|
|
13411
|
-
recommendedItems = [],
|
|
13412
|
-
loadingRecommendedItems = false,
|
|
13413
|
-
dropdownMinWidth = 200,
|
|
13414
|
-
label,
|
|
13415
|
-
labelWidth,
|
|
13416
|
-
hint,
|
|
13417
|
-
errorMessage,
|
|
13418
|
-
width,
|
|
13419
|
-
status,
|
|
13420
|
-
icon,
|
|
13421
|
-
iconColor,
|
|
13422
|
-
labelTooltip,
|
|
13423
|
-
labelTooltipProps,
|
|
13424
13845
|
className,
|
|
13425
13846
|
style
|
|
13426
13847
|
}, ref) {
|
|
13427
|
-
const
|
|
13428
|
-
const
|
|
13429
|
-
|
|
13430
|
-
|
|
13431
|
-
|
|
13432
|
-
const
|
|
13433
|
-
const
|
|
13434
|
-
const
|
|
13435
|
-
const
|
|
13436
|
-
|
|
13437
|
-
|
|
13848
|
+
const usingGroupedFields = isGroupedFields(fieldsProp);
|
|
13849
|
+
const groups = react.useMemo(
|
|
13850
|
+
() => usingGroupedFields ? fieldsProp : [{ fields: fieldsProp }],
|
|
13851
|
+
[usingGroupedFields, fieldsProp]
|
|
13852
|
+
);
|
|
13853
|
+
const fields = react.useMemo(() => groups.flatMap((group) => group.fields), [groups]);
|
|
13854
|
+
const values = normalizeValues(value);
|
|
13855
|
+
const portalContainer = usePortalContainer();
|
|
13856
|
+
const [internalActiveKeys, setInternalActiveKeys] = react.useState(
|
|
13857
|
+
() => fields.filter((field) => field.defaultActive !== false).map((field) => field.key)
|
|
13858
|
+
);
|
|
13859
|
+
const [openKey, setOpenKey] = react.useState(null);
|
|
13860
|
+
const [addOpen, setAddOpen] = react.useState(false);
|
|
13861
|
+
const triggerRefs = react.useRef(/* @__PURE__ */ new Map());
|
|
13862
|
+
const initializedDefaultsRef = react.useRef(/* @__PURE__ */ new Set());
|
|
13863
|
+
const prevOpenKeyRef = react.useRef(null);
|
|
13864
|
+
const valuesRef = react.useRef(values);
|
|
13865
|
+
valuesRef.current = values;
|
|
13866
|
+
const lastSearchedValuesRef = react.useRef(values);
|
|
13867
|
+
const invalidGroups = react.useMemo(() => {
|
|
13868
|
+
const invalid = /* @__PURE__ */ new Set();
|
|
13869
|
+
groups.forEach((group, groupIndex) => {
|
|
13870
|
+
if (!isGroupSatisfied(group, values)) invalid.add(groupIndex);
|
|
13871
|
+
});
|
|
13872
|
+
return invalid;
|
|
13873
|
+
}, [groups, values]);
|
|
13874
|
+
const isGroupsValid = react.useCallback(
|
|
13875
|
+
(current) => groups.every((group) => isGroupSatisfied(group, current)),
|
|
13876
|
+
[groups]
|
|
13877
|
+
);
|
|
13878
|
+
const runSearch = react.useCallback(
|
|
13879
|
+
(next) => {
|
|
13880
|
+
if (valuesMapEqual(lastSearchedValuesRef.current, next)) return;
|
|
13881
|
+
if (!isGroupsValid(next)) return;
|
|
13882
|
+
lastSearchedValuesRef.current = next;
|
|
13883
|
+
onSearch?.(next);
|
|
13884
|
+
},
|
|
13885
|
+
[isGroupsValid, onSearch]
|
|
13886
|
+
);
|
|
13887
|
+
react.useEffect(() => {
|
|
13888
|
+
const prevKey = prevOpenKeyRef.current;
|
|
13889
|
+
if (prevKey != null && prevKey !== openKey) {
|
|
13890
|
+
runSearch(valuesRef.current);
|
|
13891
|
+
}
|
|
13892
|
+
prevOpenKeyRef.current = openKey;
|
|
13893
|
+
}, [openKey, runSearch]);
|
|
13894
|
+
react.useEffect(() => {
|
|
13895
|
+
if (activeKeys) return;
|
|
13896
|
+
setInternalActiveKeys((current) => {
|
|
13897
|
+
const known = new Set(fields.map((field) => field.key));
|
|
13898
|
+
const kept = current.filter((key) => known.has(key));
|
|
13899
|
+
const additions = fields.filter((field) => field.defaultActive !== false && !kept.includes(field.key)).map((field) => field.key);
|
|
13900
|
+
return [...kept, ...additions];
|
|
13901
|
+
});
|
|
13902
|
+
}, [activeKeys, fields]);
|
|
13903
|
+
react.useEffect(() => {
|
|
13904
|
+
const patch = {};
|
|
13905
|
+
let changed = false;
|
|
13906
|
+
fields.forEach((field) => {
|
|
13907
|
+
if (initializedDefaultsRef.current.has(field.key)) return;
|
|
13908
|
+
if (!isEmptyValue(values[field.key])) {
|
|
13909
|
+
initializedDefaultsRef.current.add(field.key);
|
|
13910
|
+
return;
|
|
13911
|
+
}
|
|
13912
|
+
const def = resolveFieldDefault(field);
|
|
13913
|
+
if (def === void 0) return;
|
|
13914
|
+
patch[field.key] = def;
|
|
13915
|
+
initializedDefaultsRef.current.add(field.key);
|
|
13916
|
+
changed = true;
|
|
13917
|
+
});
|
|
13918
|
+
if (changed) onValueChange?.({ ...values, ...patch });
|
|
13919
|
+
}, [fields, values, onValueChange]);
|
|
13920
|
+
const resolvedActiveKeys = activeKeys ?? internalActiveKeys;
|
|
13921
|
+
const activeFields = fields.filter((field) => resolvedActiveKeys.includes(field.key));
|
|
13922
|
+
const inactiveFields = fields.filter((field) => !resolvedActiveKeys.includes(field.key));
|
|
13923
|
+
const groupIndexByKey = /* @__PURE__ */ new Map();
|
|
13924
|
+
groups.forEach((group, groupIndex) => {
|
|
13925
|
+
group.fields.forEach((field) => groupIndexByKey.set(field.key, groupIndex));
|
|
13926
|
+
});
|
|
13927
|
+
const hasValue = fields.some((field) => !isEmptyValue(values[field.key]));
|
|
13928
|
+
const hasRightActions = showAddButton || showReset;
|
|
13929
|
+
const currentOpenField = fields.find((field) => field.key === openKey);
|
|
13930
|
+
const editorPopoverStyle = react.useMemo(() => {
|
|
13931
|
+
if (currentOpenField?.type === "keyword") {
|
|
13932
|
+
return { width: CHIPFILTER_LISTBOX_WIDTH };
|
|
13933
|
+
}
|
|
13934
|
+
if (currentOpenField?.type === "date" && (currentOpenField.presets?.length ?? 0) > 0) {
|
|
13935
|
+
return { width: CHIPFILTER_DATE_PRESET_LISTBOX_WIDTH };
|
|
13936
|
+
}
|
|
13937
|
+
return { width: CHIPFILTER_LISTBOX_WIDTH };
|
|
13938
|
+
}, [currentOpenField?.type, currentOpenField?.presets?.length]);
|
|
13939
|
+
const setActive = (next) => {
|
|
13940
|
+
if (!activeKeys) setInternalActiveKeys(next);
|
|
13941
|
+
onActiveKeysChange?.(next);
|
|
13942
|
+
};
|
|
13943
|
+
const emitValue = (key, nextValue) => {
|
|
13944
|
+
const next = { ...values, [key]: nextValue };
|
|
13945
|
+
onValueChange?.(next);
|
|
13946
|
+
onFilterChange?.({ key, value: nextValue, values: next });
|
|
13947
|
+
return next;
|
|
13948
|
+
};
|
|
13949
|
+
const emitValueAndSearch = (key, nextValue) => {
|
|
13950
|
+
runSearch(emitValue(key, nextValue));
|
|
13951
|
+
};
|
|
13952
|
+
const clearValue = (key) => {
|
|
13953
|
+
const field = fields.find((f) => f.key === key);
|
|
13954
|
+
const def = field ? resolveFieldDefault(field) : void 0;
|
|
13955
|
+
runSearch(emitValue(key, def !== void 0 ? def : null));
|
|
13956
|
+
};
|
|
13957
|
+
const reset = react.useCallback(() => {
|
|
13958
|
+
const next = fields.reduce((acc, field) => {
|
|
13959
|
+
const def = resolveFieldDefault(field);
|
|
13960
|
+
acc[field.key] = def !== void 0 ? def : null;
|
|
13961
|
+
return acc;
|
|
13962
|
+
}, {});
|
|
13963
|
+
onValueChange?.(next);
|
|
13964
|
+
runSearch(next);
|
|
13965
|
+
onReset?.();
|
|
13966
|
+
}, [fields, onReset, onValueChange, runSearch]);
|
|
13967
|
+
const open = react.useCallback(
|
|
13968
|
+
(key) => {
|
|
13969
|
+
const field = fields.find((f) => f.key === key);
|
|
13970
|
+
if (!field || isInlineField(field)) return;
|
|
13971
|
+
setOpenKey(key);
|
|
13972
|
+
},
|
|
13973
|
+
[fields]
|
|
13974
|
+
);
|
|
13975
|
+
const validate = react.useCallback(() => invalidGroups.size === 0, [invalidGroups]);
|
|
13976
|
+
react.useImperativeHandle(ref, () => ({ open, reset, validate }), [open, reset, validate]);
|
|
13977
|
+
const addField = (key) => {
|
|
13978
|
+
const next = [...resolvedActiveKeys, key];
|
|
13979
|
+
setActive(next);
|
|
13980
|
+
onAddFilter?.(key);
|
|
13981
|
+
setAddOpen(false);
|
|
13982
|
+
const field = fields.find((f) => f.key === key);
|
|
13983
|
+
if (field && !isInlineField(field)) requestAnimationFrame(() => setOpenKey(key));
|
|
13984
|
+
};
|
|
13985
|
+
const rootStyle = react.useMemo(
|
|
13986
|
+
() => ({
|
|
13987
|
+
"--chipfilter-bar-bg": CHIPFILTER.barBg,
|
|
13988
|
+
"--chipfilter-bar-border": CHIPFILTER.barBorder,
|
|
13989
|
+
"--chipfilter-bar-padding-x": CHIPFILTER.barPaddingX,
|
|
13990
|
+
"--chipfilter-bar-padding-y": CHIPFILTER.barPaddingY,
|
|
13991
|
+
"--chipfilter-bar-gap": CHIPFILTER.barGap,
|
|
13992
|
+
"--chipfilter-divider-height": CHIPFILTER.dividerHeight,
|
|
13993
|
+
...style
|
|
13994
|
+
}),
|
|
13995
|
+
[style]
|
|
13996
|
+
);
|
|
13997
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
13998
|
+
"div",
|
|
13999
|
+
{
|
|
14000
|
+
className: cn(
|
|
14001
|
+
"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)]",
|
|
14002
|
+
className
|
|
14003
|
+
),
|
|
14004
|
+
style: { ...rootStyle, borderColor: "var(--chipfilter-bar-border)" },
|
|
14005
|
+
children: [
|
|
14006
|
+
showLabel && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
14007
|
+
/* @__PURE__ */ jsxRuntime.jsx(STag, { className: "shrink-0", shape: "square", size: "sm", color: "darkblue", label }),
|
|
14008
|
+
/* @__PURE__ */ jsxRuntime.jsx(Divider, { top: true })
|
|
14009
|
+
] }),
|
|
14010
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-wrap items-center gap-[var(--cmp-chipFilter-chip-group)]", children: [
|
|
14011
|
+
(() => {
|
|
14012
|
+
const nodes = [];
|
|
14013
|
+
let runBuffer = [];
|
|
14014
|
+
let runGroupIndex = null;
|
|
14015
|
+
const flushRun = () => {
|
|
14016
|
+
if (runBuffer.length === 0) return;
|
|
14017
|
+
const group = runGroupIndex != null ? groups[runGroupIndex] : void 0;
|
|
14018
|
+
const message = usingGroupedFields && group?.rule ? group.tooltipMessage ?? defaultGroupTooltipMessage(group.rule, group.fields) : void 0;
|
|
14019
|
+
if (message) {
|
|
14020
|
+
nodes.push(
|
|
14021
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14022
|
+
GroupTooltip,
|
|
14023
|
+
{
|
|
14024
|
+
message,
|
|
14025
|
+
open: invalidGroups.has(runGroupIndex),
|
|
14026
|
+
children: runBuffer
|
|
14027
|
+
},
|
|
14028
|
+
`group-${runGroupIndex}`
|
|
14029
|
+
)
|
|
14030
|
+
);
|
|
14031
|
+
} else {
|
|
14032
|
+
nodes.push(...runBuffer);
|
|
14033
|
+
}
|
|
14034
|
+
runBuffer = [];
|
|
14035
|
+
};
|
|
14036
|
+
activeFields.forEach((field, index) => {
|
|
14037
|
+
const inline = isInlineField(field);
|
|
14038
|
+
const groupIndex = groupIndexByKey.get(field.key) ?? 0;
|
|
14039
|
+
const warning = field.warning || invalidGroups.has(groupIndex);
|
|
14040
|
+
const prevField = index > 0 ? activeFields[index - 1] : null;
|
|
14041
|
+
const prevGroupIndex = prevField ? groupIndexByKey.get(prevField.key) ?? 0 : null;
|
|
14042
|
+
const needsLeadingDivider = index === 0 ? false : inline || prevField != null && isInlineField(prevField) || groupIndex !== prevGroupIndex;
|
|
14043
|
+
if (groupIndex !== runGroupIndex) {
|
|
14044
|
+
flushRun();
|
|
14045
|
+
runGroupIndex = groupIndex;
|
|
14046
|
+
}
|
|
14047
|
+
const showClear = !isAtDefaultValue(field, values[field.key]);
|
|
14048
|
+
const node = isInlineDateField(field) ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
14049
|
+
InlineDatePresetFilter,
|
|
14050
|
+
{
|
|
14051
|
+
field,
|
|
14052
|
+
value: values[field.key],
|
|
14053
|
+
disabled: disabled || field.disabled,
|
|
14054
|
+
warning,
|
|
14055
|
+
showClear,
|
|
14056
|
+
onValueChange: (next) => emitValueAndSearch(field.key, next),
|
|
14057
|
+
onClear: () => clearValue(field.key)
|
|
14058
|
+
},
|
|
14059
|
+
field.key
|
|
14060
|
+
) : field.type === "custom" ? /* @__PURE__ */ jsxRuntime.jsx(react.Fragment, { children: field.render?.({
|
|
14061
|
+
value: values[field.key],
|
|
14062
|
+
disabled: disabled || field.disabled,
|
|
14063
|
+
warning,
|
|
14064
|
+
onValueChange: (next) => emitValueAndSearch(field.key, next)
|
|
14065
|
+
}) }, field.key) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
14066
|
+
FilterChip,
|
|
14067
|
+
{
|
|
14068
|
+
field,
|
|
14069
|
+
valueText: chipDisplayValue(field, values[field.key]),
|
|
14070
|
+
active: openKey === field.key,
|
|
14071
|
+
applied: !isEmptyValue(values[field.key]),
|
|
14072
|
+
disabled: disabled || field.disabled,
|
|
14073
|
+
warning,
|
|
14074
|
+
showClear,
|
|
14075
|
+
refCallback: (node2) => triggerRefs.current.set(field.key, node2),
|
|
14076
|
+
onOpen: () => setOpenKey(openKey === field.key ? null : field.key),
|
|
14077
|
+
onClear: () => clearValue(field.key)
|
|
14078
|
+
},
|
|
14079
|
+
field.key
|
|
14080
|
+
);
|
|
14081
|
+
runBuffer.push(
|
|
14082
|
+
needsLeadingDivider ? /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, { children: [
|
|
14083
|
+
/* @__PURE__ */ jsxRuntime.jsx(Divider, { inset: true }),
|
|
14084
|
+
node
|
|
14085
|
+
] }, `${field.key}-wrap`) : node
|
|
14086
|
+
);
|
|
14087
|
+
});
|
|
14088
|
+
flushRun();
|
|
14089
|
+
return nodes;
|
|
14090
|
+
})(),
|
|
14091
|
+
(() => {
|
|
14092
|
+
const lastField = activeFields[activeFields.length - 1];
|
|
14093
|
+
const needsTrailingDivider = lastField != null && isInlineField(lastField) && !hasRightActions;
|
|
14094
|
+
return needsTrailingDivider ? /* @__PURE__ */ jsxRuntime.jsx(Divider, { inset: true }) : null;
|
|
14095
|
+
})(),
|
|
14096
|
+
hasRightActions && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
14097
|
+
/* @__PURE__ */ jsxRuntime.jsx(Divider, { inset: true }),
|
|
14098
|
+
showAddButton && /* @__PURE__ */ jsxRuntime.jsxs(RPopover9__namespace.Root, { open: addOpen, onOpenChange: setAddOpen, children: [
|
|
14099
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14100
|
+
"button",
|
|
14101
|
+
{
|
|
14102
|
+
type: "button",
|
|
14103
|
+
disabled: disabled || inactiveFields.length === 0,
|
|
14104
|
+
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",
|
|
14105
|
+
style: {
|
|
14106
|
+
minHeight: "var(--cmp-chipFilter-addButton-height)" ,
|
|
14107
|
+
borderRadius: "var(--cmp-chipFilter-addButton-radius)" ,
|
|
14108
|
+
borderColor: disabled || inactiveFields.length === 0 ? CHIPFILTER.addBorderDisabled : CHIPFILTER.addBorder,
|
|
14109
|
+
color: disabled || inactiveFields.length === 0 ? CHIPFILTER.addTextDisabled : CHIPFILTER.addText
|
|
14110
|
+
},
|
|
14111
|
+
children: [
|
|
14112
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14113
|
+
SIcon,
|
|
14114
|
+
{
|
|
14115
|
+
name: "add",
|
|
14116
|
+
size: 12,
|
|
14117
|
+
color: disabled || inactiveFields.length === 0 ? CHIPFILTER.addTextDisabled : CHIPFILTER.addText
|
|
14118
|
+
}
|
|
14119
|
+
),
|
|
14120
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "\uD544\uD130 \uCD94\uAC00" })
|
|
14121
|
+
]
|
|
14122
|
+
}
|
|
14123
|
+
) }),
|
|
14124
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14125
|
+
RPopover9__namespace.Content,
|
|
14126
|
+
{
|
|
14127
|
+
side: "bottom",
|
|
14128
|
+
align: "start",
|
|
14129
|
+
sideOffset: 4,
|
|
14130
|
+
className: cn("z-50 min-w-[180px]", FLOATING_SLIDE_ANIM),
|
|
14131
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ListBox, { children: inactiveFields.length > 0 ? inactiveFields.map((field) => /* @__PURE__ */ jsxRuntime.jsx(MenuItem, { onClick: () => addField(field.key), children: field.label }, field.key)) : /* @__PURE__ */ jsxRuntime.jsx(EmptyItem, { children: "\uCD94\uAC00\uD560 \uD544\uD130\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4." }) })
|
|
14132
|
+
}
|
|
14133
|
+
) })
|
|
14134
|
+
] }),
|
|
14135
|
+
showReset && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14136
|
+
"button",
|
|
14137
|
+
{
|
|
14138
|
+
type: "button",
|
|
14139
|
+
disabled: disabled || !hasValue,
|
|
14140
|
+
onClick: reset,
|
|
14141
|
+
className: cn(
|
|
14142
|
+
"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",
|
|
14143
|
+
// 부모 flex gap(6px)은 칩 사이 간격 기준이라, 필터 추가 버튼과의 12px 간격을 맞추려면
|
|
14144
|
+
// 부족한 만큼(12px - gap)을 추가로 띄운다. 필터 추가가 없을 땐 divider와 이미 12px이라 불필요.
|
|
14145
|
+
showAddButton && "ml-[calc(12px-var(--cmp-chipFilter-chip-group))]"
|
|
14146
|
+
),
|
|
14147
|
+
style: {
|
|
14148
|
+
color: disabled || !hasValue ? "var(--cmp-textLink-content-disabled)" : "var(--cmp-textLink-content-default)"
|
|
14149
|
+
},
|
|
14150
|
+
children: [
|
|
14151
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14152
|
+
SIcon,
|
|
14153
|
+
{
|
|
14154
|
+
name: "reset",
|
|
14155
|
+
size: 16,
|
|
14156
|
+
color: disabled || !hasValue ? "var(--cmp-textLink-icon-disabled)" : "var(--cmp-textLink-icon-default)"
|
|
14157
|
+
}
|
|
14158
|
+
),
|
|
14159
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "\uAC80\uC0C9 \uCD08\uAE30\uD654" })
|
|
14160
|
+
]
|
|
14161
|
+
}
|
|
14162
|
+
)
|
|
14163
|
+
] })
|
|
14164
|
+
] }),
|
|
14165
|
+
/* @__PURE__ */ jsxRuntime.jsxs(RPopover9__namespace.Root, { open: openKey != null, onOpenChange: (next) => !next && setOpenKey(null), children: [
|
|
14166
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14167
|
+
RPopover9__namespace.Anchor,
|
|
14168
|
+
{
|
|
14169
|
+
virtualRef: {
|
|
14170
|
+
current: openKey ? triggerRefs.current.get(openKey) : null
|
|
14171
|
+
}
|
|
14172
|
+
}
|
|
14173
|
+
),
|
|
14174
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14175
|
+
RPopover9__namespace.Content,
|
|
14176
|
+
{
|
|
14177
|
+
side: "bottom",
|
|
14178
|
+
align: "start",
|
|
14179
|
+
sideOffset: 4,
|
|
14180
|
+
onOpenAutoFocus: (event) => event.preventDefault(),
|
|
14181
|
+
className: cn("z-50", FLOATING_SLIDE_ANIM),
|
|
14182
|
+
style: editorPopoverStyle,
|
|
14183
|
+
children: currentOpenField && /* @__PURE__ */ jsxRuntime.jsx(
|
|
14184
|
+
EditorPanel,
|
|
14185
|
+
{
|
|
14186
|
+
field: currentOpenField,
|
|
14187
|
+
value: values[currentOpenField.key],
|
|
14188
|
+
disabled: disabled || currentOpenField.disabled,
|
|
14189
|
+
onValueChange: (next) => emitValue(currentOpenField.key, next),
|
|
14190
|
+
onClose: () => setOpenKey(null)
|
|
14191
|
+
}
|
|
14192
|
+
)
|
|
14193
|
+
}
|
|
14194
|
+
) })
|
|
14195
|
+
] })
|
|
14196
|
+
]
|
|
14197
|
+
}
|
|
14198
|
+
);
|
|
14199
|
+
});
|
|
14200
|
+
function Divider({ inset, top } = {}) {
|
|
14201
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
14202
|
+
"span",
|
|
14203
|
+
{
|
|
14204
|
+
"aria-hidden": true,
|
|
14205
|
+
className: cn(
|
|
14206
|
+
"inline-flex w-px shrink-0 bg-[var(--chipfilter-bar-border)]",
|
|
14207
|
+
top ? "mt-[2px] self-start" : "my-auto",
|
|
14208
|
+
inset && "mx-[calc(12px-var(--cmp-chipFilter-chip-group))]"
|
|
14209
|
+
),
|
|
14210
|
+
style: { height: "var(--chipfilter-divider-height)" }
|
|
14211
|
+
}
|
|
14212
|
+
);
|
|
14213
|
+
}
|
|
14214
|
+
function GroupTooltip({
|
|
14215
|
+
message,
|
|
14216
|
+
open,
|
|
14217
|
+
children
|
|
14218
|
+
}) {
|
|
14219
|
+
return /* @__PURE__ */ jsxRuntime.jsx(STooltip2, { trigger: "none", open, placement: "top", tooltipType: "warning", message: [message], children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-[var(--cmp-chipFilter-chip-group)]", children }) });
|
|
14220
|
+
}
|
|
14221
|
+
function FilterChip({
|
|
14222
|
+
field,
|
|
14223
|
+
valueText,
|
|
14224
|
+
active,
|
|
14225
|
+
applied,
|
|
14226
|
+
disabled,
|
|
14227
|
+
warning,
|
|
14228
|
+
showClear,
|
|
14229
|
+
refCallback,
|
|
14230
|
+
onOpen,
|
|
14231
|
+
onClear
|
|
14232
|
+
}) {
|
|
14233
|
+
const border = disabled ? CHIPFILTER.chipDisabledBorder : warning ? CHIPFILTER.chipWarningBorder : applied ? active ? "var(--color-blue-strong)" : CHIPFILTER.chipAppliedBorder : active ? CHIPFILTER.chipActiveBorder : CHIPFILTER.chipDefaultBorder;
|
|
14234
|
+
const background = disabled ? CHIPFILTER.chipDisabledBg : applied ? CHIPFILTER.chipAppliedBg : CHIPFILTER.chipDefaultBg;
|
|
14235
|
+
const textColor = disabled ? CHIPFILTER.chipDisabledText : CHIPFILTER.chipDefaultText;
|
|
14236
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14237
|
+
"button",
|
|
14238
|
+
{
|
|
14239
|
+
ref: refCallback,
|
|
14240
|
+
type: "button",
|
|
14241
|
+
disabled,
|
|
14242
|
+
"aria-expanded": active,
|
|
14243
|
+
onPointerDown: (event) => event.stopPropagation(),
|
|
14244
|
+
onClick: onOpen,
|
|
14245
|
+
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",
|
|
14246
|
+
style: {
|
|
14247
|
+
minHeight: CHIPFILTER.chipHeight,
|
|
14248
|
+
gap: CHIPFILTER.chipGap,
|
|
14249
|
+
borderRadius: CHIPFILTER.chipRadius,
|
|
14250
|
+
borderColor: border,
|
|
14251
|
+
background,
|
|
14252
|
+
color: textColor
|
|
14253
|
+
},
|
|
14254
|
+
children: [
|
|
14255
|
+
field.required && /* @__PURE__ */ jsxRuntime.jsx(
|
|
14256
|
+
SIcon,
|
|
14257
|
+
{
|
|
14258
|
+
name: "asterisk",
|
|
14259
|
+
size: 12,
|
|
14260
|
+
color: disabled ? CHIPFILTER.chipDisabledText : "var(--cmp-tag-darkblue-content)"
|
|
14261
|
+
}
|
|
14262
|
+
),
|
|
14263
|
+
applied ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex min-w-0 items-center gap-[4px] truncate", children: [
|
|
14264
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14265
|
+
"span",
|
|
14266
|
+
{
|
|
14267
|
+
className: "font-bold",
|
|
14268
|
+
style: { color: disabled ? CHIPFILTER.chipDisabledText : CHIPFILTER.chipAppliedLabel },
|
|
14269
|
+
children: field.label
|
|
14270
|
+
}
|
|
14271
|
+
),
|
|
14272
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14273
|
+
"span",
|
|
14274
|
+
{
|
|
14275
|
+
style: { color: disabled ? CHIPFILTER.chipDisabledText : CHIPFILTER.chipAppliedLabel },
|
|
14276
|
+
children: ":"
|
|
14277
|
+
}
|
|
14278
|
+
),
|
|
14279
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14280
|
+
"span",
|
|
14281
|
+
{
|
|
14282
|
+
className: "min-w-0 truncate font-bold",
|
|
14283
|
+
style: { color: disabled ? CHIPFILTER.chipDisabledText : CHIPFILTER.chipAppliedValue },
|
|
14284
|
+
children: valueText
|
|
14285
|
+
}
|
|
14286
|
+
)
|
|
14287
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
14288
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("min-w-0 truncate", active && "font-bold"), children: field.label }),
|
|
14289
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14290
|
+
SIcon,
|
|
14291
|
+
{
|
|
14292
|
+
name: "caretDown",
|
|
14293
|
+
size: 12,
|
|
14294
|
+
color: disabled ? CHIPFILTER.chipDisabledText : CHIPFILTER.chipDefaultText
|
|
14295
|
+
}
|
|
14296
|
+
)
|
|
14297
|
+
] }),
|
|
14298
|
+
applied && !disabled && showClear && /* @__PURE__ */ jsxRuntime.jsx(
|
|
14299
|
+
"span",
|
|
14300
|
+
{
|
|
14301
|
+
role: "button",
|
|
14302
|
+
tabIndex: 0,
|
|
14303
|
+
"aria-label": `${field.label} \uD544\uD130 \uC9C0\uC6B0\uAE30`,
|
|
14304
|
+
className: "inline-flex size-[16px] items-center justify-center rounded-[var(--cmp-ghostButton-radius-sm)]",
|
|
14305
|
+
onClick: (event) => {
|
|
14306
|
+
event.preventDefault();
|
|
14307
|
+
event.stopPropagation();
|
|
14308
|
+
onClear();
|
|
14309
|
+
},
|
|
14310
|
+
onKeyDown: (event) => {
|
|
14311
|
+
if (event.key !== "Enter" && event.key !== " ") return;
|
|
14312
|
+
event.preventDefault();
|
|
14313
|
+
event.stopPropagation();
|
|
14314
|
+
onClear();
|
|
14315
|
+
},
|
|
14316
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "close", size: 12, color: "var(--cmp-ghostButton-default-content)" })
|
|
14317
|
+
}
|
|
14318
|
+
)
|
|
14319
|
+
]
|
|
14320
|
+
}
|
|
14321
|
+
);
|
|
14322
|
+
}
|
|
14323
|
+
function EditorPanel({
|
|
14324
|
+
field,
|
|
14325
|
+
value,
|
|
14326
|
+
disabled,
|
|
14327
|
+
onValueChange,
|
|
14328
|
+
onClose
|
|
14329
|
+
}) {
|
|
14330
|
+
const wrapsInPaddedTop = field.type === "date";
|
|
14331
|
+
const isMulti = field.type === "multi";
|
|
14332
|
+
const selectableValues = isMulti ? (field.options ?? []).filter((option) => !option.disabled).map((option) => option.value) : [];
|
|
14333
|
+
const selectedValues = isMulti ? toArrayValue(value) : [];
|
|
14334
|
+
const allSelected = isMulti && selectableValues.length > 0 && selectableValues.every((v) => selectedValues.includes(v));
|
|
14335
|
+
const toggleSelectAll = () => {
|
|
14336
|
+
onValueChange(
|
|
14337
|
+
allSelected ? selectedValues.filter((v) => !selectableValues.includes(v)) : [...selectedValues, ...selectableValues.filter((v) => !selectedValues.includes(v))]
|
|
14338
|
+
);
|
|
14339
|
+
};
|
|
14340
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(ListBox, { children: [
|
|
14341
|
+
wrapsInPaddedTop ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-[var(--cmp-chipFilter-listbox-top-gap)] px-[var(--cmp-chipFilter-listbox-top-paddingX)] py-[var(--cmp-chipFilter-listbox-top-paddingY)]", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14342
|
+
FilterEditor,
|
|
14343
|
+
{
|
|
14344
|
+
field,
|
|
14345
|
+
value,
|
|
14346
|
+
disabled,
|
|
14347
|
+
onValueChange
|
|
14348
|
+
}
|
|
14349
|
+
) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
14350
|
+
FilterEditor,
|
|
14351
|
+
{
|
|
14352
|
+
field,
|
|
14353
|
+
value,
|
|
14354
|
+
disabled,
|
|
14355
|
+
onValueChange
|
|
14356
|
+
}
|
|
14357
|
+
),
|
|
14358
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
14359
|
+
"div",
|
|
14360
|
+
{
|
|
14361
|
+
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)]",
|
|
14362
|
+
style: { borderColor: CHIPFILTER.listboxBorder },
|
|
14363
|
+
children: [
|
|
14364
|
+
isMulti && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
14365
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14366
|
+
STextLink,
|
|
14367
|
+
{
|
|
14368
|
+
size: "sm",
|
|
14369
|
+
label: allSelected ? "\uC120\uD0DD \uD574\uC81C" : "\uC804\uCCB4 \uC120\uD0DD",
|
|
14370
|
+
labelClass: "font-bold",
|
|
14371
|
+
disabled,
|
|
14372
|
+
onClick: toggleSelectAll,
|
|
14373
|
+
style: { color: "var(--sys-color-fg-secondary)" }
|
|
14374
|
+
}
|
|
14375
|
+
),
|
|
14376
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14377
|
+
"span",
|
|
14378
|
+
{
|
|
14379
|
+
"aria-hidden": true,
|
|
14380
|
+
className: "inline-flex w-px shrink-0",
|
|
14381
|
+
style: {
|
|
14382
|
+
height: CHIPFILTER.listboxBottomDividerHeight,
|
|
14383
|
+
background: CHIPFILTER.listboxBorder
|
|
14384
|
+
}
|
|
14385
|
+
}
|
|
14386
|
+
)
|
|
14387
|
+
] }),
|
|
14388
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14389
|
+
STextLink,
|
|
14390
|
+
{
|
|
14391
|
+
size: "sm",
|
|
14392
|
+
label: "\uAC80\uC0C9",
|
|
14393
|
+
labelClass: "font-bold",
|
|
14394
|
+
onClick: onClose,
|
|
14395
|
+
style: { color: CHIPFILTER.chipAppliedValue }
|
|
14396
|
+
}
|
|
14397
|
+
)
|
|
14398
|
+
]
|
|
14399
|
+
}
|
|
14400
|
+
)
|
|
14401
|
+
] });
|
|
14402
|
+
}
|
|
14403
|
+
function FilterEditor({
|
|
14404
|
+
field,
|
|
14405
|
+
value,
|
|
14406
|
+
disabled,
|
|
14407
|
+
onValueChange
|
|
14408
|
+
}) {
|
|
14409
|
+
if (field.type === "date") {
|
|
14410
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
14411
|
+
DatePresetEditor,
|
|
14412
|
+
{
|
|
14413
|
+
field,
|
|
14414
|
+
value,
|
|
14415
|
+
disabled,
|
|
14416
|
+
onValueChange
|
|
14417
|
+
}
|
|
14418
|
+
);
|
|
14419
|
+
}
|
|
14420
|
+
if (field.type === "keyword") {
|
|
14421
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
14422
|
+
KeywordEditor,
|
|
14423
|
+
{
|
|
14424
|
+
field,
|
|
14425
|
+
value: isKeywordValue(value) ? value : keywordEntries(value),
|
|
14426
|
+
disabled,
|
|
14427
|
+
onValueChange
|
|
14428
|
+
}
|
|
14429
|
+
);
|
|
14430
|
+
}
|
|
14431
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
14432
|
+
OptionList,
|
|
14433
|
+
{
|
|
14434
|
+
field,
|
|
14435
|
+
value: field.type === "multi" ? toArrayValue(value) : value,
|
|
14436
|
+
multiple: field.type === "multi",
|
|
14437
|
+
disabled,
|
|
14438
|
+
onValueChange
|
|
14439
|
+
}
|
|
14440
|
+
);
|
|
14441
|
+
}
|
|
14442
|
+
function DatePresetEditor({
|
|
14443
|
+
field,
|
|
14444
|
+
value,
|
|
14445
|
+
disabled,
|
|
14446
|
+
onValueChange
|
|
14447
|
+
}) {
|
|
14448
|
+
const presets = field.presets ?? [];
|
|
14449
|
+
const [selectedId, setSelectedId] = react.useState(() => matchPresetId(presets, value));
|
|
14450
|
+
const syncedInitialValueRef = react.useRef(!isEmptyValue(value));
|
|
14451
|
+
react.useEffect(() => {
|
|
14452
|
+
if (syncedInitialValueRef.current || isEmptyValue(value)) return;
|
|
14453
|
+
syncedInitialValueRef.current = true;
|
|
14454
|
+
setSelectedId(matchPresetId(presets, value));
|
|
14455
|
+
}, [value, presets]);
|
|
14456
|
+
const selectedPreset = presets.find((preset) => preset.value === selectedId);
|
|
14457
|
+
const selectPreset = (preset) => {
|
|
14458
|
+
setSelectedId(preset.value);
|
|
14459
|
+
if (!preset.custom) onValueChange(preset.resolve ? preset.resolve() : null);
|
|
14460
|
+
};
|
|
14461
|
+
if (presets.length === 0) {
|
|
14462
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
14463
|
+
SDatePicker,
|
|
14464
|
+
{
|
|
14465
|
+
value: typeof value === "string" ? value : null,
|
|
14466
|
+
onValueChange,
|
|
14467
|
+
selectable: field.selectable,
|
|
14468
|
+
disabled,
|
|
14469
|
+
placeholder: field.placeholder
|
|
14470
|
+
}
|
|
14471
|
+
);
|
|
14472
|
+
}
|
|
14473
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-[var(--cmp-chipFilter-listbox-top-gap)]", children: [
|
|
14474
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-[8px]", children: presets.map((preset) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
14475
|
+
SRadio,
|
|
14476
|
+
{
|
|
14477
|
+
val: preset.value,
|
|
14478
|
+
value: selectedId,
|
|
14479
|
+
label: preset.label,
|
|
14480
|
+
disabled,
|
|
14481
|
+
onValueChange: () => selectPreset(preset)
|
|
14482
|
+
},
|
|
14483
|
+
preset.value
|
|
14484
|
+
)) }),
|
|
14485
|
+
selectedPreset?.custom && /* @__PURE__ */ jsxRuntime.jsx(
|
|
14486
|
+
SDateRangePicker,
|
|
14487
|
+
{
|
|
14488
|
+
value: Array.isArray(value) && value.length === 2 ? value : null,
|
|
14489
|
+
onValueChange,
|
|
14490
|
+
selectable: field.selectable,
|
|
14491
|
+
maxRange: field.maxRange,
|
|
14492
|
+
disabled
|
|
14493
|
+
}
|
|
14494
|
+
)
|
|
14495
|
+
] });
|
|
14496
|
+
}
|
|
14497
|
+
function InlineDatePresetFilter({
|
|
14498
|
+
field,
|
|
14499
|
+
value,
|
|
14500
|
+
disabled,
|
|
14501
|
+
warning,
|
|
14502
|
+
showClear,
|
|
14503
|
+
onValueChange,
|
|
14504
|
+
onClear
|
|
14505
|
+
}) {
|
|
14506
|
+
const presets = (field.presets ?? []).filter((preset) => !preset.custom);
|
|
14507
|
+
const [selectedId, setSelectedId] = react.useState(() => matchPresetId(presets, value));
|
|
14508
|
+
const syncedInitialValueRef = react.useRef(!isEmptyValue(value));
|
|
14509
|
+
react.useEffect(() => {
|
|
14510
|
+
if (syncedInitialValueRef.current || isEmptyValue(value)) return;
|
|
14511
|
+
syncedInitialValueRef.current = true;
|
|
14512
|
+
setSelectedId(matchPresetId(presets, value));
|
|
14513
|
+
}, [value, presets]);
|
|
14514
|
+
const applied = !isEmptyValue(value);
|
|
14515
|
+
const rangeValue = Array.isArray(value) ? value : typeof value === "string" && value !== "" ? [value, value] : null;
|
|
14516
|
+
const [pickerOpen, setPickerOpen] = react.useState(false);
|
|
14517
|
+
const portalContainer = usePortalContainer();
|
|
14518
|
+
const selectPreset = (id) => {
|
|
14519
|
+
const preset = presets.find((p) => p.value === id);
|
|
14520
|
+
if (!preset) return;
|
|
14521
|
+
setSelectedId(preset.value);
|
|
14522
|
+
onValueChange(preset.resolve ? preset.resolve() : null);
|
|
14523
|
+
};
|
|
14524
|
+
const badge = applied && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14525
|
+
"span",
|
|
14526
|
+
{
|
|
14527
|
+
className: "inline-flex shrink-0 items-center gap-[4px] whitespace-nowrap border border-solid px-[var(--cmp-chipFilter-chip-paddingX)] text-[12px] leading-[20px]",
|
|
14528
|
+
style: {
|
|
14529
|
+
minHeight: CHIPFILTER.chipHeight,
|
|
14530
|
+
borderRadius: CHIPFILTER.chipRadius,
|
|
14531
|
+
borderColor: warning ? CHIPFILTER.chipWarningBorder : CHIPFILTER.chipAppliedBorder,
|
|
14532
|
+
background: CHIPFILTER.chipAppliedBg,
|
|
14533
|
+
color: CHIPFILTER.chipAppliedLabel,
|
|
14534
|
+
cursor: rangeValue ? "pointer" : void 0
|
|
14535
|
+
},
|
|
14536
|
+
children: [
|
|
14537
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-bold", children: [
|
|
14538
|
+
field.label,
|
|
14539
|
+
":"
|
|
14540
|
+
] }),
|
|
14541
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-bold", style: { color: CHIPFILTER.chipAppliedValue }, children: displayValue(field, value) }),
|
|
14542
|
+
!disabled && showClear && /* @__PURE__ */ jsxRuntime.jsx(
|
|
14543
|
+
"span",
|
|
14544
|
+
{
|
|
14545
|
+
role: "button",
|
|
14546
|
+
tabIndex: 0,
|
|
14547
|
+
"aria-label": `${field.label} \uD544\uD130 \uC9C0\uC6B0\uAE30`,
|
|
14548
|
+
className: "inline-flex size-[16px] items-center justify-center rounded-[var(--cmp-ghostButton-radius-sm)]",
|
|
14549
|
+
onClick: (event) => {
|
|
14550
|
+
event.stopPropagation();
|
|
14551
|
+
onClear();
|
|
14552
|
+
},
|
|
14553
|
+
onKeyDown: (event) => {
|
|
14554
|
+
if (event.key !== "Enter" && event.key !== " ") return;
|
|
14555
|
+
event.preventDefault();
|
|
14556
|
+
event.stopPropagation();
|
|
14557
|
+
onClear();
|
|
14558
|
+
},
|
|
14559
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "close", size: 12, color: "var(--cmp-ghostButton-default-content)" })
|
|
14560
|
+
}
|
|
14561
|
+
)
|
|
14562
|
+
]
|
|
14563
|
+
}
|
|
14564
|
+
);
|
|
14565
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-[8px]", children: [
|
|
14566
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14567
|
+
SRadioButton,
|
|
14568
|
+
{
|
|
14569
|
+
size: "xs",
|
|
14570
|
+
options: presets.map((preset) => ({ value: preset.value, label: preset.label })),
|
|
14571
|
+
value: selectedId,
|
|
14572
|
+
disabled,
|
|
14573
|
+
onValueChange: (next) => selectPreset(String(next))
|
|
14574
|
+
}
|
|
14575
|
+
),
|
|
14576
|
+
applied && (rangeValue ? (
|
|
14577
|
+
// 뱃지 모양은 그대로 두고, 눌렀을 때 캘린더가 열려 기간을 직접 다시 고를 수 있게 한다.
|
|
14578
|
+
// 직접 고르면 프리셋 선택은 해제된다.
|
|
14579
|
+
/* @__PURE__ */ jsxRuntime.jsxs(RPopover9__namespace.Root, { open: pickerOpen, onOpenChange: setPickerOpen, children: [
|
|
14580
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14581
|
+
"button",
|
|
14582
|
+
{
|
|
14583
|
+
type: "button",
|
|
14584
|
+
disabled,
|
|
14585
|
+
className: "border-none bg-transparent p-0 outline-none disabled:cursor-not-allowed",
|
|
14586
|
+
children: badge
|
|
14587
|
+
}
|
|
14588
|
+
) }),
|
|
14589
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14590
|
+
RPopover9__namespace.Content,
|
|
14591
|
+
{
|
|
14592
|
+
side: "bottom",
|
|
14593
|
+
align: "start",
|
|
14594
|
+
sideOffset: 4,
|
|
14595
|
+
className: cn("z-50", FLOATING_SLIDE_ANIM),
|
|
14596
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14597
|
+
RangeCalendar,
|
|
14598
|
+
{
|
|
14599
|
+
value: rangeValue,
|
|
14600
|
+
selectable: field.selectable,
|
|
14601
|
+
maxRange: field.maxRange,
|
|
14602
|
+
onSelect: (range) => {
|
|
14603
|
+
setSelectedId(null);
|
|
14604
|
+
onValueChange(range);
|
|
14605
|
+
setPickerOpen(false);
|
|
14606
|
+
}
|
|
14607
|
+
}
|
|
14608
|
+
)
|
|
14609
|
+
}
|
|
14610
|
+
) })
|
|
14611
|
+
] })
|
|
14612
|
+
) : badge)
|
|
14613
|
+
] });
|
|
14614
|
+
}
|
|
14615
|
+
var MATCH_MODE_OPTIONS = [
|
|
14616
|
+
{ value: "contains", label: "\uD3EC\uD568" },
|
|
14617
|
+
{ value: "exact", label: "\uC77C\uCE58" }
|
|
14618
|
+
];
|
|
14619
|
+
var EXCLUDE_MATCH_MODE_OPTION = {
|
|
14620
|
+
value: "excludes",
|
|
14621
|
+
label: "\uBBF8\uD3EC\uD568"
|
|
14622
|
+
};
|
|
14623
|
+
function KeywordEditor({
|
|
14624
|
+
field,
|
|
14625
|
+
value,
|
|
14626
|
+
disabled,
|
|
14627
|
+
onValueChange
|
|
14628
|
+
}) {
|
|
14629
|
+
const entries3 = keywordEntries(value);
|
|
14630
|
+
const [draft, setDraft] = react.useState("");
|
|
14631
|
+
const [mode, setMode] = react.useState(
|
|
14632
|
+
isKeywordValue(value) ? value.mode : "contains"
|
|
14633
|
+
);
|
|
14634
|
+
const emit3 = (nextEntries) => {
|
|
14635
|
+
onValueChange(field.matchModes ? { keywords: nextEntries, mode } : nextEntries);
|
|
14636
|
+
};
|
|
14637
|
+
const addEntry = (raw) => {
|
|
14638
|
+
const next = raw.trim();
|
|
14639
|
+
if (next === "" || entries3.includes(next)) return;
|
|
14640
|
+
emit3([...entries3, next]);
|
|
14641
|
+
setDraft("");
|
|
14642
|
+
};
|
|
14643
|
+
const removeEntry = (entry) => {
|
|
14644
|
+
emit3(entries3.filter((e) => e !== entry));
|
|
14645
|
+
};
|
|
14646
|
+
const onKeyDown = (event) => {
|
|
14647
|
+
if (event.key === "Enter") {
|
|
14648
|
+
if (event.nativeEvent.isComposing) return;
|
|
14649
|
+
event.preventDefault();
|
|
14650
|
+
addEntry(draft);
|
|
14651
|
+
}
|
|
14652
|
+
};
|
|
14653
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
14654
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-[var(--cmp-chipFilter-listbox-top-gap)] px-[var(--cmp-chipFilter-listbox-top-paddingX)] py-[var(--cmp-chipFilter-listbox-top-paddingY)]", children: [
|
|
14655
|
+
field.matchModes && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
14656
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14657
|
+
"span",
|
|
14658
|
+
{
|
|
14659
|
+
className: "shrink-0 whitespace-nowrap text-[12px] font-medium leading-[20px]",
|
|
14660
|
+
style: { color: CHIPFILTER.listboxLabel },
|
|
14661
|
+
children: "\uAC80\uC0C9 \uC870\uAC74 :"
|
|
14662
|
+
}
|
|
14663
|
+
),
|
|
14664
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14665
|
+
SRadioButton,
|
|
14666
|
+
{
|
|
14667
|
+
size: "xs",
|
|
14668
|
+
style: { width: 150 },
|
|
14669
|
+
options: field.excludeMode ? [...MATCH_MODE_OPTIONS, EXCLUDE_MATCH_MODE_OPTION] : MATCH_MODE_OPTIONS,
|
|
14670
|
+
value: mode,
|
|
14671
|
+
disabled,
|
|
14672
|
+
onValueChange: (next) => setMode(next)
|
|
14673
|
+
}
|
|
14674
|
+
)
|
|
14675
|
+
] }),
|
|
14676
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-[6px] rounded-[4px] border border-solid border-[color:var(--sys-color-field-border-default)] bg-[var(--sys-color-field-bg-default)] px-[8px] py-[4px] focus-within:border-[color:var(--sys-color-field-border-focus)]", children: [
|
|
14677
|
+
/* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "search", size: 16, color: "var(--sys-color-field-icon-default)" }),
|
|
14678
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14679
|
+
"input",
|
|
14680
|
+
{
|
|
14681
|
+
value: draft,
|
|
14682
|
+
disabled,
|
|
14683
|
+
placeholder: field.placeholder ?? "\uC785\uB825 \uD6C4 Enter\uB85C \uCD94\uAC00",
|
|
14684
|
+
onChange: (event) => setDraft(event.target.value),
|
|
14685
|
+
onKeyDown,
|
|
14686
|
+
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"
|
|
14687
|
+
}
|
|
14688
|
+
)
|
|
14689
|
+
] })
|
|
14690
|
+
] }),
|
|
14691
|
+
entries3.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
14692
|
+
"div",
|
|
14693
|
+
{
|
|
14694
|
+
className: "max-h-[220px] overflow-auto border-t border-solid py-[var(--cmp-chipFilter-listbox-list-paddingY)]",
|
|
14695
|
+
style: { borderColor: CHIPFILTER.listboxBorder },
|
|
14696
|
+
children: entries3.map((entry) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
14697
|
+
KeywordEntryRow,
|
|
14698
|
+
{
|
|
14699
|
+
label: optionLabel(field, entry),
|
|
14700
|
+
disabled,
|
|
14701
|
+
onRemove: () => removeEntry(entry)
|
|
14702
|
+
},
|
|
14703
|
+
entry
|
|
14704
|
+
))
|
|
14705
|
+
}
|
|
14706
|
+
)
|
|
14707
|
+
] });
|
|
14708
|
+
}
|
|
14709
|
+
function KeywordEntryRow({
|
|
14710
|
+
label,
|
|
14711
|
+
disabled,
|
|
14712
|
+
onRemove
|
|
14713
|
+
}) {
|
|
14714
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14715
|
+
"div",
|
|
14716
|
+
{
|
|
14717
|
+
className: "group flex w-full items-center justify-between gap-[8px] text-[12px] leading-[20px]",
|
|
14718
|
+
style: {
|
|
14719
|
+
paddingTop: CHIPFILTER.itemPaddingY,
|
|
14720
|
+
paddingBottom: CHIPFILTER.itemPaddingY,
|
|
14721
|
+
paddingLeft: CHIPFILTER.itemPaddingLeft,
|
|
14722
|
+
paddingRight: CHIPFILTER.itemPaddingRight,
|
|
14723
|
+
color: disabled ? CHIPFILTER.chipDisabledText : CHIPFILTER.itemTextDefault
|
|
14724
|
+
},
|
|
14725
|
+
children: [
|
|
14726
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("min-w-0 truncate", !disabled && "group-hover:font-bold"), children: label }),
|
|
14727
|
+
!disabled && /* @__PURE__ */ jsxRuntime.jsx(
|
|
14728
|
+
"button",
|
|
14729
|
+
{
|
|
14730
|
+
type: "button",
|
|
14731
|
+
"aria-label": `${label} \uC0AD\uC81C`,
|
|
14732
|
+
className: "invisible inline-flex size-[16px] shrink-0 cursor-pointer items-center justify-center group-hover:visible",
|
|
14733
|
+
onClick: onRemove,
|
|
14734
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "close", size: 12, color: "var(--cmp-ghostButton-default-content)" })
|
|
14735
|
+
}
|
|
14736
|
+
)
|
|
14737
|
+
]
|
|
14738
|
+
}
|
|
14739
|
+
);
|
|
14740
|
+
}
|
|
14741
|
+
var OPTION_SEARCH_THRESHOLD = 11;
|
|
14742
|
+
function OptionList({
|
|
14743
|
+
field,
|
|
14744
|
+
value,
|
|
14745
|
+
multiple,
|
|
14746
|
+
disabled,
|
|
14747
|
+
onValueChange
|
|
14748
|
+
}) {
|
|
14749
|
+
const selected = multiple ? toArrayValue(value) : [];
|
|
14750
|
+
const singleValue = !multiple && (typeof value === "string" || typeof value === "number") ? value : null;
|
|
14751
|
+
const [search, setSearch] = react.useState("");
|
|
14752
|
+
const options = field.options ?? [];
|
|
14753
|
+
const showSearch = options.length >= OPTION_SEARCH_THRESHOLD;
|
|
14754
|
+
const filteredOptions = react.useMemo(() => {
|
|
14755
|
+
if (!showSearch || search.trim() === "") return options;
|
|
14756
|
+
const query = search.trim().toLowerCase();
|
|
14757
|
+
return options.filter((option) => option.label.toLowerCase().includes(query));
|
|
14758
|
+
}, [options, search, showSearch]);
|
|
14759
|
+
if (options.length === 0) return /* @__PURE__ */ jsxRuntime.jsx(EmptyItem, { children: "\uD45C\uC2DC\uD560 \uD56D\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4." });
|
|
14760
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14761
|
+
"div",
|
|
14762
|
+
{
|
|
14763
|
+
className: cn(
|
|
14764
|
+
"max-h-[240px] overflow-auto",
|
|
14765
|
+
!showSearch && "pt-[var(--cmp-chipFilter-listbox-list-paddingY)]",
|
|
14766
|
+
"pb-[var(--cmp-chipFilter-listbox-list-paddingY)]"
|
|
14767
|
+
),
|
|
14768
|
+
children: [
|
|
14769
|
+
showSearch && /* @__PURE__ */ jsxRuntime.jsx(
|
|
14770
|
+
"div",
|
|
14771
|
+
{
|
|
14772
|
+
className: "sticky top-0 z-[1] border-b border-solid px-[8px] pb-[4px] pt-[var(--cmp-chipFilter-listbox-list-paddingY)]",
|
|
14773
|
+
style: { background: CHIPFILTER.listboxBg, borderColor: CHIPFILTER.listboxBorder },
|
|
14774
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-[6px] rounded-[4px] border border-solid border-[color:var(--sys-color-field-border-default)] bg-[var(--sys-color-field-bg-default)] px-[8px] py-[4px] focus-within:border-[color:var(--sys-color-field-border-focus)]", children: [
|
|
14775
|
+
/* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "search", size: 16, color: "var(--sys-color-field-icon-default)" }),
|
|
14776
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14777
|
+
"input",
|
|
14778
|
+
{
|
|
14779
|
+
value: search,
|
|
14780
|
+
disabled,
|
|
14781
|
+
placeholder: "\uAC80\uC0C9",
|
|
14782
|
+
onChange: (event) => setSearch(event.target.value),
|
|
14783
|
+
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"
|
|
14784
|
+
}
|
|
14785
|
+
),
|
|
14786
|
+
search !== "" && !disabled && /* @__PURE__ */ jsxRuntime.jsx(
|
|
14787
|
+
SGhostButton,
|
|
14788
|
+
{
|
|
14789
|
+
icon: "close",
|
|
14790
|
+
size: "xxs",
|
|
14791
|
+
ariaLabel: "\uAC80\uC0C9\uC5B4 \uC9C0\uC6B0\uAE30",
|
|
14792
|
+
className: "flex-shrink-0",
|
|
14793
|
+
onClick: () => setSearch("")
|
|
14794
|
+
}
|
|
14795
|
+
)
|
|
14796
|
+
] })
|
|
14797
|
+
}
|
|
14798
|
+
),
|
|
14799
|
+
showSearch && filteredOptions.length === 0 && /* @__PURE__ */ jsxRuntime.jsx(EmptyItem, { children: "\uAC80\uC0C9 \uACB0\uACFC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4." }),
|
|
14800
|
+
filteredOptions.map((option) => {
|
|
14801
|
+
const checked = multiple ? selected.includes(option.value) : singleValue === option.value;
|
|
14802
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14803
|
+
MenuItem,
|
|
14804
|
+
{
|
|
14805
|
+
selected: checked,
|
|
14806
|
+
disabled: disabled || option.disabled,
|
|
14807
|
+
multi: multiple,
|
|
14808
|
+
onClick: () => {
|
|
14809
|
+
if (multiple) {
|
|
14810
|
+
const next = checked ? selected.filter((v) => v !== option.value) : [...selected, option.value];
|
|
14811
|
+
onValueChange(next);
|
|
14812
|
+
} else {
|
|
14813
|
+
onValueChange(option.value);
|
|
14814
|
+
}
|
|
14815
|
+
},
|
|
14816
|
+
children: [
|
|
14817
|
+
multiple && /* @__PURE__ */ jsxRuntime.jsx(OptionCheckbox, { checked }),
|
|
14818
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate", children: option.label })
|
|
14819
|
+
]
|
|
14820
|
+
},
|
|
14821
|
+
String(option.value)
|
|
14822
|
+
);
|
|
14823
|
+
})
|
|
14824
|
+
]
|
|
14825
|
+
}
|
|
14826
|
+
);
|
|
14827
|
+
}
|
|
14828
|
+
function OptionCheckbox({ checked }) {
|
|
14829
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
14830
|
+
"span",
|
|
14831
|
+
{
|
|
14832
|
+
className: cn(
|
|
14833
|
+
"inline-flex size-[16px] shrink-0 items-center justify-center rounded-[2px] border border-solid",
|
|
14834
|
+
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)]"
|
|
14835
|
+
),
|
|
14836
|
+
children: checked && /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "checkboxCheck", size: 12, color: "var(--cmp-checkbox-checked-icon-default)" })
|
|
14837
|
+
}
|
|
14838
|
+
);
|
|
14839
|
+
}
|
|
14840
|
+
function ListBox({ children }) {
|
|
14841
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
14842
|
+
"div",
|
|
14843
|
+
{
|
|
14844
|
+
className: "overflow-hidden border border-solid shadow-[var(--shadow-overlay)]",
|
|
14845
|
+
style: {
|
|
14846
|
+
borderRadius: CHIPFILTER.listboxRadius,
|
|
14847
|
+
background: CHIPFILTER.listboxBg,
|
|
14848
|
+
borderColor: CHIPFILTER.listboxBorder
|
|
14849
|
+
},
|
|
14850
|
+
children
|
|
14851
|
+
}
|
|
14852
|
+
);
|
|
14853
|
+
}
|
|
14854
|
+
function MenuItem({
|
|
14855
|
+
children,
|
|
14856
|
+
selected,
|
|
14857
|
+
disabled,
|
|
14858
|
+
multi,
|
|
14859
|
+
onMouseEnter,
|
|
14860
|
+
onClick
|
|
14861
|
+
}) {
|
|
14862
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
14863
|
+
"button",
|
|
14864
|
+
{
|
|
14865
|
+
type: "button",
|
|
14866
|
+
disabled,
|
|
14867
|
+
onMouseEnter,
|
|
14868
|
+
onClick,
|
|
14869
|
+
className: cn(
|
|
14870
|
+
"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",
|
|
14871
|
+
selected ? "font-bold" : "font-normal",
|
|
14872
|
+
!disabled && "hover:font-bold"
|
|
14873
|
+
),
|
|
14874
|
+
style: {
|
|
14875
|
+
paddingTop: CHIPFILTER.itemPaddingY,
|
|
14876
|
+
paddingBottom: CHIPFILTER.itemPaddingY,
|
|
14877
|
+
paddingLeft: multi ? CHIPFILTER.itemMultiPaddingX : CHIPFILTER.itemPaddingLeft,
|
|
14878
|
+
paddingRight: multi ? CHIPFILTER.itemMultiPaddingX : CHIPFILTER.itemPaddingRight,
|
|
14879
|
+
color: disabled ? CHIPFILTER.chipDisabledText : selected ? CHIPFILTER.itemTextSelected : CHIPFILTER.itemTextDefault
|
|
14880
|
+
},
|
|
14881
|
+
children
|
|
14882
|
+
}
|
|
14883
|
+
);
|
|
14884
|
+
}
|
|
14885
|
+
function EmptyItem({ children }) {
|
|
14886
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
14887
|
+
"div",
|
|
14888
|
+
{
|
|
14889
|
+
className: "text-[12px] leading-[20px]",
|
|
14890
|
+
style: {
|
|
14891
|
+
paddingTop: CHIPFILTER.itemPaddingY,
|
|
14892
|
+
paddingBottom: CHIPFILTER.itemPaddingY,
|
|
14893
|
+
paddingLeft: CHIPFILTER.itemPaddingLeft,
|
|
14894
|
+
paddingRight: CHIPFILTER.itemPaddingRight,
|
|
14895
|
+
color: CHIPFILTER.chipDisabledText
|
|
14896
|
+
},
|
|
14897
|
+
children
|
|
14898
|
+
}
|
|
14899
|
+
);
|
|
14900
|
+
}
|
|
14901
|
+
var SChipInput = /* @__PURE__ */ react.forwardRef(function SChipInput2({
|
|
14902
|
+
values = [],
|
|
14903
|
+
onValueChange,
|
|
14904
|
+
onInput,
|
|
14905
|
+
onFocus,
|
|
14906
|
+
onBlur,
|
|
14907
|
+
errors = [],
|
|
14908
|
+
disabledChips = [],
|
|
14909
|
+
size = "sm",
|
|
14910
|
+
disabled = false,
|
|
14911
|
+
placeholder = "\uD0DC\uADF8 \uC785\uB825 (Enter\uB85C \uB4F1\uB85D / \uCF64\uB9C8\uB85C \uAD6C\uBD84 / \uB744\uC5B4\uC4F0\uAE30 \uBD88\uAC00)",
|
|
14912
|
+
name,
|
|
14913
|
+
rules,
|
|
14914
|
+
error,
|
|
14915
|
+
useReset = false,
|
|
14916
|
+
maxCount,
|
|
14917
|
+
metaPlacement = "end",
|
|
14918
|
+
duplicateLabel,
|
|
14919
|
+
suggestions = [],
|
|
14920
|
+
loadingSuggestions = false,
|
|
14921
|
+
recommendedItems = [],
|
|
14922
|
+
loadingRecommendedItems = false,
|
|
14923
|
+
dropdownMinWidth = 200,
|
|
14924
|
+
label,
|
|
14925
|
+
labelWidth,
|
|
14926
|
+
hint,
|
|
14927
|
+
errorMessage,
|
|
14928
|
+
width,
|
|
14929
|
+
status,
|
|
14930
|
+
icon,
|
|
14931
|
+
iconColor,
|
|
14932
|
+
labelTooltip,
|
|
14933
|
+
labelTooltipProps,
|
|
14934
|
+
className,
|
|
14935
|
+
style
|
|
14936
|
+
}, ref) {
|
|
14937
|
+
const autoId = react.useId();
|
|
14938
|
+
const resolvedName = name ?? autoId;
|
|
14939
|
+
const [inputValue, setInputValue] = react.useState("");
|
|
14940
|
+
const [focused, setFocused] = react.useState(false);
|
|
14941
|
+
const [hovered, setHovered] = react.useState(false);
|
|
14942
|
+
const [activeIndex, setActiveIndex] = react.useState(-1);
|
|
14943
|
+
const [suppressSuggestions, setSuppressSuggestions] = react.useState(false);
|
|
14944
|
+
const [suppressRecommendations, setSuppressRecommendations] = react.useState(false);
|
|
14945
|
+
const inputRef = react.useRef(null);
|
|
14946
|
+
const containerRef = react.useRef(null);
|
|
14947
|
+
const inputShellRef = react.useRef(null);
|
|
13438
14948
|
const isComposingRef = react.useRef(false);
|
|
13439
14949
|
react.useImperativeHandle(ref, () => ({ focus: () => inputRef.current?.focus() }), []);
|
|
13440
14950
|
const chipError = (i) => {
|
|
@@ -14111,7 +15621,7 @@ function TimeSelector({
|
|
|
14111
15621
|
const renderColumn = (type) => {
|
|
14112
15622
|
const isHour = type === "hour";
|
|
14113
15623
|
const val = isHour ? displayHour : minute;
|
|
14114
|
-
const
|
|
15624
|
+
const displayValue2 = editingPart === type ? inputDraft[type] ?? "" : String(val).padStart(2, "0");
|
|
14115
15625
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14116
15626
|
"div",
|
|
14117
15627
|
{
|
|
@@ -14132,7 +15642,7 @@ function TimeSelector({
|
|
|
14132
15642
|
{
|
|
14133
15643
|
"aria-label": isHour ? "\uC2DC" : "\uBD84",
|
|
14134
15644
|
inputMode: "numeric",
|
|
14135
|
-
value:
|
|
15645
|
+
value: displayValue2,
|
|
14136
15646
|
placeholder: "-",
|
|
14137
15647
|
onFocus: () => beginEdit(type, val),
|
|
14138
15648
|
onBlur: () => endEdit(type),
|
|
@@ -14327,8 +15837,8 @@ function STimePicker({
|
|
|
14327
15837
|
disabled,
|
|
14328
15838
|
className,
|
|
14329
15839
|
style,
|
|
14330
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14331
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
15840
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(RPopover9__namespace.Root, { open, onOpenChange: commitOpen, children: [
|
|
15841
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14332
15842
|
"div",
|
|
14333
15843
|
{
|
|
14334
15844
|
ref: triggerRef,
|
|
@@ -14388,14 +15898,17 @@ function STimePicker({
|
|
|
14388
15898
|
]
|
|
14389
15899
|
}
|
|
14390
15900
|
) }),
|
|
14391
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14392
|
-
|
|
15901
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
15902
|
+
RPopover9__namespace.Content,
|
|
14393
15903
|
{
|
|
14394
15904
|
side: "bottom",
|
|
14395
15905
|
align: "start",
|
|
14396
15906
|
sideOffset: 4,
|
|
14397
15907
|
alignOffset: popoverAlignOffset,
|
|
14398
|
-
className: cn(
|
|
15908
|
+
className: cn(
|
|
15909
|
+
"z-50 max-w-[var(--radix-popover-content-available-width)]",
|
|
15910
|
+
FLOATING_SLIDE_ANIM
|
|
15911
|
+
),
|
|
14399
15912
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14400
15913
|
TimeSelector,
|
|
14401
15914
|
{
|
|
@@ -14554,7 +16067,7 @@ function RangeTimeSelector({
|
|
|
14554
16067
|
const { minute } = getParts(side);
|
|
14555
16068
|
const val = isHour ? getDisplayHour(side) : minute;
|
|
14556
16069
|
const currentEditingKey = getEditingKey(side, kind);
|
|
14557
|
-
const
|
|
16070
|
+
const displayValue2 = editingKey === currentEditingKey ? inputDraft[currentEditingKey] ?? "" : String(val).padStart(2, "0");
|
|
14558
16071
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14559
16072
|
"div",
|
|
14560
16073
|
{
|
|
@@ -14575,7 +16088,7 @@ function RangeTimeSelector({
|
|
|
14575
16088
|
{
|
|
14576
16089
|
"aria-label": `${side === "start" ? "\uC2DC\uC791" : "\uC885\uB8CC"} ${isHour ? "\uC2DC" : "\uBD84"}`,
|
|
14577
16090
|
inputMode: "numeric",
|
|
14578
|
-
value:
|
|
16091
|
+
value: displayValue2,
|
|
14579
16092
|
placeholder: "-",
|
|
14580
16093
|
onFocus: () => beginEdit(side, kind, val),
|
|
14581
16094
|
onBlur: () => endEdit(side, kind),
|
|
@@ -14786,8 +16299,8 @@ function STimeRangePicker({
|
|
|
14786
16299
|
disabled,
|
|
14787
16300
|
className,
|
|
14788
16301
|
style,
|
|
14789
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14790
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
16302
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(RPopover9__namespace.Root, { open, onOpenChange: commitOpen, children: [
|
|
16303
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14791
16304
|
"div",
|
|
14792
16305
|
{
|
|
14793
16306
|
ref: triggerRef,
|
|
@@ -14847,14 +16360,17 @@ function STimeRangePicker({
|
|
|
14847
16360
|
]
|
|
14848
16361
|
}
|
|
14849
16362
|
) }),
|
|
14850
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14851
|
-
|
|
16363
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
16364
|
+
RPopover9__namespace.Content,
|
|
14852
16365
|
{
|
|
14853
16366
|
side: "bottom",
|
|
14854
16367
|
align: "start",
|
|
14855
16368
|
sideOffset: 4,
|
|
14856
16369
|
alignOffset: popoverAlignOffset,
|
|
14857
|
-
className: cn(
|
|
16370
|
+
className: cn(
|
|
16371
|
+
"z-50 max-w-[var(--radix-popover-content-available-width)]",
|
|
16372
|
+
FLOATING_SLIDE_ANIM
|
|
16373
|
+
),
|
|
14858
16374
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14859
16375
|
RangeTimeSelector,
|
|
14860
16376
|
{
|
|
@@ -14887,6 +16403,7 @@ exports.GNB_RAIL = GNB_RAIL;
|
|
|
14887
16403
|
exports.GNB_RAIL_WIDTH = GNB_RAIL_WIDTH;
|
|
14888
16404
|
exports.ICONS = ICONS;
|
|
14889
16405
|
exports.PAGE_BACKGROUNDS = PAGE_BACKGROUNDS;
|
|
16406
|
+
exports.RangeCalendar = RangeCalendar;
|
|
14890
16407
|
exports.SActionModal = SActionModal;
|
|
14891
16408
|
exports.SBadge = SBadge;
|
|
14892
16409
|
exports.SBarcodeInput = SBarcodeInput;
|
|
@@ -14897,6 +16414,7 @@ exports.SCallout = SCallout;
|
|
|
14897
16414
|
exports.SCard = SCard;
|
|
14898
16415
|
exports.SCheckbox = SCheckbox;
|
|
14899
16416
|
exports.SChip = SChip2;
|
|
16417
|
+
exports.SChipFilter = SChipFilter;
|
|
14900
16418
|
exports.SChipInput = SChipInput;
|
|
14901
16419
|
exports.SCircleProgress = SCircleProgress;
|
|
14902
16420
|
exports.SConfirmModal = SConfirmModal;
|