sellmate-design-system-react 0.1.11 → 0.2.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 +7 -3
  2. package/dist/components/SActionModal/SActionModal.cjs.map +1 -1
  3. package/dist/components/SActionModal/SActionModal.js +7 -3
  4. package/dist/components/SActionModal/SActionModal.js.map +1 -1
  5. package/dist/components/SBarcodeInput/SBarcodeInput.cjs +7 -3
  6. package/dist/components/SBarcodeInput/SBarcodeInput.cjs.map +1 -1
  7. package/dist/components/SBarcodeInput/SBarcodeInput.js +7 -3
  8. package/dist/components/SBarcodeInput/SBarcodeInput.js.map +1 -1
  9. package/dist/components/SCalendar/SCalendar.cjs +7 -3
  10. package/dist/components/SCalendar/SCalendar.cjs.map +1 -1
  11. package/dist/components/SCalendar/SCalendar.js +7 -3
  12. package/dist/components/SCalendar/SCalendar.js.map +1 -1
  13. package/dist/components/SChip/SChip.cjs +7 -3
  14. package/dist/components/SChip/SChip.cjs.map +1 -1
  15. package/dist/components/SChip/SChip.js +7 -3
  16. package/dist/components/SChip/SChip.js.map +1 -1
  17. package/dist/components/SChipInput/SChipInput.cjs +23 -10
  18. package/dist/components/SChipInput/SChipInput.cjs.map +1 -1
  19. package/dist/components/SChipInput/SChipInput.js +23 -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 +7 -3
  26. package/dist/components/SConfirmModal/SConfirmModal.cjs.map +1 -1
  27. package/dist/components/SConfirmModal/SConfirmModal.js +7 -3
  28. package/dist/components/SConfirmModal/SConfirmModal.js.map +1 -1
  29. package/dist/components/SDatePicker/SDatePicker.cjs +7 -3
  30. package/dist/components/SDatePicker/SDatePicker.cjs.map +1 -1
  31. package/dist/components/SDatePicker/SDatePicker.js +7 -3
  32. package/dist/components/SDatePicker/SDatePicker.js.map +1 -1
  33. package/dist/components/SDateRangePicker/SDateRangePicker.cjs +7 -3
  34. package/dist/components/SDateRangePicker/SDateRangePicker.cjs.map +1 -1
  35. package/dist/components/SDateRangePicker/SDateRangePicker.js +7 -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 +7 -3
  42. package/dist/components/SField/SField.cjs.map +1 -1
  43. package/dist/components/SField/SField.js +7 -3
  44. package/dist/components/SField/SField.js.map +1 -1
  45. package/dist/components/SFilePicker/SFilePicker.cjs +7 -3
  46. package/dist/components/SFilePicker/SFilePicker.cjs.map +1 -1
  47. package/dist/components/SFilePicker/SFilePicker.js +7 -3
  48. package/dist/components/SFilePicker/SFilePicker.js.map +1 -1
  49. package/dist/components/SGhostButton/SGhostButton.cjs +7 -3
  50. package/dist/components/SGhostButton/SGhostButton.cjs.map +1 -1
  51. package/dist/components/SGhostButton/SGhostButton.d.ts +5 -1
  52. package/dist/components/SGhostButton/SGhostButton.js +7 -3
  53. package/dist/components/SGhostButton/SGhostButton.js.map +1 -1
  54. package/dist/components/SGnb/SGnb.cjs +3297 -0
  55. package/dist/components/SGnb/SGnb.cjs.map +1 -0
  56. package/dist/components/SGnb/SGnb.d.ts +35 -0
  57. package/dist/components/SGnb/SGnb.js +3295 -0
  58. package/dist/components/SGnb/SGnb.js.map +1 -0
  59. package/dist/components/SGnb/gnb.config.d.ts +63 -0
  60. package/dist/components/SGnb/index.d.ts +2 -0
  61. package/dist/components/SGuide/SGuide.cjs +7 -3
  62. package/dist/components/SGuide/SGuide.cjs.map +1 -1
  63. package/dist/components/SGuide/SGuide.js +7 -3
  64. package/dist/components/SGuide/SGuide.js.map +1 -1
  65. package/dist/components/SInput/SInput.cjs +7 -3
  66. package/dist/components/SInput/SInput.cjs.map +1 -1
  67. package/dist/components/SInput/SInput.js +7 -3
  68. package/dist/components/SInput/SInput.js.map +1 -1
  69. package/dist/components/SKeyValueTable/SKeyValueTable.cjs +18 -6
  70. package/dist/components/SKeyValueTable/SKeyValueTable.cjs.map +1 -1
  71. package/dist/components/SKeyValueTable/SKeyValueTable.js +18 -6
  72. package/dist/components/SKeyValueTable/SKeyValueTable.js.map +1 -1
  73. package/dist/components/SLayout/SLayout.cjs +79 -0
  74. package/dist/components/SLayout/SLayout.cjs.map +1 -0
  75. package/dist/components/SLayout/SLayout.d.ts +41 -0
  76. package/dist/components/SLayout/SLayout.js +75 -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 +13 -5
  88. package/dist/components/SLoadingModal/SLoadingModal.cjs.map +1 -1
  89. package/dist/components/SLoadingModal/SLoadingModal.js +13 -5
  90. package/dist/components/SLoadingModal/SLoadingModal.js.map +1 -1
  91. package/dist/components/SModalContainer/SModalContainer.cjs +7 -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 +7 -3
  95. package/dist/components/SModalContainer/SModalContainer.js.map +1 -1
  96. package/dist/components/SNumberInput/SNumberInput.cjs +7 -3
  97. package/dist/components/SNumberInput/SNumberInput.cjs.map +1 -1
  98. package/dist/components/SNumberInput/SNumberInput.js +7 -3
  99. package/dist/components/SNumberInput/SNumberInput.js.map +1 -1
  100. package/dist/components/SPage/SPage.cjs +86 -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 +84 -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 +7 -3
  107. package/dist/components/SPopover/SPopover.cjs.map +1 -1
  108. package/dist/components/SPopover/SPopover.js +7 -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 +18 -6
  115. package/dist/components/SSelect/SSelect.cjs.map +1 -1
  116. package/dist/components/SSelect/SSelect.js +18 -6
  117. package/dist/components/SSelect/SSelect.js.map +1 -1
  118. package/dist/components/STable/STable.cjs +26 -10
  119. package/dist/components/STable/STable.cjs.map +1 -1
  120. package/dist/components/STable/STable.js +26 -10
  121. package/dist/components/STable/STable.js.map +1 -1
  122. package/dist/components/STextarea/STextarea.cjs +7 -3
  123. package/dist/components/STextarea/STextarea.cjs.map +1 -1
  124. package/dist/components/STextarea/STextarea.js +7 -3
  125. package/dist/components/STextarea/STextarea.js.map +1 -1
  126. package/dist/components/SToast/SToast.cjs +7 -3
  127. package/dist/components/SToast/SToast.cjs.map +1 -1
  128. package/dist/components/SToast/SToast.js +7 -3
  129. package/dist/components/SToast/SToast.js.map +1 -1
  130. package/dist/components/SToast/SToastContainer.cjs +7 -3
  131. package/dist/components/SToast/SToastContainer.cjs.map +1 -1
  132. package/dist/components/SToast/SToastContainer.js +7 -3
  133. package/dist/components/SToast/SToastContainer.js.map +1 -1
  134. package/dist/components/STooltip/STooltip.cjs +7 -3
  135. package/dist/components/STooltip/STooltip.cjs.map +1 -1
  136. package/dist/components/STooltip/STooltip.js +7 -3
  137. package/dist/components/STooltip/STooltip.js.map +1 -1
  138. package/dist/index.cjs +430 -17
  139. package/dist/index.cjs.map +1 -1
  140. package/dist/index.d.ts +3 -0
  141. package/dist/index.js +422 -19
  142. package/dist/index.js.map +1 -1
  143. package/dist/styles.css +192 -26
  144. package/dist/theme.css +66 -13
  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
  }
