sellmate-design-system-react 0.1.11 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/dist/components/SActionModal/SActionModal.cjs +9 -3
  2. package/dist/components/SActionModal/SActionModal.cjs.map +1 -1
  3. package/dist/components/SActionModal/SActionModal.js +9 -3
  4. package/dist/components/SActionModal/SActionModal.js.map +1 -1
  5. package/dist/components/SBarcodeInput/SBarcodeInput.cjs +9 -3
  6. package/dist/components/SBarcodeInput/SBarcodeInput.cjs.map +1 -1
  7. package/dist/components/SBarcodeInput/SBarcodeInput.js +9 -3
  8. package/dist/components/SBarcodeInput/SBarcodeInput.js.map +1 -1
  9. package/dist/components/SCalendar/SCalendar.cjs +9 -3
  10. package/dist/components/SCalendar/SCalendar.cjs.map +1 -1
  11. package/dist/components/SCalendar/SCalendar.js +9 -3
  12. package/dist/components/SCalendar/SCalendar.js.map +1 -1
  13. package/dist/components/SChip/SChip.cjs +9 -3
  14. package/dist/components/SChip/SChip.cjs.map +1 -1
  15. package/dist/components/SChip/SChip.js +9 -3
  16. package/dist/components/SChip/SChip.js.map +1 -1
  17. package/dist/components/SChipInput/SChipInput.cjs +25 -10
  18. package/dist/components/SChipInput/SChipInput.cjs.map +1 -1
  19. package/dist/components/SChipInput/SChipInput.js +25 -10
  20. package/dist/components/SChipInput/SChipInput.js.map +1 -1
  21. package/dist/components/SCircleProgress/SCircleProgress.cjs +6 -2
  22. package/dist/components/SCircleProgress/SCircleProgress.cjs.map +1 -1
  23. package/dist/components/SCircleProgress/SCircleProgress.js +6 -2
  24. package/dist/components/SCircleProgress/SCircleProgress.js.map +1 -1
  25. package/dist/components/SConfirmModal/SConfirmModal.cjs +9 -3
  26. package/dist/components/SConfirmModal/SConfirmModal.cjs.map +1 -1
  27. package/dist/components/SConfirmModal/SConfirmModal.js +9 -3
  28. package/dist/components/SConfirmModal/SConfirmModal.js.map +1 -1
  29. package/dist/components/SDatePicker/SDatePicker.cjs +9 -3
  30. package/dist/components/SDatePicker/SDatePicker.cjs.map +1 -1
  31. package/dist/components/SDatePicker/SDatePicker.js +9 -3
  32. package/dist/components/SDatePicker/SDatePicker.js.map +1 -1
  33. package/dist/components/SDateRangePicker/SDateRangePicker.cjs +9 -3
  34. package/dist/components/SDateRangePicker/SDateRangePicker.cjs.map +1 -1
  35. package/dist/components/SDateRangePicker/SDateRangePicker.js +9 -3
  36. package/dist/components/SDateRangePicker/SDateRangePicker.js.map +1 -1
  37. package/dist/components/SDropdownButton/SDropdownButton.cjs +1 -1
  38. package/dist/components/SDropdownButton/SDropdownButton.cjs.map +1 -1
  39. package/dist/components/SDropdownButton/SDropdownButton.js +1 -1
  40. package/dist/components/SDropdownButton/SDropdownButton.js.map +1 -1
  41. package/dist/components/SField/SField.cjs +9 -3
  42. package/dist/components/SField/SField.cjs.map +1 -1
  43. package/dist/components/SField/SField.js +9 -3
  44. package/dist/components/SField/SField.js.map +1 -1
  45. package/dist/components/SFilePicker/SFilePicker.cjs +9 -3
  46. package/dist/components/SFilePicker/SFilePicker.cjs.map +1 -1
  47. package/dist/components/SFilePicker/SFilePicker.js +9 -3
  48. package/dist/components/SFilePicker/SFilePicker.js.map +1 -1
  49. package/dist/components/SGhostButton/SGhostButton.cjs +9 -3
  50. package/dist/components/SGhostButton/SGhostButton.cjs.map +1 -1
  51. package/dist/components/SGhostButton/SGhostButton.d.ts +7 -1
  52. package/dist/components/SGhostButton/SGhostButton.js +9 -3
  53. package/dist/components/SGhostButton/SGhostButton.js.map +1 -1
  54. package/dist/components/SGnb/SGnb.cjs +3478 -0
  55. package/dist/components/SGnb/SGnb.cjs.map +1 -0
  56. package/dist/components/SGnb/SGnb.d.ts +39 -0
  57. package/dist/components/SGnb/SGnb.js +3456 -0
  58. package/dist/components/SGnb/SGnb.js.map +1 -0
  59. package/dist/components/SGnb/gnb.config.d.ts +87 -0
  60. package/dist/components/SGnb/index.d.ts +2 -0
  61. package/dist/components/SGuide/SGuide.cjs +9 -3
  62. package/dist/components/SGuide/SGuide.cjs.map +1 -1
  63. package/dist/components/SGuide/SGuide.js +9 -3
  64. package/dist/components/SGuide/SGuide.js.map +1 -1
  65. package/dist/components/SInput/SInput.cjs +9 -3
  66. package/dist/components/SInput/SInput.cjs.map +1 -1
  67. package/dist/components/SInput/SInput.js +9 -3
  68. package/dist/components/SInput/SInput.js.map +1 -1
  69. package/dist/components/SKeyValueTable/SKeyValueTable.cjs +20 -6
  70. package/dist/components/SKeyValueTable/SKeyValueTable.cjs.map +1 -1
  71. package/dist/components/SKeyValueTable/SKeyValueTable.js +20 -6
  72. package/dist/components/SKeyValueTable/SKeyValueTable.js.map +1 -1
  73. package/dist/components/SLayout/SLayout.cjs +97 -0
  74. package/dist/components/SLayout/SLayout.cjs.map +1 -0
  75. package/dist/components/SLayout/SLayout.d.ts +47 -0
  76. package/dist/components/SLayout/SLayout.js +93 -0
  77. package/dist/components/SLayout/SLayout.js.map +1 -0
  78. package/dist/components/SLayout/index.d.ts +1 -0
  79. package/dist/components/SLoadingContainer/SLoadingContainer.cjs +6 -2
  80. package/dist/components/SLoadingContainer/SLoadingContainer.cjs.map +1 -1
  81. package/dist/components/SLoadingContainer/SLoadingContainer.js +6 -2
  82. package/dist/components/SLoadingContainer/SLoadingContainer.js.map +1 -1
  83. package/dist/components/SLoadingContainer/loading.cjs +6 -2
  84. package/dist/components/SLoadingContainer/loading.cjs.map +1 -1
  85. package/dist/components/SLoadingContainer/loading.js +6 -2
  86. package/dist/components/SLoadingContainer/loading.js.map +1 -1
  87. package/dist/components/SLoadingModal/SLoadingModal.cjs +15 -5
  88. package/dist/components/SLoadingModal/SLoadingModal.cjs.map +1 -1
  89. package/dist/components/SLoadingModal/SLoadingModal.js +15 -5
  90. package/dist/components/SLoadingModal/SLoadingModal.js.map +1 -1
  91. package/dist/components/SModalContainer/SModalContainer.cjs +9 -3
  92. package/dist/components/SModalContainer/SModalContainer.cjs.map +1 -1
  93. package/dist/components/SModalContainer/SModalContainer.d.ts +10 -0
  94. package/dist/components/SModalContainer/SModalContainer.js +9 -3
  95. package/dist/components/SModalContainer/SModalContainer.js.map +1 -1
  96. package/dist/components/SNumberInput/SNumberInput.cjs +9 -3
  97. package/dist/components/SNumberInput/SNumberInput.cjs.map +1 -1
  98. package/dist/components/SNumberInput/SNumberInput.js +9 -3
  99. package/dist/components/SNumberInput/SNumberInput.js.map +1 -1
  100. package/dist/components/SPage/SPage.cjs +104 -0
  101. package/dist/components/SPage/SPage.cjs.map +1 -0
  102. package/dist/components/SPage/SPage.d.ts +13 -0
  103. package/dist/components/SPage/SPage.js +102 -0
  104. package/dist/components/SPage/SPage.js.map +1 -0
  105. package/dist/components/SPage/index.d.ts +1 -0
  106. package/dist/components/SPopover/SPopover.cjs +9 -3
  107. package/dist/components/SPopover/SPopover.cjs.map +1 -1
  108. package/dist/components/SPopover/SPopover.js +9 -3
  109. package/dist/components/SPopover/SPopover.js.map +1 -1
  110. package/dist/components/SPortal/SPortal.cjs +1 -1
  111. package/dist/components/SPortal/SPortal.cjs.map +1 -1
  112. package/dist/components/SPortal/SPortal.js +1 -1
  113. package/dist/components/SPortal/SPortal.js.map +1 -1
  114. package/dist/components/SSelect/SSelect.cjs +20 -6
  115. package/dist/components/SSelect/SSelect.cjs.map +1 -1
  116. package/dist/components/SSelect/SSelect.js +20 -6
  117. package/dist/components/SSelect/SSelect.js.map +1 -1
  118. package/dist/components/STable/STable.cjs +28 -10
  119. package/dist/components/STable/STable.cjs.map +1 -1
  120. package/dist/components/STable/STable.js +28 -10
  121. package/dist/components/STable/STable.js.map +1 -1
  122. package/dist/components/STextarea/STextarea.cjs +9 -3
  123. package/dist/components/STextarea/STextarea.cjs.map +1 -1
  124. package/dist/components/STextarea/STextarea.js +9 -3
  125. package/dist/components/STextarea/STextarea.js.map +1 -1
  126. package/dist/components/SToast/SToast.cjs +9 -3
  127. package/dist/components/SToast/SToast.cjs.map +1 -1
  128. package/dist/components/SToast/SToast.js +9 -3
  129. package/dist/components/SToast/SToast.js.map +1 -1
  130. package/dist/components/SToast/SToastContainer.cjs +9 -3
  131. package/dist/components/SToast/SToastContainer.cjs.map +1 -1
  132. package/dist/components/SToast/SToastContainer.js +9 -3
  133. package/dist/components/SToast/SToastContainer.js.map +1 -1
  134. package/dist/components/STooltip/STooltip.cjs +9 -3
  135. package/dist/components/STooltip/STooltip.cjs.map +1 -1
  136. package/dist/components/STooltip/STooltip.js +9 -3
  137. package/dist/components/STooltip/STooltip.js.map +1 -1
  138. package/dist/index.cjs +453 -17
  139. package/dist/index.cjs.map +1 -1
  140. package/dist/index.d.ts +3 -0
  141. package/dist/index.js +444 -19
  142. package/dist/index.js.map +1 -1
  143. package/dist/styles.css +530 -26
  144. package/dist/theme.css +70 -14
  145. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -3347,8 +3347,12 @@ var SCircleProgress = react.forwardRef(
3347
3347
  "span",
3348
3348
  {
3349
3349
  className: cn(
3350
- "text-center text-[16px] font-bold leading-[26px]",
3351
- innerValue && "absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2"
3350
+ "text-center text-[16px] font-bold",
3351
+ innerValue ? (
3352
+ // leading-[normal]: 26px leading 은 폰트 content(19px) 위아래로 홀수(7px)만큼 남아
3353
+ // 3px/4px 로 쪼개지고 글자가 링 중심보다 위로 뜬다. (leading-normal 은 1.5 라 동일 문제)
3354
+ "absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 leading-[normal]"
3355
+ ) : "leading-[26px]"
3352
3356
  ),
3353
3357
  style: { color: percentColor },
3354
3358
  children: [
@@ -3914,7 +3918,7 @@ var SDropdownButton = react.forwardRef(
3914
3918
  ...style
3915
3919
  },
3916
3920
  children: [
3917
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: label }),
3921
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate text-center", children: label }),
3918
3922
  caret
3919
3923
  ]
3920
3924
  }
