sellmate-design-system-react 0.1.7 → 0.1.9

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 (146) hide show
  1. package/dist/components/SActionModal/SActionModal.cjs +11 -3
  2. package/dist/components/SActionModal/SActionModal.cjs.map +1 -1
  3. package/dist/components/SActionModal/SActionModal.js +11 -3
  4. package/dist/components/SActionModal/SActionModal.js.map +1 -1
  5. package/dist/components/SBarcodeInput/SBarcodeInput.cjs +226 -209
  6. package/dist/components/SBarcodeInput/SBarcodeInput.cjs.map +1 -1
  7. package/dist/components/SBarcodeInput/SBarcodeInput.js +226 -209
  8. package/dist/components/SBarcodeInput/SBarcodeInput.js.map +1 -1
  9. package/dist/components/SCalendar/SCalendar.cjs +9 -1
  10. package/dist/components/SCalendar/SCalendar.cjs.map +1 -1
  11. package/dist/components/SCalendar/SCalendar.js +9 -1
  12. package/dist/components/SCalendar/SCalendar.js.map +1 -1
  13. package/dist/components/SChip/SChip.cjs +9 -1
  14. package/dist/components/SChip/SChip.cjs.map +1 -1
  15. package/dist/components/SChip/SChip.d.ts +1 -1
  16. package/dist/components/SChip/SChip.js +9 -1
  17. package/dist/components/SChip/SChip.js.map +1 -1
  18. package/dist/components/SChipInput/SChipInput.cjs +260 -235
  19. package/dist/components/SChipInput/SChipInput.cjs.map +1 -1
  20. package/dist/components/SChipInput/SChipInput.js +259 -235
  21. package/dist/components/SChipInput/SChipInput.js.map +1 -1
  22. package/dist/components/SCircleProgress/SCircleProgress.cjs +56 -58
  23. package/dist/components/SCircleProgress/SCircleProgress.cjs.map +1 -1
  24. package/dist/components/SCircleProgress/SCircleProgress.js +56 -58
  25. package/dist/components/SCircleProgress/SCircleProgress.js.map +1 -1
  26. package/dist/components/SConfirmModal/SConfirmModal.cjs +9 -1
  27. package/dist/components/SConfirmModal/SConfirmModal.cjs.map +1 -1
  28. package/dist/components/SConfirmModal/SConfirmModal.js +9 -1
  29. package/dist/components/SConfirmModal/SConfirmModal.js.map +1 -1
  30. package/dist/components/SDatePicker/SDatePicker.cjs +247 -221
  31. package/dist/components/SDatePicker/SDatePicker.cjs.map +1 -1
  32. package/dist/components/SDatePicker/SDatePicker.js +247 -221
  33. package/dist/components/SDatePicker/SDatePicker.js.map +1 -1
  34. package/dist/components/SDateRangePicker/SDateRangePicker.cjs +308 -256
  35. package/dist/components/SDateRangePicker/SDateRangePicker.cjs.map +1 -1
  36. package/dist/components/SDateRangePicker/SDateRangePicker.js +308 -256
  37. package/dist/components/SDateRangePicker/SDateRangePicker.js.map +1 -1
  38. package/dist/components/SDropdownButton/SDropdownButton.cjs +51 -4
  39. package/dist/components/SDropdownButton/SDropdownButton.cjs.map +1 -1
  40. package/dist/components/SDropdownButton/SDropdownButton.js +52 -5
  41. package/dist/components/SDropdownButton/SDropdownButton.js.map +1 -1
  42. package/dist/components/SField/SField.cjs +226 -21
  43. package/dist/components/SField/SField.cjs.map +1 -1
  44. package/dist/components/SField/SField.d.ts +11 -0
  45. package/dist/components/SField/SField.js +226 -21
  46. package/dist/components/SField/SField.js.map +1 -1
  47. package/dist/components/SFilePicker/SFilePicker.cjs +306 -278
  48. package/dist/components/SFilePicker/SFilePicker.cjs.map +1 -1
  49. package/dist/components/SFilePicker/SFilePicker.d.ts +4 -2
  50. package/dist/components/SFilePicker/SFilePicker.js +306 -278
  51. package/dist/components/SFilePicker/SFilePicker.js.map +1 -1
  52. package/dist/components/SGhostButton/SGhostButton.cjs +8 -0
  53. package/dist/components/SGhostButton/SGhostButton.cjs.map +1 -1
  54. package/dist/components/SGhostButton/SGhostButton.js +8 -0
  55. package/dist/components/SGhostButton/SGhostButton.js.map +1 -1
  56. package/dist/components/SGuide/SGuide.cjs +12 -1
  57. package/dist/components/SGuide/SGuide.cjs.map +1 -1
  58. package/dist/components/SGuide/SGuide.js +12 -1
  59. package/dist/components/SGuide/SGuide.js.map +1 -1
  60. package/dist/components/SInput/SInput.cjs +226 -209
  61. package/dist/components/SInput/SInput.cjs.map +1 -1
  62. package/dist/components/SInput/SInput.js +226 -209
  63. package/dist/components/SInput/SInput.js.map +1 -1
  64. package/dist/components/SKeyValueTable/SKeyValueTable.cjs +640 -453
  65. package/dist/components/SKeyValueTable/SKeyValueTable.cjs.map +1 -1
  66. package/dist/components/SKeyValueTable/SKeyValueTable.d.ts +3 -1
  67. package/dist/components/SKeyValueTable/SKeyValueTable.js +640 -453
  68. package/dist/components/SKeyValueTable/SKeyValueTable.js.map +1 -1
  69. package/dist/components/SLoadingContainer/SLoadingContainer.cjs +64 -58
  70. package/dist/components/SLoadingContainer/SLoadingContainer.cjs.map +1 -1
  71. package/dist/components/SLoadingContainer/SLoadingContainer.js +64 -58
  72. package/dist/components/SLoadingContainer/SLoadingContainer.js.map +1 -1
  73. package/dist/components/SLoadingContainer/loading.cjs +64 -58
  74. package/dist/components/SLoadingContainer/loading.cjs.map +1 -1
  75. package/dist/components/SLoadingContainer/loading.js +64 -58
  76. package/dist/components/SLoadingContainer/loading.js.map +1 -1
  77. package/dist/components/SLoadingModal/SLoadingModal.cjs +68 -61
  78. package/dist/components/SLoadingModal/SLoadingModal.cjs.map +1 -1
  79. package/dist/components/SLoadingModal/SLoadingModal.js +68 -61
  80. package/dist/components/SLoadingModal/SLoadingModal.js.map +1 -1
  81. package/dist/components/SModalContainer/SModalContainer.cjs +9 -1
  82. package/dist/components/SModalContainer/SModalContainer.cjs.map +1 -1
  83. package/dist/components/SModalContainer/SModalContainer.js +9 -1
  84. package/dist/components/SModalContainer/SModalContainer.js.map +1 -1
  85. package/dist/components/SNumberInput/SNumberInput.cjs +334 -50
  86. package/dist/components/SNumberInput/SNumberInput.cjs.map +1 -1
  87. package/dist/components/SNumberInput/SNumberInput.d.ts +2 -0
  88. package/dist/components/SNumberInput/SNumberInput.js +334 -50
  89. package/dist/components/SNumberInput/SNumberInput.js.map +1 -1
  90. package/dist/components/SPagination/SPagination.cjs +1 -1
  91. package/dist/components/SPagination/SPagination.cjs.map +1 -1
  92. package/dist/components/SPagination/SPagination.js +1 -1
  93. package/dist/components/SPagination/SPagination.js.map +1 -1
  94. package/dist/components/SPopover/SPopover.cjs +20 -3
  95. package/dist/components/SPopover/SPopover.cjs.map +1 -1
  96. package/dist/components/SPopover/SPopover.js +20 -4
  97. package/dist/components/SPopover/SPopover.js.map +1 -1
  98. package/dist/components/SPopup/SPopup.cjs +2 -2
  99. package/dist/components/SPopup/SPopup.cjs.map +1 -1
  100. package/dist/components/SPopup/SPopup.js +2 -2
  101. package/dist/components/SPopup/SPopup.js.map +1 -1
  102. package/dist/components/SPortal/SPortal.cjs +8 -0
  103. package/dist/components/SPortal/SPortal.cjs.map +1 -1
  104. package/dist/components/SPortal/SPortal.js +8 -0
  105. package/dist/components/SPortal/SPortal.js.map +1 -1
  106. package/dist/components/SSelect/SSelect.cjs +76 -32
  107. package/dist/components/SSelect/SSelect.cjs.map +1 -1
  108. package/dist/components/SSelect/SSelect.js +76 -32
  109. package/dist/components/SSelect/SSelect.js.map +1 -1
  110. package/dist/components/STable/STable.cjs +133 -91
  111. package/dist/components/STable/STable.cjs.map +1 -1
  112. package/dist/components/STable/STable.js +133 -91
  113. package/dist/components/STable/STable.js.map +1 -1
  114. package/dist/components/STextLink/STextLink.cjs +137 -3
  115. package/dist/components/STextLink/STextLink.cjs.map +1 -1
  116. package/dist/components/STextLink/STextLink.d.ts +1 -1
  117. package/dist/components/STextLink/STextLink.js +118 -4
  118. package/dist/components/STextLink/STextLink.js.map +1 -1
  119. package/dist/components/STextarea/STextarea.cjs +226 -21
  120. package/dist/components/STextarea/STextarea.cjs.map +1 -1
  121. package/dist/components/STextarea/STextarea.js +226 -21
  122. package/dist/components/STextarea/STextarea.js.map +1 -1
  123. package/dist/components/SToast/SToast.cjs +8 -0
  124. package/dist/components/SToast/SToast.cjs.map +1 -1
  125. package/dist/components/SToast/SToast.js +8 -0
  126. package/dist/components/SToast/SToast.js.map +1 -1
  127. package/dist/components/SToast/SToastContainer.cjs +11 -3
  128. package/dist/components/SToast/SToastContainer.cjs.map +1 -1
  129. package/dist/components/SToast/SToastContainer.js +11 -3
  130. package/dist/components/SToast/SToastContainer.js.map +1 -1
  131. package/dist/components/STooltip/STooltip.cjs +217 -14
  132. package/dist/components/STooltip/STooltip.cjs.map +1 -1
  133. package/dist/components/STooltip/STooltip.js +217 -14
  134. package/dist/components/STooltip/STooltip.js.map +1 -1
  135. package/dist/index.cjs +532 -300
  136. package/dist/index.cjs.map +1 -1
  137. package/dist/index.js +531 -300
  138. package/dist/index.js.map +1 -1
  139. package/dist/lib/floating-anim.cjs +8 -0
  140. package/dist/lib/floating-anim.cjs.map +1 -1
  141. package/dist/lib/floating-anim.d.ts +5 -1
  142. package/dist/lib/floating-anim.js +8 -0
  143. package/dist/lib/floating-anim.js.map +1 -1
  144. package/dist/styles.css +175 -66
  145. package/dist/theme.css +49 -22
  146. package/package.json +1 -1