@@ -3942,6 +3946,8 @@ function SGhostButton({
3942
3946
  tooltipText,
3943
3947
  disabled = false,
3944
3948
  onClick,
3949
+ anchorClassName,
3950
+ anchorStyle,
3945
3951
  className,
3946
3952
  style
3947
3953
  }) {
@@ -3964,6 +3970,8 @@ function SGhostButton({
3964
3970
  };
3965
3971
  const s = SIZE2[size];
3966
3972
  const contentColor = disabled ? intent === "inverse" ? "var(--cmp-ghostButton-inverse-disabled)" : "var(--cmp-ghostButton-icon-disabled)" : `var(--cmp-ghostButton-${intent}-content)`;
3973
+ const text = (tooltipText ?? "").trim();
3974
+ const hasTooltip = text !== "";
3967
3975
  const btn = /* @__PURE__ */ jsxRuntime.jsxs(
3968
3976
  "button",
3969
3977
  {
@@ -4004,13 +4012,13 @@ function SGhostButton({
4004
4012
  ]
4005
4013
  }
4006
4014
  );
4007
- const text = (tooltipText ?? "").trim();
4008
- if (text === "") return btn;
4015
+ if (!hasTooltip) return btn;
4009
4016
  return /* @__PURE__ */ jsxRuntime.jsxs(RPopover2__namespace.Root, { open, onOpenChange: setOpen, children: [
4010
4017
  /* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Anchor, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
4011
4018
  "span",
4012
4019
  {
4013
- className: "inline-flex",
4020
+ className: cn("inline-flex", anchorClassName),
4021
+ style: anchorStyle,
4014
4022
  onMouseEnter: openNow,
4015
4023
  onMouseLeave: startHide,
4016
4024
  onFocus: openNow,
@@ -4411,7 +4419,7 @@ function SPortal({
4411
4419
  onCloseAutoFocus,
4412
4420
  onClick: autoClose ? () => onClose?.() : void 0,
4413
4421
  className: cn(
4414
- "z-50 overflow-hidden rounded-(--cmp-listBox-radius) bg-(--cmp-listBox-bg) py-4 shadow-normal-sm",
4422
+ "z-50 overflow-hidden rounded-(--cmp-listBox-radius) bg-(--cmp-listBox-bg) shadow-normal-sm",
4415
4423
  maxHeight != null && "overflow-y-auto",
4416
4424
  fit && "min-w-(--radix-popover-trigger-width)",
4417
4425
  FLOATING_SLIDE_ANIM,
@@ -4893,6 +4901,384 @@ function SLoadingModal({
4893
4901
  );
4894
4902
  }
4895
4903
 
4904
+ // src/components/SGnb/gnb.config.ts
4905
+ var belt = (p) => `var(--cmp-gnbBelt-${p})`;
4906
+ var box = (p) => `var(--cmp-gnbBox-${p})`;
4907
+ var light = (p) => `var(--cmp-light-${p})`;
4908
+ var dark = (p) => `var(--cmp-dark-${p})`;
4909
+ var GNB_LAYOUT = {
4910
+ // 사용자 명명: type="box" → gnbBox 토큰(둥금), type="belt" → gnbBelt 토큰(각짐)
4911
+ box: {
4912
+ topPaddingX: box("paddingX"),
4913
+ topGap: box("gap"),
4914
+ // 상단바 gap (버튼 간 세부 gap 은 --cmp-gnbBox-button-gap)
4915
+ bodyPadding: box("menu-body-padding"),
4916
+ itemPaddingRight: box("item-paddingRight"),
4917
+ itemGap: box("item-gap"),
4918
+ itemRadius: box("item-radius"),
4919
+ itemArrow: box("item-arrow"),
4920
+ depth1PaddingLeft: box("item-depth1-paddingLeft"),
4921
+ depth2PaddingLeft: box("item-depth2-paddingLeft"),
4922
+ depth3PaddingLeft: box("item-depth3-paddingLeft"),
4923
+ depth1Icon: box("item-depth1-icon"),
4924
+ depth1FontSize: 14,
4925
+ // token: gnbBox.item.typography.bold.fontSize
4926
+ depth1LineHeight: 24,
4927
+ // token: gnbBox.item.typography.bold.lineHeight
4928
+ depth1FontWeight: 700,
4929
+ itemFontSize: 14,
4930
+ // token: gnbBox.item.typography.default.fontSize
4931
+ itemLineHeight: 24
4932
+ // token: gnbBox.item.typography.default.lineHeight
4933
+ },
4934
+ belt: {
4935
+ topPaddingX: belt("top-paddingX"),
4936
+ topGap: belt("top-gap"),
4937
+ bodyPadding: belt("body-paddingY"),
4938
+ itemPaddingRight: belt("item-paddingRight"),
4939
+ itemGap: belt("item-gap"),
4940
+ itemRadius: "0px",
4941
+ // belt 토큰에 radius 없음 → 풀폭 행
4942
+ itemArrow: belt("item-icon"),
4943
+ depth1PaddingLeft: belt("item-depth1-paddingLeft"),
4944
+ depth2PaddingLeft: belt("item-depth2-paddingLeft"),
4945
+ depth3PaddingLeft: belt("item-depth3-paddingLeft"),
4946
+ depth1Icon: box("item-depth1-icon"),
4947
+ // belt 토큰에 depth1-icon 없음 → box 값(20) 공유
4948
+ depth1FontSize: 13,
4949
+ // token: gnbBelt.item.depth1.typography.fontSize
4950
+ depth1LineHeight: 22,
4951
+ // token: gnbBelt.item.depth1.typography.lineHeight
4952
+ depth1FontWeight: 700,
4953
+ itemFontSize: 12,
4954
+ // token: gnbBelt.item.typography.default.fontSize
4955
+ itemLineHeight: 20
4956
+ // token: gnbBelt.item.typography.default.lineHeight
4957
+ }
4958
+ };
4959
+ var GNB_COLORS = {
4960
+ light: {
4961
+ panelBg: light("bg"),
4962
+ topBorder: light("divider"),
4963
+ itemBgDefault: light("item-bg-default"),
4964
+ itemBgHover: light("item-bg-hover"),
4965
+ itemBgSelected: light("item-bg-selected"),
4966
+ itemColorDefault: light("item-fg-default"),
4967
+ itemColorActive: light("item-fg-selected")
4968
+ },
4969
+ dark: {
4970
+ panelBg: dark("bg"),
4971
+ topBorder: dark("divider"),
4972
+ itemBgDefault: dark("item-bg-default"),
4973
+ itemBgHover: dark("item-bg-hover"),
4974
+ itemBgSelected: dark("item-bg-selected"),
4975
+ itemColorDefault: dark("item-fg-default"),
4976
+ itemColorActive: dark("item-fg-selected")
4977
+ }
4978
+ };
4979
+ var GNB_COMMON = {
4980
+ topHeight: box("top-height"),
4981
+ // 56 (box=belt 동일)
4982
+ logoHeight: box("logo-height"),
4983
+ // 32
4984
+ itemPaddingY: box("item-paddingY"),
4985
+ // 6
4986
+ foldWidth: belt("fold-width")
4987
+ // 48 (belt 토큰 공유)
4988
+ };
4989
+ var GNB_MENU_WIDTH = 240;
4990
+ function findGnbAncestors(items, value) {
4991
+ const walk = (list, trail) => {
4992
+ for (const item of list) {
4993
+ if (item.value === value) return trail;
4994
+ if (item.children) {
4995
+ const found = walk(item.children, [...trail, item.value]);
4996
+ if (found) return found;
4997
+ }
4998
+ }
4999
+ return null;
5000
+ };
5001
+ return walk(items, []) ?? [];
5002
+ }
5003
+ var SLayoutContext = react.createContext(null);
5004
+ function useSLayout() {
5005
+ const ctx = react.useContext(SLayoutContext);
5006
+ if (!ctx) throw new Error("useSLayout \uC740 <SLayout> \uC548\uC5D0\uC11C\uB9CC \uC0AC\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.");
5007
+ return ctx;
5008
+ }
5009
+ var SLayout = react.forwardRef(function SLayout2({
5010
+ type = "box",
5011
+ folded,
5012
+ defaultFolded = false,
5013
+ onFoldedChange,
5014
+ className,
5015
+ style,
5016
+ children,
5017
+ ...rest
5018
+ }, ref) {
5019
+ const [uncontrolledFolded, setUncontrolledFolded] = react.useState(defaultFolded);
5020
+ const isControlled = folded !== void 0;
5021
+ const currentFolded = isControlled ? folded : uncontrolledFolded;
5022
+ const setFolded = react.useCallback(
5023
+ (next) => {
5024
+ if (!isControlled) setUncontrolledFolded(next);
5025
+ onFoldedChange?.(next);
5026
+ },
5027
+ [isControlled, onFoldedChange]
5028
+ );
5029
+ const ctx = react.useMemo(
5030
+ () => ({ type, folded: currentFolded, setFolded }),
5031
+ [type, currentFolded, setFolded]
5032
+ );
5033
+ const isBox = type === "box";
5034
+ const frameStyle = isBox ? {
5035
+ gridTemplateColumns: `${currentFolded ? 0 : GNB_MENU_WIDTH}px 1fr`,
5036
+ gridTemplateRows: `${GNB_COMMON.topHeight} 1fr`
5037
+ } : void 0;
5038
+ return /* @__PURE__ */ jsxRuntime.jsx(SLayoutContext.Provider, { value: ctx, children: /* @__PURE__ */ jsxRuntime.jsx(
5039
+ "div",
5040
+ {
5041
+ ref,
5042
+ "data-type": type,
5043
+ className: cn(
5044
+ "box-border h-full overflow-hidden",
5045
+ isBox ? "grid" : "flex flex-row",
5046
+ className
5047
+ ),
5048
+ style: { ...frameStyle, ...style },
5049
+ ...rest,
5050
+ children
5051
+ }
5052
+ ) });
5053
+ });
5054
+ var DEPTH_PADDING_LEFT = (L, depth) => depth === 1 ? L.depth1PaddingLeft : depth === 2 ? L.depth2PaddingLeft : L.depth3PaddingLeft;
5055
+ var SGnb = react.forwardRef(function SGnb2({
5056
+ type: typeProp,
5057
+ color = "light",
5058
+ items,
5059
+ value = "",
5060
+ onValueChange,
5061
+ folded: foldedProp,
5062
+ onFoldChange,
5063
+ onLauncherClick,
5064
+ logo,
5065
+ search,
5066
+ className,
5067
+ style
5068
+ }, ref) {
5069
+ const layout = react.useContext(SLayoutContext);
5070
+ const type = typeProp ?? layout?.type ?? "box";
5071
+ const folded = foldedProp ?? layout?.folded ?? false;
5072
+ const L = GNB_LAYOUT[type];
5073
+ const C = GNB_COLORS[color];
5074
+ const [expandedKeys, setExpandedKeys] = react.useState(
5075
+ () => new Set(findGnbAncestors(items, value))
5076
+ );
5077
+ const [hoveredKey, setHoveredKey] = react.useState(null);
5078
+ react.useEffect(() => {
5079
+ const ancestors = findGnbAncestors(items, value);
5080
+ if (ancestors.length === 0) return;
5081
+ setExpandedKeys((prev) => {
5082
+ const next = new Set(prev);
5083
+ ancestors.forEach((a) => next.add(a));
5084
+ return next;
5085
+ });
5086
+ }, [items, value]);
5087
+ const toggleExpand = (key) => {
5088
+ setExpandedKeys((prev) => {
5089
+ const next = new Set(prev);
5090
+ if (next.has(key)) next.delete(key);
5091
+ else next.add(key);
5092
+ return next;
5093
+ });
5094
+ };
5095
+ const handleItemClick = (item) => {
5096
+ if (item.disabled) return;
5097
+ if (item.children && item.children.length > 0) {
5098
+ toggleExpand(item.value);
5099
+ return;
5100
+ }
5101
+ onValueChange?.(item.value);
5102
+ };
5103
+ const handleFoldToggle = () => {
5104
+ const next = !folded;
5105
+ onFoldChange?.(next);
5106
+ layout?.setFolded(next);
5107
+ };
5108
+ const iconBtnClass = "inline-flex shrink-0 cursor-pointer items-center justify-center rounded-md border-0 bg-transparent p-1.5";
5109
+ const renderItem = (item, depth) => {
5110
+ const hasChildren = !!(item.children && item.children.length > 0);
5111
+ const isSelected = !hasChildren && item.value === value;
5112
+ const isExpanded = expandedKeys.has(item.value);
5113
+ const isHovered = hoveredKey === item.value;
5114
+ const bg = isSelected ? C.itemBgSelected : isHovered && !item.disabled ? C.itemBgHover : C.itemBgDefault;
5115
+ const itemStyle = {
5116
+ gap: L.itemGap,
5117
+ paddingTop: GNB_COMMON.itemPaddingY,
5118
+ paddingBottom: GNB_COMMON.itemPaddingY,
5119
+ paddingRight: L.itemPaddingRight,
5120
+ paddingLeft: DEPTH_PADDING_LEFT(L, depth),
5121
+ marginLeft: L.bodyPadding,
5122
+ marginRight: L.bodyPadding,
5123
+ borderRadius: L.itemRadius,
5124
+ backgroundColor: bg,
5125
+ color: isSelected ? C.itemColorActive : C.itemColorDefault,
5126
+ fontSize: depth === 1 ? L.depth1FontSize : L.itemFontSize,
5127
+ lineHeight: `${depth === 1 ? L.depth1LineHeight : L.itemLineHeight}px`,
5128
+ fontWeight: depth === 1 || isSelected ? L.depth1FontWeight : 400,
5129
+ opacity: item.disabled ? 0.4 : 1,
5130
+ cursor: item.disabled ? "not-allowed" : "pointer"
5131
+ };
5132
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
5133
+ /* @__PURE__ */ jsxRuntime.jsxs(
5134
+ "div",
5135
+ {
5136
+ role: hasChildren ? "button" : "menuitem",
5137
+ tabIndex: item.disabled ? -1 : 0,
5138
+ "aria-disabled": item.disabled || void 0,
5139
+ "aria-expanded": hasChildren ? isExpanded : void 0,
5140
+ "aria-current": isSelected ? "page" : void 0,
5141
+ className: "box-border flex select-none items-center transition-colors duration-150",
5142
+ style: itemStyle,
5143
+ onClick: () => handleItemClick(item),
5144
+ onMouseEnter: () => setHoveredKey(item.value),
5145
+ onMouseLeave: () => setHoveredKey((prev) => prev === item.value ? null : prev),
5146
+ onKeyDown: (e) => {
5147
+ if (e.key === "Enter" || e.key === " ") {
5148
+ e.preventDefault();
5149
+ handleItemClick(item);
5150
+ }
5151
+ },
5152
+ children: [
5153
+ depth === 1 && item.icon && /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: item.icon, size: L.depth1Icon, className: "shrink-0" }),
5154
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 overflow-hidden text-ellipsis whitespace-nowrap", children: item.label }),
5155
+ item.tag !== void 0 && item.tag !== "" && /* @__PURE__ */ jsxRuntime.jsx(
5156
+ STag,
5157
+ {
5158
+ shape: "square",
5159
+ size: "xs",
5160
+ color: isSelected ? "blue" : "grey",
5161
+ label: item.tag,
5162
+ className: "shrink-0"
5163
+ }
5164
+ ),
5165
+ hasChildren && /* @__PURE__ */ jsxRuntime.jsx(
5166
+ SIcon,
5167
+ {
5168
+ name: "chevronDown",
5169
+ size: L.itemArrow,
5170
+ rotate: isExpanded ? 180 : 0,
5171
+ className: "shrink-0 transition-transform duration-150"
5172
+ }
5173
+ )
5174
+ ]
5175
+ }
5176
+ ),
5177
+ hasChildren && isExpanded && item.children.map((child) => renderItem(child, depth + 1))
5178
+ ] }, item.value);
5179
+ };
5180
+ const railFolded = folded && type === "belt";
5181
+ const rootWidth = type === "box" ? "100%" : folded ? GNB_COMMON.foldWidth : GNB_MENU_WIDTH;
5182
+ const inBoxGrid = !!layout && type === "box";
5183
+ const rootStyle = react.useMemo(
5184
+ () => ({
5185
+ width: rootWidth,
5186
+ ...inBoxGrid ? { gridArea: "1 / 1 / -1 / -1" } : null,
5187
+ ...style
5188
+ }),
5189
+ [rootWidth, inBoxGrid, style]
5190
+ );
5191
+ const iconColor = C.itemColorDefault;
5192
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5193
+ "div",
5194
+ {
5195
+ ref,
5196
+ className: cn(
5197
+ "box-border flex flex-col",
5198
+ type === "box" && !inBoxGrid ? "h-auto" : "h-full",
5199
+ className
5200
+ ),
5201
+ style: rootStyle,
5202
+ "data-type": type,
5203
+ "data-color": color,
5204
+ children: [
5205
+ /* @__PURE__ */ jsxRuntime.jsxs(
5206
+ "div",
5207
+ {
5208
+ className: cn("box-border flex items-center", railFolded && "flex-col"),
5209
+ style: {
5210
+ gap: railFolded ? 8 : L.topGap,
5211
+ height: railFolded ? "auto" : GNB_COMMON.topHeight,
5212
+ padding: railFolded ? "8px 0" : `0 ${L.topPaddingX}`,
5213
+ borderBottom: `1px solid ${C.topBorder}`,
5214
+ backgroundColor: C.panelBg,
5215
+ color: iconColor
5216
+ },
5217
+ children: [
5218
+ /* @__PURE__ */ jsxRuntime.jsx(
5219
+ "button",
5220
+ {
5221
+ type: "button",
5222
+ "aria-label": "app launcher",
5223
+ className: iconBtnClass,
5224
+ onClick: onLauncherClick,
5225
+ children: /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "launcher", size: 20 })
5226
+ }
5227
+ ),
5228
+ !railFolded && logo && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center", style: { height: GNB_COMMON.logoHeight }, children: logo }),
5229
+ !railFolded && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children: search }),
5230
+ /* @__PURE__ */ jsxRuntime.jsx(
5231
+ "button",
5232
+ {
5233
+ type: "button",
5234
+ "aria-label": "toggle navigation",
5235
+ "aria-pressed": folded,
5236
+ className: cn(iconBtnClass, !railFolded && "ml-auto"),
5237
+ onClick: handleFoldToggle,
5238
+ children: /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "sidebar", size: 20 })
5239
+ }
5240
+ )
5241
+ ]
5242
+ }
5243
+ ),
5244
+ !folded && /* @__PURE__ */ jsxRuntime.jsx(
5245
+ "div",
5246
+ {
5247
+ role: "menu",
5248
+ className: "flex flex-col overflow-y-auto",
5249
+ style: {
5250
+ width: GNB_MENU_WIDTH,
5251
+ alignSelf: "flex-start",
5252
+ flexGrow: 1,
5253
+ flexShrink: 1,
5254
+ flexBasis: "auto",
5255
+ minHeight: 0,
5256
+ paddingTop: L.bodyPadding,
5257
+ paddingBottom: L.bodyPadding,
5258
+ backgroundColor: C.panelBg
5259
+ },
5260
+ children: items.map((item) => renderItem(item, 1))
5261
+ }
5262
+ )
5263
+ ]
5264
+ }
5265
+ );
5266
+ });
5267
+ var SPage = react.forwardRef(function SPage2({ className, style, children, ...rest }, ref) {
5268
+ const layout = react.useContext(SLayoutContext);
5269
+ const gridStyle = layout?.type === "box" ? { gridColumn: 2, gridRow: 2 } : void 0;
5270
+ return /* @__PURE__ */ jsxRuntime.jsx(
5271
+ "main",
5272
+ {
5273
+ ref,
5274
+ className: cn("box-border min-h-0 min-w-0 flex-1 overflow-auto p-24", className),
5275
+ style: { ...gridStyle, ...style },
5276
+ ...rest,
5277
+ children
5278
+ }
5279
+ );
5280
+ });
5281
+
4896
5282
  // src/components/STabs/tabs.config.ts