@@ -3939,9 +3943,12 @@ function SGhostButton({
3939
3943
  size = "sm",
3940
3944
  intent = "default",
3941
3945
  ariaLabel = "",
3946
+ ariaPressed,
3942
3947
  tooltipText,
3943
3948
  disabled = false,
3944
3949
  onClick,
3950
+ anchorClassName,
3951
+ anchorStyle,
3945
3952
  className,
3946
3953
  style
3947
3954
  }) {
@@ -3964,6 +3971,8 @@ function SGhostButton({
3964
3971
  };
3965
3972
  const s = SIZE2[size];
3966
3973
  const contentColor = disabled ? intent === "inverse" ? "var(--cmp-ghostButton-inverse-disabled)" : "var(--cmp-ghostButton-icon-disabled)" : `var(--cmp-ghostButton-${intent}-content)`;
3974
+ const text = (tooltipText ?? "").trim();
3975
+ const hasTooltip = text !== "";
3967
3976
  const btn = /* @__PURE__ */ jsxRuntime.jsxs(
3968
3977
  "button",
3969
3978
  {
@@ -3971,6 +3980,7 @@ function SGhostButton({
3971
3980
  disabled,
3972
3981
  "aria-disabled": disabled ? "true" : void 0,
3973
3982
  "aria-label": ariaLabel.trim() || void 0,
3983
+ "aria-pressed": ariaPressed,
3974
3984
  tabIndex: disabled ? -1 : void 0,
3975
3985
  onClick: (e) => {
3976
3986
  if (disabled) {
@@ -4004,13 +4014,13 @@ function SGhostButton({
4004
4014
  ]
4005
4015
  }
4006
4016
  );
4007
- const text = (tooltipText ?? "").trim();
4008
- if (text === "") return btn;
4017
+ if (!hasTooltip) return btn;
4009
4018
  return /* @__PURE__ */ jsxRuntime.jsxs(RPopover2__namespace.Root, { open, onOpenChange: setOpen, children: [
4010
4019
  /* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Anchor, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
4011
4020
  "span",
4012
4021
  {
4013
- className: "inline-flex",
4022
+ className: cn("inline-flex", anchorClassName),
4023
+ style: anchorStyle,
4014
4024
  onMouseEnter: openNow,
4015
4025
  onMouseLeave: startHide,
4016
4026
  onFocus: openNow,
@@ -4411,7 +4421,7 @@ function SPortal({
4411
4421
  onCloseAutoFocus,
4412
4422
  onClick: autoClose ? () => onClose?.() : void 0,
4413
4423
  className: cn(
4414
- "z-50 overflow-hidden rounded-(--cmp-listBox-radius) bg-(--cmp-listBox-bg) py-4 shadow-normal-sm",
4424
+ "z-50 overflow-hidden rounded-(--cmp-listBox-radius) bg-(--cmp-listBox-bg) shadow-normal-sm",
4415
4425
  maxHeight != null && "overflow-y-auto",
4416
4426
  fit && "min-w-(--radix-popover-trigger-width)",
4417
4427
  FLOATING_SLIDE_ANIM,
@@ -4893,6 +4903,404 @@ function SLoadingModal({
4893
4903
  );
4894
4904
  }
4895
4905
 
4906
+ // src/components/SGnb/gnb.config.ts
4907
+ var belt = (p) => `var(--cmp-gnbBelt-${p})`;
4908
+ var box = (p) => `var(--cmp-gnbBox-${p})`;
4909
+ var light = (p) => `var(--cmp-light-${p})`;
4910
+ var dark = (p) => `var(--cmp-dark-${p})`;
4911
+ var GNB_HEADER = {
4912
+ fix: {
4913
+ topHeight: belt("top-height"),
4914
+ topPaddingX: belt("top-paddingX"),
4915
+ topGap: belt("top-gap"),
4916
+ logoHeight: belt("logo-height")
4917
+ },
4918
+ full: {
4919
+ topHeight: box("top-height"),
4920
+ topPaddingX: box("paddingX"),
4921
+ topGap: box("gap"),
4922
+ // 상단바 gap (버튼 간 세부 gap 은 --cmp-gnbBox-button-gap)
4923
+ logoHeight: box("logo-height")
4924
+ }
4925
+ };
4926
+ var GNB_MENU = {
4927
+ box: {
4928
+ // menu.body.padding 은 전방향 토큰 → 세로 패딩과 아이템 좌우 여백 양쪽에 쓴다
4929
+ bodyPaddingY: box("menu-body-padding"),
4930
+ itemMarginX: box("menu-body-padding"),
4931
+ itemPaddingY: box("item-paddingY"),
4932
+ itemPaddingRight: box("item-paddingRight"),
4933
+ itemGap: box("item-gap"),
4934
+ itemRadius: box("item-radius"),
4935
+ itemArrow: box("item-arrow"),
4936
+ depth1PaddingLeft: box("item-depth1-paddingLeft"),
4937
+ depth2PaddingLeft: box("item-depth2-paddingLeft"),
4938
+ depth3PaddingLeft: box("item-depth3-paddingLeft"),
4939
+ depth1Icon: box("item-depth1-icon"),
4940
+ depth1FontSize: 14,
4941
+ // token: gnbBox.item.typography.bold.fontSize
4942
+ depth1LineHeight: 24,
4943
+ // token: gnbBox.item.typography.bold.lineHeight
4944
+ depth1FontWeight: 700,
4945
+ itemFontSize: 14,
4946
+ // token: gnbBox.item.typography.default.fontSize
4947
+ itemLineHeight: 24
4948
+ // token: gnbBox.item.typography.default.lineHeight
4949
+ },
4950
+ belt: {
4951
+ bodyPaddingY: belt("body-paddingY"),
4952
+ itemMarginX: "0px",
4953
+ // belt 토큰에 가로 여백 없음 → 풀폭 행 (들여쓰기는 depth*-paddingLeft 전담)
4954
+ itemPaddingY: belt("item-paddingY"),
4955
+ itemPaddingRight: belt("item-paddingRight"),
4956
+ itemGap: belt("item-gap"),
4957
+ itemRadius: "0px",
4958
+ // belt 토큰에 radius 없음 → 풀폭 행
4959
+ itemArrow: belt("item-icon"),
4960
+ depth1PaddingLeft: belt("item-depth1-paddingLeft"),
4961
+ depth2PaddingLeft: belt("item-depth2-paddingLeft"),
4962
+ depth3PaddingLeft: belt("item-depth3-paddingLeft"),
4963
+ depth1Icon: box("item-depth1-icon"),
4964
+ // belt 토큰에 depth1-icon 없음 → box 값(20) 공유
4965
+ depth1FontSize: 13,
4966
+ // token: gnbBelt.item.depth1.typography.fontSize
4967
+ depth1LineHeight: 22,
4968
+ // token: gnbBelt.item.depth1.typography.lineHeight
4969
+ depth1FontWeight: 700,
4970
+ itemFontSize: 12,
4971
+ // token: gnbBelt.item.typography.default.fontSize
4972
+ itemLineHeight: 20
4973
+ // token: gnbBelt.item.typography.default.lineHeight
4974
+ }
4975
+ };
4976
+ var GNB_COLORS = {
4977
+ light: {
4978
+ panelBg: light("bg"),
4979
+ topBorder: light("divider"),
4980
+ itemBgDefault: light("item-bg-default"),
4981
+ itemBgHover: light("item-bg-hover"),
4982
+ itemBgSelected: light("item-bg-selected"),
4983
+ itemColorDefault: light("item-fg-default"),
4984
+ itemColorHover: light("item-fg-hover"),
4985
+ itemColorActive: light("item-fg-selected"),
4986
+ itemChevron: light("item-chevron")
4987
+ },
4988
+ dark: {
4989
+ panelBg: dark("bg"),
4990
+ topBorder: dark("divider"),
4991
+ itemBgDefault: dark("item-bg-default"),
4992
+ itemBgHover: dark("item-bg-hover"),
4993
+ itemBgSelected: dark("item-bg-selected"),
4994
+ itemColorDefault: dark("item-fg-default"),
4995
+ itemColorHover: dark("item-fg-hover"),
4996
+ itemColorActive: dark("item-fg-selected"),
4997
+ itemChevron: dark("item-chevron")
4998
+ }
4999
+ };
5000
+ var GNB_COMMON = {
5001
+ /** 접힘 레일 폭. header="full" 은 접으면 메뉴만 사라져 레일이 없으므로 fix 전용. */
5002
+ foldWidth: belt("fold-width"),
5003
+ /**
5004
+ * 상단바 아이콘 버튼 사이 간격. fix 레일(세로 스택)의 gap·상하 여백에 쓴다.
5005
+ * 레일 전용 여백 토큰이 따로 없어 같은 값(8px)인 이 토큰으로 재해석했다.
5006
+ */
5007
+ buttonGap: box("button-gap")
5008
+ };
5009
+ var GNB_MENU_WIDTH = 240;
5010
+ function findGnbAncestors(items, value) {
5011
+ const walk = (list, trail) => {
5012
+ for (const item of list) {
5013
+ if (item.value === value) return trail;
5014
+ if (item.children) {
5015
+ const found = walk(item.children, [...trail, item.value]);
5016
+ if (found) return found;
5017
+ }
5018
+ }
5019
+ return null;
5020
+ };
5021
+ return walk(items, []) ?? [];
5022
+ }
5023
+ var SLayoutContext = react.createContext(null);
5024
+ function useSLayout() {
5025
+ const ctx = react.useContext(SLayoutContext);
5026
+ if (!ctx) throw new Error("useSLayout \uC740 <SLayout> \uC548\uC5D0\uC11C\uB9CC \uC0AC\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.");
5027
+ return ctx;
5028
+ }
5029
+ var SLayout = react.forwardRef(function SLayout2({
5030
+ type = "box",
5031
+ header = "fix",
5032
+ folded,
5033
+ defaultFolded = false,
5034
+ onFoldedChange,
5035
+ className,
5036
+ style,
5037
+ children,
5038
+ ...rest
5039
+ }, ref) {
5040
+ const [uncontrolledFolded, setUncontrolledFolded] = react.useState(defaultFolded);
5041
+ const isControlled = folded !== void 0;
5042
+ const currentFolded = isControlled ? folded : uncontrolledFolded;
5043
+ const setFolded = react.useCallback(
5044
+ (next) => {
5045
+ if (!isControlled) setUncontrolledFolded(next);
5046
+ onFoldedChange?.(next);
5047
+ },
5048
+ [isControlled, onFoldedChange]
5049
+ );
5050
+ const ctx = react.useMemo(
5051
+ () => ({ type, header, folded: currentFolded, setFolded }),
5052
+ [type, header, currentFolded, setFolded]
5053
+ );
5054
+ const isFullHeader = header === "full";
5055
+ const frameStyle = isFullHeader ? {
5056
+ gridTemplateColumns: `${currentFolded ? 0 : GNB_MENU_WIDTH}px 1fr`,
5057
+ gridTemplateRows: `${GNB_HEADER[header].topHeight} 1fr`
5058
+ } : void 0;
5059
+ return /* @__PURE__ */ jsxRuntime.jsx(SLayoutContext.Provider, { value: ctx, children: /* @__PURE__ */ jsxRuntime.jsx(
5060
+ "div",
5061
+ {
5062
+ ref,
5063
+ "data-type": type,
5064
+ "data-header": header,
5065
+ className: cn(
5066
+ "box-border h-full overflow-hidden",
5067
+ isFullHeader ? "grid" : "flex flex-row",
5068
+ className
5069
+ ),
5070
+ style: { ...frameStyle, ...style },
5071
+ ...rest,
5072
+ children
5073
+ }
5074
+ ) });
5075
+ });
5076
+ var DEPTH_PADDING_LEFT = (M, depth) => depth === 1 ? M.depth1PaddingLeft : depth === 2 ? M.depth2PaddingLeft : M.depth3PaddingLeft;
5077
+ var SGnb = react.forwardRef(function SGnb2({
5078
+ type: typeProp,
5079
+ header: headerProp,
5080
+ color = "light",
5081
+ items,
5082
+ value = "",
5083
+ onValueChange,
5084
+ folded: foldedProp,
5085
+ onFoldChange,
5086
+ onLauncherClick,
5087
+ logo,
5088
+ ariaLabel = "global navigation",
5089
+ className,
5090
+ style,
5091
+ ...rest
5092
+ }, ref) {
5093
+ const layout = react.useContext(SLayoutContext);
5094
+ const type = typeProp ?? layout?.type ?? "box";
5095
+ const header = headerProp ?? layout?.header ?? "fix";
5096
+ const folded = foldedProp ?? layout?.folded ?? false;
5097
+ const H = GNB_HEADER[header];
5098
+ const M = GNB_MENU[type];
5099
+ const C = GNB_COLORS[color];
5100
+ const [expandedKeys, setExpandedKeys] = react.useState(
5101
+ () => new Set(findGnbAncestors(items, value))
5102
+ );
5103
+ const [hoveredKey, setHoveredKey] = react.useState(null);
5104
+ react.useEffect(() => {
5105
+ const ancestors = findGnbAncestors(items, value);
5106
+ if (ancestors.length === 0) return;
5107
+ setExpandedKeys((prev) => {
5108
+ if (ancestors.every((a) => prev.has(a))) return prev;
5109
+ const next = new Set(prev);
5110
+ ancestors.forEach((a) => next.add(a));
5111
+ return next;
5112
+ });
5113
+ }, [items, value]);
5114
+ const toggleExpand = (key) => {
5115
+ setExpandedKeys((prev) => {
5116
+ const next = new Set(prev);
5117
+ if (next.has(key)) next.delete(key);
5118
+ else next.add(key);
5119
+ return next;
5120
+ });
5121
+ };
5122
+ const handleItemClick = (item) => {
5123
+ if (item.disabled) return;
5124
+ if (item.children && item.children.length > 0) {
5125
+ toggleExpand(item.value);
5126
+ return;
5127
+ }
5128
+ onValueChange?.(item.value);
5129
+ };
5130
+ const handleFoldToggle = () => {
5131
+ const next = !folded;
5132
+ onFoldChange?.(next);
5133
+ if (foldedProp === void 0) layout?.setFolded(next);
5134
+ };
5135
+ const renderItem = (item, depth) => {
5136
+ const hasChildren = !!(item.children && item.children.length > 0);
5137
+ const isSelected = !hasChildren && item.value === value;
5138
+ const isExpanded = expandedKeys.has(item.value);
5139
+ const isHovered = hoveredKey === item.value && !item.disabled;
5140
+ const itemStyle = {
5141
+ gap: M.itemGap,
5142
+ paddingTop: M.itemPaddingY,
5143
+ paddingBottom: M.itemPaddingY,
5144
+ paddingRight: M.itemPaddingRight,
5145
+ paddingLeft: DEPTH_PADDING_LEFT(M, depth),
5146
+ marginLeft: M.itemMarginX,
5147
+ marginRight: M.itemMarginX,
5148
+ borderRadius: M.itemRadius,
5149
+ backgroundColor: isSelected ? C.itemBgSelected : isHovered ? C.itemBgHover : C.itemBgDefault,
5150
+ color: isSelected ? C.itemColorActive : isHovered ? C.itemColorHover : C.itemColorDefault,
5151
+ // <button> 의 UA 폰트(Arial 13.3px)를 끊고 앱 폰트를 잇는다
5152
+ fontFamily: "inherit",
5153
+ fontSize: depth === 1 ? M.depth1FontSize : M.itemFontSize,
5154
+ lineHeight: `${depth === 1 ? M.depth1LineHeight : M.itemLineHeight}px`,
5155
+ fontWeight: depth === 1 || isSelected ? M.depth1FontWeight : 400,
5156
+ opacity: item.disabled ? 0.4 : 1,
5157
+ cursor: item.disabled ? "not-allowed" : "pointer"
5158
+ };
5159
+ return (
5160
+ // li 를 flex-col 로 둬야 버튼이 좌우 마진만큼 안쪽으로 들어가고,
5161
+ // 하위 ul 은 마진 없이 전폭을 써서 depth*-paddingLeft 가 들여쓰기를 단독으로 책임진다.
5162
+ /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex flex-col", children: [
5163
+ /* @__PURE__ */ jsxRuntime.jsxs(
5164
+ "button",
5165
+ {
5166
+ type: "button",
5167
+ disabled: item.disabled,
5168
+ "aria-expanded": hasChildren ? isExpanded : void 0,
5169
+ "aria-current": isSelected ? "page" : void 0,
5170
+ className: "box-border flex select-none items-center border-none bg-transparent text-left transition-colors duration-150",
5171
+ style: itemStyle,
5172
+ onClick: () => handleItemClick(item),
5173
+ onMouseEnter: () => setHoveredKey(item.value),
5174
+ onMouseLeave: () => setHoveredKey((prev) => prev === item.value ? null : prev),
5175
+ children: [
5176
+ depth === 1 && item.icon && /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: item.icon, size: M.depth1Icon, className: "shrink-0" }),
5177
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 overflow-hidden text-ellipsis whitespace-nowrap", children: item.label }),
5178
+ item.tag !== void 0 && item.tag !== "" && /* @__PURE__ */ jsxRuntime.jsx(
5179
+ STag,
5180
+ {
5181
+ shape: "square",
5182
+ size: "xs",
5183
+ color: item.tagColor ?? "blue",
5184
+ label: item.tag,
5185
+ className: "shrink-0"
5186
+ }
5187
+ ),
5188
+ hasChildren && /* @__PURE__ */ jsxRuntime.jsx(
5189
+ SIcon,
5190
+ {
5191
+ name: "chevronDown",
5192
+ size: M.itemArrow,
5193
+ color: C.itemChevron,
5194
+ rotate: isExpanded ? 180 : 0,
5195
+ className: "shrink-0 transition-transform duration-150"
5196
+ }
5197
+ )
5198
+ ]
5199
+ }
5200
+ ),
5201
+ hasChildren && isExpanded && /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "m-0 flex list-none flex-col p-0", children: item.children.map((child) => renderItem(child, depth + 1)) })
5202
+ ] }, item.value)
5203
+ );
5204
+ };
5205
+ const railFolded = folded && header === "fix";
5206
+ const rootWidth = header === "full" ? "100%" : folded ? GNB_COMMON.foldWidth : GNB_MENU_WIDTH;
5207
+ const rootStyle = {
5208
+ width: rootWidth,
5209
+ ...header === "full" ? { gridArea: "1 / 1 / -1 / -1", pointerEvents: "none" } : { backgroundColor: C.panelBg },
5210
+ ...style
5211
+ };
5212
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5213
+ "div",
5214
+ {
5215
+ ref,
5216
+ className: cn("box-border flex h-full shrink-0 flex-col", className),
5217
+ style: rootStyle,
5218
+ "data-type": type,
5219
+ "data-header": header,
5220
+ "data-color": color,
5221
+ ...rest,
5222
+ children: [
5223
+ /* @__PURE__ */ jsxRuntime.jsxs(
5224
+ "div",
5225
+ {
5226
+ className: cn("box-border flex items-center", railFolded && "flex-col"),
5227
+ style: {
5228
+ gap: railFolded ? GNB_COMMON.buttonGap : H.topGap,
5229
+ height: railFolded ? "auto" : H.topHeight,
5230
+ padding: railFolded ? `${GNB_COMMON.buttonGap} 0` : `0 ${H.topPaddingX}`,
5231
+ borderBottom: `1px solid ${C.topBorder}`,
5232
+ backgroundColor: C.panelBg,
5233
+ pointerEvents: "auto",
5234
+ // 아이콘 버튼은 자체 ghostButton 토큰을 쓰므로, 이 색은 logo 슬롯 상속용
5235
+ color: C.itemColorDefault
5236
+ },
5237
+ children: [
5238
+ onLauncherClick && /* @__PURE__ */ jsxRuntime.jsx(
5239
+ SGhostButton,
5240
+ {
5241
+ icon: "launcher",
5242
+ size: "xs",
5243
+ intent: color === "dark" ? "inverse" : "default",
5244
+ ariaLabel: "app launcher",
5245
+ onClick: onLauncherClick,
5246
+ className: "shrink-0"
5247
+ }
5248
+ ),
5249
+ !railFolded && logo && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center", style: { height: H.logoHeight }, children: logo }),
5250
+ /* @__PURE__ */ jsxRuntime.jsx(
5251
+ SGhostButton,
5252
+ {
5253
+ icon: "sidebar",
5254
+ size: "xs",
5255
+ intent: color === "dark" ? "inverse" : "default",
5256
+ ariaLabel: "toggle navigation",
5257
+ ariaPressed: folded,
5258
+ onClick: handleFoldToggle,
5259
+ className: cn("shrink-0", !railFolded && "ml-auto")
5260
+ }
5261
+ )
5262
+ ]
5263
+ }
5264
+ ),
5265
+ !folded && /* @__PURE__ */ jsxRuntime.jsx(
5266
+ "nav",
5267
+ {
5268
+ "aria-label": ariaLabel,
5269
+ className: "flex flex-col overflow-y-auto",
5270
+ style: {
5271
+ width: GNB_MENU_WIDTH,
5272
+ alignSelf: "flex-start",
5273
+ flexGrow: 1,
5274
+ flexShrink: 1,
5275
+ flexBasis: "auto",
5276
+ minHeight: 0,
5277
+ paddingTop: M.bodyPaddingY,
5278
+ paddingBottom: M.bodyPaddingY,
5279
+ backgroundColor: C.panelBg,
5280
+ pointerEvents: "auto"
5281
+ },
5282
+ children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "m-0 flex list-none flex-col p-0", children: items.map((item) => renderItem(item, 1)) })
5283
+ }
5284
+ )
5285
+ ]
5286
+ }
5287
+ );
5288
+ });
5289
+ var SPage = react.forwardRef(function SPage2({ className, style, children, ...rest }, ref) {
5290
+ const layout = react.useContext(SLayoutContext);
5291
+ const gridStyle = layout?.header === "full" ? { gridColumn: 2, gridRow: 2 } : void 0;
5292
+ return /* @__PURE__ */ jsxRuntime.jsx(
5293
+ "main",
5294
+ {
5295
+ ref,
5296
+ className: cn("box-border min-h-0 min-w-0 flex-1 overflow-auto p-24", className),
5297
+ style: { ...gridStyle, ...style },
5298
+ ...rest,
5299
+ children
5300
+ }
5301
+ );
5302
+ });
5303
+
4896
5304
  // src/components/STabs/tabs.config.ts