@@ -41,12 +41,20 @@ function cn(...inputs) {
41
41
  // src/lib/floating-anim.ts
42
42
  var FLOATING_SLIDE_ANIM = [
43
43
  "data-[state=open]:data-[side=top]:animate-floating-in-top",
44
+ "data-[state=delayed-open]:data-[side=top]:animate-floating-in-top",
45
+ "data-[state=instant-open]:data-[side=top]:animate-floating-in-top",
44
46
  "data-[state=closed]:data-[side=top]:animate-floating-out-top",
45
47
  "data-[state=open]:data-[side=bottom]:animate-floating-in-bottom",
48
+ "data-[state=delayed-open]:data-[side=bottom]:animate-floating-in-bottom",
49
+ "data-[state=instant-open]:data-[side=bottom]:animate-floating-in-bottom",
46
50
  "data-[state=closed]:data-[side=bottom]:animate-floating-out-bottom",
47
51
  "data-[state=open]:data-[side=left]:animate-floating-in-left",
52
+ "data-[state=delayed-open]:data-[side=left]:animate-floating-in-left",
53
+ "data-[state=instant-open]:data-[side=left]:animate-floating-in-left",
48
54
  "data-[state=closed]:data-[side=left]:animate-floating-out-left",
49
55
  "data-[state=open]:data-[side=right]:animate-floating-in-right",
56
+ "data-[state=delayed-open]:data-[side=right]:animate-floating-in-right",
57
+ "data-[state=instant-open]:data-[side=right]:animate-floating-in-right",
50
58
  "data-[state=closed]:data-[side=right]:animate-floating-out-right"
51
59
  ].join(" ");
52
60
  var PortalContainerContext = react.createContext(null);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/cn.ts","../../../src/lib/floating-anim.ts","../../../src/lib/portal-container.tsx","../../../src/components/SPortal/SPortal.tsx"],"names":["extendTailwindMerge","clsx","createContext","useContext","jsxs","RPopover","jsx"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQA,IAAM,UAAUA,iCAAA,CAAoB;AAAA,EAClC,MAAA,EAAQ;AAAA,IACN,WAAA,EAAa;AAAA,MACX,aAAa,CAAC,EAAE,IAAA,EAAM,CAAC,MAAM,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,MAAM,IAAA,EAAM,IAAA,EAAM,MAAM,IAAA,EAAM,IAAI,GAAG;AAAA;AAC5F;AAEJ,CAAC,CAAA;AAMM,SAAS,MAAM,MAAA,EAA8B;AAClD,EAAA,OAAO,OAAA,CAAQC,SAAA,CAAK,MAAM,CAAC,CAAA;AAC7B;;;ACfO,IAAM,mBAAA,GAAsB;AAAA,EACjC,2DAAA;AAAA,EACA,8DAAA;AAAA,EACA,iEAAA;AAAA,EACA,oEAAA;AAAA,EACA,6DAAA;AAAA,EACA,gEAAA;AAAA,EACA,+DAAA;AAAA,EACA;AACF,CAAA,CAAE,KAAK,GAAG,CAAA;ACFV,IAAM,sBAAA,GAAyBC,oBAAkC,IAAI,CAAA;AAE9B,sBAAA,CAAuB;AAOvD,SAAS,kBAAA,GAA8C;AAC5D,EAAA,OAAOC,gBAAA,CAAW,sBAAsB,CAAA,IAAK,MAAA;AAC/C;ACqCO,SAAS,OAAA,CAAQ;AAAA,EACtB,IAAA;AAAA,EACA,OAAA;AAAA,EACA,YAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA,GAAY,QAAA;AAAA,EACZ,KAAA,GAAQ,OAAA;AAAA,EACR,MAAA,GAAS,CAAA;AAAA,EACT,WAAA,GAAc,CAAA;AAAA,EACd,GAAA,GAAM,KAAA;AAAA,EACN,SAAA;AAAA,EACA,SAAA,GAAY,KAAA;AAAA,EACZ,UAAA,GAAa,KAAA;AAAA,EACb,eAAA,GAAkB,CAAA;AAAA,EAClB,eAAA;AAAA,EACA,gBAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CAAA,EAAiB;AACf,EAAA,MAAM,kBAAkB,kBAAA,EAAmB;AAE3C,EAAA,uBACEC,eAAA;AAAA,IAAUC,mBAAA,CAAA,IAAA;AAAA,IAAT;AAAA,MACC,IAAA;AAAA,MACA,cAAc,CAAA,IAAA,KAAQ;AACpB,QAAA,YAAA,GAAe,IAAI,CAAA;AACnB,QAAA,IAAI,CAAC,MAAM,OAAA,IAAU;AAAA,MACvB,CAAA;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAAC,cAAA,CAAUD,mBAAA,CAAA,MAAA,EAAT,EAAgB,UAAA,EAAY,SAAA,EAAoC,CAAA;AAAA,wBACjEC,cAAA,CAAUD,mBAAA,CAAA,MAAA,EAAT,EAAgB,SAAA,EAAW,eAAA,EAC1B,QAAA,kBAAAC,cAAA;AAAA,UAAUD,mBAAA,CAAA,OAAA;AAAA,UAAT;AAAA,YACC,IAAA,EAAM,SAAA;AAAA,YACN,KAAA;AAAA,YACA,UAAA,EAAY,MAAA;AAAA,YACZ,WAAA;AAAA,YACA,gBAAA,EAAkB,eAAA;AAAA,YAClB,YAAA,EAAY,SAAA;AAAA,YAGZ,sBAAsB,CAAA,CAAA,KAAK;AACzB,cAAA,IAAI,cAAc,SAAA,CAAU,OAAA,EAAS,QAAA,CAAS,CAAA,CAAE,MAAc,CAAA,EAAG;AAC/D,gBAAA,CAAA,CAAE,cAAA,EAAe;AAAA,cACnB;AAAA,YACF,CAAA;AAAA,YAGA,gBAAgB,CAAA,CAAA,KAAK;AACnB,cAAA,IAAI,cAAc,SAAA,CAAU,OAAA,EAAS,QAAA,CAAS,CAAA,CAAE,MAAc,CAAA,EAAG;AAC/D,gBAAA,CAAA,CAAE,cAAA,EAAe;AAAA,cACnB;AAAA,YACF,CAAA;AAAA,YACA,eAAA,EAAiB,UAAA,GAAa,CAAA,CAAA,KAAK,CAAA,CAAE,gBAAe,GAAI,MAAA;AAAA,YACxD,eAAA;AAAA,YACA,gBAAA;AAAA,YACA,OAAA,EAAS,SAAA,GAAY,MAAM,OAAA,IAAU,GAAI,MAAA;AAAA,YACzC,SAAA,EAAW,EAAA;AAAA,cACT,iGAAA;AAAA,cACA,aAAa,IAAA,IAAQ,iBAAA;AAAA,cACrB,GAAA,IAAO,uCAAA;AAAA,cACP,mBAAA;AAAA,cACA;AAAA,aACF;AAAA,YACA,KAAA,EAAO,EAAE,SAAA,EAAW,GAAG,KAAA,EAAM;AAAA,YAE5B;AAAA;AAAA,SACH,EACF;AAAA;AAAA;AAAA,GACF;AAEJ;AAEA,OAAA,CAAQ,WAAA,GAAc,SAAA","file":"SPortal.cjs","sourcesContent":["import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\n/**\n * theme.css 의 --text-* 는 기본 Tailwind 폰트사이즈 스케일(xs/sm/base...)이 아닌\n * 숫자 스케일(10~32)이라, 확장 없이는 tailwind-merge 가 이를 텍스트 컬러 그룹으로\n * 오인해 text-12 같은 클래스를 text-(--color-var) 뒤에서 충돌 제거해버린다.\n */\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n 'font-size': [{ text: ['10', '11', '12', '13', '14', '16', '18', '20', '24', '28', '32'] }],\n },\n },\n});\n\n/**\n * className 병합 유틸.\n * clsx로 조건부 클래스를 합치고, tailwind-merge로 Tailwind 클래스 충돌을 해소한다.\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","/**\n * Radix Floating(SPopover/STooltip) Content 의 placement 방향별 슬라이드+페이드.\n * Radix 가 붙이는 data-side(실제 렌더 방향)·data-state 에 맞춰 열림/닫힘 애니메이션을 적용한다.\n * (sd-floating-portal 의 sd-floating-slide-* 포팅 — 키프레임은 theme.css `--animate-floating-*`)\n *\n * 예: side=top 이면 아래(4px)에서 위로 올라오며 나타나고, 닫힐 때 다시 내려가며 사라진다.\n */\nexport const FLOATING_SLIDE_ANIM = [\n 'data-[state=open]:data-[side=top]:animate-floating-in-top',\n 'data-[state=closed]:data-[side=top]:animate-floating-out-top',\n 'data-[state=open]:data-[side=bottom]:animate-floating-in-bottom',\n 'data-[state=closed]:data-[side=bottom]:animate-floating-out-bottom',\n 'data-[state=open]:data-[side=left]:animate-floating-in-left',\n 'data-[state=closed]:data-[side=left]:animate-floating-out-left',\n 'data-[state=open]:data-[side=right]:animate-floating-in-right',\n 'data-[state=closed]:data-[side=right]:animate-floating-out-right',\n].join(' ');\n","'use client';\n\nimport { createContext, useContext } from 'react';\n\n/**\n * Floating 컴포넌트(STooltip/SPopover/SSelect listbox/SDropdownButton/SDatePicker 등)가\n * 자신의 Portal 을 어디로 렌더할지 결정하는 컨텍스트.\n *\n * 기본값(null)이면 각 컴포넌트는 body 로 portal 한다.\n * SModalContainer 는 모달이 열려있는 동안 이 값을 \"모달 스태킹 밴드(z-1001) 안의 전용 노드\"로\n * 채워서, 모달 안에서 열린 floating 이 모달 딤(z-1000) 뒤에 가려지지 않고 위로 뜨게 한다.\n * 반대로 모달 밖(베이스 화면)에서 열린 floating 은 여전히 body(z-50)로 나가므로,\n * 나중에 뜬 모달이 정상적으로 그 위를 덮는다. (소속에 따라 상대적으로 결정)\n */\nconst PortalContainerContext = createContext<HTMLElement | null>(null);\n\nexport const PortalContainerProvider = PortalContainerContext.Provider;\n\n/**\n * 현재 소속된 Portal 컨테이너를 반환한다.\n * Radix `*.Portal` 의 `container`, Ariakit 의 `portalElement` 에 그대로 넘기면 되며,\n * 컨테이너가 없을 때(모달 밖)는 `undefined` 를 반환해 각 라이브러리 기본값(body)을 쓴다.\n */\nexport function usePortalContainer(): HTMLElement | undefined {\n return useContext(PortalContainerContext) ?? undefined;\n}\n","'use client';\n\nimport { type CSSProperties, type ReactNode, type RefObject } from 'react';\nimport * as RPopover from '@radix-ui/react-popover';\nimport { cn } from '../../lib/cn';\nimport { FLOATING_SLIDE_ANIM } from '../../lib/floating-anim';\nimport { usePortalContainer } from '../../lib/portal-container';\n\nexport type SPortalPlacement = 'top' | 'bottom' | 'left' | 'right';\nexport type SPortalAlign = 'start' | 'center' | 'end';\n\n/** Radix Anchor 가 위치 계산에 쓰는 최소 인터페이스 (HTMLElement 가 충족한다). */\ntype Measurable = { getBoundingClientRect(): DOMRect };\n\nexport interface SPortalProps {\n /** 표시 여부 (제어). onClose 와 함께 사용한다. */\n open: boolean;\n /** 외부 클릭 · ESC 등으로 닫힘이 요청될 때 (sd-portal `sdClose` 대응). */\n onClose?: () => void;\n /** 열림/닫힘 변경 전체 콜백 (선택). */\n onOpenChange?: (open: boolean) => void;\n /**\n * 위치 기준이 되는 앵커 엘리먼트 ref (sd-portal `parentRef` 대응).\n * 트리거 버튼 등에 그대로 걸면 그 엘리먼트에 붙어서 뜬다.\n */\n anchorRef: RefObject<HTMLElement | null>;\n /** 표시 방향 (공간이 부족하면 자동으로 반대 방향으로 전환). */\n placement?: SPortalPlacement;\n /** 교차축 정렬 (start·center·end). */\n align?: SPortalAlign;\n /** 앵커로부터의 간격 px (sd-portal offset[1]). */\n offset?: number;\n /** 정렬축 오프셋 px (sd-portal offset[0]). */\n alignOffset?: number;\n /** 앵커 너비에 맞춰 최소 너비를 잡는다. */\n fit?: boolean;\n /** 콘텐츠 최대 높이 px. 넘치면 세로 스크롤. */\n maxHeight?: number;\n /** 콘텐츠 내부를 클릭하면 자동으로 닫는다. */\n autoClose?: boolean;\n /** 외부 클릭 · ESC 로 닫히지 않게 한다. */\n persistent?: boolean;\n /** 뷰포트 경계 여백 px (충돌 회피 패딩). */\n viewportPadding?: number;\n /** 열릴 때 포커스 이동 처리 (기본은 Radix가 콘텐츠로 포커스를 옮김). e.preventDefault()로 막을 수 있다. */\n onOpenAutoFocus?: (event: Event) => void;\n /** 닫힐 때 포커스 복귀 처리 (기본은 Radix가 앵커로 포커스를 되돌림). e.preventDefault()로 막을 수 있다. */\n onCloseAutoFocus?: (event: Event) => void;\n /** 본문 내용 (콘텐츠 자유). */\n children?: ReactNode;\n className?: string;\n style?: CSSProperties;\n ariaLabel?: string;\n}\n\n/**\n * SPortal — sd-portal/sd-floating-portal 의 사용성을 Radix Popover 로 옮긴 범용 앵커드 플로팅 컨테이너.\n *\n * 트리거를 감싸지 않고 `anchorRef` 로 임의의 엘리먼트에 붙는다(=sd-portal `parentRef`).\n * open/onClose 로 외부에서 제어하며, flip·collision·스크롤 재배치·외부클릭·ESC·모달 포털은\n * Radix 가 처리한다. 콘텐츠는 children 으로 완전히 자유롭다.\n */\nexport function SPortal({\n open,\n onClose,\n onOpenChange,\n anchorRef,\n placement = 'bottom',\n align = 'start',\n offset = 4,\n alignOffset = 0,\n fit = false,\n maxHeight,\n autoClose = false,\n persistent = false,\n viewportPadding = 0,\n onOpenAutoFocus,\n onCloseAutoFocus,\n children,\n className,\n style,\n ariaLabel,\n}: SPortalProps) {\n const portalContainer = usePortalContainer();\n\n return (\n <RPopover.Root\n open={open}\n onOpenChange={next => {\n onOpenChange?.(next);\n if (!next) onClose?.();\n }}\n >\n <RPopover.Anchor virtualRef={anchorRef as RefObject<Measurable>} />\n <RPopover.Portal container={portalContainer}>\n <RPopover.Content\n side={placement}\n align={align}\n sideOffset={offset}\n alignOffset={alignOffset}\n collisionPadding={viewportPadding}\n aria-label={ariaLabel}\n // persistent: 외부 클릭·ESC 로 닫히지 않음\n // 아니면: 앵커(트리거) 위 클릭은 소비자가 토글하므로 여기서 닫지 않는다(중복 토글 방지)\n onPointerDownOutside={e => {\n if (persistent || anchorRef.current?.contains(e.target as Node)) {\n e.preventDefault();\n }\n }}\n // 앵커(예: input)에 이미 포커스가 있는 상태로 열리는 경우(클릭 즉시 오픈), Radix는 포커스가\n // 레이어 밖에 있다고 판단해 열리자마자 닫아버린다 — 앵커 내부 포커스는 outside로 취급하지 않는다.\n onFocusOutside={e => {\n if (persistent || anchorRef.current?.contains(e.target as Node)) {\n e.preventDefault();\n }\n }}\n onEscapeKeyDown={persistent ? e => e.preventDefault() : undefined}\n onOpenAutoFocus={onOpenAutoFocus}\n onCloseAutoFocus={onCloseAutoFocus}\n onClick={autoClose ? () => onClose?.() : undefined}\n className={cn(\n 'z-50 overflow-hidden rounded-(--cmp-listBox-radius) bg-(--cmp-listBox-bg) py-4 shadow-normal-sm',\n maxHeight != null && 'overflow-y-auto',\n fit && 'min-w-(--radix-popover-trigger-width)',\n FLOATING_SLIDE_ANIM,\n className,\n )}\n style={{ maxHeight, ...style }}\n >\n {children}\n </RPopover.Content>\n </RPopover.Portal>\n </RPopover.Root>\n );\n}\n\nSPortal.displayName = 'SPortal';\n"]}
