sellmate-design-system-react 0.2.0 → 0.4.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 (138) hide show
  1. package/README.md +84 -21
  2. package/dist/components/SActionModal/SActionModal.cjs +2 -0
  3. package/dist/components/SActionModal/SActionModal.cjs.map +1 -1
  4. package/dist/components/SActionModal/SActionModal.js +2 -0
  5. package/dist/components/SActionModal/SActionModal.js.map +1 -1
  6. package/dist/components/SBarcodeInput/SBarcodeInput.cjs +2 -0
  7. package/dist/components/SBarcodeInput/SBarcodeInput.cjs.map +1 -1
  8. package/dist/components/SBarcodeInput/SBarcodeInput.js +2 -0
  9. package/dist/components/SBarcodeInput/SBarcodeInput.js.map +1 -1
  10. package/dist/components/SCalendar/SCalendar.cjs +2 -0
  11. package/dist/components/SCalendar/SCalendar.cjs.map +1 -1
  12. package/dist/components/SCalendar/SCalendar.js +2 -0
  13. package/dist/components/SCalendar/SCalendar.js.map +1 -1
  14. package/dist/components/SChip/SChip.cjs +2 -0
  15. package/dist/components/SChip/SChip.cjs.map +1 -1
  16. package/dist/components/SChip/SChip.js +2 -0
  17. package/dist/components/SChip/SChip.js.map +1 -1
  18. package/dist/components/SChipInput/SChipInput.cjs +2 -0
  19. package/dist/components/SChipInput/SChipInput.cjs.map +1 -1
  20. package/dist/components/SChipInput/SChipInput.js +2 -0
  21. package/dist/components/SChipInput/SChipInput.js.map +1 -1
  22. package/dist/components/SConfirmModal/SConfirmModal.cjs +2 -0
  23. package/dist/components/SConfirmModal/SConfirmModal.cjs.map +1 -1
  24. package/dist/components/SConfirmModal/SConfirmModal.js +2 -0
  25. package/dist/components/SConfirmModal/SConfirmModal.js.map +1 -1
  26. package/dist/components/SDatePicker/SDatePicker.cjs +2 -0
  27. package/dist/components/SDatePicker/SDatePicker.cjs.map +1 -1
  28. package/dist/components/SDatePicker/SDatePicker.js +2 -0
  29. package/dist/components/SDatePicker/SDatePicker.js.map +1 -1
  30. package/dist/components/SDateRangePicker/SDateRangePicker.cjs +2 -0
  31. package/dist/components/SDateRangePicker/SDateRangePicker.cjs.map +1 -1
  32. package/dist/components/SDateRangePicker/SDateRangePicker.js +2 -0
  33. package/dist/components/SDateRangePicker/SDateRangePicker.js.map +1 -1
  34. package/dist/components/SField/SField.cjs +2 -0
  35. package/dist/components/SField/SField.cjs.map +1 -1
  36. package/dist/components/SField/SField.js +2 -0
  37. package/dist/components/SField/SField.js.map +1 -1
  38. package/dist/components/SFilePicker/SFilePicker.cjs +2 -0
  39. package/dist/components/SFilePicker/SFilePicker.cjs.map +1 -1
  40. package/dist/components/SFilePicker/SFilePicker.js +2 -0
  41. package/dist/components/SFilePicker/SFilePicker.js.map +1 -1
  42. package/dist/components/SGhostButton/SGhostButton.cjs +2 -0
  43. package/dist/components/SGhostButton/SGhostButton.cjs.map +1 -1
  44. package/dist/components/SGhostButton/SGhostButton.d.ts +3 -1
  45. package/dist/components/SGhostButton/SGhostButton.js +2 -0
  46. package/dist/components/SGhostButton/SGhostButton.js.map +1 -1
  47. package/dist/components/SGnb/SGnb.cjs +394 -213
  48. package/dist/components/SGnb/SGnb.cjs.map +1 -1
  49. package/dist/components/SGnb/SGnb.d.ts +16 -12
  50. package/dist/components/SGnb/SGnb.js +375 -214
  51. package/dist/components/SGnb/SGnb.js.map +1 -1
  52. package/dist/components/SGnb/gnb.config.d.ts +35 -11
  53. package/dist/components/SGnb/index.d.ts +1 -1
  54. package/dist/components/SGuide/SGuide.cjs +2 -0
  55. package/dist/components/SGuide/SGuide.cjs.map +1 -1
  56. package/dist/components/SGuide/SGuide.js +2 -0
  57. package/dist/components/SGuide/SGuide.js.map +1 -1
  58. package/dist/components/SInput/SInput.cjs +2 -0
  59. package/dist/components/SInput/SInput.cjs.map +1 -1
  60. package/dist/components/SInput/SInput.js +2 -0
  61. package/dist/components/SInput/SInput.js.map +1 -1
  62. package/dist/components/SKeyValueTable/SKeyValueTable.cjs +2 -0
  63. package/dist/components/SKeyValueTable/SKeyValueTable.cjs.map +1 -1
  64. package/dist/components/SKeyValueTable/SKeyValueTable.js +2 -0
  65. package/dist/components/SKeyValueTable/SKeyValueTable.js.map +1 -1
  66. package/dist/components/SLayout/SLayout.cjs +26 -8
  67. package/dist/components/SLayout/SLayout.cjs.map +1 -1
  68. package/dist/components/SLayout/SLayout.d.ts +15 -9
  69. package/dist/components/SLayout/SLayout.js +26 -8
  70. package/dist/components/SLayout/SLayout.js.map +1 -1
  71. package/dist/components/SLayout/index.d.ts +1 -1
  72. package/dist/components/SLoadingModal/SLoadingModal.cjs +2 -0
  73. package/dist/components/SLoadingModal/SLoadingModal.cjs.map +1 -1
  74. package/dist/components/SLoadingModal/SLoadingModal.js +2 -0
  75. package/dist/components/SLoadingModal/SLoadingModal.js.map +1 -1
  76. package/dist/components/SModalContainer/SModalContainer.cjs +2 -0
  77. package/dist/components/SModalContainer/SModalContainer.cjs.map +1 -1
  78. package/dist/components/SModalContainer/SModalContainer.js +2 -0
  79. package/dist/components/SModalContainer/SModalContainer.js.map +1 -1
  80. package/dist/components/SNumberInput/SNumberInput.cjs +2 -0
  81. package/dist/components/SNumberInput/SNumberInput.cjs.map +1 -1
  82. package/dist/components/SNumberInput/SNumberInput.js +2 -0
  83. package/dist/components/SNumberInput/SNumberInput.js.map +1 -1
  84. package/dist/components/SPage/SPage.cjs +27 -9
  85. package/dist/components/SPage/SPage.cjs.map +1 -1
  86. package/dist/components/SPage/SPage.d.ts +2 -2
  87. package/dist/components/SPage/SPage.js +27 -9
  88. package/dist/components/SPage/SPage.js.map +1 -1
  89. package/dist/components/SPopover/SPopover.cjs +2 -0
  90. package/dist/components/SPopover/SPopover.cjs.map +1 -1
  91. package/dist/components/SPopover/SPopover.js +2 -0
  92. package/dist/components/SPopover/SPopover.js.map +1 -1
  93. package/dist/components/SSelect/SSelect.cjs +2 -0
  94. package/dist/components/SSelect/SSelect.cjs.map +1 -1
  95. package/dist/components/SSelect/SSelect.js +2 -0
  96. package/dist/components/SSelect/SSelect.js.map +1 -1
  97. package/dist/components/STable/STable.cjs +3 -1
  98. package/dist/components/STable/STable.cjs.map +1 -1
  99. package/dist/components/STable/STable.js +3 -1
  100. package/dist/components/STable/STable.js.map +1 -1
  101. package/dist/components/STextarea/STextarea.cjs +2 -0
  102. package/dist/components/STextarea/STextarea.cjs.map +1 -1
  103. package/dist/components/STextarea/STextarea.js +2 -0
  104. package/dist/components/STextarea/STextarea.js.map +1 -1
  105. package/dist/components/STimePicker/STimePicker.cjs +3834 -0
  106. package/dist/components/STimePicker/STimePicker.cjs.map +1 -0
  107. package/dist/components/STimePicker/STimePicker.d.ts +50 -0
  108. package/dist/components/STimePicker/STimePicker.js +3811 -0
  109. package/dist/components/STimePicker/STimePicker.js.map +1 -0
  110. package/dist/components/STimePicker/index.d.ts +2 -0
  111. package/dist/components/STimePicker/timepicker.config.d.ts +23 -0
  112. package/dist/components/STimeRangePicker/STimeRangePicker.cjs +3908 -0
  113. package/dist/components/STimeRangePicker/STimeRangePicker.cjs.map +1 -0
  114. package/dist/components/STimeRangePicker/STimeRangePicker.d.ts +53 -0
  115. package/dist/components/STimeRangePicker/STimeRangePicker.js +3885 -0
  116. package/dist/components/STimeRangePicker/STimeRangePicker.js.map +1 -0
  117. package/dist/components/STimeRangePicker/index.d.ts +1 -0
  118. package/dist/components/STimeRangePicker/time-range-picker.config.d.ts +9 -0
  119. package/dist/components/SToast/SToast.cjs +2 -0
  120. package/dist/components/SToast/SToast.cjs.map +1 -1
  121. package/dist/components/SToast/SToast.js +2 -0
  122. package/dist/components/SToast/SToast.js.map +1 -1
  123. package/dist/components/SToast/SToastContainer.cjs +2 -0
  124. package/dist/components/SToast/SToastContainer.cjs.map +1 -1
  125. package/dist/components/SToast/SToastContainer.js +2 -0
  126. package/dist/components/SToast/SToastContainer.js.map +1 -1
  127. package/dist/components/STooltip/STooltip.cjs +2 -0
  128. package/dist/components/STooltip/STooltip.cjs.map +1 -1
  129. package/dist/components/STooltip/STooltip.js +2 -0
  130. package/dist/components/STooltip/STooltip.js.map +1 -1
  131. package/dist/index.cjs +1011 -136
  132. package/dist/index.cjs.map +1 -1
  133. package/dist/index.d.ts +3 -0
  134. package/dist/index.js +1006 -136
  135. package/dist/index.js.map +1 -1
  136. package/dist/styles.css +475 -74
  137. package/dist/theme.css +85 -70
  138. package/package.json +4 -1