4897
5305
  var TAB_MAIN_SIZE = {
4898
5306
  md: { height: 36, paddingX: 24 },
@@ -5729,7 +6137,7 @@ var SSelect = react.forwardRef(function SSelect2({
5729
6137
  event.preventDefault();
5730
6138
  triggerRef.current?.focus();
5731
6139
  },
5732
- className: "rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] py-[4px] shadow-[2px_2px_12px_2px_rgba(0,0,0,0.1)]",
6140
+ className: "rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] shadow-[2px_2px_12px_2px_rgba(0,0,0,0.1)]",
5733
6141
  style: {
5734
6142
  ...dropdownWidth ? { width: dropdownWidth } : {},
5735
6143
  maxWidth: maxDropdownWidth
@@ -5780,6 +6188,10 @@ var SSelect = react.forwardRef(function SSelect2({
5780
6188
  onSelectAll: handleSelectAll,
5781
6189
  onSelect: handleSelect,
5782
6190
  onHoverValue: (value2) => {
6191
+ if (value2 == null) {
6192
+ setFocusedIndex(-1);
6193
+ return;
6194
+ }
5783
6195
  const index = navigableItems.findIndex(
5784
6196
  (item) => item.isSelectAll ? value2 === "__select_all__" : item.value === value2
5785
6197
  );
@@ -5828,6 +6240,7 @@ function ItemList({
5828
6240
  ),
5829
6241
  style: { paddingTop: 4, paddingBottom: 4, paddingRight: 12, paddingLeft: 12 },
5830
6242
  onMouseEnter: () => onHoverValue("__select_all__"),
6243
+ onMouseLeave: () => onHoverValue(null),
5831
6244
  onClick: onSelectAll,
5832
6245
  children: [
5833
6246
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -5886,10 +6299,13 @@ function ItemList({
5886
6299
  itemBase,
5887
6300
  isSelected && !multi && "font-bold text-[color:var(--cmp-listItem-content-selected)]",
5888
6301
  focusedValue === o.value && "bg-[var(--cmp-listItem-bg-hover)] text-[color:var(--cmp-listItem-content-hover)]",
5889
- activeClass
6302
+ // 비활성 항목은 hover/focus 스타일 대상에서 제외한다.
6303
+ // (:hover 는 disabled 버튼에도 매칭되므로 클래스 자체를 붙이지 않아야 한다)
6304
+ !o.disabled && activeClass
5890
6305
  ),
5891
6306
  style: { paddingTop: 4, paddingBottom: 4, paddingRight: 12, paddingLeft: padLeft },
5892
6307
  onMouseEnter: () => onHoverValue(o.value),
6308
+ onMouseLeave: () => onHoverValue(null),
5893
6309
  onClick: () => onSelect(o.value),
5894
6310
  children: [
5895
6311
  multi && /* @__PURE__ */ jsxRuntime.jsx(
@@ -6410,10 +6826,10 @@ var STable = react.forwardRef(function STable2({
6410
6826
  "div",
6411
6827
  {
6412
6828
  "aria-hidden": true,
6413
- className: "pointer-events-none absolute left-0 right-0 top-0 z-[210] h-[var(--cmp-table-header-height)] bg-white/60"
6829
+ className: "pointer-events-none absolute left-0 right-0 top-0 z-[31] h-[var(--cmp-table-header-height)] bg-white/60"
6414
6830
  }
6415
6831
  ),
6416
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-none absolute bottom-0 left-0 right-0 top-[var(--cmp-table-header-height)] z-[200] flex items-center justify-center bg-white/60 text-[12px] text-[color:var(--color-grey-65)]", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-[60px] w-full items-center justify-center", children: noDataLabel }) })
6832
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-none absolute bottom-0 left-0 right-0 top-[var(--cmp-table-header-height)] z-[30] flex items-center justify-center bg-white/60 text-[12px] text-[color:var(--color-grey-65)]", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-[60px] w-full items-center justify-center", children: noDataLabel }) })
6417
6833
  ] }),
6418
6834
  isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 z-30 flex items-center justify-center bg-white/60", children: /* @__PURE__ */ jsxRuntime.jsx(SCircleProgress, { indeterminate: true }) })
6419
6835
  ]
@@ -9168,11 +9584,20 @@ var SChipInput = react.forwardRef(function SChipInput2({
9168
9584
  style: { width: 1, height: 12, backgroundColor: "#E1E1E1" }
9169
9585
  }
9170
9586
  ),
9171
- showMaxCount && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "s-chip-input__max-count text-12 text-(--cmp-chipInput-text-placeholder)", children: [
9172
- "\uCD5C\uB300 ",
9173
- maxCount,
9174
- "\uAC1C"
9175
- ] }),
9587
+ showMaxCount && /* @__PURE__ */ jsxRuntime.jsxs(
9588
+ "span",
9589
+ {
9590
+ className: cn(
9591
+ "s-chip-input__max-count text-12",
9592
+ isMax ? "text-(--sys-color-fg-warning)" : "text-(--cmp-chipInput-text-placeholder)"
9593
+ ),
9594
+ children: [
9595
+ "\uCD5C\uB300 ",
9596
+ maxCount,
9597
+ "\uAC1C"
9598
+ ]
9599
+ }
9600
+ ),
9176
9601
  showResetLink && /* @__PURE__ */ jsxRuntime.jsx(
9177
9602
  STextLink,
9178
9603
  {
@@ -9209,7 +9634,7 @@ var SChipInput = react.forwardRef(function SChipInput2({
9209
9634
  onMouseDown: (e) => e.preventDefault(),
9210
9635
  children: [
9211
9636
  loading2 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "s-chip-input__suggestions-empty p-12 text-center text-12 leading-20 text-(--color-grey-65)", children: "\uBD88\uB7EC\uC624\uB294 \uC911..." }),
9212
- !effectiveAutocomplete ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-8 p-12", children: items.map((item, i) => {
9637
+ !effectiveAutocomplete ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-8 px-12 py-6", children: items.map((item, i) => {
9213
9638
  const selected = values.includes(item);
9214
9639
  const active = i === activeIndex && !selected;
9215
9640
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -9413,6 +9838,11 @@ exports.BADGE_COLORS = BADGE_COLORS;
9413
9838
  exports.BUTTON_COLORS = BUTTON_COLORS;
9414
9839
  exports.BUTTON_SIZES = BUTTON_SIZES;
9415
9840
  exports.COLOR_KEYS = COLOR_KEYS;
9841
+ exports.GNB_COLORS = GNB_COLORS;
9842
+ exports.GNB_COMMON = GNB_COMMON;
9843
+ exports.GNB_HEADER = GNB_HEADER;
9844
+ exports.GNB_MENU = GNB_MENU;
9845
+ exports.GNB_MENU_WIDTH = GNB_MENU_WIDTH;
9416
9846
  exports.ICONS = ICONS;
9417
9847
  exports.SActionModal = SActionModal;
9418
9848
  exports.SBadge = SBadge;
@@ -9434,15 +9864,19 @@ exports.SField = SField;
9434
9864
  exports.SFilePicker = SFilePicker;
9435
9865
  exports.SForm = SForm;
9436
9866
  exports.SGhostButton = SGhostButton;
9867
+ exports.SGnb = SGnb;
9437
9868
  exports.SGuide = SGuide;
9438
9869
  exports.SIcon = SIcon;
9439
9870
  exports.SInput = SInput;
9440
9871
  exports.SKeyValueTable = SKeyValueTable;
9872
+ exports.SLayout = SLayout;
9873
+ exports.SLayoutContext = SLayoutContext;
9441
9874
  exports.SLinearProgress = SLinearProgress;
9442
9875
  exports.SLoadingContainer = SLoadingContainer;
9443
9876
  exports.SLoadingModal = SLoadingModal;
9444
9877
  exports.SLoadingViewport = SLoadingViewport;
9445
9878
  exports.SNumberInput = SNumberInput;
9879
+ exports.SPage = SPage;
9446
9880
  exports.SPagination = SPagination;
9447
9881
  exports.SPopover = SPopover;
9448
9882
  exports.SPopup = SPopup;
@@ -9466,8 +9900,10 @@ exports.TAG_SHAPES = TAG_SHAPES;
9466
9900
  exports.TAG_SIZES = TAG_SIZES;
9467
9901
  exports.buttonPreset = buttonPreset;
9468
9902
  exports.cn = cn;
9903
+ exports.findGnbAncestors = findGnbAncestors;
9469
9904
  exports.isColorKey = isColorKey;
9470
9905
  exports.loading = loading;
9471
9906
  exports.resolveColor = resolveColor;
9907
+ exports.useSLayout = useSLayout;
9472
9908
  //# sourceMappingURL=index.cjs.map
9473
9909
  //# sourceMappingURL=index.cjs.map