1
+ {"version":3,"sources":["../../../src/lib/cn.ts","../../../src/lib/floating-anim.ts","../../../src/lib/portal-container.tsx","../../../src/components/SPortal/SPortal.tsx"],"names":["extendTailwindMerge","clsx","createContext","useContext","jsxs","RPopover","jsx"],"mappings":"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","file":"SPortal.cjs","sourcesContent":["import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\n/**\n * theme.css 의 --text-* 는 기본 Tailwind 폰트사이즈 스케일(xs/sm/base...)이 아닌\n * 숫자 스케일(10~32)이라, 확장 없이는 tailwind-merge 가 이를 텍스트 컬러 그룹으로\n * 오인해 text-12 같은 클래스를 text-(--color-var) 뒤에서 충돌 제거해버린다.\n */\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n 'font-size': [{ text: ['10', '11', '12', '13', '14', '16', '18', '20', '24', '28', '32'] }],\n },\n },\n});\n\n/**\n * className 병합 유틸.\n * clsx로 조건부 클래스를 합치고, tailwind-merge로 Tailwind 클래스 충돌을 해소한다.\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","/**\n * Radix Floating(SPopover/STooltip/RTooltip) Content 의 placement 방향별 슬라이드+페이드.\n * Radix 가 붙이는 data-side(실제 렌더 방향)·data-state 에 맞춰 열림/닫힘 애니메이션을 적용한다.\n * (sd-floating-portal 의 sd-floating-slide-* 포팅 — 키프레임은 theme.css `--animate-floating-*`)\n *\n * 예: side=top 이면 아래(4px)에서 위로 올라오며 나타나고, 닫힐 때 다시 내려가며 사라진다.\n *\n * @radix-ui/react-popover · react-dropdown-menu 의 data-state 는 open/closed 지만,\n * @radix-ui/react-tooltip 은 open 대신 delayed-open/instant-open 을 쓴다 — 두 케이스 모두 커버한다.\n * Tailwind JIT는 소스에 리터럴로 등장하는 클래스명만 스캔하므로 템플릿으로 조합하지 않고 전부 나열한다.\n */\nexport const FLOATING_SLIDE_ANIM = [\n 'data-[state=open]:data-[side=top]:animate-floating-in-top',\n 'data-[state=delayed-open]:data-[side=top]:animate-floating-in-top',\n 'data-[state=instant-open]:data-[side=top]:animate-floating-in-top',\n 'data-[state=closed]:data-[side=top]:animate-floating-out-top',\n 'data-[state=open]:data-[side=bottom]:animate-floating-in-bottom',\n 'data-[state=delayed-open]:data-[side=bottom]:animate-floating-in-bottom',\n 'data-[state=instant-open]:data-[side=bottom]:animate-floating-in-bottom',\n 'data-[state=closed]:data-[side=bottom]:animate-floating-out-bottom',\n 'data-[state=open]:data-[side=left]:animate-floating-in-left',\n 'data-[state=delayed-open]:data-[side=left]:animate-floating-in-left',\n 'data-[state=instant-open]:data-[side=left]:animate-floating-in-left',\n 'data-[state=closed]:data-[side=left]:animate-floating-out-left',\n 'data-[state=open]:data-[side=right]:animate-floating-in-right',\n 'data-[state=delayed-open]:data-[side=right]:animate-floating-in-right',\n 'data-[state=instant-open]:data-[side=right]:animate-floating-in-right',\n 'data-[state=closed]:data-[side=right]:animate-floating-out-right',\n].join(' ');\n","'use client';\n\nimport { createContext, useContext } from 'react';\n\n/**\n * Floating 컴포넌트(STooltip/SPopover/SSelect listbox/SDropdownButton/SDatePicker 등)가\n * 자신의 Portal 을 어디로 렌더할지 결정하는 컨텍스트.\n *\n * 기본값(null)이면 각 컴포넌트는 body 로 portal 한다.\n * SModalContainer 는 모달이 열려있는 동안 이 값을 \"모달 스태킹 밴드(z-1001) 안의 전용 노드\"로\n * 채워서, 모달 안에서 열린 floating 이 모달 딤(z-1000) 뒤에 가려지지 않고 위로 뜨게 한다.\n * 반대로 모달 밖(베이스 화면)에서 열린 floating 은 여전히 body(z-50)로 나가므로,\n * 나중에 뜬 모달이 정상적으로 그 위를 덮는다. (소속에 따라 상대적으로 결정)\n */\nconst PortalContainerContext = createContext<HTMLElement | null>(null);\n\nexport const PortalContainerProvider = PortalContainerContext.Provider;\n\n/**\n * 현재 소속된 Portal 컨테이너를 반환한다.\n * Radix `*.Portal` 의 `container`, Ariakit 의 `portalElement` 에 그대로 넘기면 되며,\n * 컨테이너가 없을 때(모달 밖)는 `undefined` 를 반환해 각 라이브러리 기본값(body)을 쓴다.\n */\nexport function usePortalContainer(): HTMLElement | undefined {\n return useContext(PortalContainerContext) ?? undefined;\n}\n","'use client';\n\nimport { type CSSProperties, type ReactNode, type RefObject } from 'react';\nimport * as RPopover from '@radix-ui/react-popover';\nimport { cn } from '../../lib/cn';\nimport { FLOATING_SLIDE_ANIM } from '../../lib/floating-anim';\nimport { usePortalContainer } from '../../lib/portal-container';\n\nexport type SPortalPlacement = 'top' | 'bottom' | 'left' | 'right';\nexport type SPortalAlign = 'start' | 'center' | 'end';\n\n/** Radix Anchor 가 위치 계산에 쓰는 최소 인터페이스 (HTMLElement 가 충족한다). */\ntype Measurable = { getBoundingClientRect(): DOMRect };\n\nexport interface SPortalProps {\n /** 표시 여부 (제어). onClose 와 함께 사용한다. */\n open: boolean;\n /** 외부 클릭 · ESC 등으로 닫힘이 요청될 때 (sd-portal `sdClose` 대응). */\n onClose?: () => void;\n /** 열림/닫힘 변경 전체 콜백 (선택). */\n onOpenChange?: (open: boolean) => void;\n /**\n * 위치 기준이 되는 앵커 엘리먼트 ref (sd-portal `parentRef` 대응).\n * 트리거 버튼 등에 그대로 걸면 그 엘리먼트에 붙어서 뜬다.\n */\n anchorRef: RefObject<HTMLElement | null>;\n /** 표시 방향 (공간이 부족하면 자동으로 반대 방향으로 전환). */\n placement?: SPortalPlacement;\n /** 교차축 정렬 (start·center·end). */\n align?: SPortalAlign;\n /** 앵커로부터의 간격 px (sd-portal offset[1]). */\n offset?: number;\n /** 정렬축 오프셋 px (sd-portal offset[0]). */\n alignOffset?: number;\n /** 앵커 너비에 맞춰 최소 너비를 잡는다. */\n fit?: boolean;\n /** 콘텐츠 최대 높이 px. 넘치면 세로 스크롤. */\n maxHeight?: number;\n /** 콘텐츠 내부를 클릭하면 자동으로 닫는다. */\n autoClose?: boolean;\n /** 외부 클릭 · ESC 로 닫히지 않게 한다. */\n persistent?: boolean;\n /** 뷰포트 경계 여백 px (충돌 회피 패딩). */\n viewportPadding?: number;\n /** 열릴 때 포커스 이동 처리 (기본은 Radix가 콘텐츠로 포커스를 옮김). e.preventDefault()로 막을 수 있다. */\n onOpenAutoFocus?: (event: Event) => void;\n /** 닫힐 때 포커스 복귀 처리 (기본은 Radix가 앵커로 포커스를 되돌림). e.preventDefault()로 막을 수 있다. */\n onCloseAutoFocus?: (event: Event) => void;\n /** 본문 내용 (콘텐츠 자유). */\n children?: ReactNode;\n className?: string;\n style?: CSSProperties;\n ariaLabel?: string;\n}\n\n/**\n * SPortal — sd-portal/sd-floating-portal 의 사용성을 Radix Popover 로 옮긴 범용 앵커드 플로팅 컨테이너.\n *\n * 트리거를 감싸지 않고 `anchorRef` 로 임의의 엘리먼트에 붙는다(=sd-portal `parentRef`).\n * open/onClose 로 외부에서 제어하며, flip·collision·스크롤 재배치·외부클릭·ESC·모달 포털은\n * Radix 가 처리한다. 콘텐츠는 children 으로 완전히 자유롭다.\n */\nexport function SPortal({\n open,\n onClose,\n onOpenChange,\n anchorRef,\n placement = 'bottom',\n align = 'start',\n offset = 4,\n alignOffset = 0,\n fit = false,\n maxHeight,\n autoClose = false,\n persistent = false,\n viewportPadding = 0,\n onOpenAutoFocus,\n onCloseAutoFocus,\n children,\n className,\n style,\n ariaLabel,\n}: SPortalProps) {\n const portalContainer = usePortalContainer();\n\n return (\n <RPopover.Root\n open={open}\n onOpenChange={next => {\n onOpenChange?.(next);\n if (!next) onClose?.();\n }}\n >\n <RPopover.Anchor virtualRef={anchorRef as RefObject<Measurable>} />\n <RPopover.Portal container={portalContainer}>\n <RPopover.Content\n side={placement}\n align={align}\n sideOffset={offset}\n alignOffset={alignOffset}\n collisionPadding={viewportPadding}\n aria-label={ariaLabel}\n // persistent: 외부 클릭·ESC 로 닫히지 않음\n // 아니면: 앵커(트리거) 위 클릭은 소비자가 토글하므로 여기서 닫지 않는다(중복 토글 방지)\n onPointerDownOutside={e => {\n if (persistent || anchorRef.current?.contains(e.target as Node)) {\n e.preventDefault();\n }\n }}\n // 앵커(예: input)에 이미 포커스가 있는 상태로 열리는 경우(클릭 즉시 오픈), Radix는 포커스가\n // 레이어 밖에 있다고 판단해 열리자마자 닫아버린다 — 앵커 내부 포커스는 outside로 취급하지 않는다.\n onFocusOutside={e => {\n if (persistent || anchorRef.current?.contains(e.target as Node)) {\n e.preventDefault();\n }\n }}\n onEscapeKeyDown={persistent ? e => e.preventDefault() : undefined}\n onOpenAutoFocus={onOpenAutoFocus}\n onCloseAutoFocus={onCloseAutoFocus}\n onClick={autoClose ? () => onClose?.() : undefined}\n className={cn(\n 'z-50 overflow-hidden rounded-(--cmp-listBox-radius) bg-(--cmp-listBox-bg) py-4 shadow-normal-sm',\n maxHeight != null && 'overflow-y-auto',\n fit && 'min-w-(--radix-popover-trigger-width)',\n FLOATING_SLIDE_ANIM,\n className,\n )}\n style={{ maxHeight, ...style }}\n >\n {children}\n </RPopover.Content>\n </RPopover.Portal>\n </RPopover.Root>\n );\n}\n\nSPortal.displayName = 'SPortal';\n"]}
@@ -19,12 +19,20 @@ function cn(...inputs) {
19
19
  // src/lib/floating-anim.ts
20
20
  var FLOATING_SLIDE_ANIM = [
21
21
  "data-[state=open]:data-[side=top]:animate-floating-in-top",
22
+ "data-[state=delayed-open]:data-[side=top]:animate-floating-in-top",
23
+ "data-[state=instant-open]:data-[side=top]:animate-floating-in-top",
22
24
  "data-[state=closed]:data-[side=top]:animate-floating-out-top",
23
25
  "data-[state=open]:data-[side=bottom]:animate-floating-in-bottom",
26
+ "data-[state=delayed-open]:data-[side=bottom]:animate-floating-in-bottom",
27
+ "data-[state=instant-open]:data-[side=bottom]:animate-floating-in-bottom",
24
28
  "data-[state=closed]:data-[side=bottom]:animate-floating-out-bottom",
25
29
  "data-[state=open]:data-[side=left]:animate-floating-in-left",
30
+ "data-[state=delayed-open]:data-[side=left]:animate-floating-in-left",
31
+ "data-[state=instant-open]:data-[side=left]:animate-floating-in-left",
26
32
  "data-[state=closed]:data-[side=left]:animate-floating-out-left",
27
33
  "data-[state=open]:data-[side=right]:animate-floating-in-right",
34
+ "data-[state=delayed-open]:data-[side=right]:animate-floating-in-right",
35
+ "data-[state=instant-open]:data-[side=right]:animate-floating-in-right",
28
36
  "data-[state=closed]:data-[side=right]:animate-floating-out-right"
29
37
  ].join(" ");
30
38
  var PortalContainerContext = createContext(null);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/cn.ts","../../../src/lib/floating-anim.ts","../../../src/lib/portal-container.tsx","../../../src/components/SPortal/SPortal.tsx"],"names":[],"mappings":";;;;;;AAQA,IAAM,UAAU,mBAAA,CAAoB;AAAA,EAClC,MAAA,EAAQ;AAAA,IACN,WAAA,EAAa;AAAA,MACX,aAAa,CAAC,EAAE,IAAA,EAAM,CAAC,MAAM,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,MAAM,IAAA,EAAM,IAAA,EAAM,MAAM,IAAA,EAAM,IAAI,GAAG;AAAA;AAC5F;AAEJ,CAAC,CAAA;AAMM,SAAS,MAAM,MAAA,EAA8B;AAClD,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC7B;;;ACfO,IAAM,mBAAA,GAAsB;AAAA,EACjC,2DAAA;AAAA,EACA,8DAAA;AAAA,EACA,iEAAA;AAAA,EACA,oEAAA;AAAA,EACA,6DAAA;AAAA,EACA,gEAAA;AAAA,EACA,+DAAA;AAAA,EACA;AACF,CAAA,CAAE,KAAK,GAAG,CAAA;ACFV,IAAM,sBAAA,GAAyB,cAAkC,IAAI,CAAA;AAE9B,sBAAA,CAAuB;AAOvD,SAAS,kBAAA,GAA8C;AAC5D,EAAA,OAAO,UAAA,CAAW,sBAAsB,CAAA,IAAK,MAAA;AAC/C;ACqCO,SAAS,OAAA,CAAQ;AAAA,EACtB,IAAA;AAAA,EACA,OAAA;AAAA,EACA,YAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA,GAAY,QAAA;AAAA,EACZ,KAAA,GAAQ,OAAA;AAAA,EACR,MAAA,GAAS,CAAA;AAAA,EACT,WAAA,GAAc,CAAA;AAAA,EACd,GAAA,GAAM,KAAA;AAAA,EACN,SAAA;AAAA,EACA,SAAA,GAAY,KAAA;AAAA,EACZ,UAAA,GAAa,KAAA;AAAA,EACb,eAAA,GAAkB,CAAA;AAAA,EAClB,eAAA;AAAA,EACA,gBAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CAAA,EAAiB;AACf,EAAA,MAAM,kBAAkB,kBAAA,EAAmB;AAE3C,EAAA,uBACE,IAAA;AAAA,IAAU,QAAA,CAAA,IAAA;AAAA,IAAT;AAAA,MACC,IAAA;AAAA,MACA,cAAc,CAAA,IAAA,KAAQ;AACpB,QAAA,YAAA,GAAe,IAAI,CAAA;AACnB,QAAA,IAAI,CAAC,MAAM,OAAA,IAAU;AAAA,MACvB,CAAA;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAU,QAAA,CAAA,MAAA,EAAT,EAAgB,UAAA,EAAY,SAAA,EAAoC,CAAA;AAAA,wBACjE,GAAA,CAAU,QAAA,CAAA,MAAA,EAAT,EAAgB,SAAA,EAAW,eAAA,EAC1B,QAAA,kBAAA,GAAA;AAAA,UAAU,QAAA,CAAA,OAAA;AAAA,UAAT;AAAA,YACC,IAAA,EAAM,SAAA;AAAA,YACN,KAAA;AAAA,YACA,UAAA,EAAY,MAAA;AAAA,YACZ,WAAA;AAAA,YACA,gBAAA,EAAkB,eAAA;AAAA,YAClB,YAAA,EAAY,SAAA;AAAA,YAGZ,sBAAsB,CAAA,CAAA,KAAK;AACzB,cAAA,IAAI,cAAc,SAAA,CAAU,OAAA,EAAS,QAAA,CAAS,CAAA,CAAE,MAAc,CAAA,EAAG;AAC/D,gBAAA,CAAA,CAAE,cAAA,EAAe;AAAA,cACnB;AAAA,YACF,CAAA;AAAA,YAGA,gBAAgB,CAAA,CAAA,KAAK;AACnB,cAAA,IAAI,cAAc,SAAA,CAAU,OAAA,EAAS,QAAA,CAAS,CAAA,CAAE,MAAc,CAAA,EAAG;AAC/D,gBAAA,CAAA,CAAE,cAAA,EAAe;AAAA,cACnB;AAAA,YACF,CAAA;AAAA,YACA,eAAA,EAAiB,UAAA,GAAa,CAAA,CAAA,KAAK,CAAA,CAAE,gBAAe,GAAI,MAAA;AAAA,YACxD,eAAA;AAAA,YACA,gBAAA;AAAA,YACA,OAAA,EAAS,SAAA,GAAY,MAAM,OAAA,IAAU,GAAI,MAAA;AAAA,YACzC,SAAA,EAAW,EAAA;AAAA,cACT,iGAAA;AAAA,cACA,aAAa,IAAA,IAAQ,iBAAA;AAAA,cACrB,GAAA,IAAO,uCAAA;AAAA,cACP,mBAAA;AAAA,cACA;AAAA,aACF;AAAA,YACA,KAAA,EAAO,EAAE,SAAA,EAAW,GAAG,KAAA,EAAM;AAAA,YAE5B;AAAA;AAAA,SACH,EACF;AAAA;AAAA;AAAA,GACF;AAEJ;AAEA,OAAA,CAAQ,WAAA,GAAc,SAAA","file":"SPortal.js","sourcesContent":["import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\n/**\n * theme.css 의 --text-* 는 기본 Tailwind 폰트사이즈 스케일(xs/sm/base...)이 아닌\n * 숫자 스케일(10~32)이라, 확장 없이는 tailwind-merge 가 이를 텍스트 컬러 그룹으로\n * 오인해 text-12 같은 클래스를 text-(--color-var) 뒤에서 충돌 제거해버린다.\n */\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n 'font-size': [{ text: ['10', '11', '12', '13', '14', '16', '18', '20', '24', '28', '32'] }],\n },\n },\n});\n\n/**\n * className 병합 유틸.\n * clsx로 조건부 클래스를 합치고, tailwind-merge로 Tailwind 클래스 충돌을 해소한다.\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","/**\n * Radix Floating(SPopover/STooltip) Content 의 placement 방향별 슬라이드+페이드.\n * Radix 가 붙이는 data-side(실제 렌더 방향)·data-state 에 맞춰 열림/닫힘 애니메이션을 적용한다.\n * (sd-floating-portal 의 sd-floating-slide-* 포팅 — 키프레임은 theme.css `--animate-floating-*`)\n *\n * 예: side=top 이면 아래(4px)에서 위로 올라오며 나타나고, 닫힐 때 다시 내려가며 사라진다.\n */\nexport const FLOATING_SLIDE_ANIM = [\n 'data-[state=open]:data-[side=top]:animate-floating-in-top',\n 'data-[state=closed]:data-[side=top]:animate-floating-out-top',\n 'data-[state=open]:data-[side=bottom]:animate-floating-in-bottom',\n 'data-[state=closed]:data-[side=bottom]:animate-floating-out-bottom',\n 'data-[state=open]:data-[side=left]:animate-floating-in-left',\n 'data-[state=closed]:data-[side=left]:animate-floating-out-left',\n 'data-[state=open]:data-[side=right]:animate-floating-in-right',\n 'data-[state=closed]:data-[side=right]:animate-floating-out-right',\n].join(' ');\n","'use client';\n\nimport { createContext, useContext } from 'react';\n\n/**\n * Floating 컴포넌트(STooltip/SPopover/SSelect listbox/SDropdownButton/SDatePicker 등)가\n * 자신의 Portal 을 어디로 렌더할지 결정하는 컨텍스트.\n *\n * 기본값(null)이면 각 컴포넌트는 body 로 portal 한다.\n * SModalContainer 는 모달이 열려있는 동안 이 값을 \"모달 스태킹 밴드(z-1001) 안의 전용 노드\"로\n * 채워서, 모달 안에서 열린 floating 이 모달 딤(z-1000) 뒤에 가려지지 않고 위로 뜨게 한다.\n * 반대로 모달 밖(베이스 화면)에서 열린 floating 은 여전히 body(z-50)로 나가므로,\n * 나중에 뜬 모달이 정상적으로 그 위를 덮는다. (소속에 따라 상대적으로 결정)\n */\nconst PortalContainerContext = createContext<HTMLElement | null>(null);\n\nexport const PortalContainerProvider = PortalContainerContext.Provider;\n\n/**\n * 현재 소속된 Portal 컨테이너를 반환한다.\n * Radix `*.Portal` 의 `container`, Ariakit 의 `portalElement` 에 그대로 넘기면 되며,\n * 컨테이너가 없을 때(모달 밖)는 `undefined` 를 반환해 각 라이브러리 기본값(body)을 쓴다.\n */\nexport function usePortalContainer(): HTMLElement | undefined {\n return useContext(PortalContainerContext) ?? undefined;\n}\n","'use client';\n\nimport { type CSSProperties, type ReactNode, type RefObject } from 'react';\nimport * as RPopover from '@radix-ui/react-popover';\nimport { cn } from '../../lib/cn';\nimport { FLOATING_SLIDE_ANIM } from '../../lib/floating-anim';\nimport { usePortalContainer } from '../../lib/portal-container';\n\nexport type SPortalPlacement = 'top' | 'bottom' | 'left' | 'right';\nexport type SPortalAlign = 'start' | 'center' | 'end';\n\n/** Radix Anchor 가 위치 계산에 쓰는 최소 인터페이스 (HTMLElement 가 충족한다). */\ntype Measurable = { getBoundingClientRect(): DOMRect };\n\nexport interface SPortalProps {\n /** 표시 여부 (제어). onClose 와 함께 사용한다. */\n open: boolean;\n /** 외부 클릭 · ESC 등으로 닫힘이 요청될 때 (sd-portal `sdClose` 대응). */\n onClose?: () => void;\n /** 열림/닫힘 변경 전체 콜백 (선택). */\n onOpenChange?: (open: boolean) => void;\n /**\n * 위치 기준이 되는 앵커 엘리먼트 ref (sd-portal `parentRef` 대응).\n * 트리거 버튼 등에 그대로 걸면 그 엘리먼트에 붙어서 뜬다.\n */\n anchorRef: RefObject<HTMLElement | null>;\n /** 표시 방향 (공간이 부족하면 자동으로 반대 방향으로 전환). */\n placement?: SPortalPlacement;\n /** 교차축 정렬 (start·center·end). */\n align?: SPortalAlign;\n /** 앵커로부터의 간격 px (sd-portal offset[1]). */\n offset?: number;\n /** 정렬축 오프셋 px (sd-portal offset[0]). */\n alignOffset?: number;\n /** 앵커 너비에 맞춰 최소 너비를 잡는다. */\n fit?: boolean;\n /** 콘텐츠 최대 높이 px. 넘치면 세로 스크롤. */\n maxHeight?: number;\n /** 콘텐츠 내부를 클릭하면 자동으로 닫는다. */\n autoClose?: boolean;\n /** 외부 클릭 · ESC 로 닫히지 않게 한다. */\n persistent?: boolean;\n /** 뷰포트 경계 여백 px (충돌 회피 패딩). */\n viewportPadding?: number;\n /** 열릴 때 포커스 이동 처리 (기본은 Radix가 콘텐츠로 포커스를 옮김). e.preventDefault()로 막을 수 있다. */\n onOpenAutoFocus?: (event: Event) => void;\n /** 닫힐 때 포커스 복귀 처리 (기본은 Radix가 앵커로 포커스를 되돌림). e.preventDefault()로 막을 수 있다. */\n onCloseAutoFocus?: (event: Event) => void;\n /** 본문 내용 (콘텐츠 자유). */\n children?: ReactNode;\n className?: string;\n style?: CSSProperties;\n ariaLabel?: string;\n}\n\n/**\n * SPortal — sd-portal/sd-floating-portal 의 사용성을 Radix Popover 로 옮긴 범용 앵커드 플로팅 컨테이너.\n *\n * 트리거를 감싸지 않고 `anchorRef` 로 임의의 엘리먼트에 붙는다(=sd-portal `parentRef`).\n * open/onClose 로 외부에서 제어하며, flip·collision·스크롤 재배치·외부클릭·ESC·모달 포털은\n * Radix 가 처리한다. 콘텐츠는 children 으로 완전히 자유롭다.\n */\nexport function SPortal({\n open,\n onClose,\n onOpenChange,\n anchorRef,\n placement = 'bottom',\n align = 'start',\n offset = 4,\n alignOffset = 0,\n fit = false,\n maxHeight,\n autoClose = false,\n persistent = false,\n viewportPadding = 0,\n onOpenAutoFocus,\n onCloseAutoFocus,\n children,\n className,\n style,\n ariaLabel,\n}: SPortalProps) {\n const portalContainer = usePortalContainer();\n\n return (\n <RPopover.Root\n open={open}\n onOpenChange={next => {\n onOpenChange?.(next);\n if (!next) onClose?.();\n }}\n >\n <RPopover.Anchor virtualRef={anchorRef as RefObject<Measurable>} />\n <RPopover.Portal container={portalContainer}>\n <RPopover.Content\n side={placement}\n align={align}\n sideOffset={offset}\n alignOffset={alignOffset}\n collisionPadding={viewportPadding}\n aria-label={ariaLabel}\n // persistent: 외부 클릭·ESC 로 닫히지 않음\n // 아니면: 앵커(트리거) 위 클릭은 소비자가 토글하므로 여기서 닫지 않는다(중복 토글 방지)\n onPointerDownOutside={e => {\n if (persistent || anchorRef.current?.contains(e.target as Node)) {\n e.preventDefault();\n }\n }}\n // 앵커(예: input)에 이미 포커스가 있는 상태로 열리는 경우(클릭 즉시 오픈), Radix는 포커스가\n // 레이어 밖에 있다고 판단해 열리자마자 닫아버린다 — 앵커 내부 포커스는 outside로 취급하지 않는다.\n onFocusOutside={e => {\n if (persistent || anchorRef.current?.contains(e.target as Node)) {\n e.preventDefault();\n }\n }}\n onEscapeKeyDown={persistent ? e => e.preventDefault() : undefined}\n onOpenAutoFocus={onOpenAutoFocus}\n onCloseAutoFocus={onCloseAutoFocus}\n onClick={autoClose ? () => onClose?.() : undefined}\n className={cn(\n 'z-50 overflow-hidden rounded-(--cmp-listBox-radius) bg-(--cmp-listBox-bg) py-4 shadow-normal-sm',\n maxHeight != null && 'overflow-y-auto',\n fit && 'min-w-(--radix-popover-trigger-width)',\n FLOATING_SLIDE_ANIM,\n className,\n )}\n style={{ maxHeight, ...style }}\n >\n {children}\n </RPopover.Content>\n </RPopover.Portal>\n </RPopover.Root>\n );\n}\n\nSPortal.displayName = 'SPortal';\n"]}
1
+ {"version":3,"sources":["../../../src/lib/cn.ts","../../../src/lib/floating-anim.ts","../../../src/lib/portal-container.tsx","../../../src/components/SPortal/SPortal.tsx"],"names":[],"mappings":"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","file":"SPortal.js","sourcesContent":["import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\n/**\n * theme.css 의 --text-* 는 기본 Tailwind 폰트사이즈 스케일(xs/sm/base...)이 아닌\n * 숫자 스케일(10~32)이라, 확장 없이는 tailwind-merge 가 이를 텍스트 컬러 그룹으로\n * 오인해 text-12 같은 클래스를 text-(--color-var) 뒤에서 충돌 제거해버린다.\n */\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n 'font-size': [{ text: ['10', '11', '12', '13', '14', '16', '18', '20', '24', '28', '32'] }],\n },\n },\n});\n\n/**\n * className 병합 유틸.\n * clsx로 조건부 클래스를 합치고, tailwind-merge로 Tailwind 클래스 충돌을 해소한다.\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","/**\n * Radix Floating(SPopover/STooltip/RTooltip) Content 의 placement 방향별 슬라이드+페이드.\n * Radix 가 붙이는 data-side(실제 렌더 방향)·data-state 에 맞춰 열림/닫힘 애니메이션을 적용한다.\n * (sd-floating-portal 의 sd-floating-slide-* 포팅 — 키프레임은 theme.css `--animate-floating-*`)\n *\n * 예: side=top 이면 아래(4px)에서 위로 올라오며 나타나고, 닫힐 때 다시 내려가며 사라진다.\n *\n * @radix-ui/react-popover · react-dropdown-menu 의 data-state 는 open/closed 지만,\n * @radix-ui/react-tooltip 은 open 대신 delayed-open/instant-open 을 쓴다 — 두 케이스 모두 커버한다.\n * Tailwind JIT는 소스에 리터럴로 등장하는 클래스명만 스캔하므로 템플릿으로 조합하지 않고 전부 나열한다.\n */\nexport const FLOATING_SLIDE_ANIM = [\n 'data-[state=open]:data-[side=top]:animate-floating-in-top',\n 'data-[state=delayed-open]:data-[side=top]:animate-floating-in-top',\n 'data-[state=instant-open]:data-[side=top]:animate-floating-in-top',\n 'data-[state=closed]:data-[side=top]:animate-floating-out-top',\n 'data-[state=open]:data-[side=bottom]:animate-floating-in-bottom',\n 'data-[state=delayed-open]:data-[side=bottom]:animate-floating-in-bottom',\n 'data-[state=instant-open]:data-[side=bottom]:animate-floating-in-bottom',\n 'data-[state=closed]:data-[side=bottom]:animate-floating-out-bottom',\n 'data-[state=open]:data-[side=left]:animate-floating-in-left',\n 'data-[state=delayed-open]:data-[side=left]:animate-floating-in-left',\n 'data-[state=instant-open]:data-[side=left]:animate-floating-in-left',\n 'data-[state=closed]:data-[side=left]:animate-floating-out-left',\n 'data-[state=open]:data-[side=right]:animate-floating-in-right',\n 'data-[state=delayed-open]:data-[side=right]:animate-floating-in-right',\n 'data-[state=instant-open]:data-[side=right]:animate-floating-in-right',\n 'data-[state=closed]:data-[side=right]:animate-floating-out-right',\n].join(' ');\n","'use client';\n\nimport { createContext, useContext } from 'react';\n\n/**\n * Floating 컴포넌트(STooltip/SPopover/SSelect listbox/SDropdownButton/SDatePicker 등)가\n * 자신의 Portal 을 어디로 렌더할지 결정하는 컨텍스트.\n *\n * 기본값(null)이면 각 컴포넌트는 body 로 portal 한다.\n * SModalContainer 는 모달이 열려있는 동안 이 값을 \"모달 스태킹 밴드(z-1001) 안의 전용 노드\"로\n * 채워서, 모달 안에서 열린 floating 이 모달 딤(z-1000) 뒤에 가려지지 않고 위로 뜨게 한다.\n * 반대로 모달 밖(베이스 화면)에서 열린 floating 은 여전히 body(z-50)로 나가므로,\n * 나중에 뜬 모달이 정상적으로 그 위를 덮는다. (소속에 따라 상대적으로 결정)\n */\nconst PortalContainerContext = createContext<HTMLElement | null>(null);\n\nexport const PortalContainerProvider = PortalContainerContext.Provider;\n\n/**\n * 현재 소속된 Portal 컨테이너를 반환한다.\n * Radix `*.Portal` 의 `container`, Ariakit 의 `portalElement` 에 그대로 넘기면 되며,\n * 컨테이너가 없을 때(모달 밖)는 `undefined` 를 반환해 각 라이브러리 기본값(body)을 쓴다.\n */\nexport function usePortalContainer(): HTMLElement | undefined {\n return useContext(PortalContainerContext) ?? undefined;\n}\n","'use client';\n\nimport { type CSSProperties, type ReactNode, type RefObject } from 'react';\nimport * as RPopover from '@radix-ui/react-popover';\nimport { cn } from '../../lib/cn';\nimport { FLOATING_SLIDE_ANIM } from '../../lib/floating-anim';\nimport { usePortalContainer } from '../../lib/portal-container';\n\nexport type SPortalPlacement = 'top' | 'bottom' | 'left' | 'right';\nexport type SPortalAlign = 'start' | 'center' | 'end';\n\n/** Radix Anchor 가 위치 계산에 쓰는 최소 인터페이스 (HTMLElement 가 충족한다). */\ntype Measurable = { getBoundingClientRect(): DOMRect };\n\nexport interface SPortalProps {\n /** 표시 여부 (제어). onClose 와 함께 사용한다. */\n open: boolean;\n /** 외부 클릭 · ESC 등으로 닫힘이 요청될 때 (sd-portal `sdClose` 대응). */\n onClose?: () => void;\n /** 열림/닫힘 변경 전체 콜백 (선택). */\n onOpenChange?: (open: boolean) => void;\n /**\n * 위치 기준이 되는 앵커 엘리먼트 ref (sd-portal `parentRef` 대응).\n * 트리거 버튼 등에 그대로 걸면 그 엘리먼트에 붙어서 뜬다.\n */\n anchorRef: RefObject<HTMLElement | null>;\n /** 표시 방향 (공간이 부족하면 자동으로 반대 방향으로 전환). */\n placement?: SPortalPlacement;\n /** 교차축 정렬 (start·center·end). */\n align?: SPortalAlign;\n /** 앵커로부터의 간격 px (sd-portal offset[1]). */\n offset?: number;\n /** 정렬축 오프셋 px (sd-portal offset[0]). */\n alignOffset?: number;\n /** 앵커 너비에 맞춰 최소 너비를 잡는다. */\n fit?: boolean;\n /** 콘텐츠 최대 높이 px. 넘치면 세로 스크롤. */\n maxHeight?: number;\n /** 콘텐츠 내부를 클릭하면 자동으로 닫는다. */\n autoClose?: boolean;\n /** 외부 클릭 · ESC 로 닫히지 않게 한다. */\n persistent?: boolean;\n /** 뷰포트 경계 여백 px (충돌 회피 패딩). */\n viewportPadding?: number;\n /** 열릴 때 포커스 이동 처리 (기본은 Radix가 콘텐츠로 포커스를 옮김). e.preventDefault()로 막을 수 있다. */\n onOpenAutoFocus?: (event: Event) => void;\n /** 닫힐 때 포커스 복귀 처리 (기본은 Radix가 앵커로 포커스를 되돌림). e.preventDefault()로 막을 수 있다. */\n onCloseAutoFocus?: (event: Event) => void;\n /** 본문 내용 (콘텐츠 자유). */\n children?: ReactNode;\n className?: string;\n style?: CSSProperties;\n ariaLabel?: string;\n}\n\n/**\n * SPortal — sd-portal/sd-floating-portal 의 사용성을 Radix Popover 로 옮긴 범용 앵커드 플로팅 컨테이너.\n *\n * 트리거를 감싸지 않고 `anchorRef` 로 임의의 엘리먼트에 붙는다(=sd-portal `parentRef`).\n * open/onClose 로 외부에서 제어하며, flip·collision·스크롤 재배치·외부클릭·ESC·모달 포털은\n * Radix 가 처리한다. 콘텐츠는 children 으로 완전히 자유롭다.\n */\nexport function SPortal({\n open,\n onClose,\n onOpenChange,\n anchorRef,\n placement = 'bottom',\n align = 'start',\n offset = 4,\n alignOffset = 0,\n fit = false,\n maxHeight,\n autoClose = false,\n persistent = false,\n viewportPadding = 0,\n onOpenAutoFocus,\n onCloseAutoFocus,\n children,\n className,\n style,\n ariaLabel,\n}: SPortalProps) {\n const portalContainer = usePortalContainer();\n\n return (\n <RPopover.Root\n open={open}\n onOpenChange={next => {\n onOpenChange?.(next);\n if (!next) onClose?.();\n }}\n >\n <RPopover.Anchor virtualRef={anchorRef as RefObject<Measurable>} />\n <RPopover.Portal container={portalContainer}>\n <RPopover.Content\n side={placement}\n align={align}\n sideOffset={offset}\n alignOffset={alignOffset}\n collisionPadding={viewportPadding}\n aria-label={ariaLabel}\n // persistent: 외부 클릭·ESC 로 닫히지 않음\n // 아니면: 앵커(트리거) 위 클릭은 소비자가 토글하므로 여기서 닫지 않는다(중복 토글 방지)\n onPointerDownOutside={e => {\n if (persistent || anchorRef.current?.contains(e.target as Node)) {\n e.preventDefault();\n }\n }}\n // 앵커(예: input)에 이미 포커스가 있는 상태로 열리는 경우(클릭 즉시 오픈), Radix는 포커스가\n // 레이어 밖에 있다고 판단해 열리자마자 닫아버린다 — 앵커 내부 포커스는 outside로 취급하지 않는다.\n onFocusOutside={e => {\n if (persistent || anchorRef.current?.contains(e.target as Node)) {\n e.preventDefault();\n }\n }}\n onEscapeKeyDown={persistent ? e => e.preventDefault() : undefined}\n onOpenAutoFocus={onOpenAutoFocus}\n onCloseAutoFocus={onCloseAutoFocus}\n onClick={autoClose ? () => onClose?.() : undefined}\n className={cn(\n 'z-50 overflow-hidden rounded-(--cmp-listBox-radius) bg-(--cmp-listBox-bg) py-4 shadow-normal-sm',\n maxHeight != null && 'overflow-y-auto',\n fit && 'min-w-(--radix-popover-trigger-width)',\n FLOATING_SLIDE_ANIM,\n className,\n )}\n style={{ maxHeight, ...style }}\n >\n {children}\n </RPopover.Content>\n </RPopover.Portal>\n </RPopover.Root>\n );\n}\n\nSPortal.displayName = 'SPortal';\n"]}
@@ -2883,12 +2883,20 @@ var SIcon = react.forwardRef(function SIcon2({ name, size = 24, color, rotate, l
2883
2883
  // src/lib/floating-anim.ts
2884
2884
  var FLOATING_SLIDE_ANIM = [
2885
2885
  "data-[state=open]:data-[side=top]:animate-floating-in-top",
2886
+ "data-[state=delayed-open]:data-[side=top]:animate-floating-in-top",
2887
+ "data-[state=instant-open]:data-[side=top]:animate-floating-in-top",
2886
2888
  "data-[state=closed]:data-[side=top]:animate-floating-out-top",
2887
2889
  "data-[state=open]:data-[side=bottom]:animate-floating-in-bottom",
2890
+ "data-[state=delayed-open]:data-[side=bottom]:animate-floating-in-bottom",
2891
+ "data-[state=instant-open]:data-[side=bottom]:animate-floating-in-bottom",
2888
2892
  "data-[state=closed]:data-[side=bottom]:animate-floating-out-bottom",
2889
2893
  "data-[state=open]:data-[side=left]:animate-floating-in-left",
2894
+ "data-[state=delayed-open]:data-[side=left]:animate-floating-in-left",
2895
+ "data-[state=instant-open]:data-[side=left]:animate-floating-in-left",
2890
2896
  "data-[state=closed]:data-[side=left]:animate-floating-out-left",
2891
2897
  "data-[state=open]:data-[side=right]:animate-floating-in-right",
2898
+ "data-[state=delayed-open]:data-[side=right]:animate-floating-in-right",
2899
+ "data-[state=instant-open]:data-[side=right]:animate-floating-in-right",
2892
2900
  "data-[state=closed]:data-[side=right]:animate-floating-out-right"
2893
2901
  ].join(" ");
2894
2902
 
@@ -3083,7 +3091,8 @@ var HIDE_DELAY_MS = 100;
3083
3091
  function useBody(content, message = []) {
3084
3092
  if (content != null) return content;
3085
3093
  if (message.length === 0) return null;
3086
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: message.map((line, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { children: line }, i)) });
3094
+ const singleLine = message.length === 1;
3095
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: message.map((line, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: singleLine ? "leading-[24px]" : void 0, children: line }, i)) });
3087
3096
  }