package/dist/index.cjs CHANGED
@@ -1,3 +1,4 @@
1
+ "use client";
1
2
  'use strict';
2
3
 
3
4
  var clsx = require('clsx');
@@ -40,7 +41,6 @@ var RDialog__namespace = /*#__PURE__*/_interopNamespace(RDialog);
40
41
  var RCheckbox__namespace = /*#__PURE__*/_interopNamespace(RCheckbox);
41
42
  var Ariakit__namespace = /*#__PURE__*/_interopNamespace(Ariakit);
42
43
 
43
- // src/lib/cn.ts
44
44
  var twMerge = tailwindMerge.extendTailwindMerge({
45
45
  extend: {
46
46
  classGroups: {
@@ -3943,6 +3943,7 @@ function SGhostButton({
3943
3943
  size = "sm",
3944
3944
  intent = "default",
3945
3945
  ariaLabel = "",
3946
+ ariaPressed,
3946
3947
  tooltipText,
3947
3948
  disabled = false,
3948
3949
  onClick,
@@ -3979,6 +3980,7 @@ function SGhostButton({
3979
3980
  disabled,
3980
3981
  "aria-disabled": disabled ? "true" : void 0,
3981
3982
  "aria-label": ariaLabel.trim() || void 0,
3983
+ "aria-pressed": ariaPressed,
3982
3984
  tabIndex: disabled ? -1 : void 0,
3983
3985
  onClick: (e) => {
3984
3986
  if (disabled) {
@@ -4906,13 +4908,27 @@ var belt = (p) => `var(--cmp-gnbBelt-${p})`;
4906
4908
  var box = (p) => `var(--cmp-gnbBox-${p})`;
4907
4909
  var light = (p) => `var(--cmp-light-${p})`;
4908
4910
  var dark = (p) => `var(--cmp-dark-${p})`;
4909
- var GNB_LAYOUT = {
4910
- // 사용자 명명: type="box" → gnbBox 토큰(둥금), type="belt" → gnbBelt 토큰(각짐)
4911
- box: {
4911
+ var GNB_HEADER = {
4912
+ fix: {
4913
+ topHeight: belt("top-height"),
4914
+ topPaddingX: belt("top-paddingX"),
4915
+ topGap: belt("top-gap"),
4916
+ logoHeight: belt("logo-height")
4917
+ },
4918
+ full: {
4919
+ topHeight: box("top-height"),
4912
4920
  topPaddingX: box("paddingX"),
4913
4921
  topGap: box("gap"),
4914
4922
  // 상단바 gap (버튼 간 세부 gap 은 --cmp-gnbBox-button-gap)
4915
- bodyPadding: box("menu-body-padding"),
4923
+ logoHeight: box("logo-height")
4924
+ }
4925
+ };
4926
+ var GNB_MENU = {
4927
+ box: {
4928
+ // menu.body.padding 은 전방향 토큰 → 세로 패딩과 아이템 좌우 여백 양쪽에 쓴다
4929
+ bodyPaddingY: box("menu-body-padding"),
4930
+ itemMarginX: box("menu-body-padding"),
4931
+ itemPaddingY: box("item-paddingY"),
4916
4932
  itemPaddingRight: box("item-paddingRight"),
4917
4933
  itemGap: box("item-gap"),
4918
4934
  itemRadius: box("item-radius"),
@@ -4932,9 +4948,10 @@ var GNB_LAYOUT = {
4932
4948
  // token: gnbBox.item.typography.default.lineHeight
4933
4949
  },
4934
4950
  belt: {
4935
- topPaddingX: belt("top-paddingX"),
4936
- topGap: belt("top-gap"),
4937
- bodyPadding: belt("body-paddingY"),
4951
+ bodyPaddingY: belt("body-paddingY"),
4952
+ itemMarginX: "0px",
4953
+ // belt 토큰에 가로 여백 없음 → 풀폭 행 (들여쓰기는 depth*-paddingLeft 전담)
4954
+ itemPaddingY: belt("item-paddingY"),
4938
4955
  itemPaddingRight: belt("item-paddingRight"),
4939
4956
  itemGap: belt("item-gap"),
4940
4957
  itemRadius: "0px",
@@ -4964,7 +4981,9 @@ var GNB_COLORS = {
4964
4981
  itemBgHover: light("item-bg-hover"),
4965
4982
  itemBgSelected: light("item-bg-selected"),
4966
4983
  itemColorDefault: light("item-fg-default"),
4967
- itemColorActive: light("item-fg-selected")
4984
+ itemColorHover: light("item-fg-hover"),
4985
+ itemColorActive: light("item-fg-selected"),
4986
+ itemChevron: light("item-chevron")
4968
4987
  },
4969
4988
  dark: {
4970
4989
  panelBg: dark("bg"),
@@ -4973,18 +4992,19 @@ var GNB_COLORS = {
4973
4992
  itemBgHover: dark("item-bg-hover"),
4974
4993
  itemBgSelected: dark("item-bg-selected"),
4975
4994
  itemColorDefault: dark("item-fg-default"),
4976
- itemColorActive: dark("item-fg-selected")
4995
+ itemColorHover: dark("item-fg-hover"),
4996
+ itemColorActive: dark("item-fg-selected"),
4997
+ itemChevron: dark("item-chevron")
4977
4998
  }
4978
4999
  };
4979
5000
  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 토큰 공유)
5001
+ /** 접힘 레일 폭. header="full" 은 접으면 메뉴만 사라져 레일이 없으므로 fix 전용. */
5002
+ foldWidth: belt("fold-width"),
5003
+ /**
5004
+ * 상단바 아이콘 버튼 사이 간격. fix 레일(세로 스택)의 gap·상하 여백에 쓴다.
5005
+ * 레일 전용 여백 토큰이 따로 없어 같은 값(8px)인 이 토큰으로 재해석했다.
5006
+ */
5007
+ buttonGap: box("button-gap")
4988
5008
  };
4989
5009
  var GNB_MENU_WIDTH = 240;
4990
5010
  function findGnbAncestors(items, value) {
@@ -5008,6 +5028,7 @@ function useSLayout() {
5008
5028
  }
5009
5029
  var SLayout = react.forwardRef(function SLayout2({
5010
5030
  type = "box",
5031
+ header = "fix",
5011
5032
  folded,
5012
5033
  defaultFolded = false,
5013
5034
  onFoldedChange,
@@ -5027,22 +5048,23 @@ var SLayout = react.forwardRef(function SLayout2({
5027
5048
  [isControlled, onFoldedChange]
5028
5049
  );
5029
5050
  const ctx = react.useMemo(
5030
- () => ({ type, folded: currentFolded, setFolded }),
5031
- [type, currentFolded, setFolded]
5051
+ () => ({ type, header, folded: currentFolded, setFolded }),
5052
+ [type, header, currentFolded, setFolded]
5032
5053
  );
5033
- const isBox = type === "box";
5034
- const frameStyle = isBox ? {
5054
+ const isFullHeader = header === "full";
5055
+ const frameStyle = isFullHeader ? {
5035
5056
  gridTemplateColumns: `${currentFolded ? 0 : GNB_MENU_WIDTH}px 1fr`,
5036
- gridTemplateRows: `${GNB_COMMON.topHeight} 1fr`
5057
+ gridTemplateRows: `${GNB_HEADER[header].topHeight} 1fr`
5037
5058
  } : void 0;
5038
5059
  return /* @__PURE__ */ jsxRuntime.jsx(SLayoutContext.Provider, { value: ctx, children: /* @__PURE__ */ jsxRuntime.jsx(
5039
5060
  "div",
5040
5061
  {
5041
5062
  ref,
5042
5063
  "data-type": type,
5064
+ "data-header": header,
5043
5065
  className: cn(
5044
5066
  "box-border h-full overflow-hidden",
5045
- isBox ? "grid" : "flex flex-row",
5067
+ isFullHeader ? "grid" : "flex flex-row",
5046
5068
  className
5047
5069
  ),
5048
5070
  style: { ...frameStyle, ...style },
@@ -5051,9 +5073,10 @@ var SLayout = react.forwardRef(function SLayout2({
5051
5073
  }
5052
5074
  ) });
5053
5075
  });
5054
- var DEPTH_PADDING_LEFT = (L, depth) => depth === 1 ? L.depth1PaddingLeft : depth === 2 ? L.depth2PaddingLeft : L.depth3PaddingLeft;
5076
+ var DEPTH_PADDING_LEFT = (M, depth) => depth === 1 ? M.depth1PaddingLeft : depth === 2 ? M.depth2PaddingLeft : M.depth3PaddingLeft;
5055
5077
  var SGnb = react.forwardRef(function SGnb2({
5056
5078
  type: typeProp,
5079
+ header: headerProp,
5057
5080
  color = "light",
5058
5081
  items,
5059
5082
  value = "",
@@ -5062,14 +5085,17 @@ var SGnb = react.forwardRef(function SGnb2({
5062
5085
  onFoldChange,
5063
5086
  onLauncherClick,
5064
5087
  logo,
5065
- search,
5088
+ ariaLabel = "global navigation",
5066
5089
  className,
5067
- style
5090
+ style,
5091
+ ...rest
5068
5092
  }, ref) {
5069
5093
  const layout = react.useContext(SLayoutContext);
5070
5094
  const type = typeProp ?? layout?.type ?? "box";
5095
+ const header = headerProp ?? layout?.header ?? "fix";
5071
5096
  const folded = foldedProp ?? layout?.folded ?? false;
5072
- const L = GNB_LAYOUT[type];
5097
+ const H = GNB_HEADER[header];
5098
+ const M = GNB_MENU[type];
5073
5099
  const C = GNB_COLORS[color];
5074
5100
  const [expandedKeys, setExpandedKeys] = react.useState(
5075
5101
  () => new Set(findGnbAncestors(items, value))
@@ -5079,6 +5105,7 @@ var SGnb = react.forwardRef(function SGnb2({
5079
5105
  const ancestors = findGnbAncestors(items, value);
5080
5106
  if (ancestors.length === 0) return;
5081
5107
  setExpandedKeys((prev) => {
5108
+ if (ancestors.every((a) => prev.has(a))) return prev;
5082
5109
  const next = new Set(prev);
5083
5110
  ancestors.forEach((a) => next.add(a));
5084
5111
  return next;
@@ -5103,148 +5130,142 @@ var SGnb = react.forwardRef(function SGnb2({
5103
5130
  const handleFoldToggle = () => {
5104
5131
  const next = !folded;
5105
5132
  onFoldChange?.(next);
5106
- layout?.setFolded(next);
5133
+ if (foldedProp === void 0) layout?.setFolded(next);
5107
5134
  };
5108
- const iconBtnClass = "inline-flex shrink-0 cursor-pointer items-center justify-center rounded-md border-0 bg-transparent p-1.5";
5109
5135
  const renderItem = (item, depth) => {
5110
5136
  const hasChildren = !!(item.children && item.children.length > 0);
5111
5137
  const isSelected = !hasChildren && item.value === value;
5112
5138
  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;
5139
+ const isHovered = hoveredKey === item.value && !item.disabled;
5115
5140
  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,
5141
+ gap: M.itemGap,
5142
+ paddingTop: M.itemPaddingY,
5143
+ paddingBottom: M.itemPaddingY,
5144
+ paddingRight: M.itemPaddingRight,
5145
+ paddingLeft: DEPTH_PADDING_LEFT(M, depth),
5146
+ marginLeft: M.itemMarginX,
5147
+ marginRight: M.itemMarginX,
5148
+ borderRadius: M.itemRadius,
5149
+ backgroundColor: isSelected ? C.itemBgSelected : isHovered ? C.itemBgHover : C.itemBgDefault,
5150
+ color: isSelected ? C.itemColorActive : isHovered ? C.itemColorHover : C.itemColorDefault,
5151
+ // <button> UA 폰트(Arial 13.3px)를 끊고 앱 폰트를 잇는다
5152
+ fontFamily: "inherit",
5153
+ fontSize: depth === 1 ? M.depth1FontSize : M.itemFontSize,
5154
+ lineHeight: `${depth === 1 ? M.depth1LineHeight : M.itemLineHeight}px`,
5155
+ fontWeight: depth === 1 || isSelected ? M.depth1FontWeight : 400,
5129
5156
  opacity: item.disabled ? 0.4 : 1,
5130
5157
  cursor: item.disabled ? "not-allowed" : "pointer"
5131
5158
  };
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);
5159
+ return (
5160
+ // li flex-col 로 둬야 버튼이 좌우 마진만큼 안쪽으로 들어가고,
5161
+ // 하위 ul 은 마진 없이 전폭을 써서 depth*-paddingLeft 가 들여쓰기를 단독으로 책임진다.
5162
+ /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex flex-col", children: [
5163
+ /* @__PURE__ */ jsxRuntime.jsxs(
5164
+ "button",
5165
+ {
5166
+ type: "button",
5167
+ disabled: item.disabled,
5168
+ "aria-expanded": hasChildren ? isExpanded : void 0,
5169
+ "aria-current": isSelected ? "page" : void 0,
5170
+ className: "box-border flex select-none items-center border-none bg-transparent text-left transition-colors duration-150",
5171
+ style: itemStyle,
5172
+ onClick: () => handleItemClick(item),
5173
+ onMouseEnter: () => setHoveredKey(item.value),
5174
+ onMouseLeave: () => setHoveredKey((prev) => prev === item.value ? null : prev),
5175
+ children: [
5176
+ depth === 1 && item.icon && /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: item.icon, size: M.depth1Icon, className: "shrink-0" }),
5177
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 overflow-hidden text-ellipsis whitespace-nowrap", children: item.label }),
5178
+ item.tag !== void 0 && item.tag !== "" && /* @__PURE__ */ jsxRuntime.jsx(
5179
+ STag,
5180
+ {
5181
+ shape: "square",
5182
+ size: "xs",
5183
+ color: item.tagColor ?? "blue",
5184
+ label: item.tag,
5185
+ className: "shrink-0"
5186
+ }
5187
+ ),
5188
+ hasChildren && /* @__PURE__ */ jsxRuntime.jsx(
5189
+ SIcon,
5190
+ {
5191
+ name: "chevronDown",
5192
+ size: M.itemArrow,
5193
+ color: C.itemChevron,
5194
+ rotate: isExpanded ? 180 : 0,
5195
+ className: "shrink-0 transition-transform duration-150"
5196
+ }
5197
+ )
5198
+ ]
5199
+ }
5200
+ ),
5201
+ hasChildren && isExpanded && /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "m-0 flex list-none flex-col p-0", children: item.children.map((child) => renderItem(child, depth + 1)) })
5202
+ ] }, item.value)
5203
+ );
5204
+ };
5205
+ const railFolded = folded && header === "fix";
5206
+ const rootWidth = header === "full" ? "100%" : folded ? GNB_COMMON.foldWidth : GNB_MENU_WIDTH;
5207
+ const rootStyle = {
5208
+ width: rootWidth,
5209
+ ...header === "full" ? { gridArea: "1 / 1 / -1 / -1", pointerEvents: "none" } : { backgroundColor: C.panelBg },
5210
+ ...style
5179
5211
  };
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
5212
  return /* @__PURE__ */ jsxRuntime.jsxs(
5193
5213
  "div",
5194
5214
  {
5195
5215
  ref,
5196
- className: cn(
5197
- "box-border flex flex-col",
5198
- type === "box" && !inBoxGrid ? "h-auto" : "h-full",
5199
- className
5200
- ),
5216
+ className: cn("box-border flex h-full shrink-0 flex-col", className),
5201
5217
  style: rootStyle,
5202
5218
  "data-type": type,
5219
+ "data-header": header,
5203
5220
  "data-color": color,
5221
+ ...rest,
5204
5222
  children: [
5205
5223
  /* @__PURE__ */ jsxRuntime.jsxs(
5206
5224
  "div",
5207
5225
  {
5208
5226
  className: cn("box-border flex items-center", railFolded && "flex-col"),
5209
5227
  style: {
5210
- gap: railFolded ? 8 : L.topGap,
5211
- height: railFolded ? "auto" : GNB_COMMON.topHeight,
5212
- padding: railFolded ? "8px 0" : `0 ${L.topPaddingX}`,
5228
+ gap: railFolded ? GNB_COMMON.buttonGap : H.topGap,
5229
+ height: railFolded ? "auto" : H.topHeight,
5230
+ padding: railFolded ? `${GNB_COMMON.buttonGap} 0` : `0 ${H.topPaddingX}`,
5213
5231
  borderBottom: `1px solid ${C.topBorder}`,
5214
5232
  backgroundColor: C.panelBg,
5215
- color: iconColor
5233
+ pointerEvents: "auto",
5234
+ // 아이콘 버튼은 자체 ghostButton 토큰을 쓰므로, 이 색은 logo 슬롯 상속용
5235
+ color: C.itemColorDefault
5216
5236
  },
5217
5237
  children: [
5218
- /* @__PURE__ */ jsxRuntime.jsx(
5219
- "button",
5238
+ onLauncherClick && /* @__PURE__ */ jsxRuntime.jsx(
5239
+ SGhostButton,
5220
5240
  {
5221
- type: "button",
5222
- "aria-label": "app launcher",
5223
- className: iconBtnClass,
5241
+ icon: "launcher",
5242
+ size: "xs",
5243
+ intent: color === "dark" ? "inverse" : "default",
5244
+ ariaLabel: "app launcher",
5224
5245
  onClick: onLauncherClick,
5225
- children: /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "launcher", size: 20 })
5246
+ className: "shrink-0"
5226
5247
  }
5227
5248
  ),
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 }),
5249
+ !railFolded && logo && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center", style: { height: H.logoHeight }, children: logo }),
5230
5250
  /* @__PURE__ */ jsxRuntime.jsx(
5231
- "button",
5251
+ SGhostButton,
5232
5252
  {
5233
- type: "button",
5234
- "aria-label": "toggle navigation",
5235
- "aria-pressed": folded,
5236
- className: cn(iconBtnClass, !railFolded && "ml-auto"),
5253
+ icon: "sidebar",
5254
+ size: "xs",
5255
+ intent: color === "dark" ? "inverse" : "default",
5256
+ ariaLabel: "toggle navigation",
5257
+ ariaPressed: folded,
5237
5258
  onClick: handleFoldToggle,
5238
- children: /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "sidebar", size: 20 })
5259
+ className: cn("shrink-0", !railFolded && "ml-auto")
5239
5260
  }
5240
5261
  )
5241
5262
  ]
5242
5263
  }
5243
5264
  ),
5244
5265
  !folded && /* @__PURE__ */ jsxRuntime.jsx(
5245
- "div",
5266
+ "nav",
5246
5267
  {
5247
- role: "menu",
5268
+ "aria-label": ariaLabel,
5248
5269
  className: "flex flex-col overflow-y-auto",
5249
5270
  style: {
5250
5271
  width: GNB_MENU_WIDTH,
@@ -5253,11 +5274,12 @@ var SGnb = react.forwardRef(function SGnb2({
5253
5274
  flexShrink: 1,
5254
5275
  flexBasis: "auto",
5255
5276
  minHeight: 0,
5256
- paddingTop: L.bodyPadding,
5257
- paddingBottom: L.bodyPadding,
5258
- backgroundColor: C.panelBg
5277
+ paddingTop: M.bodyPaddingY,
5278
+ paddingBottom: M.bodyPaddingY,
5279
+ backgroundColor: C.panelBg,
5280
+ pointerEvents: "auto"
5259
5281
  },
5260
- children: items.map((item) => renderItem(item, 1))
5282
+ children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "m-0 flex list-none flex-col p-0", children: items.map((item) => renderItem(item, 1)) })
5261
5283
  }
5262
5284
  )
5263
5285
  ]
@@ -5266,7 +5288,7 @@ var SGnb = react.forwardRef(function SGnb2({
5266
5288
  });
5267
5289
  var SPage = react.forwardRef(function SPage2({ className, style, children, ...rest }, ref) {
5268
5290
  const layout = react.useContext(SLayoutContext);
5269
- const gridStyle = layout?.type === "box" ? { gridColumn: 2, gridRow: 2 } : void 0;
5291
+ const gridStyle = layout?.header === "full" ? { gridColumn: 2, gridRow: 2 } : void 0;
5270
5292
  return /* @__PURE__ */ jsxRuntime.jsx(
5271
5293
  "main",
5272
5294
  {
@@ -6638,7 +6660,7 @@ var STable = react.forwardRef(function STable2({
6638
6660
  ref: scrollRef,
6639
6661
  onScroll: handleScroll,
6640
6662
  className: cn(
6641
- "relative overflow-auto border border-solid border-[color:var(--cmp-table-border-color)]",
6663
+ "bg-white relative overflow-auto border border-solid border-[color:var(--cmp-table-border-color)]",
6642
6664
  radiusClass,
6643
6665
  // 원본 sd-table__scroll-container--loading/--no-data: 로딩·데이터 없음 시 스크롤·인터랙션 차단
6644
6666
  (isLoading || rowCount === 0) && "overflow-hidden pointer-events-none"
@@ -9812,13 +9834,862 @@ var SBarcodeInput = react.forwardRef(
9812
9834
  }
9813
9835
  );
9814
9836
 
9837
+ // src/components/STimePicker/timepicker.config.ts
9838
+ var V2 = (path) => `var(--cmp-timepicker-${path})`;
9839
+ var TIMEPICKER_SIZES = ["sm", "md"];
9840
+ var TIMEPICKER_SIZE_CONFIG = {
9841
+ sm: {
9842
+ height: V2("sm-height"),
9843
+ paddingX: V2("sm-paddingX"),
9844
+ gap: V2("sm-gap"),
9845
+ icon: V2("sm-icon"),
9846
+ radius: V2("sm-radius"),
9847
+ // TODO: component.timepicker 토큰에 typography가 추가되면 CSS 변수로 교체한다.
9848
+ fontSize: 12,
9849
+ lineHeight: 20,
9850
+ minWidth: 80,
9851
+ fieldMinWidth: 128
9852
+ },
9853
+ md: {
9854
+ height: V2("md-height"),
9855
+ paddingX: V2("md-paddingX"),
9856
+ gap: V2("md-gap"),
9857
+ icon: V2("md-icon"),
9858
+ radius: V2("md-radius"),
9859
+ // TODO: component.timepicker 토큰에 typography가 추가되면 CSS 변수로 교체한다.
9860
+ fontSize: 14,
9861
+ lineHeight: 24,
9862
+ minWidth: 96,
9863
+ fieldMinWidth: 160
9864
+ }
9865
+ };
9866
+ function clampTimePart(value, min, max) {
9867
+ if (!Number.isFinite(value)) return min;
9868
+ return Math.min(Math.max(value, min), max);
9869
+ }
9870
+ function padTimePart(value) {
9871
+ return String(value).padStart(2, "0");
9872
+ }
9873
+ function parseTimeValue(value) {
9874
+ const match = /^(\d{1,2}):(\d{1,2})$/.exec(value ?? "");
9875
+ if (!match) return { hour: 0, minute: 0 };
9876
+ return {
9877
+ hour: clampTimePart(Number(match[1]), 0, 23),
9878
+ minute: clampTimePart(Number(match[2]), 0, 59)
9879
+ };
9880
+ }
9881
+ function formatTimeValue(hour, minute) {
9882
+ return `${padTimePart(clampTimePart(hour, 0, 23))}:${padTimePart(clampTimePart(minute, 0, 59))}`;
9883
+ }
9884
+ function formatTimeDisplay(value, type) {
9885
+ if (value == null || value === "") return "";
9886
+ const { hour, minute } = parseTimeValue(value);
9887
+ if (type === "default") return formatTimeValue(hour, minute);
9888
+ const meridiem = hour >= 12 ? "\uC624\uD6C4" : "\uC624\uC804";
9889
+ const displayHour = hour % 12 === 0 ? 12 : hour % 12;
9890
+ return `${meridiem} ${padTimePart(displayHour)}:${padTimePart(minute)}`;
9891
+ }
9892
+ function TimeSelector({
9893
+ value,
9894
+ useMeridiem,
9895
+ minuteStep,
9896
+ onChange
9897
+ }) {
9898
+ const parsed = react.useMemo(() => parseTimeValue(value), [value]);
9899
+ const [hour, setHour] = react.useState(parsed.hour);
9900
+ const [minute, setMinute] = react.useState(parsed.minute);
9901
+ const [editingPart, setEditingPart] = react.useState(null);
9902
+ const [inputDraft, setInputDraft] = react.useState({});
9903
+ react.useEffect(() => {
9904
+ setHour(parsed.hour);
9905
+ setMinute(parsed.minute);
9906
+ }, [parsed.hour, parsed.minute]);
9907
+ const meridiem = hour >= 12 ? "PM" : "AM";
9908
+ const displayHour = useMeridiem ? hour % 12 === 0 ? 12 : hour % 12 : hour;
9909
+ const commit = (nextHour, nextMinute) => {
9910
+ const h = clampTimePart(nextHour, 0, 23);
9911
+ const m = clampTimePart(nextMinute, 0, 59);
9912
+ setHour(h);
9913
+ setMinute(m);
9914
+ onChange(formatTimeValue(h, m));
9915
+ };
9916
+ const setMeridiem = (next) => {
9917
+ if (next === meridiem) return;
9918
+ commit(next === "AM" ? hour - 12 : hour + 12, minute);
9919
+ };
9920
+ const changeMinute = (delta) => {
9921
+ const next = minute + delta;
9922
+ if (next > 59) {
9923
+ commit((hour + 1) % 24, next - 60);
9924
+ return;
9925
+ }
9926
+ if (next < 0) {
9927
+ commit((hour + 23) % 24, next + 60);
9928
+ return;
9929
+ }
9930
+ commit(hour, next);
9931
+ };
9932
+ const changeHour = (delta) => commit((hour + delta + 24) % 24, minute);
9933
+ const sanitizeInput = (next) => next.replace(/\D/g, "").slice(0, 2);
9934
+ const beginEdit = (part, currentValue) => {
9935
+ setEditingPart(part);
9936
+ setInputDraft((prev) => ({ ...prev, [part]: String(currentValue).padStart(2, "0") }));
9937
+ };
9938
+ const commitHourDraft = (draft) => {
9939
+ const clamped = clampTimePart(Number(draft), useMeridiem ? 1 : 0, useMeridiem ? 12 : 23);
9940
+ const nextHour = useMeridiem ? meridiem === "PM" ? clamped === 12 ? 12 : clamped + 12 : clamped === 12 ? 0 : clamped : clamped;
9941
+ commit(nextHour, minute);
9942
+ return clamped;
9943
+ };
9944
+ const commitMinuteDraft = (draft) => {
9945
+ const clamped = clampTimePart(Number(draft), 0, 59);
9946
+ commit(hour, clamped);
9947
+ return clamped;
9948
+ };
9949
+ const endEdit = (part) => {
9950
+ const draft = inputDraft[part];
9951
+ if (part === "hour" && draft != null && draft !== "") {
9952
+ commitHourDraft(draft);
9953
+ }
9954
+ if (part === "minute" && draft != null && draft !== "") {
9955
+ commitMinuteDraft(draft);
9956
+ }
9957
+ setEditingPart(null);
9958
+ setInputDraft({});
9959
+ };
9960
+ const inputStyle = {
9961
+ width: "var(--cmp-timepicker-selector-input-width)",
9962
+ height: "var(--cmp-textinput-sm-height)",
9963
+ borderRadius: "var(--cmp-textinput-sm-radius)",
9964
+ border: "var(--cmp-textinput-borderWidth) solid var(--cmp-textinput-border-default)",
9965
+ color: "var(--cmp-textinput-text-default)",
9966
+ fontSize: 12,
9967
+ lineHeight: "20px"
9968
+ };
9969
+ const renderColumn = (type) => {
9970
+ const isHour = type === "hour";
9971
+ const val = isHour ? displayHour : minute;
9972
+ const displayValue = editingPart === type ? inputDraft[type] ?? "" : String(val).padStart(2, "0");
9973
+ return /* @__PURE__ */ jsxRuntime.jsxs(
9974
+ "div",
9975
+ {
9976
+ className: "flex flex-col items-center justify-center",
9977
+ style: { gap: "var(--cmp-timepicker-selector-time-column-gap)" },
9978
+ children: [
9979
+ /* @__PURE__ */ jsxRuntime.jsx(
9980
+ SGhostButton,
9981
+ {
9982
+ icon: "chevronUp",
9983
+ size: "xs",
9984
+ ariaLabel: `${isHour ? "\uC2DC" : "\uBD84"} \uC99D\uAC00`,
9985
+ onClick: () => isHour ? changeHour(1) : changeMinute(minuteStep)
9986
+ }
9987
+ ),
9988
+ /* @__PURE__ */ jsxRuntime.jsx(
9989
+ "input",
9990
+ {
9991
+ "aria-label": isHour ? "\uC2DC" : "\uBD84",
9992
+ inputMode: "numeric",
9993
+ value: displayValue,
9994
+ placeholder: "-",
9995
+ onFocus: () => beginEdit(type, val),
9996
+ onBlur: () => endEdit(type),
9997
+ onChange: (event) => {
9998
+ const draft = sanitizeInput(event.target.value);
9999
+ setInputDraft((prev) => ({ ...prev, [type]: draft }));
10000
+ if (draft === "") return;
10001
+ const raw = Number(draft);
10002
+ if (isHour) {
10003
+ if (draft.length < 2) return;
10004
+ const clamped2 = commitHourDraft(draft);
10005
+ const displayDraft2 = raw === clamped2 ? draft : String(clamped2);
10006
+ setInputDraft((prev) => ({ ...prev, [type]: displayDraft2 }));
10007
+ return;
10008
+ }
10009
+ if (draft.length < 2) return;
10010
+ const clamped = commitMinuteDraft(draft);
10011
+ const displayDraft = raw === clamped ? draft : String(clamped);
10012
+ setInputDraft((prev) => ({ ...prev, [type]: displayDraft }));
10013
+ },
10014
+ className: "box-border bg-white text-center outline-none",
10015
+ style: inputStyle
10016
+ }
10017
+ ),
10018
+ /* @__PURE__ */ jsxRuntime.jsx(
10019
+ SGhostButton,
10020
+ {
10021
+ icon: "chevronDown",
10022
+ size: "xs",
10023
+ ariaLabel: `${isHour ? "\uC2DC" : "\uBD84"} \uAC10\uC18C`,
10024
+ onClick: () => isHour ? changeHour(-1) : changeMinute(-minuteStep)
10025
+ }
10026
+ )
10027
+ ]
10028
+ }
10029
+ );
10030
+ };
10031
+ return /* @__PURE__ */ jsxRuntime.jsxs(
10032
+ "div",
10033
+ {
10034
+ className: "flex flex-col items-stretch justify-center overflow-hidden",
10035
+ style: {
10036
+ background: "var(--cmp-timepicker-selector-bg)",
10037
+ borderRadius: "var(--cmp-timepicker-selector-radius)",
10038
+ boxShadow: "4px 8px 16px -4px rgba(34,34,34,0.1), 0 0 24px -6px rgba(34,34,34,0.12)"
10039
+ },
10040
+ children: [
10041
+ useMeridiem && /* @__PURE__ */ jsxRuntime.jsx(
10042
+ "div",
10043
+ {
10044
+ className: "flex items-center justify-center",
10045
+ style: {
10046
+ padding: "var(--cmp-timepicker-selector-section-paddingY) var(--cmp-timepicker-selector-section-paddingX)"
10047
+ },
10048
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "isolate flex", children: ["AM", "PM"].map((item, index) => {
10049
+ const selected = item === meridiem;
10050
+ return /* @__PURE__ */ jsxRuntime.jsx(
10051
+ "button",
10052
+ {
10053
+ type: "button",
10054
+ onClick: () => setMeridiem(item),
10055
+ className: cn(
10056
+ "box-border h-[var(--cmp-textinput-sm-height)] w-[61px] cursor-pointer border border-solid bg-white text-center text-[12px] font-medium leading-[20px]",
10057
+ index === 0 ? "rounded-l-[var(--cmp-select-sm-radius)]" : "rounded-r-[var(--cmp-select-sm-radius)]",
10058
+ index === 0 ? "-mr-px" : "",
10059
+ selected ? "z-[1] border-[var(--cmp-timepicker-border-focus)] text-[var(--cmp-timepicker-border-focus)]" : "border-[var(--cmp-timepicker-border-default)] text-[var(--cmp-field-hint-color)]"
10060
+ ),
10061
+ children: item === "AM" ? "\uC624\uC804" : "\uC624\uD6C4"
10062
+ },
10063
+ item
10064
+ );
10065
+ }) })
10066
+ }
10067
+ ),
10068
+ useMeridiem && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-px w-full bg-[var(--sys-color-divider-default)]" }),
10069
+ /* @__PURE__ */ jsxRuntime.jsxs(
10070
+ "div",
10071
+ {
10072
+ className: "flex items-center justify-center",
10073
+ style: {
10074
+ gap: "var(--cmp-timepicker-selector-time-gap)",
10075
+ padding: "var(--cmp-timepicker-selector-section-paddingY) var(--cmp-timepicker-selector-section-paddingX)"
10076
+ },
10077
+ children: [
10078
+ renderColumn("hour"),
10079
+ /* @__PURE__ */ jsxRuntime.jsx(
10080
+ "span",
10081
+ {
10082
+ className: "text-center",
10083
+ style: {
10084
+ width: "var(--cmp-timepicker-selector-colon-size)",
10085
+ color: "var(--cmp-field-hint-color)",
10086
+ fontSize: "var(--cmp-timepicker-selector-colon-size)",
10087
+ lineHeight: "var(--cmp-timepicker-selector-colon-size)"
10088
+ },
10089
+ children: ":"
10090
+ }
10091
+ ),
10092
+ renderColumn("minute")
10093
+ ]
10094
+ }
10095
+ )
10096
+ ]
10097
+ }
10098
+ );
10099
+ }
10100
+ function STimePicker({
10101
+ value,
10102
+ onValueChange,
10103
+ onOpenChange,
10104
+ type = "default",
10105
+ size = "sm",
10106
+ placeholder = "00:00",
10107
+ disabled = false,
10108
+ clearable = false,
10109
+ useMeridiem,
10110
+ minuteStep = 1,
10111
+ width,
10112
+ name,
10113
+ rules,
10114
+ status,
10115
+ label,
10116
+ labelWidth,
10117
+ icon,
10118
+ iconColor,
10119
+ labelTooltip,
10120
+ labelTooltipProps,
10121
+ addonLabel,
10122
+ addonAlign,
10123
+ hint,
10124
+ error,
10125
+ errorMessage,
10126
+ className,
10127
+ style
10128
+ }) {
10129
+ const portalContainer = usePortalContainer();
10130
+ const [open, setOpen] = react.useState(false);
10131
+ const [focused, setFocused] = react.useState(false);
10132
+ const [ruleError, setRuleError] = react.useState("");
10133
+ const dims = TIMEPICKER_SIZE_CONFIG[size] ?? TIMEPICKER_SIZE_CONFIG.sm;
10134
+ const normalized = value ? formatTimeValue(parseTimeValue(value).hour, parseTimeValue(value).minute) : null;
10135
+ const effectiveUseMeridiem = useMeridiem ?? type === "midday";
10136
+ const displayText = formatTimeDisplay(normalized, effectiveUseMeridiem ? "midday" : "default");
10137
+ const hasValue = normalized != null && normalized !== "";
10138
+ useFormField({
10139
+ name,
10140
+ validate: () => {
10141
+ const msg = runRules(value, rules);
10142
+ setRuleError(msg);
10143
+ return msg === "";
10144
+ },
10145
+ resetValidation: () => setRuleError("")
10146
+ });
10147
+ const resolvedError = error || ruleError !== "";
10148
+ const resolvedStatus = status ?? (rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0);
10149
+ const commitOpen = (next) => {
10150
+ if (disabled) return;
10151
+ setOpen(next);
10152
+ onOpenChange?.(next);
10153
+ if (!next && rules && rules.length > 0) setRuleError(runRules(value, rules));
10154
+ };
10155
+ const commitValue = (next) => {
10156
+ onValueChange?.(next);
10157
+ if (rules && rules.length > 0) setRuleError(runRules(next, rules));
10158
+ };
10159
+ return /* @__PURE__ */ jsxRuntime.jsx(
10160
+ SField,
10161
+ {
10162
+ label,
10163
+ labelWidth,
10164
+ icon,
10165
+ iconColor,
10166
+ labelTooltip,
10167
+ labelTooltipProps,
10168
+ addonLabel,
10169
+ addonAlign,
10170
+ size,
10171
+ hint,
10172
+ error: resolvedError,
10173
+ status: resolvedStatus,
10174
+ focused: focused || open,
10175
+ errorMessage: ruleError !== "" ? ruleError : errorMessage,
10176
+ width,
10177
+ disabled,
10178
+ className,
10179
+ style: { minWidth: dims.fieldMinWidth, ...style },
10180
+ children: /* @__PURE__ */ jsxRuntime.jsxs(RPopover2__namespace.Root, { open, onOpenChange: commitOpen, children: [
10181
+ /* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
10182
+ "button",
10183
+ {
10184
+ type: "button",
10185
+ name,
10186
+ disabled,
10187
+ onFocus: () => setFocused(true),
10188
+ onBlur: () => setFocused(false),
10189
+ className: "flex h-full w-full items-center overflow-hidden bg-transparent outline-none disabled:cursor-not-allowed",
10190
+ style: { padding: `0 ${dims.paddingX}`, gap: dims.gap, borderRadius: dims.radius },
10191
+ children: [
10192
+ /* @__PURE__ */ jsxRuntime.jsx(
10193
+ SIcon,
10194
+ {
10195
+ name: "clockOutline",
10196
+ size: dims.icon,
10197
+ color: disabled ? "var(--cmp-timepicker-icon-disabled)" : "var(--cmp-timepicker-icon-default)",
10198
+ className: "flex-shrink-0"
10199
+ }
10200
+ ),
10201
+ /* @__PURE__ */ jsxRuntime.jsx(
10202
+ "span",
10203
+ {
10204
+ className: "flex-1 truncate text-center",
10205
+ style: {
10206
+ minWidth: dims.minWidth,
10207
+ fontSize: dims.fontSize,
10208
+ lineHeight: `${dims.lineHeight}px`,
10209
+ color: disabled ? "var(--cmp-timepicker-text-disabled)" : hasValue ? "var(--cmp-timepicker-text-default)" : "var(--cmp-field-hint-color)"
10210
+ },
10211
+ children: hasValue ? displayText : placeholder
10212
+ }
10213
+ ),
10214
+ clearable && hasValue && !disabled && /* @__PURE__ */ jsxRuntime.jsx(
10215
+ SGhostButton,
10216
+ {
10217
+ icon: "close",
10218
+ size: "xs",
10219
+ ariaLabel: "\uC2DC\uAC04 \uC9C0\uC6B0\uAE30",
10220
+ onClick: (event) => {
10221
+ event.stopPropagation();
10222
+ commitValue(null);
10223
+ }
10224
+ }
10225
+ )
10226
+ ]
10227
+ }
10228
+ ) }),
10229
+ /* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
10230
+ RPopover2__namespace.Content,
10231
+ {
10232
+ side: "bottom",
10233
+ align: "start",
10234
+ sideOffset: 4,
10235
+ className: cn("z-50", FLOATING_SLIDE_ANIM),
10236
+ children: /* @__PURE__ */ jsxRuntime.jsx(
10237
+ TimeSelector,
10238
+ {
10239
+ value: normalized,
10240
+ useMeridiem: effectiveUseMeridiem,
10241
+ minuteStep,
10242
+ onChange: commitValue
10243
+ }
10244
+ )
10245
+ }
10246
+ ) })
10247
+ ] })
10248
+ }
10249
+ );
10250
+ }
10251
+
10252
+ // src/components/STimeRangePicker/time-range-picker.config.ts
10253
+ function getTimeMinutes(value) {
10254
+ const { hour, minute } = parseTimeValue(value);
10255
+ return hour * 60 + minute;
10256
+ }
10257
+ function normalizeTimeRangeValue(value, rangeOrder = "strict") {
10258
+ if (value == null) return null;
10259
+ const normalized = value.map((item) => {
10260
+ const parsed = parseTimeValue(item);
10261
+ return formatTimeValue(parsed.hour, parsed.minute);
10262
+ });
10263
+ if (rangeOrder === "strict" && getTimeMinutes(normalized[0]) > getTimeMinutes(normalized[1])) {
10264
+ return [normalized[0], normalized[0]];
10265
+ }
10266
+ return normalized;
10267
+ }
10268
+ function formatTimeRangeDisplay(value, type) {
10269
+ if (value == null || value[0] === "" || value[1] === "") return "";
10270
+ return `${formatTimeDisplay(value[0], type)} ~ ${formatTimeDisplay(value[1], type)}`;
10271
+ }
10272
+ function RangeTimeSelector({
10273
+ value,
10274
+ useMeridiem,
10275
+ minuteStep,
10276
+ rangeOrder,
10277
+ onChange
10278
+ }) {
10279
+ const range = react.useMemo(() => value ?? ["00:00", "23:59"], [value]);
10280
+ const [editingKey, setEditingKey] = react.useState(null);
10281
+ const [inputDraft, setInputDraft] = react.useState({});
10282
+ const autoAdjustedRef = react.useRef(null);
10283
+ const getParts = (side) => parseTimeValue(side === "start" ? range[0] : range[1]);
10284
+ const getMeridiem = (side) => getParts(side).hour >= 12 ? "PM" : "AM";
10285
+ const getDisplayHour = (side) => {
10286
+ const { hour } = getParts(side);
10287
+ if (!useMeridiem) return hour;
10288
+ const displayHour = hour % 12;
10289
+ return displayHour === 0 ? 12 : displayHour;
10290
+ };
10291
+ const commit = (side, hour, minute, direction = "unknown") => {
10292
+ const next = formatTimeValue(hour, minute);
10293
+ onChange(normalizeNextRange(side === "start" ? [next, range[1]] : [range[0], next], side, direction));
10294
+ };
10295
+ const getTimeMinutes2 = (time) => {
10296
+ const { hour, minute } = parseTimeValue(time);
10297
+ return hour * 60 + minute;
10298
+ };
10299
+ const normalizeNextRange = (nextRange, changedSide, direction) => {
10300
+ if (rangeOrder === "allow-cross-day") return nextRange;
10301
+ const [start, end] = nextRange;
10302
+ const [currentStart, currentEnd] = range;
10303
+ if (getTimeMinutes2(start) <= getTimeMinutes2(end)) {
10304
+ const shouldKeepSynced = autoAdjustedRef.current?.side === changedSide && currentStart === currentEnd && start !== end && (direction === "unknown" || autoAdjustedRef.current.direction === direction);
10305
+ if (shouldKeepSynced) {
10306
+ return changedSide === "start" ? [start, start] : [end, end];
10307
+ }
10308
+ autoAdjustedRef.current = null;
10309
+ return nextRange;
10310
+ }
10311
+ autoAdjustedRef.current = {
10312
+ side: changedSide,
10313
+ direction: changedSide === "start" ? "increase" : "decrease"
10314
+ };
10315
+ return changedSide === "start" ? [start, start] : [end, end];
10316
+ };
10317
+ const changeHour = (side, delta) => {
10318
+ const { hour, minute } = getParts(side);
10319
+ commit(side, (hour + delta + 24) % 24, minute, delta > 0 ? "increase" : "decrease");
10320
+ };
10321
+ const changeMinute = (side, delta) => {
10322
+ const { hour, minute } = getParts(side);
10323
+ const next = minute + delta;
10324
+ if (next > 59) {
10325
+ commit(side, (hour + 1) % 24, next - 60, delta > 0 ? "increase" : "decrease");
10326
+ return;
10327
+ }
10328
+ if (next < 0) {
10329
+ commit(side, (hour + 23) % 24, next + 60, delta > 0 ? "increase" : "decrease");
10330
+ return;
10331
+ }
10332
+ commit(side, hour, next, delta > 0 ? "increase" : "decrease");
10333
+ };
10334
+ const setMeridiem = (side, next) => {
10335
+ const current = getMeridiem(side);
10336
+ if (current === next) return;
10337
+ const { hour, minute } = getParts(side);
10338
+ commit(side, next === "AM" ? hour - 12 : hour + 12, minute);
10339
+ };
10340
+ const getEditingKey = (side, part) => `${side}-${part}`;
10341
+ const sanitizeInput = (next) => next.replace(/\D/g, "").slice(0, 2);
10342
+ const beginEdit = (side, part, currentValue) => {
10343
+ const key = getEditingKey(side, part);
10344
+ setEditingKey(key);
10345
+ setInputDraft((prev) => ({ ...prev, [key]: String(currentValue).padStart(2, "0") }));
10346
+ };
10347
+ const commitHourDraft = (side, draft) => {
10348
+ const clamped = clampTimePart(Number(draft), useMeridiem ? 1 : 0, useMeridiem ? 12 : 23);
10349
+ const parts = getParts(side);
10350
+ const meridiem = getMeridiem(side);
10351
+ const nextHour = useMeridiem ? meridiem === "PM" ? clamped === 12 ? 12 : clamped + 12 : clamped === 12 ? 0 : clamped : clamped;
10352
+ commit(side, nextHour, parts.minute);
10353
+ return clamped;
10354
+ };
10355
+ const commitMinuteDraft = (side, draft) => {
10356
+ const { hour } = getParts(side);
10357
+ const clamped = clampTimePart(Number(draft), 0, 59);
10358
+ commit(side, hour, clamped);
10359
+ return clamped;
10360
+ };
10361
+ const endEdit = (side, part) => {
10362
+ const key = getEditingKey(side, part);
10363
+ const draft = inputDraft[key];
10364
+ if (part === "hour" && draft != null && draft !== "") {
10365
+ commitHourDraft(side, draft);
10366
+ }
10367
+ if (part === "minute" && draft != null && draft !== "") {
10368
+ commitMinuteDraft(side, draft);
10369
+ }
10370
+ setEditingKey(null);
10371
+ setInputDraft({});
10372
+ };
10373
+ const inputStyle = {
10374
+ width: "var(--cmp-timepicker-selector-input-width)",
10375
+ height: "var(--cmp-textinput-sm-height)",
10376
+ borderRadius: "var(--cmp-textinput-sm-radius)",
10377
+ border: "var(--cmp-textinput-borderWidth) solid var(--cmp-textinput-border-default)",
10378
+ color: "var(--cmp-textinput-text-default)",
10379
+ fontSize: 12,
10380
+ lineHeight: "20px"
10381
+ };
10382
+ const renderColumn = (side, kind) => {
10383
+ const isHour = kind === "hour";
10384
+ const { minute } = getParts(side);
10385
+ const val = isHour ? getDisplayHour(side) : minute;
10386
+ const currentEditingKey = getEditingKey(side, kind);
10387
+ const displayValue = editingKey === currentEditingKey ? inputDraft[currentEditingKey] ?? "" : String(val).padStart(2, "0");
10388
+ return /* @__PURE__ */ jsxRuntime.jsxs(
10389
+ "div",
10390
+ {
10391
+ className: "flex flex-col items-center justify-center",
10392
+ style: { gap: "var(--cmp-timepicker-selector-time-column-gap)" },
10393
+ children: [
10394
+ /* @__PURE__ */ jsxRuntime.jsx(
10395
+ SGhostButton,
10396
+ {
10397
+ icon: "chevronUp",
10398
+ size: "xs",
10399
+ ariaLabel: `${side === "start" ? "\uC2DC\uC791" : "\uC885\uB8CC"} ${isHour ? "\uC2DC" : "\uBD84"} \uC99D\uAC00`,
10400
+ onClick: () => isHour ? changeHour(side, 1) : changeMinute(side, minuteStep)
10401
+ }
10402
+ ),
10403
+ /* @__PURE__ */ jsxRuntime.jsx(
10404
+ "input",
10405
+ {
10406
+ "aria-label": `${side === "start" ? "\uC2DC\uC791" : "\uC885\uB8CC"} ${isHour ? "\uC2DC" : "\uBD84"}`,
10407
+ inputMode: "numeric",
10408
+ value: displayValue,
10409
+ placeholder: "-",
10410
+ onFocus: () => beginEdit(side, kind, val),
10411
+ onBlur: () => endEdit(side, kind),
10412
+ onChange: (event) => {
10413
+ const draft = sanitizeInput(event.target.value);
10414
+ setInputDraft((prev) => ({ ...prev, [currentEditingKey]: draft }));
10415
+ if (draft === "") return;
10416
+ const raw = Number(draft);
10417
+ if (isHour) {
10418
+ if (draft.length < 2) return;
10419
+ const clamped2 = commitHourDraft(side, draft);
10420
+ const displayDraft2 = raw === clamped2 ? draft : String(clamped2);
10421
+ setInputDraft((prev) => ({ ...prev, [currentEditingKey]: displayDraft2 }));
10422
+ return;
10423
+ }
10424
+ if (draft.length < 2) return;
10425
+ const clamped = commitMinuteDraft(side, draft);
10426
+ const displayDraft = raw === clamped ? draft : String(clamped);
10427
+ setInputDraft((prev) => ({ ...prev, [currentEditingKey]: displayDraft }));
10428
+ },
10429
+ className: "box-border bg-white text-center outline-none",
10430
+ style: inputStyle
10431
+ }
10432
+ ),
10433
+ /* @__PURE__ */ jsxRuntime.jsx(
10434
+ SGhostButton,
10435
+ {
10436
+ icon: "chevronDown",
10437
+ size: "xs",
10438
+ ariaLabel: `${side === "start" ? "\uC2DC\uC791" : "\uC885\uB8CC"} ${isHour ? "\uC2DC" : "\uBD84"} \uAC10\uC18C`,
10439
+ onClick: () => isHour ? changeHour(side, -1) : changeMinute(side, -minuteStep)
10440
+ }
10441
+ )
10442
+ ]
10443
+ }
10444
+ );
10445
+ };
10446
+ const renderPanel = (side, title) => /* @__PURE__ */ jsxRuntime.jsxs(
10447
+ "div",
10448
+ {
10449
+ className: "flex flex-col items-center justify-center",
10450
+ style: { gap: "var(--cmp-timepicker-selector-range-section-gap)" },
10451
+ children: [
10452
+ /* @__PURE__ */ jsxRuntime.jsxs(
10453
+ "div",
10454
+ {
10455
+ className: "flex flex-col items-center",
10456
+ style: { gap: "var(--cmp-timepicker-selector-range-heading-gap)" },
10457
+ children: [
10458
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "whitespace-nowrap text-center text-[12px] font-bold leading-[20px] text-[var(--cmp-timepicker-selector-range-heading-color)]", children: title }),
10459
+ useMeridiem && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "isolate flex", children: ["AM", "PM"].map((item, index) => {
10460
+ const selected = item === getMeridiem(side);
10461
+ return /* @__PURE__ */ jsxRuntime.jsx(
10462
+ "button",
10463
+ {
10464
+ type: "button",
10465
+ onClick: () => setMeridiem(side, item),
10466
+ className: cn(
10467
+ "box-border h-[var(--cmp-textinput-sm-height)] w-[61px] cursor-pointer border border-solid bg-white text-center text-[12px] font-medium leading-[20px]",
10468
+ index === 0 ? "rounded-l-[var(--cmp-select-sm-radius)] -mr-px" : "rounded-r-[var(--cmp-select-sm-radius)]",
10469
+ selected ? "z-[1] border-[var(--cmp-timepicker-border-focus)] text-[var(--cmp-timepicker-border-focus)]" : "border-[var(--cmp-timepicker-border-default)] text-[var(--cmp-field-hint-color)]"
10470
+ ),
10471
+ children: item === "AM" ? "\uC624\uC804" : "\uC624\uD6C4"
10472
+ },
10473
+ item
10474
+ );
10475
+ }) })
10476
+ ]
10477
+ }
10478
+ ),
10479
+ /* @__PURE__ */ jsxRuntime.jsxs(
10480
+ "div",
10481
+ {
10482
+ className: "flex items-center justify-center",
10483
+ style: {
10484
+ gap: "var(--cmp-timepicker-selector-time-gap)",
10485
+ padding: "0 var(--cmp-timepicker-selector-section-paddingX)"
10486
+ },
10487
+ children: [
10488
+ renderColumn(side, "hour"),
10489
+ /* @__PURE__ */ jsxRuntime.jsx(
10490
+ "span",
10491
+ {
10492
+ className: "text-center",
10493
+ style: {
10494
+ width: "var(--cmp-timepicker-selector-colon-size)",
10495
+ color: "var(--cmp-field-hint-color)",
10496
+ fontSize: "var(--cmp-timepicker-selector-colon-size)",
10497
+ lineHeight: "var(--cmp-timepicker-selector-colon-size)"
10498
+ },
10499
+ children: ":"
10500
+ }
10501
+ ),
10502
+ renderColumn(side, "minute")
10503
+ ]
10504
+ }
10505
+ )
10506
+ ]
10507
+ }
10508
+ );
10509
+ return /* @__PURE__ */ jsxRuntime.jsxs(
10510
+ "div",
10511
+ {
10512
+ className: "flex items-start justify-center overflow-hidden",
10513
+ style: {
10514
+ gap: "var(--cmp-timepicker-selector-range-panelGap)",
10515
+ padding: "var(--cmp-timepicker-selector-range-paddingXY)",
10516
+ background: "var(--cmp-timepicker-selector-bg)",
10517
+ borderRadius: "var(--cmp-timepicker-selector-radius)",
10518
+ boxShadow: "var(--shadow-spread-sm), var(--shadow-spread-md)"
10519
+ },
10520
+ children: [
10521
+ renderPanel("start", "\uC2DC\uC791 \uC2DC\uAC04"),
10522
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "self-stretch w-px bg-[var(--sys-color-divider-default)]" }),
10523
+ renderPanel("end", "\uC885\uB8CC \uC2DC\uAC04")
10524
+ ]
10525
+ }
10526
+ );
10527
+ }
10528
+ function STimeRangePicker({
10529
+ value,
10530
+ onValueChange,
10531
+ onOpenChange,
10532
+ type = "default",
10533
+ size = "sm",
10534
+ placeholder = "00:00 ~ 23:59",
10535
+ disabled = false,
10536
+ clearable = false,
10537
+ useMeridiem,
10538
+ minuteStep = 1,
10539
+ rangeOrder = "strict",
10540
+ width,
10541
+ name,
10542
+ rules,
10543
+ status,
10544
+ label,
10545
+ labelWidth,
10546
+ icon,
10547
+ iconColor,
10548
+ labelTooltip,
10549
+ labelTooltipProps,
10550
+ addonLabel,
10551
+ addonAlign,
10552
+ hint,
10553
+ error,
10554
+ errorMessage,
10555
+ className,
10556
+ style
10557
+ }) {
10558
+ const portalContainer = usePortalContainer();
10559
+ const [open, setOpen] = react.useState(false);
10560
+ const [focused, setFocused] = react.useState(false);
10561
+ const [ruleError, setRuleError] = react.useState("");
10562
+ const dims = TIMEPICKER_SIZE_CONFIG[size] ?? TIMEPICKER_SIZE_CONFIG.sm;
10563
+ const normalized = normalizeTimeRangeValue(value ?? null, rangeOrder);
10564
+ const effectiveUseMeridiem = useMeridiem ?? type === "midday";
10565
+ const displayText = formatTimeRangeDisplay(
10566
+ normalized,
10567
+ effectiveUseMeridiem ? "midday" : "default"
10568
+ );
10569
+ const hasValue = normalized != null && normalized[0] !== "" && normalized[1] !== "";
10570
+ useFormField({
10571
+ name,
10572
+ validate: () => {
10573
+ const msg = runRules(value, rules);
10574
+ setRuleError(msg);
10575
+ return msg === "";
10576
+ },
10577
+ resetValidation: () => setRuleError("")
10578
+ });
10579
+ const resolvedError = error || ruleError !== "";
10580
+ const resolvedStatus = status ?? (rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0);
10581
+ const commitOpen = (next) => {
10582
+ if (disabled) return;
10583
+ setOpen(next);
10584
+ onOpenChange?.(next);
10585
+ if (!next && rules && rules.length > 0) setRuleError(runRules(value, rules));
10586
+ };
10587
+ const commitValue = (next) => {
10588
+ onValueChange?.(next);
10589
+ if (rules && rules.length > 0) setRuleError(runRules(next, rules));
10590
+ };
10591
+ return /* @__PURE__ */ jsxRuntime.jsx(
10592
+ SField,
10593
+ {
10594
+ label,
10595
+ labelWidth,
10596
+ icon,
10597
+ iconColor,
10598
+ labelTooltip,
10599
+ labelTooltipProps,
10600
+ addonLabel,
10601
+ addonAlign,
10602
+ size,
10603
+ hint,
10604
+ error: resolvedError,
10605
+ status: resolvedStatus,
10606
+ focused: focused || open,
10607
+ errorMessage: ruleError !== "" ? ruleError : errorMessage,
10608
+ width,
10609
+ disabled,
10610
+ className,
10611
+ style: { minWidth: dims.fieldMinWidth, ...style },
10612
+ children: /* @__PURE__ */ jsxRuntime.jsxs(RPopover2__namespace.Root, { open, onOpenChange: commitOpen, children: [
10613
+ /* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
10614
+ "button",
10615
+ {
10616
+ type: "button",
10617
+ name,
10618
+ disabled,
10619
+ onFocus: () => setFocused(true),
10620
+ onBlur: () => setFocused(false),
10621
+ className: "flex h-full w-full items-center overflow-hidden bg-transparent outline-none disabled:cursor-not-allowed",
10622
+ style: { padding: `0 ${dims.paddingX}`, gap: dims.gap, borderRadius: dims.radius },
10623
+ children: [
10624
+ /* @__PURE__ */ jsxRuntime.jsx(
10625
+ SIcon,
10626
+ {
10627
+ name: "clockOutline",
10628
+ size: dims.icon,
10629
+ color: disabled ? "var(--cmp-timepicker-icon-disabled)" : "var(--cmp-timepicker-icon-default)",
10630
+ className: "flex-shrink-0"
10631
+ }
10632
+ ),
10633
+ /* @__PURE__ */ jsxRuntime.jsx(
10634
+ "span",
10635
+ {
10636
+ className: "flex-1 truncate text-center",
10637
+ style: {
10638
+ minWidth: dims.minWidth,
10639
+ fontSize: dims.fontSize,
10640
+ lineHeight: `${dims.lineHeight}px`,
10641
+ color: disabled ? "var(--cmp-timepicker-text-disabled)" : hasValue ? "var(--cmp-timepicker-text-default)" : "var(--cmp-field-hint-color)"
10642
+ },
10643
+ children: hasValue ? displayText : placeholder
10644
+ }
10645
+ ),
10646
+ clearable && hasValue && !disabled && /* @__PURE__ */ jsxRuntime.jsx(
10647
+ SGhostButton,
10648
+ {
10649
+ icon: "close",
10650
+ size: "xs",
10651
+ ariaLabel: "\uC2DC\uAC04 \uBC94\uC704 \uC9C0\uC6B0\uAE30",
10652
+ onClick: (event) => {
10653
+ event.stopPropagation();
10654
+ commitValue(null);
10655
+ }
10656
+ }
10657
+ )
10658
+ ]
10659
+ }
10660
+ ) }),
10661
+ /* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
10662
+ RPopover2__namespace.Content,
10663
+ {
10664
+ side: "bottom",
10665
+ align: "start",
10666
+ sideOffset: 4,
10667
+ className: cn("z-50", FLOATING_SLIDE_ANIM),
10668
+ children: /* @__PURE__ */ jsxRuntime.jsx(
10669
+ RangeTimeSelector,
10670
+ {
10671
+ value: normalized,
10672
+ useMeridiem: effectiveUseMeridiem,
10673
+ minuteStep,
10674
+ rangeOrder,
10675
+ onChange: commitValue
10676
+ }
10677
+ )
10678
+ }
10679
+ ) })
10680
+ ] })
10681
+ }
10682
+ );
10683
+ }
10684
+
9815
10685
  exports.BADGE_COLORS = BADGE_COLORS;
9816
10686
  exports.BUTTON_COLORS = BUTTON_COLORS;
9817
10687
  exports.BUTTON_SIZES = BUTTON_SIZES;
9818
10688
  exports.COLOR_KEYS = COLOR_KEYS;
9819
10689
  exports.GNB_COLORS = GNB_COLORS;
9820
10690
  exports.GNB_COMMON = GNB_COMMON;
9821
- exports.GNB_LAYOUT = GNB_LAYOUT;
10691
+ exports.GNB_HEADER = GNB_HEADER;
10692
+ exports.GNB_MENU = GNB_MENU;
9822
10693
  exports.GNB_MENU_WIDTH = GNB_MENU_WIDTH;
9823
10694
  exports.ICONS = ICONS;
9824
10695
  exports.SActionModal = SActionModal;
@@ -9868,6 +10739,8 @@ exports.STabs = STabs;
9868
10739
  exports.STag = STag;
9869
10740
  exports.STextLink = STextLink;
9870
10741
  exports.STextarea = STextarea;
10742
+ exports.STimePicker = STimePicker;
10743
+ exports.STimeRangePicker = STimeRangePicker;
9871
10744
  exports.SToast = SToast;
9872
10745
  exports.SToastContainer = SToastContainer;
9873
10746
  exports.SToggle = SToggle;
@@ -9875,6 +10748,8 @@ exports.STooltip = STooltip;
9875
10748
  exports.TAG_COLORS = TAG_COLORS;
9876
10749
  exports.TAG_SHAPES = TAG_SHAPES;
9877
10750
  exports.TAG_SIZES = TAG_SIZES;
10751
+ exports.TIMEPICKER_SIZES = TIMEPICKER_SIZES;
10752
+ exports.TIMEPICKER_SIZE_CONFIG = TIMEPICKER_SIZE_CONFIG;
9878
10753
  exports.buttonPreset = buttonPreset;
9879
10754
  exports.cn = cn;
9880
10755
  exports.findGnbAncestors = findGnbAncestors;