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.d.ts CHANGED
@@ -23,6 +23,9 @@ export * from './components/SGuide';
23
23
  export * from './components/SConfirmModal';
24
24
  export * from './components/SActionModal';
25
25
  export * from './components/SLoadingModal';
26
+ export * from './components/SGnb';
27
+ export * from './components/SLayout';
28
+ export * from './components/SPage';
26
29
  export * from './components/STabs';
27
30
  export * from './components/SPagination';
28
31
  export * from './components/STable';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { clsx } from 'clsx';
2
2
  import { extendTailwindMerge } from 'tailwind-merge';
3
- import { forwardRef, useState, useEffect, useRef, useCallback, createContext, useImperativeHandle, useMemo, useId, useLayoutEffect, useContext, useSyncExternalStore, Fragment as Fragment$1 } from 'react';
3
+ import { forwardRef, useState, useEffect, useRef, useCallback, createContext, useImperativeHandle, useMemo, useContext, useId, useLayoutEffect, useSyncExternalStore, Fragment as Fragment$1 } from 'react';
4
4
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
5
  import { createPortal } from 'react-dom';
6
6
  import { createRoot } from 'react-dom/client';
@@ -3319,8 +3319,12 @@ var SCircleProgress = forwardRef(
3319
3319
  "span",
3320
3320
  {
3321
3321
  className: cn(
3322
- "text-center text-[16px] font-bold leading-[26px]",
3323
- innerValue && "absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2"
3322
+ "text-center text-[16px] font-bold",
3323
+ innerValue ? (
3324
+ // leading-[normal]: 26px leading 은 폰트 content(19px) 위아래로 홀수(7px)만큼 남아
3325
+ // 3px/4px 로 쪼개지고 글자가 링 중심보다 위로 뜬다. (leading-normal 은 1.5 라 동일 문제)
3326
+ "absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 leading-[normal]"
3327
+ ) : "leading-[26px]"
3324
3328
  ),
3325
3329
  style: { color: percentColor },
3326
3330
  children: [
@@ -3886,7 +3890,7 @@ var SDropdownButton = forwardRef(
3886
3890
  ...style
3887
3891
  },
3888
3892
  children: [
3889
- /* @__PURE__ */ jsx("span", { className: "truncate", children: label }),
3893
+ /* @__PURE__ */ jsx("span", { className: "flex-1 truncate text-center", children: label }),
3890
3894
  caret
3891
3895
  ]
3892
3896
  }
@@ -3914,6 +3918,8 @@ function SGhostButton({
3914
3918
  tooltipText,
3915
3919
  disabled = false,
3916
3920
  onClick,
3921
+ anchorClassName,
3922
+ anchorStyle,
3917
3923
  className,
3918
3924
  style
3919
3925
  }) {
@@ -3936,6 +3942,8 @@ function SGhostButton({
3936
3942
  };
3937
3943
  const s = SIZE2[size];
3938
3944
  const contentColor = disabled ? intent === "inverse" ? "var(--cmp-ghostButton-inverse-disabled)" : "var(--cmp-ghostButton-icon-disabled)" : `var(--cmp-ghostButton-${intent}-content)`;
3945
+ const text = (tooltipText ?? "").trim();
3946
+ const hasTooltip = text !== "";
3939
3947
  const btn = /* @__PURE__ */ jsxs(
3940
3948
  "button",
3941
3949
  {
@@ -3976,13 +3984,13 @@ function SGhostButton({
3976
3984
  ]
3977
3985
  }
3978
3986
  );
3979
- const text = (tooltipText ?? "").trim();
3980
- if (text === "") return btn;
3987
+ if (!hasTooltip) return btn;
3981
3988
  return /* @__PURE__ */ jsxs(RPopover2.Root, { open, onOpenChange: setOpen, children: [
3982
3989
  /* @__PURE__ */ jsx(RPopover2.Anchor, { asChild: true, children: /* @__PURE__ */ jsx(
3983
3990
  "span",
3984
3991
  {
3985
- className: "inline-flex",
3992
+ className: cn("inline-flex", anchorClassName),
3993
+ style: anchorStyle,
3986
3994
  onMouseEnter: openNow,
3987
3995
  onMouseLeave: startHide,
3988
3996
  onFocus: openNow,
@@ -4383,7 +4391,7 @@ function SPortal({
4383
4391
  onCloseAutoFocus,
4384
4392
  onClick: autoClose ? () => onClose?.() : void 0,
4385
4393
  className: cn(
4386
- "z-50 overflow-hidden rounded-(--cmp-listBox-radius) bg-(--cmp-listBox-bg) py-4 shadow-normal-sm",
4394
+ "z-50 overflow-hidden rounded-(--cmp-listBox-radius) bg-(--cmp-listBox-bg) shadow-normal-sm",
4387
4395
  maxHeight != null && "overflow-y-auto",
4388
4396
  fit && "min-w-(--radix-popover-trigger-width)",
4389
4397
  FLOATING_SLIDE_ANIM,
@@ -4865,6 +4873,384 @@ function SLoadingModal({
4865
4873
  );
4866
4874
  }
4867
4875
 
4876
+ // src/components/SGnb/gnb.config.ts
4877
+ var belt = (p) => `var(--cmp-gnbBelt-${p})`;
4878
+ var box = (p) => `var(--cmp-gnbBox-${p})`;
4879
+ var light = (p) => `var(--cmp-light-${p})`;
4880
+ var dark = (p) => `var(--cmp-dark-${p})`;
4881
+ var GNB_LAYOUT = {
4882
+ // 사용자 명명: type="box" → gnbBox 토큰(둥금), type="belt" → gnbBelt 토큰(각짐)
4883
+ box: {
4884
+ topPaddingX: box("paddingX"),
4885
+ topGap: box("gap"),
4886
+ // 상단바 gap (버튼 간 세부 gap 은 --cmp-gnbBox-button-gap)
4887
+ bodyPadding: box("menu-body-padding"),
4888
+ itemPaddingRight: box("item-paddingRight"),
4889
+ itemGap: box("item-gap"),
4890
+ itemRadius: box("item-radius"),
4891
+ itemArrow: box("item-arrow"),
4892
+ depth1PaddingLeft: box("item-depth1-paddingLeft"),
4893
+ depth2PaddingLeft: box("item-depth2-paddingLeft"),
4894
+ depth3PaddingLeft: box("item-depth3-paddingLeft"),
4895
+ depth1Icon: box("item-depth1-icon"),
4896
+ depth1FontSize: 14,
4897
+ // token: gnbBox.item.typography.bold.fontSize
4898
+ depth1LineHeight: 24,
4899
+ // token: gnbBox.item.typography.bold.lineHeight
4900
+ depth1FontWeight: 700,
4901
+ itemFontSize: 14,
4902
+ // token: gnbBox.item.typography.default.fontSize
4903
+ itemLineHeight: 24
4904
+ // token: gnbBox.item.typography.default.lineHeight
4905
+ },
4906
+ belt: {
4907
+ topPaddingX: belt("top-paddingX"),
4908
+ topGap: belt("top-gap"),
4909
+ bodyPadding: belt("body-paddingY"),
4910
+ itemPaddingRight: belt("item-paddingRight"),
4911
+ itemGap: belt("item-gap"),
4912
+ itemRadius: "0px",
4913
+ // belt 토큰에 radius 없음 → 풀폭 행
4914
+ itemArrow: belt("item-icon"),
4915
+ depth1PaddingLeft: belt("item-depth1-paddingLeft"),
4916
+ depth2PaddingLeft: belt("item-depth2-paddingLeft"),
4917
+ depth3PaddingLeft: belt("item-depth3-paddingLeft"),
4918
+ depth1Icon: box("item-depth1-icon"),
4919
+ // belt 토큰에 depth1-icon 없음 → box 값(20) 공유
4920
+ depth1FontSize: 13,
4921
+ // token: gnbBelt.item.depth1.typography.fontSize
4922
+ depth1LineHeight: 22,
4923
+ // token: gnbBelt.item.depth1.typography.lineHeight
4924
+ depth1FontWeight: 700,
4925
+ itemFontSize: 12,
4926
+ // token: gnbBelt.item.typography.default.fontSize
4927
+ itemLineHeight: 20
4928
+ // token: gnbBelt.item.typography.default.lineHeight
4929
+ }
4930
+ };
4931
+ var GNB_COLORS = {
4932
+ light: {
4933
+ panelBg: light("bg"),
4934
+ topBorder: light("divider"),
4935
+ itemBgDefault: light("item-bg-default"),
4936
+ itemBgHover: light("item-bg-hover"),
4937
+ itemBgSelected: light("item-bg-selected"),
4938
+ itemColorDefault: light("item-fg-default"),
4939
+ itemColorActive: light("item-fg-selected")
4940
+ },
4941
+ dark: {
4942
+ panelBg: dark("bg"),
4943
+ topBorder: dark("divider"),
4944
+ itemBgDefault: dark("item-bg-default"),
4945
+ itemBgHover: dark("item-bg-hover"),
4946
+ itemBgSelected: dark("item-bg-selected"),
4947
+ itemColorDefault: dark("item-fg-default"),
4948
+ itemColorActive: dark("item-fg-selected")
4949
+ }
4950
+ };
4951
+ var GNB_COMMON = {
4952
+ topHeight: box("top-height"),
4953
+ // 56 (box=belt 동일)
4954
+ logoHeight: box("logo-height"),
4955
+ // 32
4956
+ itemPaddingY: box("item-paddingY"),
4957
+ // 6
4958
+ foldWidth: belt("fold-width")
4959
+ // 48 (belt 토큰 공유)
4960
+ };
4961
+ var GNB_MENU_WIDTH = 240;
4962
+ function findGnbAncestors(items, value) {
4963
+ const walk = (list, trail) => {
4964
+ for (const item of list) {
4965
+ if (item.value === value) return trail;
4966
+ if (item.children) {
4967
+ const found = walk(item.children, [...trail, item.value]);
4968
+ if (found) return found;
4969
+ }
4970
+ }
4971
+ return null;
4972
+ };
4973
+ return walk(items, []) ?? [];
4974
+ }
4975
+ var SLayoutContext = createContext(null);
4976
+ function useSLayout() {
4977
+ const ctx = useContext(SLayoutContext);
4978
+ if (!ctx) throw new Error("useSLayout \uC740 <SLayout> \uC548\uC5D0\uC11C\uB9CC \uC0AC\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.");
4979
+ return ctx;
4980
+ }
4981
+ var SLayout = forwardRef(function SLayout2({
4982
+ type = "box",
4983
+ folded,
4984
+ defaultFolded = false,
4985
+ onFoldedChange,
4986
+ className,
4987
+ style,
4988
+ children,
4989
+ ...rest
4990
+ }, ref) {
4991
+ const [uncontrolledFolded, setUncontrolledFolded] = useState(defaultFolded);
4992
+ const isControlled = folded !== void 0;
4993
+ const currentFolded = isControlled ? folded : uncontrolledFolded;
4994
+ const setFolded = useCallback(
4995
+ (next) => {
4996
+ if (!isControlled) setUncontrolledFolded(next);
4997
+ onFoldedChange?.(next);
4998
+ },
4999
+ [isControlled, onFoldedChange]
5000
+ );
5001
+ const ctx = useMemo(
5002
+ () => ({ type, folded: currentFolded, setFolded }),
5003
+ [type, currentFolded, setFolded]
5004
+ );
5005
+ const isBox = type === "box";
5006
+ const frameStyle = isBox ? {
5007
+ gridTemplateColumns: `${currentFolded ? 0 : GNB_MENU_WIDTH}px 1fr`,
5008
+ gridTemplateRows: `${GNB_COMMON.topHeight} 1fr`
5009
+ } : void 0;
5010
+ return /* @__PURE__ */ jsx(SLayoutContext.Provider, { value: ctx, children: /* @__PURE__ */ jsx(
5011
+ "div",
5012
+ {
5013
+ ref,
5014
+ "data-type": type,
5015
+ className: cn(
5016
+ "box-border h-full overflow-hidden",
5017
+ isBox ? "grid" : "flex flex-row",
5018
+ className
5019
+ ),
5020
+ style: { ...frameStyle, ...style },
5021
+ ...rest,
5022
+ children
5023
+ }
5024
+ ) });
5025
+ });
5026
+ var DEPTH_PADDING_LEFT = (L, depth) => depth === 1 ? L.depth1PaddingLeft : depth === 2 ? L.depth2PaddingLeft : L.depth3PaddingLeft;
5027
+ var SGnb = forwardRef(function SGnb2({
5028
+ type: typeProp,
5029
+ color = "light",
5030
+ items,
5031
+ value = "",
5032
+ onValueChange,
5033
+ folded: foldedProp,
5034
+ onFoldChange,
5035
+ onLauncherClick,
5036
+ logo,
5037
+ search,
5038
+ className,
5039
+ style
5040
+ }, ref) {
5041
+ const layout = useContext(SLayoutContext);
5042
+ const type = typeProp ?? layout?.type ?? "box";
5043
+ const folded = foldedProp ?? layout?.folded ?? false;
5044
+ const L = GNB_LAYOUT[type];
5045
+ const C = GNB_COLORS[color];
5046
+ const [expandedKeys, setExpandedKeys] = useState(
5047
+ () => new Set(findGnbAncestors(items, value))
5048
+ );
5049
+ const [hoveredKey, setHoveredKey] = useState(null);
5050
+ useEffect(() => {
5051
+ const ancestors = findGnbAncestors(items, value);
5052
+ if (ancestors.length === 0) return;
5053
+ setExpandedKeys((prev) => {
5054
+ const next = new Set(prev);
5055
+ ancestors.forEach((a) => next.add(a));
5056
+ return next;
5057
+ });
5058
+ }, [items, value]);
5059
+ const toggleExpand = (key) => {
5060
+ setExpandedKeys((prev) => {
5061
+ const next = new Set(prev);
5062
+ if (next.has(key)) next.delete(key);
5063
+ else next.add(key);
5064
+ return next;
5065
+ });
5066
+ };
5067
+ const handleItemClick = (item) => {
5068
+ if (item.disabled) return;
5069
+ if (item.children && item.children.length > 0) {
5070
+ toggleExpand(item.value);
5071
+ return;
5072
+ }
5073
+ onValueChange?.(item.value);
5074
+ };
5075
+ const handleFoldToggle = () => {
5076
+ const next = !folded;
5077
+ onFoldChange?.(next);
5078
+ layout?.setFolded(next);
5079
+ };
5080
+ const iconBtnClass = "inline-flex shrink-0 cursor-pointer items-center justify-center rounded-md border-0 bg-transparent p-1.5";
5081
+ const renderItem = (item, depth) => {
5082
+ const hasChildren = !!(item.children && item.children.length > 0);
5083
+ const isSelected = !hasChildren && item.value === value;
5084
+ const isExpanded = expandedKeys.has(item.value);
5085
+ const isHovered = hoveredKey === item.value;
5086
+ const bg = isSelected ? C.itemBgSelected : isHovered && !item.disabled ? C.itemBgHover : C.itemBgDefault;
5087
+ const itemStyle = {
5088
+ gap: L.itemGap,
5089
+ paddingTop: GNB_COMMON.itemPaddingY,
5090
+ paddingBottom: GNB_COMMON.itemPaddingY,
5091
+ paddingRight: L.itemPaddingRight,
5092
+ paddingLeft: DEPTH_PADDING_LEFT(L, depth),
5093
+ marginLeft: L.bodyPadding,
5094
+ marginRight: L.bodyPadding,
5095
+ borderRadius: L.itemRadius,
5096
+ backgroundColor: bg,
5097
+ color: isSelected ? C.itemColorActive : C.itemColorDefault,
5098
+ fontSize: depth === 1 ? L.depth1FontSize : L.itemFontSize,
5099
+ lineHeight: `${depth === 1 ? L.depth1LineHeight : L.itemLineHeight}px`,
5100
+ fontWeight: depth === 1 || isSelected ? L.depth1FontWeight : 400,
5101
+ opacity: item.disabled ? 0.4 : 1,
5102
+ cursor: item.disabled ? "not-allowed" : "pointer"
5103
+ };
5104
+ return /* @__PURE__ */ jsxs("div", { children: [
5105
+ /* @__PURE__ */ jsxs(
5106
+ "div",
5107
+ {
5108
+ role: hasChildren ? "button" : "menuitem",
5109
+ tabIndex: item.disabled ? -1 : 0,
5110
+ "aria-disabled": item.disabled || void 0,
5111
+ "aria-expanded": hasChildren ? isExpanded : void 0,
5112
+ "aria-current": isSelected ? "page" : void 0,
5113
+ className: "box-border flex select-none items-center transition-colors duration-150",
5114
+ style: itemStyle,
5115
+ onClick: () => handleItemClick(item),
5116
+ onMouseEnter: () => setHoveredKey(item.value),
5117
+ onMouseLeave: () => setHoveredKey((prev) => prev === item.value ? null : prev),
5118
+ onKeyDown: (e) => {
5119
+ if (e.key === "Enter" || e.key === " ") {
5120
+ e.preventDefault();
5121
+ handleItemClick(item);
5122
+ }
5123
+ },
5124
+ children: [
5125
+ depth === 1 && item.icon && /* @__PURE__ */ jsx(SIcon, { name: item.icon, size: L.depth1Icon, className: "shrink-0" }),
5126
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 overflow-hidden text-ellipsis whitespace-nowrap", children: item.label }),
5127
+ item.tag !== void 0 && item.tag !== "" && /* @__PURE__ */ jsx(
5128
+ STag,
5129
+ {
5130
+ shape: "square",
5131
+ size: "xs",
5132
+ color: isSelected ? "blue" : "grey",
5133
+ label: item.tag,
5134
+ className: "shrink-0"
5135
+ }
5136
+ ),
5137
+ hasChildren && /* @__PURE__ */ jsx(
5138
+ SIcon,
5139
+ {
5140
+ name: "chevronDown",
5141
+ size: L.itemArrow,
5142
+ rotate: isExpanded ? 180 : 0,
5143
+ className: "shrink-0 transition-transform duration-150"
5144
+ }
5145
+ )
5146
+ ]
5147
+ }
5148
+ ),
5149
+ hasChildren && isExpanded && item.children.map((child) => renderItem(child, depth + 1))
5150
+ ] }, item.value);
5151
+ };
5152
+ const railFolded = folded && type === "belt";
5153
+ const rootWidth = type === "box" ? "100%" : folded ? GNB_COMMON.foldWidth : GNB_MENU_WIDTH;
5154
+ const inBoxGrid = !!layout && type === "box";
5155
+ const rootStyle = useMemo(
5156
+ () => ({
5157
+ width: rootWidth,
5158
+ ...inBoxGrid ? { gridArea: "1 / 1 / -1 / -1" } : null,
5159
+ ...style
5160
+ }),
5161
+ [rootWidth, inBoxGrid, style]
5162
+ );
5163
+ const iconColor = C.itemColorDefault;
5164
+ return /* @__PURE__ */ jsxs(
5165
+ "div",
5166
+ {
5167
+ ref,
5168
+ className: cn(
5169
+ "box-border flex flex-col",
5170
+ type === "box" && !inBoxGrid ? "h-auto" : "h-full",
5171
+ className
5172
+ ),
5173
+ style: rootStyle,
5174
+ "data-type": type,
5175
+ "data-color": color,
5176
+ children: [
5177
+ /* @__PURE__ */ jsxs(
5178
+ "div",
5179
+ {
5180
+ className: cn("box-border flex items-center", railFolded && "flex-col"),
5181
+ style: {
5182
+ gap: railFolded ? 8 : L.topGap,
5183
+ height: railFolded ? "auto" : GNB_COMMON.topHeight,
5184
+ padding: railFolded ? "8px 0" : `0 ${L.topPaddingX}`,
5185
+ borderBottom: `1px solid ${C.topBorder}`,
5186
+ backgroundColor: C.panelBg,
5187
+ color: iconColor
5188
+ },
5189
+ children: [
5190
+ /* @__PURE__ */ jsx(
5191
+ "button",
5192
+ {
5193
+ type: "button",
5194
+ "aria-label": "app launcher",
5195
+ className: iconBtnClass,
5196
+ onClick: onLauncherClick,
5197
+ children: /* @__PURE__ */ jsx(SIcon, { name: "launcher", size: 20 })
5198
+ }
5199
+ ),
5200
+ !railFolded && logo && /* @__PURE__ */ jsx("div", { className: "flex items-center", style: { height: GNB_COMMON.logoHeight }, children: logo }),
5201
+ !railFolded && /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: search }),
5202
+ /* @__PURE__ */ jsx(
5203
+ "button",
5204
+ {
5205
+ type: "button",
5206
+ "aria-label": "toggle navigation",
5207
+ "aria-pressed": folded,
5208
+ className: cn(iconBtnClass, !railFolded && "ml-auto"),
5209
+ onClick: handleFoldToggle,
5210
+ children: /* @__PURE__ */ jsx(SIcon, { name: "sidebar", size: 20 })
5211
+ }
5212
+ )
5213
+ ]
5214
+ }
5215
+ ),
5216
+ !folded && /* @__PURE__ */ jsx(
5217
+ "div",
5218
+ {
5219
+ role: "menu",
5220
+ className: "flex flex-col overflow-y-auto",
5221
+ style: {
5222
+ width: GNB_MENU_WIDTH,
5223
+ alignSelf: "flex-start",
5224
+ flexGrow: 1,
5225
+ flexShrink: 1,
5226
+ flexBasis: "auto",
5227
+ minHeight: 0,
5228
+ paddingTop: L.bodyPadding,
5229
+ paddingBottom: L.bodyPadding,
5230
+ backgroundColor: C.panelBg
5231
+ },
5232
+ children: items.map((item) => renderItem(item, 1))
5233
+ }
5234
+ )
5235
+ ]
5236
+ }
5237
+ );
5238
+ });
5239
+ var SPage = forwardRef(function SPage2({ className, style, children, ...rest }, ref) {
5240
+ const layout = useContext(SLayoutContext);
5241
+ const gridStyle = layout?.type === "box" ? { gridColumn: 2, gridRow: 2 } : void 0;
5242
+ return /* @__PURE__ */ jsx(
5243
+ "main",
5244
+ {
5245
+ ref,
5246
+ className: cn("box-border min-h-0 min-w-0 flex-1 overflow-auto p-24", className),
5247
+ style: { ...gridStyle, ...style },
5248
+ ...rest,
5249
+ children
5250
+ }
5251
+ );
5252
+ });
5253
+
4868
5254
  // src/components/STabs/tabs.config.ts
4869
5255
  var TAB_MAIN_SIZE = {
4870
5256
  md: { height: 36, paddingX: 24 },
@@ -5701,7 +6087,7 @@ var SSelect = forwardRef(function SSelect2({
5701
6087
  event.preventDefault();
5702
6088
  triggerRef.current?.focus();
5703
6089
  },
5704
- className: "rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] py-[4px] shadow-[2px_2px_12px_2px_rgba(0,0,0,0.1)]",
6090
+ className: "rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] shadow-[2px_2px_12px_2px_rgba(0,0,0,0.1)]",
5705
6091
  style: {
5706
6092
  ...dropdownWidth ? { width: dropdownWidth } : {},
5707
6093
  maxWidth: maxDropdownWidth
@@ -5752,6 +6138,10 @@ var SSelect = forwardRef(function SSelect2({
5752
6138
  onSelectAll: handleSelectAll,
5753
6139
  onSelect: handleSelect,
5754
6140
  onHoverValue: (value2) => {
6141
+ if (value2 == null) {
6142
+ setFocusedIndex(-1);
6143
+ return;
6144
+ }
5755
6145
  const index = navigableItems.findIndex(
5756
6146
  (item) => item.isSelectAll ? value2 === "__select_all__" : item.value === value2
5757
6147
  );
@@ -5800,6 +6190,7 @@ function ItemList({
5800
6190
  ),
5801
6191
  style: { paddingTop: 4, paddingBottom: 4, paddingRight: 12, paddingLeft: 12 },
5802
6192
  onMouseEnter: () => onHoverValue("__select_all__"),
6193
+ onMouseLeave: () => onHoverValue(null),
5803
6194
  onClick: onSelectAll,
5804
6195
  children: [
5805
6196
  /* @__PURE__ */ jsx(
@@ -5858,10 +6249,13 @@ function ItemList({
5858
6249
  itemBase,
5859
6250
  isSelected && !multi && "font-bold text-[color:var(--cmp-listItem-content-selected)]",
5860
6251
  focusedValue === o.value && "bg-[var(--cmp-listItem-bg-hover)] text-[color:var(--cmp-listItem-content-hover)]",
5861
- activeClass
6252
+ // 비활성 항목은 hover/focus 스타일 대상에서 제외한다.
6253
+ // (:hover 는 disabled 버튼에도 매칭되므로 클래스 자체를 붙이지 않아야 한다)
6254
+ !o.disabled && activeClass
5862
6255
  ),
5863
6256
  style: { paddingTop: 4, paddingBottom: 4, paddingRight: 12, paddingLeft: padLeft },
5864
6257
  onMouseEnter: () => onHoverValue(o.value),
6258
+ onMouseLeave: () => onHoverValue(null),
5865
6259
  onClick: () => onSelect(o.value),
5866
6260
  children: [
5867
6261
  multi && /* @__PURE__ */ jsx(
@@ -6382,10 +6776,10 @@ var STable = forwardRef(function STable2({
6382
6776
  "div",
6383
6777
  {
6384
6778
  "aria-hidden": true,
6385
- className: "pointer-events-none absolute left-0 right-0 top-0 z-[210] h-[var(--cmp-table-header-height)] bg-white/60"
6779
+ className: "pointer-events-none absolute left-0 right-0 top-0 z-[31] h-[var(--cmp-table-header-height)] bg-white/60"
6386
6780
  }
6387
6781
  ),
6388
- /* @__PURE__ */ 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__ */ jsx("div", { className: "flex min-h-[60px] w-full items-center justify-center", children: noDataLabel }) })
6782
+ /* @__PURE__ */ 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__ */ jsx("div", { className: "flex min-h-[60px] w-full items-center justify-center", children: noDataLabel }) })
6389
6783
  ] }),
6390
6784
  isLoading && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 z-30 flex items-center justify-center bg-white/60", children: /* @__PURE__ */ jsx(SCircleProgress, { indeterminate: true }) })
6391
6785
  ]
@@ -9140,11 +9534,20 @@ var SChipInput = forwardRef(function SChipInput2({
9140
9534
  style: { width: 1, height: 12, backgroundColor: "#E1E1E1" }
9141
9535
  }
9142
9536
  ),
9143
- showMaxCount && /* @__PURE__ */ jsxs("span", { className: "s-chip-input__max-count text-12 text-(--cmp-chipInput-text-placeholder)", children: [
9144
- "\uCD5C\uB300 ",
9145
- maxCount,
9146
- "\uAC1C"
9147
- ] }),
9537
+ showMaxCount && /* @__PURE__ */ jsxs(
9538
+ "span",
9539
+ {
9540
+ className: cn(
9541
+ "s-chip-input__max-count text-12",
9542
+ isMax ? "text-(--sys-color-fg-warning)" : "text-(--cmp-chipInput-text-placeholder)"
9543
+ ),
9544
+ children: [
9545
+ "\uCD5C\uB300 ",
9546
+ maxCount,
9547
+ "\uAC1C"
9548
+ ]
9549
+ }
9550
+ ),
9148
9551
  showResetLink && /* @__PURE__ */ jsx(
9149
9552
  STextLink,
9150
9553
  {
@@ -9181,7 +9584,7 @@ var SChipInput = forwardRef(function SChipInput2({
9181
9584
  onMouseDown: (e) => e.preventDefault(),
9182
9585
  children: [
9183
9586
  loading2 && /* @__PURE__ */ 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..." }),
9184
- !effectiveAutocomplete ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-8 p-12", children: items.map((item, i) => {
9587
+ !effectiveAutocomplete ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-8 px-12 py-6", children: items.map((item, i) => {
9185
9588
  const selected = values.includes(item);
9186
9589
  const active = i === activeIndex && !selected;
9187
9590
  return /* @__PURE__ */ jsx(
@@ -9381,6 +9784,6 @@ var SBarcodeInput = forwardRef(
9381
9784
  }
9382
9785
  );
9383
9786
 
9384
- export { BADGE_COLORS, BUTTON_COLORS, BUTTON_SIZES, COLOR_KEYS, ICONS, SActionModal, SBadge, SBarcodeInput, SButton, SCalendar, SCallout, SCard, SCheckbox, SChip, SChipInput, SCircleProgress, SConfirmModal, SDatePicker, SDateRangePicker, SDivider, SDropdownButton, SField, SFilePicker, SForm, SGhostButton, SGuide, SIcon, SInput, SKeyValueTable, SLinearProgress, SLoadingContainer, SLoadingModal, SLoadingViewport, SNumberInput, SPagination, SPopover, SPopup, SPortal, SRadio, SRadioButton, SRadioGroup, SSelect, SSwitch, STable, STabs, STag, STextLink, STextarea, SToast, SToastContainer, SToggle, STooltip, TAG_COLORS, TAG_SHAPES, TAG_SIZES, buttonPreset, cn, isColorKey, loading, resolveColor };
9787
+ export { BADGE_COLORS, BUTTON_COLORS, BUTTON_SIZES, COLOR_KEYS, GNB_COLORS, GNB_COMMON, GNB_LAYOUT, GNB_MENU_WIDTH, ICONS, SActionModal, SBadge, SBarcodeInput, SButton, SCalendar, SCallout, SCard, SCheckbox, SChip, SChipInput, SCircleProgress, SConfirmModal, SDatePicker, SDateRangePicker, SDivider, SDropdownButton, SField, SFilePicker, SForm, SGhostButton, SGnb, SGuide, SIcon, SInput, SKeyValueTable, SLayout, SLayoutContext, SLinearProgress, SLoadingContainer, SLoadingModal, SLoadingViewport, SNumberInput, SPage, SPagination, SPopover, SPopup, SPortal, SRadio, SRadioButton, SRadioGroup, SSelect, SSwitch, STable, STabs, STag, STextLink, STextarea, SToast, SToastContainer, SToggle, STooltip, TAG_COLORS, TAG_SHAPES, TAG_SIZES, buttonPreset, cn, findGnbAncestors, isColorKey, loading, resolveColor, useSLayout };
9385
9788
  //# sourceMappingURL=index.js.map
9386
9789
  //# sourceMappingURL=index.js.map