3088
3097
  var STooltip = react.forwardRef(function STooltip2({
3089
3098
  content,
@@ -3141,7 +3150,7 @@ var STooltip = react.forwardRef(function STooltip2({
3141
3150
  if (disabled || body == null) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: triggerNode });
3142
3151
  const isHover = trigger === "hover";
3143
3152
  const contentClass = cn(
3144
- "z-50 max-w-xs rounded-[6px] px-[16px] py-[12px] text-[12px] leading-[20px]",
3153
+ "z-50 max-w-xs rounded-[6px] px-[16px] py-[12px] text-[12px] leading-[20px] shadow-[2px_2px_12px_2px_rgba(0,0,0,0.1)]",
3145
3154
  FLOATING_SLIDE_ANIM,
3146
3155
  className
3147
3156
  );
@@ -3186,11 +3195,17 @@ var STooltip = react.forwardRef(function STooltip2({
3186
3195
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-[12px]", children: [
3187
3196
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children: body }),
3188
3197
  useClose && /* @__PURE__ */ jsxRuntime.jsx(
3189
- RPopover2__namespace.Close,
3198
+ SGhostButton,
3190
3199
  {
3191
- "aria-label": "\uB2EB\uAE30",
3192
- className: "shrink-0 cursor-pointer opacity-70 hover:opacity-100",
3193
- children: /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "close", size: 16, color: fg })
3200
+ icon: "close",
3201
+ size: "xs",
3202
+ intent: tooltipType === "default" ? "inverse" : "default",
3203
+ ariaLabel: "\uB2EB\uAE30",
3204
+ className: "shrink-0",
3205
+ onClick: () => {
3206
+ cancelHide();
3207
+ setOpen(false);
3208
+ }
3194
3209
  }
3195
3210
  )
3196
3211
  ] }),
