sellmate-design-system-react 9.0.0-beta.45 → 9.0.0-beta.46
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 +48 -4
- package/dist/components/SButton/README.md +2 -0
- package/dist/components/SChatInput/README.md +44 -0
- package/dist/components/SChatInput/SChatInput.d.ts +60 -0
- package/dist/components/SChatInput/index.d.ts +1 -0
- package/dist/components/SChatMessage/README.md +81 -0
- package/dist/components/SChatMessage/SChatMessage.d.ts +102 -0
- package/dist/components/SChatMessage/index.d.ts +1 -0
- package/dist/components/SGhostButton/README.md +2 -0
- package/dist/components/SIcon/README.md +2 -0
- package/dist/components/SIcon/icons.gen.d.ts +1 -0
- package/dist/components/SImage/README.md +5 -0
- package/dist/components/SLoginCard/README.md +34 -0
- package/dist/components/SLoginCard/SLoginCard.d.ts +28 -0
- package/dist/components/SLoginCard/index.d.ts +1 -0
- package/dist/components/SLoginCard/sellmate-wordmark.d.ts +13 -0
- package/dist/components/STextarea/README.md +2 -0
- package/dist/index.cjs +2417 -2091
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2413 -2093
- package/dist/index.js.map +1 -1
- package/dist/llms-full.txt +204 -4
- package/dist/llms.txt +50 -6
- package/dist/styles.css +86 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -5,9 +5,9 @@ var clsx = require('clsx');
|
|
|
5
5
|
var tailwindMerge = require('tailwind-merge');
|
|
6
6
|
var react = require('react');
|
|
7
7
|
var jsxRuntime = require('react/jsx-runtime');
|
|
8
|
+
var RPopover12 = require('@radix-ui/react-popover');
|
|
8
9
|
var reactDom = require('react-dom');
|
|
9
10
|
var RCheckbox = require('@radix-ui/react-checkbox');
|
|
10
|
-
var RPopover12 = 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 RDropdown2 = require('@radix-ui/react-dropdown-menu');
|
|
@@ -33,8 +33,8 @@ function _interopNamespace(e) {
|
|
|
33
33
|
return Object.freeze(n);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
var RCheckbox__namespace = /*#__PURE__*/_interopNamespace(RCheckbox);
|
|
37
36
|
var RPopover12__namespace = /*#__PURE__*/_interopNamespace(RPopover12);
|
|
37
|
+
var RCheckbox__namespace = /*#__PURE__*/_interopNamespace(RCheckbox);
|
|
38
38
|
var RTooltip__namespace = /*#__PURE__*/_interopNamespace(RTooltip);
|
|
39
39
|
var RDropdown2__namespace = /*#__PURE__*/_interopNamespace(RDropdown2);
|
|
40
40
|
var RSwitch__namespace = /*#__PURE__*/_interopNamespace(RSwitch);
|
|
@@ -2757,6 +2757,38 @@ var Icon_star = (p) => {
|
|
|
2757
2757
|
}
|
|
2758
2758
|
);
|
|
2759
2759
|
};
|
|
2760
|
+
var Icon_stop = (p) => {
|
|
2761
|
+
const { size = 24, ...rest } = p;
|
|
2762
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2763
|
+
"svg",
|
|
2764
|
+
{
|
|
2765
|
+
width: size,
|
|
2766
|
+
height: size,
|
|
2767
|
+
viewBox: "0 0 24 24",
|
|
2768
|
+
fill: "none",
|
|
2769
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2770
|
+
...rest,
|
|
2771
|
+
children: [
|
|
2772
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2773
|
+
"path",
|
|
2774
|
+
{
|
|
2775
|
+
d: "M15.5 7.5C16.0523 7.5 16.5 7.94772 16.5 8.5V15.5C16.5 16.0523 16.0523 16.5 15.5 16.5H8.5C7.94772 16.5 7.5 16.0523 7.5 15.5V8.5C7.5 7.94772 7.94772 7.5 8.5 7.5H15.5Z",
|
|
2776
|
+
fill: "currentColor"
|
|
2777
|
+
}
|
|
2778
|
+
),
|
|
2779
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2780
|
+
"path",
|
|
2781
|
+
{
|
|
2782
|
+
fillRule: "evenodd",
|
|
2783
|
+
clipRule: "evenodd",
|
|
2784
|
+
d: "M12 1.0498C18.0474 1.04991 22.9501 5.95263 22.9502 12C22.9501 18.0474 18.0474 22.9501 12 22.9502C5.95266 22.9501 1.04991 18.0473 1.0498 12C1.0499 5.95265 5.95266 1.04994 12 1.0498ZM12 2.5498C6.78108 2.54994 2.5499 6.78108 2.5498 12C2.54991 17.2189 6.78109 21.4501 12 21.4502C17.2189 21.4501 21.4501 17.2189 21.4502 12C21.4501 6.78106 17.2189 2.54991 12 2.5498Z",
|
|
2785
|
+
fill: "currentColor"
|
|
2786
|
+
}
|
|
2787
|
+
)
|
|
2788
|
+
]
|
|
2789
|
+
}
|
|
2790
|
+
);
|
|
2791
|
+
};
|
|
2760
2792
|
var Icon_store = (p) => {
|
|
2761
2793
|
const { size = 24, ...rest } = p;
|
|
2762
2794
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -3256,6 +3288,7 @@ var ICONS = {
|
|
|
3256
3288
|
shield: Icon_shield,
|
|
3257
3289
|
sidebar: Icon_sidebar,
|
|
3258
3290
|
star: Icon_star,
|
|
3291
|
+
stop: Icon_stop,
|
|
3259
3292
|
store: Icon_store,
|
|
3260
3293
|
synchronize: Icon_synchronize,
|
|
3261
3294
|
thumbsDown: Icon_thumbsDown,
|
|
@@ -3766,409 +3799,1474 @@ function withDisplayName(component, name) {
|
|
|
3766
3799
|
return component;
|
|
3767
3800
|
}
|
|
3768
3801
|
|
|
3769
|
-
// src/lib/
|
|
3770
|
-
var
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3802
|
+
// src/lib/floating-anim.ts
|
|
3803
|
+
var FLOATING_SLIDE_ANIM = [
|
|
3804
|
+
"data-[state=open]:data-[side=top]:animate-floating-in-top",
|
|
3805
|
+
"data-[state=delayed-open]:data-[side=top]:animate-floating-in-top",
|
|
3806
|
+
"data-[state=instant-open]:data-[side=top]:animate-floating-in-top",
|
|
3807
|
+
"data-[state=closed]:data-[side=top]:animate-floating-out-top",
|
|
3808
|
+
"data-[state=open]:data-[side=bottom]:animate-floating-in-bottom",
|
|
3809
|
+
"data-[state=delayed-open]:data-[side=bottom]:animate-floating-in-bottom",
|
|
3810
|
+
"data-[state=instant-open]:data-[side=bottom]:animate-floating-in-bottom",
|
|
3811
|
+
"data-[state=closed]:data-[side=bottom]:animate-floating-out-bottom",
|
|
3812
|
+
"data-[state=open]:data-[side=left]:animate-floating-in-left",
|
|
3813
|
+
"data-[state=delayed-open]:data-[side=left]:animate-floating-in-left",
|
|
3814
|
+
"data-[state=instant-open]:data-[side=left]:animate-floating-in-left",
|
|
3815
|
+
"data-[state=closed]:data-[side=left]:animate-floating-out-left",
|
|
3816
|
+
"data-[state=open]:data-[side=right]:animate-floating-in-right",
|
|
3817
|
+
"data-[state=delayed-open]:data-[side=right]:animate-floating-in-right",
|
|
3818
|
+
"data-[state=instant-open]:data-[side=right]:animate-floating-in-right",
|
|
3819
|
+
"data-[state=closed]:data-[side=right]:animate-floating-out-right"
|
|
3820
|
+
].join(" ");
|
|
3821
|
+
var PortalContainerContext = /* @__PURE__ */ react.createContext(null);
|
|
3822
|
+
var InsideModalContext = /* @__PURE__ */ react.createContext(false);
|
|
3823
|
+
var PortalContainerProvider = PortalContainerContext.Provider;
|
|
3824
|
+
var InsideModalProvider = InsideModalContext.Provider;
|
|
3825
|
+
function usePortalContainer() {
|
|
3826
|
+
return react.useContext(PortalContainerContext) ?? void 0;
|
|
3827
|
+
}
|
|
3828
|
+
function useInsideModal() {
|
|
3829
|
+
return react.useContext(InsideModalContext);
|
|
3830
|
+
}
|
|
3831
|
+
|
|
3832
|
+
// src/components/STag/tag.config.ts
|
|
3833
|
+
var TAG_SHAPES = ["square", "pill"];
|
|
3834
|
+
var TAG_SIZES = ["xs", "sm", "md"];
|
|
3835
|
+
var TAG_COLORS = [
|
|
3836
|
+
"grey",
|
|
3837
|
+
"red",
|
|
3838
|
+
"orange",
|
|
3839
|
+
"yellow",
|
|
3840
|
+
"green",
|
|
3841
|
+
"blue",
|
|
3842
|
+
"darkblue",
|
|
3843
|
+
"indigo"
|
|
3844
|
+
];
|
|
3845
|
+
var TAG_SIZE_CONFIG = {
|
|
3846
|
+
xs: {
|
|
3847
|
+
height: 20,
|
|
3848
|
+
paddingX: 8,
|
|
3849
|
+
gap: 4,
|
|
3850
|
+
radius: 6,
|
|
3851
|
+
iconSize: 12,
|
|
3852
|
+
fontSize: 11,
|
|
3853
|
+
fontWeight: 500,
|
|
3854
|
+
lineHeight: 18
|
|
3855
|
+
},
|
|
3856
|
+
sm: {
|
|
3857
|
+
height: 24,
|
|
3858
|
+
paddingX: 8,
|
|
3859
|
+
gap: 4,
|
|
3860
|
+
radius: 6,
|
|
3861
|
+
iconSize: 16,
|
|
3862
|
+
fontSize: 12,
|
|
3863
|
+
fontWeight: 700,
|
|
3864
|
+
lineHeight: 20
|
|
3865
|
+
},
|
|
3866
|
+
md: {
|
|
3867
|
+
height: 28,
|
|
3868
|
+
paddingX: 12,
|
|
3869
|
+
gap: 6,
|
|
3870
|
+
radius: 8,
|
|
3871
|
+
iconSize: 16,
|
|
3872
|
+
fontSize: 14,
|
|
3873
|
+
fontWeight: 700,
|
|
3874
|
+
lineHeight: 24
|
|
3875
|
+
}
|
|
3776
3876
|
};
|
|
3777
|
-
var
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3877
|
+
var STag = /* @__PURE__ */ react.forwardRef(function STag2({
|
|
3878
|
+
shape = "square",
|
|
3879
|
+
size = "sm",
|
|
3880
|
+
color = "grey",
|
|
3881
|
+
deep = false,
|
|
3882
|
+
label = "",
|
|
3883
|
+
icon,
|
|
3884
|
+
iconLeft = true,
|
|
3885
|
+
width,
|
|
3886
|
+
className,
|
|
3887
|
+
style,
|
|
3888
|
+
...rest
|
|
3889
|
+
}, ref) {
|
|
3890
|
+
const s = TAG_SIZE_CONFIG[size];
|
|
3891
|
+
const contentColor = deep ? `var(--cmp-tag-${color}-deep-content, var(--cmp-tag-deep-content))` : `var(--cmp-tag-${color}-content)`;
|
|
3892
|
+
const bgColor = deep ? `var(--cmp-tag-${color}-deep-bg)` : `var(--cmp-tag-${color}-bg)`;
|
|
3893
|
+
const iconNode = icon ? /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: icon, size: s.iconSize, color: contentColor }) : null;
|
|
3894
|
+
const resolvedWidth = typeof width === "number" ? `${width}px` : width;
|
|
3895
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3896
|
+
"span",
|
|
3897
|
+
{
|
|
3898
|
+
ref,
|
|
3899
|
+
"aria-label": label || "tag",
|
|
3900
|
+
className: cn(
|
|
3901
|
+
"box-border inline-flex w-fit select-none items-center justify-center whitespace-nowrap",
|
|
3902
|
+
className
|
|
3903
|
+
),
|
|
3904
|
+
style: {
|
|
3905
|
+
minHeight: s.height,
|
|
3906
|
+
padding: `0 ${s.paddingX}px`,
|
|
3907
|
+
gap: s.gap,
|
|
3908
|
+
borderRadius: shape === "pill" ? 999 : s.radius,
|
|
3909
|
+
fontSize: s.fontSize,
|
|
3910
|
+
fontWeight: s.fontWeight,
|
|
3911
|
+
lineHeight: `${s.lineHeight}px`,
|
|
3912
|
+
background: bgColor,
|
|
3913
|
+
color: contentColor,
|
|
3914
|
+
...resolvedWidth != null ? { width: resolvedWidth } : {},
|
|
3915
|
+
...style
|
|
3916
|
+
},
|
|
3917
|
+
...rest,
|
|
3918
|
+
children: [
|
|
3919
|
+
icon && iconLeft && iconNode,
|
|
3920
|
+
label && // leading-none: 태그는 min-height 로 높이가 정해지고 flex 가 세로 중앙 정렬하므로
|
|
3921
|
+
// 레이블에 line-height 가 필요 없다. 오히려 line-height 를 주면 브라우저가
|
|
3922
|
+
// 폰트 ascent/descent 를 정수 px 로 반올림한 뒤 남는 half-leading 을 내림 처리해
|
|
3923
|
+
// 베이스라인이 최대 1px 위로 밀린다(xs 에서 특히 눈에 띈다).
|
|
3924
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex min-w-0 items-center justify-center leading-none", children: label }),
|
|
3925
|
+
icon && !iconLeft && iconNode
|
|
3926
|
+
]
|
|
3785
3927
|
}
|
|
3786
|
-
|
|
3928
|
+
);
|
|
3929
|
+
});
|
|
3930
|
+
var SIZE = {
|
|
3931
|
+
xxs: { icon: 12, radius: "sm" },
|
|
3932
|
+
xs: { icon: 16, radius: "sm" },
|
|
3933
|
+
sm: { icon: 20, radius: "sm" },
|
|
3934
|
+
md: { icon: 24, radius: "md" },
|
|
3935
|
+
lg: { icon: 32, radius: "md" }
|
|
3787
3936
|
};
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
var SDraggableItemView = /* @__PURE__ */ react.forwardRef(
|
|
3792
|
-
function SDraggableItemView2({
|
|
3793
|
-
title,
|
|
3794
|
-
supportingText,
|
|
3795
|
-
supportingTextPosition,
|
|
3796
|
-
trailing,
|
|
3797
|
-
depth,
|
|
3798
|
-
accentStripe,
|
|
3799
|
-
bordered,
|
|
3800
|
-
selected,
|
|
3801
|
-
dense,
|
|
3802
|
-
size,
|
|
3803
|
-
dragging,
|
|
3804
|
-
disabled,
|
|
3805
|
-
hovered,
|
|
3806
|
-
dragHandleProps,
|
|
3807
|
-
onDragHandleMouseDown,
|
|
3808
|
-
className,
|
|
3809
|
-
style,
|
|
3810
|
-
...rest
|
|
3811
|
-
}, ref) {
|
|
3812
|
-
const renderState = { hovered, dragging, disabled };
|
|
3813
|
-
const titleNode = renderSlot(title, renderState);
|
|
3814
|
-
const supportingTextNode = renderSlot(supportingText, renderState);
|
|
3815
|
-
const hasSupportingText = supportingTextNode != null && supportingTextNode !== "";
|
|
3816
|
-
const trailingNode = renderSlot(trailing, renderState);
|
|
3817
|
-
const titleTypo = size === "sm" ? selected ? "typo-item-sm-selected" : "typo-item-sm-default" : selected ? "typo-item-md-selected" : "typo-item-md-default";
|
|
3818
|
-
const paddingYClass = dense ? size === "sm" ? "py-(--cmp-listDraggableItem-paddingY-sm-dense)" : "py-(--cmp-listDraggableItem-paddingY-md-dense)" : size === "sm" ? "py-(--cmp-listDraggableItem-paddingY-sm-normal)" : "py-(--cmp-listDraggableItem-paddingY-md-normal)";
|
|
3819
|
-
const normalizedDepth = Math.max(1, Math.floor(depth));
|
|
3820
|
-
const depthOffset = (normalizedDepth - 1) * 20;
|
|
3821
|
-
const depthStyle = depthOffset === 0 ? style : bordered ? {
|
|
3822
|
-
...style,
|
|
3823
|
-
marginLeft: depthOffset,
|
|
3824
|
-
width: `calc(100% - ${depthOffset}px)`
|
|
3825
|
-
} : {
|
|
3826
|
-
...style,
|
|
3827
|
-
paddingLeft: `calc(var(--cmp-listDraggableItem-paddingX) + ${depthOffset}px)`
|
|
3828
|
-
};
|
|
3829
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3830
|
-
"div",
|
|
3831
|
-
{
|
|
3832
|
-
ref,
|
|
3833
|
-
"aria-disabled": disabled || void 0,
|
|
3834
|
-
"data-dragging": dragging || void 0,
|
|
3835
|
-
style: depthStyle,
|
|
3836
|
-
className: cn(
|
|
3837
|
-
"relative flex w-full items-center gap-(--cmp-listDraggableItem-gap) overflow-hidden px-(--cmp-listDraggableItem-paddingX)",
|
|
3838
|
-
titleTypo,
|
|
3839
|
-
disabled ? "bg-(--cmp-listDraggableItem-bg-default) text-(--sys-color-disabled-text)" : selected ? "bg-(--cmp-listDraggableItem-bg-selected) text-(--cmp-listDraggableItem-text-selected)" : "bg-(--cmp-listDraggableItem-bg-default) text-(--cmp-listDraggableItem-text-default)",
|
|
3840
|
-
!disabled && !selected && !dragging && cn(
|
|
3841
|
-
"hover:bg-(--cmp-listDraggableItem-bg-hover)",
|
|
3842
|
-
// 리스트가 드래그 중이면(SDraggableList 가 data-drag-active 를 붙인다) hover 를 무효화한다.
|
|
3843
|
-
"[[data-drag-active]_&]:hover:bg-(--cmp-listDraggableItem-bg-default)"
|
|
3844
|
-
),
|
|
3845
|
-
// 높이는 세로 패딩과 내용이 정한다 — 항목에 높이를 못 박지 않는다 (SListItem 과 동일)
|
|
3846
|
-
paddingYClass,
|
|
3847
|
-
// 항목 사이 구분선은 리스트가 그린다.
|
|
3848
|
-
bordered && cn(
|
|
3849
|
-
"rounded-(--cmp-listDraggableItem-radius-bordered) border border-(--cmp-listDraggableItem-border-default)",
|
|
3850
|
-
!disabled && !selected && !dragging && cn(
|
|
3851
|
-
"hover:border-(--cmp-listDraggableItem-bordered-border-hover)",
|
|
3852
|
-
"[[data-drag-active]_&]:hover:border-(--cmp-listDraggableItem-border-default)"
|
|
3853
|
-
),
|
|
3854
|
-
!disabled && selected && !dragging && "border-(--cmp-listDraggableItem-bordered-border-selected) bg-(--cmp-listDraggableItem-bordered-bg-selected)",
|
|
3855
|
-
!disabled && selected && dragging && "border-(--cmp-listDraggableItem-bordered-dragging-border-color) bg-(--cmp-listDraggableItem-bordered-dragging-bg)"
|
|
3856
|
-
),
|
|
3857
|
-
disabled && "cursor-not-allowed",
|
|
3858
|
-
className
|
|
3859
|
-
),
|
|
3860
|
-
...rest,
|
|
3861
|
-
children: [
|
|
3862
|
-
accentStripe && selected && !bordered && !disabled && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3863
|
-
"span",
|
|
3864
|
-
{
|
|
3865
|
-
"aria-hidden": "true",
|
|
3866
|
-
className: "pointer-events-none absolute bottom-[-1px] left-0 top-0 w-(--cmp-listDraggableItem-accentStripe-width) bg-(--cmp-listDraggableItem-accentStripe-color)"
|
|
3867
|
-
}
|
|
3868
|
-
),
|
|
3869
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3870
|
-
"div",
|
|
3871
|
-
{
|
|
3872
|
-
...dragHandleProps,
|
|
3873
|
-
role: dragHandleProps?.role ?? "button",
|
|
3874
|
-
tabIndex: dragHandleProps?.tabIndex ?? (disabled ? -1 : 0),
|
|
3875
|
-
"aria-label": dragHandleProps?.["aria-label"] ?? "\uB4DC\uB798\uADF8 \uD578\uB4E4",
|
|
3876
|
-
"aria-disabled": disabled || void 0,
|
|
3877
|
-
onMouseDown: onDragHandleMouseDown,
|
|
3878
|
-
className: cn(
|
|
3879
|
-
"flex size-[24px] shrink-0 select-none items-center justify-center rounded-[4px]",
|
|
3880
|
-
disabled ? "cursor-not-allowed opacity-0" : "cursor-grab hover:bg-black/5 active:cursor-grabbing",
|
|
3881
|
-
!disabled && !dragging && "[[data-drag-active]_&]:hover:bg-transparent",
|
|
3882
|
-
dragging && "bg-black/5",
|
|
3883
|
-
dragHandleProps?.className
|
|
3884
|
-
),
|
|
3885
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "drag", size: 16, color: "grey_65" })
|
|
3886
|
-
}
|
|
3887
|
-
),
|
|
3888
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3889
|
-
"div",
|
|
3890
|
-
{
|
|
3891
|
-
className: cn(
|
|
3892
|
-
"flex min-w-0 flex-1 items-center gap-[8px]",
|
|
3893
|
-
dragging && "opacity-(--cmp-listDraggableItem-dragging-content-opacity)"
|
|
3894
|
-
),
|
|
3895
|
-
children: [
|
|
3896
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3897
|
-
"span",
|
|
3898
|
-
{
|
|
3899
|
-
className: cn(
|
|
3900
|
-
"min-w-0 flex-1",
|
|
3901
|
-
supportingTextPosition === "bottom" ? "flex flex-col" : "flex items-center gap-[8px] whitespace-nowrap"
|
|
3902
|
-
),
|
|
3903
|
-
children: [
|
|
3904
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate", children: titleNode }),
|
|
3905
|
-
hasSupportingText && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3906
|
-
"span",
|
|
3907
|
-
{
|
|
3908
|
-
className: cn(
|
|
3909
|
-
"typo-body-sm-default min-w-0 truncate text-(--sys-color-fg-secondary)",
|
|
3910
|
-
supportingTextPosition === "right" && "flex-1"
|
|
3911
|
-
),
|
|
3912
|
-
children: supportingTextNode
|
|
3913
|
-
}
|
|
3914
|
-
)
|
|
3915
|
-
]
|
|
3916
|
-
}
|
|
3917
|
-
),
|
|
3918
|
-
trailingNode
|
|
3919
|
-
]
|
|
3920
|
-
}
|
|
3921
|
-
)
|
|
3922
|
-
]
|
|
3923
|
-
}
|
|
3924
|
-
);
|
|
3925
|
-
}
|
|
3926
|
-
);
|
|
3927
|
-
var SDraggableItemImpl = /* @__PURE__ */ react.forwardRef(function SDraggableItem({
|
|
3928
|
-
title,
|
|
3929
|
-
supportingText,
|
|
3930
|
-
supportingTextPosition = "right",
|
|
3931
|
-
trailing,
|
|
3932
|
-
depth = 1,
|
|
3933
|
-
accentStripe = false,
|
|
3934
|
-
bordered = false,
|
|
3935
|
-
selected = false,
|
|
3936
|
-
dragging = false,
|
|
3937
|
-
dense = false,
|
|
3937
|
+
var TOOLTIP_HIDE_DELAY_MS = 100;
|
|
3938
|
+
function SGhostButton({
|
|
3939
|
+
icon,
|
|
3938
3940
|
size = "sm",
|
|
3941
|
+
intent = "default",
|
|
3942
|
+
ariaLabel = "",
|
|
3943
|
+
ariaPressed,
|
|
3944
|
+
ariaExpanded,
|
|
3945
|
+
tooltipText,
|
|
3939
3946
|
disabled = false,
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
onDragHandleMouseDown,
|
|
3947
|
+
onClick,
|
|
3948
|
+
anchorClassName,
|
|
3949
|
+
anchorStyle,
|
|
3944
3950
|
className,
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
const
|
|
3950
|
-
const
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
onMouseEnter?.(event);
|
|
3951
|
+
style
|
|
3952
|
+
}) {
|
|
3953
|
+
const portalContainer = usePortalContainer();
|
|
3954
|
+
const [open, setOpen] = react.useState(false);
|
|
3955
|
+
const hideTimer = react.useRef(void 0);
|
|
3956
|
+
const cancelHide = () => {
|
|
3957
|
+
if (hideTimer.current) {
|
|
3958
|
+
clearTimeout(hideTimer.current);
|
|
3959
|
+
hideTimer.current = void 0;
|
|
3960
|
+
}
|
|
3956
3961
|
};
|
|
3957
|
-
const
|
|
3958
|
-
|
|
3959
|
-
|
|
3962
|
+
const openNow = () => {
|
|
3963
|
+
cancelHide();
|
|
3964
|
+
setOpen(true);
|
|
3960
3965
|
};
|
|
3961
|
-
const
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
if (dragOverlay && rect) {
|
|
3965
|
-
setOverlay({
|
|
3966
|
-
offsetX: event.clientX - rect.left,
|
|
3967
|
-
offsetY: event.clientY - rect.top,
|
|
3968
|
-
rect,
|
|
3969
|
-
x: event.clientX,
|
|
3970
|
-
y: event.clientY
|
|
3971
|
-
});
|
|
3972
|
-
}
|
|
3973
|
-
dragHandleProps?.onMouseDown?.(event);
|
|
3974
|
-
onDragHandleMouseDown?.(event);
|
|
3966
|
+
const startHide = () => {
|
|
3967
|
+
cancelHide();
|
|
3968
|
+
hideTimer.current = setTimeout(() => setOpen(false), TOOLTIP_HIDE_DELAY_MS);
|
|
3975
3969
|
};
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
x: event.clientX,
|
|
3983
|
-
y: event.clientY
|
|
3984
|
-
} : current
|
|
3985
|
-
);
|
|
3986
|
-
};
|
|
3987
|
-
const handleMouseUp = () => {
|
|
3988
|
-
setOverlay(null);
|
|
3989
|
-
};
|
|
3990
|
-
window.addEventListener("mousemove", handleMouseMove);
|
|
3991
|
-
window.addEventListener("mouseup", handleMouseUp);
|
|
3992
|
-
return () => {
|
|
3993
|
-
window.removeEventListener("mousemove", handleMouseMove);
|
|
3994
|
-
window.removeEventListener("mouseup", handleMouseUp);
|
|
3995
|
-
};
|
|
3996
|
-
}, [overlayVisible]);
|
|
3997
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3998
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3999
|
-
SDraggableItemView,
|
|
4000
|
-
{
|
|
4001
|
-
ref: (node) => setRefs([rootRef, ref], node),
|
|
4002
|
-
title,
|
|
4003
|
-
supportingText,
|
|
4004
|
-
supportingTextPosition,
|
|
4005
|
-
trailing,
|
|
4006
|
-
depth,
|
|
4007
|
-
accentStripe,
|
|
4008
|
-
bordered,
|
|
4009
|
-
selected,
|
|
4010
|
-
dense,
|
|
4011
|
-
size,
|
|
4012
|
-
dragging: dragging || overlayVisible,
|
|
4013
|
-
disabled,
|
|
4014
|
-
hovered,
|
|
4015
|
-
dragHandleProps,
|
|
4016
|
-
onDragHandleMouseDown: handleDragMouseDown,
|
|
4017
|
-
onMouseEnter: handleMouseEnter,
|
|
4018
|
-
onMouseLeave: handleMouseLeave,
|
|
4019
|
-
className,
|
|
4020
|
-
...rest
|
|
4021
|
-
}
|
|
4022
|
-
),
|
|
4023
|
-
overlay && typeof document !== "undefined" && reactDom.createPortal(
|
|
4024
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4025
|
-
"div",
|
|
4026
|
-
{
|
|
4027
|
-
className: "pointer-events-none fixed",
|
|
4028
|
-
style: {
|
|
4029
|
-
left: overlay.x - overlay.offsetX,
|
|
4030
|
-
opacity: dragOverlayOpacity,
|
|
4031
|
-
top: overlay.y - overlay.offsetY,
|
|
4032
|
-
width: overlay.rect.width,
|
|
4033
|
-
zIndex: Z_INDEX.drag
|
|
4034
|
-
},
|
|
4035
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4036
|
-
SDraggableItemView,
|
|
4037
|
-
{
|
|
4038
|
-
title,
|
|
4039
|
-
supportingText,
|
|
4040
|
-
supportingTextPosition,
|
|
4041
|
-
trailing,
|
|
4042
|
-
depth,
|
|
4043
|
-
accentStripe,
|
|
4044
|
-
bordered,
|
|
4045
|
-
selected,
|
|
4046
|
-
dense,
|
|
4047
|
-
size,
|
|
4048
|
-
dragging: true,
|
|
4049
|
-
disabled,
|
|
4050
|
-
hovered: true,
|
|
4051
|
-
dragHandleProps,
|
|
4052
|
-
className
|
|
4053
|
-
}
|
|
4054
|
-
)
|
|
4055
|
-
}
|
|
4056
|
-
),
|
|
4057
|
-
document.body
|
|
4058
|
-
)
|
|
4059
|
-
] });
|
|
4060
|
-
});
|
|
4061
|
-
var SDraggableItem2 = /* @__PURE__ */ withDisplayName(SDraggableItemImpl, "SDraggableItem");
|
|
4062
|
-
var SDivider = /* @__PURE__ */ react.forwardRef(function SDivider2({ vertical = false, height, className, style, ...rest }, ref) {
|
|
4063
|
-
const fixedHeight = vertical && height !== void 0;
|
|
4064
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4065
|
-
"hr",
|
|
3970
|
+
const s = SIZE[size];
|
|
3971
|
+
const contentColor = disabled ? intent === "inverse" ? "var(--cmp-ghostButton-inverse-disabled)" : "var(--cmp-ghostButton-icon-disabled)" : `var(--cmp-ghostButton-${intent}-content)`;
|
|
3972
|
+
const text = (tooltipText ?? "").trim();
|
|
3973
|
+
const hasTooltip = text !== "";
|
|
3974
|
+
const btn2 = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3975
|
+
"button",
|
|
4066
3976
|
{
|
|
4067
|
-
|
|
4068
|
-
|
|
3977
|
+
type: "button",
|
|
3978
|
+
disabled,
|
|
3979
|
+
"aria-disabled": disabled ? "true" : void 0,
|
|
3980
|
+
"aria-label": ariaLabel.trim() || void 0,
|
|
3981
|
+
"aria-pressed": ariaPressed,
|
|
3982
|
+
"aria-expanded": ariaExpanded,
|
|
3983
|
+
tabIndex: disabled ? -1 : void 0,
|
|
3984
|
+
onClick: (e) => {
|
|
3985
|
+
if (disabled) {
|
|
3986
|
+
e.preventDefault();
|
|
3987
|
+
return;
|
|
3988
|
+
}
|
|
3989
|
+
onClick?.(e);
|
|
3990
|
+
},
|
|
4069
3991
|
className: cn(
|
|
4070
|
-
"
|
|
4071
|
-
|
|
3992
|
+
"group/ghost-button relative box-border inline-flex items-center justify-center border-none bg-transparent p-0 transition-shadow",
|
|
3993
|
+
disabled ? "cursor-not-allowed" : "cursor-pointer",
|
|
3994
|
+
"focus-visible:outline-none focus-visible:shadow-[0_0_0_2px_var(--cmp-ghostButton-action-hover-bg)]",
|
|
4072
3995
|
className
|
|
4073
3996
|
),
|
|
4074
3997
|
style: {
|
|
4075
|
-
|
|
4076
|
-
|
|
3998
|
+
width: `var(--cmp-ghostButton-${size}-size)`,
|
|
3999
|
+
height: `var(--cmp-ghostButton-${size}-size)`,
|
|
4000
|
+
borderRadius: `var(--cmp-ghostButton-radius-${s.radius})`,
|
|
4077
4001
|
...style
|
|
4078
4002
|
},
|
|
4079
|
-
|
|
4003
|
+
children: [
|
|
4004
|
+
!disabled && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4005
|
+
"span",
|
|
4006
|
+
{
|
|
4007
|
+
"aria-hidden": true,
|
|
4008
|
+
className: "pointer-events-none absolute inset-0 rounded-[inherit] opacity-0 transition-opacity duration-200 group-hover/ghost-button:opacity-5",
|
|
4009
|
+
style: { background: `var(--cmp-ghostButton-${intent}-hover-bg)` }
|
|
4010
|
+
}
|
|
4011
|
+
),
|
|
4012
|
+
/* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: icon, size: s.icon, color: contentColor })
|
|
4013
|
+
]
|
|
4080
4014
|
}
|
|
4081
4015
|
);
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4016
|
+
if (!hasTooltip) return btn2;
|
|
4017
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(RPopover12__namespace.Root, { open, onOpenChange: setOpen, children: [
|
|
4018
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover12__namespace.Anchor, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4019
|
+
"span",
|
|
4020
|
+
{
|
|
4021
|
+
className: cn("inline-flex", anchorClassName),
|
|
4022
|
+
style: anchorStyle,
|
|
4023
|
+
onMouseEnter: openNow,
|
|
4024
|
+
onMouseLeave: startHide,
|
|
4025
|
+
onFocus: openNow,
|
|
4026
|
+
onBlur: startHide,
|
|
4027
|
+
children: btn2
|
|
4028
|
+
}
|
|
4029
|
+
) }),
|
|
4030
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover12__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4031
|
+
RPopover12__namespace.Content,
|
|
4032
|
+
{
|
|
4033
|
+
side: "top",
|
|
4034
|
+
sideOffset: 4,
|
|
4035
|
+
className: cn("z-50", FLOATING_SLIDE_ANIM),
|
|
4036
|
+
"aria-hidden": true,
|
|
4037
|
+
onOpenAutoFocus: (e) => e.preventDefault(),
|
|
4038
|
+
onMouseEnter: cancelHide,
|
|
4039
|
+
onMouseLeave: startHide,
|
|
4040
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(STag, { shape: "square", size: "xs", color: "grey", label: text })
|
|
4041
|
+
}
|
|
4042
|
+
) })
|
|
4043
|
+
] });
|
|
4044
|
+
}
|
|
4045
|
+
|
|
4046
|
+
// src/lib/sanitize-inline-html.ts
|
|
4047
|
+
var ALLOWED_INLINE_TAGS = /* @__PURE__ */ new Set(["A", "B", "STRONG", "I", "EM", "BR", "SPAN"]);
|
|
4048
|
+
var ALLOWED_ATTRS_BY_TAG = {
|
|
4049
|
+
A: /* @__PURE__ */ new Set(["href", "target", "rel", "class"])
|
|
4086
4050
|
};
|
|
4087
|
-
var
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4051
|
+
var COMMON_ALLOWED_ATTRS = /* @__PURE__ */ new Set(["class"]);
|
|
4052
|
+
var SAFE_HREF_RE = /^(https?:|mailto:|tel:|\/|#|\.)/i;
|
|
4053
|
+
var DROP_CONTENT_TAGS = /* @__PURE__ */ new Set([
|
|
4054
|
+
"SCRIPT",
|
|
4055
|
+
"STYLE",
|
|
4056
|
+
"IFRAME",
|
|
4057
|
+
"OBJECT",
|
|
4058
|
+
"EMBED",
|
|
4059
|
+
"META",
|
|
4060
|
+
"LINK",
|
|
4061
|
+
"BASE",
|
|
4062
|
+
"NOSCRIPT",
|
|
4063
|
+
// SVG/MATH 는 foreign-content 파싱 모드로 전환되어 재직렬화 시 다른 트리로
|
|
4064
|
+
// 재파싱될 수 있다(mXSS 벡터). 인라인 라벨에 필요 없으므로 통째로 제거한다.
|
|
4065
|
+
"SVG",
|
|
4066
|
+
"MATH",
|
|
4067
|
+
"TEMPLATE"
|
|
4068
|
+
]);
|
|
4069
|
+
var escapeHtml = (value) => value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
4070
|
+
var sanitizeNode = (node) => {
|
|
4071
|
+
if (node.nodeType === Node.COMMENT_NODE) {
|
|
4072
|
+
node.remove();
|
|
4073
|
+
return;
|
|
4074
|
+
}
|
|
4075
|
+
if (node.nodeType !== Node.ELEMENT_NODE) return;
|
|
4076
|
+
const element = node;
|
|
4077
|
+
const tagName = element.tagName.toUpperCase();
|
|
4078
|
+
if (DROP_CONTENT_TAGS.has(tagName)) {
|
|
4079
|
+
element.remove();
|
|
4080
|
+
return;
|
|
4081
|
+
}
|
|
4082
|
+
Array.from(element.childNodes).forEach((child) => sanitizeNode(child));
|
|
4083
|
+
if (ALLOWED_INLINE_TAGS.has(tagName)) {
|
|
4084
|
+
if (element.hasAttribute("className")) {
|
|
4085
|
+
const val = element.getAttribute("className");
|
|
4086
|
+
element.removeAttribute("className");
|
|
4087
|
+
if (!element.hasAttribute("class")) element.setAttribute("class", val);
|
|
4095
4088
|
}
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
}
|
|
4089
|
+
const allowedAttrs = ALLOWED_ATTRS_BY_TAG[tagName] ?? COMMON_ALLOWED_ATTRS;
|
|
4090
|
+
Array.from(element.attributes).forEach((attr) => {
|
|
4091
|
+
if (!allowedAttrs.has(attr.name)) element.removeAttribute(attr.name);
|
|
4100
4092
|
});
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4093
|
+
if (tagName === "A") {
|
|
4094
|
+
const href = element.getAttribute("href");
|
|
4095
|
+
if (href !== null && href !== "" && !SAFE_HREF_RE.test(href)) element.removeAttribute("href");
|
|
4096
|
+
if (element.hasAttribute("target")) {
|
|
4097
|
+
element.setAttribute("rel", "noopener noreferrer");
|
|
4098
|
+
}
|
|
4099
|
+
}
|
|
4100
|
+
return;
|
|
4101
|
+
}
|
|
4102
|
+
const parent = element.parentNode;
|
|
4103
|
+
if (parent == null) return;
|
|
4104
|
+
while (element.firstChild) parent.insertBefore(element.firstChild, element);
|
|
4105
|
+
parent.removeChild(element);
|
|
4106
|
+
};
|
|
4107
|
+
var sanitizeInlineHtml = (value) => {
|
|
4108
|
+
if (typeof document === "undefined") return escapeHtml(value);
|
|
4109
|
+
const template = document.createElement("template");
|
|
4110
|
+
template.innerHTML = value;
|
|
4111
|
+
Array.from(template.content.childNodes).forEach((child) => sanitizeNode(child));
|
|
4112
|
+
return template.innerHTML;
|
|
4113
|
+
};
|
|
4114
|
+
var HIDE_DELAY_MS = 100;
|
|
4115
|
+
function useBody(content, message = []) {
|
|
4116
|
+
if (content != null) return content;
|
|
4117
|
+
if (message.length === 0) return null;
|
|
4118
|
+
const singleLine = message.length === 1;
|
|
4119
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: message.map((line, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4115
4120
|
"div",
|
|
4116
4121
|
{
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
),
|
|
4123
|
-
...rest,
|
|
4124
|
-
children: showDivider ? withDividers(children) : children
|
|
4125
|
-
}
|
|
4126
|
-
);
|
|
4127
|
-
});
|
|
4128
|
-
var SList2 = /* @__PURE__ */ withDisplayName(SListImpl, "SList");
|
|
4129
|
-
var DraggableGroupContext = /* @__PURE__ */ react.createContext(null);
|
|
4130
|
-
function useSDraggableGroup() {
|
|
4131
|
-
return react.useContext(DraggableGroupContext);
|
|
4122
|
+
className: singleLine ? "leading-[24px]" : void 0,
|
|
4123
|
+
dangerouslySetInnerHTML: { __html: sanitizeInlineHtml(line) }
|
|
4124
|
+
},
|
|
4125
|
+
i
|
|
4126
|
+
)) });
|
|
4132
4127
|
}
|
|
4133
|
-
function
|
|
4128
|
+
var STooltipImpl = /* @__PURE__ */ react.forwardRef(function STooltip({
|
|
4129
|
+
content,
|
|
4130
|
+
message = [],
|
|
4131
|
+
open: openProp,
|
|
4132
|
+
onOpenChange,
|
|
4133
|
+
trigger = "hover",
|
|
4134
|
+
placement = "top",
|
|
4135
|
+
sideOffset = 8,
|
|
4136
|
+
tooltipType = "default",
|
|
4137
|
+
showClose = false,
|
|
4138
|
+
disabled = false,
|
|
4134
4139
|
children,
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
const
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4140
|
+
icon = "helpOutline",
|
|
4141
|
+
iconSize = 12,
|
|
4142
|
+
color = "#01BB4B",
|
|
4143
|
+
ariaLabel,
|
|
4144
|
+
className,
|
|
4145
|
+
triggerClassName,
|
|
4146
|
+
style,
|
|
4147
|
+
contentProps
|
|
4148
|
+
}, ref) {
|
|
4149
|
+
const portalContainer = usePortalContainer();
|
|
4150
|
+
const [internalOpen, setInternalOpen] = react.useState(false);
|
|
4151
|
+
const isControlled = openProp !== void 0;
|
|
4152
|
+
const open = isControlled ? openProp : internalOpen;
|
|
4153
|
+
const hideTimer = react.useRef(void 0);
|
|
4154
|
+
const cancelHide = react.useCallback(() => {
|
|
4155
|
+
if (hideTimer.current) {
|
|
4156
|
+
clearTimeout(hideTimer.current);
|
|
4157
|
+
hideTimer.current = void 0;
|
|
4158
|
+
}
|
|
4159
|
+
}, []);
|
|
4160
|
+
const setOpenState = react.useCallback(
|
|
4161
|
+
(next) => {
|
|
4162
|
+
if (!isControlled) setInternalOpen(next);
|
|
4163
|
+
onOpenChange?.(next);
|
|
4151
4164
|
},
|
|
4152
|
-
[]
|
|
4165
|
+
[isControlled, onOpenChange]
|
|
4153
4166
|
);
|
|
4154
|
-
const
|
|
4155
|
-
(
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4167
|
+
const openNow = () => {
|
|
4168
|
+
cancelHide();
|
|
4169
|
+
setOpenState(true);
|
|
4170
|
+
};
|
|
4171
|
+
const startHide = () => {
|
|
4172
|
+
if (showClose) return;
|
|
4173
|
+
cancelHide();
|
|
4174
|
+
hideTimer.current = setTimeout(() => setOpenState(false), HIDE_DELAY_MS);
|
|
4175
|
+
};
|
|
4176
|
+
react.useImperativeHandle(
|
|
4177
|
+
ref,
|
|
4178
|
+
() => ({
|
|
4179
|
+
show: () => {
|
|
4180
|
+
cancelHide();
|
|
4181
|
+
setOpenState(true);
|
|
4182
|
+
},
|
|
4183
|
+
hide: () => {
|
|
4184
|
+
cancelHide();
|
|
4185
|
+
setOpenState(false);
|
|
4186
|
+
}
|
|
4187
|
+
}),
|
|
4188
|
+
[cancelHide, setOpenState]
|
|
4161
4189
|
);
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4190
|
+
const isHover = trigger === "hover";
|
|
4191
|
+
const isNone = trigger === "none";
|
|
4192
|
+
if (isNone && children == null && typeof console !== "undefined") {
|
|
4193
|
+
console.warn(
|
|
4194
|
+
'[STooltip] trigger="none" \uC740 \uC704\uCE58 \uAE30\uC900\uC774 \uB420 children \uC774 \uD544\uC694\uD569\uB2C8\uB2E4. \uC544\uC774\uCF58 \uD2B8\uB9AC\uAC70\uB85C \uD3F4\uBC31\uD569\uB2C8\uB2E4.'
|
|
4195
|
+
);
|
|
4196
|
+
}
|
|
4197
|
+
const body = useBody(content, message);
|
|
4198
|
+
const bg = `var(--cmp-tooltip-${tooltipType}-bg)`;
|
|
4199
|
+
const fg = `var(--cmp-tooltip-${tooltipType}-content)`;
|
|
4200
|
+
const triggerNode = children ?? /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("inline-flex cursor-pointer", triggerClassName), "aria-label": ariaLabel, children: /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: icon, size: iconSize, color }) });
|
|
4201
|
+
if (disabled || body == null) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: triggerNode });
|
|
4202
|
+
const {
|
|
4203
|
+
className: contentPropsClassName,
|
|
4204
|
+
style: contentPropsStyle,
|
|
4205
|
+
...restContentProps
|
|
4206
|
+
} = contentProps ?? {};
|
|
4207
|
+
const contentClass = cn(
|
|
4208
|
+
"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",
|
|
4209
|
+
FLOATING_SLIDE_ANIM,
|
|
4210
|
+
className,
|
|
4211
|
+
contentPropsClassName
|
|
4212
|
+
);
|
|
4213
|
+
const contentStyle = {
|
|
4214
|
+
background: bg,
|
|
4215
|
+
color: fg,
|
|
4216
|
+
fontWeight: tooltipType === "default" ? 500 : 700,
|
|
4217
|
+
...style,
|
|
4218
|
+
...contentPropsStyle
|
|
4219
|
+
};
|
|
4220
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(RPopover12__namespace.Root, { open, onOpenChange: setOpenState, children: [
|
|
4221
|
+
isNone ? (
|
|
4222
|
+
// 트리거 없음: children 을 래퍼 없이 그대로 앵커로 쓴다 (소비자 레이아웃 보존).
|
|
4223
|
+
// mouse/focus 핸들러가 없으므로 showClose 없이도 자동 닫힘이 발생하지 않는다.
|
|
4224
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover12__namespace.Anchor, { asChild: true, children: triggerNode })
|
|
4225
|
+
) : isHover ? (
|
|
4226
|
+
// hover: Anchor(위치 기준) + 직접 mouse 핸들러 — 클릭으로 토글되지 않도록 Trigger 미사용
|
|
4227
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover12__namespace.Anchor, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4228
|
+
"span",
|
|
4229
|
+
{
|
|
4230
|
+
className: "inline-flex",
|
|
4231
|
+
onMouseEnter: openNow,
|
|
4232
|
+
onMouseLeave: startHide,
|
|
4233
|
+
onFocus: openNow,
|
|
4234
|
+
onBlur: startHide,
|
|
4235
|
+
children: triggerNode
|
|
4236
|
+
}
|
|
4237
|
+
) })
|
|
4238
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(RPopover12__namespace.Trigger, { asChild: true, children: triggerNode }),
|
|
4239
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover12__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4240
|
+
RPopover12__namespace.Content,
|
|
4241
|
+
{
|
|
4242
|
+
side: placement,
|
|
4243
|
+
sideOffset,
|
|
4244
|
+
className: contentClass,
|
|
4245
|
+
style: contentStyle,
|
|
4246
|
+
onOpenAutoFocus: (e) => e.preventDefault(),
|
|
4247
|
+
onInteractOutside: (e) => {
|
|
4248
|
+
if (showClose || isNone) e.preventDefault();
|
|
4249
|
+
},
|
|
4250
|
+
onEscapeKeyDown: (e) => {
|
|
4251
|
+
if (showClose || isNone) e.preventDefault();
|
|
4252
|
+
},
|
|
4253
|
+
onMouseEnter: isHover ? cancelHide : void 0,
|
|
4254
|
+
onMouseLeave: isHover ? startHide : void 0,
|
|
4255
|
+
...restContentProps,
|
|
4256
|
+
children: [
|
|
4257
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-[12px]", children: [
|
|
4258
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children: body }),
|
|
4259
|
+
showClose && !isNone && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4260
|
+
SGhostButton,
|
|
4261
|
+
{
|
|
4262
|
+
icon: "close",
|
|
4263
|
+
size: "xs",
|
|
4264
|
+
intent: tooltipType === "default" ? "inverse" : "default",
|
|
4265
|
+
ariaLabel: "\uB2EB\uAE30",
|
|
4266
|
+
className: "shrink-0",
|
|
4267
|
+
onClick: () => {
|
|
4268
|
+
cancelHide();
|
|
4269
|
+
setOpenState(false);
|
|
4270
|
+
}
|
|
4271
|
+
}
|
|
4272
|
+
)
|
|
4273
|
+
] }),
|
|
4274
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover12__namespace.Arrow, { width: 16, height: 12, style: { fill: bg } })
|
|
4275
|
+
]
|
|
4276
|
+
}
|
|
4277
|
+
) })
|
|
4278
|
+
] });
|
|
4279
|
+
});
|
|
4280
|
+
var STooltip2 = /* @__PURE__ */ withDisplayName(STooltipImpl, "STooltip");
|
|
4281
|
+
function runRules(value, rules) {
|
|
4282
|
+
if (!rules || rules.length === 0) return "";
|
|
4283
|
+
for (const rule of rules) {
|
|
4284
|
+
const result = rule(value ?? "");
|
|
4285
|
+
if (result !== true) return typeof result === "string" ? result : "\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 \uAC12\uC785\uB2C8\uB2E4.";
|
|
4286
|
+
}
|
|
4287
|
+
return "";
|
|
4288
|
+
}
|
|
4289
|
+
var FormContext = /* @__PURE__ */ react.createContext(null);
|
|
4290
|
+
function useFormContext() {
|
|
4291
|
+
return react.useContext(FormContext);
|
|
4292
|
+
}
|
|
4293
|
+
function useFormField(field) {
|
|
4294
|
+
const ctx = useFormContext();
|
|
4295
|
+
const cbRef = react.useRef(field);
|
|
4296
|
+
cbRef.current = field;
|
|
4297
|
+
const name = field.name ?? "";
|
|
4298
|
+
react.useEffect(() => {
|
|
4299
|
+
if (!ctx) return;
|
|
4300
|
+
return ctx.register({
|
|
4301
|
+
name,
|
|
4302
|
+
validate: () => cbRef.current.validate(),
|
|
4303
|
+
resetValidation: () => cbRef.current.resetValidation()
|
|
4304
|
+
});
|
|
4305
|
+
}, [ctx, name]);
|
|
4306
|
+
}
|
|
4307
|
+
var FIELD_SIZE = {
|
|
4308
|
+
sm: { height: 28, radius: 4, fieldGap: 12, labelGap: 6, fontSize: 12, lineHeight: 20, icon: 16 },
|
|
4309
|
+
md: { height: 36, radius: 6, fieldGap: 16, labelGap: 8, fontSize: 14, lineHeight: 24, icon: 16 }
|
|
4310
|
+
};
|
|
4311
|
+
var ALIGN = {
|
|
4312
|
+
start: "flex-start",
|
|
4313
|
+
center: "center",
|
|
4314
|
+
end: "flex-end"
|
|
4315
|
+
};
|
|
4316
|
+
var FOCUS_RING_SHADOW = "0px 0px 4px 0px #0071ff66";
|
|
4317
|
+
var cssLen = (v) => v === void 0 || v === "" || v === 0 ? void 0 : typeof v === "number" ? `${v}px` : v;
|
|
4318
|
+
var SField = /* @__PURE__ */ react.forwardRef(function SField2({
|
|
4319
|
+
name,
|
|
4320
|
+
label = "",
|
|
4321
|
+
icon,
|
|
4322
|
+
iconColor,
|
|
4323
|
+
labelTooltip = "",
|
|
4324
|
+
labelTooltipProps,
|
|
4325
|
+
labelWidth,
|
|
4326
|
+
labelHeight,
|
|
4327
|
+
size = "sm",
|
|
4328
|
+
addonLabel = "",
|
|
4329
|
+
addonAlign = "start",
|
|
4330
|
+
error = false,
|
|
4331
|
+
errorMessage = "",
|
|
4332
|
+
status,
|
|
4333
|
+
focused = false,
|
|
4334
|
+
hovered = false,
|
|
4335
|
+
rules: _rules,
|
|
4336
|
+
hint = "",
|
|
4337
|
+
disabled = false,
|
|
4338
|
+
readOnly = false,
|
|
4339
|
+
width,
|
|
4340
|
+
minWidth,
|
|
4341
|
+
maxWidth,
|
|
4342
|
+
multiline = false,
|
|
4343
|
+
borderless = false,
|
|
4344
|
+
children,
|
|
4345
|
+
className,
|
|
4346
|
+
style,
|
|
4347
|
+
onMouseEnter,
|
|
4348
|
+
onMouseLeave
|
|
4349
|
+
}, ref) {
|
|
4350
|
+
const rootRef = react.useRef(null);
|
|
4351
|
+
react.useImperativeHandle(
|
|
4352
|
+
ref,
|
|
4353
|
+
() => ({
|
|
4354
|
+
focus: () => {
|
|
4355
|
+
const root = rootRef.current;
|
|
4356
|
+
if (!root) return;
|
|
4357
|
+
const focusable = root.querySelector(
|
|
4358
|
+
"input,textarea,select,button,[tabindex]"
|
|
4359
|
+
);
|
|
4360
|
+
focusable?.focus();
|
|
4361
|
+
root.scrollIntoView({ block: "nearest" });
|
|
4362
|
+
}
|
|
4363
|
+
}),
|
|
4364
|
+
[]
|
|
4365
|
+
);
|
|
4366
|
+
const s = FIELD_SIZE[size];
|
|
4367
|
+
if (label !== "" && addonLabel !== "" && typeof console !== "undefined") {
|
|
4368
|
+
console.warn(
|
|
4369
|
+
"[SField] label \uACFC addonLabel \uC740 \uD568\uAED8 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. addonLabel \uC744 \uBB34\uC2DC\uD569\uB2C8\uB2E4."
|
|
4370
|
+
);
|
|
4371
|
+
}
|
|
4372
|
+
const effectiveAddonLabel = label !== "" ? "" : addonLabel;
|
|
4373
|
+
const resolvedError = status === "error" || status === void 0 && error;
|
|
4374
|
+
const resolvedSuccess = status === "pass";
|
|
4375
|
+
const showError = resolvedError && errorMessage !== "";
|
|
4376
|
+
const interactive = !disabled && !readOnly;
|
|
4377
|
+
const isPercentWidth = typeof width === "string" && width.trim().endsWith("%");
|
|
4378
|
+
const resolvedWidth = fieldWidthValue(width);
|
|
4379
|
+
const hug = resolvedWidth !== void 0 && !isPercentWidth;
|
|
4380
|
+
const addonWidth = effectiveAddonLabel !== "" ? cssLen(labelWidth) : void 0;
|
|
4381
|
+
const maxWidthValue = fieldWidthValue(maxWidth);
|
|
4382
|
+
const resolvedMaxWidth = maxWidthValue === void 0 || effectiveAddonLabel === "" ? maxWidthValue : addonWidth ? `calc(${maxWidthValue} + ${addonWidth})` : void 0;
|
|
4383
|
+
const borderColor = borderless ? "transparent" : disabled ? "var(--color-grey-45)" : (
|
|
4384
|
+
// focus·hover(제어 prop) 가 error/pass 보다 우선 — 실제 :hover/:focus-within 클래스도
|
|
4385
|
+
// 같은 순서로 --field-bc 를 덮으므로, prop 으로 흉내 낸 상태도 그와 같게 둔다.
|
|
4386
|
+
interactive && (focused || hovered) ? "var(--sys-color-field-border-focus)" : resolvedSuccess ? "var(--sys-color-field-border-success)" : resolvedError ? "var(--sys-color-field-border-danger)" : "var(--sys-color-field-border-default)"
|
|
4387
|
+
);
|
|
4388
|
+
const bgColor = borderless ? "transparent" : disabled ? "var(--color-grey-30)" : readOnly ? "var(--sys-color-field-bg-readOnly)" : "var(--sys-color-field-bg-default)";
|
|
4389
|
+
const textColor = disabled ? "var(--color-grey-65)" : readOnly ? "var(--sys-color-field-text-readOnly)" : "var(--sys-color-field-text-default)";
|
|
4390
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4391
|
+
"div",
|
|
4392
|
+
{
|
|
4393
|
+
ref: rootRef,
|
|
4394
|
+
"data-name": name || void 0,
|
|
4395
|
+
className: cn(
|
|
4396
|
+
"h-fit flex-col",
|
|
4397
|
+
// hug 시 inline-flex 를 유지하면 기존에 세로로 쌓여 있던 필드들이 한 줄에 붙어버리므로
|
|
4398
|
+
// 블록 레벨(flex)로 두어 쌓임은 그대로 유지한다. 나란히 놓으려면 부모를 flex 로.
|
|
4399
|
+
hug ? "flex w-fit max-w-full" : "inline-flex w-full",
|
|
4400
|
+
className
|
|
4401
|
+
),
|
|
4402
|
+
style,
|
|
4403
|
+
onMouseEnter,
|
|
4404
|
+
onMouseLeave,
|
|
4405
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-start", children: [
|
|
4406
|
+
label !== "" && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4407
|
+
"div",
|
|
4408
|
+
{
|
|
4409
|
+
className: "flex shrink-0 items-center font-bold text-(--sys-color-field-text-default)",
|
|
4410
|
+
style: {
|
|
4411
|
+
height: cssLen(labelHeight) ?? s.height,
|
|
4412
|
+
marginRight: s.fieldGap,
|
|
4413
|
+
width: cssLen(labelWidth),
|
|
4414
|
+
fontSize: s.fontSize,
|
|
4415
|
+
lineHeight: `${s.lineHeight}px`
|
|
4416
|
+
},
|
|
4417
|
+
children: [
|
|
4418
|
+
icon && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4419
|
+
SIcon,
|
|
4420
|
+
{
|
|
4421
|
+
name: icon,
|
|
4422
|
+
size: s.icon,
|
|
4423
|
+
color: iconColor,
|
|
4424
|
+
style: { marginRight: s.labelGap }
|
|
4425
|
+
}
|
|
4426
|
+
),
|
|
4427
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 overflow-hidden text-ellipsis whitespace-nowrap", children: label }),
|
|
4428
|
+
(labelTooltip !== "" || labelTooltipProps) && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 flex items-center", style: { marginLeft: s.labelGap }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4429
|
+
STooltip2,
|
|
4430
|
+
{
|
|
4431
|
+
message: labelTooltip !== "" ? [labelTooltip] : void 0,
|
|
4432
|
+
iconSize: s.icon,
|
|
4433
|
+
...labelTooltipProps
|
|
4434
|
+
}
|
|
4435
|
+
) })
|
|
4436
|
+
]
|
|
4437
|
+
}
|
|
4438
|
+
),
|
|
4439
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4440
|
+
"div",
|
|
4441
|
+
{
|
|
4442
|
+
className: cn("flex min-w-0 flex-col", !hug && !isPercentWidth && "flex-1"),
|
|
4443
|
+
style: {
|
|
4444
|
+
width: resolvedWidth,
|
|
4445
|
+
minWidth: fieldWidthValue(minWidth),
|
|
4446
|
+
maxWidth: resolvedMaxWidth
|
|
4447
|
+
},
|
|
4448
|
+
children: [
|
|
4449
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4450
|
+
"div",
|
|
4451
|
+
{
|
|
4452
|
+
className: cn(
|
|
4453
|
+
"relative box-border flex min-w-0 items-stretch border border-solid border-(--field-bc)",
|
|
4454
|
+
// 둘 다 넘친 것을 잘라 내지만 clip 은 스크롤 상자를 만들지 않는다. hidden 이면
|
|
4455
|
+
// 이 상자가 스크롤포트가 되어 안쪽의 position:sticky 가 페이지 스크롤을 따라가지
|
|
4456
|
+
// 못한다 (SEditor 의 고정 툴바). 여러 줄 필드에서만 바꿔 파급을 좁힌다.
|
|
4457
|
+
multiline ? "overflow-clip" : "overflow-hidden",
|
|
4458
|
+
interactive && !borderless && "hover:border-(--sys-color-field-border-focus) hover:shadow-[0px_0px_4px_0px_#0071ff66] focus-within:border-(--sys-color-field-border-focus) focus-within:shadow-[0px_0px_4px_0px_#0071ff66]",
|
|
4459
|
+
disabled && "cursor-not-allowed"
|
|
4460
|
+
),
|
|
4461
|
+
style: {
|
|
4462
|
+
// @ts-expect-error CSS 변수
|
|
4463
|
+
"--field-bc": borderColor,
|
|
4464
|
+
// focused/hovered prop이 명시된 경우 강조를 즉시 반영
|
|
4465
|
+
...interactive && !borderless && (focused || hovered) ? { boxShadow: FOCUS_RING_SHADOW } : {},
|
|
4466
|
+
...multiline ? { minHeight: s.height } : { height: s.height },
|
|
4467
|
+
"borderRadius": s.radius,
|
|
4468
|
+
"background": bgColor,
|
|
4469
|
+
"color": textColor
|
|
4470
|
+
},
|
|
4471
|
+
"data-focused": focused || void 0,
|
|
4472
|
+
"data-hovered": hovered || void 0,
|
|
4473
|
+
children: [
|
|
4474
|
+
effectiveAddonLabel !== "" && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4475
|
+
"div",
|
|
4476
|
+
{
|
|
4477
|
+
className: "flex shrink-0 items-center gap-(--cmp-field-addonLabel-gap) whitespace-nowrap border-r border-solid px-(--cmp-field-addonLabel-paddingX) text-12 font-medium leading-sd-20",
|
|
4478
|
+
style: {
|
|
4479
|
+
// 원본 sd-field: labelWidth가 addon 폭(--sd-field-addon-width)에도 적용됨
|
|
4480
|
+
width: cssLen(labelWidth),
|
|
4481
|
+
justifyContent: ALIGN[addonAlign],
|
|
4482
|
+
background: "var(--cmp-field-addonLabel-bg)",
|
|
4483
|
+
borderRightColor: disabled ? "var(--cmp-field-addonLabel-border-disabled)" : "var(--cmp-field-addonLabel-border-default)",
|
|
4484
|
+
borderTopLeftRadius: s.radius - 1,
|
|
4485
|
+
borderBottomLeftRadius: s.radius - 1
|
|
4486
|
+
},
|
|
4487
|
+
children: [
|
|
4488
|
+
icon && !label && /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: icon, size: s.icon, color: iconColor }),
|
|
4489
|
+
effectiveAddonLabel
|
|
4490
|
+
]
|
|
4491
|
+
}
|
|
4492
|
+
),
|
|
4493
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex min-w-0 flex-1", multiline && "bg-inherit"), children })
|
|
4494
|
+
]
|
|
4495
|
+
}
|
|
4496
|
+
),
|
|
4497
|
+
showError ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-(--cmp-field-contents-gap) px-(--cmp-field-message-paddingX) text-12 font-normal leading-sd-20 text-(--cmp-field-errorMessage-color)", children: errorMessage }) : hint !== "" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-(--cmp-field-contents-gap) px-(--cmp-field-message-paddingX) text-12 font-normal leading-sd-20 text-(--cmp-field-hint-color)", children: hint }) : null
|
|
4498
|
+
]
|
|
4499
|
+
}
|
|
4500
|
+
)
|
|
4501
|
+
] })
|
|
4502
|
+
}
|
|
4503
|
+
);
|
|
4504
|
+
});
|
|
4505
|
+
|
|
4506
|
+
// src/lib/autofill.ts
|
|
4507
|
+
var AUTOFILL_RESET_CLASS = "autofill:[-webkit-text-fill-color:currentColor] autofill:[box-shadow:0_0_0_1000px_var(--sys-color-field-bg-default)_inset] autofill:[transition:background-color_5000s_ease-in-out_0s] [&:-webkit-autofill]:[-webkit-text-fill-color:currentColor] [&:-webkit-autofill]:[box-shadow:0_0_0_1000px_var(--sys-color-field-bg-default)_inset] [&:-webkit-autofill]:[transition:background-color_5000s_ease-in-out_0s]";
|
|
4508
|
+
var TEXTAREA_SIZE = {
|
|
4509
|
+
sm: {
|
|
4510
|
+
fontSize: 12,
|
|
4511
|
+
lineHeight: 20,
|
|
4512
|
+
paddingX: "var(--cmp-textinput-sm-paddingX)",
|
|
4513
|
+
paddingY: "var(--cmp-textinput-sm-paddingY)"
|
|
4514
|
+
},
|
|
4515
|
+
md: {
|
|
4516
|
+
fontSize: 14,
|
|
4517
|
+
lineHeight: 24,
|
|
4518
|
+
paddingX: "var(--cmp-textinput-md-paddingX)",
|
|
4519
|
+
paddingY: "var(--cmp-textinput-md-paddingY)"
|
|
4520
|
+
}
|
|
4521
|
+
};
|
|
4522
|
+
var MIN_ROWS = 2;
|
|
4523
|
+
var STextarea = /* @__PURE__ */ react.forwardRef(function STextarea2({
|
|
4524
|
+
value,
|
|
4525
|
+
onValueChange,
|
|
4526
|
+
onChange,
|
|
4527
|
+
size = "sm",
|
|
4528
|
+
rows = MIN_ROWS,
|
|
4529
|
+
autogrow = false,
|
|
4530
|
+
maxRows,
|
|
4531
|
+
rules,
|
|
4532
|
+
status,
|
|
4533
|
+
focused,
|
|
4534
|
+
hovered,
|
|
4535
|
+
textareaClassName,
|
|
4536
|
+
textareaStyle,
|
|
4537
|
+
label,
|
|
4538
|
+
labelWidth,
|
|
4539
|
+
icon,
|
|
4540
|
+
iconColor,
|
|
4541
|
+
labelTooltip,
|
|
4542
|
+
labelTooltipProps,
|
|
4543
|
+
addonLabel,
|
|
4544
|
+
addonAlign,
|
|
4545
|
+
hint,
|
|
4546
|
+
error,
|
|
4547
|
+
errorMessage,
|
|
4548
|
+
width,
|
|
4549
|
+
disabled = false,
|
|
4550
|
+
readOnly = false,
|
|
4551
|
+
placeholder = "\uC785\uB825\uD574 \uC8FC\uC138\uC694.",
|
|
4552
|
+
onBlur,
|
|
4553
|
+
className,
|
|
4554
|
+
style,
|
|
4555
|
+
...rest
|
|
4556
|
+
}, ref) {
|
|
4557
|
+
const p = TEXTAREA_SIZE[size];
|
|
4558
|
+
const heightForRows = (n) => `calc(${p.lineHeight * n}px + ${p.paddingY} * 2)`;
|
|
4559
|
+
const minHeight = heightForRows(MIN_ROWS);
|
|
4560
|
+
const maxHeight = autogrow && maxRows != null ? heightForRows(maxRows) : void 0;
|
|
4561
|
+
const [ruleError, setRuleError] = react.useState("");
|
|
4562
|
+
const innerRef = react.useRef(null);
|
|
4563
|
+
const setRefs2 = react.useCallback(
|
|
4564
|
+
(node) => {
|
|
4565
|
+
innerRef.current = node;
|
|
4566
|
+
if (typeof ref === "function") ref(node);
|
|
4567
|
+
else if (ref) ref.current = node;
|
|
4568
|
+
},
|
|
4569
|
+
[ref]
|
|
4570
|
+
);
|
|
4571
|
+
react.useLayoutEffect(() => {
|
|
4572
|
+
const el = innerRef.current;
|
|
4573
|
+
if (el == null) return;
|
|
4574
|
+
if (!autogrow) {
|
|
4575
|
+
el.style.height = "";
|
|
4576
|
+
return;
|
|
4577
|
+
}
|
|
4578
|
+
el.style.height = "auto";
|
|
4579
|
+
el.style.height = `${el.scrollHeight}px`;
|
|
4580
|
+
}, [autogrow, maxHeight, minHeight, rows, value]);
|
|
4581
|
+
useFormField({
|
|
4582
|
+
name: rest.name,
|
|
4583
|
+
validate: () => {
|
|
4584
|
+
const msg = runRules(value, rules);
|
|
4585
|
+
setRuleError(msg);
|
|
4586
|
+
return msg === "";
|
|
4587
|
+
},
|
|
4588
|
+
resetValidation: () => setRuleError("")
|
|
4589
|
+
});
|
|
4590
|
+
const resolvedError = error || ruleError !== "";
|
|
4591
|
+
const resolvedErrorMessage = ruleError !== "" ? ruleError : errorMessage;
|
|
4592
|
+
const resolvedStatus = status ?? (rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0);
|
|
4593
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4594
|
+
SField,
|
|
4595
|
+
{
|
|
4596
|
+
label,
|
|
4597
|
+
labelWidth,
|
|
4598
|
+
icon,
|
|
4599
|
+
iconColor,
|
|
4600
|
+
labelTooltip,
|
|
4601
|
+
labelTooltipProps,
|
|
4602
|
+
addonLabel,
|
|
4603
|
+
addonAlign,
|
|
4604
|
+
hint,
|
|
4605
|
+
size,
|
|
4606
|
+
error: resolvedError,
|
|
4607
|
+
status: resolvedStatus,
|
|
4608
|
+
focused,
|
|
4609
|
+
hovered,
|
|
4610
|
+
errorMessage: resolvedErrorMessage,
|
|
4611
|
+
width,
|
|
4612
|
+
disabled,
|
|
4613
|
+
readOnly,
|
|
4614
|
+
multiline: true,
|
|
4615
|
+
className,
|
|
4616
|
+
style,
|
|
4617
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4618
|
+
"textarea",
|
|
4619
|
+
{
|
|
4620
|
+
ref: setRefs2,
|
|
4621
|
+
value: value ?? "",
|
|
4622
|
+
rows,
|
|
4623
|
+
disabled,
|
|
4624
|
+
readOnly,
|
|
4625
|
+
placeholder,
|
|
4626
|
+
onChange: (e) => {
|
|
4627
|
+
onChange?.(e);
|
|
4628
|
+
onValueChange?.(e.target.value);
|
|
4629
|
+
if (ruleError !== "") setRuleError(runRules(e.target.value, rules));
|
|
4630
|
+
},
|
|
4631
|
+
onBlur: (e) => {
|
|
4632
|
+
onBlur?.(e);
|
|
4633
|
+
if (rules && rules.length > 0) setRuleError(runRules(e.target.value, rules));
|
|
4634
|
+
},
|
|
4635
|
+
className: cn(
|
|
4636
|
+
"w-full border-0 bg-transparent outline-none placeholder:text-[color:var(--sys-color-field-text-placeholder)] disabled:cursor-not-allowed",
|
|
4637
|
+
// autogrow 와 끌어서 늘리기는 같은 높이를 두고 다투므로 함께 두지 않는다
|
|
4638
|
+
autogrow ? "resize-none" : "resize-y",
|
|
4639
|
+
AUTOFILL_RESET_CLASS,
|
|
4640
|
+
textareaClassName
|
|
4641
|
+
),
|
|
4642
|
+
style: {
|
|
4643
|
+
minHeight,
|
|
4644
|
+
maxHeight,
|
|
4645
|
+
// 상한이 있으면 거기 닿았을 때 안에서 스크롤한다. 상한이 없으면 높이가 늘 내용과
|
|
4646
|
+
// 같으므로 스크롤바가 나올 일이 없고, 반올림으로 1px 이 넘쳐 깜빡이는 것만 막는다.
|
|
4647
|
+
overflowY: autogrow ? maxRows != null ? "auto" : "hidden" : void 0,
|
|
4648
|
+
padding: `${p.paddingY} ${p.paddingX}`,
|
|
4649
|
+
fontSize: p.fontSize,
|
|
4650
|
+
lineHeight: `${p.lineHeight}px`,
|
|
4651
|
+
color: disabled ? "var(--cmp-textinput-text-disabled)" : "var(--sys-color-field-text-default)",
|
|
4652
|
+
...textareaStyle
|
|
4653
|
+
},
|
|
4654
|
+
...rest
|
|
4655
|
+
}
|
|
4656
|
+
)
|
|
4657
|
+
}
|
|
4658
|
+
);
|
|
4659
|
+
});
|
|
4660
|
+
var DEFAULT_PLACEHOLDER = "\uBA54\uC2DC\uC9C0\uB97C \uC785\uB825\uD574 \uC8FC\uC138\uC694...";
|
|
4661
|
+
var FIELD_MIN_HEIGHT = 48;
|
|
4662
|
+
var FIELD_BORDER = 1;
|
|
4663
|
+
var TEXTAREA_MIN_HEIGHT = FIELD_MIN_HEIGHT - FIELD_BORDER * 2;
|
|
4664
|
+
var BUTTON_BOTTOM_INSET = `calc((${FIELD_MIN_HEIGHT}px - var(--cmp-ghostButton-md-size)) / 2)`;
|
|
4665
|
+
var DEFAULT_MAX_ROWS = 5;
|
|
4666
|
+
var SChatInputImpl = /* @__PURE__ */ react.forwardRef(function SChatInput({
|
|
4667
|
+
value = "",
|
|
4668
|
+
onValueChange,
|
|
4669
|
+
placeholder = DEFAULT_PLACEHOLDER,
|
|
4670
|
+
disabled = false,
|
|
4671
|
+
onSend,
|
|
4672
|
+
onAttach,
|
|
4673
|
+
busy = false,
|
|
4674
|
+
onStop,
|
|
4675
|
+
footerAction,
|
|
4676
|
+
maxRows = DEFAULT_MAX_ROWS,
|
|
4677
|
+
className,
|
|
4678
|
+
style,
|
|
4679
|
+
textareaClassName,
|
|
4680
|
+
...rest
|
|
4681
|
+
}, ref) {
|
|
4682
|
+
const canSend = !disabled && !busy && value.trim() !== "";
|
|
4683
|
+
const send = react.useCallback(() => {
|
|
4684
|
+
if (!canSend) return;
|
|
4685
|
+
onSend?.(value);
|
|
4686
|
+
}, [canSend, onSend, value]);
|
|
4687
|
+
const handleKeyDown = (e) => {
|
|
4688
|
+
rest.onKeyDown?.(e);
|
|
4689
|
+
if (e.key !== "Enter" || e.shiftKey || e.nativeEvent.isComposing) return;
|
|
4690
|
+
e.preventDefault();
|
|
4691
|
+
send();
|
|
4692
|
+
};
|
|
4693
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col bg-(--sys-color-field-bg-default)", className), style, children: [
|
|
4694
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-end gap-sd-8 p-sd-12", children: [
|
|
4695
|
+
onAttach != null && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4696
|
+
SGhostButton,
|
|
4697
|
+
{
|
|
4698
|
+
icon: "attachFile",
|
|
4699
|
+
size: "md",
|
|
4700
|
+
ariaLabel: "\uD30C\uC77C \uCCA8\uBD80",
|
|
4701
|
+
disabled,
|
|
4702
|
+
onClick: onAttach,
|
|
4703
|
+
style: { marginBottom: BUTTON_BOTTOM_INSET }
|
|
4704
|
+
}
|
|
4705
|
+
),
|
|
4706
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4707
|
+
STextarea,
|
|
4708
|
+
{
|
|
4709
|
+
ref,
|
|
4710
|
+
size: "md",
|
|
4711
|
+
rows: 1,
|
|
4712
|
+
autogrow: true,
|
|
4713
|
+
maxRows,
|
|
4714
|
+
width: "100%",
|
|
4715
|
+
value,
|
|
4716
|
+
onValueChange,
|
|
4717
|
+
placeholder,
|
|
4718
|
+
disabled,
|
|
4719
|
+
className: "min-w-0 flex-1",
|
|
4720
|
+
textareaClassName,
|
|
4721
|
+
textareaStyle: { minHeight: TEXTAREA_MIN_HEIGHT },
|
|
4722
|
+
...rest,
|
|
4723
|
+
onKeyDown: handleKeyDown
|
|
4724
|
+
}
|
|
4725
|
+
),
|
|
4726
|
+
busy ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4727
|
+
SGhostButton,
|
|
4728
|
+
{
|
|
4729
|
+
icon: "stop",
|
|
4730
|
+
size: "md",
|
|
4731
|
+
intent: "danger",
|
|
4732
|
+
ariaLabel: "\uC751\uB2F5 \uC911\uC9C0",
|
|
4733
|
+
onClick: onStop,
|
|
4734
|
+
style: { marginBottom: BUTTON_BOTTOM_INSET }
|
|
4735
|
+
}
|
|
4736
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
4737
|
+
SGhostButton,
|
|
4738
|
+
{
|
|
4739
|
+
icon: "send",
|
|
4740
|
+
size: "md",
|
|
4741
|
+
intent: "subAction",
|
|
4742
|
+
ariaLabel: "\uC804\uC1A1",
|
|
4743
|
+
disabled: !canSend,
|
|
4744
|
+
onClick: send,
|
|
4745
|
+
style: { marginBottom: BUTTON_BOTTOM_INSET }
|
|
4746
|
+
}
|
|
4747
|
+
)
|
|
4748
|
+
] }),
|
|
4749
|
+
footerAction != null && // 보조 액션은 입력창 아래 가운데에 선다 — 주 동작(전송)과 층이 다름을 자리로 드러낸다.
|
|
4750
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center", children: footerAction })
|
|
4751
|
+
] });
|
|
4752
|
+
});
|
|
4753
|
+
var SChatInput2 = /* @__PURE__ */ withDisplayName(SChatInputImpl, "SChatInput");
|
|
4754
|
+
var CHAT_MESSAGE_DIRECTIONS = ["incoming", "outgoing"];
|
|
4755
|
+
var CHAT_MESSAGE_VARIANTS = ["default", "template"];
|
|
4756
|
+
var BUBBLE_SURFACE = {
|
|
4757
|
+
incoming: "bg-(--sys-color-bg-screen) text-(--sys-color-fg-primary)",
|
|
4758
|
+
outgoing: "bg-(--sys-color-bg-brand) text-(--sys-color-fg-inverse)",
|
|
4759
|
+
template: "bg-(--sys-color-bg-accentFaint) text-(--sys-color-fg-deep)"
|
|
4760
|
+
};
|
|
4761
|
+
var CHAT_MESSAGE_READ_STATUSES = ["read", "unread"];
|
|
4762
|
+
var READ_STATUS_LABEL = {
|
|
4763
|
+
read: "\uC77D\uC74C",
|
|
4764
|
+
unread: "\uC548 \uC77D\uC74C"
|
|
4765
|
+
};
|
|
4766
|
+
var READ_STATUS_COLOR = {
|
|
4767
|
+
read: "text-(--sys-color-fg-tertiary)",
|
|
4768
|
+
unread: "text-(--sys-color-fg-warning)"
|
|
4769
|
+
};
|
|
4770
|
+
var AVATAR_SIZE = 32;
|
|
4771
|
+
var AVATAR_ROW_HEIGHT = 40;
|
|
4772
|
+
var AVATAR_ICON_SIZE = 40;
|
|
4773
|
+
function Avatar({ src, alt, placeholder }) {
|
|
4774
|
+
if (placeholder) {
|
|
4775
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", style: { width: AVATAR_SIZE, height: AVATAR_ROW_HEIGHT } });
|
|
4776
|
+
}
|
|
4777
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex shrink-0 items-center", style: { height: AVATAR_ROW_HEIGHT }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4778
|
+
"div",
|
|
4779
|
+
{
|
|
4780
|
+
className: "relative overflow-hidden rounded-full bg-(--sys-color-bg-screen)",
|
|
4781
|
+
style: { width: AVATAR_SIZE, height: AVATAR_SIZE },
|
|
4782
|
+
children: src != null ? /* @__PURE__ */ jsxRuntime.jsx(SImage, { src, alt: alt ?? "", fit: "cover", className: "h-full w-full" }) : (
|
|
4783
|
+
// 원 밖으로 나가는 만큼을 좌우로 나눠 가운데를 맞추고, 아래는 원이 자른다.
|
|
4784
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4785
|
+
SIcon,
|
|
4786
|
+
{
|
|
4787
|
+
name: "user",
|
|
4788
|
+
size: AVATAR_ICON_SIZE,
|
|
4789
|
+
color: "var(--sys-color-fg-quaternary)",
|
|
4790
|
+
className: "absolute top-0",
|
|
4791
|
+
style: { left: (AVATAR_SIZE - AVATAR_ICON_SIZE) / 2 }
|
|
4792
|
+
}
|
|
4793
|
+
)
|
|
4794
|
+
)
|
|
4795
|
+
}
|
|
4796
|
+
) });
|
|
4797
|
+
}
|
|
4798
|
+
var SChatMessageImpl = /* @__PURE__ */ react.forwardRef(function SChatMessage({
|
|
4799
|
+
direction = "incoming",
|
|
4800
|
+
sender,
|
|
4801
|
+
time,
|
|
4802
|
+
readStatus,
|
|
4803
|
+
avatarSrc,
|
|
4804
|
+
avatarAlt,
|
|
4805
|
+
continued = false,
|
|
4806
|
+
variant = "default",
|
|
4807
|
+
actions,
|
|
4808
|
+
messages,
|
|
4809
|
+
className,
|
|
4810
|
+
...rest
|
|
4811
|
+
}, ref) {
|
|
4812
|
+
const outgoing = direction === "outgoing";
|
|
4813
|
+
const surface = variant === "template" ? "template" : direction;
|
|
4814
|
+
const bubbles = messages ?? [];
|
|
4815
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4816
|
+
"div",
|
|
4817
|
+
{
|
|
4818
|
+
ref,
|
|
4819
|
+
className: cn(
|
|
4820
|
+
// 아바타와 본문 열이 같은 줄에 서고, 보낸 메시지는 좌우를 뒤집는다.
|
|
4821
|
+
// items-start 라 이름이 있든 없든 아바타는 언제나 첫 줄에 붙는다.
|
|
4822
|
+
"flex items-start gap-sd-12",
|
|
4823
|
+
outgoing && "flex-row-reverse",
|
|
4824
|
+
className
|
|
4825
|
+
),
|
|
4826
|
+
...rest,
|
|
4827
|
+
children: [
|
|
4828
|
+
!outgoing && /* @__PURE__ */ jsxRuntime.jsx(Avatar, { src: avatarSrc, alt: avatarAlt, placeholder: continued }),
|
|
4829
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex min-w-0 flex-col gap-sd-4", outgoing ? "items-end" : "items-start"), children: [
|
|
4830
|
+
!outgoing && !continued && sender != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "typo-body-sm-default px-sd-8 text-(--sys-color-fg-secondary)", children: sender }),
|
|
4831
|
+
bubbles.length > 0 && // 말풍선끼리는 이름·시각과의 간격(4px)보다 벌려 한 덩어리 안의 여러 발화로 읽히게 한다.
|
|
4832
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4833
|
+
"div",
|
|
4834
|
+
{
|
|
4835
|
+
className: cn("flex min-w-0 flex-col gap-sd-8", outgoing ? "items-end" : "items-start"),
|
|
4836
|
+
children: bubbles.map((message, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4837
|
+
"div",
|
|
4838
|
+
{
|
|
4839
|
+
className: cn(
|
|
4840
|
+
// 라운드 12px 은 대응 토큰이 없어 값으로 둔다 (디자인팀 토큰 추가 요청 대상).
|
|
4841
|
+
"typo-body-md-default max-w-full rounded-[12px] px-sd-16 py-sd-8",
|
|
4842
|
+
// 한글은 기본 규칙으로 두면 어절 한가운데서도 줄이 바뀐다 — 띄어쓰기에서만 끊고,
|
|
4843
|
+
// 끊을 자리가 없는 긴 토큰(URL·주문번호)만 흘려보낸다.
|
|
4844
|
+
"break-keep wrap-break-word",
|
|
4845
|
+
BUBBLE_SURFACE[surface]
|
|
4846
|
+
),
|
|
4847
|
+
children: message
|
|
4848
|
+
},
|
|
4849
|
+
index
|
|
4850
|
+
))
|
|
4851
|
+
}
|
|
4852
|
+
),
|
|
4853
|
+
(readStatus != null || time != null) && // 읽음 표시와 시각은 한 줄에 선다 — 읽음이 먼저, 시각이 뒤다.
|
|
4854
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "typo-body-sm-default flex items-center gap-sd-4 px-sd-8", children: [
|
|
4855
|
+
readStatus != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: READ_STATUS_COLOR[readStatus], children: READ_STATUS_LABEL[readStatus] }),
|
|
4856
|
+
time != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-(--sys-color-fg-tertiary)", children: time })
|
|
4857
|
+
] }),
|
|
4858
|
+
actions != null && // 버튼이 많아 한 줄에 안 들어가면 감싼다 — 넘쳐서 잘리는 것보다 낫다.
|
|
4859
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-wrap gap-sd-8 px-sd-8", outgoing && "justify-end"), children: actions })
|
|
4860
|
+
] })
|
|
4861
|
+
]
|
|
4862
|
+
}
|
|
4863
|
+
);
|
|
4864
|
+
});
|
|
4865
|
+
var SChatMessage2 = /* @__PURE__ */ withDisplayName(SChatMessageImpl, "SChatMessage");
|
|
4866
|
+
|
|
4867
|
+
// src/lib/z-index.ts
|
|
4868
|
+
var Z_INDEX = {
|
|
4869
|
+
baseFloating: 50,
|
|
4870
|
+
modalHost: 1e3,
|
|
4871
|
+
toast: 1100,
|
|
4872
|
+
loading: 1200,
|
|
4873
|
+
drag: 1300
|
|
4874
|
+
};
|
|
4875
|
+
var setRefs = (refs, value) => {
|
|
4876
|
+
refs.forEach((ref) => {
|
|
4877
|
+
if (typeof ref === "function") {
|
|
4878
|
+
ref(value);
|
|
4879
|
+
return;
|
|
4880
|
+
}
|
|
4881
|
+
if (ref) {
|
|
4882
|
+
ref.current = value;
|
|
4883
|
+
}
|
|
4884
|
+
});
|
|
4885
|
+
};
|
|
4886
|
+
function renderSlot(slot, state2) {
|
|
4887
|
+
return typeof slot === "function" ? slot(state2) : slot;
|
|
4888
|
+
}
|
|
4889
|
+
var SDraggableItemView = /* @__PURE__ */ react.forwardRef(
|
|
4890
|
+
function SDraggableItemView2({
|
|
4891
|
+
title,
|
|
4892
|
+
supportingText,
|
|
4893
|
+
supportingTextPosition,
|
|
4894
|
+
trailing,
|
|
4895
|
+
depth,
|
|
4896
|
+
accentStripe,
|
|
4897
|
+
bordered,
|
|
4898
|
+
selected,
|
|
4899
|
+
dense,
|
|
4900
|
+
size,
|
|
4901
|
+
dragging,
|
|
4902
|
+
disabled,
|
|
4903
|
+
hovered,
|
|
4904
|
+
dragHandleProps,
|
|
4905
|
+
onDragHandleMouseDown,
|
|
4906
|
+
className,
|
|
4907
|
+
style,
|
|
4908
|
+
...rest
|
|
4909
|
+
}, ref) {
|
|
4910
|
+
const renderState = { hovered, dragging, disabled };
|
|
4911
|
+
const titleNode = renderSlot(title, renderState);
|
|
4912
|
+
const supportingTextNode = renderSlot(supportingText, renderState);
|
|
4913
|
+
const hasSupportingText = supportingTextNode != null && supportingTextNode !== "";
|
|
4914
|
+
const trailingNode = renderSlot(trailing, renderState);
|
|
4915
|
+
const titleTypo = size === "sm" ? selected ? "typo-item-sm-selected" : "typo-item-sm-default" : selected ? "typo-item-md-selected" : "typo-item-md-default";
|
|
4916
|
+
const paddingYClass = dense ? size === "sm" ? "py-(--cmp-listDraggableItem-paddingY-sm-dense)" : "py-(--cmp-listDraggableItem-paddingY-md-dense)" : size === "sm" ? "py-(--cmp-listDraggableItem-paddingY-sm-normal)" : "py-(--cmp-listDraggableItem-paddingY-md-normal)";
|
|
4917
|
+
const normalizedDepth = Math.max(1, Math.floor(depth));
|
|
4918
|
+
const depthOffset = (normalizedDepth - 1) * 20;
|
|
4919
|
+
const depthStyle = depthOffset === 0 ? style : bordered ? {
|
|
4920
|
+
...style,
|
|
4921
|
+
marginLeft: depthOffset,
|
|
4922
|
+
width: `calc(100% - ${depthOffset}px)`
|
|
4923
|
+
} : {
|
|
4924
|
+
...style,
|
|
4925
|
+
paddingLeft: `calc(var(--cmp-listDraggableItem-paddingX) + ${depthOffset}px)`
|
|
4926
|
+
};
|
|
4927
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4928
|
+
"div",
|
|
4929
|
+
{
|
|
4930
|
+
ref,
|
|
4931
|
+
"aria-disabled": disabled || void 0,
|
|
4932
|
+
"data-dragging": dragging || void 0,
|
|
4933
|
+
style: depthStyle,
|
|
4934
|
+
className: cn(
|
|
4935
|
+
"relative flex w-full items-center gap-(--cmp-listDraggableItem-gap) overflow-hidden px-(--cmp-listDraggableItem-paddingX)",
|
|
4936
|
+
titleTypo,
|
|
4937
|
+
disabled ? "bg-(--cmp-listDraggableItem-bg-default) text-(--sys-color-disabled-text)" : selected ? "bg-(--cmp-listDraggableItem-bg-selected) text-(--cmp-listDraggableItem-text-selected)" : "bg-(--cmp-listDraggableItem-bg-default) text-(--cmp-listDraggableItem-text-default)",
|
|
4938
|
+
!disabled && !selected && !dragging && cn(
|
|
4939
|
+
"hover:bg-(--cmp-listDraggableItem-bg-hover)",
|
|
4940
|
+
// 리스트가 드래그 중이면(SDraggableList 가 data-drag-active 를 붙인다) hover 를 무효화한다.
|
|
4941
|
+
"[[data-drag-active]_&]:hover:bg-(--cmp-listDraggableItem-bg-default)"
|
|
4942
|
+
),
|
|
4943
|
+
// 높이는 세로 패딩과 내용이 정한다 — 항목에 높이를 못 박지 않는다 (SListItem 과 동일)
|
|
4944
|
+
paddingYClass,
|
|
4945
|
+
// 항목 사이 구분선은 리스트가 그린다.
|
|
4946
|
+
bordered && cn(
|
|
4947
|
+
"rounded-(--cmp-listDraggableItem-radius-bordered) border border-(--cmp-listDraggableItem-border-default)",
|
|
4948
|
+
!disabled && !selected && !dragging && cn(
|
|
4949
|
+
"hover:border-(--cmp-listDraggableItem-bordered-border-hover)",
|
|
4950
|
+
"[[data-drag-active]_&]:hover:border-(--cmp-listDraggableItem-border-default)"
|
|
4951
|
+
),
|
|
4952
|
+
!disabled && selected && !dragging && "border-(--cmp-listDraggableItem-bordered-border-selected) bg-(--cmp-listDraggableItem-bordered-bg-selected)",
|
|
4953
|
+
!disabled && selected && dragging && "border-(--cmp-listDraggableItem-bordered-dragging-border-color) bg-(--cmp-listDraggableItem-bordered-dragging-bg)"
|
|
4954
|
+
),
|
|
4955
|
+
disabled && "cursor-not-allowed",
|
|
4956
|
+
className
|
|
4957
|
+
),
|
|
4958
|
+
...rest,
|
|
4959
|
+
children: [
|
|
4960
|
+
accentStripe && selected && !bordered && !disabled && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4961
|
+
"span",
|
|
4962
|
+
{
|
|
4963
|
+
"aria-hidden": "true",
|
|
4964
|
+
className: "pointer-events-none absolute bottom-[-1px] left-0 top-0 w-(--cmp-listDraggableItem-accentStripe-width) bg-(--cmp-listDraggableItem-accentStripe-color)"
|
|
4965
|
+
}
|
|
4966
|
+
),
|
|
4967
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4968
|
+
"div",
|
|
4969
|
+
{
|
|
4970
|
+
...dragHandleProps,
|
|
4971
|
+
role: dragHandleProps?.role ?? "button",
|
|
4972
|
+
tabIndex: dragHandleProps?.tabIndex ?? (disabled ? -1 : 0),
|
|
4973
|
+
"aria-label": dragHandleProps?.["aria-label"] ?? "\uB4DC\uB798\uADF8 \uD578\uB4E4",
|
|
4974
|
+
"aria-disabled": disabled || void 0,
|
|
4975
|
+
onMouseDown: onDragHandleMouseDown,
|
|
4976
|
+
className: cn(
|
|
4977
|
+
"flex size-[24px] shrink-0 select-none items-center justify-center rounded-[4px]",
|
|
4978
|
+
disabled ? "cursor-not-allowed opacity-0" : "cursor-grab hover:bg-black/5 active:cursor-grabbing",
|
|
4979
|
+
!disabled && !dragging && "[[data-drag-active]_&]:hover:bg-transparent",
|
|
4980
|
+
dragging && "bg-black/5",
|
|
4981
|
+
dragHandleProps?.className
|
|
4982
|
+
),
|
|
4983
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "drag", size: 16, color: "grey_65" })
|
|
4984
|
+
}
|
|
4985
|
+
),
|
|
4986
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4987
|
+
"div",
|
|
4988
|
+
{
|
|
4989
|
+
className: cn(
|
|
4990
|
+
"flex min-w-0 flex-1 items-center gap-[8px]",
|
|
4991
|
+
dragging && "opacity-(--cmp-listDraggableItem-dragging-content-opacity)"
|
|
4992
|
+
),
|
|
4993
|
+
children: [
|
|
4994
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4995
|
+
"span",
|
|
4996
|
+
{
|
|
4997
|
+
className: cn(
|
|
4998
|
+
"min-w-0 flex-1",
|
|
4999
|
+
supportingTextPosition === "bottom" ? "flex flex-col" : "flex items-center gap-[8px] whitespace-nowrap"
|
|
5000
|
+
),
|
|
5001
|
+
children: [
|
|
5002
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate", children: titleNode }),
|
|
5003
|
+
hasSupportingText && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5004
|
+
"span",
|
|
5005
|
+
{
|
|
5006
|
+
className: cn(
|
|
5007
|
+
"typo-body-sm-default min-w-0 truncate text-(--sys-color-fg-secondary)",
|
|
5008
|
+
supportingTextPosition === "right" && "flex-1"
|
|
5009
|
+
),
|
|
5010
|
+
children: supportingTextNode
|
|
5011
|
+
}
|
|
5012
|
+
)
|
|
5013
|
+
]
|
|
5014
|
+
}
|
|
5015
|
+
),
|
|
5016
|
+
trailingNode
|
|
5017
|
+
]
|
|
5018
|
+
}
|
|
5019
|
+
)
|
|
5020
|
+
]
|
|
5021
|
+
}
|
|
5022
|
+
);
|
|
5023
|
+
}
|
|
5024
|
+
);
|
|
5025
|
+
var SDraggableItemImpl = /* @__PURE__ */ react.forwardRef(function SDraggableItem({
|
|
5026
|
+
title,
|
|
5027
|
+
supportingText,
|
|
5028
|
+
supportingTextPosition = "right",
|
|
5029
|
+
trailing,
|
|
5030
|
+
depth = 1,
|
|
5031
|
+
accentStripe = false,
|
|
5032
|
+
bordered = false,
|
|
5033
|
+
selected = false,
|
|
5034
|
+
dragging = false,
|
|
5035
|
+
dense = false,
|
|
5036
|
+
size = "sm",
|
|
5037
|
+
disabled = false,
|
|
5038
|
+
dragOverlay = true,
|
|
5039
|
+
dragOverlayOpacity = 0.75,
|
|
5040
|
+
dragHandleProps,
|
|
5041
|
+
onDragHandleMouseDown,
|
|
5042
|
+
className,
|
|
5043
|
+
onMouseEnter,
|
|
5044
|
+
onMouseLeave,
|
|
5045
|
+
...rest
|
|
5046
|
+
}, ref) {
|
|
5047
|
+
const [hovered, setHovered] = react.useState(false);
|
|
5048
|
+
const [overlay, setOverlay] = react.useState(null);
|
|
5049
|
+
const rootRef = react.useRef(null);
|
|
5050
|
+
const overlayVisible = overlay != null;
|
|
5051
|
+
const handleMouseEnter = (event) => {
|
|
5052
|
+
if (!disabled) setHovered(true);
|
|
5053
|
+
onMouseEnter?.(event);
|
|
5054
|
+
};
|
|
5055
|
+
const handleMouseLeave = (event) => {
|
|
5056
|
+
setHovered(false);
|
|
5057
|
+
onMouseLeave?.(event);
|
|
5058
|
+
};
|
|
5059
|
+
const handleDragMouseDown = (event) => {
|
|
5060
|
+
if (disabled) return;
|
|
5061
|
+
const rect = rootRef.current?.getBoundingClientRect();
|
|
5062
|
+
if (dragOverlay && rect) {
|
|
5063
|
+
setOverlay({
|
|
5064
|
+
offsetX: event.clientX - rect.left,
|
|
5065
|
+
offsetY: event.clientY - rect.top,
|
|
5066
|
+
rect,
|
|
5067
|
+
x: event.clientX,
|
|
5068
|
+
y: event.clientY
|
|
5069
|
+
});
|
|
5070
|
+
}
|
|
5071
|
+
dragHandleProps?.onMouseDown?.(event);
|
|
5072
|
+
onDragHandleMouseDown?.(event);
|
|
5073
|
+
};
|
|
5074
|
+
react.useEffect(() => {
|
|
5075
|
+
if (!overlayVisible) return void 0;
|
|
5076
|
+
const handleMouseMove = (event) => {
|
|
5077
|
+
setOverlay(
|
|
5078
|
+
(current) => current ? {
|
|
5079
|
+
...current,
|
|
5080
|
+
x: event.clientX,
|
|
5081
|
+
y: event.clientY
|
|
5082
|
+
} : current
|
|
5083
|
+
);
|
|
5084
|
+
};
|
|
5085
|
+
const handleMouseUp = () => {
|
|
5086
|
+
setOverlay(null);
|
|
5087
|
+
};
|
|
5088
|
+
window.addEventListener("mousemove", handleMouseMove);
|
|
5089
|
+
window.addEventListener("mouseup", handleMouseUp);
|
|
5090
|
+
return () => {
|
|
5091
|
+
window.removeEventListener("mousemove", handleMouseMove);
|
|
5092
|
+
window.removeEventListener("mouseup", handleMouseUp);
|
|
5093
|
+
};
|
|
5094
|
+
}, [overlayVisible]);
|
|
5095
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5096
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5097
|
+
SDraggableItemView,
|
|
5098
|
+
{
|
|
5099
|
+
ref: (node) => setRefs([rootRef, ref], node),
|
|
5100
|
+
title,
|
|
5101
|
+
supportingText,
|
|
5102
|
+
supportingTextPosition,
|
|
5103
|
+
trailing,
|
|
5104
|
+
depth,
|
|
5105
|
+
accentStripe,
|
|
5106
|
+
bordered,
|
|
5107
|
+
selected,
|
|
5108
|
+
dense,
|
|
5109
|
+
size,
|
|
5110
|
+
dragging: dragging || overlayVisible,
|
|
5111
|
+
disabled,
|
|
5112
|
+
hovered,
|
|
5113
|
+
dragHandleProps,
|
|
5114
|
+
onDragHandleMouseDown: handleDragMouseDown,
|
|
5115
|
+
onMouseEnter: handleMouseEnter,
|
|
5116
|
+
onMouseLeave: handleMouseLeave,
|
|
5117
|
+
className,
|
|
5118
|
+
...rest
|
|
5119
|
+
}
|
|
5120
|
+
),
|
|
5121
|
+
overlay && typeof document !== "undefined" && reactDom.createPortal(
|
|
5122
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5123
|
+
"div",
|
|
5124
|
+
{
|
|
5125
|
+
className: "pointer-events-none fixed",
|
|
5126
|
+
style: {
|
|
5127
|
+
left: overlay.x - overlay.offsetX,
|
|
5128
|
+
opacity: dragOverlayOpacity,
|
|
5129
|
+
top: overlay.y - overlay.offsetY,
|
|
5130
|
+
width: overlay.rect.width,
|
|
5131
|
+
zIndex: Z_INDEX.drag
|
|
5132
|
+
},
|
|
5133
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5134
|
+
SDraggableItemView,
|
|
5135
|
+
{
|
|
5136
|
+
title,
|
|
5137
|
+
supportingText,
|
|
5138
|
+
supportingTextPosition,
|
|
5139
|
+
trailing,
|
|
5140
|
+
depth,
|
|
5141
|
+
accentStripe,
|
|
5142
|
+
bordered,
|
|
5143
|
+
selected,
|
|
5144
|
+
dense,
|
|
5145
|
+
size,
|
|
5146
|
+
dragging: true,
|
|
5147
|
+
disabled,
|
|
5148
|
+
hovered: true,
|
|
5149
|
+
dragHandleProps,
|
|
5150
|
+
className
|
|
5151
|
+
}
|
|
5152
|
+
)
|
|
5153
|
+
}
|
|
5154
|
+
),
|
|
5155
|
+
document.body
|
|
5156
|
+
)
|
|
5157
|
+
] });
|
|
5158
|
+
});
|
|
5159
|
+
var SDraggableItem2 = /* @__PURE__ */ withDisplayName(SDraggableItemImpl, "SDraggableItem");
|
|
5160
|
+
var SDivider = /* @__PURE__ */ react.forwardRef(function SDivider2({ vertical = false, height, className, style, ...rest }, ref) {
|
|
5161
|
+
const fixedHeight = vertical && height !== void 0;
|
|
5162
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5163
|
+
"hr",
|
|
5164
|
+
{
|
|
5165
|
+
ref,
|
|
5166
|
+
"aria-orientation": vertical ? "vertical" : "horizontal",
|
|
5167
|
+
className: cn(
|
|
5168
|
+
"shrink-0 border-0",
|
|
5169
|
+
vertical ? cn("inline-block w-px", fixedHeight ? "self-center" : "h-auto self-stretch") : "block h-px w-full",
|
|
5170
|
+
className
|
|
5171
|
+
),
|
|
5172
|
+
style: {
|
|
5173
|
+
backgroundColor: "var(--sys-color-divider-default, #E1E1E1)",
|
|
5174
|
+
...fixedHeight ? { height: typeof height === "number" ? `${height}px` : height } : null,
|
|
5175
|
+
...style
|
|
5176
|
+
},
|
|
5177
|
+
...rest
|
|
5178
|
+
}
|
|
5179
|
+
);
|
|
5180
|
+
});
|
|
5181
|
+
var PADDING_CLASS = {
|
|
5182
|
+
default: "p-(--cmp-list-group-padding)",
|
|
5183
|
+
none: ""
|
|
5184
|
+
};
|
|
5185
|
+
var dividerStyle = { backgroundColor: "var(--cmp-listItem-border-default)" };
|
|
5186
|
+
function hasBorderedChild(children) {
|
|
5187
|
+
let bordered = false;
|
|
5188
|
+
react.Children.forEach(children, (child) => {
|
|
5189
|
+
if (!react.isValidElement(child)) return;
|
|
5190
|
+
if (child.props.bordered === true) {
|
|
5191
|
+
bordered = true;
|
|
5192
|
+
return;
|
|
5193
|
+
}
|
|
5194
|
+
react.Children.forEach(child.props.children, (wrapped) => {
|
|
5195
|
+
if (react.isValidElement(wrapped) && wrapped.props.bordered === true) {
|
|
5196
|
+
bordered = true;
|
|
5197
|
+
}
|
|
5198
|
+
});
|
|
5199
|
+
});
|
|
5200
|
+
return bordered;
|
|
5201
|
+
}
|
|
5202
|
+
function withDividers(children) {
|
|
5203
|
+
return react.Children.toArray(children).flatMap(
|
|
5204
|
+
(child, index) => index === 0 ? [child] : [
|
|
5205
|
+
/* @__PURE__ */ jsxRuntime.jsx(SDivider, { "aria-hidden": "true", style: dividerStyle }, `s-list-divider-${index}`),
|
|
5206
|
+
child
|
|
5207
|
+
]
|
|
5208
|
+
);
|
|
5209
|
+
}
|
|
5210
|
+
var SListImpl = /* @__PURE__ */ react.forwardRef(function SList({ className, children, gap = false, padding = "none", ...rest }, ref) {
|
|
5211
|
+
const showDivider = !gap && !hasBorderedChild(children);
|
|
5212
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5213
|
+
"div",
|
|
5214
|
+
{
|
|
5215
|
+
ref,
|
|
5216
|
+
className: cn(
|
|
5217
|
+
gap && "flex flex-col gap-(--cmp-list-group-gap)",
|
|
5218
|
+
PADDING_CLASS[padding],
|
|
5219
|
+
className
|
|
5220
|
+
),
|
|
5221
|
+
...rest,
|
|
5222
|
+
children: showDivider ? withDividers(children) : children
|
|
5223
|
+
}
|
|
5224
|
+
);
|
|
5225
|
+
});
|
|
5226
|
+
var SList2 = /* @__PURE__ */ withDisplayName(SListImpl, "SList");
|
|
5227
|
+
var DraggableGroupContext = /* @__PURE__ */ react.createContext(null);
|
|
5228
|
+
function useSDraggableGroup() {
|
|
5229
|
+
return react.useContext(DraggableGroupContext);
|
|
5230
|
+
}
|
|
5231
|
+
function SDraggableProviderInternal({
|
|
5232
|
+
children,
|
|
5233
|
+
defaultGroup,
|
|
5234
|
+
legacyOnMove
|
|
5235
|
+
}) {
|
|
5236
|
+
const listsRef = react.useRef(/* @__PURE__ */ new Map());
|
|
5237
|
+
const legacyOnMoveRef = react.useRef(legacyOnMove);
|
|
5238
|
+
const pointerRef = react.useRef(null);
|
|
5239
|
+
const [dragging, setDragging] = react.useState(null);
|
|
5240
|
+
const [drop, setDrop] = react.useState(null);
|
|
5241
|
+
const dropRef = react.useRef(drop);
|
|
5242
|
+
legacyOnMoveRef.current = legacyOnMove;
|
|
5243
|
+
dropRef.current = drop;
|
|
5244
|
+
const registerList = react.useCallback(
|
|
5245
|
+
(group, listId, element, items, onChange) => {
|
|
5246
|
+
const key = `${group}:${listId}`;
|
|
5247
|
+
if (element) listsRef.current.set(key, { element, items, onChange });
|
|
5248
|
+
else listsRef.current.delete(key);
|
|
5249
|
+
},
|
|
5250
|
+
[]
|
|
5251
|
+
);
|
|
5252
|
+
const startDrag = react.useCallback(
|
|
5253
|
+
(event, group, listId, index, itemKey) => {
|
|
5254
|
+
event.preventDefault();
|
|
5255
|
+
setDragging({ group, listId, index, itemKey });
|
|
5256
|
+
setDrop({ group, listId, index });
|
|
5257
|
+
},
|
|
5258
|
+
[]
|
|
5259
|
+
);
|
|
5260
|
+
react.useEffect(() => {
|
|
5261
|
+
if (!dragging) return void 0;
|
|
5262
|
+
let autoScrollFrame = null;
|
|
5263
|
+
const findListAtPointer = (clientX, clientY) => {
|
|
5264
|
+
const element = document.elementFromPoint(clientX, clientY);
|
|
5265
|
+
const listElement = element?.closest("[data-draggable-list-id]");
|
|
5266
|
+
const group = listElement?.dataset.draggableGroup;
|
|
5267
|
+
const listId = listElement?.dataset.draggableListId;
|
|
5268
|
+
const list = group && listId ? listsRef.current.get(`${group}:${listId}`) : void 0;
|
|
5269
|
+
return group && listId && list ? { group, listId, list } : null;
|
|
4172
5270
|
};
|
|
4173
5271
|
const updateDropTarget = (clientX, clientY) => {
|
|
4174
5272
|
const target = findListAtPointer(clientX, clientY);
|
|
@@ -4913,23 +6011,104 @@ var SExpansionListImpl = /* @__PURE__ */ react.forwardRef(function SExpansionLis
|
|
|
4913
6011
|
if (isListItemElement(child)) {
|
|
4914
6012
|
return react.cloneElement(child, { clickable: child.props.clickable ?? true });
|
|
4915
6013
|
}
|
|
4916
|
-
if (!isExpansionItemElement(child)) return child;
|
|
4917
|
-
const depth = child.props.depth ?? 1;
|
|
4918
|
-
const itemKey = String(child.key ?? index);
|
|
4919
|
-
return react.cloneElement(child, {
|
|
4920
|
-
expanded: openKeys[depth] === itemKey,
|
|
4921
|
-
onToggle: (next, event) => {
|
|
4922
|
-
setOpenKeys((current) => ({
|
|
4923
|
-
...current,
|
|
4924
|
-
[depth]: next ? itemKey : current[depth] === itemKey ? void 0 : current[depth]
|
|
4925
|
-
}));
|
|
4926
|
-
child.props.onToggle?.(next, event);
|
|
4927
|
-
}
|
|
4928
|
-
});
|
|
4929
|
-
});
|
|
4930
|
-
return /* @__PURE__ */ jsxRuntime.jsx(SList2, { ref, ...rest, children: listChildren });
|
|
6014
|
+
if (!isExpansionItemElement(child)) return child;
|
|
6015
|
+
const depth = child.props.depth ?? 1;
|
|
6016
|
+
const itemKey = String(child.key ?? index);
|
|
6017
|
+
return react.cloneElement(child, {
|
|
6018
|
+
expanded: openKeys[depth] === itemKey,
|
|
6019
|
+
onToggle: (next, event) => {
|
|
6020
|
+
setOpenKeys((current) => ({
|
|
6021
|
+
...current,
|
|
6022
|
+
[depth]: next ? itemKey : current[depth] === itemKey ? void 0 : current[depth]
|
|
6023
|
+
}));
|
|
6024
|
+
child.props.onToggle?.(next, event);
|
|
6025
|
+
}
|
|
6026
|
+
});
|
|
6027
|
+
});
|
|
6028
|
+
return /* @__PURE__ */ jsxRuntime.jsx(SList2, { ref, ...rest, children: listChildren });
|
|
6029
|
+
});
|
|
6030
|
+
var SExpansionList2 = /* @__PURE__ */ withDisplayName(SExpansionListImpl, "SExpansionList");
|
|
6031
|
+
function SellmateWordmark({ className }) {
|
|
6032
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6033
|
+
"svg",
|
|
6034
|
+
{
|
|
6035
|
+
className,
|
|
6036
|
+
width: "276",
|
|
6037
|
+
height: "40",
|
|
6038
|
+
viewBox: "0 0 276 40",
|
|
6039
|
+
fill: "#00275F",
|
|
6040
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
6041
|
+
role: "img",
|
|
6042
|
+
"aria-label": "Sellmate",
|
|
6043
|
+
children: [
|
|
6044
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M22.6953 15.17H13.0352C10.9045 15.17 9.36459 14.8464 8.56779 14.2353C7.81576 13.6602 7.47556 12.7615 7.47556 11.3325C7.47556 9.90362 7.81576 8.98695 8.56779 8.4028C9.5526 7.62992 10.8418 7.48613 13.0352 7.48613H33.7072V0H13.1516C4.91507 0 0 4.23285 0 11.3325C0 18.4322 4.91507 22.6561 13.1516 22.6561H22.8206C24.1187 22.6292 26.0973 22.6561 27.2701 23.5908C27.9953 24.1659 28.3713 25.2444 28.3713 26.7811C28.3713 28.2011 28.0669 29.0908 27.3955 29.6569C26.1331 30.7174 23.6711 31.2476 20.0721 31.2476C6.75038 31.2476 0.877371 27.2125 0.823654 27.1676L0 26.5834V34.2852L0.196961 34.438C0.402874 34.5998 5.29108 38.3743 19.9557 38.3743C30.3499 38.3743 35.8469 34.3661 35.8469 26.7721C35.8469 19.1782 30.9318 15.17 22.6953 15.17Z" }),
|
|
6045
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M94.6954 0H87.4258V38.3833H94.6954V0Z" }),
|
|
6046
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M109.874 0H102.604V38.3833H109.874V0Z" }),
|
|
6047
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M160.887 10.728C158.675 8.97557 153.885 8.35547 150.466 8.35547C147.314 8.35547 143.035 9.04746 140.752 10.5483C138.558 9.03848 134.261 8.35547 131.056 8.35547C127.394 8.35547 122.631 9.17328 120.635 10.728C118.54 12.3636 117.475 14.844 117.475 18.1063V38.7224H124.744V18.1063C124.744 17.3514 125.058 16.7762 125.702 16.3539C126.669 15.7158 129.203 15.4911 131.083 15.4911C134.395 15.4911 137.135 15.6888 137.135 18.1063V38.7224H144.405V18.1063C144.405 15.9135 146.625 15.4911 150.457 15.4911C152.552 15.4911 155.067 15.7787 155.81 16.3359C156.482 16.8302 156.786 17.3963 156.786 18.1063V38.7224H164.056V18.1063C164.056 14.871 162.99 12.3906 160.896 10.728H160.887Z" }),
|
|
6048
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M195.015 8.35547H174.648V15.4911H194.854C197.074 15.4911 198.453 15.599 199.348 16.1741C199.895 16.5246 200.208 17.1537 200.289 18.0704H183.314C175.095 18.0704 171.264 21.3506 171.264 28.3964C171.264 34.9569 175.865 38.7224 183.887 38.7224H195.024C209.053 38.7224 207.639 35.9454 207.639 28.9715V18.1063C207.639 11.5458 203.512 8.35547 195.024 8.35547H195.015ZM200.369 28.9715C200.369 29.6276 200.441 30.5982 199.689 31.1194C198.847 31.7036 196.895 31.5867 194.854 31.5867H184.048C180.288 31.5867 178.533 30.5443 178.533 28.2975C178.533 25.4217 181.255 25.188 184.048 25.188H200.369V28.9715Z" }),
|
|
6049
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M227.692 0.521243L227.683 0H220.413V8.01636H212.866V15.143H220.413V37.862L220.422 38.3833H227.692V15.143H235.239V8.01636H227.692V0.521243Z" }),
|
|
6050
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M75.2766 10.728C73.2801 9.15531 70.084 8.35547 65.7688 8.35547H56.3146C47.9438 8.35547 43.7002 11.6357 43.7002 18.1063V29.2052C43.7002 34.4536 47.9528 38.7224 53.1812 38.7224H76.6553V31.6856H54.4793C52.5366 31.6856 50.9609 30.1039 50.9609 28.1537V27.4527H74.9006C76.2793 27.4527 77.1925 27.1472 77.7117 26.5181C78.1683 25.9519 78.3922 25.0802 78.3922 23.858V18.0973C78.3922 14.844 77.3447 12.3547 75.2766 10.719V10.728ZM50.9609 18.1063C50.9609 17.4233 51.31 16.8751 52.0621 16.3628C52.9126 15.7877 54.4346 15.4821 56.4758 15.4821H65.6076C67.6936 15.4821 69.2335 15.7607 70.075 16.282C70.7913 16.7223 71.1225 17.2975 71.1225 18.0973V20.416H50.9609V18.0973V18.1063Z" }),
|
|
6051
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M271.48 10.728C269.483 9.15531 266.287 8.35547 261.972 8.35547H252.518C244.147 8.35547 239.895 11.6357 239.895 18.1063V29.2052C239.895 34.4536 244.147 38.7224 249.376 38.7224H272.85V31.6856H250.674C248.731 31.6856 247.155 30.1039 247.155 28.1537V27.4527H271.095C272.474 27.4527 273.387 27.1472 273.906 26.5181C274.363 25.9519 274.586 25.0802 274.586 23.858V18.0973C274.586 14.844 273.539 12.3547 271.471 10.719L271.48 10.728ZM247.164 20.416V18.0973C247.164 17.4143 247.513 16.8661 248.265 16.3539C249.116 15.7787 250.638 15.4731 252.679 15.4731H261.811C263.897 15.4731 265.437 15.7517 266.278 16.273C266.995 16.7133 267.326 17.2885 267.326 18.0883V20.407H247.164V20.416Z" })
|
|
6052
|
+
]
|
|
6053
|
+
}
|
|
6054
|
+
);
|
|
6055
|
+
}
|
|
6056
|
+
var BUTTON_LABEL = "\uD1B5\uD569 \uACC4\uC815\uC73C\uB85C \uB85C\uADF8\uC778";
|
|
6057
|
+
var SLoginCardImpl = /* @__PURE__ */ react.forwardRef(function SLoginCard({ product, title, description, onLogin, footerNote, className, ...rest }, ref) {
|
|
6058
|
+
const hasIntro = title != null || description != null;
|
|
6059
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6060
|
+
"div",
|
|
6061
|
+
{
|
|
6062
|
+
ref,
|
|
6063
|
+
className: cn(
|
|
6064
|
+
// 폭도 높이도 부모가 준 만큼 채우고, 그 안에서 내용을 가운데 세운다.
|
|
6065
|
+
// 폭에만 상하한이 있다 — 640px 을 넘으면 소개 문장의 읽기 폭이 늘어지고, 368px 아래로
|
|
6066
|
+
// 내려가면 버튼(320px)이 안쪽 여백을 밀어낸다. 그 사이에서는 부모를 그대로 따른다.
|
|
6067
|
+
// 부모가 높이를 주지 않으면 h-full 이 auto 로 풀려 카드가 내용 높이로 줄어든다 —
|
|
6068
|
+
// 로그인 화면 밖(모달·스토리)에서도 그대로 쓸 수 있는 이유다.
|
|
6069
|
+
"flex h-full w-full max-w-[640px] min-w-[368px] shrink-0 flex-col items-center justify-center gap-sd-60",
|
|
6070
|
+
// 라운드 24px·폭 상하한(640/368px)은 대응 토큰이 없어 값으로 둔다 (디자인팀 토큰 추가 요청 대상).
|
|
6071
|
+
"rounded-[24px] bg-(--sys-color-bg-frame) p-sd-24 text-center",
|
|
6072
|
+
// 한글은 기본 규칙으로 두면 어절 한가운데서도 줄이 바뀐다 — `break-keep` 으로 띄어쓰기에서만
|
|
6073
|
+
// 끊는다. 끊을 자리가 아예 없는 긴 토큰(URL·주문번호)만 `wrap-break-word` 로 흘려보낸다.
|
|
6074
|
+
"break-keep wrap-break-word",
|
|
6075
|
+
className
|
|
6076
|
+
),
|
|
6077
|
+
...rest,
|
|
6078
|
+
children: [
|
|
6079
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-sd-32", children: [
|
|
6080
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-sd-8", children: [
|
|
6081
|
+
/* @__PURE__ */ jsxRuntime.jsx(SellmateWordmark, {}),
|
|
6082
|
+
product != null && // 24px 는 typo 프리셋(최대 18px)에 없는 등급이다 — 제품명은 로고의 일부처럼 읽혀야
|
|
6083
|
+
// 해서 본문 스케일 위에 선다. 여기만 값으로 두고, 프리셋이 생기면 갈아탄다.
|
|
6084
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "m-0 text-[24px] leading-[36px] font-bold text-(--sys-color-fg-accentLight)", children: product })
|
|
6085
|
+
] }),
|
|
6086
|
+
hasIntro && // 소개와 보조 설명은 한 문단으로 읽힌다.
|
|
6087
|
+
// `text-balance` 는 상속되므로 여기 한 번만 걸어 둘을 함께 덮는다 — 가운데 정렬에서는
|
|
6088
|
+
// 마지막 줄에 한 어절만 남는 모양이 가장 눈에 띄어서, 줄 길이를 고르게 나눠야 한다.
|
|
6089
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-sd-4 text-balance", children: [
|
|
6090
|
+
title != null && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "typo-body-lg-medium m-0 text-(--sys-color-fg-secondary)", children: title }),
|
|
6091
|
+
description != null && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "typo-body-md-default m-0 text-(--sys-color-fg-tertiary)", children: description })
|
|
6092
|
+
] })
|
|
6093
|
+
] }),
|
|
6094
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-sd-12", children: [
|
|
6095
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6096
|
+
SButton,
|
|
6097
|
+
{
|
|
6098
|
+
color: "secondary",
|
|
6099
|
+
size: "lg",
|
|
6100
|
+
label: BUTTON_LABEL,
|
|
6101
|
+
onClick: onLogin,
|
|
6102
|
+
className: "w-[320px]"
|
|
6103
|
+
}
|
|
6104
|
+
),
|
|
6105
|
+
footerNote != null && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "typo-body-sm-default m-0 text-(--sys-color-fg-tertiary)", children: footerNote })
|
|
6106
|
+
] })
|
|
6107
|
+
]
|
|
6108
|
+
}
|
|
6109
|
+
);
|
|
4931
6110
|
});
|
|
4932
|
-
var
|
|
6111
|
+
var SLoginCard2 = /* @__PURE__ */ withDisplayName(SLoginCardImpl, "SLoginCard");
|
|
4933
6112
|
function SCheckbox({
|
|
4934
6113
|
value = false,
|
|
4935
6114
|
val,
|
|
@@ -4957,292 +6136,48 @@ function SCheckbox({
|
|
|
4957
6136
|
};
|
|
4958
6137
|
const boxBg = disabled ? "var(--cmp-checkbox-bg-disabled)" : inverse ? "transparent" : isChecked ? "var(--cmp-checkbox-checked-bg-default)" : "var(--cmp-checkbox-unchecked-bg-default)";
|
|
4959
6138
|
const boxBorder = disabled ? "var(--cmp-checkbox-border-disabled)" : inverse ? "var(--cmp-checkbox-checked-border-inverse)" : isChecked ? "var(--cmp-checkbox-checked-bg-default)" : "var(--cmp-checkbox-unchecked-border-default)";
|
|
4960
|
-
const iconColor = disabled ? "var(--cmp-checkbox-checked-icon-disabled)" : "var(--cmp-checkbox-checked-icon-default)";
|
|
4961
|
-
const labelColor = disabled ? "var(--cmp-checkbox-label-disabled)" : inverse ? "var(--cmp-checkbox-label-inverse)" : "var(--cmp-checkbox-label-default)";
|
|
4962
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4963
|
-
"label",
|
|
4964
|
-
{
|
|
4965
|
-
className: cn(
|
|
4966
|
-
"inline-flex items-center gap-[var(--cmp-checkbox-gap)] align-middle",
|
|
4967
|
-
disabled ? "cursor-not-allowed" : "cursor-pointer",
|
|
4968
|
-
className
|
|
4969
|
-
),
|
|
4970
|
-
style,
|
|
4971
|
-
children: [
|
|
4972
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4973
|
-
RCheckbox__namespace.Root,
|
|
4974
|
-
{
|
|
4975
|
-
checked: state2,
|
|
4976
|
-
disabled,
|
|
4977
|
-
onCheckedChange: handleChange,
|
|
4978
|
-
className: cn(
|
|
4979
|
-
"flex h-[var(--cmp-checkbox-size)] w-[var(--cmp-checkbox-size)] items-center justify-center rounded-[var(--cmp-checkbox-radius)] border-[length:var(--cmp-checkbox-borderWidth)] border-solid bg-[var(--cb-bg)] border-[color:var(--cb-border)] outline-none",
|
|
4980
|
-
disabled ? "cursor-not-allowed" : "cursor-pointer",
|
|
4981
|
-
!disabled && !isChecked && !inverse && "hover:border-[color:var(--cmp-checkbox-unchecked-border-hover)] hover:bg-[var(--cmp-checkbox-unchecked-bg-hover)]"
|
|
4982
|
-
),
|
|
4983
|
-
style: { "--cb-bg": boxBg, "--cb-border": boxBorder },
|
|
4984
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(RCheckbox__namespace.Indicator, { className: "flex items-center justify-center leading-none", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4985
|
-
SIcon,
|
|
4986
|
-
{
|
|
4987
|
-
name: state2 === "indeterminate" ? "checkboxIndeterminate" : "checkboxCheck",
|
|
4988
|
-
size: 12,
|
|
4989
|
-
color: iconColor
|
|
4990
|
-
}
|
|
4991
|
-
) })
|
|
4992
|
-
}
|
|
4993
|
-
),
|
|
4994
|
-
label && // 고스트(500) 텍스트로 너비를 고정 → 두께 400↔500 전환 시 레이아웃이 밀리지 않음
|
|
4995
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "grid text-nowrap text-[12px] leading-[20px]", style: { color: labelColor }, children: [
|
|
4996
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "invisible font-medium", style: { gridArea: "1 / 1" }, children: label }),
|
|
4997
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { gridArea: "1 / 1", fontWeight: isChecked ? 500 : 400 }, children: label })
|
|
4998
|
-
] })
|
|
4999
|
-
]
|
|
5000
|
-
}
|
|
5001
|
-
);
|
|
5002
|
-
}
|
|
5003
|
-
|
|
5004
|
-
// src/lib/floating-anim.ts
|
|
5005
|
-
var FLOATING_SLIDE_ANIM = [
|
|
5006
|
-
"data-[state=open]:data-[side=top]:animate-floating-in-top",
|
|
5007
|
-
"data-[state=delayed-open]:data-[side=top]:animate-floating-in-top",
|
|
5008
|
-
"data-[state=instant-open]:data-[side=top]:animate-floating-in-top",
|
|
5009
|
-
"data-[state=closed]:data-[side=top]:animate-floating-out-top",
|
|
5010
|
-
"data-[state=open]:data-[side=bottom]:animate-floating-in-bottom",
|
|
5011
|
-
"data-[state=delayed-open]:data-[side=bottom]:animate-floating-in-bottom",
|
|
5012
|
-
"data-[state=instant-open]:data-[side=bottom]:animate-floating-in-bottom",
|
|
5013
|
-
"data-[state=closed]:data-[side=bottom]:animate-floating-out-bottom",
|
|
5014
|
-
"data-[state=open]:data-[side=left]:animate-floating-in-left",
|
|
5015
|
-
"data-[state=delayed-open]:data-[side=left]:animate-floating-in-left",
|
|
5016
|
-
"data-[state=instant-open]:data-[side=left]:animate-floating-in-left",
|
|
5017
|
-
"data-[state=closed]:data-[side=left]:animate-floating-out-left",
|
|
5018
|
-
"data-[state=open]:data-[side=right]:animate-floating-in-right",
|
|
5019
|
-
"data-[state=delayed-open]:data-[side=right]:animate-floating-in-right",
|
|
5020
|
-
"data-[state=instant-open]:data-[side=right]:animate-floating-in-right",
|
|
5021
|
-
"data-[state=closed]:data-[side=right]:animate-floating-out-right"
|
|
5022
|
-
].join(" ");
|
|
5023
|
-
var PortalContainerContext = /* @__PURE__ */ react.createContext(null);
|
|
5024
|
-
var InsideModalContext = /* @__PURE__ */ react.createContext(false);
|
|
5025
|
-
var PortalContainerProvider = PortalContainerContext.Provider;
|
|
5026
|
-
var InsideModalProvider = InsideModalContext.Provider;
|
|
5027
|
-
function usePortalContainer() {
|
|
5028
|
-
return react.useContext(PortalContainerContext) ?? void 0;
|
|
5029
|
-
}
|
|
5030
|
-
function useInsideModal() {
|
|
5031
|
-
return react.useContext(InsideModalContext);
|
|
5032
|
-
}
|
|
5033
|
-
|
|
5034
|
-
// src/components/STag/tag.config.ts
|
|
5035
|
-
var TAG_SHAPES = ["square", "pill"];
|
|
5036
|
-
var TAG_SIZES = ["xs", "sm", "md"];
|
|
5037
|
-
var TAG_COLORS = [
|
|
5038
|
-
"grey",
|
|
5039
|
-
"red",
|
|
5040
|
-
"orange",
|
|
5041
|
-
"yellow",
|
|
5042
|
-
"green",
|
|
5043
|
-
"blue",
|
|
5044
|
-
"darkblue",
|
|
5045
|
-
"indigo"
|
|
5046
|
-
];
|
|
5047
|
-
var TAG_SIZE_CONFIG = {
|
|
5048
|
-
xs: {
|
|
5049
|
-
height: 20,
|
|
5050
|
-
paddingX: 8,
|
|
5051
|
-
gap: 4,
|
|
5052
|
-
radius: 6,
|
|
5053
|
-
iconSize: 12,
|
|
5054
|
-
fontSize: 11,
|
|
5055
|
-
fontWeight: 500,
|
|
5056
|
-
lineHeight: 18
|
|
5057
|
-
},
|
|
5058
|
-
sm: {
|
|
5059
|
-
height: 24,
|
|
5060
|
-
paddingX: 8,
|
|
5061
|
-
gap: 4,
|
|
5062
|
-
radius: 6,
|
|
5063
|
-
iconSize: 16,
|
|
5064
|
-
fontSize: 12,
|
|
5065
|
-
fontWeight: 700,
|
|
5066
|
-
lineHeight: 20
|
|
5067
|
-
},
|
|
5068
|
-
md: {
|
|
5069
|
-
height: 28,
|
|
5070
|
-
paddingX: 12,
|
|
5071
|
-
gap: 6,
|
|
5072
|
-
radius: 8,
|
|
5073
|
-
iconSize: 16,
|
|
5074
|
-
fontSize: 14,
|
|
5075
|
-
fontWeight: 700,
|
|
5076
|
-
lineHeight: 24
|
|
5077
|
-
}
|
|
5078
|
-
};
|
|
5079
|
-
var STag = /* @__PURE__ */ react.forwardRef(function STag2({
|
|
5080
|
-
shape = "square",
|
|
5081
|
-
size = "sm",
|
|
5082
|
-
color = "grey",
|
|
5083
|
-
deep = false,
|
|
5084
|
-
label = "",
|
|
5085
|
-
icon,
|
|
5086
|
-
iconLeft = true,
|
|
5087
|
-
width,
|
|
5088
|
-
className,
|
|
5089
|
-
style,
|
|
5090
|
-
...rest
|
|
5091
|
-
}, ref) {
|
|
5092
|
-
const s = TAG_SIZE_CONFIG[size];
|
|
5093
|
-
const contentColor = deep ? `var(--cmp-tag-${color}-deep-content, var(--cmp-tag-deep-content))` : `var(--cmp-tag-${color}-content)`;
|
|
5094
|
-
const bgColor = deep ? `var(--cmp-tag-${color}-deep-bg)` : `var(--cmp-tag-${color}-bg)`;
|
|
5095
|
-
const iconNode = icon ? /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: icon, size: s.iconSize, color: contentColor }) : null;
|
|
5096
|
-
const resolvedWidth = typeof width === "number" ? `${width}px` : width;
|
|
5097
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5098
|
-
"span",
|
|
5099
|
-
{
|
|
5100
|
-
ref,
|
|
5101
|
-
"aria-label": label || "tag",
|
|
5102
|
-
className: cn(
|
|
5103
|
-
"box-border inline-flex w-fit select-none items-center justify-center whitespace-nowrap",
|
|
5104
|
-
className
|
|
5105
|
-
),
|
|
5106
|
-
style: {
|
|
5107
|
-
minHeight: s.height,
|
|
5108
|
-
padding: `0 ${s.paddingX}px`,
|
|
5109
|
-
gap: s.gap,
|
|
5110
|
-
borderRadius: shape === "pill" ? 999 : s.radius,
|
|
5111
|
-
fontSize: s.fontSize,
|
|
5112
|
-
fontWeight: s.fontWeight,
|
|
5113
|
-
lineHeight: `${s.lineHeight}px`,
|
|
5114
|
-
background: bgColor,
|
|
5115
|
-
color: contentColor,
|
|
5116
|
-
...resolvedWidth != null ? { width: resolvedWidth } : {},
|
|
5117
|
-
...style
|
|
5118
|
-
},
|
|
5119
|
-
...rest,
|
|
5120
|
-
children: [
|
|
5121
|
-
icon && iconLeft && iconNode,
|
|
5122
|
-
label && // leading-none: 태그는 min-height 로 높이가 정해지고 flex 가 세로 중앙 정렬하므로
|
|
5123
|
-
// 레이블에 line-height 가 필요 없다. 오히려 line-height 를 주면 브라우저가
|
|
5124
|
-
// 폰트 ascent/descent 를 정수 px 로 반올림한 뒤 남는 half-leading 을 내림 처리해
|
|
5125
|
-
// 베이스라인이 최대 1px 위로 밀린다(xs 에서 특히 눈에 띈다).
|
|
5126
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex min-w-0 items-center justify-center leading-none", children: label }),
|
|
5127
|
-
icon && !iconLeft && iconNode
|
|
5128
|
-
]
|
|
5129
|
-
}
|
|
5130
|
-
);
|
|
5131
|
-
});
|
|
5132
|
-
var SIZE = {
|
|
5133
|
-
xxs: { icon: 12, radius: "sm" },
|
|
5134
|
-
xs: { icon: 16, radius: "sm" },
|
|
5135
|
-
sm: { icon: 20, radius: "sm" },
|
|
5136
|
-
md: { icon: 24, radius: "md" },
|
|
5137
|
-
lg: { icon: 32, radius: "md" }
|
|
5138
|
-
};
|
|
5139
|
-
var TOOLTIP_HIDE_DELAY_MS = 100;
|
|
5140
|
-
function SGhostButton({
|
|
5141
|
-
icon,
|
|
5142
|
-
size = "sm",
|
|
5143
|
-
intent = "default",
|
|
5144
|
-
ariaLabel = "",
|
|
5145
|
-
ariaPressed,
|
|
5146
|
-
ariaExpanded,
|
|
5147
|
-
tooltipText,
|
|
5148
|
-
disabled = false,
|
|
5149
|
-
onClick,
|
|
5150
|
-
anchorClassName,
|
|
5151
|
-
anchorStyle,
|
|
5152
|
-
className,
|
|
5153
|
-
style
|
|
5154
|
-
}) {
|
|
5155
|
-
const portalContainer = usePortalContainer();
|
|
5156
|
-
const [open, setOpen] = react.useState(false);
|
|
5157
|
-
const hideTimer = react.useRef(void 0);
|
|
5158
|
-
const cancelHide = () => {
|
|
5159
|
-
if (hideTimer.current) {
|
|
5160
|
-
clearTimeout(hideTimer.current);
|
|
5161
|
-
hideTimer.current = void 0;
|
|
5162
|
-
}
|
|
5163
|
-
};
|
|
5164
|
-
const openNow = () => {
|
|
5165
|
-
cancelHide();
|
|
5166
|
-
setOpen(true);
|
|
5167
|
-
};
|
|
5168
|
-
const startHide = () => {
|
|
5169
|
-
cancelHide();
|
|
5170
|
-
hideTimer.current = setTimeout(() => setOpen(false), TOOLTIP_HIDE_DELAY_MS);
|
|
5171
|
-
};
|
|
5172
|
-
const s = SIZE[size];
|
|
5173
|
-
const contentColor = disabled ? intent === "inverse" ? "var(--cmp-ghostButton-inverse-disabled)" : "var(--cmp-ghostButton-icon-disabled)" : `var(--cmp-ghostButton-${intent}-content)`;
|
|
5174
|
-
const text = (tooltipText ?? "").trim();
|
|
5175
|
-
const hasTooltip = text !== "";
|
|
5176
|
-
const btn2 = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5177
|
-
"button",
|
|
5178
|
-
{
|
|
5179
|
-
type: "button",
|
|
5180
|
-
disabled,
|
|
5181
|
-
"aria-disabled": disabled ? "true" : void 0,
|
|
5182
|
-
"aria-label": ariaLabel.trim() || void 0,
|
|
5183
|
-
"aria-pressed": ariaPressed,
|
|
5184
|
-
"aria-expanded": ariaExpanded,
|
|
5185
|
-
tabIndex: disabled ? -1 : void 0,
|
|
5186
|
-
onClick: (e) => {
|
|
5187
|
-
if (disabled) {
|
|
5188
|
-
e.preventDefault();
|
|
5189
|
-
return;
|
|
5190
|
-
}
|
|
5191
|
-
onClick?.(e);
|
|
5192
|
-
},
|
|
6139
|
+
const iconColor = disabled ? "var(--cmp-checkbox-checked-icon-disabled)" : "var(--cmp-checkbox-checked-icon-default)";
|
|
6140
|
+
const labelColor = disabled ? "var(--cmp-checkbox-label-disabled)" : inverse ? "var(--cmp-checkbox-label-inverse)" : "var(--cmp-checkbox-label-default)";
|
|
6141
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6142
|
+
"label",
|
|
6143
|
+
{
|
|
5193
6144
|
className: cn(
|
|
5194
|
-
"
|
|
6145
|
+
"inline-flex items-center gap-[var(--cmp-checkbox-gap)] align-middle",
|
|
5195
6146
|
disabled ? "cursor-not-allowed" : "cursor-pointer",
|
|
5196
|
-
"focus-visible:outline-none focus-visible:shadow-[0_0_0_2px_var(--cmp-ghostButton-action-hover-bg)]",
|
|
5197
6147
|
className
|
|
5198
6148
|
),
|
|
5199
|
-
style
|
|
5200
|
-
width: `var(--cmp-ghostButton-${size}-size)`,
|
|
5201
|
-
height: `var(--cmp-ghostButton-${size}-size)`,
|
|
5202
|
-
borderRadius: `var(--cmp-ghostButton-radius-${s.radius})`,
|
|
5203
|
-
...style
|
|
5204
|
-
},
|
|
6149
|
+
style,
|
|
5205
6150
|
children: [
|
|
5206
|
-
|
|
5207
|
-
|
|
6151
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6152
|
+
RCheckbox__namespace.Root,
|
|
5208
6153
|
{
|
|
5209
|
-
|
|
5210
|
-
|
|
5211
|
-
|
|
6154
|
+
checked: state2,
|
|
6155
|
+
disabled,
|
|
6156
|
+
onCheckedChange: handleChange,
|
|
6157
|
+
className: cn(
|
|
6158
|
+
"flex h-[var(--cmp-checkbox-size)] w-[var(--cmp-checkbox-size)] items-center justify-center rounded-[var(--cmp-checkbox-radius)] border-[length:var(--cmp-checkbox-borderWidth)] border-solid bg-[var(--cb-bg)] border-[color:var(--cb-border)] outline-none",
|
|
6159
|
+
disabled ? "cursor-not-allowed" : "cursor-pointer",
|
|
6160
|
+
!disabled && !isChecked && !inverse && "hover:border-[color:var(--cmp-checkbox-unchecked-border-hover)] hover:bg-[var(--cmp-checkbox-unchecked-bg-hover)]"
|
|
6161
|
+
),
|
|
6162
|
+
style: { "--cb-bg": boxBg, "--cb-border": boxBorder },
|
|
6163
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(RCheckbox__namespace.Indicator, { className: "flex items-center justify-center leading-none", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6164
|
+
SIcon,
|
|
6165
|
+
{
|
|
6166
|
+
name: state2 === "indeterminate" ? "checkboxIndeterminate" : "checkboxCheck",
|
|
6167
|
+
size: 12,
|
|
6168
|
+
color: iconColor
|
|
6169
|
+
}
|
|
6170
|
+
) })
|
|
5212
6171
|
}
|
|
5213
6172
|
),
|
|
5214
|
-
|
|
6173
|
+
label && // 고스트(500) 텍스트로 너비를 고정 → 두께 400↔500 전환 시 레이아웃이 밀리지 않음
|
|
6174
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "grid text-nowrap text-[12px] leading-[20px]", style: { color: labelColor }, children: [
|
|
6175
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "invisible font-medium", style: { gridArea: "1 / 1" }, children: label }),
|
|
6176
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { gridArea: "1 / 1", fontWeight: isChecked ? 500 : 400 }, children: label })
|
|
6177
|
+
] })
|
|
5215
6178
|
]
|
|
5216
6179
|
}
|
|
5217
6180
|
);
|
|
5218
|
-
if (!hasTooltip) return btn2;
|
|
5219
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(RPopover12__namespace.Root, { open, onOpenChange: setOpen, children: [
|
|
5220
|
-
/* @__PURE__ */ jsxRuntime.jsx(RPopover12__namespace.Anchor, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5221
|
-
"span",
|
|
5222
|
-
{
|
|
5223
|
-
className: cn("inline-flex", anchorClassName),
|
|
5224
|
-
style: anchorStyle,
|
|
5225
|
-
onMouseEnter: openNow,
|
|
5226
|
-
onMouseLeave: startHide,
|
|
5227
|
-
onFocus: openNow,
|
|
5228
|
-
onBlur: startHide,
|
|
5229
|
-
children: btn2
|
|
5230
|
-
}
|
|
5231
|
-
) }),
|
|
5232
|
-
/* @__PURE__ */ jsxRuntime.jsx(RPopover12__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5233
|
-
RPopover12__namespace.Content,
|
|
5234
|
-
{
|
|
5235
|
-
side: "top",
|
|
5236
|
-
sideOffset: 4,
|
|
5237
|
-
className: cn("z-50", FLOATING_SLIDE_ANIM),
|
|
5238
|
-
"aria-hidden": true,
|
|
5239
|
-
onOpenAutoFocus: (e) => e.preventDefault(),
|
|
5240
|
-
onMouseEnter: cancelHide,
|
|
5241
|
-
onMouseLeave: startHide,
|
|
5242
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(STag, { shape: "square", size: "xs", color: "grey", label: text })
|
|
5243
|
-
}
|
|
5244
|
-
) })
|
|
5245
|
-
] });
|
|
5246
6181
|
}
|
|
5247
6182
|
var TREE_LABEL_TYPOGRAPHY = {
|
|
5248
6183
|
sm: {
|
|
@@ -5430,443 +6365,207 @@ var STreeItemImpl = /* @__PURE__ */ react.forwardRef(function STreeItem({
|
|
|
5430
6365
|
"group/tree-item box-border flex w-full items-center gap-(--cmp-tree-item-rowGap) overflow-hidden bg-(--cmp-tree-item-bg-default) px-(--cmp-tree-item-paddingX) text-left",
|
|
5431
6366
|
typography.rowHeight,
|
|
5432
6367
|
border && "border-b border-(--cmp-tree-item-border-default)",
|
|
5433
|
-
!node.disabled && "hover:bg-(--cmp-tree-item-bg-hover)",
|
|
5434
|
-
node.disabled && "cursor-not-allowed opacity-60",
|
|
5435
|
-
!node.disabled && hasChildren && "cursor-pointer",
|
|
5436
|
-
className
|
|
5437
|
-
),
|
|
5438
|
-
...rest,
|
|
5439
|
-
children: [
|
|
5440
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5441
|
-
TreeConnector,
|
|
5442
|
-
{
|
|
5443
|
-
guideline,
|
|
5444
|
-
size,
|
|
5445
|
-
depth,
|
|
5446
|
-
hasChildren,
|
|
5447
|
-
isLast: last,
|
|
5448
|
-
ancestorLast
|
|
5449
|
-
}
|
|
5450
|
-
),
|
|
5451
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "box-border flex min-w-0 flex-1 items-center gap-(--cmp-tree-item-contentGap)", children: [
|
|
5452
|
-
hasChildren ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
5453
|
-
SGhostButton,
|
|
5454
|
-
{
|
|
5455
|
-
icon: expanded ? "caretDown" : "caretRight",
|
|
5456
|
-
size: "xxs",
|
|
5457
|
-
ariaLabel: expanded ? "collapse tree item" : "expand tree item",
|
|
5458
|
-
ariaExpanded: expanded,
|
|
5459
|
-
disabled: node.disabled,
|
|
5460
|
-
onClick: (event) => {
|
|
5461
|
-
event.stopPropagation();
|
|
5462
|
-
if (node.disabled) return;
|
|
5463
|
-
onToggle?.(node, event);
|
|
5464
|
-
}
|
|
5465
|
-
}
|
|
5466
|
-
) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "size-(--cmp-tree-item-arrow-icon) shrink-0", "aria-hidden": "true" }),
|
|
5467
|
-
leadingNode,
|
|
5468
|
-
selectable && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5469
|
-
"span",
|
|
5470
|
-
{
|
|
5471
|
-
onClick: (event) => event.stopPropagation(),
|
|
5472
|
-
className: "flex shrink-0",
|
|
5473
|
-
"aria-hidden": node.disabled ? "true" : void 0,
|
|
5474
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5475
|
-
SCheckbox,
|
|
5476
|
-
{
|
|
5477
|
-
value: checkboxValue,
|
|
5478
|
-
disabled: node.disabled,
|
|
5479
|
-
onValueChange: () => handleSelect()
|
|
5480
|
-
}
|
|
5481
|
-
)
|
|
5482
|
-
}
|
|
5483
|
-
),
|
|
5484
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5485
|
-
"span",
|
|
5486
|
-
{
|
|
5487
|
-
onClick: (event) => {
|
|
5488
|
-
if (!selectable) return;
|
|
5489
|
-
event.stopPropagation();
|
|
5490
|
-
if (!node.disabled && selectable) onTreeSelect?.(node, event);
|
|
5491
|
-
},
|
|
5492
|
-
className: cn(
|
|
5493
|
-
"block min-w-0 flex-1 truncate py-(--cmp-tree-item-paddingY) text-(--cmp-tree-item-text-default)",
|
|
5494
|
-
labelTypo,
|
|
5495
|
-
node.disabled ? "cursor-not-allowed" : selectable ? "cursor-pointer" : void 0
|
|
5496
|
-
),
|
|
5497
|
-
children: node.label
|
|
5498
|
-
}
|
|
5499
|
-
),
|
|
5500
|
-
trailingNode
|
|
5501
|
-
] })
|
|
5502
|
-
]
|
|
5503
|
-
}
|
|
5504
|
-
);
|
|
5505
|
-
});
|
|
5506
|
-
var STreeItem2 = /* @__PURE__ */ withDisplayName(STreeItemImpl, "STreeItem");
|
|
5507
|
-
var STreeImpl = /* @__PURE__ */ react.forwardRef(function STree({
|
|
5508
|
-
items,
|
|
5509
|
-
value,
|
|
5510
|
-
defaultValue,
|
|
5511
|
-
expandedIds,
|
|
5512
|
-
defaultExpandedIds,
|
|
5513
|
-
selectable = true,
|
|
5514
|
-
size = "sm",
|
|
5515
|
-
showSelectAll = false,
|
|
5516
|
-
cascadeSelection = true,
|
|
5517
|
-
guideline = true,
|
|
5518
|
-
border = true,
|
|
5519
|
-
leading,
|
|
5520
|
-
trailing,
|
|
5521
|
-
onValueChange,
|
|
5522
|
-
onExpandedChange,
|
|
5523
|
-
className,
|
|
5524
|
-
...rest
|
|
5525
|
-
}, ref) {
|
|
5526
|
-
const [internalValue, setInternalValue] = react.useState(defaultValue ?? []);
|
|
5527
|
-
const [internalExpandedIds, setInternalExpandedIds] = react.useState(
|
|
5528
|
-
defaultExpandedIds ?? items.filter((item4) => item4.children?.length).map((item4) => item4.id)
|
|
5529
|
-
);
|
|
5530
|
-
const currentValue = value ?? internalValue;
|
|
5531
|
-
const currentExpandedIds = expandedIds ?? internalExpandedIds;
|
|
5532
|
-
const selectedSet = react.useMemo(() => toSelectedSet(currentValue), [currentValue]);
|
|
5533
|
-
const expandedSet = react.useMemo(() => new Set(currentExpandedIds), [currentExpandedIds]);
|
|
5534
|
-
const selectableIds = react.useMemo(() => items.flatMap(collectSelectableIds), [items]);
|
|
5535
|
-
const allSelected = selectableIds.length > 0 && selectableIds.every((id) => selectedSet.has(id));
|
|
5536
|
-
const someSelected = selectableIds.some((id) => selectedSet.has(id));
|
|
5537
|
-
const allIndeterminate = someSelected && !allSelected;
|
|
5538
|
-
const showAllItem = selectable && showSelectAll;
|
|
5539
|
-
const updateExpanded = (node) => {
|
|
5540
|
-
const next = new Set(currentExpandedIds);
|
|
5541
|
-
if (next.has(node.id)) next.delete(node.id);
|
|
5542
|
-
else next.add(node.id);
|
|
5543
|
-
const nextValue = Array.from(next);
|
|
5544
|
-
if (expandedIds === void 0) setInternalExpandedIds(nextValue);
|
|
5545
|
-
onExpandedChange?.(nextValue, node);
|
|
5546
|
-
};
|
|
5547
|
-
const updateSelected = (node) => {
|
|
5548
|
-
if (node.disabled) return;
|
|
5549
|
-
const targetIds = cascadeSelection ? collectSelectableIds(node) : [node.id];
|
|
5550
|
-
const everySelected = getSelectionState(node, selectedSet, cascadeSelection).selected;
|
|
5551
|
-
const next = new Set(selectedSet);
|
|
5552
|
-
targetIds.forEach((id) => {
|
|
5553
|
-
if (everySelected) next.delete(id);
|
|
5554
|
-
else next.add(id);
|
|
5555
|
-
});
|
|
5556
|
-
const orderedIds = collectIds(items).filter((id) => next.has(id));
|
|
5557
|
-
if (value === void 0) setInternalValue(orderedIds);
|
|
5558
|
-
onValueChange?.(orderedIds, node);
|
|
5559
|
-
};
|
|
5560
|
-
const updateAllSelected = (event) => {
|
|
5561
|
-
event?.stopPropagation();
|
|
5562
|
-
if (selectableIds.length === 0) return;
|
|
5563
|
-
const next = new Set(selectedSet);
|
|
5564
|
-
selectableIds.forEach((id) => {
|
|
5565
|
-
if (allSelected) next.delete(id);
|
|
5566
|
-
else next.add(id);
|
|
5567
|
-
});
|
|
5568
|
-
const orderedIds = collectIds(items).filter((id) => next.has(id));
|
|
5569
|
-
if (value === void 0) setInternalValue(orderedIds);
|
|
5570
|
-
onValueChange?.(orderedIds, TREE_ALL_NODE);
|
|
5571
|
-
};
|
|
5572
|
-
const renderNodes = (nodes, depth = 1, ancestorLast = []) => nodes.map((node, index) => {
|
|
5573
|
-
const isLast = index === nodes.length - 1;
|
|
5574
|
-
const isExpanded = expandedSet.has(node.id);
|
|
5575
|
-
const { selected, indeterminate } = getSelectionState(node, selectedSet, cascadeSelection);
|
|
5576
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, { children: [
|
|
5577
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5578
|
-
STreeItem2,
|
|
5579
|
-
{
|
|
5580
|
-
node,
|
|
5581
|
-
depth,
|
|
5582
|
-
last: isLast,
|
|
5583
|
-
ancestorLast,
|
|
5584
|
-
expanded: isExpanded,
|
|
5585
|
-
selected,
|
|
5586
|
-
indeterminate,
|
|
5587
|
-
selectable,
|
|
5588
|
-
size,
|
|
5589
|
-
guideline,
|
|
5590
|
-
border,
|
|
5591
|
-
leading,
|
|
5592
|
-
trailing,
|
|
5593
|
-
onToggle: updateExpanded,
|
|
5594
|
-
onTreeSelect: updateSelected
|
|
5595
|
-
}
|
|
5596
|
-
),
|
|
5597
|
-
node.children?.length ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
5598
|
-
"div",
|
|
5599
|
-
{
|
|
5600
|
-
"aria-hidden": !isExpanded,
|
|
5601
|
-
className: cn(
|
|
5602
|
-
"grid w-full overflow-hidden transition-[grid-template-rows] duration-200 ease-out motion-reduce:transition-none",
|
|
5603
|
-
isExpanded ? "grid-rows-[1fr]" : "grid-rows-[0fr]"
|
|
5604
|
-
),
|
|
5605
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 overflow-hidden", children: renderNodes(node.children, depth + 1, [...ancestorLast, isLast]) })
|
|
5606
|
-
}
|
|
5607
|
-
) : null
|
|
5608
|
-
] }, node.id);
|
|
5609
|
-
});
|
|
5610
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5611
|
-
"div",
|
|
5612
|
-
{
|
|
5613
|
-
ref,
|
|
5614
|
-
role: "tree",
|
|
5615
|
-
className: cn("flex w-full flex-col items-start bg-(--cmp-tree-item-bg-default)", className),
|
|
6368
|
+
!node.disabled && "hover:bg-(--cmp-tree-item-bg-hover)",
|
|
6369
|
+
node.disabled && "cursor-not-allowed opacity-60",
|
|
6370
|
+
!node.disabled && hasChildren && "cursor-pointer",
|
|
6371
|
+
className
|
|
6372
|
+
),
|
|
5616
6373
|
...rest,
|
|
5617
6374
|
children: [
|
|
5618
|
-
|
|
5619
|
-
|
|
6375
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6376
|
+
TreeConnector,
|
|
5620
6377
|
{
|
|
5621
|
-
|
|
5622
|
-
indeterminate: allIndeterminate,
|
|
5623
|
-
border,
|
|
6378
|
+
guideline,
|
|
5624
6379
|
size,
|
|
5625
|
-
|
|
6380
|
+
depth,
|
|
6381
|
+
hasChildren,
|
|
6382
|
+
isLast: last,
|
|
6383
|
+
ancestorLast
|
|
5626
6384
|
}
|
|
5627
6385
|
),
|
|
5628
|
-
|
|
6386
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "box-border flex min-w-0 flex-1 items-center gap-(--cmp-tree-item-contentGap)", children: [
|
|
6387
|
+
hasChildren ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
6388
|
+
SGhostButton,
|
|
6389
|
+
{
|
|
6390
|
+
icon: expanded ? "caretDown" : "caretRight",
|
|
6391
|
+
size: "xxs",
|
|
6392
|
+
ariaLabel: expanded ? "collapse tree item" : "expand tree item",
|
|
6393
|
+
ariaExpanded: expanded,
|
|
6394
|
+
disabled: node.disabled,
|
|
6395
|
+
onClick: (event) => {
|
|
6396
|
+
event.stopPropagation();
|
|
6397
|
+
if (node.disabled) return;
|
|
6398
|
+
onToggle?.(node, event);
|
|
6399
|
+
}
|
|
6400
|
+
}
|
|
6401
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "size-(--cmp-tree-item-arrow-icon) shrink-0", "aria-hidden": "true" }),
|
|
6402
|
+
leadingNode,
|
|
6403
|
+
selectable && /* @__PURE__ */ jsxRuntime.jsx(
|
|
6404
|
+
"span",
|
|
6405
|
+
{
|
|
6406
|
+
onClick: (event) => event.stopPropagation(),
|
|
6407
|
+
className: "flex shrink-0",
|
|
6408
|
+
"aria-hidden": node.disabled ? "true" : void 0,
|
|
6409
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6410
|
+
SCheckbox,
|
|
6411
|
+
{
|
|
6412
|
+
value: checkboxValue,
|
|
6413
|
+
disabled: node.disabled,
|
|
6414
|
+
onValueChange: () => handleSelect()
|
|
6415
|
+
}
|
|
6416
|
+
)
|
|
6417
|
+
}
|
|
6418
|
+
),
|
|
6419
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6420
|
+
"span",
|
|
6421
|
+
{
|
|
6422
|
+
onClick: (event) => {
|
|
6423
|
+
if (!selectable) return;
|
|
6424
|
+
event.stopPropagation();
|
|
6425
|
+
if (!node.disabled && selectable) onTreeSelect?.(node, event);
|
|
6426
|
+
},
|
|
6427
|
+
className: cn(
|
|
6428
|
+
"block min-w-0 flex-1 truncate py-(--cmp-tree-item-paddingY) text-(--cmp-tree-item-text-default)",
|
|
6429
|
+
labelTypo,
|
|
6430
|
+
node.disabled ? "cursor-not-allowed" : selectable ? "cursor-pointer" : void 0
|
|
6431
|
+
),
|
|
6432
|
+
children: node.label
|
|
6433
|
+
}
|
|
6434
|
+
),
|
|
6435
|
+
trailingNode
|
|
6436
|
+
] })
|
|
5629
6437
|
]
|
|
5630
6438
|
}
|
|
5631
6439
|
);
|
|
5632
6440
|
});
|
|
5633
|
-
var
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
"BASE",
|
|
5651
|
-
"NOSCRIPT",
|
|
5652
|
-
// SVG/MATH 는 foreign-content 파싱 모드로 전환되어 재직렬화 시 다른 트리로
|
|
5653
|
-
// 재파싱될 수 있다(mXSS 벡터). 인라인 라벨에 필요 없으므로 통째로 제거한다.
|
|
5654
|
-
"SVG",
|
|
5655
|
-
"MATH",
|
|
5656
|
-
"TEMPLATE"
|
|
5657
|
-
]);
|
|
5658
|
-
var escapeHtml = (value) => value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
5659
|
-
var sanitizeNode = (node) => {
|
|
5660
|
-
if (node.nodeType === Node.COMMENT_NODE) {
|
|
5661
|
-
node.remove();
|
|
5662
|
-
return;
|
|
5663
|
-
}
|
|
5664
|
-
if (node.nodeType !== Node.ELEMENT_NODE) return;
|
|
5665
|
-
const element = node;
|
|
5666
|
-
const tagName = element.tagName.toUpperCase();
|
|
5667
|
-
if (DROP_CONTENT_TAGS.has(tagName)) {
|
|
5668
|
-
element.remove();
|
|
5669
|
-
return;
|
|
5670
|
-
}
|
|
5671
|
-
Array.from(element.childNodes).forEach((child) => sanitizeNode(child));
|
|
5672
|
-
if (ALLOWED_INLINE_TAGS.has(tagName)) {
|
|
5673
|
-
if (element.hasAttribute("className")) {
|
|
5674
|
-
const val = element.getAttribute("className");
|
|
5675
|
-
element.removeAttribute("className");
|
|
5676
|
-
if (!element.hasAttribute("class")) element.setAttribute("class", val);
|
|
5677
|
-
}
|
|
5678
|
-
const allowedAttrs = ALLOWED_ATTRS_BY_TAG[tagName] ?? COMMON_ALLOWED_ATTRS;
|
|
5679
|
-
Array.from(element.attributes).forEach((attr) => {
|
|
5680
|
-
if (!allowedAttrs.has(attr.name)) element.removeAttribute(attr.name);
|
|
5681
|
-
});
|
|
5682
|
-
if (tagName === "A") {
|
|
5683
|
-
const href = element.getAttribute("href");
|
|
5684
|
-
if (href !== null && href !== "" && !SAFE_HREF_RE.test(href)) element.removeAttribute("href");
|
|
5685
|
-
if (element.hasAttribute("target")) {
|
|
5686
|
-
element.setAttribute("rel", "noopener noreferrer");
|
|
5687
|
-
}
|
|
5688
|
-
}
|
|
5689
|
-
return;
|
|
5690
|
-
}
|
|
5691
|
-
const parent = element.parentNode;
|
|
5692
|
-
if (parent == null) return;
|
|
5693
|
-
while (element.firstChild) parent.insertBefore(element.firstChild, element);
|
|
5694
|
-
parent.removeChild(element);
|
|
5695
|
-
};
|
|
5696
|
-
var sanitizeInlineHtml = (value) => {
|
|
5697
|
-
if (typeof document === "undefined") return escapeHtml(value);
|
|
5698
|
-
const template = document.createElement("template");
|
|
5699
|
-
template.innerHTML = value;
|
|
5700
|
-
Array.from(template.content.childNodes).forEach((child) => sanitizeNode(child));
|
|
5701
|
-
return template.innerHTML;
|
|
5702
|
-
};
|
|
5703
|
-
var HIDE_DELAY_MS = 100;
|
|
5704
|
-
function useBody(content, message = []) {
|
|
5705
|
-
if (content != null) return content;
|
|
5706
|
-
if (message.length === 0) return null;
|
|
5707
|
-
const singleLine = message.length === 1;
|
|
5708
|
-
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: message.map((line, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5709
|
-
"div",
|
|
5710
|
-
{
|
|
5711
|
-
className: singleLine ? "leading-[24px]" : void 0,
|
|
5712
|
-
dangerouslySetInnerHTML: { __html: sanitizeInlineHtml(line) }
|
|
5713
|
-
},
|
|
5714
|
-
i
|
|
5715
|
-
)) });
|
|
5716
|
-
}
|
|
5717
|
-
var STooltipImpl = /* @__PURE__ */ react.forwardRef(function STooltip({
|
|
5718
|
-
content,
|
|
5719
|
-
message = [],
|
|
5720
|
-
open: openProp,
|
|
5721
|
-
onOpenChange,
|
|
5722
|
-
trigger = "hover",
|
|
5723
|
-
placement = "top",
|
|
5724
|
-
sideOffset = 8,
|
|
5725
|
-
tooltipType = "default",
|
|
5726
|
-
showClose = false,
|
|
5727
|
-
disabled = false,
|
|
5728
|
-
children,
|
|
5729
|
-
icon = "helpOutline",
|
|
5730
|
-
iconSize = 12,
|
|
5731
|
-
color = "#01BB4B",
|
|
5732
|
-
ariaLabel,
|
|
6441
|
+
var STreeItem2 = /* @__PURE__ */ withDisplayName(STreeItemImpl, "STreeItem");
|
|
6442
|
+
var STreeImpl = /* @__PURE__ */ react.forwardRef(function STree({
|
|
6443
|
+
items,
|
|
6444
|
+
value,
|
|
6445
|
+
defaultValue,
|
|
6446
|
+
expandedIds,
|
|
6447
|
+
defaultExpandedIds,
|
|
6448
|
+
selectable = true,
|
|
6449
|
+
size = "sm",
|
|
6450
|
+
showSelectAll = false,
|
|
6451
|
+
cascadeSelection = true,
|
|
6452
|
+
guideline = true,
|
|
6453
|
+
border = true,
|
|
6454
|
+
leading,
|
|
6455
|
+
trailing,
|
|
6456
|
+
onValueChange,
|
|
6457
|
+
onExpandedChange,
|
|
5733
6458
|
className,
|
|
5734
|
-
|
|
5735
|
-
style,
|
|
5736
|
-
contentProps
|
|
6459
|
+
...rest
|
|
5737
6460
|
}, ref) {
|
|
5738
|
-
const
|
|
5739
|
-
const [
|
|
5740
|
-
|
|
5741
|
-
const open = isControlled ? openProp : internalOpen;
|
|
5742
|
-
const hideTimer = react.useRef(void 0);
|
|
5743
|
-
const cancelHide = react.useCallback(() => {
|
|
5744
|
-
if (hideTimer.current) {
|
|
5745
|
-
clearTimeout(hideTimer.current);
|
|
5746
|
-
hideTimer.current = void 0;
|
|
5747
|
-
}
|
|
5748
|
-
}, []);
|
|
5749
|
-
const setOpenState = react.useCallback(
|
|
5750
|
-
(next) => {
|
|
5751
|
-
if (!isControlled) setInternalOpen(next);
|
|
5752
|
-
onOpenChange?.(next);
|
|
5753
|
-
},
|
|
5754
|
-
[isControlled, onOpenChange]
|
|
5755
|
-
);
|
|
5756
|
-
const openNow = () => {
|
|
5757
|
-
cancelHide();
|
|
5758
|
-
setOpenState(true);
|
|
5759
|
-
};
|
|
5760
|
-
const startHide = () => {
|
|
5761
|
-
if (showClose) return;
|
|
5762
|
-
cancelHide();
|
|
5763
|
-
hideTimer.current = setTimeout(() => setOpenState(false), HIDE_DELAY_MS);
|
|
5764
|
-
};
|
|
5765
|
-
react.useImperativeHandle(
|
|
5766
|
-
ref,
|
|
5767
|
-
() => ({
|
|
5768
|
-
show: () => {
|
|
5769
|
-
cancelHide();
|
|
5770
|
-
setOpenState(true);
|
|
5771
|
-
},
|
|
5772
|
-
hide: () => {
|
|
5773
|
-
cancelHide();
|
|
5774
|
-
setOpenState(false);
|
|
5775
|
-
}
|
|
5776
|
-
}),
|
|
5777
|
-
[cancelHide, setOpenState]
|
|
5778
|
-
);
|
|
5779
|
-
const isHover = trigger === "hover";
|
|
5780
|
-
const isNone = trigger === "none";
|
|
5781
|
-
if (isNone && children == null && typeof console !== "undefined") {
|
|
5782
|
-
console.warn(
|
|
5783
|
-
'[STooltip] trigger="none" \uC740 \uC704\uCE58 \uAE30\uC900\uC774 \uB420 children \uC774 \uD544\uC694\uD569\uB2C8\uB2E4. \uC544\uC774\uCF58 \uD2B8\uB9AC\uAC70\uB85C \uD3F4\uBC31\uD569\uB2C8\uB2E4.'
|
|
5784
|
-
);
|
|
5785
|
-
}
|
|
5786
|
-
const body = useBody(content, message);
|
|
5787
|
-
const bg = `var(--cmp-tooltip-${tooltipType}-bg)`;
|
|
5788
|
-
const fg = `var(--cmp-tooltip-${tooltipType}-content)`;
|
|
5789
|
-
const triggerNode = children ?? /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("inline-flex cursor-pointer", triggerClassName), "aria-label": ariaLabel, children: /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: icon, size: iconSize, color }) });
|
|
5790
|
-
if (disabled || body == null) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: triggerNode });
|
|
5791
|
-
const {
|
|
5792
|
-
className: contentPropsClassName,
|
|
5793
|
-
style: contentPropsStyle,
|
|
5794
|
-
...restContentProps
|
|
5795
|
-
} = contentProps ?? {};
|
|
5796
|
-
const contentClass = cn(
|
|
5797
|
-
"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",
|
|
5798
|
-
FLOATING_SLIDE_ANIM,
|
|
5799
|
-
className,
|
|
5800
|
-
contentPropsClassName
|
|
6461
|
+
const [internalValue, setInternalValue] = react.useState(defaultValue ?? []);
|
|
6462
|
+
const [internalExpandedIds, setInternalExpandedIds] = react.useState(
|
|
6463
|
+
defaultExpandedIds ?? items.filter((item4) => item4.children?.length).map((item4) => item4.id)
|
|
5801
6464
|
);
|
|
5802
|
-
const
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
6465
|
+
const currentValue = value ?? internalValue;
|
|
6466
|
+
const currentExpandedIds = expandedIds ?? internalExpandedIds;
|
|
6467
|
+
const selectedSet = react.useMemo(() => toSelectedSet(currentValue), [currentValue]);
|
|
6468
|
+
const expandedSet = react.useMemo(() => new Set(currentExpandedIds), [currentExpandedIds]);
|
|
6469
|
+
const selectableIds = react.useMemo(() => items.flatMap(collectSelectableIds), [items]);
|
|
6470
|
+
const allSelected = selectableIds.length > 0 && selectableIds.every((id) => selectedSet.has(id));
|
|
6471
|
+
const someSelected = selectableIds.some((id) => selectedSet.has(id));
|
|
6472
|
+
const allIndeterminate = someSelected && !allSelected;
|
|
6473
|
+
const showAllItem = selectable && showSelectAll;
|
|
6474
|
+
const updateExpanded = (node) => {
|
|
6475
|
+
const next = new Set(currentExpandedIds);
|
|
6476
|
+
if (next.has(node.id)) next.delete(node.id);
|
|
6477
|
+
else next.add(node.id);
|
|
6478
|
+
const nextValue = Array.from(next);
|
|
6479
|
+
if (expandedIds === void 0) setInternalExpandedIds(nextValue);
|
|
6480
|
+
onExpandedChange?.(nextValue, node);
|
|
5808
6481
|
};
|
|
5809
|
-
|
|
5810
|
-
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
)
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
|
|
6482
|
+
const updateSelected = (node) => {
|
|
6483
|
+
if (node.disabled) return;
|
|
6484
|
+
const targetIds = cascadeSelection ? collectSelectableIds(node) : [node.id];
|
|
6485
|
+
const everySelected = getSelectionState(node, selectedSet, cascadeSelection).selected;
|
|
6486
|
+
const next = new Set(selectedSet);
|
|
6487
|
+
targetIds.forEach((id) => {
|
|
6488
|
+
if (everySelected) next.delete(id);
|
|
6489
|
+
else next.add(id);
|
|
6490
|
+
});
|
|
6491
|
+
const orderedIds = collectIds(items).filter((id) => next.has(id));
|
|
6492
|
+
if (value === void 0) setInternalValue(orderedIds);
|
|
6493
|
+
onValueChange?.(orderedIds, node);
|
|
6494
|
+
};
|
|
6495
|
+
const updateAllSelected = (event) => {
|
|
6496
|
+
event?.stopPropagation();
|
|
6497
|
+
if (selectableIds.length === 0) return;
|
|
6498
|
+
const next = new Set(selectedSet);
|
|
6499
|
+
selectableIds.forEach((id) => {
|
|
6500
|
+
if (allSelected) next.delete(id);
|
|
6501
|
+
else next.add(id);
|
|
6502
|
+
});
|
|
6503
|
+
const orderedIds = collectIds(items).filter((id) => next.has(id));
|
|
6504
|
+
if (value === void 0) setInternalValue(orderedIds);
|
|
6505
|
+
onValueChange?.(orderedIds, TREE_ALL_NODE);
|
|
6506
|
+
};
|
|
6507
|
+
const renderNodes = (nodes, depth = 1, ancestorLast = []) => nodes.map((node, index) => {
|
|
6508
|
+
const isLast = index === nodes.length - 1;
|
|
6509
|
+
const isExpanded = expandedSet.has(node.id);
|
|
6510
|
+
const { selected, indeterminate } = getSelectionState(node, selectedSet, cascadeSelection);
|
|
6511
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, { children: [
|
|
6512
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6513
|
+
STreeItem2,
|
|
5818
6514
|
{
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
|
|
5824
|
-
|
|
6515
|
+
node,
|
|
6516
|
+
depth,
|
|
6517
|
+
last: isLast,
|
|
6518
|
+
ancestorLast,
|
|
6519
|
+
expanded: isExpanded,
|
|
6520
|
+
selected,
|
|
6521
|
+
indeterminate,
|
|
6522
|
+
selectable,
|
|
6523
|
+
size,
|
|
6524
|
+
guideline,
|
|
6525
|
+
border,
|
|
6526
|
+
leading,
|
|
6527
|
+
trailing,
|
|
6528
|
+
onToggle: updateExpanded,
|
|
6529
|
+
onTreeSelect: updateSelected
|
|
5825
6530
|
}
|
|
5826
|
-
)
|
|
5827
|
-
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
|
|
5833
|
-
|
|
5834
|
-
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5850
|
-
|
|
5851
|
-
|
|
5852
|
-
|
|
5853
|
-
|
|
5854
|
-
|
|
5855
|
-
|
|
5856
|
-
|
|
5857
|
-
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
] }),
|
|
5863
|
-
/* @__PURE__ */ jsxRuntime.jsx(RPopover12__namespace.Arrow, { width: 16, height: 12, style: { fill: bg } })
|
|
5864
|
-
]
|
|
5865
|
-
}
|
|
5866
|
-
) })
|
|
5867
|
-
] });
|
|
6531
|
+
),
|
|
6532
|
+
node.children?.length ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
6533
|
+
"div",
|
|
6534
|
+
{
|
|
6535
|
+
"aria-hidden": !isExpanded,
|
|
6536
|
+
className: cn(
|
|
6537
|
+
"grid w-full overflow-hidden transition-[grid-template-rows] duration-200 ease-out motion-reduce:transition-none",
|
|
6538
|
+
isExpanded ? "grid-rows-[1fr]" : "grid-rows-[0fr]"
|
|
6539
|
+
),
|
|
6540
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 overflow-hidden", children: renderNodes(node.children, depth + 1, [...ancestorLast, isLast]) })
|
|
6541
|
+
}
|
|
6542
|
+
) : null
|
|
6543
|
+
] }, node.id);
|
|
6544
|
+
});
|
|
6545
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6546
|
+
"div",
|
|
6547
|
+
{
|
|
6548
|
+
ref,
|
|
6549
|
+
role: "tree",
|
|
6550
|
+
className: cn("flex w-full flex-col items-start bg-(--cmp-tree-item-bg-default)", className),
|
|
6551
|
+
...rest,
|
|
6552
|
+
children: [
|
|
6553
|
+
showAllItem && /* @__PURE__ */ jsxRuntime.jsx(
|
|
6554
|
+
STreeAllItem,
|
|
6555
|
+
{
|
|
6556
|
+
selected: allSelected,
|
|
6557
|
+
indeterminate: allIndeterminate,
|
|
6558
|
+
border,
|
|
6559
|
+
size,
|
|
6560
|
+
onSelect: updateAllSelected
|
|
6561
|
+
}
|
|
6562
|
+
),
|
|
6563
|
+
renderNodes(items)
|
|
6564
|
+
]
|
|
6565
|
+
}
|
|
6566
|
+
);
|
|
5868
6567
|
});
|
|
5869
|
-
var
|
|
6568
|
+
var STree2 = /* @__PURE__ */ withDisplayName(STreeImpl, "STree");
|
|
5870
6569
|
var BODY_PADDING_CLASS = {
|
|
5871
6570
|
default: "p-(--sys-space-panel-padding-default)",
|
|
5872
6571
|
wide: "p-(--sys-space-panel-padding-wide)",
|
|
@@ -11670,931 +12369,704 @@ var SStepper = /* @__PURE__ */ react.forwardRef(function SStepper2({
|
|
|
11670
12369
|
]
|
|
11671
12370
|
},
|
|
11672
12371
|
`${groupKey}-${group.startIndex}`
|
|
11673
|
-
);
|
|
11674
|
-
})
|
|
11675
|
-
]
|
|
11676
|
-
}
|
|
11677
|
-
);
|
|
11678
|
-
}
|
|
11679
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
11680
|
-
"div",
|
|
11681
|
-
{
|
|
11682
|
-
role: "list",
|
|
11683
|
-
"aria-label": ariaLabel,
|
|
11684
|
-
className: cn("inline-flex items-center", className),
|
|
11685
|
-
style: {
|
|
11686
|
-
gap: STEPPER_LAYOUT.containerGap,
|
|
11687
|
-
fontSize: config.fontSize,
|
|
11688
|
-
lineHeight: config.lineHeight,
|
|
11689
|
-
...style
|
|
11690
|
-
},
|
|
11691
|
-
children: items.map((item4, index) => {
|
|
11692
|
-
const state2 = getState(item4, index);
|
|
11693
|
-
const content = isClickable ? /* @__PURE__ */ jsxRuntime.jsx("span", { role: "listitem", "aria-current": state2 === "active" ? "step" : void 0, children: renderClickableStepContent(item4, index) }) : renderStepContent(item4, index);
|
|
11694
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11695
|
-
"span",
|
|
11696
|
-
{
|
|
11697
|
-
className: "inline-flex items-center",
|
|
11698
|
-
style: { gap: STEPPER_LAYOUT.containerGap },
|
|
11699
|
-
children: [
|
|
11700
|
-
content,
|
|
11701
|
-
index < items.length - 1 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11702
|
-
"span",
|
|
11703
|
-
{
|
|
11704
|
-
"aria-hidden": true,
|
|
11705
|
-
className: "inline-flex h-px shrink-0 items-center",
|
|
11706
|
-
style: { width: STEPPER_LAYOUT.dashWidth, color: STEPPER_COLORS.dash },
|
|
11707
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11708
|
-
"svg",
|
|
11709
|
-
{
|
|
11710
|
-
width: "20",
|
|
11711
|
-
height: "1",
|
|
11712
|
-
viewBox: "0 0 20 1",
|
|
11713
|
-
fill: "none",
|
|
11714
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
11715
|
-
children: [
|
|
11716
|
-
/* @__PURE__ */ jsxRuntime.jsx("rect", { width: "1.6", height: "1", fill: "currentColor" }),
|
|
11717
|
-
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "5", width: "3.3", height: "1", fill: "currentColor" }),
|
|
11718
|
-
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "11.7", width: "3.3", height: "1", fill: "currentColor" }),
|
|
11719
|
-
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "18.4", width: "1.6", height: "1", fill: "currentColor" })
|
|
11720
|
-
]
|
|
11721
|
-
}
|
|
11722
|
-
)
|
|
11723
|
-
}
|
|
11724
|
-
)
|
|
11725
|
-
]
|
|
11726
|
-
},
|
|
11727
|
-
getItemValue(item4, index)
|
|
11728
|
-
);
|
|
11729
|
-
})
|
|
11730
|
-
}
|
|
11731
|
-
);
|
|
11732
|
-
});
|
|
11733
|
-
|
|
11734
|
-
// src/lib/date.ts
|
|
11735
|
-
function todayStr() {
|
|
11736
|
-
const d = /* @__PURE__ */ new Date();
|
|
11737
|
-
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
|
11738
|
-
}
|
|
11739
|
-
function formatDate(year, month, day) {
|
|
11740
|
-
return `${year}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
|
|
11741
|
-
}
|
|
11742
|
-
function calcYearMonth(year, month, dir) {
|
|
11743
|
-
if (dir === "prev")
|
|
11744
|
-
return month === 1 ? { year: year - 1, month: 12 } : { year, month: month - 1 };
|
|
11745
|
-
return month === 12 ? { year: year + 1, month: 1 } : { year, month: month + 1 };
|
|
11746
|
-
}
|
|
11747
|
-
function monthCells(year, month) {
|
|
11748
|
-
const firstDayIndex = new Date(year, month - 1, 1).getDay();
|
|
11749
|
-
const daysInCurrent = new Date(year, month, 0).getDate();
|
|
11750
|
-
const prev = calcYearMonth(year, month, "prev");
|
|
11751
|
-
const daysInPrev = new Date(prev.year, prev.month, 0).getDate();
|
|
11752
|
-
const next = calcYearMonth(year, month, "next");
|
|
11753
|
-
const cells = [];
|
|
11754
|
-
for (let i = firstDayIndex - 1; i >= 0; i--) {
|
|
11755
|
-
const day = daysInPrev - i;
|
|
11756
|
-
cells.push({ date: formatDate(prev.year, prev.month, day), day, inCurrentMonth: false });
|
|
11757
|
-
}
|
|
11758
|
-
for (let day = 1; day <= daysInCurrent; day++) {
|
|
11759
|
-
cells.push({ date: formatDate(year, month, day), day, inCurrentMonth: true });
|
|
11760
|
-
}
|
|
11761
|
-
const remaining = (7 - cells.length % 7) % 7;
|
|
11762
|
-
for (let day = 1; day <= remaining; day++) {
|
|
11763
|
-
cells.push({ date: formatDate(next.year, next.month, day), day, inCurrentMonth: false });
|
|
12372
|
+
);
|
|
12373
|
+
})
|
|
12374
|
+
]
|
|
12375
|
+
}
|
|
12376
|
+
);
|
|
11764
12377
|
}
|
|
11765
|
-
return
|
|
11766
|
-
}
|
|
11767
|
-
var WEEK_LABELS = ["\uC77C", "\uC6D4", "\uD654", "\uC218", "\uBAA9", "\uAE08", "\uD1A0"];
|
|
11768
|
-
|
|
11769
|
-
// src/components/SCalendarBoard/calendarBoard.config.ts
|
|
11770
|
-
var CALENDAR_BOARD_EVENT_COLORS = [
|
|
11771
|
-
"default",
|
|
11772
|
-
"blue",
|
|
11773
|
-
"oceanBlue",
|
|
11774
|
-
"lightBlue",
|
|
11775
|
-
"green",
|
|
11776
|
-
"yellow",
|
|
11777
|
-
"orange",
|
|
11778
|
-
"red",
|
|
11779
|
-
"white"
|
|
11780
|
-
];
|
|
11781
|
-
var BG = (name) => `var(--cmp-calendarBoard-eventButton-bg-${name})`;
|
|
11782
|
-
var CALENDAR_BOARD_EVENT_PRESETS = {
|
|
11783
|
-
default: { bg: BG("default"), dot: "indigo" },
|
|
11784
|
-
blue: { bg: BG("blue"), dot: "blue" },
|
|
11785
|
-
oceanBlue: { bg: BG("oceanBlue"), dot: "darkblue" },
|
|
11786
|
-
lightBlue: { bg: BG("lightBlue"), dot: "lightblue" },
|
|
11787
|
-
green: { bg: BG("green"), dot: "green" },
|
|
11788
|
-
yellow: { bg: BG("yellow"), dot: "yellow" },
|
|
11789
|
-
orange: { bg: BG("orange"), dot: "orange" },
|
|
11790
|
-
red: { bg: BG("red"), dot: "red" },
|
|
11791
|
-
white: { bg: BG("white"), dot: "grey" }
|
|
11792
|
-
};
|
|
11793
|
-
var CALENDAR_BOARD_MAX_VISIBLE_EVENTS = 4;
|
|
11794
|
-
var CALENDAR_BOARD_DAY_COLORS = [
|
|
11795
|
-
"default",
|
|
11796
|
-
"danger",
|
|
11797
|
-
"accent",
|
|
11798
|
-
"complete",
|
|
11799
|
-
"dim"
|
|
11800
|
-
];
|
|
11801
|
-
var CALENDAR_BOARD_DAY_BG = {
|
|
11802
|
-
default: "var(--cmp-calendarBoard-dayCard-bg)",
|
|
11803
|
-
danger: "var(--color-red-30)",
|
|
11804
|
-
accent: "var(--color-brilliantblue-40)",
|
|
11805
|
-
complete: "var(--color-green-45)",
|
|
11806
|
-
dim: "var(--color-grey-25)"
|
|
11807
|
-
};
|
|
11808
|
-
function CalendarEventButton({
|
|
11809
|
-
event,
|
|
11810
|
-
onSelect,
|
|
11811
|
-
className
|
|
11812
|
-
}) {
|
|
11813
|
-
const preset = CALENDAR_BOARD_EVENT_PRESETS[event.color ?? "default"];
|
|
11814
|
-
const dot = event.dotColor ?? preset.dot;
|
|
11815
|
-
const disabled = event.disabled === true;
|
|
11816
|
-
const hasDescription = event.description != null && event.description !== "";
|
|
11817
|
-
const hasValue = event.value != null && event.value !== "";
|
|
11818
|
-
const title = [event.label.replace(/<[^>]*>/g, ""), event.description, event.value].filter((v) => v != null && v !== "").join(" ") || void 0;
|
|
11819
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11820
|
-
"button",
|
|
11821
|
-
{
|
|
11822
|
-
type: "button",
|
|
11823
|
-
disabled,
|
|
11824
|
-
title,
|
|
11825
|
-
className: cn(
|
|
11826
|
-
// hover 는 배경 위에 8% 오버레이를 얹는다 — 프리셋 배경이 9종이라 색마다 hover 색을 두지 않는다.
|
|
11827
|
-
"group relative flex w-full min-w-0 items-center overflow-hidden text-left",
|
|
11828
|
-
"h-(--cmp-calendarBoard-item-height) shrink-0 rounded-(--cmp-calendarBoard-item-radius)",
|
|
11829
|
-
"gap-(--cmp-calendarBoard-eventButton-inline-gap) px-(--cmp-calendarBoard-item-paddingX)",
|
|
11830
|
-
"bg-(--ceb-bg) text-(--cmp-calendarBoard-eventButton-text-color-default)",
|
|
11831
|
-
disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer",
|
|
11832
|
-
className
|
|
11833
|
-
),
|
|
11834
|
-
style: { "--ceb-bg": preset.bg },
|
|
11835
|
-
onClick: (e) => {
|
|
11836
|
-
if (disabled) return;
|
|
11837
|
-
onSelect?.(event, e);
|
|
11838
|
-
},
|
|
11839
|
-
children: [
|
|
11840
|
-
!disabled && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11841
|
-
"span",
|
|
11842
|
-
{
|
|
11843
|
-
"aria-hidden": true,
|
|
11844
|
-
className: "pointer-events-none absolute inset-0 rounded-(--cmp-calendarBoard-item-radius) bg-(--cmp-calendarBoard-eventButton-hover-overlay-color) opacity-0 transition-opacity group-hover:opacity-(--cmp-calendarBoard-eventButton-hover-overlay-opacity)"
|
|
11845
|
-
}
|
|
11846
|
-
),
|
|
11847
|
-
/* @__PURE__ */ jsxRuntime.jsx(SBadge, { "aria-hidden": true, color: dot, className: "shrink-0" }),
|
|
11848
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-1 items-center gap-(--cmp-calendarBoard-eventButton-label-gap)", children: [
|
|
11849
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "typo-body-sm-default min-w-0 flex-1 truncate", children: [
|
|
11850
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11851
|
-
"span",
|
|
11852
|
-
{
|
|
11853
|
-
className: cn(
|
|
11854
|
-
"typo-body-sm-semibold",
|
|
11855
|
-
hasDescription && "me-(--cmp-calendarBoard-eventButton-label-gap)"
|
|
11856
|
-
),
|
|
11857
|
-
dangerouslySetInnerHTML: { __html: sanitizeInlineHtml(event.label) }
|
|
11858
|
-
}
|
|
11859
|
-
),
|
|
11860
|
-
hasDescription && event.description
|
|
11861
|
-
] }),
|
|
11862
|
-
hasValue && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex shrink-0 items-center gap-(--cmp-calendarBoard-eventButton-label-gap)", children: [
|
|
11863
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11864
|
-
"span",
|
|
11865
|
-
{
|
|
11866
|
-
"aria-hidden": true,
|
|
11867
|
-
className: "typo-body-sm-default text-(--cmp-calendarBoard-eventButton-text-color-separator)",
|
|
11868
|
-
children: "/"
|
|
11869
|
-
}
|
|
11870
|
-
),
|
|
11871
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "typo-body-sm-default whitespace-nowrap", children: event.value })
|
|
11872
|
-
] })
|
|
11873
|
-
] })
|
|
11874
|
-
]
|
|
11875
|
-
}
|
|
11876
|
-
);
|
|
11877
|
-
}
|
|
11878
|
-
var CalendarMoreButton = /* @__PURE__ */ react.forwardRef(function CalendarMoreButton2({ count, label = "\uB354\uBCF4\uAE30", onClick, className }, ref) {
|
|
11879
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11880
|
-
"button",
|
|
11881
|
-
{
|
|
11882
|
-
ref,
|
|
11883
|
-
type: "button",
|
|
11884
|
-
className: cn(
|
|
11885
|
-
"group relative flex w-full min-w-0 cursor-pointer items-center overflow-hidden text-left",
|
|
11886
|
-
"h-(--cmp-calendarBoard-item-height) shrink-0 rounded-(--cmp-calendarBoard-item-radius)",
|
|
11887
|
-
"gap-(--cmp-calendarBoard-moreButton-gap) px-(--cmp-calendarBoard-item-paddingX)",
|
|
11888
|
-
"bg-(--cmp-calendarBoard-moreButton-bg)",
|
|
11889
|
-
className
|
|
11890
|
-
),
|
|
11891
|
-
onClick,
|
|
11892
|
-
children: [
|
|
11893
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11894
|
-
"span",
|
|
11895
|
-
{
|
|
11896
|
-
"aria-hidden": true,
|
|
11897
|
-
className: "pointer-events-none absolute inset-0 rounded-(--cmp-calendarBoard-item-radius) bg-(--cmp-calendarBoard-moreButton-hover-overlay-color) opacity-0 transition-opacity group-hover:opacity-(--cmp-calendarBoard-moreButton-hover-overlay-opacity)"
|
|
11898
|
-
}
|
|
11899
|
-
),
|
|
11900
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "typo-body-sm-semibold shrink-0 text-(--cmp-calendarBoard-moreButton-count-color)", children: [
|
|
11901
|
-
count,
|
|
11902
|
-
"\uAC1C"
|
|
11903
|
-
] }),
|
|
11904
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "typo-body-sm-default min-w-0 truncate text-(--cmp-calendarBoard-moreButton-label-color)", children: label })
|
|
11905
|
-
]
|
|
11906
|
-
}
|
|
11907
|
-
);
|
|
11908
|
-
});
|
|
11909
|
-
var CalendarDayCard = /* @__PURE__ */ react.forwardRef(function CalendarDayCard2({
|
|
11910
|
-
date,
|
|
11911
|
-
day,
|
|
11912
|
-
inCurrentMonth,
|
|
11913
|
-
isToday,
|
|
11914
|
-
isSelected,
|
|
11915
|
-
selectable,
|
|
11916
|
-
color,
|
|
11917
|
-
events,
|
|
11918
|
-
body,
|
|
11919
|
-
hiddenCount,
|
|
11920
|
-
isOpen,
|
|
11921
|
-
moreLabel,
|
|
11922
|
-
onDaySelect,
|
|
11923
|
-
onEventClick,
|
|
11924
|
-
onOpenEvents,
|
|
11925
|
-
...rest
|
|
11926
|
-
}, ref) {
|
|
11927
|
-
const hasEvents = events.length + hiddenCount > 0;
|
|
11928
|
-
const interactive = selectable || hasEvents;
|
|
11929
|
-
const activate = () => {
|
|
11930
|
-
if (hasEvents) onOpenEvents?.();
|
|
11931
|
-
if (selectable) onDaySelect?.(date);
|
|
11932
|
-
};
|
|
11933
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12378
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
11934
12379
|
"div",
|
|
11935
12380
|
{
|
|
11936
|
-
|
|
11937
|
-
|
|
11938
|
-
|
|
11939
|
-
|
|
11940
|
-
|
|
11941
|
-
|
|
11942
|
-
|
|
11943
|
-
|
|
11944
|
-
|
|
11945
|
-
|
|
11946
|
-
|
|
11947
|
-
|
|
11948
|
-
|
|
11949
|
-
activate();
|
|
11950
|
-
}
|
|
11951
|
-
} : void 0,
|
|
11952
|
-
className: cn(
|
|
11953
|
-
"relative flex min-h-(--cmp-calendarBoard-dayCard-minHeight) min-w-(--cmp-calendarBoard-dayCard-minWidth) flex-col bg-(--cdc-bg) px-(--cmp-calendarBoard-dayCard-paddingX) outline-none",
|
|
11954
|
-
interactive && "cursor-pointer"
|
|
11955
|
-
),
|
|
11956
|
-
style: { ...rest.style, "--cdc-bg": CALENDAR_BOARD_DAY_BG[color] },
|
|
11957
|
-
children: [
|
|
11958
|
-
isSelected && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11959
|
-
"span",
|
|
11960
|
-
{
|
|
11961
|
-
"aria-hidden": true,
|
|
11962
|
-
className: "pointer-events-none absolute inset-[1px] rounded-(--cmp-calendarBoard-dayCard-focus-border-radius) border-(length:--cmp-calendarBoard-dayCard-focus-border-width) border-solid border-(--cmp-calendarBoard-dayCard-focus-border-color)"
|
|
11963
|
-
}
|
|
11964
|
-
),
|
|
11965
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex shrink-0 pt-(--cmp-calendarBoard-dayCard-header-paddingTop) pb-(--cmp-calendarBoard-dayCard-header-paddingBottom)", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12381
|
+
role: "list",
|
|
12382
|
+
"aria-label": ariaLabel,
|
|
12383
|
+
className: cn("inline-flex items-center", className),
|
|
12384
|
+
style: {
|
|
12385
|
+
gap: STEPPER_LAYOUT.containerGap,
|
|
12386
|
+
fontSize: config.fontSize,
|
|
12387
|
+
lineHeight: config.lineHeight,
|
|
12388
|
+
...style
|
|
12389
|
+
},
|
|
12390
|
+
children: items.map((item4, index) => {
|
|
12391
|
+
const state2 = getState(item4, index);
|
|
12392
|
+
const content = isClickable ? /* @__PURE__ */ jsxRuntime.jsx("span", { role: "listitem", "aria-current": state2 === "active" ? "step" : void 0, children: renderClickableStepContent(item4, index) }) : renderStepContent(item4, index);
|
|
12393
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11966
12394
|
"span",
|
|
11967
12395
|
{
|
|
11968
|
-
className:
|
|
11969
|
-
|
|
11970
|
-
isToday ? "typo-body-md-bold bg-(--cmp-calendarBoard-daySequence-bg-today) text-(--cmp-calendarBoard-daySequence-text-today)" : cn(
|
|
11971
|
-
"typo-body-md-medium",
|
|
11972
|
-
inCurrentMonth ? "text-(--cmp-calendarBoard-daySequence-text-default)" : "text-(--cmp-calendarBoard-daySequence-text-otherMonth)"
|
|
11973
|
-
),
|
|
11974
|
-
// 오늘이 아니면서 선택된 날은 테두리 원으로 표시한다 (오늘은 이미 채운 원이라 겹치지 않는다).
|
|
11975
|
-
// 굵기는 1px 로 고정한다 — 칸을 감싸는 focus 테두리(2px)와 달리 얇은 원이고, 대응 토큰이 없다.
|
|
11976
|
-
isSelected && !isToday && "border border-solid border-(--cmp-calendarBoard-daySequence-border-selected)"
|
|
11977
|
-
),
|
|
11978
|
-
children: day
|
|
11979
|
-
}
|
|
11980
|
-
) }),
|
|
11981
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
11982
|
-
"div",
|
|
11983
|
-
{
|
|
11984
|
-
className: cn(
|
|
11985
|
-
"flex min-h-0 flex-col gap-(--cmp-calendarBoard-dayCard-grid-gap) pb-(--cmp-calendarBoard-dayCard-grid-paddingBottom)",
|
|
11986
|
-
// 슬롯은 남는 세로를 다 갖는다 — 안에서 h-full 로 칸을 채울 수 있어야 한다.
|
|
11987
|
-
body != null && "flex-1"
|
|
11988
|
-
),
|
|
12396
|
+
className: "inline-flex items-center",
|
|
12397
|
+
style: { gap: STEPPER_LAYOUT.containerGap },
|
|
11989
12398
|
children: [
|
|
11990
|
-
|
|
11991
|
-
|
|
11992
|
-
|
|
11993
|
-
{
|
|
11994
|
-
event,
|
|
11995
|
-
onSelect: (ev, e) => {
|
|
11996
|
-
e.stopPropagation();
|
|
11997
|
-
onEventClick?.(ev, e);
|
|
11998
|
-
}
|
|
11999
|
-
},
|
|
12000
|
-
event.id ?? `${event.date}-${i}`
|
|
12001
|
-
)),
|
|
12002
|
-
hiddenCount > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
12003
|
-
CalendarMoreButton,
|
|
12399
|
+
content,
|
|
12400
|
+
index < items.length - 1 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
12401
|
+
"span",
|
|
12004
12402
|
{
|
|
12005
|
-
|
|
12006
|
-
|
|
12007
|
-
|
|
12008
|
-
|
|
12009
|
-
|
|
12010
|
-
|
|
12403
|
+
"aria-hidden": true,
|
|
12404
|
+
className: "inline-flex h-px shrink-0 items-center",
|
|
12405
|
+
style: { width: STEPPER_LAYOUT.dashWidth, color: STEPPER_COLORS.dash },
|
|
12406
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12407
|
+
"svg",
|
|
12408
|
+
{
|
|
12409
|
+
width: "20",
|
|
12410
|
+
height: "1",
|
|
12411
|
+
viewBox: "0 0 20 1",
|
|
12412
|
+
fill: "none",
|
|
12413
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
12414
|
+
children: [
|
|
12415
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { width: "1.6", height: "1", fill: "currentColor" }),
|
|
12416
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "5", width: "3.3", height: "1", fill: "currentColor" }),
|
|
12417
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "11.7", width: "3.3", height: "1", fill: "currentColor" }),
|
|
12418
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "18.4", width: "1.6", height: "1", fill: "currentColor" })
|
|
12419
|
+
]
|
|
12420
|
+
}
|
|
12421
|
+
)
|
|
12011
12422
|
}
|
|
12012
12423
|
)
|
|
12013
12424
|
]
|
|
12014
|
-
}
|
|
12015
|
-
)
|
|
12016
|
-
]
|
|
12017
|
-
}
|
|
12018
|
-
);
|
|
12019
|
-
});
|
|
12020
|
-
var MAX_HEIGHT = 480;
|
|
12021
|
-
var MAX_WIDTH = "calc(100vw - 16px)";
|
|
12022
|
-
function CalendarDayEventListBox({
|
|
12023
|
-
date,
|
|
12024
|
-
events,
|
|
12025
|
-
onEventClick,
|
|
12026
|
-
minWidth,
|
|
12027
|
-
minHeight,
|
|
12028
|
-
onClose,
|
|
12029
|
-
closeLabel = "\uB2EB\uAE30"
|
|
12030
|
-
}) {
|
|
12031
|
-
const [y, m, d] = date.split("-").map(Number);
|
|
12032
|
-
const weekday = WEEK_LABELS[new Date(y, m - 1, d).getDay()];
|
|
12033
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12034
|
-
"div",
|
|
12035
|
-
{
|
|
12036
|
-
className: "flex w-max flex-col overflow-hidden rounded-(--cmp-calendarBoard-radius) bg-(--cmp-calendarBoard-bg) shadow-(--shadow-overlay)",
|
|
12037
|
-
style: { minWidth, maxWidth: MAX_WIDTH, minHeight, maxHeight: MAX_HEIGHT },
|
|
12038
|
-
children: [
|
|
12039
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-(--cmp-calendarBoard-dayEvent-header-gap) px-(--cmp-calendarBoard-dayEvent-header-paddingX) py-(--cmp-calendarBoard-dayEvent-header-paddingY)", children: [
|
|
12040
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "typo-heading-md text-(--cmp-calendarBoard-header-content-color)", children: [
|
|
12041
|
-
d,
|
|
12042
|
-
"\uC77C"
|
|
12043
|
-
] }),
|
|
12044
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "typo-body-lg-default flex-1 text-(--cmp-calendarBoard-header-content-color)", children: [
|
|
12045
|
-
"(",
|
|
12046
|
-
weekday,
|
|
12047
|
-
")"
|
|
12048
|
-
] }),
|
|
12049
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12050
|
-
SGhostButton,
|
|
12051
|
-
{
|
|
12052
|
-
icon: "close",
|
|
12053
|
-
size: "xs",
|
|
12054
|
-
ariaLabel: closeLabel,
|
|
12055
|
-
className: "shrink-0",
|
|
12056
|
-
onClick: onClose
|
|
12057
|
-
}
|
|
12058
|
-
)
|
|
12059
|
-
] }),
|
|
12060
|
-
/* @__PURE__ */ jsxRuntime.jsx(SScrollArea, { axis: "vertical", className: "min-h-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-(--cmp-calendarBoard-dayEvent-body-gap) px-(--cmp-calendarBoard-dayEvent-body-paddingX) pb-(--cmp-calendarBoard-dayEvent-body-paddingBottom)", children: events.map((event, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
12061
|
-
CalendarEventButton,
|
|
12062
|
-
{
|
|
12063
|
-
event,
|
|
12064
|
-
onSelect: onEventClick
|
|
12065
12425
|
},
|
|
12066
|
-
|
|
12067
|
-
)
|
|
12068
|
-
|
|
12426
|
+
getItemValue(item4, index)
|
|
12427
|
+
);
|
|
12428
|
+
})
|
|
12069
12429
|
}
|
|
12070
12430
|
);
|
|
12431
|
+
});
|
|
12432
|
+
|
|
12433
|
+
// src/lib/date.ts
|
|
12434
|
+
function todayStr() {
|
|
12435
|
+
const d = /* @__PURE__ */ new Date();
|
|
12436
|
+
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
|
12071
12437
|
}
|
|
12072
|
-
|
|
12073
|
-
|
|
12074
|
-
function shiftIntoView(desired, size, viewport) {
|
|
12075
|
-
const max = Math.max(viewport - size - VIEWPORT_PADDING2, VIEWPORT_PADDING2);
|
|
12076
|
-
return Math.min(Math.max(desired, VIEWPORT_PADDING2), max) - desired;
|
|
12438
|
+
function formatDate(year, month, day) {
|
|
12439
|
+
return `${year}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
|
|
12077
12440
|
}
|
|
12078
|
-
function
|
|
12079
|
-
|
|
12080
|
-
|
|
12081
|
-
|
|
12082
|
-
const row = v("--cmp-calendarBoard-item-height") + gap;
|
|
12083
|
-
if (row <= 0) return null;
|
|
12084
|
-
const header = v("--cmp-calendarBoard-dayCard-header-paddingTop") + v("--cmp-calendarBoard-daySequence-size") + v("--cmp-calendarBoard-dayCard-header-paddingBottom");
|
|
12085
|
-
const free = cell.getBoundingClientRect().height - header - v("--cmp-calendarBoard-dayCard-grid-paddingBottom") + gap;
|
|
12086
|
-
if (free <= 0) return null;
|
|
12087
|
-
return Math.max(1, Math.floor(free / row));
|
|
12441
|
+
function calcYearMonth(year, month, dir) {
|
|
12442
|
+
if (dir === "prev")
|
|
12443
|
+
return month === 1 ? { year: year - 1, month: 12 } : { year, month: month - 1 };
|
|
12444
|
+
return month === 12 ? { year: year + 1, month: 1 } : { year, month: month + 1 };
|
|
12088
12445
|
}
|
|
12089
|
-
function
|
|
12090
|
-
year,
|
|
12091
|
-
month,
|
|
12092
|
-
|
|
12093
|
-
|
|
12094
|
-
|
|
12095
|
-
|
|
12096
|
-
|
|
12097
|
-
|
|
12098
|
-
|
|
12099
|
-
|
|
12100
|
-
|
|
12101
|
-
|
|
12102
|
-
|
|
12103
|
-
|
|
12104
|
-
|
|
12105
|
-
|
|
12106
|
-
|
|
12107
|
-
|
|
12108
|
-
}
|
|
12109
|
-
|
|
12110
|
-
|
|
12111
|
-
|
|
12112
|
-
|
|
12113
|
-
|
|
12114
|
-
|
|
12115
|
-
|
|
12116
|
-
|
|
12117
|
-
|
|
12118
|
-
|
|
12119
|
-
|
|
12120
|
-
|
|
12121
|
-
|
|
12122
|
-
|
|
12123
|
-
|
|
12124
|
-
|
|
12125
|
-
|
|
12126
|
-
|
|
12127
|
-
|
|
12128
|
-
)
|
|
12129
|
-
|
|
12130
|
-
|
|
12131
|
-
|
|
12132
|
-
|
|
12133
|
-
|
|
12134
|
-
|
|
12135
|
-
|
|
12136
|
-
|
|
12137
|
-
|
|
12138
|
-
|
|
12139
|
-
|
|
12140
|
-
|
|
12141
|
-
|
|
12142
|
-
|
|
12143
|
-
|
|
12144
|
-
|
|
12145
|
-
|
|
12146
|
-
|
|
12147
|
-
|
|
12148
|
-
|
|
12149
|
-
|
|
12150
|
-
|
|
12151
|
-
|
|
12152
|
-
|
|
12153
|
-
|
|
12154
|
-
|
|
12155
|
-
|
|
12156
|
-
const
|
|
12157
|
-
|
|
12158
|
-
|
|
12159
|
-
|
|
12160
|
-
|
|
12161
|
-
const adjust = () => {
|
|
12162
|
-
const cellRect = cell.getBoundingClientRect();
|
|
12163
|
-
const panelRect = panelEl.getBoundingClientRect();
|
|
12164
|
-
const next = {
|
|
12165
|
-
cellWidth: cellRect.width,
|
|
12166
|
-
cellHeight: cellRect.height,
|
|
12167
|
-
side: -(cellRect.height + DAY_EVENT_OUTDENT) + shiftIntoView(cellRect.top - DAY_EVENT_OUTDENT, panelRect.height, window.innerHeight),
|
|
12168
|
-
align: -DAY_EVENT_OUTDENT + shiftIntoView(cellRect.left - DAY_EVENT_OUTDENT, panelRect.width, window.innerWidth)
|
|
12169
|
-
};
|
|
12170
|
-
setPlacement(
|
|
12171
|
-
(prev) => prev.cellWidth === next.cellWidth && prev.cellHeight === next.cellHeight && prev.side === next.side && prev.align === next.align ? prev : next
|
|
12172
|
-
);
|
|
12173
|
-
};
|
|
12174
|
-
adjust();
|
|
12175
|
-
const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(adjust);
|
|
12176
|
-
observer?.observe(panelEl);
|
|
12177
|
-
window.addEventListener("scroll", adjust, true);
|
|
12178
|
-
window.addEventListener("resize", adjust);
|
|
12179
|
-
return () => {
|
|
12180
|
-
observer?.disconnect();
|
|
12181
|
-
window.removeEventListener("scroll", adjust, true);
|
|
12182
|
-
window.removeEventListener("resize", adjust);
|
|
12183
|
-
};
|
|
12184
|
-
}, [openDate, panelEl]);
|
|
12185
|
-
const columns = "repeat(7, minmax(var(--cmp-calendarBoard-dayCard-minWidth), 1fr))";
|
|
12186
|
-
const openEventList = (date, list) => {
|
|
12187
|
-
if (onMoreClick) {
|
|
12188
|
-
onMoreClick({ date, events: list });
|
|
12189
|
-
return;
|
|
12190
|
-
}
|
|
12191
|
-
setOpenDate((prev) => prev === date ? null : date);
|
|
12192
|
-
};
|
|
12446
|
+
function monthCells(year, month) {
|
|
12447
|
+
const firstDayIndex = new Date(year, month - 1, 1).getDay();
|
|
12448
|
+
const daysInCurrent = new Date(year, month, 0).getDate();
|
|
12449
|
+
const prev = calcYearMonth(year, month, "prev");
|
|
12450
|
+
const daysInPrev = new Date(prev.year, prev.month, 0).getDate();
|
|
12451
|
+
const next = calcYearMonth(year, month, "next");
|
|
12452
|
+
const cells = [];
|
|
12453
|
+
for (let i = firstDayIndex - 1; i >= 0; i--) {
|
|
12454
|
+
const day = daysInPrev - i;
|
|
12455
|
+
cells.push({ date: formatDate(prev.year, prev.month, day), day, inCurrentMonth: false });
|
|
12456
|
+
}
|
|
12457
|
+
for (let day = 1; day <= daysInCurrent; day++) {
|
|
12458
|
+
cells.push({ date: formatDate(year, month, day), day, inCurrentMonth: true });
|
|
12459
|
+
}
|
|
12460
|
+
const remaining = (7 - cells.length % 7) % 7;
|
|
12461
|
+
for (let day = 1; day <= remaining; day++) {
|
|
12462
|
+
cells.push({ date: formatDate(next.year, next.month, day), day, inCurrentMonth: false });
|
|
12463
|
+
}
|
|
12464
|
+
return cells;
|
|
12465
|
+
}
|
|
12466
|
+
var WEEK_LABELS = ["\uC77C", "\uC6D4", "\uD654", "\uC218", "\uBAA9", "\uAE08", "\uD1A0"];
|
|
12467
|
+
|
|
12468
|
+
// src/components/SCalendarBoard/calendarBoard.config.ts
|
|
12469
|
+
var CALENDAR_BOARD_EVENT_COLORS = [
|
|
12470
|
+
"default",
|
|
12471
|
+
"blue",
|
|
12472
|
+
"oceanBlue",
|
|
12473
|
+
"lightBlue",
|
|
12474
|
+
"green",
|
|
12475
|
+
"yellow",
|
|
12476
|
+
"orange",
|
|
12477
|
+
"red",
|
|
12478
|
+
"white"
|
|
12479
|
+
];
|
|
12480
|
+
var BG = (name) => `var(--cmp-calendarBoard-eventButton-bg-${name})`;
|
|
12481
|
+
var CALENDAR_BOARD_EVENT_PRESETS = {
|
|
12482
|
+
default: { bg: BG("default"), dot: "indigo" },
|
|
12483
|
+
blue: { bg: BG("blue"), dot: "blue" },
|
|
12484
|
+
oceanBlue: { bg: BG("oceanBlue"), dot: "darkblue" },
|
|
12485
|
+
lightBlue: { bg: BG("lightBlue"), dot: "lightblue" },
|
|
12486
|
+
green: { bg: BG("green"), dot: "green" },
|
|
12487
|
+
yellow: { bg: BG("yellow"), dot: "yellow" },
|
|
12488
|
+
orange: { bg: BG("orange"), dot: "orange" },
|
|
12489
|
+
red: { bg: BG("red"), dot: "red" },
|
|
12490
|
+
white: { bg: BG("white"), dot: "grey" }
|
|
12491
|
+
};
|
|
12492
|
+
var CALENDAR_BOARD_MAX_VISIBLE_EVENTS = 4;
|
|
12493
|
+
var CALENDAR_BOARD_DAY_COLORS = [
|
|
12494
|
+
"default",
|
|
12495
|
+
"danger",
|
|
12496
|
+
"accent",
|
|
12497
|
+
"complete",
|
|
12498
|
+
"dim"
|
|
12499
|
+
];
|
|
12500
|
+
var CALENDAR_BOARD_DAY_BG = {
|
|
12501
|
+
default: "var(--cmp-calendarBoard-dayCard-bg)",
|
|
12502
|
+
danger: "var(--color-red-30)",
|
|
12503
|
+
accent: "var(--color-brilliantblue-40)",
|
|
12504
|
+
complete: "var(--color-green-45)",
|
|
12505
|
+
dim: "var(--color-grey-25)"
|
|
12506
|
+
};
|
|
12507
|
+
function CalendarEventButton({
|
|
12508
|
+
event,
|
|
12509
|
+
onSelect,
|
|
12510
|
+
className
|
|
12511
|
+
}) {
|
|
12512
|
+
const preset = CALENDAR_BOARD_EVENT_PRESETS[event.color ?? "default"];
|
|
12513
|
+
const dot = event.dotColor ?? preset.dot;
|
|
12514
|
+
const disabled = event.disabled === true;
|
|
12515
|
+
const hasDescription = event.description != null && event.description !== "";
|
|
12516
|
+
const hasValue = event.value != null && event.value !== "";
|
|
12517
|
+
const title = [event.label.replace(/<[^>]*>/g, ""), event.description, event.value].filter((v) => v != null && v !== "").join(" ") || void 0;
|
|
12193
12518
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12194
|
-
"
|
|
12519
|
+
"button",
|
|
12195
12520
|
{
|
|
12521
|
+
type: "button",
|
|
12522
|
+
disabled,
|
|
12523
|
+
title,
|
|
12196
12524
|
className: cn(
|
|
12197
|
-
//
|
|
12198
|
-
"flex
|
|
12525
|
+
// hover 는 배경 위에 8% 오버레이를 얹는다 — 프리셋 배경이 9종이라 색마다 hover 색을 두지 않는다.
|
|
12526
|
+
"group relative flex w-full min-w-0 items-center overflow-hidden text-left",
|
|
12527
|
+
"h-(--cmp-calendarBoard-item-height) shrink-0 rounded-(--cmp-calendarBoard-item-radius)",
|
|
12528
|
+
"gap-(--cmp-calendarBoard-eventButton-inline-gap) px-(--cmp-calendarBoard-item-paddingX)",
|
|
12529
|
+
"bg-(--ceb-bg) text-(--cmp-calendarBoard-eventButton-text-color-default)",
|
|
12530
|
+
disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer",
|
|
12199
12531
|
className
|
|
12200
12532
|
),
|
|
12201
|
-
style,
|
|
12533
|
+
style: { "--ceb-bg": preset.bg },
|
|
12534
|
+
onClick: (e) => {
|
|
12535
|
+
if (disabled) return;
|
|
12536
|
+
onSelect?.(event, e);
|
|
12537
|
+
},
|
|
12202
12538
|
children: [
|
|
12203
|
-
/* @__PURE__ */ jsxRuntime.
|
|
12204
|
-
|
|
12539
|
+
!disabled && /* @__PURE__ */ jsxRuntime.jsx(
|
|
12540
|
+
"span",
|
|
12541
|
+
{
|
|
12542
|
+
"aria-hidden": true,
|
|
12543
|
+
className: "pointer-events-none absolute inset-0 rounded-(--cmp-calendarBoard-item-radius) bg-(--cmp-calendarBoard-eventButton-hover-overlay-color) opacity-0 transition-opacity group-hover:opacity-(--cmp-calendarBoard-eventButton-hover-overlay-opacity)"
|
|
12544
|
+
}
|
|
12545
|
+
),
|
|
12546
|
+
/* @__PURE__ */ jsxRuntime.jsx(SBadge, { "aria-hidden": true, color: dot, className: "shrink-0" }),
|
|
12547
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-1 items-center gap-(--cmp-calendarBoard-eventButton-label-gap)", children: [
|
|
12548
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "typo-body-sm-default min-w-0 flex-1 truncate", children: [
|
|
12205
12549
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12206
|
-
|
|
12550
|
+
"span",
|
|
12207
12551
|
{
|
|
12208
|
-
|
|
12209
|
-
|
|
12210
|
-
|
|
12211
|
-
|
|
12552
|
+
className: cn(
|
|
12553
|
+
"typo-body-sm-semibold",
|
|
12554
|
+
hasDescription && "me-(--cmp-calendarBoard-eventButton-label-gap)"
|
|
12555
|
+
),
|
|
12556
|
+
dangerouslySetInnerHTML: { __html: sanitizeInlineHtml(event.label) }
|
|
12212
12557
|
}
|
|
12213
12558
|
),
|
|
12214
|
-
|
|
12215
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12216
|
-
SGhostButton,
|
|
12217
|
-
{
|
|
12218
|
-
icon: "chevronRight",
|
|
12219
|
-
size: "xxs",
|
|
12220
|
-
ariaLabel: "\uB2E4\uC74C \uD574",
|
|
12221
|
-
onClick: () => setView({ year: view.year + 1, month: view.month })
|
|
12222
|
-
}
|
|
12223
|
-
)
|
|
12559
|
+
hasDescription && event.description
|
|
12224
12560
|
] }),
|
|
12225
|
-
/* @__PURE__ */ jsxRuntime.
|
|
12226
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-(--cmp-calendarBoard-header-content-gap)", children: [
|
|
12561
|
+
hasValue && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex shrink-0 items-center gap-(--cmp-calendarBoard-eventButton-label-gap)", children: [
|
|
12227
12562
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12228
|
-
|
|
12563
|
+
"span",
|
|
12229
12564
|
{
|
|
12230
|
-
|
|
12231
|
-
|
|
12232
|
-
|
|
12233
|
-
onClick: () => setView(calcYearMonth(view.year, view.month, "prev"))
|
|
12565
|
+
"aria-hidden": true,
|
|
12566
|
+
className: "typo-body-sm-default text-(--cmp-calendarBoard-eventButton-text-color-separator)",
|
|
12567
|
+
children: "/"
|
|
12234
12568
|
}
|
|
12235
12569
|
),
|
|
12236
|
-
/* @__PURE__ */ jsxRuntime.
|
|
12237
|
-
|
|
12238
|
-
|
|
12239
|
-
|
|
12240
|
-
|
|
12241
|
-
|
|
12242
|
-
|
|
12243
|
-
|
|
12244
|
-
|
|
12245
|
-
|
|
12246
|
-
|
|
12247
|
-
|
|
12248
|
-
|
|
12249
|
-
|
|
12250
|
-
|
|
12251
|
-
|
|
12252
|
-
|
|
12253
|
-
|
|
12254
|
-
|
|
12255
|
-
|
|
12256
|
-
|
|
12257
|
-
|
|
12258
|
-
}
|
|
12259
|
-
),
|
|
12260
|
-
headerRight != null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-auto flex items-center", children: headerRight })
|
|
12261
|
-
] }),
|
|
12262
|
-
/* @__PURE__ */ jsxRuntime.jsx(SDivider, {}),
|
|
12570
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "typo-body-sm-default whitespace-nowrap", children: event.value })
|
|
12571
|
+
] })
|
|
12572
|
+
] })
|
|
12573
|
+
]
|
|
12574
|
+
}
|
|
12575
|
+
);
|
|
12576
|
+
}
|
|
12577
|
+
var CalendarMoreButton = /* @__PURE__ */ react.forwardRef(function CalendarMoreButton2({ count, label = "\uB354\uBCF4\uAE30", onClick, className }, ref) {
|
|
12578
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12579
|
+
"button",
|
|
12580
|
+
{
|
|
12581
|
+
ref,
|
|
12582
|
+
type: "button",
|
|
12583
|
+
className: cn(
|
|
12584
|
+
"group relative flex w-full min-w-0 cursor-pointer items-center overflow-hidden text-left",
|
|
12585
|
+
"h-(--cmp-calendarBoard-item-height) shrink-0 rounded-(--cmp-calendarBoard-item-radius)",
|
|
12586
|
+
"gap-(--cmp-calendarBoard-moreButton-gap) px-(--cmp-calendarBoard-item-paddingX)",
|
|
12587
|
+
"bg-(--cmp-calendarBoard-moreButton-bg)",
|
|
12588
|
+
className
|
|
12589
|
+
),
|
|
12590
|
+
onClick,
|
|
12591
|
+
children: [
|
|
12263
12592
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12264
|
-
"
|
|
12593
|
+
"span",
|
|
12265
12594
|
{
|
|
12266
|
-
|
|
12267
|
-
|
|
12268
|
-
children: WEEK_LABELS.map((label) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
12269
|
-
"div",
|
|
12270
|
-
{
|
|
12271
|
-
className: "typo-body-md-default flex justify-center text-(--cmp-calendarBoard-grid-weekRow-color)",
|
|
12272
|
-
children: label
|
|
12273
|
-
},
|
|
12274
|
-
label
|
|
12275
|
-
))
|
|
12595
|
+
"aria-hidden": true,
|
|
12596
|
+
className: "pointer-events-none absolute inset-0 rounded-(--cmp-calendarBoard-item-radius) bg-(--cmp-calendarBoard-moreButton-hover-overlay-color) opacity-0 transition-opacity group-hover:opacity-(--cmp-calendarBoard-moreButton-hover-overlay-opacity)"
|
|
12276
12597
|
}
|
|
12277
12598
|
),
|
|
12278
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
12279
|
-
|
|
12280
|
-
|
|
12281
|
-
|
|
12282
|
-
|
|
12283
|
-
|
|
12284
|
-
|
|
12285
|
-
|
|
12286
|
-
|
|
12287
|
-
|
|
12288
|
-
|
|
12289
|
-
|
|
12290
|
-
|
|
12291
|
-
|
|
12292
|
-
|
|
12293
|
-
|
|
12294
|
-
|
|
12295
|
-
|
|
12296
|
-
|
|
12297
|
-
|
|
12298
|
-
|
|
12299
|
-
|
|
12300
|
-
|
|
12301
|
-
|
|
12302
|
-
|
|
12303
|
-
|
|
12304
|
-
|
|
12305
|
-
|
|
12306
|
-
|
|
12307
|
-
|
|
12308
|
-
|
|
12309
|
-
|
|
12310
|
-
|
|
12311
|
-
|
|
12312
|
-
|
|
12313
|
-
|
|
12314
|
-
|
|
12315
|
-
|
|
12316
|
-
|
|
12317
|
-
|
|
12318
|
-
|
|
12319
|
-
|
|
12320
|
-
|
|
12321
|
-
|
|
12322
|
-
|
|
12323
|
-
|
|
12324
|
-
|
|
12325
|
-
|
|
12599
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "typo-body-sm-semibold shrink-0 text-(--cmp-calendarBoard-moreButton-count-color)", children: [
|
|
12600
|
+
count,
|
|
12601
|
+
"\uAC1C"
|
|
12602
|
+
] }),
|
|
12603
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "typo-body-sm-default min-w-0 truncate text-(--cmp-calendarBoard-moreButton-label-color)", children: label })
|
|
12604
|
+
]
|
|
12605
|
+
}
|
|
12606
|
+
);
|
|
12607
|
+
});
|
|
12608
|
+
var CalendarDayCard = /* @__PURE__ */ react.forwardRef(function CalendarDayCard2({
|
|
12609
|
+
date,
|
|
12610
|
+
day,
|
|
12611
|
+
inCurrentMonth,
|
|
12612
|
+
isToday,
|
|
12613
|
+
isSelected,
|
|
12614
|
+
selectable,
|
|
12615
|
+
color,
|
|
12616
|
+
events,
|
|
12617
|
+
body,
|
|
12618
|
+
hiddenCount,
|
|
12619
|
+
isOpen,
|
|
12620
|
+
moreLabel,
|
|
12621
|
+
onDaySelect,
|
|
12622
|
+
onEventClick,
|
|
12623
|
+
onOpenEvents,
|
|
12624
|
+
...rest
|
|
12625
|
+
}, ref) {
|
|
12626
|
+
const hasEvents = events.length + hiddenCount > 0;
|
|
12627
|
+
const interactive = selectable || hasEvents;
|
|
12628
|
+
const activate = () => {
|
|
12629
|
+
if (hasEvents) onOpenEvents?.();
|
|
12630
|
+
if (selectable) onDaySelect?.(date);
|
|
12631
|
+
};
|
|
12632
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12633
|
+
"div",
|
|
12634
|
+
{
|
|
12635
|
+
...rest,
|
|
12636
|
+
ref,
|
|
12637
|
+
role: "gridcell",
|
|
12638
|
+
"data-date": date,
|
|
12639
|
+
"aria-selected": selectable ? isSelected : void 0,
|
|
12640
|
+
"aria-current": isToday ? "date" : void 0,
|
|
12641
|
+
"aria-haspopup": hasEvents ? "dialog" : void 0,
|
|
12642
|
+
"aria-expanded": hasEvents ? isOpen : void 0,
|
|
12643
|
+
tabIndex: interactive ? 0 : void 0,
|
|
12644
|
+
onClick: interactive ? activate : void 0,
|
|
12645
|
+
onKeyDown: interactive ? (e) => {
|
|
12646
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
12647
|
+
e.preventDefault();
|
|
12648
|
+
activate();
|
|
12649
|
+
}
|
|
12650
|
+
} : void 0,
|
|
12651
|
+
className: cn(
|
|
12652
|
+
"relative flex min-h-(--cmp-calendarBoard-dayCard-minHeight) min-w-(--cmp-calendarBoard-dayCard-minWidth) flex-col bg-(--cdc-bg) px-(--cmp-calendarBoard-dayCard-paddingX) outline-none",
|
|
12653
|
+
interactive && "cursor-pointer"
|
|
12654
|
+
),
|
|
12655
|
+
style: { ...rest.style, "--cdc-bg": CALENDAR_BOARD_DAY_BG[color] },
|
|
12656
|
+
children: [
|
|
12657
|
+
isSelected && /* @__PURE__ */ jsxRuntime.jsx(
|
|
12658
|
+
"span",
|
|
12659
|
+
{
|
|
12660
|
+
"aria-hidden": true,
|
|
12661
|
+
className: "pointer-events-none absolute inset-[1px] rounded-(--cmp-calendarBoard-dayCard-focus-border-radius) border-(length:--cmp-calendarBoard-dayCard-focus-border-width) border-solid border-(--cmp-calendarBoard-dayCard-focus-border-color)"
|
|
12662
|
+
}
|
|
12663
|
+
),
|
|
12664
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex shrink-0 pt-(--cmp-calendarBoard-dayCard-header-paddingTop) pb-(--cmp-calendarBoard-dayCard-header-paddingBottom)", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12665
|
+
"span",
|
|
12666
|
+
{
|
|
12667
|
+
className: cn(
|
|
12668
|
+
"inline-flex size-(--cmp-calendarBoard-daySequence-size) items-center justify-center rounded-(--cmp-calendarBoard-daySequence-radius)",
|
|
12669
|
+
isToday ? "typo-body-md-bold bg-(--cmp-calendarBoard-daySequence-bg-today) text-(--cmp-calendarBoard-daySequence-text-today)" : cn(
|
|
12670
|
+
"typo-body-md-medium",
|
|
12671
|
+
inCurrentMonth ? "text-(--cmp-calendarBoard-daySequence-text-default)" : "text-(--cmp-calendarBoard-daySequence-text-otherMonth)"
|
|
12326
12672
|
),
|
|
12327
|
-
|
|
12328
|
-
|
|
12673
|
+
// 오늘이 아니면서 선택된 날은 테두리 원으로 표시한다 (오늘은 이미 채운 원이라 겹치지 않는다).
|
|
12674
|
+
// 굵기는 1px 로 고정한다 — 칸을 감싸는 focus 테두리(2px)와 달리 얇은 원이고, 대응 토큰이 없다.
|
|
12675
|
+
isSelected && !isToday && "border border-solid border-(--cmp-calendarBoard-daySequence-border-selected)"
|
|
12676
|
+
),
|
|
12677
|
+
children: day
|
|
12678
|
+
}
|
|
12679
|
+
) }),
|
|
12680
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
12681
|
+
"div",
|
|
12682
|
+
{
|
|
12683
|
+
className: cn(
|
|
12684
|
+
"flex min-h-0 flex-col gap-(--cmp-calendarBoard-dayCard-grid-gap) pb-(--cmp-calendarBoard-dayCard-grid-paddingBottom)",
|
|
12685
|
+
// 슬롯은 남는 세로를 다 갖는다 — 안에서 h-full 로 칸을 채울 수 있어야 한다.
|
|
12686
|
+
body != null && "flex-1"
|
|
12687
|
+
),
|
|
12688
|
+
children: [
|
|
12689
|
+
body,
|
|
12690
|
+
body == null && events.map((event, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
12691
|
+
CalendarEventButton,
|
|
12329
12692
|
{
|
|
12330
|
-
|
|
12331
|
-
|
|
12332
|
-
|
|
12333
|
-
|
|
12334
|
-
|
|
12335
|
-
align: "start",
|
|
12336
|
-
ref: setPanelEl,
|
|
12337
|
-
sideOffset: placement.side,
|
|
12338
|
-
alignOffset: placement.align,
|
|
12339
|
-
avoidCollisions: false,
|
|
12340
|
-
className: cn("z-50 outline-none", FLOATING_SLIDE_ANIM),
|
|
12341
|
-
onOpenAutoFocus: (e) => e.preventDefault(),
|
|
12342
|
-
children: openDate != null && /* @__PURE__ */ jsxRuntime.jsx(
|
|
12343
|
-
CalendarDayEventListBox,
|
|
12344
|
-
{
|
|
12345
|
-
date: openDate,
|
|
12346
|
-
minWidth: placement.cellWidth > 0 ? placement.cellWidth + DAY_EVENT_OUTDENT * 2 : void 0,
|
|
12347
|
-
minHeight: placement.cellHeight > 0 ? placement.cellHeight + DAY_EVENT_OUTDENT * 2 : void 0,
|
|
12348
|
-
events: openEvents,
|
|
12349
|
-
onEventClick,
|
|
12350
|
-
onClose: () => setOpenDate(null)
|
|
12351
|
-
}
|
|
12352
|
-
)
|
|
12693
|
+
event,
|
|
12694
|
+
onSelect: (ev, e) => {
|
|
12695
|
+
e.stopPropagation();
|
|
12696
|
+
onEventClick?.(ev, e);
|
|
12697
|
+
}
|
|
12353
12698
|
},
|
|
12354
|
-
|
|
12355
|
-
)
|
|
12699
|
+
event.id ?? `${event.date}-${i}`
|
|
12700
|
+
)),
|
|
12701
|
+
hiddenCount > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
12702
|
+
CalendarMoreButton,
|
|
12703
|
+
{
|
|
12704
|
+
count: hiddenCount,
|
|
12705
|
+
label: moreLabel,
|
|
12706
|
+
onClick: (e) => {
|
|
12707
|
+
e.stopPropagation();
|
|
12708
|
+
onOpenEvents?.();
|
|
12709
|
+
}
|
|
12710
|
+
}
|
|
12711
|
+
)
|
|
12356
12712
|
]
|
|
12357
12713
|
}
|
|
12358
12714
|
)
|
|
12359
12715
|
]
|
|
12360
12716
|
}
|
|
12361
12717
|
);
|
|
12362
|
-
}
|
|
12363
|
-
|
|
12364
|
-
|
|
12365
|
-
|
|
12366
|
-
|
|
12367
|
-
|
|
12368
|
-
|
|
12369
|
-
return `min(${css}, ${availableHeight})`;
|
|
12370
|
-
}
|
|
12371
|
-
function runRules(value, rules) {
|
|
12372
|
-
if (!rules || rules.length === 0) return "";
|
|
12373
|
-
for (const rule of rules) {
|
|
12374
|
-
const result = rule(value ?? "");
|
|
12375
|
-
if (result !== true) return typeof result === "string" ? result : "\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 \uAC12\uC785\uB2C8\uB2E4.";
|
|
12376
|
-
}
|
|
12377
|
-
return "";
|
|
12378
|
-
}
|
|
12379
|
-
var FormContext = /* @__PURE__ */ react.createContext(null);
|
|
12380
|
-
function useFormContext() {
|
|
12381
|
-
return react.useContext(FormContext);
|
|
12382
|
-
}
|
|
12383
|
-
function useFormField(field) {
|
|
12384
|
-
const ctx = useFormContext();
|
|
12385
|
-
const cbRef = react.useRef(field);
|
|
12386
|
-
cbRef.current = field;
|
|
12387
|
-
const name = field.name ?? "";
|
|
12388
|
-
react.useEffect(() => {
|
|
12389
|
-
if (!ctx) return;
|
|
12390
|
-
return ctx.register({
|
|
12391
|
-
name,
|
|
12392
|
-
validate: () => cbRef.current.validate(),
|
|
12393
|
-
resetValidation: () => cbRef.current.resetValidation()
|
|
12394
|
-
});
|
|
12395
|
-
}, [ctx, name]);
|
|
12396
|
-
}
|
|
12397
|
-
var FIELD_SIZE = {
|
|
12398
|
-
sm: { height: 28, radius: 4, fieldGap: 12, labelGap: 6, fontSize: 12, lineHeight: 20, icon: 16 },
|
|
12399
|
-
md: { height: 36, radius: 6, fieldGap: 16, labelGap: 8, fontSize: 14, lineHeight: 24, icon: 16 }
|
|
12400
|
-
};
|
|
12401
|
-
var ALIGN = {
|
|
12402
|
-
start: "flex-start",
|
|
12403
|
-
center: "center",
|
|
12404
|
-
end: "flex-end"
|
|
12405
|
-
};
|
|
12406
|
-
var FOCUS_RING_SHADOW = "0px 0px 4px 0px #0071ff66";
|
|
12407
|
-
var cssLen = (v) => v === void 0 || v === "" || v === 0 ? void 0 : typeof v === "number" ? `${v}px` : v;
|
|
12408
|
-
var SField = /* @__PURE__ */ react.forwardRef(function SField2({
|
|
12409
|
-
name,
|
|
12410
|
-
label = "",
|
|
12411
|
-
icon,
|
|
12412
|
-
iconColor,
|
|
12413
|
-
labelTooltip = "",
|
|
12414
|
-
labelTooltipProps,
|
|
12415
|
-
labelWidth,
|
|
12416
|
-
labelHeight,
|
|
12417
|
-
size = "sm",
|
|
12418
|
-
addonLabel = "",
|
|
12419
|
-
addonAlign = "start",
|
|
12420
|
-
error = false,
|
|
12421
|
-
errorMessage = "",
|
|
12422
|
-
status,
|
|
12423
|
-
focused = false,
|
|
12424
|
-
hovered = false,
|
|
12425
|
-
rules: _rules,
|
|
12426
|
-
hint = "",
|
|
12427
|
-
disabled = false,
|
|
12428
|
-
readOnly = false,
|
|
12429
|
-
width,
|
|
12718
|
+
});
|
|
12719
|
+
var MAX_HEIGHT = 480;
|
|
12720
|
+
var MAX_WIDTH = "calc(100vw - 16px)";
|
|
12721
|
+
function CalendarDayEventListBox({
|
|
12722
|
+
date,
|
|
12723
|
+
events,
|
|
12724
|
+
onEventClick,
|
|
12430
12725
|
minWidth,
|
|
12431
|
-
|
|
12432
|
-
|
|
12433
|
-
|
|
12434
|
-
|
|
12435
|
-
|
|
12436
|
-
|
|
12437
|
-
|
|
12438
|
-
|
|
12439
|
-
|
|
12440
|
-
|
|
12441
|
-
|
|
12442
|
-
|
|
12443
|
-
|
|
12444
|
-
|
|
12445
|
-
|
|
12446
|
-
|
|
12447
|
-
|
|
12448
|
-
"
|
|
12449
|
-
|
|
12450
|
-
|
|
12451
|
-
|
|
12452
|
-
|
|
12453
|
-
|
|
12454
|
-
|
|
12726
|
+
minHeight,
|
|
12727
|
+
onClose,
|
|
12728
|
+
closeLabel = "\uB2EB\uAE30"
|
|
12729
|
+
}) {
|
|
12730
|
+
const [y, m, d] = date.split("-").map(Number);
|
|
12731
|
+
const weekday = WEEK_LABELS[new Date(y, m - 1, d).getDay()];
|
|
12732
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12733
|
+
"div",
|
|
12734
|
+
{
|
|
12735
|
+
className: "flex w-max flex-col overflow-hidden rounded-(--cmp-calendarBoard-radius) bg-(--cmp-calendarBoard-bg) shadow-(--shadow-overlay)",
|
|
12736
|
+
style: { minWidth, maxWidth: MAX_WIDTH, minHeight, maxHeight: MAX_HEIGHT },
|
|
12737
|
+
children: [
|
|
12738
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-(--cmp-calendarBoard-dayEvent-header-gap) px-(--cmp-calendarBoard-dayEvent-header-paddingX) py-(--cmp-calendarBoard-dayEvent-header-paddingY)", children: [
|
|
12739
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "typo-heading-md text-(--cmp-calendarBoard-header-content-color)", children: [
|
|
12740
|
+
d,
|
|
12741
|
+
"\uC77C"
|
|
12742
|
+
] }),
|
|
12743
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "typo-body-lg-default flex-1 text-(--cmp-calendarBoard-header-content-color)", children: [
|
|
12744
|
+
"(",
|
|
12745
|
+
weekday,
|
|
12746
|
+
")"
|
|
12747
|
+
] }),
|
|
12748
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12749
|
+
SGhostButton,
|
|
12750
|
+
{
|
|
12751
|
+
icon: "close",
|
|
12752
|
+
size: "xs",
|
|
12753
|
+
ariaLabel: closeLabel,
|
|
12754
|
+
className: "shrink-0",
|
|
12755
|
+
onClick: onClose
|
|
12756
|
+
}
|
|
12757
|
+
)
|
|
12758
|
+
] }),
|
|
12759
|
+
/* @__PURE__ */ jsxRuntime.jsx(SScrollArea, { axis: "vertical", className: "min-h-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-(--cmp-calendarBoard-dayEvent-body-gap) px-(--cmp-calendarBoard-dayEvent-body-paddingX) pb-(--cmp-calendarBoard-dayEvent-body-paddingBottom)", children: events.map((event, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
12760
|
+
CalendarEventButton,
|
|
12761
|
+
{
|
|
12762
|
+
event,
|
|
12763
|
+
onSelect: onEventClick
|
|
12764
|
+
},
|
|
12765
|
+
event.id ?? `${event.date}-${i}`
|
|
12766
|
+
)) }) })
|
|
12767
|
+
]
|
|
12768
|
+
}
|
|
12455
12769
|
);
|
|
12456
|
-
|
|
12457
|
-
|
|
12458
|
-
|
|
12459
|
-
|
|
12460
|
-
|
|
12461
|
-
|
|
12462
|
-
|
|
12463
|
-
|
|
12464
|
-
const
|
|
12465
|
-
const
|
|
12466
|
-
const
|
|
12467
|
-
const
|
|
12468
|
-
|
|
12469
|
-
const
|
|
12470
|
-
const
|
|
12471
|
-
|
|
12472
|
-
|
|
12473
|
-
|
|
12474
|
-
|
|
12475
|
-
|
|
12476
|
-
|
|
12770
|
+
}
|
|
12771
|
+
var DAY_EVENT_OUTDENT = 16;
|
|
12772
|
+
var VIEWPORT_PADDING2 = 8;
|
|
12773
|
+
function shiftIntoView(desired, size, viewport) {
|
|
12774
|
+
const max = Math.max(viewport - size - VIEWPORT_PADDING2, VIEWPORT_PADDING2);
|
|
12775
|
+
return Math.min(Math.max(desired, VIEWPORT_PADDING2), max) - desired;
|
|
12776
|
+
}
|
|
12777
|
+
function measureRowCapacity(cell) {
|
|
12778
|
+
const cs = getComputedStyle(cell);
|
|
12779
|
+
const v = (name) => Number.parseFloat(cs.getPropertyValue(name)) || 0;
|
|
12780
|
+
const gap = v("--cmp-calendarBoard-dayCard-grid-gap");
|
|
12781
|
+
const row = v("--cmp-calendarBoard-item-height") + gap;
|
|
12782
|
+
if (row <= 0) return null;
|
|
12783
|
+
const header = v("--cmp-calendarBoard-dayCard-header-paddingTop") + v("--cmp-calendarBoard-daySequence-size") + v("--cmp-calendarBoard-dayCard-header-paddingBottom");
|
|
12784
|
+
const free = cell.getBoundingClientRect().height - header - v("--cmp-calendarBoard-dayCard-grid-paddingBottom") + gap;
|
|
12785
|
+
if (free <= 0) return null;
|
|
12786
|
+
return Math.max(1, Math.floor(free / row));
|
|
12787
|
+
}
|
|
12788
|
+
function SCalendarBoard({
|
|
12789
|
+
year,
|
|
12790
|
+
month,
|
|
12791
|
+
defaultYear,
|
|
12792
|
+
defaultMonth,
|
|
12793
|
+
onViewChange,
|
|
12794
|
+
selectable = false,
|
|
12795
|
+
value,
|
|
12796
|
+
onValueChange,
|
|
12797
|
+
events,
|
|
12798
|
+
dayColors,
|
|
12799
|
+
dayContent,
|
|
12800
|
+
onEventClick,
|
|
12801
|
+
onMoreClick,
|
|
12802
|
+
todayLabel = "\uC624\uB298",
|
|
12803
|
+
moreLabel,
|
|
12804
|
+
headerRight,
|
|
12805
|
+
className,
|
|
12806
|
+
style
|
|
12807
|
+
}) {
|
|
12808
|
+
const today = todayStr();
|
|
12809
|
+
const [ty, tm] = [Number(today.slice(0, 4)), Number(today.slice(5, 7))];
|
|
12810
|
+
const [innerView, setInnerView] = react.useState(() => ({
|
|
12811
|
+
year: defaultYear ?? ty,
|
|
12812
|
+
month: defaultMonth ?? tm
|
|
12813
|
+
}));
|
|
12814
|
+
const controlled = year != null && month != null;
|
|
12815
|
+
const view = controlled ? { year, month } : innerView;
|
|
12816
|
+
const [openDate, setOpenDate] = react.useState(null);
|
|
12817
|
+
const [placement, setPlacement] = react.useState({ cellWidth: 0, cellHeight: 0, side: 0, align: 0 });
|
|
12818
|
+
const [panelEl, setPanelEl] = react.useState(null);
|
|
12819
|
+
const portalContainer = usePortalContainer();
|
|
12820
|
+
const setView = react.useCallback(
|
|
12821
|
+
(next) => {
|
|
12822
|
+
setOpenDate(null);
|
|
12823
|
+
if (!controlled) setInnerView(next);
|
|
12824
|
+
onViewChange?.(next);
|
|
12825
|
+
},
|
|
12826
|
+
[controlled, onViewChange]
|
|
12477
12827
|
);
|
|
12478
|
-
const
|
|
12479
|
-
const
|
|
12480
|
-
|
|
12828
|
+
const cells = react.useMemo(() => monthCells(view.year, view.month), [view.year, view.month]);
|
|
12829
|
+
const rowCount = cells.length / 7;
|
|
12830
|
+
const gridRef = react.useRef(null);
|
|
12831
|
+
const [rowCapacity, setRowCapacity] = react.useState(CALENDAR_BOARD_MAX_VISIBLE_EVENTS);
|
|
12832
|
+
react.useEffect(() => {
|
|
12833
|
+
const grid = gridRef.current;
|
|
12834
|
+
if (grid == null || typeof ResizeObserver === "undefined") return;
|
|
12835
|
+
const cell = grid.querySelector('[role="gridcell"]');
|
|
12836
|
+
if (cell == null) return;
|
|
12837
|
+
const apply = () => {
|
|
12838
|
+
const next = measureRowCapacity(cell);
|
|
12839
|
+
if (next != null) setRowCapacity(next);
|
|
12840
|
+
};
|
|
12841
|
+
apply();
|
|
12842
|
+
const observer = new ResizeObserver(apply);
|
|
12843
|
+
observer.observe(cell);
|
|
12844
|
+
return () => observer.disconnect();
|
|
12845
|
+
}, [rowCount]);
|
|
12846
|
+
const eventMap = react.useMemo(() => {
|
|
12847
|
+
const map = /* @__PURE__ */ new Map();
|
|
12848
|
+
(events ?? []).forEach((event) => {
|
|
12849
|
+
const list = map.get(event.date);
|
|
12850
|
+
if (list) list.push(event);
|
|
12851
|
+
else map.set(event.date, [event]);
|
|
12852
|
+
});
|
|
12853
|
+
return map;
|
|
12854
|
+
}, [events]);
|
|
12855
|
+
const openEvents = openDate ? eventMap.get(openDate) ?? [] : [];
|
|
12856
|
+
react.useLayoutEffect(() => {
|
|
12857
|
+
if (openDate == null || panelEl == null) return;
|
|
12858
|
+
const cell = gridRef.current?.querySelector(`[data-date="${openDate}"]`);
|
|
12859
|
+
if (cell == null) return;
|
|
12860
|
+
const adjust = () => {
|
|
12861
|
+
const cellRect = cell.getBoundingClientRect();
|
|
12862
|
+
const panelRect = panelEl.getBoundingClientRect();
|
|
12863
|
+
const next = {
|
|
12864
|
+
cellWidth: cellRect.width,
|
|
12865
|
+
cellHeight: cellRect.height,
|
|
12866
|
+
side: -(cellRect.height + DAY_EVENT_OUTDENT) + shiftIntoView(cellRect.top - DAY_EVENT_OUTDENT, panelRect.height, window.innerHeight),
|
|
12867
|
+
align: -DAY_EVENT_OUTDENT + shiftIntoView(cellRect.left - DAY_EVENT_OUTDENT, panelRect.width, window.innerWidth)
|
|
12868
|
+
};
|
|
12869
|
+
setPlacement(
|
|
12870
|
+
(prev) => prev.cellWidth === next.cellWidth && prev.cellHeight === next.cellHeight && prev.side === next.side && prev.align === next.align ? prev : next
|
|
12871
|
+
);
|
|
12872
|
+
};
|
|
12873
|
+
adjust();
|
|
12874
|
+
const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(adjust);
|
|
12875
|
+
observer?.observe(panelEl);
|
|
12876
|
+
window.addEventListener("scroll", adjust, true);
|
|
12877
|
+
window.addEventListener("resize", adjust);
|
|
12878
|
+
return () => {
|
|
12879
|
+
observer?.disconnect();
|
|
12880
|
+
window.removeEventListener("scroll", adjust, true);
|
|
12881
|
+
window.removeEventListener("resize", adjust);
|
|
12882
|
+
};
|
|
12883
|
+
}, [openDate, panelEl]);
|
|
12884
|
+
const columns = "repeat(7, minmax(var(--cmp-calendarBoard-dayCard-minWidth), 1fr))";
|
|
12885
|
+
const openEventList = (date, list) => {
|
|
12886
|
+
if (onMoreClick) {
|
|
12887
|
+
onMoreClick({ date, events: list });
|
|
12888
|
+
return;
|
|
12889
|
+
}
|
|
12890
|
+
setOpenDate((prev) => prev === date ? null : date);
|
|
12891
|
+
};
|
|
12892
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12481
12893
|
"div",
|
|
12482
12894
|
{
|
|
12483
|
-
ref: rootRef,
|
|
12484
|
-
"data-name": name || void 0,
|
|
12485
12895
|
className: cn(
|
|
12486
|
-
"
|
|
12487
|
-
|
|
12488
|
-
// 블록 레벨(flex)로 두어 쌓임은 그대로 유지한다. 나란히 놓으려면 부모를 flex 로.
|
|
12489
|
-
hug ? "flex w-fit max-w-full" : "inline-flex w-full",
|
|
12896
|
+
// 판 높이는 부모가 정한다 — 행이 그 높이를 균등 분할하고, 칸 높이가 다시 "몇 줄 보일지" 를 정한다.
|
|
12897
|
+
"flex h-full w-full flex-col overflow-hidden rounded-(--cmp-calendarBoard-radius) border border-solid border-(--cmp-calendarBoard-border) bg-(--cmp-calendarBoard-bg)",
|
|
12490
12898
|
className
|
|
12491
12899
|
),
|
|
12492
12900
|
style,
|
|
12493
|
-
|
|
12494
|
-
|
|
12495
|
-
|
|
12496
|
-
|
|
12901
|
+
children: [
|
|
12902
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-(--cmp-calendarBoard-header-gap) px-sd-16 py-sd-12", children: [
|
|
12903
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-(--cmp-calendarBoard-header-content-gap)", children: [
|
|
12904
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12905
|
+
SGhostButton,
|
|
12906
|
+
{
|
|
12907
|
+
icon: "chevronLeft",
|
|
12908
|
+
size: "xxs",
|
|
12909
|
+
ariaLabel: "\uC774\uC804 \uD574",
|
|
12910
|
+
onClick: () => setView({ year: view.year - 1, month: view.month })
|
|
12911
|
+
}
|
|
12912
|
+
),
|
|
12913
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "typo-heading-lg inline-flex min-w-[48px] justify-center text-(--cmp-calendarBoard-header-content-color)", children: view.year }),
|
|
12914
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12915
|
+
SGhostButton,
|
|
12916
|
+
{
|
|
12917
|
+
icon: "chevronRight",
|
|
12918
|
+
size: "xxs",
|
|
12919
|
+
ariaLabel: "\uB2E4\uC74C \uD574",
|
|
12920
|
+
onClick: () => setView({ year: view.year + 1, month: view.month })
|
|
12921
|
+
}
|
|
12922
|
+
)
|
|
12923
|
+
] }),
|
|
12924
|
+
/* @__PURE__ */ jsxRuntime.jsx(SDivider, { vertical: true, height: "var(--cmp-calendarBoard-header-content-divider-height)" }),
|
|
12925
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-(--cmp-calendarBoard-header-content-gap)", children: [
|
|
12926
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12927
|
+
SGhostButton,
|
|
12928
|
+
{
|
|
12929
|
+
icon: "chevronLeft",
|
|
12930
|
+
size: "xxs",
|
|
12931
|
+
ariaLabel: "\uC774\uC804 \uB2EC",
|
|
12932
|
+
onClick: () => setView(calcYearMonth(view.year, view.month, "prev"))
|
|
12933
|
+
}
|
|
12934
|
+
),
|
|
12935
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "typo-heading-lg inline-flex min-w-[48px] justify-center text-(--cmp-calendarBoard-header-content-color)", children: [
|
|
12936
|
+
view.month,
|
|
12937
|
+
"\uC6D4"
|
|
12938
|
+
] }),
|
|
12939
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12940
|
+
SGhostButton,
|
|
12941
|
+
{
|
|
12942
|
+
icon: "chevronRight",
|
|
12943
|
+
size: "xxs",
|
|
12944
|
+
ariaLabel: "\uB2E4\uC74C \uB2EC",
|
|
12945
|
+
onClick: () => setView(calcYearMonth(view.year, view.month, "next"))
|
|
12946
|
+
}
|
|
12947
|
+
)
|
|
12948
|
+
] }),
|
|
12949
|
+
todayLabel !== "" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
12950
|
+
SButton,
|
|
12951
|
+
{
|
|
12952
|
+
color: "neutral",
|
|
12953
|
+
outline: true,
|
|
12954
|
+
size: "xs",
|
|
12955
|
+
label: todayLabel,
|
|
12956
|
+
onClick: () => setView({ year: ty, month: tm })
|
|
12957
|
+
}
|
|
12958
|
+
),
|
|
12959
|
+
headerRight != null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-auto flex items-center", children: headerRight })
|
|
12960
|
+
] }),
|
|
12961
|
+
/* @__PURE__ */ jsxRuntime.jsx(SDivider, {}),
|
|
12962
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12497
12963
|
"div",
|
|
12498
12964
|
{
|
|
12499
|
-
className: "
|
|
12500
|
-
style: {
|
|
12501
|
-
|
|
12502
|
-
|
|
12503
|
-
|
|
12504
|
-
|
|
12505
|
-
|
|
12506
|
-
|
|
12507
|
-
|
|
12508
|
-
|
|
12509
|
-
SIcon,
|
|
12510
|
-
{
|
|
12511
|
-
name: icon,
|
|
12512
|
-
size: s.icon,
|
|
12513
|
-
color: iconColor,
|
|
12514
|
-
style: { marginRight: s.labelGap }
|
|
12515
|
-
}
|
|
12516
|
-
),
|
|
12517
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 overflow-hidden text-ellipsis whitespace-nowrap", children: label }),
|
|
12518
|
-
(labelTooltip !== "" || labelTooltipProps) && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 flex items-center", style: { marginLeft: s.labelGap }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12519
|
-
STooltip2,
|
|
12520
|
-
{
|
|
12521
|
-
message: labelTooltip !== "" ? [labelTooltip] : void 0,
|
|
12522
|
-
iconSize: s.icon,
|
|
12523
|
-
...labelTooltipProps
|
|
12524
|
-
}
|
|
12525
|
-
) })
|
|
12526
|
-
]
|
|
12965
|
+
className: "grid shrink-0 bg-(--cmp-calendarBoard-grid-bg) pt-(--cmp-calendarBoard-grid-paddingTop) pb-(--cmp-calendarBoard-grid-gap)",
|
|
12966
|
+
style: { gridTemplateColumns: columns },
|
|
12967
|
+
children: WEEK_LABELS.map((label) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
12968
|
+
"div",
|
|
12969
|
+
{
|
|
12970
|
+
className: "typo-body-md-default flex justify-center text-(--cmp-calendarBoard-grid-weekRow-color)",
|
|
12971
|
+
children: label
|
|
12972
|
+
},
|
|
12973
|
+
label
|
|
12974
|
+
))
|
|
12527
12975
|
}
|
|
12528
12976
|
),
|
|
12529
12977
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
12530
|
-
|
|
12978
|
+
RPopover12__namespace.Root,
|
|
12531
12979
|
{
|
|
12532
|
-
|
|
12533
|
-
|
|
12534
|
-
|
|
12535
|
-
minWidth: fieldWidthValue(minWidth),
|
|
12536
|
-
maxWidth: resolvedMaxWidth
|
|
12980
|
+
open: openDate !== null,
|
|
12981
|
+
onOpenChange: (open) => {
|
|
12982
|
+
if (!open) setOpenDate(null);
|
|
12537
12983
|
},
|
|
12538
12984
|
children: [
|
|
12539
|
-
/* @__PURE__ */ jsxRuntime.
|
|
12985
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12540
12986
|
"div",
|
|
12541
12987
|
{
|
|
12542
|
-
|
|
12543
|
-
|
|
12544
|
-
|
|
12545
|
-
// 이 상자가 스크롤포트가 되어 안쪽의 position:sticky 가 페이지 스크롤을 따라가지
|
|
12546
|
-
// 못한다 (SEditor 의 고정 툴바). 여러 줄 필드에서만 바꿔 파급을 좁힌다.
|
|
12547
|
-
multiline ? "overflow-clip" : "overflow-hidden",
|
|
12548
|
-
interactive && !borderless && "hover:border-(--sys-color-field-border-focus) hover:shadow-[0px_0px_4px_0px_#0071ff66] focus-within:border-(--sys-color-field-border-focus) focus-within:shadow-[0px_0px_4px_0px_#0071ff66]",
|
|
12549
|
-
disabled && "cursor-not-allowed"
|
|
12550
|
-
),
|
|
12988
|
+
ref: gridRef,
|
|
12989
|
+
role: "grid",
|
|
12990
|
+
className: "grid min-h-0 flex-1 gap-px overflow-auto border-t border-solid border-(--cmp-calendarBoard-grid-month-border) bg-(--cmp-calendarBoard-grid-month-border)",
|
|
12551
12991
|
style: {
|
|
12552
|
-
|
|
12553
|
-
|
|
12554
|
-
|
|
12555
|
-
...interactive && !borderless && (focused || hovered) ? { boxShadow: FOCUS_RING_SHADOW } : {},
|
|
12556
|
-
...multiline ? { minHeight: s.height } : { height: s.height },
|
|
12557
|
-
"borderRadius": s.radius,
|
|
12558
|
-
"background": bgColor,
|
|
12559
|
-
"color": textColor
|
|
12992
|
+
gridTemplateColumns: columns,
|
|
12993
|
+
// 행은 판 높이를 균등하게 나눠 갖는다 — 일정이 많은 주만 길어지면 격자가 깨진다.
|
|
12994
|
+
gridTemplateRows: `repeat(${rowCount}, minmax(var(--cmp-calendarBoard-dayCard-minHeight), 1fr))`
|
|
12560
12995
|
},
|
|
12561
|
-
|
|
12562
|
-
|
|
12563
|
-
|
|
12564
|
-
|
|
12565
|
-
|
|
12996
|
+
children: cells.map((cell) => {
|
|
12997
|
+
const content = dayContent?.[cell.date];
|
|
12998
|
+
const list = content == null ? eventMap.get(cell.date) ?? [] : [];
|
|
12999
|
+
const folded = list.length > rowCapacity;
|
|
13000
|
+
const visible = folded ? list.slice(0, rowCapacity - 1) : list;
|
|
13001
|
+
const card = /* @__PURE__ */ jsxRuntime.jsx(
|
|
13002
|
+
CalendarDayCard,
|
|
12566
13003
|
{
|
|
12567
|
-
|
|
12568
|
-
|
|
12569
|
-
|
|
12570
|
-
|
|
12571
|
-
|
|
12572
|
-
|
|
12573
|
-
|
|
12574
|
-
|
|
12575
|
-
|
|
12576
|
-
|
|
12577
|
-
|
|
12578
|
-
|
|
12579
|
-
|
|
12580
|
-
|
|
12581
|
-
|
|
12582
|
-
|
|
12583
|
-
|
|
12584
|
-
|
|
13004
|
+
date: cell.date,
|
|
13005
|
+
day: cell.day,
|
|
13006
|
+
inCurrentMonth: cell.inCurrentMonth,
|
|
13007
|
+
isToday: cell.date === today,
|
|
13008
|
+
isSelected: value != null && value === cell.date,
|
|
13009
|
+
selectable,
|
|
13010
|
+
color: dayColors?.[cell.date] ?? "default",
|
|
13011
|
+
events: visible,
|
|
13012
|
+
body: content,
|
|
13013
|
+
hiddenCount: folded ? list.length - (rowCapacity - 1) : 0,
|
|
13014
|
+
isOpen: openDate === cell.date,
|
|
13015
|
+
moreLabel,
|
|
13016
|
+
onDaySelect: (date) => onValueChange?.(date, list),
|
|
13017
|
+
onEventClick,
|
|
13018
|
+
onOpenEvents: () => openEventList(cell.date, list)
|
|
13019
|
+
},
|
|
13020
|
+
cell.date
|
|
13021
|
+
);
|
|
13022
|
+
return cell.date === openDate ? /* @__PURE__ */ jsxRuntime.jsx(RPopover12__namespace.Anchor, { asChild: true, children: card }, cell.date) : card;
|
|
13023
|
+
})
|
|
12585
13024
|
}
|
|
12586
13025
|
),
|
|
12587
|
-
|
|
13026
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover12__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
13027
|
+
RPopover12__namespace.Content,
|
|
13028
|
+
{
|
|
13029
|
+
onInteractOutside: (e) => {
|
|
13030
|
+
const target = e.detail.originalEvent.target;
|
|
13031
|
+
if (target instanceof Node && gridRef.current?.contains(target)) e.preventDefault();
|
|
13032
|
+
},
|
|
13033
|
+
side: "bottom",
|
|
13034
|
+
align: "start",
|
|
13035
|
+
ref: setPanelEl,
|
|
13036
|
+
sideOffset: placement.side,
|
|
13037
|
+
alignOffset: placement.align,
|
|
13038
|
+
avoidCollisions: false,
|
|
13039
|
+
className: cn("z-50 outline-none", FLOATING_SLIDE_ANIM),
|
|
13040
|
+
onOpenAutoFocus: (e) => e.preventDefault(),
|
|
13041
|
+
children: openDate != null && /* @__PURE__ */ jsxRuntime.jsx(
|
|
13042
|
+
CalendarDayEventListBox,
|
|
13043
|
+
{
|
|
13044
|
+
date: openDate,
|
|
13045
|
+
minWidth: placement.cellWidth > 0 ? placement.cellWidth + DAY_EVENT_OUTDENT * 2 : void 0,
|
|
13046
|
+
minHeight: placement.cellHeight > 0 ? placement.cellHeight + DAY_EVENT_OUTDENT * 2 : void 0,
|
|
13047
|
+
events: openEvents,
|
|
13048
|
+
onEventClick,
|
|
13049
|
+
onClose: () => setOpenDate(null)
|
|
13050
|
+
}
|
|
13051
|
+
)
|
|
13052
|
+
},
|
|
13053
|
+
openDate
|
|
13054
|
+
) })
|
|
12588
13055
|
]
|
|
12589
13056
|
}
|
|
12590
13057
|
)
|
|
12591
|
-
]
|
|
13058
|
+
]
|
|
12592
13059
|
}
|
|
12593
13060
|
);
|
|
12594
|
-
}
|
|
13061
|
+
}
|
|
12595
13062
|
|
|
12596
|
-
// src/lib/
|
|
12597
|
-
var
|
|
13063
|
+
// src/lib/floating-height.ts
|
|
13064
|
+
var POPOVER_AVAILABLE_HEIGHT = "var(--radix-popover-content-available-height)";
|
|
13065
|
+
function clampToAvailableHeight(value, availableHeight) {
|
|
13066
|
+
if (value == null || value === "") return availableHeight;
|
|
13067
|
+
const css = typeof value === "number" ? `${value}px` : value;
|
|
13068
|
+
return `min(${css}, ${availableHeight})`;
|
|
13069
|
+
}
|
|
12598
13070
|
var FONT = {
|
|
12599
13071
|
sm: {
|
|
12600
13072
|
fontSize: 12,
|
|
@@ -14879,158 +15351,6 @@ var SInput = /* @__PURE__ */ react.forwardRef(function SInput2({
|
|
|
14879
15351
|
}
|
|
14880
15352
|
);
|
|
14881
15353
|
});
|
|
14882
|
-
var TEXTAREA_SIZE = {
|
|
14883
|
-
sm: {
|
|
14884
|
-
fontSize: 12,
|
|
14885
|
-
lineHeight: 20,
|
|
14886
|
-
paddingX: "var(--cmp-textinput-sm-paddingX)",
|
|
14887
|
-
paddingY: "var(--cmp-textinput-sm-paddingY)"
|
|
14888
|
-
},
|
|
14889
|
-
md: {
|
|
14890
|
-
fontSize: 14,
|
|
14891
|
-
lineHeight: 24,
|
|
14892
|
-
paddingX: "var(--cmp-textinput-md-paddingX)",
|
|
14893
|
-
paddingY: "var(--cmp-textinput-md-paddingY)"
|
|
14894
|
-
}
|
|
14895
|
-
};
|
|
14896
|
-
var MIN_ROWS = 2;
|
|
14897
|
-
var STextarea = /* @__PURE__ */ react.forwardRef(function STextarea2({
|
|
14898
|
-
value,
|
|
14899
|
-
onValueChange,
|
|
14900
|
-
onChange,
|
|
14901
|
-
size = "sm",
|
|
14902
|
-
rows = MIN_ROWS,
|
|
14903
|
-
autogrow = false,
|
|
14904
|
-
maxRows,
|
|
14905
|
-
rules,
|
|
14906
|
-
status,
|
|
14907
|
-
focused,
|
|
14908
|
-
hovered,
|
|
14909
|
-
textareaClassName,
|
|
14910
|
-
textareaStyle,
|
|
14911
|
-
label,
|
|
14912
|
-
labelWidth,
|
|
14913
|
-
icon,
|
|
14914
|
-
iconColor,
|
|
14915
|
-
labelTooltip,
|
|
14916
|
-
labelTooltipProps,
|
|
14917
|
-
addonLabel,
|
|
14918
|
-
addonAlign,
|
|
14919
|
-
hint,
|
|
14920
|
-
error,
|
|
14921
|
-
errorMessage,
|
|
14922
|
-
width,
|
|
14923
|
-
disabled = false,
|
|
14924
|
-
readOnly = false,
|
|
14925
|
-
placeholder = "\uC785\uB825\uD574 \uC8FC\uC138\uC694.",
|
|
14926
|
-
onBlur,
|
|
14927
|
-
className,
|
|
14928
|
-
style,
|
|
14929
|
-
...rest
|
|
14930
|
-
}, ref) {
|
|
14931
|
-
const p = TEXTAREA_SIZE[size];
|
|
14932
|
-
const heightForRows = (n) => `calc(${p.lineHeight * n}px + ${p.paddingY} * 2)`;
|
|
14933
|
-
const minHeight = heightForRows(MIN_ROWS);
|
|
14934
|
-
const maxHeight = autogrow && maxRows != null ? heightForRows(maxRows) : void 0;
|
|
14935
|
-
const [ruleError, setRuleError] = react.useState("");
|
|
14936
|
-
const innerRef = react.useRef(null);
|
|
14937
|
-
const setRefs2 = react.useCallback(
|
|
14938
|
-
(node) => {
|
|
14939
|
-
innerRef.current = node;
|
|
14940
|
-
if (typeof ref === "function") ref(node);
|
|
14941
|
-
else if (ref) ref.current = node;
|
|
14942
|
-
},
|
|
14943
|
-
[ref]
|
|
14944
|
-
);
|
|
14945
|
-
react.useLayoutEffect(() => {
|
|
14946
|
-
const el = innerRef.current;
|
|
14947
|
-
if (el == null) return;
|
|
14948
|
-
if (!autogrow) {
|
|
14949
|
-
el.style.height = "";
|
|
14950
|
-
return;
|
|
14951
|
-
}
|
|
14952
|
-
el.style.height = "auto";
|
|
14953
|
-
el.style.height = `${el.scrollHeight}px`;
|
|
14954
|
-
}, [autogrow, maxHeight, minHeight, rows, value]);
|
|
14955
|
-
useFormField({
|
|
14956
|
-
name: rest.name,
|
|
14957
|
-
validate: () => {
|
|
14958
|
-
const msg = runRules(value, rules);
|
|
14959
|
-
setRuleError(msg);
|
|
14960
|
-
return msg === "";
|
|
14961
|
-
},
|
|
14962
|
-
resetValidation: () => setRuleError("")
|
|
14963
|
-
});
|
|
14964
|
-
const resolvedError = error || ruleError !== "";
|
|
14965
|
-
const resolvedErrorMessage = ruleError !== "" ? ruleError : errorMessage;
|
|
14966
|
-
const resolvedStatus = status ?? (rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0);
|
|
14967
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
14968
|
-
SField,
|
|
14969
|
-
{
|
|
14970
|
-
label,
|
|
14971
|
-
labelWidth,
|
|
14972
|
-
icon,
|
|
14973
|
-
iconColor,
|
|
14974
|
-
labelTooltip,
|
|
14975
|
-
labelTooltipProps,
|
|
14976
|
-
addonLabel,
|
|
14977
|
-
addonAlign,
|
|
14978
|
-
hint,
|
|
14979
|
-
size,
|
|
14980
|
-
error: resolvedError,
|
|
14981
|
-
status: resolvedStatus,
|
|
14982
|
-
focused,
|
|
14983
|
-
hovered,
|
|
14984
|
-
errorMessage: resolvedErrorMessage,
|
|
14985
|
-
width,
|
|
14986
|
-
disabled,
|
|
14987
|
-
readOnly,
|
|
14988
|
-
multiline: true,
|
|
14989
|
-
className,
|
|
14990
|
-
style,
|
|
14991
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14992
|
-
"textarea",
|
|
14993
|
-
{
|
|
14994
|
-
ref: setRefs2,
|
|
14995
|
-
value: value ?? "",
|
|
14996
|
-
rows,
|
|
14997
|
-
disabled,
|
|
14998
|
-
readOnly,
|
|
14999
|
-
placeholder,
|
|
15000
|
-
onChange: (e) => {
|
|
15001
|
-
onChange?.(e);
|
|
15002
|
-
onValueChange?.(e.target.value);
|
|
15003
|
-
if (ruleError !== "") setRuleError(runRules(e.target.value, rules));
|
|
15004
|
-
},
|
|
15005
|
-
onBlur: (e) => {
|
|
15006
|
-
onBlur?.(e);
|
|
15007
|
-
if (rules && rules.length > 0) setRuleError(runRules(e.target.value, rules));
|
|
15008
|
-
},
|
|
15009
|
-
className: cn(
|
|
15010
|
-
"w-full border-0 bg-transparent outline-none placeholder:text-[color:var(--sys-color-field-text-placeholder)] disabled:cursor-not-allowed",
|
|
15011
|
-
// autogrow 와 끌어서 늘리기는 같은 높이를 두고 다투므로 함께 두지 않는다
|
|
15012
|
-
autogrow ? "resize-none" : "resize-y",
|
|
15013
|
-
AUTOFILL_RESET_CLASS,
|
|
15014
|
-
textareaClassName
|
|
15015
|
-
),
|
|
15016
|
-
style: {
|
|
15017
|
-
minHeight,
|
|
15018
|
-
maxHeight,
|
|
15019
|
-
// 상한이 있으면 거기 닿았을 때 안에서 스크롤한다. 상한이 없으면 높이가 늘 내용과
|
|
15020
|
-
// 같으므로 스크롤바가 나올 일이 없고, 반올림으로 1px 이 넘쳐 깜빡이는 것만 막는다.
|
|
15021
|
-
overflowY: autogrow ? maxRows != null ? "auto" : "hidden" : void 0,
|
|
15022
|
-
padding: `${p.paddingY} ${p.paddingX}`,
|
|
15023
|
-
fontSize: p.fontSize,
|
|
15024
|
-
lineHeight: `${p.lineHeight}px`,
|
|
15025
|
-
color: disabled ? "var(--cmp-textinput-text-disabled)" : "var(--sys-color-field-text-default)",
|
|
15026
|
-
...textareaStyle
|
|
15027
|
-
},
|
|
15028
|
-
...rest
|
|
15029
|
-
}
|
|
15030
|
-
)
|
|
15031
|
-
}
|
|
15032
|
-
);
|
|
15033
|
-
});
|
|
15034
15354
|
var PAD2 = {
|
|
15035
15355
|
sm: { fontSize: 12, lineHeight: 20, stepper: 20, icon: 12 },
|
|
15036
15356
|
md: { fontSize: 14, lineHeight: 24, stepper: 24, icon: 14 }
|
|
@@ -23100,6 +23420,9 @@ exports.CALENDAR_BOARD_DAY_COLORS = CALENDAR_BOARD_DAY_COLORS;
|
|
|
23100
23420
|
exports.CALENDAR_BOARD_EVENT_COLORS = CALENDAR_BOARD_EVENT_COLORS;
|
|
23101
23421
|
exports.CALENDAR_BOARD_EVENT_PRESETS = CALENDAR_BOARD_EVENT_PRESETS;
|
|
23102
23422
|
exports.CALENDAR_BOARD_MAX_VISIBLE_EVENTS = CALENDAR_BOARD_MAX_VISIBLE_EVENTS;
|
|
23423
|
+
exports.CHAT_MESSAGE_DIRECTIONS = CHAT_MESSAGE_DIRECTIONS;
|
|
23424
|
+
exports.CHAT_MESSAGE_READ_STATUSES = CHAT_MESSAGE_READ_STATUSES;
|
|
23425
|
+
exports.CHAT_MESSAGE_VARIANTS = CHAT_MESSAGE_VARIANTS;
|
|
23103
23426
|
exports.COLOR_KEYS = COLOR_KEYS;
|
|
23104
23427
|
exports.FIELD_WIDTH_GRADES = FIELD_WIDTH_GRADES;
|
|
23105
23428
|
exports.GNB_COLORS = GNB_COLORS;
|
|
@@ -23133,6 +23456,8 @@ exports.SCalendar = SCalendar;
|
|
|
23133
23456
|
exports.SCalendarBoard = SCalendarBoard;
|
|
23134
23457
|
exports.SCallout = SCallout;
|
|
23135
23458
|
exports.SCard = SCard;
|
|
23459
|
+
exports.SChatInput = SChatInput2;
|
|
23460
|
+
exports.SChatMessage = SChatMessage2;
|
|
23136
23461
|
exports.SCheckbox = SCheckbox;
|
|
23137
23462
|
exports.SChip = SChip2;
|
|
23138
23463
|
exports.SChipFilter = SChipFilter;
|
|
@@ -23177,6 +23502,7 @@ exports.SListItem = SListItem2;
|
|
|
23177
23502
|
exports.SLoadingContainer = SLoadingContainer;
|
|
23178
23503
|
exports.SLoadingModal = SLoadingModal;
|
|
23179
23504
|
exports.SLoadingViewport = SLoadingViewport;
|
|
23505
|
+
exports.SLoginCard = SLoginCard2;
|
|
23180
23506
|
exports.SModal = SModal;
|
|
23181
23507
|
exports.SModalOutlet = SModalOutlet;
|
|
23182
23508
|
exports.SNumberInput = SNumberInput;
|