sellmate-design-system-react 8.1.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 +156 -109
- 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/SGhostButton/README.md +4 -0
- package/dist/components/SGuide/README.md +1 -1
- package/dist/components/SGuide/SGuide.d.ts +1 -1
- package/dist/components/SIcon/README.md +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 +2 -2
- package/dist/components/SListItem/SListItem.d.ts +2 -2
- package/dist/components/SPage/README.md +21 -0
- package/dist/components/SPage/SPage.d.ts +10 -0
- package/dist/components/SPage/SPageHeader.d.ts +32 -0
- package/dist/components/SPage/index.d.ts +1 -0
- package/dist/components/SPortal/README.md +1 -1
- package/dist/components/SPortal/SPortal.d.ts +7 -1
- package/dist/components/SRadio/README.md +2 -0
- package/dist/components/SRadioButton/README.md +13 -0
- package/dist/components/SSelect/README.md +2 -2
- package/dist/components/SSelect/SSelect.d.ts +2 -2
- package/dist/components/STag/README.md +2 -0
- package/dist/components/STextLink/README.md +2 -0
- package/dist/components/STooltip/README.md +2 -0
- package/dist/index.cjs +1632 -223
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1644 -237
- package/dist/index.js.map +1 -1
- package/dist/lib/floating-width.d.ts +22 -0
- package/dist/llms-full.txt +277 -115
- package/dist/llms.txt +158 -111
- package/dist/styles.css +197 -5
- package/package.json +7 -4
package/dist/index.cjs
CHANGED
|
@@ -7,7 +7,7 @@ var react = require('react');
|
|
|
7
7
|
var jsxRuntime = require('react/jsx-runtime');
|
|
8
8
|
var reactDom = require('react-dom');
|
|
9
9
|
var RCheckbox = require('@radix-ui/react-checkbox');
|
|
10
|
-
var
|
|
10
|
+
var RPopover9 = require('@radix-ui/react-popover');
|
|
11
11
|
var client = require('react-dom/client');
|
|
12
12
|
var RTooltip = require('@radix-ui/react-tooltip');
|
|
13
13
|
var RDropdown = require('@radix-ui/react-dropdown-menu');
|
|
@@ -34,7 +34,7 @@ function _interopNamespace(e) {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
var RCheckbox__namespace = /*#__PURE__*/_interopNamespace(RCheckbox);
|
|
37
|
-
var
|
|
37
|
+
var RPopover9__namespace = /*#__PURE__*/_interopNamespace(RPopover9);
|
|
38
38
|
var RTooltip__namespace = /*#__PURE__*/_interopNamespace(RTooltip);
|
|
39
39
|
var RDropdown__namespace = /*#__PURE__*/_interopNamespace(RDropdown);
|
|
40
40
|
var RSwitch__namespace = /*#__PURE__*/_interopNamespace(RSwitch);
|
|
@@ -2593,6 +2593,27 @@ var Icon_sidebar = (p) => {
|
|
|
2593
2593
|
}
|
|
2594
2594
|
);
|
|
2595
2595
|
};
|
|
2596
|
+
var Icon_star = (p) => {
|
|
2597
|
+
const { size = 24, ...rest } = p;
|
|
2598
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2599
|
+
"svg",
|
|
2600
|
+
{
|
|
2601
|
+
width: size,
|
|
2602
|
+
height: size,
|
|
2603
|
+
viewBox: "0 0 24 24",
|
|
2604
|
+
fill: "none",
|
|
2605
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2606
|
+
...rest,
|
|
2607
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2608
|
+
"path",
|
|
2609
|
+
{
|
|
2610
|
+
d: "M12.3358 3.45335C12.0755 2.84888 11.2185 2.84888 10.9582 3.45335L8.78136 8.50811C8.67278 8.76024 8.43512 8.93291 8.16178 8.95826L2.68175 9.46652C2.02642 9.5273 1.76157 10.3424 2.25602 10.7768L6.39071 14.409C6.59695 14.5902 6.68773 14.8696 6.62737 15.1374L5.41733 20.5063C5.27263 21.1483 5.966 21.6521 6.5319 21.3161L11.2641 18.5062C11.5001 18.366 11.7939 18.366 12.0299 18.5062L16.7621 21.3161C17.328 21.6521 18.0214 21.1483 17.8767 20.5063L16.6666 15.1374C16.6063 14.8696 16.6971 14.5902 16.9033 14.409L21.038 10.7768C21.5324 10.3424 21.2676 9.5273 20.6123 9.46652L15.1322 8.95826C14.8589 8.93291 14.6212 8.76024 14.5126 8.50811L12.3358 3.45335Z",
|
|
2611
|
+
fill: "currentColor"
|
|
2612
|
+
}
|
|
2613
|
+
)
|
|
2614
|
+
}
|
|
2615
|
+
);
|
|
2616
|
+
};
|
|
2596
2617
|
var Icon_store = (p) => {
|
|
2597
2618
|
const { size = 24, ...rest } = p;
|
|
2598
2619
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -3087,6 +3108,7 @@ var ICONS = {
|
|
|
3087
3108
|
settingOutline: Icon_settingOutline,
|
|
3088
3109
|
shield: Icon_shield,
|
|
3089
3110
|
sidebar: Icon_sidebar,
|
|
3111
|
+
star: Icon_star,
|
|
3090
3112
|
store: Icon_store,
|
|
3091
3113
|
synchronize: Icon_synchronize,
|
|
3092
3114
|
thumbsDown: Icon_thumbsDown,
|
|
@@ -3220,12 +3242,13 @@ var SDraggableItemView = /* @__PURE__ */ react.forwardRef(
|
|
|
3220
3242
|
!disabled && !selected && !dragging && "hover:bg-(--cmp-listDraggableItem-bg-hover)",
|
|
3221
3243
|
hasSupportingText && supportingTextPosition === "bottom" ? dense ? "min-h-[52px]" : "min-h-[60px]" : dense ? "h-[32px]" : "h-[40px]",
|
|
3222
3244
|
paddingYClass,
|
|
3223
|
-
|
|
3245
|
+
// 항목 사이 구분선은 리스트가 그린다 — SDraggableList 의 separator (SList.tsx)
|
|
3246
|
+
bordered && cn(
|
|
3224
3247
|
"rounded-(--cmp-listDraggableItem-radius-bordered) border border-(--cmp-listDraggableItem-border-default)",
|
|
3225
3248
|
!disabled && !selected && !dragging && "hover:border-(--cmp-listDraggableItem-bordered-border-hover)",
|
|
3226
3249
|
!disabled && selected && !dragging && "border-(--cmp-listDraggableItem-bordered-border-selected) bg-(--cmp-listDraggableItem-bordered-bg-selected)",
|
|
3227
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)"
|
|
3228
|
-
)
|
|
3251
|
+
),
|
|
3229
3252
|
disabled && "cursor-not-allowed",
|
|
3230
3253
|
className
|
|
3231
3254
|
),
|
|
@@ -3427,7 +3450,7 @@ var SDraggableItemImpl = /* @__PURE__ */ react.forwardRef(function SDraggableIte
|
|
|
3427
3450
|
] });
|
|
3428
3451
|
});
|
|
3429
3452
|
var SDraggableItem2 = /* @__PURE__ */ withDisplayName(SDraggableItemImpl, "SDraggableItem");
|
|
3430
|
-
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) {
|
|
3431
3454
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3432
3455
|
"div",
|
|
3433
3456
|
{
|
|
@@ -3435,6 +3458,7 @@ var SListImpl = /* @__PURE__ */ react.forwardRef(function SList({ className, chi
|
|
|
3435
3458
|
className: cn(
|
|
3436
3459
|
useGap && "flex flex-col gap-(--cmp-list-group-gap)",
|
|
3437
3460
|
usePadding && "p-(--cmp-list-group-padding)",
|
|
3461
|
+
separator && "[&>*]:border-b [&>*]:border-(--cmp-listItem-border-default)",
|
|
3438
3462
|
className
|
|
3439
3463
|
),
|
|
3440
3464
|
...rest,
|
|
@@ -3806,7 +3830,7 @@ var SExpansionItem = /* @__PURE__ */ react.forwardRef(
|
|
|
3806
3830
|
ref,
|
|
3807
3831
|
className: cn(
|
|
3808
3832
|
"group/expansion-item relative overflow-hidden bg-(--cmp-listExpansionItem-title-bg-default)",
|
|
3809
|
-
|
|
3833
|
+
// 항목 사이 구분선은 리스트가 그린다 — SList/SExpansionList 의 separator (SList.tsx)
|
|
3810
3834
|
// 보더 색은 시맨틱 토큰(border-default → hover strong → 펼침 accentLight)을 쓴다.
|
|
3811
3835
|
// TODO: expansionItem/bordered/radius 토큰 생성 후 rounded 고정값도 토큰으로 교체한다.
|
|
3812
3836
|
bordered && "rounded-[8px] border border-border-default hover:border-border-strong [&:has(>button:hover)]:border-border-strong",
|
|
@@ -3916,7 +3940,7 @@ var SListItemImpl = /* @__PURE__ */ react.forwardRef(function SListItem({
|
|
|
3916
3940
|
trailing,
|
|
3917
3941
|
bordered = false,
|
|
3918
3942
|
selected = false,
|
|
3919
|
-
clickable =
|
|
3943
|
+
clickable = false,
|
|
3920
3944
|
interaction,
|
|
3921
3945
|
accentStripe = false,
|
|
3922
3946
|
dense = false,
|
|
@@ -3969,10 +3993,10 @@ var SListItemImpl = /* @__PURE__ */ react.forwardRef(function SListItem({
|
|
|
3969
3993
|
"gap-(--cmp-listItem-gap)",
|
|
3970
3994
|
"pr-(--cmp-listItem-paddingX)",
|
|
3971
3995
|
depth === 2 ? "pl-[36px]" : depth === 3 ? "pl-[56px]" : "pl-[16px]",
|
|
3972
|
-
bordered
|
|
3996
|
+
bordered && cn(
|
|
3973
3997
|
"overflow-hidden rounded-(--cmp-listItem-radius-bordered) border border-(--cmp-listItem-border-default)",
|
|
3974
3998
|
isSelected ? "border-(--cmp-listItem-bordered-border-selected)" : isInteractive && "hover:border-(--cmp-listItem-bordered-border-hover)"
|
|
3975
|
-
)
|
|
3999
|
+
),
|
|
3976
4000
|
className
|
|
3977
4001
|
),
|
|
3978
4002
|
...rest,
|
|
@@ -4051,6 +4075,8 @@ var SExpansionListImpl = /* @__PURE__ */ react.forwardRef(function SExpansionLis
|
|
|
4051
4075
|
const depth2 = child.props.depth ?? 1;
|
|
4052
4076
|
const itemKey2 = String(child.key ?? index);
|
|
4053
4077
|
return react.cloneElement(child, {
|
|
4078
|
+
// 선택을 리스트가 관리하는 이상 아이템은 클릭 가능해야 한다 — SListItem 의 기본값(false)을 뒤집는다
|
|
4079
|
+
clickable: child.props.clickable ?? true,
|
|
4054
4080
|
selected: selectedKeys[depth2] === itemKey2,
|
|
4055
4081
|
onClick: (event) => {
|
|
4056
4082
|
setSelectedKeys((current) => ({ ...current, [depth2]: itemKey2 }));
|
|
@@ -4356,8 +4382,8 @@ function SGhostButton({
|
|
|
4356
4382
|
}
|
|
4357
4383
|
);
|
|
4358
4384
|
if (!hasTooltip) return btn;
|
|
4359
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4360
|
-
/* @__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(
|
|
4361
4387
|
"span",
|
|
4362
4388
|
{
|
|
4363
4389
|
className: cn("inline-flex", anchorClassName),
|
|
@@ -4369,8 +4395,8 @@ function SGhostButton({
|
|
|
4369
4395
|
children: btn
|
|
4370
4396
|
}
|
|
4371
4397
|
) }),
|
|
4372
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4373
|
-
|
|
4398
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4399
|
+
RPopover9__namespace.Content,
|
|
4374
4400
|
{
|
|
4375
4401
|
side: "top",
|
|
4376
4402
|
sideOffset: 4,
|
|
@@ -4841,7 +4867,7 @@ var STooltipImpl = /* @__PURE__ */ react.forwardRef(function STooltip({
|
|
|
4841
4867
|
...restContentProps
|
|
4842
4868
|
} = contentProps ?? {};
|
|
4843
4869
|
const contentClass = cn(
|
|
4844
|
-
"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",
|
|
4845
4871
|
FLOATING_SLIDE_ANIM,
|
|
4846
4872
|
className,
|
|
4847
4873
|
contentPropsClassName
|
|
@@ -4853,14 +4879,14 @@ var STooltipImpl = /* @__PURE__ */ react.forwardRef(function STooltip({
|
|
|
4853
4879
|
...style,
|
|
4854
4880
|
...contentPropsStyle
|
|
4855
4881
|
};
|
|
4856
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4882
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(RPopover9__namespace.Root, { open, onOpenChange: setOpenState, children: [
|
|
4857
4883
|
isNone ? (
|
|
4858
4884
|
// 트리거 없음: children 을 래퍼 없이 그대로 앵커로 쓴다 (소비자 레이아웃 보존).
|
|
4859
4885
|
// mouse/focus 핸들러가 없으므로 useClose 없이도 자동 닫힘이 발생하지 않는다.
|
|
4860
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4886
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Anchor, { asChild: true, children: triggerNode })
|
|
4861
4887
|
) : isHover ? (
|
|
4862
4888
|
// hover: Anchor(위치 기준) + 직접 mouse 핸들러 — 클릭으로 토글되지 않도록 Trigger 미사용
|
|
4863
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4889
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Anchor, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4864
4890
|
"span",
|
|
4865
4891
|
{
|
|
4866
4892
|
className: "inline-flex",
|
|
@@ -4871,9 +4897,9 @@ var STooltipImpl = /* @__PURE__ */ react.forwardRef(function STooltip({
|
|
|
4871
4897
|
children: triggerNode
|
|
4872
4898
|
}
|
|
4873
4899
|
) })
|
|
4874
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
4875
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4876
|
-
|
|
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,
|
|
4877
4903
|
{
|
|
4878
4904
|
side: placement,
|
|
4879
4905
|
sideOffset,
|
|
@@ -4907,7 +4933,7 @@ var STooltipImpl = /* @__PURE__ */ react.forwardRef(function STooltip({
|
|
|
4907
4933
|
}
|
|
4908
4934
|
)
|
|
4909
4935
|
] }),
|
|
4910
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4936
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Arrow, { width: 16, height: 12, style: { fill: bg } })
|
|
4911
4937
|
]
|
|
4912
4938
|
}
|
|
4913
4939
|
) })
|
|
@@ -5915,6 +5941,15 @@ var STextLink = /* @__PURE__ */ react.forwardRef(function STextLink2({
|
|
|
5915
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 }) }) })
|
|
5916
5942
|
] }) });
|
|
5917
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
|
+
}
|
|
5918
5953
|
var SIZE2 = {
|
|
5919
5954
|
xs: { height: 24, paddingX: 8, gap: 6, arrow: 12, fontSize: 12, minWidth: 64, splitMinWidth: 72 },
|
|
5920
5955
|
sm: {
|
|
@@ -5951,6 +5986,7 @@ function splitDivider(color, outline) {
|
|
|
5951
5986
|
};
|
|
5952
5987
|
return (outline ? outlined : solid)[color];
|
|
5953
5988
|
}
|
|
5989
|
+
var VIEWPORT_PADDING = 12;
|
|
5954
5990
|
var itemClass = cn(
|
|
5955
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",
|
|
5956
5992
|
"text-[color:var(--sys-color-fg-secondary)]",
|
|
@@ -6032,12 +6068,16 @@ var SDropdownButtonImpl = /* @__PURE__ */ react.forwardRef(
|
|
|
6032
6068
|
sideOffset: 4,
|
|
6033
6069
|
align: "start",
|
|
6034
6070
|
alignOffset: split ? splitAlignOffset : 0,
|
|
6071
|
+
collisionPadding: VIEWPORT_PADDING,
|
|
6035
6072
|
className: cn(
|
|
6036
6073
|
"z-50 overflow-hidden rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] shadow-normal-sm",
|
|
6037
|
-
|
|
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))]",
|
|
6038
6078
|
FLOATING_SLIDE_ANIM
|
|
6039
6079
|
),
|
|
6040
|
-
style: split ? { minWidth: splitWidth } : void 0,
|
|
6080
|
+
style: split ? { minWidth: clampToAvailableWidth(splitWidth, DROPDOWN_AVAILABLE_WIDTH) } : void 0,
|
|
6041
6081
|
children: items.map((it) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6042
6082
|
RDropdown__namespace.Item,
|
|
6043
6083
|
{
|
|
@@ -6049,7 +6089,7 @@ var SDropdownButtonImpl = /* @__PURE__ */ react.forwardRef(
|
|
|
6049
6089
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6050
6090
|
"span",
|
|
6051
6091
|
{
|
|
6052
|
-
className: "min-w-0
|
|
6092
|
+
className: "min-w-0 break-words",
|
|
6053
6093
|
dangerouslySetInnerHTML: { __html: sanitizeInlineHtml(it.label) }
|
|
6054
6094
|
}
|
|
6055
6095
|
)
|
|
@@ -6261,16 +6301,20 @@ function SPopover({
|
|
|
6261
6301
|
const descColor = type === "default" ? "var(--cmp-popover-default-description)" : "var(--cmp-popover-light-description)";
|
|
6262
6302
|
const leftLinkLabelClass = type === "default" ? "text-[color:var(--cmp-popover-default-subAction)]" : "text-[color:var(--cmp-popover-light-subAction)]";
|
|
6263
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 }) });
|
|
6264
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6265
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6266
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6267
|
-
|
|
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,
|
|
6268
6308
|
{
|
|
6269
6309
|
side: placement,
|
|
6270
6310
|
sideOffset: 8,
|
|
6271
6311
|
className: cn(
|
|
6272
6312
|
// 닫기 버튼이 항상 있으므로 우측은 close clearance(36px) 로 고정
|
|
6273
|
-
"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))]",
|
|
6274
6318
|
FLOATING_SLIDE_ANIM,
|
|
6275
6319
|
menuClassName
|
|
6276
6320
|
),
|
|
@@ -6326,7 +6370,7 @@ function SPopover({
|
|
|
6326
6370
|
]
|
|
6327
6371
|
}
|
|
6328
6372
|
),
|
|
6329
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6373
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Arrow, { width: 16, height: 12, style: { fill: bg } })
|
|
6330
6374
|
]
|
|
6331
6375
|
}
|
|
6332
6376
|
) })
|
|
@@ -6355,8 +6399,9 @@ function SPortal({
|
|
|
6355
6399
|
ariaLabel
|
|
6356
6400
|
}) {
|
|
6357
6401
|
const portalContainer = usePortalContainer();
|
|
6402
|
+
const { minWidth: styleMinWidth, maxWidth: styleMaxWidth, ...restStyle } = style ?? {};
|
|
6358
6403
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6359
|
-
|
|
6404
|
+
RPopover9__namespace.Root,
|
|
6360
6405
|
{
|
|
6361
6406
|
open,
|
|
6362
6407
|
onOpenChange: (next) => {
|
|
@@ -6364,9 +6409,9 @@ function SPortal({
|
|
|
6364
6409
|
if (!next) onClose?.();
|
|
6365
6410
|
},
|
|
6366
6411
|
children: [
|
|
6367
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6368
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6369
|
-
|
|
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,
|
|
6370
6415
|
{
|
|
6371
6416
|
side: placement,
|
|
6372
6417
|
align,
|
|
@@ -6393,11 +6438,18 @@ function SPortal({
|
|
|
6393
6438
|
className: cn(
|
|
6394
6439
|
"z-50 overflow-hidden rounded-(--cmp-listBox-radius) bg-(--cmp-listBox-bg) shadow-normal-sm",
|
|
6395
6440
|
maxHeight != null && "overflow-y-auto",
|
|
6396
|
-
|
|
6441
|
+
// 앵커가 창보다 넓을 수 있는 자리(가로 스크롤 안의 트리거 등)에서도 하한이 상한을
|
|
6442
|
+
// 이기지 않도록, 앵커 너비 역시 가용 폭으로 가둔다.
|
|
6443
|
+
fit && "min-w-[min(var(--radix-popover-trigger-width),var(--radix-popover-content-available-width))]",
|
|
6397
6444
|
FLOATING_SLIDE_ANIM,
|
|
6398
6445
|
className
|
|
6399
6446
|
),
|
|
6400
|
-
style: {
|
|
6447
|
+
style: {
|
|
6448
|
+
maxHeight,
|
|
6449
|
+
...restStyle,
|
|
6450
|
+
...styleMinWidth != null ? { minWidth: clampToAvailableWidth(styleMinWidth, POPOVER_AVAILABLE_WIDTH) } : {},
|
|
6451
|
+
maxWidth: clampToAvailableWidth(styleMaxWidth, POPOVER_AVAILABLE_WIDTH)
|
|
6452
|
+
},
|
|
6401
6453
|
children
|
|
6402
6454
|
}
|
|
6403
6455
|
) })
|
|
@@ -6557,16 +6609,18 @@ function SGuide({
|
|
|
6557
6609
|
);
|
|
6558
6610
|
if (isNotion)
|
|
6559
6611
|
return /* @__PURE__ */ jsxRuntime.jsx("span", { className, style, children: trigger });
|
|
6560
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6561
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6562
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6563
|
-
|
|
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,
|
|
6564
6616
|
{
|
|
6565
6617
|
side: "bottom",
|
|
6566
6618
|
align: "start",
|
|
6567
6619
|
sideOffset: 4,
|
|
6568
6620
|
className: cn(
|
|
6569
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)]",
|
|
6570
6624
|
FLOATING_SLIDE_ANIM
|
|
6571
6625
|
),
|
|
6572
6626
|
style: {
|
|
@@ -8639,10 +8693,10 @@ var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
|
|
|
8639
8693
|
}
|
|
8640
8694
|
),
|
|
8641
8695
|
header === "fix" && menuResizeHandle,
|
|
8642
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
8643
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8644
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8645
|
-
|
|
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,
|
|
8646
8700
|
{
|
|
8647
8701
|
side: "right",
|
|
8648
8702
|
sideOffset: 4,
|
|
@@ -8660,16 +8714,81 @@ var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
|
|
|
8660
8714
|
}
|
|
8661
8715
|
);
|
|
8662
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
|
+
);
|
|
8663
8768
|
var MIN_CONTENT_WIDTH = `calc(var(${SLAYOUT_MIN_WIDTH_VAR}, 0px) - 100cqw + 100%)`;
|
|
8664
8769
|
var BACKGROUND_CLASS = {
|
|
8665
8770
|
frame: `bg-[var(--sys-color-bg-frame)] ${SCROLLBAR_TRACK_BORDER_CLASS} ${SCROLLBAR_TRACK_BG_CLASS}`,
|
|
8666
8771
|
neutral: `bg-[var(--sys-color-bg-neutralLight)] ${SCROLLBAR_TRACK_BORDER_CLASS} ${SCROLLBAR_TRACK_BG_WHITE_CLASS}`,
|
|
8667
8772
|
screen: `bg-[var(--sys-color-bg-screen)] ${SCROLLBAR_TRACK_BORDER_CLASS} ${SCROLLBAR_TRACK_BG_CLASS}`
|
|
8668
8773
|
};
|
|
8669
|
-
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) {
|
|
8670
8784
|
const layout = react.useContext(SLayoutContext);
|
|
8671
8785
|
const gridStyle = layout?.header === "full" ? { gridArea: "page" } : void 0;
|
|
8672
|
-
|
|
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(
|
|
8673
8792
|
"main",
|
|
8674
8793
|
{
|
|
8675
8794
|
ref,
|
|
@@ -8680,11 +8799,29 @@ var SPage = /* @__PURE__ */ react.forwardRef(function SPage2({ background = "fra
|
|
|
8680
8799
|
BACKGROUND_CLASS[background],
|
|
8681
8800
|
className
|
|
8682
8801
|
),
|
|
8683
|
-
style: { ...gridStyle, ...style },
|
|
8802
|
+
style: header == null ? { ...gridStyle, ...style } : style,
|
|
8803
|
+
onScroll: handleScroll,
|
|
8684
8804
|
...rest,
|
|
8685
8805
|
children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { minWidth: MIN_CONTENT_WIDTH }, children })
|
|
8686
8806
|
}
|
|
8687
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
|
+
);
|
|
8688
8825
|
});
|
|
8689
8826
|
|
|
8690
8827
|
// src/components/SPage/page.config.ts
|
|
@@ -11058,7 +11195,7 @@ var SInput = /* @__PURE__ */ react.forwardRef(function SInput2({
|
|
|
11058
11195
|
lineHeight: `${f.lineHeight}px`
|
|
11059
11196
|
},
|
|
11060
11197
|
children: [
|
|
11061
|
-
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 }),
|
|
11062
11199
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11063
11200
|
"input",
|
|
11064
11201
|
{
|
|
@@ -11090,7 +11227,7 @@ var SInput = /* @__PURE__ */ react.forwardRef(function SInput2({
|
|
|
11090
11227
|
...rest
|
|
11091
11228
|
}
|
|
11092
11229
|
),
|
|
11093
|
-
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 }),
|
|
11094
11231
|
clearable && hasValue && !disabled && !readOnly && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11095
11232
|
SGhostButton,
|
|
11096
11233
|
{
|
|
@@ -11988,8 +12125,8 @@ function SDatePicker({
|
|
|
11988
12125
|
disabled,
|
|
11989
12126
|
className,
|
|
11990
12127
|
style,
|
|
11991
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11992
|
-
/* @__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(
|
|
11993
12130
|
"button",
|
|
11994
12131
|
{
|
|
11995
12132
|
type: "button",
|
|
@@ -12025,13 +12162,16 @@ function SDatePicker({
|
|
|
12025
12162
|
]
|
|
12026
12163
|
}
|
|
12027
12164
|
) }),
|
|
12028
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12029
|
-
|
|
12165
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12166
|
+
RPopover9__namespace.Content,
|
|
12030
12167
|
{
|
|
12031
12168
|
side: "bottom",
|
|
12032
12169
|
align: "start",
|
|
12033
12170
|
sideOffset: 4,
|
|
12034
|
-
className: cn(
|
|
12171
|
+
className: cn(
|
|
12172
|
+
"z-50 max-w-[var(--radix-popover-content-available-width)]",
|
|
12173
|
+
FLOATING_SLIDE_ANIM
|
|
12174
|
+
),
|
|
12035
12175
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12036
12176
|
SCalendar,
|
|
12037
12177
|
{
|
|
@@ -12179,78 +12319,81 @@ function RangeCalendar({
|
|
|
12179
12319
|
}
|
|
12180
12320
|
};
|
|
12181
12321
|
const GRID_COLS = "grid grid-cols-[repeat(7,var(--cmp-datepicker-calendar-day-width))]";
|
|
12182
|
-
const renderPanel = (gy, gm, isLeft) =>
|
|
12183
|
-
|
|
12184
|
-
|
|
12185
|
-
|
|
12186
|
-
|
|
12187
|
-
|
|
12188
|
-
|
|
12189
|
-
|
|
12190
|
-
|
|
12191
|
-
|
|
12192
|
-
|
|
12193
|
-
|
|
12194
|
-
|
|
12195
|
-
|
|
12196
|
-
|
|
12197
|
-
|
|
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
|
+
)
|
|
12198
12351
|
] }),
|
|
12199
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12200
|
-
|
|
12201
|
-
{
|
|
12202
|
-
icon: "chevronRight",
|
|
12203
|
-
size: "xxs",
|
|
12204
|
-
ariaLabel: "nextMonth",
|
|
12205
|
-
onClick: goNextMonth,
|
|
12206
|
-
className: cn(isLeft && "invisible pointer-events-none")
|
|
12207
|
-
}
|
|
12208
|
-
)
|
|
12209
|
-
] }),
|
|
12210
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: GRID_COLS, children: WEEK_LABELS.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
12211
|
-
"span",
|
|
12212
|
-
{
|
|
12213
|
-
className: "flex h-[20px] items-center justify-center text-[12px] font-normal text-[color:var(--cmp-datepicker-calendar-week-color)]",
|
|
12214
|
-
children: l
|
|
12215
|
-
},
|
|
12216
|
-
l
|
|
12217
|
-
)) }),
|
|
12218
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(GRID_COLS, "gap-y-[var(--cmp-datepicker-calendar-grid-rowGap)]"), children: monthCells(gy, gm).map((cell) => {
|
|
12219
|
-
const isEdge = cell.inCurrentMonth && (cell.date === rStart || complete && cell.date === rEnd);
|
|
12220
|
-
const between = cell.inCurrentMonth && inRange(cell.date);
|
|
12221
|
-
const disabled = cell.inCurrentMonth && isDisabled(cell.date);
|
|
12222
|
-
const isToday = cell.inCurrentMonth && today === cell.date;
|
|
12223
|
-
let cellBg;
|
|
12224
|
-
if (between) cellBg = RANGE_BG;
|
|
12225
|
-
else if (cell.inCurrentMonth && hasRange && cell.date === rStart)
|
|
12226
|
-
cellBg = `linear-gradient(to right, transparent 50%, ${RANGE_BG} 50%)`;
|
|
12227
|
-
else if (cell.inCurrentMonth && hasRange && cell.date === rEnd) cellBg = RANGE_BG;
|
|
12228
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
12229
|
-
"div",
|
|
12352
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: GRID_COLS, children: WEEK_LABELS.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
12353
|
+
"span",
|
|
12230
12354
|
{
|
|
12231
|
-
className: "flex h-[
|
|
12232
|
-
|
|
12233
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12234
|
-
"button",
|
|
12235
|
-
{
|
|
12236
|
-
type: "button",
|
|
12237
|
-
disabled: !cell.inCurrentMonth || disabled,
|
|
12238
|
-
onMouseEnter: () => setHover(cell.date),
|
|
12239
|
-
onClick: () => cell.inCurrentMonth && click(cell.date),
|
|
12240
|
-
className: cn(
|
|
12241
|
-
"relative z-[1] flex h-[var(--cmp-datepicker-calendar-day-circle-size)] w-[var(--cmp-datepicker-calendar-day-circle-size)] items-center justify-center rounded-[var(--cmp-datepicker-calendar-day-circle-radius)] border border-solid border-transparent bg-transparent text-[14px]",
|
|
12242
|
-
!cell.inCurrentMonth ? "invisible pointer-events-none" : disabled ? "cursor-not-allowed" : "cursor-pointer",
|
|
12243
|
-
isEdge ? "bg-[var(--cmp-datepicker-calendar-day-select-bg)] text-[color:var(--cmp-datepicker-calendar-day-select-text)]" : disabled ? "text-[color:var(--cmp-datepicker-calendar-day-disabled-text)]" : "text-[color:var(--cmp-datepicker-calendar-day-default-text)] hover:border-[color:var(--cmp-datepicker-calendar-day-hover-border)] hover:text-[color:var(--cmp-datepicker-calendar-day-hover-text)]",
|
|
12244
|
-
isToday && !disabled && "font-bold"
|
|
12245
|
-
),
|
|
12246
|
-
children: cell.inCurrentMonth ? cell.day : ""
|
|
12247
|
-
}
|
|
12248
|
-
)
|
|
12355
|
+
className: "flex h-[20px] items-center justify-center text-[12px] font-normal text-[color:var(--cmp-datepicker-calendar-week-color)]",
|
|
12356
|
+
children: l
|
|
12249
12357
|
},
|
|
12250
|
-
|
|
12251
|
-
)
|
|
12252
|
-
|
|
12253
|
-
|
|
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
|
+
);
|
|
12254
12397
|
const renderTimeSection = (which, date, suffix) => {
|
|
12255
12398
|
const active = !!date;
|
|
12256
12399
|
const [yy = "", mm = "", dd = ""] = date ? date.split("-") : [];
|
|
@@ -12318,8 +12461,11 @@ function RangeCalendar({
|
|
|
12318
12461
|
"div",
|
|
12319
12462
|
{
|
|
12320
12463
|
className: cn(
|
|
12321
|
-
"inline-flex flex-col gap-[var(--cmp-datepicker-calendar-gap)] rounded-[var(--cmp-datepicker-calendar-radius)] bg-[var(--cmp-datepicker-calendar-bg)] p-[var(--cmp-datepicker-calendar-paddingXY)] shadow-[2px_2px_12px_2px_rgba(0,0,0,0.2)] select-none",
|
|
12322
|
-
|
|
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]"
|
|
12323
12469
|
),
|
|
12324
12470
|
children: [
|
|
12325
12471
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex items-center justify-center", children: [
|
|
@@ -12338,11 +12484,20 @@ function RangeCalendar({
|
|
|
12338
12484
|
}
|
|
12339
12485
|
)
|
|
12340
12486
|
] }),
|
|
12341
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
12342
|
-
|
|
12343
|
-
|
|
12344
|
-
|
|
12345
|
-
|
|
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
|
+
),
|
|
12346
12501
|
useTimePicker && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
12347
12502
|
/* @__PURE__ */ jsxRuntime.jsx(SDivider, {}),
|
|
12348
12503
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-[var(--cmp-datepicker-calendar-time-gap)]", children: [
|
|
@@ -12401,7 +12556,25 @@ function SDateRangePicker({
|
|
|
12401
12556
|
});
|
|
12402
12557
|
const resolvedError = error || ruleError !== "";
|
|
12403
12558
|
const resolvedStatus = status ?? (rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0);
|
|
12404
|
-
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
|
+
};
|
|
12405
12578
|
const select = (r) => {
|
|
12406
12579
|
setPendingStart(null);
|
|
12407
12580
|
onValueChange?.(r);
|
|
@@ -12427,11 +12600,12 @@ function SDateRangePicker({
|
|
|
12427
12600
|
focused: open,
|
|
12428
12601
|
errorMessage: ruleError !== "" ? ruleError : errorMessage,
|
|
12429
12602
|
width,
|
|
12603
|
+
minWidth: dims.fieldMinW,
|
|
12430
12604
|
disabled,
|
|
12431
12605
|
className,
|
|
12432
12606
|
style,
|
|
12433
12607
|
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12434
|
-
|
|
12608
|
+
RPopover9__namespace.Root,
|
|
12435
12609
|
{
|
|
12436
12610
|
open,
|
|
12437
12611
|
onOpenChange: (o) => {
|
|
@@ -12440,7 +12614,7 @@ function SDateRangePicker({
|
|
|
12440
12614
|
if (!o) setPendingStart(null);
|
|
12441
12615
|
},
|
|
12442
12616
|
children: [
|
|
12443
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12617
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12444
12618
|
"button",
|
|
12445
12619
|
{
|
|
12446
12620
|
type: "button",
|
|
@@ -12481,13 +12655,16 @@ function SDateRangePicker({
|
|
|
12481
12655
|
]
|
|
12482
12656
|
}
|
|
12483
12657
|
) }),
|
|
12484
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12485
|
-
|
|
12658
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12659
|
+
RPopover9__namespace.Content,
|
|
12486
12660
|
{
|
|
12487
12661
|
side: "bottom",
|
|
12488
12662
|
align: "start",
|
|
12489
12663
|
sideOffset: 4,
|
|
12490
|
-
className: cn(
|
|
12664
|
+
className: cn(
|
|
12665
|
+
"z-50 max-w-[var(--radix-popover-content-available-width)]",
|
|
12666
|
+
FLOATING_SLIDE_ANIM
|
|
12667
|
+
),
|
|
12491
12668
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12492
12669
|
RangeCalendar,
|
|
12493
12670
|
{
|
|
@@ -13475,7 +13652,7 @@ function SRadioButton({
|
|
|
13475
13652
|
disabled: od,
|
|
13476
13653
|
onClick: () => !od && !selected && onValueChange?.(o.value),
|
|
13477
13654
|
className: cn(
|
|
13478
|
-
"relative box-border inline-flex items-center justify-center whitespace-nowrap border border-solid text-[12px] font-medium leading-[20px] transition-colors",
|
|
13655
|
+
"relative box-border grow inline-flex items-center justify-center whitespace-nowrap border border-solid text-[12px] font-medium leading-[20px] transition-colors",
|
|
13479
13656
|
i === 0 ? "rounded-l-[var(--cmp-radioButton-radius)]" : "-ml-px",
|
|
13480
13657
|
i === options.length - 1 ? "rounded-r-[var(--cmp-radioButton-radius)]" : "",
|
|
13481
13658
|
selected ? "z-10" : "",
|
|
@@ -13497,85 +13674,1309 @@ function SRadioButton({
|
|
|
13497
13674
|
}
|
|
13498
13675
|
);
|
|
13499
13676
|
}
|
|
13500
|
-
var
|
|
13501
|
-
|
|
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,
|
|
13502
13833
|
onValueChange,
|
|
13503
|
-
|
|
13504
|
-
|
|
13505
|
-
|
|
13506
|
-
|
|
13507
|
-
|
|
13508
|
-
|
|
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,
|
|
13509
13844
|
disabled = false,
|
|
13510
|
-
placeholder = "\uD0DC\uADF8 \uC785\uB825 (Enter\uB85C \uB4F1\uB85D / \uCF64\uB9C8\uB85C \uAD6C\uBD84 / \uB744\uC5B4\uC4F0\uAE30 \uBD88\uAC00)",
|
|
13511
|
-
name,
|
|
13512
|
-
rules,
|
|
13513
|
-
error,
|
|
13514
|
-
useReset = false,
|
|
13515
|
-
maxCount,
|
|
13516
|
-
metaPlacement = "end",
|
|
13517
|
-
duplicateLabel,
|
|
13518
|
-
suggestions = [],
|
|
13519
|
-
loadingSuggestions = false,
|
|
13520
|
-
recommendedItems = [],
|
|
13521
|
-
loadingRecommendedItems = false,
|
|
13522
|
-
dropdownMinWidth = 200,
|
|
13523
|
-
label,
|
|
13524
|
-
labelWidth,
|
|
13525
|
-
hint,
|
|
13526
|
-
errorMessage,
|
|
13527
|
-
width,
|
|
13528
|
-
status,
|
|
13529
|
-
icon,
|
|
13530
|
-
iconColor,
|
|
13531
|
-
labelTooltip,
|
|
13532
|
-
labelTooltipProps,
|
|
13533
13845
|
className,
|
|
13534
13846
|
style
|
|
13535
13847
|
}, ref) {
|
|
13536
|
-
const
|
|
13537
|
-
const
|
|
13538
|
-
|
|
13539
|
-
|
|
13540
|
-
|
|
13541
|
-
const
|
|
13542
|
-
const
|
|
13543
|
-
const
|
|
13544
|
-
const
|
|
13545
|
-
|
|
13546
|
-
|
|
13547
|
-
const
|
|
13548
|
-
|
|
13549
|
-
const
|
|
13550
|
-
|
|
13551
|
-
|
|
13552
|
-
|
|
13553
|
-
|
|
13554
|
-
const
|
|
13555
|
-
|
|
13556
|
-
|
|
13557
|
-
|
|
13558
|
-
|
|
13559
|
-
|
|
13560
|
-
|
|
13561
|
-
|
|
13562
|
-
|
|
13563
|
-
|
|
13564
|
-
|
|
13565
|
-
|
|
13566
|
-
|
|
13567
|
-
|
|
13568
|
-
|
|
13569
|
-
|
|
13570
|
-
|
|
13571
|
-
|
|
13572
|
-
|
|
13573
|
-
|
|
13574
|
-
|
|
13575
|
-
|
|
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);
|
|
13576
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));
|
|
13577
13926
|
});
|
|
13578
|
-
const
|
|
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);
|
|
14948
|
+
const isComposingRef = react.useRef(false);
|
|
14949
|
+
react.useImperativeHandle(ref, () => ({ focus: () => inputRef.current?.focus() }), []);
|
|
14950
|
+
const chipError = (i) => {
|
|
14951
|
+
if (values.indexOf(values[i]) !== i) return true;
|
|
14952
|
+
if (typeof errors === "function") return errors(values[i] ?? "");
|
|
14953
|
+
return errors[i] ?? false;
|
|
14954
|
+
};
|
|
14955
|
+
const chipDisabled = (i) => {
|
|
14956
|
+
if (disabled) return true;
|
|
14957
|
+
if (typeof disabledChips === "function") return disabledChips(values[i] ?? "");
|
|
14958
|
+
return disabledChips[i] ?? false;
|
|
14959
|
+
};
|
|
14960
|
+
const duplicateMessage = react.useMemo(() => {
|
|
14961
|
+
const seen = /* @__PURE__ */ new Set();
|
|
14962
|
+
for (const v of values) {
|
|
14963
|
+
if (seen.has(v))
|
|
14964
|
+
return duplicateLabel ? `\uC774\uBBF8 \uC785\uB825\uB41C ${duplicateLabel}\uC785\uB2C8\uB2E4.` : "\uC911\uBCF5\uB41C \uAC12\uC774 \uC874\uC7AC\uD569\uB2C8\uB2E4.";
|
|
14965
|
+
seen.add(v);
|
|
14966
|
+
}
|
|
14967
|
+
return "";
|
|
14968
|
+
}, [values, duplicateLabel]);
|
|
14969
|
+
const ruleMessage = react.useMemo(() => runRules(values, rules), [values, rules]);
|
|
14970
|
+
const resolvedErrorMessage = duplicateMessage || ruleMessage || errorMessage;
|
|
14971
|
+
const resolvedError = error || duplicateMessage !== "" || ruleMessage !== "";
|
|
14972
|
+
const resolvedStatus = status ?? (resolvedError ? "error" : void 0);
|
|
14973
|
+
useFormField({
|
|
14974
|
+
name,
|
|
14975
|
+
validate: () => runRules(values, rules) === "" && duplicateMessage === "",
|
|
14976
|
+
resetValidation: () => {
|
|
14977
|
+
}
|
|
14978
|
+
});
|
|
14979
|
+
const isMax = maxCount != null && values.length >= maxCount;
|
|
13579
14980
|
const resolvedDropdownMinWidth = dropdownMinWidth == null ? void 0 : typeof dropdownMinWidth === "number" ? `${dropdownMinWidth}px` : dropdownMinWidth;
|
|
13580
14981
|
const commit = (next) => onValueChange?.(next);
|
|
13581
14982
|
const addChip = (v) => {
|
|
@@ -14220,7 +15621,7 @@ function TimeSelector({
|
|
|
14220
15621
|
const renderColumn = (type) => {
|
|
14221
15622
|
const isHour = type === "hour";
|
|
14222
15623
|
const val = isHour ? displayHour : minute;
|
|
14223
|
-
const
|
|
15624
|
+
const displayValue2 = editingPart === type ? inputDraft[type] ?? "" : String(val).padStart(2, "0");
|
|
14224
15625
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14225
15626
|
"div",
|
|
14226
15627
|
{
|
|
@@ -14241,7 +15642,7 @@ function TimeSelector({
|
|
|
14241
15642
|
{
|
|
14242
15643
|
"aria-label": isHour ? "\uC2DC" : "\uBD84",
|
|
14243
15644
|
inputMode: "numeric",
|
|
14244
|
-
value:
|
|
15645
|
+
value: displayValue2,
|
|
14245
15646
|
placeholder: "-",
|
|
14246
15647
|
onFocus: () => beginEdit(type, val),
|
|
14247
15648
|
onBlur: () => endEdit(type),
|
|
@@ -14436,8 +15837,8 @@ function STimePicker({
|
|
|
14436
15837
|
disabled,
|
|
14437
15838
|
className,
|
|
14438
15839
|
style,
|
|
14439
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14440
|
-
/* @__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(
|
|
14441
15842
|
"div",
|
|
14442
15843
|
{
|
|
14443
15844
|
ref: triggerRef,
|
|
@@ -14497,14 +15898,17 @@ function STimePicker({
|
|
|
14497
15898
|
]
|
|
14498
15899
|
}
|
|
14499
15900
|
) }),
|
|
14500
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14501
|
-
|
|
15901
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
15902
|
+
RPopover9__namespace.Content,
|
|
14502
15903
|
{
|
|
14503
15904
|
side: "bottom",
|
|
14504
15905
|
align: "start",
|
|
14505
15906
|
sideOffset: 4,
|
|
14506
15907
|
alignOffset: popoverAlignOffset,
|
|
14507
|
-
className: cn(
|
|
15908
|
+
className: cn(
|
|
15909
|
+
"z-50 max-w-[var(--radix-popover-content-available-width)]",
|
|
15910
|
+
FLOATING_SLIDE_ANIM
|
|
15911
|
+
),
|
|
14508
15912
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14509
15913
|
TimeSelector,
|
|
14510
15914
|
{
|
|
@@ -14663,7 +16067,7 @@ function RangeTimeSelector({
|
|
|
14663
16067
|
const { minute } = getParts(side);
|
|
14664
16068
|
const val = isHour ? getDisplayHour(side) : minute;
|
|
14665
16069
|
const currentEditingKey = getEditingKey(side, kind);
|
|
14666
|
-
const
|
|
16070
|
+
const displayValue2 = editingKey === currentEditingKey ? inputDraft[currentEditingKey] ?? "" : String(val).padStart(2, "0");
|
|
14667
16071
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14668
16072
|
"div",
|
|
14669
16073
|
{
|
|
@@ -14684,7 +16088,7 @@ function RangeTimeSelector({
|
|
|
14684
16088
|
{
|
|
14685
16089
|
"aria-label": `${side === "start" ? "\uC2DC\uC791" : "\uC885\uB8CC"} ${isHour ? "\uC2DC" : "\uBD84"}`,
|
|
14686
16090
|
inputMode: "numeric",
|
|
14687
|
-
value:
|
|
16091
|
+
value: displayValue2,
|
|
14688
16092
|
placeholder: "-",
|
|
14689
16093
|
onFocus: () => beginEdit(side, kind, val),
|
|
14690
16094
|
onBlur: () => endEdit(side, kind),
|
|
@@ -14895,8 +16299,8 @@ function STimeRangePicker({
|
|
|
14895
16299
|
disabled,
|
|
14896
16300
|
className,
|
|
14897
16301
|
style,
|
|
14898
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14899
|
-
/* @__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(
|
|
14900
16304
|
"div",
|
|
14901
16305
|
{
|
|
14902
16306
|
ref: triggerRef,
|
|
@@ -14956,14 +16360,17 @@ function STimeRangePicker({
|
|
|
14956
16360
|
]
|
|
14957
16361
|
}
|
|
14958
16362
|
) }),
|
|
14959
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14960
|
-
|
|
16363
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover9__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
16364
|
+
RPopover9__namespace.Content,
|
|
14961
16365
|
{
|
|
14962
16366
|
side: "bottom",
|
|
14963
16367
|
align: "start",
|
|
14964
16368
|
sideOffset: 4,
|
|
14965
16369
|
alignOffset: popoverAlignOffset,
|
|
14966
|
-
className: cn(
|
|
16370
|
+
className: cn(
|
|
16371
|
+
"z-50 max-w-[var(--radix-popover-content-available-width)]",
|
|
16372
|
+
FLOATING_SLIDE_ANIM
|
|
16373
|
+
),
|
|
14967
16374
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14968
16375
|
RangeTimeSelector,
|
|
14969
16376
|
{
|
|
@@ -14996,6 +16403,7 @@ exports.GNB_RAIL = GNB_RAIL;
|
|
|
14996
16403
|
exports.GNB_RAIL_WIDTH = GNB_RAIL_WIDTH;
|
|
14997
16404
|
exports.ICONS = ICONS;
|
|
14998
16405
|
exports.PAGE_BACKGROUNDS = PAGE_BACKGROUNDS;
|
|
16406
|
+
exports.RangeCalendar = RangeCalendar;
|
|
14999
16407
|
exports.SActionModal = SActionModal;
|
|
15000
16408
|
exports.SBadge = SBadge;
|
|
15001
16409
|
exports.SBarcodeInput = SBarcodeInput;
|
|
@@ -15006,6 +16414,7 @@ exports.SCallout = SCallout;
|
|
|
15006
16414
|
exports.SCard = SCard;
|
|
15007
16415
|
exports.SCheckbox = SCheckbox;
|
|
15008
16416
|
exports.SChip = SChip2;
|
|
16417
|
+
exports.SChipFilter = SChipFilter;
|
|
15009
16418
|
exports.SChipInput = SChipInput;
|
|
15010
16419
|
exports.SCircleProgress = SCircleProgress;
|
|
15011
16420
|
exports.SConfirmModal = SConfirmModal;
|