@@ -3228,8 +3243,8 @@ function useFormField(field) {
3228
3243
  }, [ctx, name]);
3229
3244
  }
3230
3245
  var FIELD_SIZE = {
3231
- sm: { height: 28, radius: 4, fieldGap: 12, labelGap: 6, fontSize: 12, lineHeight: 20, icon: 12 },
3232
- md: { height: 36, radius: 6, fieldGap: 16, labelGap: 8, fontSize: 14, lineHeight: 24, icon: 12 }
3246
+ sm: { height: 28, radius: 4, fieldGap: 12, labelGap: 6, fontSize: 12, lineHeight: 20, icon: 16 },
3247
+ md: { height: 36, radius: 6, fieldGap: 16, labelGap: 8, fontSize: 14, lineHeight: 24, icon: 16 }
3233
3248
  };
3234
3249
  var ALIGN = {
3235
3250
  start: "flex-start",
@@ -3244,6 +3259,7 @@ var SField = react.forwardRef(function SField2({
3244
3259
  labelTooltip = "",
3245
3260
  labelTooltipProps,
3246
3261
  labelWidth,
3262
+ labelHeight,
3247
3263
  size = "sm",
3248
3264
  addonLabel = "",
3249
3265
  addonAlign = "start",
@@ -3258,6 +3274,7 @@ var SField = react.forwardRef(function SField2({
3258
3274
  readOnly = false,
3259
3275
  width,
3260
3276
  multiline = false,
3277
+ borderless = false,
3261
3278
  children,
3262
3279
  className,
3263
3280
  style,
@@ -3291,8 +3308,8 @@ var SField = react.forwardRef(function SField2({
3291
3308
  const resolvedSuccess = status === "pass";
3292
3309
  const showError = resolvedError && errorMessage !== "";
3293
3310
  const interactive = !disabled && !readOnly;
3294
- const borderColor = disabled ? "var(--color-grey-45)" : interactive && focused ? "var(--sys-color-field-border-focus)" : resolvedSuccess ? "var(--sys-color-field-border-success)" : resolvedError ? "var(--sys-color-field-border-danger)" : "var(--sys-color-field-border-default)";
3295
- const bgColor = disabled ? "var(--color-grey-30)" : readOnly ? "var(--sys-color-field-bg-readOnly)" : "var(--sys-color-field-bg-default)";
3311
+ const borderColor = borderless ? "transparent" : disabled ? "var(--color-grey-45)" : interactive && focused ? "var(--sys-color-field-border-focus)" : resolvedSuccess ? "var(--sys-color-field-border-success)" : resolvedError ? "var(--sys-color-field-border-danger)" : "var(--sys-color-field-border-default)";
3312
+ const bgColor = borderless ? "transparent" : disabled ? "var(--color-grey-30)" : readOnly ? "var(--sys-color-field-bg-readOnly)" : "var(--sys-color-field-bg-default)";
3296
3313
  const textColor = disabled ? "var(--color-grey-65)" : readOnly ? "var(--sys-color-field-text-readOnly)" : "var(--sys-color-field-text-default)";
3297
3314
  return /* @__PURE__ */ jsxRuntime.jsx(
3298
3315
  "div",
@@ -3309,7 +3326,7 @@ var SField = react.forwardRef(function SField2({
3309
3326
  {
3310
3327
  className: "flex shrink-0 items-center font-bold text-(--sys-color-field-text-default)",
3311
3328
  style: {
3312
- height: s.height,
3329
+ height: cssLen(labelHeight) ?? s.height,
3313
3330
  marginRight: s.fieldGap,
3314
3331
  width: cssLen(labelWidth),
3315
3332
  fontSize: s.fontSize,
@@ -3335,14 +3352,14 @@ var SField = react.forwardRef(function SField2({
3335
3352
  {
3336
3353
  className: cn(
3337
3354
  "relative box-border flex min-w-0 items-stretch overflow-hidden border border-solid border-(--field-bc)",
3338
- interactive && "hover:border-(--sys-color-field-border-focus) hover:shadow-[0px_0px_4px_0px_#0071ff66] focus-within:border-(--sys-color-field-border-focus) focus-within:shadow-[0px_0px_4px_0px_#0071ff66]",
3355
+ interactive && !borderless && "hover:border-(--sys-color-field-border-focus) hover:shadow-[0px_0px_4px_0px_#0071ff66] focus-within:border-(--sys-color-field-border-focus) focus-within:shadow-[0px_0px_4px_0px_#0071ff66]",
3339
3356
  disabled && "cursor-not-allowed"
3340
3357
  ),
3341
3358
  style: {
3342
3359
  // @ts-expect-error CSS 변수
3343
3360
  "--field-bc": borderColor,
3344
3361
  // focused/hovered prop이 명시된 경우 강조를 즉시 반영
3345
- ...interactive && focused ? { boxShadow: "0px 0px 4px 0px #0071ff66" } : {},
3362
+ ...interactive && !borderless && focused ? { boxShadow: "0px 0px 4px 0px #0071ff66" } : {},
3346
3363
  ...multiline ? { minHeight: s.height } : { height: s.height },
3347
3364
  "width": cssLen(width),
3348
3365
  "borderRadius": s.radius,
@@ -3387,15 +3404,28 @@ function flattenOptions(options, depth = 1) {
3387
3404
  const out = [];
3388
3405
  for (const o of options) {
3389
3406
  const hasChildren = Array.isArray(o.children) && o.children.length > 0;
3390
- out.push({
3391
- value: String(o.value),
3392
- label: o.label,
3393
- disabled: !!o.disabled,
3394
- depth,
3395
- isGroup: hasChildren,
3396
- raw: o.value
3397
- });
3398
- if (hasChildren) out.push(...flattenOptions(o.children, depth + 1));
3407
+ if (hasChildren) {
3408
+ const childFlat = flattenOptions(o.children, depth + 1);
3409
+ const allChildrenDisabled = childFlat.every((c) => c.disabled);
3410
+ out.push({
3411
+ value: String(o.value),
3412
+ label: o.label,
3413
+ disabled: !!o.disabled || allChildrenDisabled,
3414
+ depth,
3415
+ isGroup: true,
3416
+ raw: o.value
3417
+ });
3418
+ out.push(...childFlat);
3419
+ } else {
3420
+ out.push({
3421
+ value: String(o.value),
3422
+ label: o.label,
3423
+ disabled: !!o.disabled,
3424
+ depth,
3425
+ isGroup: false,
3426
+ raw: o.value
3427
+ });
3428
+ }
3399
3429
  }
3400
3430
  return out;
3401
3431
  }
@@ -3519,6 +3549,9 @@ var SSelect = react.forwardRef(function SSelect2({
3519
3549
  );
3520
3550
  const flat = react.useMemo(() => flattenOptions(options), [options]);
3521
3551
  const selectable = react.useMemo(() => selectableOptions(flat), [flat]);
3552
+ const hasLeaf = react.useMemo(() => flat.some((o) => !o.isGroup), [flat]);
3553
+ const allOptionsDisabled = hasLeaf && selectable.length === 0;
3554
+ const effectiveDisabled = disabled || allOptionsDisabled;
3522
3555
  const showSearch = useSearch && selectable.length >= SEARCH_THRESHOLD;
3523
3556
  const labelByValue = react.useMemo(() => new Map(flat.map((o) => [o.value, o.label])), [flat]);
3524
3557
  const rawByValue = react.useMemo(() => new Map(flat.map((o) => [o.value, o.raw])), [flat]);
@@ -3569,6 +3602,7 @@ var SSelect = react.forwardRef(function SSelect2({
3569
3602
  const selectStore = /* @__PURE__ */ jsxRuntime.jsxs(
3570
3603
  Ariakit__namespace.SelectProvider,
3571
3604
  {
3605
+ animated: portalContainer == null ? 150 : false,
3572
3606
  value: multi ? selected : selected[0] ?? "",
3573
3607
  setValue: (v) => emit(Array.isArray(v) ? v : v === "" ? [] : [v]),
3574
3608
  open,
@@ -3584,10 +3618,10 @@ var SSelect = react.forwardRef(function SSelect2({
3584
3618
  Ariakit__namespace.Select,
3585
3619
  {
3586
3620
  ref: triggerRef,
3587
- disabled,
3621
+ disabled: effectiveDisabled,
3588
3622
  className: "flex h-full w-full cursor-pointer items-center justify-between gap-[8px] bg-transparent px-[12px] text-left text-[12px] leading-[20px] outline-none disabled:cursor-not-allowed",
3589
3623
  style: {
3590
- color: disabled ? "var(--cmp-select-text-disabled)" : isPlaceholder ? "var(--cmp-select-icon-default)" : "var(--cmp-select-text-default)"
3624
+ color: effectiveDisabled ? "var(--cmp-select-text-disabled)" : isPlaceholder ? "var(--cmp-select-icon-default)" : "var(--cmp-select-text-default)"
3591
3625
  },
3592
3626
  children: [
3593
3627
  isHtmlLabel(triggerText) ? /* @__PURE__ */ jsxRuntime.jsx(
@@ -3602,7 +3636,7 @@ var SSelect = react.forwardRef(function SSelect2({
3602
3636
  {
3603
3637
  name: "chevronDown",
3604
3638
  size: 12,
3605
- color: disabled ? "var(--cmp-select-icon-disabled)" : "var(--cmp-select-icon-default)",
3639
+ color: effectiveDisabled ? "var(--cmp-select-icon-disabled)" : "var(--cmp-select-icon-default)",
3606
3640
  className: cn("shrink-0 transition-transform duration-200", open && "rotate-180")
3607
3641
  }
3608
3642
  )
@@ -3616,7 +3650,7 @@ var SSelect = react.forwardRef(function SSelect2({
3616
3650
  portalElement: portalContainer,
3617
3651
  gutter: 4,
3618
3652
  sameWidth: !dropdownWidth,
3619
- className: "z-50 overflow-auto rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] py-[4px] shadow-[2px_2px_12px_2px_rgba(0,0,0,0.1)]",
3653
+ className: "z-50 overflow-auto rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] shadow-[2px_2px_12px_2px_rgba(0,0,0,0.1)] data-[enter]:animate-floating-in-bottom data-[leave]:animate-floating-out-bottom",
3620
3654
  style: {
3621
3655
  maxHeight: dropdownHeight,
3622
3656
  ...dropdownWidth ? { width: dropdownWidth } : {},
@@ -3657,7 +3691,7 @@ var SSelect = react.forwardRef(function SSelect2({
3657
3691
  ),
3658
3692
  hasItems ? /* @__PURE__ */ jsxRuntime.jsx(ItemList, { items: filtered, multi, selected, useSearch: showSearch }) : (
3659
3693
  // 원본 sd-select-listbox__empty (표시할 항목이 없을 때)
3660
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-[12px] py-[12px] text-center text-[12px] leading-[20px] text-[color:var(--cmp-listItem-content-disabled)]", children: "\uD45C\uC2DC\uD560 \uD56D\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4." })
3694
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-[12px] py-[12px] text-left text-[12px] leading-[20px] text-[color:var(--cmp-listItem-content-disabled)]", children: "\uD45C\uC2DC\uD560 \uD56D\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4." })
3661
3695
  )
3662
3696
  ]
3663
3697
  }
@@ -3680,7 +3714,7 @@ var SSelect = react.forwardRef(function SSelect2({
3680
3714
  error: error || ruleError !== "",
3681
3715
  status: rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0,
3682
3716
  errorMessage: ruleError !== "" ? ruleError : errorMessage,
3683
- disabled,
3717
+ disabled: effectiveDisabled,
3684
3718
  width,
3685
3719
  className,
3686
3720
  style,
@@ -3715,7 +3749,11 @@ function ItemList({
3715
3749
  {
3716
3750
  className: cn(
3717
3751
  "select-none py-[4px] pr-[12px] text-[12px] leading-[20px] text-[color:var(--cmp-listItem-content-default)]",
3718
- isDepth1 ? "border-t border-solid border-[color:var(--cmp-listItem-depth1-border-color)] bg-[var(--cmp-listItem-depth1-bg-default)] font-bold" : "bg-[var(--cmp-listItem-depth2-middle-bg)] font-medium"
3752
+ isDepth1 ? "border-t border-solid border-[color:var(--cmp-listItem-depth1-border-color)] bg-[var(--cmp-listItem-depth1-bg-default)] font-bold" : "bg-[var(--cmp-listItem-depth2-middle-bg)] font-medium",
3753
+ // 하위가 전부 비활성이면(select.config 에서 bubble-up) 어미 그룹도 비활성 처리:
3754
+ // 텍스트는 회색(#888), depth1 그룹은 파란 배경 대신 회색(#EEE)으로 (depth2 는 #F6F6F6 유지)
3755
+ o.disabled && "text-[color:var(--cmp-listItem-content-disabled)]",
3756
+ o.disabled && isDepth1 && "bg-[var(--cmp-listItem-depth1-bg-disabled)]"
3719
3757
  ),
3720
3758
  style: { paddingLeft: padLeft },
3721
3759
  children: o.label
@@ -3742,15 +3780,21 @@ function ItemList({
3742
3780
  "span",
3743
3781
  {
3744
3782
  className: cn(
3745
- "flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center rounded-[2px] border border-solid group-data-[active-item]:border-[color:var(--cmp-checkbox-checked-border-inverse)]",
3746
- isSelected ? "border-[color:var(--cmp-checkbox-checked-bg-default)] bg-[var(--cmp-checkbox-checked-bg-default)] group-data-[active-item]:bg-transparent" : "border-[color:var(--cmp-checkbox-unchecked-border-default)] bg-transparent"
3783
+ "flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center rounded-[2px] border border-solid",
3784
+ o.disabled ? (
3785
+ // 비활성: 회색 채움(#E1E1E1) + 회색 테두리(#CCCCCC)
3786
+ "border-[color:var(--cmp-checkbox-border-disabled)] bg-[var(--cmp-checkbox-bg-disabled)]"
3787
+ ) : cn(
3788
+ "group-data-[active-item]:border-[color:var(--cmp-checkbox-checked-border-inverse)]",
3789
+ isSelected ? "border-[color:var(--cmp-checkbox-checked-bg-default)] bg-[var(--cmp-checkbox-checked-bg-default)] group-data-[active-item]:bg-transparent" : "border-[color:var(--cmp-checkbox-unchecked-border-default)] bg-transparent"
3790
+ )
3747
3791
  ),
3748
3792
  children: isSelected && /* @__PURE__ */ jsxRuntime.jsx(
3749
3793
  SIcon,
3750
3794
  {
3751
3795
  name: "checkboxCheck",
3752
3796
  size: 12,
3753
- color: "var(--cmp-checkbox-checked-icon-default)"
3797
+ color: o.disabled ? "var(--cmp-checkbox-checked-icon-disabled)" : "var(--cmp-checkbox-checked-icon-default)"
3754
3798
  }
3755
3799
  )
3756
3800
  }