4897
5283
  var TAB_MAIN_SIZE = {
4898
5284
  md: { height: 36, paddingX: 24 },
@@ -5729,7 +6115,7 @@ var SSelect = react.forwardRef(function SSelect2({
5729
6115
  event.preventDefault();
5730
6116
  triggerRef.current?.focus();
5731
6117
  },
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)]",
6118
+ className: "rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] shadow-[2px_2px_12px_2px_rgba(0,0,0,0.1)]",
5733
6119
  style: {
5734
6120
  ...dropdownWidth ? { width: dropdownWidth } : {},
5735
6121
  maxWidth: maxDropdownWidth
@@ -5780,6 +6166,10 @@ var SSelect = react.forwardRef(function SSelect2({
5780
6166
  onSelectAll: handleSelectAll,
5781
6167
  onSelect: handleSelect,
5782
6168
  onHoverValue: (value2) => {
6169
+ if (value2 == null) {
6170
+ setFocusedIndex(-1);
6171
+ return;
6172
+ }
5783
6173
  const index = navigableItems.findIndex(
5784
6174
  (item) => item.isSelectAll ? value2 === "__select_all__" : item.value === value2
5785
6175
  );
@@ -5828,6 +6218,7 @@ function ItemList({
5828
6218
  ),
5829
6219
  style: { paddingTop: 4, paddingBottom: 4, paddingRight: 12, paddingLeft: 12 },
5830
6220
  onMouseEnter: () => onHoverValue("__select_all__"),
6221
+ onMouseLeave: () => onHoverValue(null),
5831
6222
  onClick: onSelectAll,
5832
6223
  children: [
5833
6224
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -5886,10 +6277,13 @@ function ItemList({
5886
6277
  itemBase,
5887
6278
  isSelected && !multi && "font-bold text-[color:var(--cmp-listItem-content-selected)]",
5888
6279
  focusedValue === o.value && "bg-[var(--cmp-listItem-bg-hover)] text-[color:var(--cmp-listItem-content-hover)]",
5889
- activeClass
6280
+ // 비활성 항목은 hover/focus 스타일 대상에서 제외한다.
6281
+ // (:hover 는 disabled 버튼에도 매칭되므로 클래스 자체를 붙이지 않아야 한다)
6282
+ !o.disabled && activeClass
5890
6283
  ),
5891
6284
  style: { paddingTop: 4, paddingBottom: 4, paddingRight: 12, paddingLeft: padLeft },
5892
6285
  onMouseEnter: () => onHoverValue(o.value),
6286
+ onMouseLeave: () => onHoverValue(null),
5893
6287
  onClick: () => onSelect(o.value),
5894
6288
  children: [
5895
6289
  multi && /* @__PURE__ */ jsxRuntime.jsx(
@@ -6410,10 +6804,10 @@ var STable = react.forwardRef(function STable2({
6410
6804
  "div",
6411
6805
  {
6412
6806
  "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"
6807
+ className: "pointer-events-none absolute left-0 right-0 top-0 z-[31] h-[var(--cmp-table-header-height)] bg-white/60"
6414
6808
  }
6415
6809
  ),
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 }) })
6810
+ /* @__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
6811
  ] }),
6418
6812
  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
6813
  ]
@@ -9168,11 +9562,20 @@ var SChipInput = react.forwardRef(function SChipInput2({
9168
9562
  style: { width: 1, height: 12, backgroundColor: "#E1E1E1" }
9169
9563
  }
9170
9564
  ),
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
- ] }),
9565
+ showMaxCount && /* @__PURE__ */ jsxRuntime.jsxs(
9566
+ "span",
9567
+ {
9568
+ className: cn(
9569
+ "s-chip-input__max-count text-12",
9570
+ isMax ? "text-(--sys-color-fg-warning)" : "text-(--cmp-chipInput-text-placeholder)"
9571
+ ),
9572
+ children: [
9573
+ "\uCD5C\uB300 ",
9574
+ maxCount,
9575
+ "\uAC1C"
9576
+ ]
9577
+ }
9578
+ ),
9176
9579
  showResetLink && /* @__PURE__ */ jsxRuntime.jsx(
9177
9580
  STextLink,
9178
9581
  {
@@ -9209,7 +9612,7 @@ var SChipInput = react.forwardRef(function SChipInput2({
9209
9612
  onMouseDown: (e) => e.preventDefault(),
9210
9613
  children: [
9211
9614
  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) => {
9615
+ !effectiveAutocomplete ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-8 px-12 py-6", children: items.map((item, i) => {
9213
9616
  const selected = values.includes(item);
9214
9617
  const active = i === activeIndex && !selected;
9215
9618
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -9413,6 +9816,10 @@ exports.BADGE_COLORS = BADGE_COLORS;
9413
9816
  exports.BUTTON_COLORS = BUTTON_COLORS;
9414
9817
  exports.BUTTON_SIZES = BUTTON_SIZES;
9415
9818
  exports.COLOR_KEYS = COLOR_KEYS;
9819
+ exports.GNB_COLORS = GNB_COLORS;
9820
+ exports.GNB_COMMON = GNB_COMMON;
9821
+ exports.GNB_LAYOUT = GNB_LAYOUT;
9822
+ exports.GNB_MENU_WIDTH = GNB_MENU_WIDTH;
9416
9823
  exports.ICONS = ICONS;
9417
9824
  exports.SActionModal = SActionModal;
9418
9825
  exports.SBadge = SBadge;
@@ -9434,15 +9841,19 @@ exports.SField = SField;
9434
9841
  exports.SFilePicker = SFilePicker;
9435
9842
  exports.SForm = SForm;
9436
9843
  exports.SGhostButton = SGhostButton;
9844
+ exports.SGnb = SGnb;
9437
9845
  exports.SGuide = SGuide;
9438
9846
  exports.SIcon = SIcon;
9439
9847
  exports.SInput = SInput;
9440
9848
  exports.SKeyValueTable = SKeyValueTable;
9849
+ exports.SLayout = SLayout;
9850
+ exports.SLayoutContext = SLayoutContext;
9441
9851
  exports.SLinearProgress = SLinearProgress;
9442
9852
  exports.SLoadingContainer = SLoadingContainer;
9443
9853
  exports.SLoadingModal = SLoadingModal;
9444
9854
  exports.SLoadingViewport = SLoadingViewport;
9445
9855
  exports.SNumberInput = SNumberInput;
9856
+ exports.SPage = SPage;
9446
9857
  exports.SPagination = SPagination;
9447
9858
  exports.SPopover = SPopover;
9448
9859
  exports.SPopup = SPopup;
@@ -9466,8 +9877,10 @@ exports.TAG_SHAPES = TAG_SHAPES;
9466
9877
  exports.TAG_SIZES = TAG_SIZES;
9467
9878
  exports.buttonPreset = buttonPreset;
9468
9879
  exports.cn = cn;
9880
+ exports.findGnbAncestors = findGnbAncestors;
9469
9881
  exports.isColorKey = isColorKey;
9470
9882
  exports.loading = loading;
9471
9883
  exports.resolveColor = resolveColor;
9884
+ exports.useSLayout = useSLayout;
9472
9885
  //# sourceMappingURL=index.cjs.map
9473
9886
  //# sourceMappingURL=index.cjs.map