sellmate-design-system-react 4.3.0 → 5.0.1
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 +18 -0
- package/README.md +2 -2
- package/dist/components/SActionModal/README.md +6 -4
- package/dist/components/SActionModal/SActionModal.d.ts +3 -12
- package/dist/components/SActionModal/index.d.ts +1 -1
- package/dist/components/SButton/README.md +2 -6
- package/dist/components/SConfirmModal/README.md +1 -1
- package/dist/components/SConfirmModal/SConfirmModal.d.ts +1 -1
- package/dist/components/SDrawer/README.md +8 -5
- package/dist/components/SDrawer/SDrawer.d.ts +14 -11
- package/dist/components/SFooter/README.md +40 -0
- package/dist/components/SFooter/SFooter.d.ts +36 -0
- package/dist/components/SFooter/index.d.ts +1 -0
- package/dist/components/SGhostButton/README.md +2 -2
- package/dist/components/SGnb/README.md +0 -5
- package/dist/components/SGnb/SGnb.d.ts +6 -2
- package/dist/components/SGnb/gnb.config.d.ts +2 -0
- package/dist/components/SLayout/README.md +1 -6
- package/dist/components/SLayout/SLayout.d.ts +39 -17
- package/dist/components/SLoadingModal/README.md +1 -1
- package/dist/components/SLoadingModal/SLoadingModal.d.ts +1 -1
- package/dist/components/SModalContainer/README.md +1 -1
- package/dist/components/SModalContainer/SModalContainer.d.ts +6 -2
- package/dist/components/SOverlayHeader/README.md +45 -0
- package/dist/components/SOverlayHeader/SOverlayHeader.d.ts +28 -0
- package/dist/components/SOverlayHeader/index.d.ts +1 -0
- package/dist/components/SPage/SPage.d.ts +2 -2
- package/dist/components/SPopup/README.md +2 -2
- package/dist/index.cjs +439 -256
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +439 -256
- package/dist/index.js.map +1 -1
- package/dist/lib/global-overlay.d.ts +17 -0
- package/dist/lib/isomorphic-layout-effect.d.ts +8 -0
- package/dist/llms-full.txt +109 -23
- package/dist/llms.txt +18 -0
- package/dist/styles.css +27 -17
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -5329,6 +5329,16 @@ var SCircleProgress = /* @__PURE__ */ react.forwardRef(
|
|
|
5329
5329
|
);
|
|
5330
5330
|
}
|
|
5331
5331
|
);
|
|
5332
|
+
|
|
5333
|
+
// src/lib/global-overlay.ts
|
|
5334
|
+
var GLOBAL_OVERLAY_ATTR = "data-s-global-overlay";
|
|
5335
|
+
var globalOverlayProps = { [GLOBAL_OVERLAY_ATTR]: "" };
|
|
5336
|
+
function isFromGlobalOverlay(event) {
|
|
5337
|
+
const detail = event.detail;
|
|
5338
|
+
const target = detail?.originalEvent?.target ?? event.target;
|
|
5339
|
+
const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
|
|
5340
|
+
return !!element?.closest(`[${GLOBAL_OVERLAY_ATTR}]`);
|
|
5341
|
+
}
|
|
5332
5342
|
var SLoadingContainer = /* @__PURE__ */ react.forwardRef(
|
|
5333
5343
|
function SLoadingContainer2({ open = false, message, zIndex = Z_INDEX.loading, className, style }, ref) {
|
|
5334
5344
|
const [mounted2, setMounted] = react.useState(false);
|
|
@@ -5365,6 +5375,7 @@ var SLoadingContainer = /* @__PURE__ */ react.forwardRef(
|
|
|
5365
5375
|
"div",
|
|
5366
5376
|
{
|
|
5367
5377
|
ref: setRef,
|
|
5378
|
+
...globalOverlayProps,
|
|
5368
5379
|
"aria-hidden": !open,
|
|
5369
5380
|
className: cn(
|
|
5370
5381
|
"fixed inset-0 flex items-center justify-center transition-opacity duration-200",
|
|
@@ -5572,6 +5583,7 @@ var SDropdownButtonImpl = /* @__PURE__ */ react.forwardRef(
|
|
|
5572
5583
|
style
|
|
5573
5584
|
}, ref) {
|
|
5574
5585
|
const portalContainer = usePortalContainer();
|
|
5586
|
+
const insideModal = useInsideModal();
|
|
5575
5587
|
const [open, setOpen] = react.useState(false);
|
|
5576
5588
|
const splitWrapRef = react.useRef(null);
|
|
5577
5589
|
const splitToggleRef = react.useRef(null);
|
|
@@ -5660,6 +5672,7 @@ var SDropdownButtonImpl = /* @__PURE__ */ react.forwardRef(
|
|
|
5660
5672
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5661
5673
|
RDropdown__namespace.Root,
|
|
5662
5674
|
{
|
|
5675
|
+
modal: !insideModal,
|
|
5663
5676
|
open,
|
|
5664
5677
|
onOpenChange: (o) => {
|
|
5665
5678
|
setOpen(o);
|
|
@@ -6002,6 +6015,53 @@ function SPortal({
|
|
|
6002
6015
|
}
|
|
6003
6016
|
);
|
|
6004
6017
|
}
|
|
6018
|
+
function SFooter({
|
|
6019
|
+
bg = "white",
|
|
6020
|
+
left,
|
|
6021
|
+
button,
|
|
6022
|
+
children,
|
|
6023
|
+
className,
|
|
6024
|
+
leftClassName,
|
|
6025
|
+
style
|
|
6026
|
+
}) {
|
|
6027
|
+
const isGrey = bg === "grey";
|
|
6028
|
+
const hasSlot = left != null || children != null;
|
|
6029
|
+
const hasButton = button != null;
|
|
6030
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6031
|
+
"footer",
|
|
6032
|
+
{
|
|
6033
|
+
className: cn(
|
|
6034
|
+
"relative flex w-full flex-shrink-0 items-center justify-end gap-[var(--cmp-overlay-footer-gap)] overflow-hidden px-[var(--cmp-overlay-footer-paddingX)] py-[var(--cmp-overlay-footer-paddingY)] shadow-[var(--shadow-spread-md)]",
|
|
6035
|
+
isGrey ? "bg-[var(--cmp-overlay-footer-bg-neutral)]" : "bg-[var(--cmp-overlay-footer-bg-default)]",
|
|
6036
|
+
className
|
|
6037
|
+
),
|
|
6038
|
+
style,
|
|
6039
|
+
children: [
|
|
6040
|
+
hasSlot && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6041
|
+
"div",
|
|
6042
|
+
{
|
|
6043
|
+
className: cn("flex min-w-px flex-[1_0_0] items-center justify-between", leftClassName),
|
|
6044
|
+
children: [
|
|
6045
|
+
left,
|
|
6046
|
+
children
|
|
6047
|
+
]
|
|
6048
|
+
}
|
|
6049
|
+
),
|
|
6050
|
+
hasButton && /* @__PURE__ */ jsxRuntime.jsx(
|
|
6051
|
+
SButton,
|
|
6052
|
+
{
|
|
6053
|
+
color: button.color ?? "primary",
|
|
6054
|
+
outline: button.outline,
|
|
6055
|
+
size: button.size ?? "md",
|
|
6056
|
+
disabled: button.disabled,
|
|
6057
|
+
onClick: () => button.onClick?.(),
|
|
6058
|
+
label: button.label ?? "\uD655\uC778"
|
|
6059
|
+
}
|
|
6060
|
+
)
|
|
6061
|
+
]
|
|
6062
|
+
}
|
|
6063
|
+
);
|
|
6064
|
+
}
|
|
6005
6065
|
var SPopup = /* @__PURE__ */ react.forwardRef(function SPopup2({
|
|
6006
6066
|
popupTitle = "",
|
|
6007
6067
|
type = "default",
|
|
@@ -6050,29 +6110,7 @@ var SPopup = /* @__PURE__ */ react.forwardRef(function SPopup2({
|
|
|
6050
6110
|
children
|
|
6051
6111
|
}
|
|
6052
6112
|
),
|
|
6053
|
-
useFooter && /* @__PURE__ */ jsxRuntime.
|
|
6054
|
-
"footer",
|
|
6055
|
-
{
|
|
6056
|
-
className: "relative z-[1] flex h-[52px] w-full flex-shrink-0 items-center gap-[var(--cmp-overlay-footer-gap)] px-[var(--cmp-overlay-footer-paddingX)] py-[var(--cmp-overlay-footer-paddingY)]",
|
|
6057
|
-
style: {
|
|
6058
|
-
background: "var(--cmp-overlay-footer-bg-default)",
|
|
6059
|
-
boxShadow: "var(--shadow-spread-md)"
|
|
6060
|
-
},
|
|
6061
|
-
children: [
|
|
6062
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-w-0 flex-1 items-center", children: footerLeft }),
|
|
6063
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6064
|
-
SButton,
|
|
6065
|
-
{
|
|
6066
|
-
color: submitButton?.color ?? "primary",
|
|
6067
|
-
outline: submitButton?.outline,
|
|
6068
|
-
size: submitButton?.size ?? "md",
|
|
6069
|
-
onClick: onSubmit,
|
|
6070
|
-
label: submitButton?.label ?? "\uD655\uC778"
|
|
6071
|
-
}
|
|
6072
|
-
)
|
|
6073
|
-
]
|
|
6074
|
-
}
|
|
6075
|
-
)
|
|
6113
|
+
useFooter && /* @__PURE__ */ jsxRuntime.jsx(SFooter, { left: footerLeft, button: { ...submitButton, onClick: onSubmit } })
|
|
6076
6114
|
]
|
|
6077
6115
|
}
|
|
6078
6116
|
);
|
|
@@ -6094,6 +6132,7 @@ function SGuide({
|
|
|
6094
6132
|
style
|
|
6095
6133
|
}) {
|
|
6096
6134
|
const [open, setOpen] = react.useState(false);
|
|
6135
|
+
const portalContainer = usePortalContainer();
|
|
6097
6136
|
const isNotion = type === "notion";
|
|
6098
6137
|
const defaultLabel = DEFAULT_LABEL[type];
|
|
6099
6138
|
const iconName = ICON[type];
|
|
@@ -6128,7 +6167,7 @@ function SGuide({
|
|
|
6128
6167
|
return /* @__PURE__ */ jsxRuntime.jsx("span", { className, style, children: trigger });
|
|
6129
6168
|
return /* @__PURE__ */ jsxRuntime.jsxs(RPopover2__namespace.Root, { open, onOpenChange: setOpen, children: [
|
|
6130
6169
|
/* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Trigger, { asChild: true, children: trigger }),
|
|
6131
|
-
/* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6170
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6132
6171
|
RPopover2__namespace.Content,
|
|
6133
6172
|
{
|
|
6134
6173
|
side: "bottom",
|
|
@@ -6226,7 +6265,7 @@ function SModalContainer({
|
|
|
6226
6265
|
ariaTitle = "\uBAA8\uB2EC",
|
|
6227
6266
|
showClose = false,
|
|
6228
6267
|
onClose,
|
|
6229
|
-
persistent =
|
|
6268
|
+
persistent = true,
|
|
6230
6269
|
width,
|
|
6231
6270
|
height,
|
|
6232
6271
|
children,
|
|
@@ -6269,6 +6308,13 @@ function SModalContainer({
|
|
|
6269
6308
|
e.preventDefault();
|
|
6270
6309
|
if (stackRegistrationRef.current?.isTop()) triggerShake();
|
|
6271
6310
|
} : void 0;
|
|
6311
|
+
const guardInteractOutside = (e) => {
|
|
6312
|
+
if (isFromGlobalOverlay(e)) {
|
|
6313
|
+
e.preventDefault();
|
|
6314
|
+
return;
|
|
6315
|
+
}
|
|
6316
|
+
guardClose?.(e);
|
|
6317
|
+
};
|
|
6272
6318
|
return /* @__PURE__ */ jsxRuntime.jsx(RDialog__namespace.Root, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsx(RDialog__namespace.Portal, { container: modalHost, forceMount: rendered ? true : void 0, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pointer-events-none absolute inset-0", style: { zIndex: layerIndex ?? 0 }, children: [
|
|
6273
6319
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6274
6320
|
RDialog__namespace.Overlay,
|
|
@@ -6295,8 +6341,8 @@ function SModalContainer({
|
|
|
6295
6341
|
contentRef.current?.focus({ preventScroll: true });
|
|
6296
6342
|
},
|
|
6297
6343
|
onEscapeKeyDown: guardClose,
|
|
6298
|
-
onPointerDownOutside:
|
|
6299
|
-
onInteractOutside:
|
|
6344
|
+
onPointerDownOutside: guardInteractOutside,
|
|
6345
|
+
onInteractOutside: guardInteractOutside,
|
|
6300
6346
|
children: [
|
|
6301
6347
|
/* @__PURE__ */ jsxRuntime.jsx(RDialog__namespace.Title, { className: "sr-only", children: ariaTitle }),
|
|
6302
6348
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -6447,7 +6493,7 @@ function SConfirmModal({
|
|
|
6447
6493
|
)) })
|
|
6448
6494
|
] })
|
|
6449
6495
|
] }),
|
|
6450
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-shrink-0 gap-[
|
|
6496
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-shrink-0 gap-[var(--cmp-modal-confirm-button-gap)]", children: [
|
|
6451
6497
|
subButtonLabel && /* @__PURE__ */ jsxRuntime.jsx(
|
|
6452
6498
|
SButton,
|
|
6453
6499
|
{
|
|
@@ -6478,6 +6524,64 @@ function SConfirmModal({
|
|
|
6478
6524
|
}
|
|
6479
6525
|
);
|
|
6480
6526
|
}
|
|
6527
|
+
function SOverlayHeader({
|
|
6528
|
+
title,
|
|
6529
|
+
description,
|
|
6530
|
+
showClose = false,
|
|
6531
|
+
onClose,
|
|
6532
|
+
reserveCloseSpace = false,
|
|
6533
|
+
className,
|
|
6534
|
+
titleClassName,
|
|
6535
|
+
descriptionClassName,
|
|
6536
|
+
style
|
|
6537
|
+
}) {
|
|
6538
|
+
const hasDescription = description != null && description !== "";
|
|
6539
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6540
|
+
"header",
|
|
6541
|
+
{
|
|
6542
|
+
className: cn(
|
|
6543
|
+
"relative flex w-full flex-shrink-0 items-center",
|
|
6544
|
+
"gap-[var(--cmp-overlay-header-gap)] bg-[var(--cmp-overlay-header-bg)] py-[var(--cmp-overlay-header-paddingY)] pl-[var(--cmp-overlay-header-paddingX)]",
|
|
6545
|
+
showClose || reserveCloseSpace ? "pr-[calc(var(--cmp-overlay-header-paddingX)+20px)]" : "pr-[var(--cmp-overlay-header-paddingX)]",
|
|
6546
|
+
className
|
|
6547
|
+
),
|
|
6548
|
+
style,
|
|
6549
|
+
children: [
|
|
6550
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6551
|
+
"h2",
|
|
6552
|
+
{
|
|
6553
|
+
className: cn(
|
|
6554
|
+
"m-0 overflow-hidden text-ellipsis whitespace-nowrap",
|
|
6555
|
+
"text-[16px] font-bold leading-[26px]",
|
|
6556
|
+
titleClassName
|
|
6557
|
+
),
|
|
6558
|
+
style: { color: "var(--cmp-overlay-header-title-color)" },
|
|
6559
|
+
children: title
|
|
6560
|
+
}
|
|
6561
|
+
),
|
|
6562
|
+
hasDescription && /* @__PURE__ */ jsxRuntime.jsx(
|
|
6563
|
+
"div",
|
|
6564
|
+
{
|
|
6565
|
+
className: cn(
|
|
6566
|
+
"flex min-w-0 flex-1 items-center gap-sd-2 text-[12px] font-normal leading-[20px] text-[color:var(--color-grey-65)]",
|
|
6567
|
+
descriptionClassName
|
|
6568
|
+
),
|
|
6569
|
+
children: description
|
|
6570
|
+
}
|
|
6571
|
+
),
|
|
6572
|
+
showClose && /* @__PURE__ */ jsxRuntime.jsx(
|
|
6573
|
+
SGhostButton,
|
|
6574
|
+
{
|
|
6575
|
+
icon: "close",
|
|
6576
|
+
ariaLabel: "\uB2EB\uAE30",
|
|
6577
|
+
onClick: () => onClose?.(),
|
|
6578
|
+
className: "absolute right-[12px] top-[12px]"
|
|
6579
|
+
}
|
|
6580
|
+
)
|
|
6581
|
+
]
|
|
6582
|
+
}
|
|
6583
|
+
);
|
|
6584
|
+
}
|
|
6481
6585
|
function SActionModal({
|
|
6482
6586
|
open,
|
|
6483
6587
|
onOpenChange,
|
|
@@ -6504,35 +6608,9 @@ function SActionModal({
|
|
|
6504
6608
|
height,
|
|
6505
6609
|
className: "w-fit min-w-[min(480px,calc(100dvw-48px))] min-h-[min(320px,calc(100dvh-48px))]",
|
|
6506
6610
|
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-0 flex-auto flex-col", children: [
|
|
6507
|
-
/* @__PURE__ */ jsxRuntime.
|
|
6508
|
-
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "whitespace-nowrap text-[16px] font-bold leading-[26px] text-[color:var(--cmp-overlay-header-title-color)]", children: modalTitle }),
|
|
6509
|
-
description != null && description !== "" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-w-0 flex-1 items-center gap-sd-2 text-[12px] font-normal leading-[20px] text-[color:var(--color-grey-65)]", children: description })
|
|
6510
|
-
] }),
|
|
6611
|
+
/* @__PURE__ */ jsxRuntime.jsx(SOverlayHeader, { title: modalTitle, description, reserveCloseSpace: true }),
|
|
6511
6612
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 flex-1 overflow-auto px-[var(--cmp-modal-action-body-paddingX)] pb-[var(--cmp-modal-action-body-paddingBottom)]", children }),
|
|
6512
|
-
(button || footerLeft) && /* @__PURE__ */ jsxRuntime.
|
|
6513
|
-
"footer",
|
|
6514
|
-
{
|
|
6515
|
-
className: "flex flex-shrink-0 items-center justify-end gap-[var(--cmp-modal-action-footer-gap)] border-t border-solid px-[var(--cmp-modal-action-footer-paddingX)] py-[var(--cmp-modal-action-footer-paddingY)]",
|
|
6516
|
-
style: {
|
|
6517
|
-
background: "var(--cmp-modal-action-footer-bg)",
|
|
6518
|
-
borderTopColor: "var(--cmp-modal-action-footer-border)"
|
|
6519
|
-
},
|
|
6520
|
-
children: [
|
|
6521
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-w-0 flex-1 items-center gap-sd-2", children: footerLeft }),
|
|
6522
|
-
button && /* @__PURE__ */ jsxRuntime.jsx(
|
|
6523
|
-
SButton,
|
|
6524
|
-
{
|
|
6525
|
-
color: button.color ?? "primary",
|
|
6526
|
-
outline: button.outline,
|
|
6527
|
-
size: button.size ?? "md",
|
|
6528
|
-
disabled: button.disabled,
|
|
6529
|
-
onClick: () => button.onClick?.(),
|
|
6530
|
-
label: button.label ?? "\uD655\uC778"
|
|
6531
|
-
}
|
|
6532
|
-
)
|
|
6533
|
-
]
|
|
6534
|
-
}
|
|
6535
|
-
)
|
|
6613
|
+
(button || footerLeft) && /* @__PURE__ */ jsxRuntime.jsx(SFooter, { bg: "grey", left: footerLeft, button })
|
|
6536
6614
|
] })
|
|
6537
6615
|
}
|
|
6538
6616
|
);
|
|
@@ -6601,13 +6679,43 @@ function SLoadingModal({
|
|
|
6601
6679
|
);
|
|
6602
6680
|
}
|
|
6603
6681
|
var CLOSE_ANIMATION_DURATION2 = 300;
|
|
6682
|
+
function toPx(value, percentBase) {
|
|
6683
|
+
if (typeof value === "number") return value;
|
|
6684
|
+
if (typeof value !== "string") return void 0;
|
|
6685
|
+
const normalized = value.trim();
|
|
6686
|
+
if (normalized.endsWith("px")) {
|
|
6687
|
+
const numeric = Number(normalized.slice(0, -2));
|
|
6688
|
+
return Number.isFinite(numeric) ? numeric : void 0;
|
|
6689
|
+
}
|
|
6690
|
+
if (normalized.endsWith("%")) {
|
|
6691
|
+
const numeric = Number(normalized.slice(0, -1));
|
|
6692
|
+
return Number.isFinite(numeric) ? percentBase * numeric / 100 : void 0;
|
|
6693
|
+
}
|
|
6694
|
+
if (normalized.endsWith("vw")) {
|
|
6695
|
+
const numeric = Number(normalized.slice(0, -2));
|
|
6696
|
+
return Number.isFinite(numeric) ? window.innerWidth * numeric / 100 : void 0;
|
|
6697
|
+
}
|
|
6698
|
+
if (normalized.endsWith("vh")) {
|
|
6699
|
+
const numeric = Number(normalized.slice(0, -2));
|
|
6700
|
+
return Number.isFinite(numeric) ? window.innerHeight * numeric / 100 : void 0;
|
|
6701
|
+
}
|
|
6702
|
+
return void 0;
|
|
6703
|
+
}
|
|
6704
|
+
function clamp3(value, min, max) {
|
|
6705
|
+
const minValue = min ?? Number.NEGATIVE_INFINITY;
|
|
6706
|
+
const maxValue = max ?? Number.POSITIVE_INFINITY;
|
|
6707
|
+
return Math.min(Math.max(value, minValue), maxValue);
|
|
6708
|
+
}
|
|
6604
6709
|
function SDrawer({
|
|
6605
6710
|
open,
|
|
6606
6711
|
onOpenChange,
|
|
6607
6712
|
onClose,
|
|
6608
|
-
persistent =
|
|
6713
|
+
persistent = true,
|
|
6609
6714
|
title = "",
|
|
6610
6715
|
width = 572,
|
|
6716
|
+
resizable = false,
|
|
6717
|
+
minWidth,
|
|
6718
|
+
maxWidth,
|
|
6611
6719
|
footerLeft,
|
|
6612
6720
|
button,
|
|
6613
6721
|
children,
|
|
@@ -6621,7 +6729,13 @@ function SDrawer({
|
|
|
6621
6729
|
const backdropPointerDownRef = react.useRef(false);
|
|
6622
6730
|
const contentRef = react.useRef(null);
|
|
6623
6731
|
const stackRegistrationRef = react.useRef(null);
|
|
6732
|
+
const resizeCleanupRef = react.useRef(null);
|
|
6733
|
+
const resizeStateRef = react.useRef(null);
|
|
6624
6734
|
const [layerIndex, setLayerIndex] = react.useState(null);
|
|
6735
|
+
const [currentWidth, setCurrentWidth] = react.useState(width);
|
|
6736
|
+
react.useEffect(() => {
|
|
6737
|
+
setCurrentWidth(width);
|
|
6738
|
+
}, [width]);
|
|
6625
6739
|
react.useEffect(() => {
|
|
6626
6740
|
if (open) {
|
|
6627
6741
|
setRendered(true);
|
|
@@ -6631,6 +6745,9 @@ function SDrawer({
|
|
|
6631
6745
|
const timer = window.setTimeout(() => setRendered(false), CLOSE_ANIMATION_DURATION2);
|
|
6632
6746
|
return () => window.clearTimeout(timer);
|
|
6633
6747
|
}, [open, rendered]);
|
|
6748
|
+
react.useEffect(() => {
|
|
6749
|
+
return () => resizeCleanupRef.current?.();
|
|
6750
|
+
}, []);
|
|
6634
6751
|
react.useEffect(() => {
|
|
6635
6752
|
if (!open) {
|
|
6636
6753
|
setEntered(false);
|
|
@@ -6658,6 +6775,13 @@ function SDrawer({
|
|
|
6658
6775
|
event.preventDefault();
|
|
6659
6776
|
if (stackRegistrationRef.current?.isTop()) triggerShake();
|
|
6660
6777
|
} : void 0;
|
|
6778
|
+
const guardInteractOutside = (e) => {
|
|
6779
|
+
if (isFromGlobalOverlay(e)) {
|
|
6780
|
+
e.preventDefault();
|
|
6781
|
+
return;
|
|
6782
|
+
}
|
|
6783
|
+
guardClose?.(e);
|
|
6784
|
+
};
|
|
6661
6785
|
const handleBackdropInteraction = () => {
|
|
6662
6786
|
if (persistent) {
|
|
6663
6787
|
if (stackRegistrationRef.current?.isTop()) triggerShake();
|
|
@@ -6665,6 +6789,40 @@ function SDrawer({
|
|
|
6665
6789
|
}
|
|
6666
6790
|
onOpenChange?.(false);
|
|
6667
6791
|
};
|
|
6792
|
+
const handleResizeStart = (event) => {
|
|
6793
|
+
event.preventDefault();
|
|
6794
|
+
event.stopPropagation();
|
|
6795
|
+
const panel = contentRef.current?.querySelector("[data-s-drawer-panel]");
|
|
6796
|
+
if (!panel) return;
|
|
6797
|
+
resizeStateRef.current = {
|
|
6798
|
+
startX: event.clientX,
|
|
6799
|
+
startWidth: panel.getBoundingClientRect().width,
|
|
6800
|
+
minWidth: toPx(minWidth, window.innerWidth),
|
|
6801
|
+
maxWidth: toPx(maxWidth, window.innerWidth)
|
|
6802
|
+
};
|
|
6803
|
+
const onMove = (moveEvent) => {
|
|
6804
|
+
const resizeState = resizeStateRef.current;
|
|
6805
|
+
if (!resizeState) return;
|
|
6806
|
+
const nextWidth = resizeState.startWidth + resizeState.startX - moveEvent.clientX;
|
|
6807
|
+
setCurrentWidth(clamp3(nextWidth, resizeState.minWidth, resizeState.maxWidth));
|
|
6808
|
+
};
|
|
6809
|
+
resizeCleanupRef.current?.();
|
|
6810
|
+
const previousCursor = document.body.style.cursor;
|
|
6811
|
+
const previousUserSelect = document.body.style.userSelect;
|
|
6812
|
+
const cleanupResize = () => {
|
|
6813
|
+
resizeStateRef.current = null;
|
|
6814
|
+
document.body.style.cursor = previousCursor;
|
|
6815
|
+
document.body.style.userSelect = previousUserSelect;
|
|
6816
|
+
document.removeEventListener("mousemove", onMove);
|
|
6817
|
+
document.removeEventListener("mouseup", cleanupResize);
|
|
6818
|
+
resizeCleanupRef.current = null;
|
|
6819
|
+
};
|
|
6820
|
+
resizeCleanupRef.current = cleanupResize;
|
|
6821
|
+
document.body.style.cursor = "col-resize";
|
|
6822
|
+
document.body.style.userSelect = "none";
|
|
6823
|
+
document.addEventListener("mousemove", onMove);
|
|
6824
|
+
document.addEventListener("mouseup", cleanupResize);
|
|
6825
|
+
};
|
|
6668
6826
|
const modalHost = getModalHost();
|
|
6669
6827
|
return /* @__PURE__ */ jsxRuntime.jsx(RDialog__namespace.Root, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsx(RDialog__namespace.Portal, { container: modalHost, forceMount: rendered ? true : void 0, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pointer-events-none absolute inset-0", style: { zIndex: layerIndex ?? 0 }, children: [
|
|
6670
6828
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -6694,14 +6852,14 @@ function SDrawer({
|
|
|
6694
6852
|
{
|
|
6695
6853
|
forceMount: rendered ? true : void 0,
|
|
6696
6854
|
ref: contentRef,
|
|
6697
|
-
className: "pointer-events-
|
|
6855
|
+
className: "pointer-events-none absolute inset-y-0 right-0 flex w-fit max-w-full justify-end outline-none",
|
|
6698
6856
|
onOpenAutoFocus: (event) => {
|
|
6699
6857
|
event.preventDefault();
|
|
6700
6858
|
contentRef.current?.focus({ preventScroll: true });
|
|
6701
6859
|
},
|
|
6702
6860
|
onEscapeKeyDown: guardClose,
|
|
6703
|
-
onPointerDownOutside:
|
|
6704
|
-
onInteractOutside:
|
|
6861
|
+
onPointerDownOutside: guardInteractOutside,
|
|
6862
|
+
onInteractOutside: guardInteractOutside,
|
|
6705
6863
|
children: [
|
|
6706
6864
|
/* @__PURE__ */ jsxRuntime.jsx(RDialog__namespace.Title, { className: "sr-only", children: title || "Drawer" }),
|
|
6707
6865
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -6712,42 +6870,35 @@ function SDrawer({
|
|
|
6712
6870
|
shaking && "animate-drawer-shake",
|
|
6713
6871
|
className
|
|
6714
6872
|
),
|
|
6873
|
+
"data-s-drawer-panel": true,
|
|
6715
6874
|
"data-state": open && entered ? "open" : "closed",
|
|
6716
|
-
style: { width, ...style },
|
|
6875
|
+
style: { width: currentWidth, minWidth, maxWidth, ...style },
|
|
6717
6876
|
onAnimationEnd: (event) => {
|
|
6718
6877
|
if (event.animationName === "drawer-shake") setShaking(false);
|
|
6719
6878
|
},
|
|
6720
6879
|
children: [
|
|
6721
|
-
/* @__PURE__ */ jsxRuntime.
|
|
6722
|
-
|
|
6723
|
-
|
|
6724
|
-
|
|
6725
|
-
|
|
6726
|
-
|
|
6727
|
-
|
|
6728
|
-
|
|
6729
|
-
|
|
6730
|
-
|
|
6731
|
-
|
|
6732
|
-
|
|
6880
|
+
resizable && /* @__PURE__ */ jsxRuntime.jsx(
|
|
6881
|
+
"button",
|
|
6882
|
+
{
|
|
6883
|
+
type: "button",
|
|
6884
|
+
"aria-label": "Drawer \uB108\uBE44 \uC870\uC808",
|
|
6885
|
+
className: "absolute inset-y-0 left-0 z-[1] w-[8px] -translate-x-1/2 cursor-col-resize touch-none border-0 bg-transparent p-0",
|
|
6886
|
+
onMouseDown: handleResizeStart
|
|
6887
|
+
}
|
|
6888
|
+
),
|
|
6889
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6890
|
+
SOverlayHeader,
|
|
6891
|
+
{
|
|
6892
|
+
title,
|
|
6893
|
+
showClose: true,
|
|
6894
|
+
onClose: () => {
|
|
6895
|
+
onClose?.();
|
|
6896
|
+
onOpenChange?.(false);
|
|
6733
6897
|
}
|
|
6734
|
-
|
|
6735
|
-
|
|
6898
|
+
}
|
|
6899
|
+
),
|
|
6736
6900
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 flex-1 overflow-auto border-t border-solid border-[color:var(--cmp-drawer-body-border)]", children: /* @__PURE__ */ jsxRuntime.jsx(InsideModalProvider, { value: true, children: /* @__PURE__ */ jsxRuntime.jsx(PortalContainerProvider, { value: portalContainer, children }) }) }),
|
|
6737
|
-
(button || footerLeft) && /* @__PURE__ */ jsxRuntime.
|
|
6738
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-w-0 flex-1 items-center justify-between", children: footerLeft }),
|
|
6739
|
-
button && /* @__PURE__ */ jsxRuntime.jsx(
|
|
6740
|
-
SButton,
|
|
6741
|
-
{
|
|
6742
|
-
color: button.color ?? "primary",
|
|
6743
|
-
outline: button.outline,
|
|
6744
|
-
size: button.size ?? "md",
|
|
6745
|
-
disabled: button.disabled,
|
|
6746
|
-
onClick: () => button.onClick?.(),
|
|
6747
|
-
label: button.label ?? "\uD655\uC778"
|
|
6748
|
-
}
|
|
6749
|
-
)
|
|
6750
|
-
] })
|
|
6901
|
+
(button || footerLeft) && /* @__PURE__ */ jsxRuntime.jsx(SFooter, { left: footerLeft, leftClassName: "justify-between", button })
|
|
6751
6902
|
]
|
|
6752
6903
|
}
|
|
6753
6904
|
),
|
|
@@ -7002,6 +7153,80 @@ var SModal = {
|
|
|
7002
7153
|
return mount((refImpl) => /* @__PURE__ */ jsxRuntime.jsx(CreateMount, { options, refImpl }));
|
|
7003
7154
|
}
|
|
7004
7155
|
};
|
|
7156
|
+
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? react.useLayoutEffect : react.useEffect;
|
|
7157
|
+
var isSameNav = (a, b) => a === b || !!a && !!b && a.columnWidth === b.columnWidth && a.topHeight === b.topHeight && a.foldMs === b.foldMs && a.requireFullHeader === b.requireFullHeader;
|
|
7158
|
+
var SLayoutContext = /* @__PURE__ */ react.createContext(null);
|
|
7159
|
+
function useSLayout() {
|
|
7160
|
+
const ctx = react.useContext(SLayoutContext);
|
|
7161
|
+
if (!ctx) throw new Error("useSLayout \uC740 <SLayout> \uC548\uC5D0\uC11C\uB9CC \uC0AC\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.");
|
|
7162
|
+
return ctx;
|
|
7163
|
+
}
|
|
7164
|
+
var SLayout = /* @__PURE__ */ react.forwardRef(function SLayout2({
|
|
7165
|
+
type = "box",
|
|
7166
|
+
header = "fix",
|
|
7167
|
+
useRail = false,
|
|
7168
|
+
folded,
|
|
7169
|
+
defaultFolded = false,
|
|
7170
|
+
onFoldedChange,
|
|
7171
|
+
className,
|
|
7172
|
+
style,
|
|
7173
|
+
children,
|
|
7174
|
+
...rest
|
|
7175
|
+
}, ref) {
|
|
7176
|
+
const [uncontrolledFolded, setUncontrolledFolded] = react.useState(defaultFolded);
|
|
7177
|
+
const isControlled = folded !== void 0;
|
|
7178
|
+
const currentFolded = isControlled ? folded : uncontrolledFolded;
|
|
7179
|
+
const setFolded = react.useCallback(
|
|
7180
|
+
(next) => {
|
|
7181
|
+
if (!isControlled) setUncontrolledFolded(next);
|
|
7182
|
+
onFoldedChange?.(next);
|
|
7183
|
+
},
|
|
7184
|
+
[isControlled, onFoldedChange]
|
|
7185
|
+
);
|
|
7186
|
+
const [nav, setNav] = react.useState(null);
|
|
7187
|
+
const registerNav = react.useCallback(
|
|
7188
|
+
(next) => setNav((prev) => isSameNav(prev, next) ? prev : next),
|
|
7189
|
+
[]
|
|
7190
|
+
);
|
|
7191
|
+
const effectiveHeader = header === "full" || nav?.requireFullHeader ? "full" : "fix";
|
|
7192
|
+
const ctx = react.useMemo(
|
|
7193
|
+
() => ({
|
|
7194
|
+
type,
|
|
7195
|
+
header: effectiveHeader,
|
|
7196
|
+
useRail,
|
|
7197
|
+
folded: currentFolded,
|
|
7198
|
+
setFolded,
|
|
7199
|
+
registerNav
|
|
7200
|
+
}),
|
|
7201
|
+
[type, effectiveHeader, useRail, currentFolded, setFolded, registerNav]
|
|
7202
|
+
);
|
|
7203
|
+
const isFullHeader = effectiveHeader === "full";
|
|
7204
|
+
const frameStyle = isFullHeader ? {
|
|
7205
|
+
// 자식이 좌표가 아니라 이름으로 자리를 잡게 한다 — 열·행이 늘어도 자식을 고칠 일이 없다.
|
|
7206
|
+
gridTemplateAreas: '"header header" "nav page"',
|
|
7207
|
+
gridTemplateColumns: `${currentFolded ? 0 : nav?.columnWidth ?? 0}px 1fr`,
|
|
7208
|
+
gridTemplateRows: `${nav?.topHeight ?? "0px"} 1fr`,
|
|
7209
|
+
// 메뉴가 미끄러지는 동안 페이지 열도 같은 길이로 따라와야 한 덩어리로 읽힌다.
|
|
7210
|
+
// (fix 는 SGnb 가 제 폭을 직접 전환하므로 프레임이 손댈 게 없다)
|
|
7211
|
+
transition: `grid-template-columns ${nav?.foldMs ?? 0}ms ease-out`
|
|
7212
|
+
} : void 0;
|
|
7213
|
+
return /* @__PURE__ */ jsxRuntime.jsx(SLayoutContext.Provider, { value: ctx, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7214
|
+
"div",
|
|
7215
|
+
{
|
|
7216
|
+
ref,
|
|
7217
|
+
"data-type": type,
|
|
7218
|
+
"data-header": effectiveHeader,
|
|
7219
|
+
className: cn(
|
|
7220
|
+
"box-border h-full overflow-hidden",
|
|
7221
|
+
isFullHeader ? "grid" : "flex flex-row",
|
|
7222
|
+
className
|
|
7223
|
+
),
|
|
7224
|
+
style: { ...frameStyle, ...style },
|
|
7225
|
+
...rest,
|
|
7226
|
+
children
|
|
7227
|
+
}
|
|
7228
|
+
) });
|
|
7229
|
+
});
|
|
7005
7230
|
|
|
7006
7231
|
// src/components/SGnb/gnb.config.ts
|
|
7007
7232
|
var gnb = (p) => `var(--cmp-gnb-${p})`;
|
|
@@ -7134,6 +7359,21 @@ function findGnbRailValue(items, value) {
|
|
|
7134
7359
|
if (items.some((item) => item.value === value)) return value;
|
|
7135
7360
|
return findGnbAncestors(items, value)[0];
|
|
7136
7361
|
}
|
|
7362
|
+
function findGnbSiblingValues(items, value) {
|
|
7363
|
+
const walk = (list) => {
|
|
7364
|
+
if (list.some((item) => item.value === value)) {
|
|
7365
|
+
return list.filter((item) => item.value !== value).map((item) => item.value);
|
|
7366
|
+
}
|
|
7367
|
+
for (const item of list) {
|
|
7368
|
+
if (item.children) {
|
|
7369
|
+
const found = walk(item.children);
|
|
7370
|
+
if (found) return found;
|
|
7371
|
+
}
|
|
7372
|
+
}
|
|
7373
|
+
return null;
|
|
7374
|
+
};
|
|
7375
|
+
return walk(items) ?? [];
|
|
7376
|
+
}
|
|
7137
7377
|
function findGnbAncestors(items, value) {
|
|
7138
7378
|
const walk = (list, trail) => {
|
|
7139
7379
|
for (const item of list) {
|
|
@@ -7147,79 +7387,6 @@ function findGnbAncestors(items, value) {
|
|
|
7147
7387
|
};
|
|
7148
7388
|
return walk(items, []) ?? [];
|
|
7149
7389
|
}
|
|
7150
|
-
var SLayoutContext = /* @__PURE__ */ react.createContext(null);
|
|
7151
|
-
function useSLayout() {
|
|
7152
|
-
const ctx = react.useContext(SLayoutContext);
|
|
7153
|
-
if (!ctx) throw new Error("useSLayout \uC740 <SLayout> \uC548\uC5D0\uC11C\uB9CC \uC0AC\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.");
|
|
7154
|
-
return ctx;
|
|
7155
|
-
}
|
|
7156
|
-
var SLayout = /* @__PURE__ */ react.forwardRef(function SLayout2({
|
|
7157
|
-
type = "box",
|
|
7158
|
-
header = "fix",
|
|
7159
|
-
useRail = false,
|
|
7160
|
-
folded,
|
|
7161
|
-
defaultFolded = false,
|
|
7162
|
-
onFoldedChange,
|
|
7163
|
-
className,
|
|
7164
|
-
style,
|
|
7165
|
-
children,
|
|
7166
|
-
...rest
|
|
7167
|
-
}, ref) {
|
|
7168
|
-
const [uncontrolledFolded, setUncontrolledFolded] = react.useState(defaultFolded);
|
|
7169
|
-
const isControlled = folded !== void 0;
|
|
7170
|
-
const currentFolded = isControlled ? folded : uncontrolledFolded;
|
|
7171
|
-
const setFolded = react.useCallback(
|
|
7172
|
-
(next) => {
|
|
7173
|
-
if (!isControlled) setUncontrolledFolded(next);
|
|
7174
|
-
onFoldedChange?.(next);
|
|
7175
|
-
},
|
|
7176
|
-
[isControlled, onFoldedChange]
|
|
7177
|
-
);
|
|
7178
|
-
const [gnbState, setGnbState] = react.useState({ forceFull: false, menuVisible: true });
|
|
7179
|
-
const reportGnbState = react.useCallback(
|
|
7180
|
-
(next) => setGnbState(
|
|
7181
|
-
(prev) => prev.forceFull === next.forceFull && prev.menuVisible === next.menuVisible ? prev : next
|
|
7182
|
-
),
|
|
7183
|
-
[]
|
|
7184
|
-
);
|
|
7185
|
-
const effectiveHeader = header === "full" || gnbState.forceFull ? "full" : "fix";
|
|
7186
|
-
const ctx = react.useMemo(
|
|
7187
|
-
() => ({
|
|
7188
|
-
type,
|
|
7189
|
-
header: effectiveHeader,
|
|
7190
|
-
useRail,
|
|
7191
|
-
folded: currentFolded,
|
|
7192
|
-
setFolded,
|
|
7193
|
-
reportGnbState
|
|
7194
|
-
}),
|
|
7195
|
-
[type, effectiveHeader, useRail, currentFolded, setFolded, reportGnbState]
|
|
7196
|
-
);
|
|
7197
|
-
const isFullHeader = effectiveHeader === "full";
|
|
7198
|
-
const gnbColumnWidth = (useRail ? GNB_RAIL_WIDTH : 0) + (gnbState.menuVisible ? GNB_MENU_WIDTH : 0);
|
|
7199
|
-
const frameStyle = isFullHeader ? {
|
|
7200
|
-
gridTemplateColumns: `${currentFolded ? 0 : gnbColumnWidth}px 1fr`,
|
|
7201
|
-
gridTemplateRows: `${GNB_HEADER[effectiveHeader].topHeight} 1fr`,
|
|
7202
|
-
// 메뉴가 미끄러지는 동안 페이지 열도 같은 길이로 따라와야 한 덩어리로 읽힌다.
|
|
7203
|
-
// (fix 는 SGnb 가 제 폭을 직접 전환하므로 프레임이 손댈 게 없다)
|
|
7204
|
-
transition: `grid-template-columns ${GNB_FOLD_MS}ms ease-out`
|
|
7205
|
-
} : void 0;
|
|
7206
|
-
return /* @__PURE__ */ jsxRuntime.jsx(SLayoutContext.Provider, { value: ctx, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7207
|
-
"div",
|
|
7208
|
-
{
|
|
7209
|
-
ref,
|
|
7210
|
-
"data-type": type,
|
|
7211
|
-
"data-header": effectiveHeader,
|
|
7212
|
-
className: cn(
|
|
7213
|
-
"box-border h-full overflow-hidden",
|
|
7214
|
-
isFullHeader ? "grid" : "flex flex-row",
|
|
7215
|
-
className
|
|
7216
|
-
),
|
|
7217
|
-
style: { ...frameStyle, ...style },
|
|
7218
|
-
...rest,
|
|
7219
|
-
children
|
|
7220
|
-
}
|
|
7221
|
-
) });
|
|
7222
|
-
});
|
|
7223
7390
|
var DEPTH_PADDING_LEFT = (M, depth) => depth === 1 ? M.depth1PaddingLeft : depth === 2 ? M.depth2PaddingLeft : M.depth3PaddingLeft;
|
|
7224
7391
|
var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
|
|
7225
7392
|
type: typeProp,
|
|
@@ -7281,8 +7448,12 @@ var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
|
|
|
7281
7448
|
const toggleExpand = (key) => {
|
|
7282
7449
|
setExpandedKeys((prev) => {
|
|
7283
7450
|
const next = new Set(prev);
|
|
7284
|
-
if (next.has(key))
|
|
7285
|
-
|
|
7451
|
+
if (next.has(key)) {
|
|
7452
|
+
next.delete(key);
|
|
7453
|
+
} else {
|
|
7454
|
+
findGnbSiblingValues(items, key).forEach((sibling) => next.delete(sibling));
|
|
7455
|
+
next.add(key);
|
|
7456
|
+
}
|
|
7286
7457
|
return next;
|
|
7287
7458
|
});
|
|
7288
7459
|
};
|
|
@@ -7453,16 +7624,30 @@ var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
|
|
|
7453
7624
|
const menuItems = useRail ? items.find((item) => item.value === activeRail)?.children ?? [] : items;
|
|
7454
7625
|
const showMenu = !useRail || menuItems.length > 0;
|
|
7455
7626
|
const bodyWidth = (useRail ? GNB_RAIL_WIDTH : 0) + (showMenu ? GNB_MENU_WIDTH : 0);
|
|
7456
|
-
|
|
7457
|
-
|
|
7458
|
-
|
|
7627
|
+
const registerNav = layout?.registerNav;
|
|
7628
|
+
useIsomorphicLayoutEffect(() => {
|
|
7629
|
+
if (!registerNav) return;
|
|
7630
|
+
registerNav({
|
|
7631
|
+
columnWidth: bodyWidth,
|
|
7632
|
+
topHeight: H.topHeight,
|
|
7633
|
+
foldMs: GNB_FOLD_MS,
|
|
7634
|
+
requireFullHeader: railHasLeaf
|
|
7635
|
+
});
|
|
7636
|
+
return () => registerNav(null);
|
|
7637
|
+
}, [registerNav, bodyWidth, H.topHeight, railHasLeaf]);
|
|
7459
7638
|
const railFolded = folded && header === "fix";
|
|
7460
|
-
const
|
|
7639
|
+
const isFull = header === "full";
|
|
7640
|
+
const isFullFrame = isFull && !!layout;
|
|
7461
7641
|
const rightBorder = color === "light" ? `1px solid ${C.topBorder}` : void 0;
|
|
7462
|
-
const rootStyle = {
|
|
7463
|
-
|
|
7642
|
+
const rootStyle = isFullFrame ? { display: "contents", ...style } : isFull ? (
|
|
7643
|
+
// 단독 full — 상단바가 전폭이어야 하므로 루트도 전폭이고, 배경·선은 상단바·메뉴가 각자 그린다.
|
|
7644
|
+
{ width: "100%", ...style }
|
|
7645
|
+
) : {
|
|
7646
|
+
// fix 를 닫으면 48px 레일로 좁혀진다.
|
|
7647
|
+
width: folded ? GNB_COMMON.foldWidth : bodyWidth,
|
|
7464
7648
|
transition: `width ${GNB_FOLD_MS}ms ease-out`,
|
|
7465
|
-
|
|
7649
|
+
backgroundColor: C.panelBg,
|
|
7650
|
+
borderRight: rightBorder,
|
|
7466
7651
|
...style
|
|
7467
7652
|
};
|
|
7468
7653
|
const hideAfterSlide = (hidden) => `visibility 0s linear ${hidden ? `${GNB_FOLD_MS}ms` : "0s"}`;
|
|
@@ -7535,7 +7720,11 @@ var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
|
|
|
7535
7720
|
"div",
|
|
7536
7721
|
{
|
|
7537
7722
|
ref,
|
|
7538
|
-
className: cn(
|
|
7723
|
+
className: cn(
|
|
7724
|
+
"box-border",
|
|
7725
|
+
!isFullFrame && "flex h-full shrink-0 flex-col overflow-hidden",
|
|
7726
|
+
className
|
|
7727
|
+
),
|
|
7539
7728
|
style: rootStyle,
|
|
7540
7729
|
"data-type": type,
|
|
7541
7730
|
"data-header": header,
|
|
@@ -7547,6 +7736,7 @@ var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
|
|
|
7547
7736
|
{
|
|
7548
7737
|
className: "relative box-border flex shrink-0 items-center overflow-hidden",
|
|
7549
7738
|
style: {
|
|
7739
|
+
...isFullFrame ? { gridArea: "header" } : null,
|
|
7550
7740
|
height: H.topHeight,
|
|
7551
7741
|
// 간격은 컨테이너 gap 대신 각 요소 margin 으로 준다 — 순서가 header 마다 달라
|
|
7552
7742
|
// 이웃 쌍마다 값이 다르기 때문(위 launcherButton/logoBox 주석).
|
|
@@ -7554,7 +7744,6 @@ var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
|
|
|
7554
7744
|
padding: `0 ${railFolded ? GNB_RAIL.padding : H.topPaddingX}`,
|
|
7555
7745
|
borderBottom: `1px solid ${C.topBorder}`,
|
|
7556
7746
|
backgroundColor: C.panelBg,
|
|
7557
|
-
pointerEvents: "auto",
|
|
7558
7747
|
transition: `padding ${GNB_FOLD_MS}ms ease-out`,
|
|
7559
7748
|
// 아이콘 버튼은 자체 ghostButton 토큰을 쓰므로, 이 색은 logo 슬롯 상속용
|
|
7560
7749
|
color: C.itemColorDefault
|
|
@@ -7571,94 +7760,87 @@ var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
|
|
|
7571
7760
|
] })
|
|
7572
7761
|
}
|
|
7573
7762
|
),
|
|
7574
|
-
/* @__PURE__ */ jsxRuntime.
|
|
7763
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7575
7764
|
"div",
|
|
7576
7765
|
{
|
|
7577
|
-
className: "
|
|
7578
|
-
style: {
|
|
7579
|
-
|
|
7580
|
-
|
|
7581
|
-
|
|
7582
|
-
|
|
7583
|
-
|
|
7584
|
-
|
|
7585
|
-
|
|
7586
|
-
|
|
7587
|
-
|
|
7588
|
-
|
|
7589
|
-
|
|
7590
|
-
|
|
7591
|
-
|
|
7592
|
-
|
|
7593
|
-
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
|
|
7598
|
-
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
|
|
7603
|
-
|
|
7604
|
-
|
|
7605
|
-
|
|
7606
|
-
|
|
7607
|
-
|
|
7608
|
-
|
|
7609
|
-
|
|
7610
|
-
|
|
7766
|
+
className: cn("overflow-hidden", !isFullFrame && "min-h-0 flex-1"),
|
|
7767
|
+
style: isFullFrame ? { gridArea: "nav" } : void 0,
|
|
7768
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7769
|
+
"div",
|
|
7770
|
+
{
|
|
7771
|
+
className: "flex h-full flex-row",
|
|
7772
|
+
style: {
|
|
7773
|
+
width: bodyWidth,
|
|
7774
|
+
transform: folded ? "translateX(-100%)" : "none",
|
|
7775
|
+
visibility: folded ? "hidden" : "visible",
|
|
7776
|
+
transition: `transform ${GNB_FOLD_MS}ms ease-out, ${hideAfterSlide(folded)}`
|
|
7777
|
+
},
|
|
7778
|
+
children: [
|
|
7779
|
+
useRail && // 레일 컬럼 — 스크롤되는 아이템 목록(nav)과 하단 고정 footer 를 한 컬럼에 담는다.
|
|
7780
|
+
// footer 는 내비게이션이 아니므로 nav(landmark) 밖에 두고, 컬럼 폭·구분선·배경은 이 래퍼가
|
|
7781
|
+
// 전체 높이에 걸쳐 책임진다(그래야 footer 자리까지 배경·오른쪽 선이 이어진다).
|
|
7782
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
7783
|
+
"div",
|
|
7784
|
+
{
|
|
7785
|
+
className: "flex shrink-0 flex-col overflow-hidden",
|
|
7786
|
+
style: {
|
|
7787
|
+
width: GNB_RAIL_WIDTH,
|
|
7788
|
+
borderRight: `1px solid ${C.topBorder}`,
|
|
7789
|
+
backgroundColor: C.panelBg
|
|
7790
|
+
},
|
|
7791
|
+
children: [
|
|
7792
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7793
|
+
"nav",
|
|
7794
|
+
{
|
|
7795
|
+
"aria-label": `${ariaLabel} rail`,
|
|
7796
|
+
className: cn(
|
|
7797
|
+
"flex min-h-0 flex-1 flex-col overflow-x-hidden overflow-y-auto",
|
|
7798
|
+
SCROLLBAR_HIDDEN_CLASS
|
|
7799
|
+
),
|
|
7800
|
+
style: { padding: GNB_RAIL.padding },
|
|
7801
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "m-0 flex list-none flex-col p-0", style: { gap: GNB_RAIL.gap }, children: railItems.map(renderRailItem) })
|
|
7802
|
+
}
|
|
7611
7803
|
),
|
|
7612
|
-
|
|
7613
|
-
|
|
7614
|
-
|
|
7615
|
-
|
|
7616
|
-
|
|
7617
|
-
|
|
7618
|
-
|
|
7619
|
-
|
|
7620
|
-
|
|
7621
|
-
|
|
7622
|
-
|
|
7623
|
-
|
|
7624
|
-
|
|
7625
|
-
|
|
7626
|
-
|
|
7627
|
-
|
|
7628
|
-
|
|
7629
|
-
|
|
7630
|
-
|
|
7631
|
-
|
|
7632
|
-
|
|
7633
|
-
|
|
7634
|
-
|
|
7635
|
-
|
|
7636
|
-
|
|
7637
|
-
|
|
7638
|
-
|
|
7804
|
+
railFooter && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: railFooter })
|
|
7805
|
+
]
|
|
7806
|
+
}
|
|
7807
|
+
),
|
|
7808
|
+
showMenu && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7809
|
+
"div",
|
|
7810
|
+
{
|
|
7811
|
+
className: "flex shrink-0 flex-col overflow-hidden",
|
|
7812
|
+
style: {
|
|
7813
|
+
width: GNB_MENU_WIDTH,
|
|
7814
|
+
backgroundColor: C.panelBg,
|
|
7815
|
+
// full 은 루트가 오른쪽 선을 못 그리므로(전폭이거나 아예 없다) 메뉴 오른쪽(페이지 경계)이 대신 그린다.
|
|
7816
|
+
borderRight: isFull ? rightBorder : void 0
|
|
7817
|
+
},
|
|
7818
|
+
children: [
|
|
7819
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7820
|
+
"nav",
|
|
7821
|
+
{
|
|
7822
|
+
"aria-label": ariaLabel,
|
|
7823
|
+
className: cn(
|
|
7824
|
+
"flex min-h-0 flex-1 flex-col overflow-x-hidden overflow-y-auto",
|
|
7825
|
+
SCROLLBAR_HIDDEN_CLASS
|
|
7826
|
+
),
|
|
7827
|
+
style: {
|
|
7828
|
+
paddingTop: M.bodyPaddingY,
|
|
7829
|
+
paddingBottom: M.bodyPaddingY
|
|
7830
|
+
},
|
|
7831
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "m-0 flex list-none flex-col p-0", children: menuItems.map((item) => renderItem(item, 1)) })
|
|
7832
|
+
}
|
|
7639
7833
|
),
|
|
7640
|
-
|
|
7641
|
-
|
|
7642
|
-
|
|
7643
|
-
|
|
7644
|
-
|
|
7645
|
-
|
|
7646
|
-
|
|
7647
|
-
menuFooter && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: menuFooter })
|
|
7648
|
-
]
|
|
7649
|
-
}
|
|
7650
|
-
)
|
|
7651
|
-
]
|
|
7834
|
+
menuFooter && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: menuFooter })
|
|
7835
|
+
]
|
|
7836
|
+
}
|
|
7837
|
+
)
|
|
7838
|
+
]
|
|
7839
|
+
}
|
|
7840
|
+
)
|
|
7652
7841
|
}
|
|
7653
7842
|
),
|
|
7654
|
-
railFolded && foldedFooter && /* @__PURE__ */ jsxRuntime.jsx(
|
|
7655
|
-
"div",
|
|
7656
|
-
{
|
|
7657
|
-
className: "flex shrink-0 items-center justify-center mb-[24px]",
|
|
7658
|
-
style: { pointerEvents: "auto" },
|
|
7659
|
-
children: foldedFooter
|
|
7660
|
-
}
|
|
7661
|
-
)
|
|
7843
|
+
railFolded && foldedFooter && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex shrink-0 items-center justify-center mb-[24px]", children: foldedFooter })
|
|
7662
7844
|
]
|
|
7663
7845
|
}
|
|
7664
7846
|
);
|
|
@@ -7670,7 +7852,7 @@ var BACKGROUND_CLASS = {
|
|
|
7670
7852
|
};
|
|
7671
7853
|
var SPage = /* @__PURE__ */ react.forwardRef(function SPage2({ background = "frame", className, style, children, ...rest }, ref) {
|
|
7672
7854
|
const layout = react.useContext(SLayoutContext);
|
|
7673
|
-
const gridStyle = layout?.header === "full" ? {
|
|
7855
|
+
const gridStyle = layout?.header === "full" ? { gridArea: "page" } : void 0;
|
|
7674
7856
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
7675
7857
|
"main",
|
|
7676
7858
|
{
|
|
@@ -11977,6 +12159,7 @@ var SToastContainer = /* @__PURE__ */ react.forwardRef(
|
|
|
11977
12159
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11978
12160
|
"div",
|
|
11979
12161
|
{
|
|
12162
|
+
...globalOverlayProps,
|
|
11980
12163
|
style: {
|
|
11981
12164
|
position: "fixed",
|
|
11982
12165
|
zIndex,
|