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.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
  }
@@ -3911,9 +3915,12 @@ function SGhostButton({
3911
3915
  size = "sm",
3912
3916
  intent = "default",
3913
3917
  ariaLabel = "",
3918
+ ariaPressed,
3914
3919
  tooltipText,
3915
3920
  disabled = false,
3916
3921
  onClick,
3922
+ anchorClassName,
3923
+ anchorStyle,
3917
3924
  className,
3918
3925
  style
3919
3926
  }) {
@@ -3936,6 +3943,8 @@ function SGhostButton({
3936
3943
  };
3937
3944
  const s = SIZE2[size];
3938
3945
  const contentColor = disabled ? intent === "inverse" ? "var(--cmp-ghostButton-inverse-disabled)" : "var(--cmp-ghostButton-icon-disabled)" : `var(--cmp-ghostButton-${intent}-content)`;
3946
+ const text = (tooltipText ?? "").trim();
3947
+ const hasTooltip = text !== "";
3939
3948
  const btn = /* @__PURE__ */ jsxs(
3940
3949
  "button",
3941
3950
  {
@@ -3943,6 +3952,7 @@ function SGhostButton({
3943
3952
  disabled,
3944
3953
  "aria-disabled": disabled ? "true" : void 0,
3945
3954
  "aria-label": ariaLabel.trim() || void 0,
3955
+ "aria-pressed": ariaPressed,
3946
3956
  tabIndex: disabled ? -1 : void 0,
3947
3957
  onClick: (e) => {
3948
3958
  if (disabled) {
@@ -3976,13 +3986,13 @@ function SGhostButton({
3976
3986
  ]
3977
3987
  }
3978
3988
  );
3979
- const text = (tooltipText ?? "").trim();
3980
- if (text === "") return btn;
3989
+ if (!hasTooltip) return btn;
3981
3990
  return /* @__PURE__ */ jsxs(RPopover2.Root, { open, onOpenChange: setOpen, children: [
3982
3991
  /* @__PURE__ */ jsx(RPopover2.Anchor, { asChild: true, children: /* @__PURE__ */ jsx(
3983
3992
  "span",
3984
3993
  {
3985
- className: "inline-flex",
3994
+ className: cn("inline-flex", anchorClassName),
3995
+ style: anchorStyle,
3986
3996
  onMouseEnter: openNow,
3987
3997
  onMouseLeave: startHide,
3988
3998
  onFocus: openNow,
@@ -4383,7 +4393,7 @@ function SPortal({
4383
4393
  onCloseAutoFocus,
4384
4394
  onClick: autoClose ? () => onClose?.() : void 0,
4385
4395
  className: cn(
4386
- "z-50 overflow-hidden rounded-(--cmp-listBox-radius) bg-(--cmp-listBox-bg) py-4 shadow-normal-sm",
4396
+ "z-50 overflow-hidden rounded-(--cmp-listBox-radius) bg-(--cmp-listBox-bg) shadow-normal-sm",
4387
4397
  maxHeight != null && "overflow-y-auto",
4388
4398
  fit && "min-w-(--radix-popover-trigger-width)",
4389
4399
  FLOATING_SLIDE_ANIM,
@@ -4865,6 +4875,404 @@ function SLoadingModal({
4865
4875
  );
4866
4876
  }
4867
4877
 
4878
+ // src/components/SGnb/gnb.config.ts
4879
+ var belt = (p) => `var(--cmp-gnbBelt-${p})`;
4880
+ var box = (p) => `var(--cmp-gnbBox-${p})`;
4881
+ var light = (p) => `var(--cmp-light-${p})`;
4882
+ var dark = (p) => `var(--cmp-dark-${p})`;
4883
+ var GNB_HEADER = {
4884
+ fix: {
4885
+ topHeight: belt("top-height"),
4886
+ topPaddingX: belt("top-paddingX"),
4887
+ topGap: belt("top-gap"),
4888
+ logoHeight: belt("logo-height")
4889
+ },
4890
+ full: {
4891
+ topHeight: box("top-height"),
4892
+ topPaddingX: box("paddingX"),
4893
+ topGap: box("gap"),
4894
+ // 상단바 gap (버튼 간 세부 gap 은 --cmp-gnbBox-button-gap)
4895
+ logoHeight: box("logo-height")
4896
+ }
4897
+ };
4898
+ var GNB_MENU = {
4899
+ box: {
4900
+ // menu.body.padding 은 전방향 토큰 → 세로 패딩과 아이템 좌우 여백 양쪽에 쓴다
4901
+ bodyPaddingY: box("menu-body-padding"),
4902
+ itemMarginX: box("menu-body-padding"),
4903
+ itemPaddingY: box("item-paddingY"),
4904
+ itemPaddingRight: box("item-paddingRight"),
4905
+ itemGap: box("item-gap"),
4906
+ itemRadius: box("item-radius"),
4907
+ itemArrow: box("item-arrow"),
4908
+ depth1PaddingLeft: box("item-depth1-paddingLeft"),
4909
+ depth2PaddingLeft: box("item-depth2-paddingLeft"),
4910
+ depth3PaddingLeft: box("item-depth3-paddingLeft"),
4911
+ depth1Icon: box("item-depth1-icon"),
4912
+ depth1FontSize: 14,
4913
+ // token: gnbBox.item.typography.bold.fontSize
4914
+ depth1LineHeight: 24,
4915
+ // token: gnbBox.item.typography.bold.lineHeight
4916
+ depth1FontWeight: 700,
4917
+ itemFontSize: 14,
4918
+ // token: gnbBox.item.typography.default.fontSize
4919
+ itemLineHeight: 24
4920
+ // token: gnbBox.item.typography.default.lineHeight
4921
+ },
4922
+ belt: {
4923
+ bodyPaddingY: belt("body-paddingY"),
4924
+ itemMarginX: "0px",
4925
+ // belt 토큰에 가로 여백 없음 → 풀폭 행 (들여쓰기는 depth*-paddingLeft 전담)
4926
+ itemPaddingY: belt("item-paddingY"),
4927
+ itemPaddingRight: belt("item-paddingRight"),
4928
+ itemGap: belt("item-gap"),
4929
+ itemRadius: "0px",
4930
+ // belt 토큰에 radius 없음 → 풀폭 행
4931
+ itemArrow: belt("item-icon"),
4932
+ depth1PaddingLeft: belt("item-depth1-paddingLeft"),
4933
+ depth2PaddingLeft: belt("item-depth2-paddingLeft"),
4934
+ depth3PaddingLeft: belt("item-depth3-paddingLeft"),
4935
+ depth1Icon: box("item-depth1-icon"),
4936
+ // belt 토큰에 depth1-icon 없음 → box 값(20) 공유
4937
+ depth1FontSize: 13,
4938
+ // token: gnbBelt.item.depth1.typography.fontSize
4939
+ depth1LineHeight: 22,
4940
+ // token: gnbBelt.item.depth1.typography.lineHeight
4941
+ depth1FontWeight: 700,
4942
+ itemFontSize: 12,
4943
+ // token: gnbBelt.item.typography.default.fontSize
4944
+ itemLineHeight: 20
4945
+ // token: gnbBelt.item.typography.default.lineHeight
4946
+ }
4947
+ };
4948
+ var GNB_COLORS = {
4949
+ light: {
4950
+ panelBg: light("bg"),
4951
+ topBorder: light("divider"),
4952
+ itemBgDefault: light("item-bg-default"),
4953
+ itemBgHover: light("item-bg-hover"),
4954
+ itemBgSelected: light("item-bg-selected"),
4955
+ itemColorDefault: light("item-fg-default"),
4956
+ itemColorHover: light("item-fg-hover"),
4957
+ itemColorActive: light("item-fg-selected"),
4958
+ itemChevron: light("item-chevron")
4959
+ },
4960
+ dark: {
4961
+ panelBg: dark("bg"),
4962
+ topBorder: dark("divider"),
4963
+ itemBgDefault: dark("item-bg-default"),
4964
+ itemBgHover: dark("item-bg-hover"),
4965
+ itemBgSelected: dark("item-bg-selected"),
4966
+ itemColorDefault: dark("item-fg-default"),
4967
+ itemColorHover: dark("item-fg-hover"),
4968
+ itemColorActive: dark("item-fg-selected"),
4969
+ itemChevron: dark("item-chevron")
4970
+ }
4971
+ };
4972
+ var GNB_COMMON = {
4973
+ /** 접힘 레일 폭. header="full" 은 접으면 메뉴만 사라져 레일이 없으므로 fix 전용. */
4974
+ foldWidth: belt("fold-width"),
4975
+ /**
4976
+ * 상단바 아이콘 버튼 사이 간격. fix 레일(세로 스택)의 gap·상하 여백에 쓴다.
4977
+ * 레일 전용 여백 토큰이 따로 없어 같은 값(8px)인 이 토큰으로 재해석했다.
4978
+ */
4979
+ buttonGap: box("button-gap")
4980
+ };
4981
+ var GNB_MENU_WIDTH = 240;
4982
+ function findGnbAncestors(items, value) {
4983
+ const walk = (list, trail) => {
4984
+ for (const item of list) {
4985
+ if (item.value === value) return trail;
4986
+ if (item.children) {
4987
+ const found = walk(item.children, [...trail, item.value]);
4988
+ if (found) return found;
4989
+ }
4990
+ }
4991
+ return null;
4992
+ };
4993
+ return walk(items, []) ?? [];
4994
+ }
4995
+ var SLayoutContext = createContext(null);
4996
+ function useSLayout() {
4997
+ const ctx = useContext(SLayoutContext);
4998
+ if (!ctx) throw new Error("useSLayout \uC740 <SLayout> \uC548\uC5D0\uC11C\uB9CC \uC0AC\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.");
4999
+ return ctx;
5000
+ }
5001
+ var SLayout = forwardRef(function SLayout2({
5002
+ type = "box",
5003
+ header = "fix",
5004
+ folded,
5005
+ defaultFolded = false,
5006
+ onFoldedChange,
5007
+ className,
5008
+ style,
5009
+ children,
5010
+ ...rest
5011
+ }, ref) {
5012
+ const [uncontrolledFolded, setUncontrolledFolded] = useState(defaultFolded);
5013
+ const isControlled = folded !== void 0;
5014
+ const currentFolded = isControlled ? folded : uncontrolledFolded;
5015
+ const setFolded = useCallback(
5016
+ (next) => {
5017
+ if (!isControlled) setUncontrolledFolded(next);
5018
+ onFoldedChange?.(next);
5019
+ },
5020
+ [isControlled, onFoldedChange]
5021
+ );
5022
+ const ctx = useMemo(
5023
+ () => ({ type, header, folded: currentFolded, setFolded }),
5024
+ [type, header, currentFolded, setFolded]
5025
+ );
5026
+ const isFullHeader = header === "full";
5027
+ const frameStyle = isFullHeader ? {
5028
+ gridTemplateColumns: `${currentFolded ? 0 : GNB_MENU_WIDTH}px 1fr`,
5029
+ gridTemplateRows: `${GNB_HEADER[header].topHeight} 1fr`
5030
+ } : void 0;
5031
+ return /* @__PURE__ */ jsx(SLayoutContext.Provider, { value: ctx, children: /* @__PURE__ */ jsx(
5032
+ "div",
5033
+ {
5034
+ ref,
5035
+ "data-type": type,
5036
+ "data-header": header,
5037
+ className: cn(
5038
+ "box-border h-full overflow-hidden",
5039
+ isFullHeader ? "grid" : "flex flex-row",
5040
+ className
5041
+ ),
5042
+ style: { ...frameStyle, ...style },
5043
+ ...rest,
5044
+ children
5045
+ }
5046
+ ) });
5047
+ });
5048
+ var DEPTH_PADDING_LEFT = (M, depth) => depth === 1 ? M.depth1PaddingLeft : depth === 2 ? M.depth2PaddingLeft : M.depth3PaddingLeft;
5049
+ var SGnb = forwardRef(function SGnb2({
5050
+ type: typeProp,
5051
+ header: headerProp,
5052
+ color = "light",
5053
+ items,
5054
+ value = "",
5055
+ onValueChange,
5056
+ folded: foldedProp,
5057
+ onFoldChange,
5058
+ onLauncherClick,
5059
+ logo,
5060
+ ariaLabel = "global navigation",
5061
+ className,
5062
+ style,
5063
+ ...rest
5064
+ }, ref) {
5065
+ const layout = useContext(SLayoutContext);
5066
+ const type = typeProp ?? layout?.type ?? "box";
5067
+ const header = headerProp ?? layout?.header ?? "fix";
5068
+ const folded = foldedProp ?? layout?.folded ?? false;
5069
+ const H = GNB_HEADER[header];
5070
+ const M = GNB_MENU[type];
5071
+ const C = GNB_COLORS[color];
5072
+ const [expandedKeys, setExpandedKeys] = useState(
5073
+ () => new Set(findGnbAncestors(items, value))
5074
+ );
5075
+ const [hoveredKey, setHoveredKey] = useState(null);
5076
+ useEffect(() => {
5077
+ const ancestors = findGnbAncestors(items, value);
5078
+ if (ancestors.length === 0) return;
5079
+ setExpandedKeys((prev) => {
5080
+ if (ancestors.every((a) => prev.has(a))) return prev;
5081
+ const next = new Set(prev);
5082
+ ancestors.forEach((a) => next.add(a));
5083
+ return next;
5084
+ });
5085
+ }, [items, value]);
5086
+ const toggleExpand = (key) => {
5087
+ setExpandedKeys((prev) => {
5088
+ const next = new Set(prev);
5089
+ if (next.has(key)) next.delete(key);
5090
+ else next.add(key);
5091
+ return next;
5092
+ });
5093
+ };
5094
+ const handleItemClick = (item) => {
5095
+ if (item.disabled) return;
5096
+ if (item.children && item.children.length > 0) {
5097
+ toggleExpand(item.value);
5098
+ return;
5099
+ }
5100
+ onValueChange?.(item.value);
5101
+ };
5102
+ const handleFoldToggle = () => {
5103
+ const next = !folded;
5104
+ onFoldChange?.(next);
5105
+ if (foldedProp === void 0) layout?.setFolded(next);
5106
+ };
5107
+ const renderItem = (item, depth) => {
5108
+ const hasChildren = !!(item.children && item.children.length > 0);
5109
+ const isSelected = !hasChildren && item.value === value;
5110
+ const isExpanded = expandedKeys.has(item.value);
5111
+ const isHovered = hoveredKey === item.value && !item.disabled;
5112
+ const itemStyle = {
5113
+ gap: M.itemGap,
5114
+ paddingTop: M.itemPaddingY,
5115
+ paddingBottom: M.itemPaddingY,
5116
+ paddingRight: M.itemPaddingRight,
5117
+ paddingLeft: DEPTH_PADDING_LEFT(M, depth),
5118
+ marginLeft: M.itemMarginX,
5119
+ marginRight: M.itemMarginX,
5120
+ borderRadius: M.itemRadius,
5121
+ backgroundColor: isSelected ? C.itemBgSelected : isHovered ? C.itemBgHover : C.itemBgDefault,
5122
+ color: isSelected ? C.itemColorActive : isHovered ? C.itemColorHover : C.itemColorDefault,
5123
+ // <button> 의 UA 폰트(Arial 13.3px)를 끊고 앱 폰트를 잇는다
5124
+ fontFamily: "inherit",
5125
+ fontSize: depth === 1 ? M.depth1FontSize : M.itemFontSize,
5126
+ lineHeight: `${depth === 1 ? M.depth1LineHeight : M.itemLineHeight}px`,
5127
+ fontWeight: depth === 1 || isSelected ? M.depth1FontWeight : 400,
5128
+ opacity: item.disabled ? 0.4 : 1,
5129
+ cursor: item.disabled ? "not-allowed" : "pointer"
5130
+ };
5131
+ return (
5132
+ // li 를 flex-col 로 둬야 버튼이 좌우 마진만큼 안쪽으로 들어가고,
5133
+ // 하위 ul 은 마진 없이 전폭을 써서 depth*-paddingLeft 가 들여쓰기를 단독으로 책임진다.
5134
+ /* @__PURE__ */ jsxs("li", { className: "flex flex-col", children: [
5135
+ /* @__PURE__ */ jsxs(
5136
+ "button",
5137
+ {
5138
+ type: "button",
5139
+ disabled: item.disabled,
5140
+ "aria-expanded": hasChildren ? isExpanded : void 0,
5141
+ "aria-current": isSelected ? "page" : void 0,
5142
+ className: "box-border flex select-none items-center border-none bg-transparent text-left transition-colors duration-150",
5143
+ style: itemStyle,
5144
+ onClick: () => handleItemClick(item),
5145
+ onMouseEnter: () => setHoveredKey(item.value),
5146
+ onMouseLeave: () => setHoveredKey((prev) => prev === item.value ? null : prev),
5147
+ children: [
5148
+ depth === 1 && item.icon && /* @__PURE__ */ jsx(SIcon, { name: item.icon, size: M.depth1Icon, className: "shrink-0" }),
5149
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 overflow-hidden text-ellipsis whitespace-nowrap", children: item.label }),
5150
+ item.tag !== void 0 && item.tag !== "" && /* @__PURE__ */ jsx(
5151
+ STag,
5152
+ {
5153
+ shape: "square",
5154
+ size: "xs",
5155
+ color: item.tagColor ?? "blue",
5156
+ label: item.tag,
5157
+ className: "shrink-0"
5158
+ }
5159
+ ),
5160
+ hasChildren && /* @__PURE__ */ jsx(
5161
+ SIcon,
5162
+ {
5163
+ name: "chevronDown",
5164
+ size: M.itemArrow,
5165
+ color: C.itemChevron,
5166
+ rotate: isExpanded ? 180 : 0,
5167
+ className: "shrink-0 transition-transform duration-150"
5168
+ }
5169
+ )
5170
+ ]
5171
+ }
5172
+ ),
5173
+ hasChildren && isExpanded && /* @__PURE__ */ jsx("ul", { className: "m-0 flex list-none flex-col p-0", children: item.children.map((child) => renderItem(child, depth + 1)) })
5174
+ ] }, item.value)
5175
+ );
5176
+ };
5177
+ const railFolded = folded && header === "fix";
5178
+ const rootWidth = header === "full" ? "100%" : folded ? GNB_COMMON.foldWidth : GNB_MENU_WIDTH;
5179
+ const rootStyle = {
5180
+ width: rootWidth,
5181
+ ...header === "full" ? { gridArea: "1 / 1 / -1 / -1", pointerEvents: "none" } : { backgroundColor: C.panelBg },
5182
+ ...style
5183
+ };
5184
+ return /* @__PURE__ */ jsxs(
5185
+ "div",
5186
+ {
5187
+ ref,
5188
+ className: cn("box-border flex h-full shrink-0 flex-col", className),
5189
+ style: rootStyle,
5190
+ "data-type": type,
5191
+ "data-header": header,
5192
+ "data-color": color,
5193
+ ...rest,
5194
+ children: [
5195
+ /* @__PURE__ */ jsxs(
5196
+ "div",
5197
+ {
5198
+ className: cn("box-border flex items-center", railFolded && "flex-col"),
5199
+ style: {
5200
+ gap: railFolded ? GNB_COMMON.buttonGap : H.topGap,
5201
+ height: railFolded ? "auto" : H.topHeight,
5202
+ padding: railFolded ? `${GNB_COMMON.buttonGap} 0` : `0 ${H.topPaddingX}`,
5203
+ borderBottom: `1px solid ${C.topBorder}`,
5204
+ backgroundColor: C.panelBg,
5205
+ pointerEvents: "auto",
5206
+ // 아이콘 버튼은 자체 ghostButton 토큰을 쓰므로, 이 색은 logo 슬롯 상속용
5207
+ color: C.itemColorDefault
5208
+ },
5209
+ children: [
5210
+ onLauncherClick && /* @__PURE__ */ jsx(
5211
+ SGhostButton,
5212
+ {
5213
+ icon: "launcher",
5214
+ size: "xs",
5215
+ intent: color === "dark" ? "inverse" : "default",
5216
+ ariaLabel: "app launcher",
5217
+ onClick: onLauncherClick,
5218
+ className: "shrink-0"
5219
+ }
5220
+ ),
5221
+ !railFolded && logo && /* @__PURE__ */ jsx("div", { className: "flex items-center", style: { height: H.logoHeight }, children: logo }),
5222
+ /* @__PURE__ */ jsx(
5223
+ SGhostButton,
5224
+ {
5225
+ icon: "sidebar",
5226
+ size: "xs",
5227
+ intent: color === "dark" ? "inverse" : "default",
5228
+ ariaLabel: "toggle navigation",
5229
+ ariaPressed: folded,
5230
+ onClick: handleFoldToggle,
5231
+ className: cn("shrink-0", !railFolded && "ml-auto")
5232
+ }
5233
+ )
5234
+ ]
5235
+ }
5236
+ ),
5237
+ !folded && /* @__PURE__ */ jsx(
5238
+ "nav",
5239
+ {
5240
+ "aria-label": ariaLabel,
5241
+ className: "flex flex-col overflow-y-auto",
5242
+ style: {
5243
+ width: GNB_MENU_WIDTH,
5244
+ alignSelf: "flex-start",
5245
+ flexGrow: 1,
5246
+ flexShrink: 1,
5247
+ flexBasis: "auto",
5248
+ minHeight: 0,
5249
+ paddingTop: M.bodyPaddingY,
5250
+ paddingBottom: M.bodyPaddingY,
5251
+ backgroundColor: C.panelBg,
5252
+ pointerEvents: "auto"
5253
+ },
5254
+ children: /* @__PURE__ */ jsx("ul", { className: "m-0 flex list-none flex-col p-0", children: items.map((item) => renderItem(item, 1)) })
5255
+ }
5256
+ )
5257
+ ]
5258
+ }
5259
+ );
5260
+ });
5261
+ var SPage = forwardRef(function SPage2({ className, style, children, ...rest }, ref) {
5262
+ const layout = useContext(SLayoutContext);
5263
+ const gridStyle = layout?.header === "full" ? { gridColumn: 2, gridRow: 2 } : void 0;
5264
+ return /* @__PURE__ */ jsx(
5265
+ "main",
5266
+ {
5267
+ ref,
5268
+ className: cn("box-border min-h-0 min-w-0 flex-1 overflow-auto p-24", className),
5269
+ style: { ...gridStyle, ...style },
5270
+ ...rest,
5271
+ children
5272
+ }
5273
+ );
5274
+ });
5275
+
4868
5276
  // src/components/STabs/tabs.config.ts
4869
5277
  var TAB_MAIN_SIZE = {
4870
5278
  md: { height: 36, paddingX: 24 },
@@ -5701,7 +6109,7 @@ var SSelect = forwardRef(function SSelect2({
5701
6109
  event.preventDefault();
5702
6110
  triggerRef.current?.focus();
5703
6111
  },
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)]",
6112
+ className: "rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] shadow-[2px_2px_12px_2px_rgba(0,0,0,0.1)]",
5705
6113
  style: {
5706
6114
  ...dropdownWidth ? { width: dropdownWidth } : {},
5707
6115
  maxWidth: maxDropdownWidth
@@ -5752,6 +6160,10 @@ var SSelect = forwardRef(function SSelect2({
5752
6160
  onSelectAll: handleSelectAll,
5753
6161
  onSelect: handleSelect,
5754
6162
  onHoverValue: (value2) => {
6163
+ if (value2 == null) {
6164
+ setFocusedIndex(-1);
6165
+ return;
6166
+ }
5755
6167
  const index = navigableItems.findIndex(
5756
6168
  (item) => item.isSelectAll ? value2 === "__select_all__" : item.value === value2
5757
6169
  );
@@ -5800,6 +6212,7 @@ function ItemList({
5800
6212
  ),
5801
6213
  style: { paddingTop: 4, paddingBottom: 4, paddingRight: 12, paddingLeft: 12 },
5802
6214
  onMouseEnter: () => onHoverValue("__select_all__"),
6215
+ onMouseLeave: () => onHoverValue(null),
5803
6216
  onClick: onSelectAll,
5804
6217
  children: [
5805
6218
  /* @__PURE__ */ jsx(
@@ -5858,10 +6271,13 @@ function ItemList({
5858
6271
  itemBase,
5859
6272
  isSelected && !multi && "font-bold text-[color:var(--cmp-listItem-content-selected)]",
5860
6273
  focusedValue === o.value && "bg-[var(--cmp-listItem-bg-hover)] text-[color:var(--cmp-listItem-content-hover)]",
5861
- activeClass
6274
+ // 비활성 항목은 hover/focus 스타일 대상에서 제외한다.
6275
+ // (:hover 는 disabled 버튼에도 매칭되므로 클래스 자체를 붙이지 않아야 한다)
6276
+ !o.disabled && activeClass
5862
6277
  ),
5863
6278
  style: { paddingTop: 4, paddingBottom: 4, paddingRight: 12, paddingLeft: padLeft },
5864
6279
  onMouseEnter: () => onHoverValue(o.value),
6280
+ onMouseLeave: () => onHoverValue(null),
5865
6281
  onClick: () => onSelect(o.value),
5866
6282
  children: [
5867
6283
  multi && /* @__PURE__ */ jsx(
@@ -6382,10 +6798,10 @@ var STable = forwardRef(function STable2({
6382
6798
  "div",
6383
6799
  {
6384
6800
  "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"
6801
+ className: "pointer-events-none absolute left-0 right-0 top-0 z-[31] h-[var(--cmp-table-header-height)] bg-white/60"
6386
6802
  }
6387
6803
  ),
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 }) })
6804
+ /* @__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
6805
  ] }),
6390
6806
  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
6807
  ]
@@ -9140,11 +9556,20 @@ var SChipInput = forwardRef(function SChipInput2({
9140
9556
  style: { width: 1, height: 12, backgroundColor: "#E1E1E1" }
9141
9557
  }
9142
9558
  ),
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
- ] }),
9559
+ showMaxCount && /* @__PURE__ */ jsxs(
9560
+ "span",
9561
+ {
9562
+ className: cn(
9563
+ "s-chip-input__max-count text-12",
9564
+ isMax ? "text-(--sys-color-fg-warning)" : "text-(--cmp-chipInput-text-placeholder)"
9565
+ ),
9566
+ children: [
9567
+ "\uCD5C\uB300 ",
9568
+ maxCount,
9569
+ "\uAC1C"
9570
+ ]
9571
+ }
9572
+ ),
9148
9573
  showResetLink && /* @__PURE__ */ jsx(
9149
9574
  STextLink,
9150
9575
  {
@@ -9181,7 +9606,7 @@ var SChipInput = forwardRef(function SChipInput2({
9181
9606
  onMouseDown: (e) => e.preventDefault(),
9182
9607
  children: [
9183
9608
  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) => {
9609
+ !effectiveAutocomplete ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-8 px-12 py-6", children: items.map((item, i) => {
9185
9610
  const selected = values.includes(item);
9186
9611
  const active = i === activeIndex && !selected;
9187
9612
  return /* @__PURE__ */ jsx(
@@ -9381,6 +9806,6 @@ var SBarcodeInput = forwardRef(
9381
9806
  }
9382
9807
  );
9383
9808
 
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 };
9809
+ export { BADGE_COLORS, BUTTON_COLORS, BUTTON_SIZES, COLOR_KEYS, GNB_COLORS, GNB_COMMON, GNB_HEADER, GNB_MENU, 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
9810
  //# sourceMappingURL=index.js.map
9386
9811
  //# sourceMappingURL=index.js.map