@ncds/ui-admin 1.8.3 → 1.8.5

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 (217) hide show
  1. package/dist/cjs/assets/scripts/featuredIcon.js +87 -0
  2. package/dist/cjs/assets/scripts/notification/FloatingNotification.js +178 -0
  3. package/dist/cjs/assets/scripts/notification/FullWidthNotification.js +133 -0
  4. package/dist/cjs/assets/scripts/notification/MessageNotification.js +159 -0
  5. package/dist/cjs/assets/scripts/notification/Notification.js +120 -0
  6. package/dist/cjs/assets/scripts/notification/const/classNames.js +50 -0
  7. package/dist/cjs/assets/scripts/notification/const/icons.js +31 -0
  8. package/dist/cjs/assets/scripts/notification/const/index.js +87 -0
  9. package/dist/cjs/assets/scripts/notification/const/sizes.js +46 -0
  10. package/dist/cjs/assets/scripts/notification/const/types.js +14 -0
  11. package/dist/cjs/assets/scripts/notification/index.js +116 -0
  12. package/dist/cjs/assets/scripts/notification/positionSync.js +180 -0
  13. package/dist/cjs/assets/scripts/notification/utils.js +122 -0
  14. package/dist/cjs/assets/scripts/shared/ButtonCloseX.js +45 -0
  15. package/dist/cjs/assets/scripts/utils/sanitize.js +39 -0
  16. package/dist/cjs/src/components/data-display/data-grid/DataGrid.js +5 -1
  17. package/dist/cjs/src/components/data-display/table/Table.js +118 -96
  18. package/dist/cjs/src/components/data-display/table/useTableScrollbars.js +187 -0
  19. package/dist/cjs/src/components/forms-and-input/combo-box/ComboBox.js +11 -10
  20. package/dist/cjs/src/components/forms-and-input/image-file-input/ImageFileInput.js +5 -2
  21. package/dist/cjs/src/components/forms-and-input/select-box/SelectBox.js +67 -29
  22. package/dist/cjs/src/components/index.js +33 -0
  23. package/dist/cjs/src/components/layout/block-container/BlockContainer.js +38 -0
  24. package/dist/cjs/src/components/layout/block-container/index.js +16 -0
  25. package/dist/cjs/src/components/layout/block-header/BlockHeader.js +107 -0
  26. package/dist/cjs/src/components/layout/block-header/SubTitle.js +56 -0
  27. package/dist/cjs/src/components/layout/block-header/index.js +27 -0
  28. package/dist/cjs/src/components/layout/page-title/PageTitle.js +95 -0
  29. package/dist/cjs/src/components/layout/page-title/index.js +16 -0
  30. package/dist/cjs/src/components/overlays/dropdown/Dropdown.js +47 -19
  31. package/dist/cjs/src/components/overlays/notification/CalloutNotification.js +25 -0
  32. package/dist/cjs/src/components/overlays/notification/FloatingNotification.js +86 -13
  33. package/dist/cjs/src/components/overlays/notification/Notification.js +7 -0
  34. package/dist/cjs/src/components/overlays/notification/host.js +12 -0
  35. package/dist/cjs/src/components/overlays/tooltip/Tooltip.js +57 -44
  36. package/dist/cjs/src/components/select-dropdown/SelectDropdown.js +2 -1
  37. package/dist/cjs/src/contexts/FloatingContext.js +11 -0
  38. package/dist/cjs/src/contexts/index.js +16 -0
  39. package/dist/cjs/src/hooks/index.js +11 -0
  40. package/dist/cjs/src/hooks/useFloatingPosition.js +78 -0
  41. package/dist/cjs/src/hooks/usePortalState.js +17 -0
  42. package/dist/cjs/src/utils/dropdown/maxSelection.js +35 -0
  43. package/dist/cjs/src/utils/dropdown/multiSelect.js +72 -15
  44. package/dist/esm/assets/scripts/featuredIcon.js +80 -0
  45. package/dist/esm/assets/scripts/notification/FloatingNotification.js +171 -0
  46. package/dist/esm/assets/scripts/notification/FullWidthNotification.js +126 -0
  47. package/dist/esm/assets/scripts/notification/MessageNotification.js +152 -0
  48. package/dist/esm/assets/scripts/notification/Notification.js +113 -0
  49. package/dist/esm/assets/scripts/notification/const/classNames.js +44 -0
  50. package/dist/esm/assets/scripts/notification/const/icons.js +25 -0
  51. package/dist/esm/assets/scripts/notification/const/index.js +4 -0
  52. package/dist/esm/assets/scripts/notification/const/sizes.js +40 -0
  53. package/dist/esm/assets/scripts/notification/const/types.js +8 -0
  54. package/dist/esm/assets/scripts/notification/index.js +10 -0
  55. package/dist/esm/assets/scripts/notification/positionSync.js +171 -0
  56. package/dist/esm/assets/scripts/notification/utils.js +109 -0
  57. package/dist/esm/assets/scripts/shared/ButtonCloseX.js +37 -0
  58. package/dist/esm/assets/scripts/utils/sanitize.js +31 -0
  59. package/dist/esm/src/components/data-display/data-grid/DataGrid.js +5 -1
  60. package/dist/esm/src/components/data-display/table/Table.js +118 -96
  61. package/dist/esm/src/components/data-display/table/useTableScrollbars.js +179 -0
  62. package/dist/esm/src/components/forms-and-input/combo-box/ComboBox.js +11 -10
  63. package/dist/esm/src/components/forms-and-input/image-file-input/ImageFileInput.js +5 -2
  64. package/dist/esm/src/components/forms-and-input/select-box/SelectBox.js +67 -29
  65. package/dist/esm/src/components/index.js +3 -0
  66. package/dist/esm/src/components/layout/block-container/BlockContainer.js +31 -0
  67. package/dist/esm/src/components/layout/block-container/index.js +1 -0
  68. package/dist/esm/src/components/layout/block-header/BlockHeader.js +100 -0
  69. package/dist/esm/src/components/layout/block-header/SubTitle.js +49 -0
  70. package/dist/esm/src/components/layout/block-header/index.js +2 -0
  71. package/dist/esm/src/components/layout/page-title/PageTitle.js +88 -0
  72. package/dist/esm/src/components/layout/page-title/index.js +1 -0
  73. package/dist/esm/src/components/overlays/dropdown/Dropdown.js +47 -19
  74. package/dist/esm/src/components/overlays/notification/CalloutNotification.js +19 -0
  75. package/dist/esm/src/components/overlays/notification/FloatingNotification.js +86 -14
  76. package/dist/esm/src/components/overlays/notification/Notification.js +7 -0
  77. package/dist/esm/src/components/overlays/notification/host.js +9 -0
  78. package/dist/esm/src/components/overlays/tooltip/Tooltip.js +58 -45
  79. package/dist/esm/src/components/select-dropdown/SelectDropdown.js +2 -1
  80. package/dist/esm/src/contexts/FloatingContext.js +4 -0
  81. package/dist/esm/src/contexts/index.js +1 -0
  82. package/dist/esm/src/hooks/index.js +1 -0
  83. package/dist/esm/src/hooks/useFloatingPosition.js +71 -0
  84. package/dist/esm/src/hooks/usePortalState.js +10 -0
  85. package/dist/esm/src/utils/dropdown/maxSelection.js +27 -0
  86. package/dist/esm/src/utils/dropdown/multiSelect.js +70 -14
  87. package/dist/temp/assets/scripts/featuredIcon.d.ts +22 -0
  88. package/dist/temp/assets/scripts/featuredIcon.js +79 -0
  89. package/dist/temp/assets/scripts/notification/FloatingNotification.d.ts +24 -0
  90. package/dist/temp/assets/scripts/notification/FloatingNotification.js +156 -0
  91. package/dist/temp/assets/scripts/notification/FullWidthNotification.d.ts +21 -0
  92. package/dist/temp/assets/scripts/notification/FullWidthNotification.js +111 -0
  93. package/dist/temp/assets/scripts/notification/MessageNotification.d.ts +22 -0
  94. package/dist/temp/assets/scripts/notification/MessageNotification.js +140 -0
  95. package/dist/temp/assets/scripts/notification/Notification.d.ts +22 -0
  96. package/dist/temp/assets/scripts/notification/Notification.js +112 -0
  97. package/dist/temp/assets/scripts/notification/const/classNames.d.ts +43 -0
  98. package/dist/temp/assets/scripts/notification/const/classNames.js +44 -0
  99. package/dist/temp/assets/scripts/notification/const/icons.d.ts +25 -0
  100. package/dist/temp/assets/scripts/notification/const/icons.js +25 -0
  101. package/dist/temp/assets/scripts/notification/const/index.d.ts +5 -0
  102. package/dist/temp/assets/scripts/notification/const/index.js +4 -0
  103. package/dist/temp/assets/scripts/notification/const/sizes.d.ts +32 -0
  104. package/dist/temp/assets/scripts/notification/const/sizes.js +40 -0
  105. package/dist/temp/assets/scripts/notification/const/types.d.ts +19 -0
  106. package/dist/temp/assets/scripts/notification/const/types.js +8 -0
  107. package/dist/temp/assets/scripts/notification/index.d.ts +8 -0
  108. package/dist/temp/assets/scripts/notification/index.js +10 -0
  109. package/dist/temp/assets/scripts/notification/positionSync.d.ts +50 -0
  110. package/dist/temp/assets/scripts/notification/positionSync.js +170 -0
  111. package/dist/temp/assets/scripts/notification/utils.d.ts +8 -0
  112. package/dist/temp/assets/scripts/notification/utils.js +115 -0
  113. package/dist/temp/assets/scripts/shared/ButtonCloseX.d.ts +5 -0
  114. package/dist/temp/assets/scripts/shared/ButtonCloseX.js +33 -0
  115. package/dist/temp/assets/scripts/utils/sanitize.d.ts +22 -0
  116. package/dist/temp/assets/scripts/utils/sanitize.js +31 -0
  117. package/dist/temp/src/components/data-display/data-grid/DataGrid.js +1 -1
  118. package/dist/temp/src/components/data-display/data-grid/DataGrid.types.d.ts +7 -0
  119. package/dist/temp/src/components/data-display/table/Table.d.ts +4 -1
  120. package/dist/temp/src/components/data-display/table/Table.js +53 -68
  121. package/dist/temp/src/components/data-display/table/types.d.ts +18 -0
  122. package/dist/temp/src/components/data-display/table/useTableScrollbars.d.ts +25 -0
  123. package/dist/temp/src/components/data-display/table/useTableScrollbars.js +136 -0
  124. package/dist/temp/src/components/forms-and-input/combo-box/ComboBox.d.ts +8 -0
  125. package/dist/temp/src/components/forms-and-input/combo-box/ComboBox.js +7 -11
  126. package/dist/temp/src/components/forms-and-input/image-file-input/ImageFileInput.js +1 -1
  127. package/dist/temp/src/components/forms-and-input/select-box/SelectBox.d.ts +13 -0
  128. package/dist/temp/src/components/forms-and-input/select-box/SelectBox.js +30 -3
  129. package/dist/temp/src/components/index.d.ts +3 -0
  130. package/dist/temp/src/components/index.js +3 -0
  131. package/dist/temp/src/components/layout/block-container/BlockContainer.d.ts +19 -0
  132. package/dist/temp/src/components/layout/block-container/BlockContainer.js +11 -0
  133. package/dist/temp/src/components/layout/block-container/index.d.ts +1 -0
  134. package/dist/temp/src/components/layout/block-container/index.js +1 -0
  135. package/dist/temp/src/components/layout/block-header/BlockHeader.d.ts +23 -0
  136. package/dist/temp/src/components/layout/block-header/BlockHeader.js +21 -0
  137. package/dist/temp/src/components/layout/block-header/SubTitle.d.ts +19 -0
  138. package/dist/temp/src/components/layout/block-header/SubTitle.js +8 -0
  139. package/dist/temp/src/components/layout/block-header/index.d.ts +2 -0
  140. package/dist/temp/src/components/layout/block-header/index.js +2 -0
  141. package/dist/temp/src/components/layout/page-title/PageTitle.d.ts +22 -0
  142. package/dist/temp/src/components/layout/page-title/PageTitle.js +19 -0
  143. package/dist/temp/src/components/layout/page-title/index.d.ts +1 -0
  144. package/dist/temp/src/components/layout/page-title/index.js +1 -0
  145. package/dist/temp/src/components/overlays/dropdown/Dropdown.d.ts +5 -0
  146. package/dist/temp/src/components/overlays/dropdown/Dropdown.js +35 -11
  147. package/dist/temp/src/components/overlays/notification/CalloutNotification.d.ts +9 -0
  148. package/dist/temp/src/components/overlays/notification/CalloutNotification.js +6 -0
  149. package/dist/temp/src/components/overlays/notification/FloatingNotification.d.ts +15 -0
  150. package/dist/temp/src/components/overlays/notification/FloatingNotification.js +81 -13
  151. package/dist/temp/src/components/overlays/notification/Notification.d.ts +18 -3
  152. package/dist/temp/src/components/overlays/notification/Notification.js +4 -0
  153. package/dist/temp/src/components/overlays/notification/host.d.ts +9 -0
  154. package/dist/temp/src/components/overlays/notification/host.js +9 -0
  155. package/dist/temp/src/components/overlays/tooltip/Tooltip.d.ts +5 -1
  156. package/dist/temp/src/components/overlays/tooltip/Tooltip.js +25 -22
  157. package/dist/temp/src/components/select-dropdown/SelectDropdown.d.ts +6 -0
  158. package/dist/temp/src/components/select-dropdown/SelectDropdown.js +2 -2
  159. package/dist/temp/src/contexts/FloatingContext.d.ts +6 -0
  160. package/dist/temp/src/contexts/FloatingContext.js +4 -0
  161. package/dist/temp/src/contexts/index.d.ts +1 -0
  162. package/dist/temp/src/contexts/index.js +1 -0
  163. package/dist/temp/src/hooks/index.d.ts +1 -0
  164. package/dist/temp/src/hooks/index.js +1 -0
  165. package/dist/temp/src/hooks/useFloatingPosition.d.ts +19 -0
  166. package/dist/temp/src/hooks/useFloatingPosition.js +55 -0
  167. package/dist/temp/src/hooks/usePortalState.d.ts +6 -0
  168. package/dist/temp/src/hooks/usePortalState.js +7 -0
  169. package/dist/temp/src/utils/dropdown/maxSelection.d.ts +24 -0
  170. package/dist/temp/src/utils/dropdown/maxSelection.js +28 -0
  171. package/dist/temp/src/utils/dropdown/multiSelect.d.ts +42 -2
  172. package/dist/temp/src/utils/dropdown/multiSelect.js +66 -13
  173. package/dist/types/assets/scripts/featuredIcon.d.ts +22 -0
  174. package/dist/types/assets/scripts/notification/FloatingNotification.d.ts +24 -0
  175. package/dist/types/assets/scripts/notification/FullWidthNotification.d.ts +21 -0
  176. package/dist/types/assets/scripts/notification/MessageNotification.d.ts +22 -0
  177. package/dist/types/assets/scripts/notification/Notification.d.ts +22 -0
  178. package/dist/types/assets/scripts/notification/const/classNames.d.ts +43 -0
  179. package/dist/types/assets/scripts/notification/const/icons.d.ts +25 -0
  180. package/dist/types/assets/scripts/notification/const/index.d.ts +5 -0
  181. package/dist/types/assets/scripts/notification/const/sizes.d.ts +32 -0
  182. package/dist/types/assets/scripts/notification/const/types.d.ts +19 -0
  183. package/dist/types/assets/scripts/notification/index.d.ts +8 -0
  184. package/dist/types/assets/scripts/notification/positionSync.d.ts +50 -0
  185. package/dist/types/assets/scripts/notification/utils.d.ts +8 -0
  186. package/dist/types/assets/scripts/shared/ButtonCloseX.d.ts +5 -0
  187. package/dist/types/assets/scripts/utils/sanitize.d.ts +22 -0
  188. package/dist/types/src/components/data-display/data-grid/DataGrid.types.d.ts +7 -0
  189. package/dist/types/src/components/data-display/table/Table.d.ts +4 -1
  190. package/dist/types/src/components/data-display/table/types.d.ts +18 -0
  191. package/dist/types/src/components/data-display/table/useTableScrollbars.d.ts +25 -0
  192. package/dist/types/src/components/forms-and-input/combo-box/ComboBox.d.ts +8 -0
  193. package/dist/types/src/components/forms-and-input/select-box/SelectBox.d.ts +13 -0
  194. package/dist/types/src/components/index.d.ts +3 -0
  195. package/dist/types/src/components/layout/block-container/BlockContainer.d.ts +19 -0
  196. package/dist/types/src/components/layout/block-container/index.d.ts +1 -0
  197. package/dist/types/src/components/layout/block-header/BlockHeader.d.ts +23 -0
  198. package/dist/types/src/components/layout/block-header/SubTitle.d.ts +19 -0
  199. package/dist/types/src/components/layout/block-header/index.d.ts +2 -0
  200. package/dist/types/src/components/layout/page-title/PageTitle.d.ts +22 -0
  201. package/dist/types/src/components/layout/page-title/index.d.ts +1 -0
  202. package/dist/types/src/components/overlays/dropdown/Dropdown.d.ts +5 -0
  203. package/dist/types/src/components/overlays/notification/CalloutNotification.d.ts +9 -0
  204. package/dist/types/src/components/overlays/notification/FloatingNotification.d.ts +15 -0
  205. package/dist/types/src/components/overlays/notification/Notification.d.ts +18 -3
  206. package/dist/types/src/components/overlays/notification/host.d.ts +9 -0
  207. package/dist/types/src/components/overlays/tooltip/Tooltip.d.ts +5 -1
  208. package/dist/types/src/components/select-dropdown/SelectDropdown.d.ts +6 -0
  209. package/dist/types/src/contexts/FloatingContext.d.ts +6 -0
  210. package/dist/types/src/contexts/index.d.ts +1 -0
  211. package/dist/types/src/hooks/index.d.ts +1 -0
  212. package/dist/types/src/hooks/useFloatingPosition.d.ts +19 -0
  213. package/dist/types/src/hooks/usePortalState.d.ts +6 -0
  214. package/dist/types/src/utils/dropdown/maxSelection.d.ts +24 -0
  215. package/dist/types/src/utils/dropdown/multiSelect.d.ts +42 -2
  216. package/dist/ui-admin/assets/styles/style.css +596 -64
  217. package/package.json +1 -1
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.ButtonCloseX = ButtonCloseX;
7
+ exports.X_CLOSE_SVG = exports.SVG_SIZE = void 0;
8
+ // 공통 X버튼 로직 (React ButtonCloseX 컴포넌트와 동일한 구조)
9
+ // React ButtonCloseX와 동일한 SVG 사이즈 매핑
10
+ const SVG_SIZE = exports.SVG_SIZE = {
11
+ xs: 16,
12
+ sm: 20,
13
+ md: 20,
14
+ lg: 24
15
+ };
16
+ // X버튼 SVG 아이콘
17
+ const X_CLOSE_SVG = size => `<svg width="${size}" height="${size}" fill="none" viewBox="0 0 24 24" stroke="currentColor">
18
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
19
+ </svg>`;
20
+ // X버튼 렌더링 유틸리티 (React ButtonCloseX와 동일한 인터페이스)
21
+ exports.X_CLOSE_SVG = X_CLOSE_SVG;
22
+ function ButtonCloseX(size) {
23
+ let theme = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'light';
24
+ let additionalClasses = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
25
+ let ariaLabel = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : '닫기';
26
+ let onClick = arguments.length > 4 ? arguments[4] : undefined;
27
+ const svgSize = SVG_SIZE[size];
28
+ const buttonId = `close-btn-${Math.random().toString(36).substr(2, 9)}`;
29
+ const buttonHTML = `
30
+ <button type="button" id="${buttonId}" class="ncua-button-close-x ncua-button-close-x--${size} ncua-button-close-x--${theme} ${additionalClasses}" aria-label="${ariaLabel}">
31
+ ${X_CLOSE_SVG(svgSize.toString())}
32
+ </button>
33
+ `;
34
+ // onClick이 제공된 경우 이벤트 바인딩
35
+ if (onClick) {
36
+ // DOM에 추가된 후 이벤트 바인딩을 위해 setTimeout 사용
37
+ setTimeout(() => {
38
+ const button = document.getElementById(buttonId);
39
+ if (button) {
40
+ button.addEventListener('click', onClick);
41
+ }
42
+ }, 0);
43
+ }
44
+ return buttonHTML;
45
+ }
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.sanitizeHtml = sanitizeHtml;
7
+ exports.setSafeInnerHTML = setSafeInnerHTML;
8
+ var _dompurify = _interopRequireDefault(require("dompurify"));
9
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
+ /**
11
+ * HTML 문자열을 DOMPurify 기본 설정으로 sanitize한다.
12
+ *
13
+ * 제거되는 항목 (기본 설정):
14
+ * - `<script>`, `<iframe>`, `<object>` 등 실행 위험 태그
15
+ * - `onclick`, `onerror` 등 inline 이벤트 핸들러 속성
16
+ * - `href="javascript:..."` 같은 javascript: URL
17
+ *
18
+ * 유지되는 항목:
19
+ * - `<svg>`, `<button>`, `<div>`, `<span>`, `<input>` 등 일반 HTML/SVG 태그
20
+ * - `class`, `style`, `role`, `aria-*`, `data-*` 등 표현용 속성
21
+ * - SVG 표현 속성 (`viewBox`, `stroke`, `fill` 등)
22
+ *
23
+ * 이벤트 바인딩은 addEventListener로 별도 처리할 것.
24
+ */
25
+ function sanitizeHtml(dirty) {
26
+ return _dompurify.default.sanitize(dirty);
27
+ }
28
+ /**
29
+ * 엘리먼트에 콘텐츠를 안전하게 설정한다.
30
+ * - string: sanitize 후 innerHTML 교체
31
+ * - HTMLElement: 기존 자식 제거 후 appendChild
32
+ */
33
+ function setSafeInnerHTML(element, content) {
34
+ if (content instanceof HTMLElement) {
35
+ element.replaceChildren(content);
36
+ return;
37
+ }
38
+ element.innerHTML = sanitizeHtml(content);
39
+ }
@@ -80,7 +80,9 @@ const DataGridTable = /*#__PURE__*/(0, _react.forwardRef)((_ref5, ref) => {
80
80
  fixedHeader,
81
81
  maxHeight,
82
82
  hoverable,
83
- selectable
83
+ selectable,
84
+ horizontalScroll,
85
+ minWidth
84
86
  } = _ref5;
85
87
  return (0, _jsxRuntime.jsx)("div", {
86
88
  ref: ref,
@@ -92,6 +94,8 @@ const DataGridTable = /*#__PURE__*/(0, _react.forwardRef)((_ref5, ref) => {
92
94
  maxHeight: maxHeight,
93
95
  hoverable: hoverable,
94
96
  selectable: selectable,
97
+ horizontalScroll: horizontalScroll,
98
+ minWidth: minWidth,
95
99
  children: children
96
100
  })
97
101
  });
@@ -8,13 +8,19 @@ var _jsxRuntime = require("react/jsx-runtime");
8
8
  var _uiAdminIcon = require("@ncds/ui-admin-icon");
9
9
  var _classnames = _interopRequireDefault(require("classnames"));
10
10
  var _react = require("react");
11
+ var _FloatingContext = require("../../../contexts/FloatingContext");
12
+ var _useTableScrollbars = require("./useTableScrollbars");
11
13
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
- // ──────────────────────────────────────────────
13
- // $table-header-height 동기화 — sticky thead가 차지하는 높이를 maxHeight에 보상
14
- const TABLE_HEADER_HEIGHT = 40;
15
- // 스크롤바 트랙 상하 여백 합계 (top 8px + bottom 8px) — SCSS &--fixed-header &__scrollbar 오프셋과 동기화
16
- const SCROLLBAR_TRACK_OFFSET = 16;
17
- const SCROLLBAR_THUMB_MIN_HEIGHT = 40;
14
+ // 가로 스크롤 디자인 기준 폭 — 14인치 모니터 + LNB 고려한 디자인 권장 너비
15
+ const DEFAULT_HORIZONTAL_SCROLL_MIN_WIDTH = 1140;
16
+ const FLOATING_PORTAL_VALUE = {
17
+ preferPortal: true
18
+ };
19
+ // TABLE_HEADER_HEIGHT·DEFAULT_HORIZONTAL_SCROLL_MIN_WIDTH를 CSS 커스텀 프로퍼티로 주입 — SCSS fallback 단일 소스
20
+ const WRAPPER_STYLE = {
21
+ '--ncua-table-header-height': `${_useTableScrollbars.TABLE_HEADER_HEIGHT}px`,
22
+ '--ncua-table-default-min-width': `${DEFAULT_HORIZONTAL_SCROLL_MIN_WIDTH}px`
23
+ };
18
24
  // Sort Icons (@ncds/ui-admin-icon)
19
25
  // ──────────────────────────────────────────────
20
26
  const SORT_ICONS = {
@@ -79,6 +85,7 @@ const HeaderCell = /*#__PURE__*/(0, _react.forwardRef)((_ref4, ref) => {
79
85
  sortDirection,
80
86
  onSort,
81
87
  width,
88
+ minWidth,
82
89
  style,
83
90
  ...rest
84
91
  } = _ref4;
@@ -91,7 +98,8 @@ const HeaderCell = /*#__PURE__*/(0, _react.forwardRef)((_ref4, ref) => {
91
98
  }),
92
99
  style: {
93
100
  ...style,
94
- width
101
+ width,
102
+ minWidth
95
103
  },
96
104
  "aria-sort": isSortable ? ARIA_SORT_MAP[sortDirection] : undefined,
97
105
  onClick: isSortable ? onSort : undefined,
@@ -160,10 +168,11 @@ const Pagination = _ref7 => {
160
168
  Pagination.displayName = 'Table.Pagination';
161
169
  const ColGroup = _ref8 => {
162
170
  let {
163
- widths
171
+ widths,
172
+ minWidths
164
173
  } = _ref8;
165
174
  const resolveColWidth = width => {
166
- if (width === 'auto') return undefined;
175
+ if (width === undefined || width === 'auto') return undefined;
167
176
  if (typeof width === 'number') return `${width}px`;
168
177
  return width;
169
178
  };
@@ -172,7 +181,8 @@ const ColGroup = _ref8 => {
172
181
  // biome-ignore lint/suspicious/noArrayIndexKey: colgroup columns never reorder or change
173
182
  (0, _jsxRuntime.jsx)("col", {
174
183
  style: {
175
- width: resolveColWidth(width)
184
+ width: resolveColWidth(width),
185
+ minWidth: resolveColWidth(minWidths?.[index])
176
186
  }
177
187
  }, index))
178
188
  });
@@ -234,6 +244,8 @@ const TableComponent = /*#__PURE__*/(0, _react.forwardRef)((_ref0, ref) => {
234
244
  maxHeight,
235
245
  hoverable = true,
236
246
  selectable = false,
247
+ horizontalScroll = false,
248
+ minWidth,
237
249
  children,
238
250
  className,
239
251
  ...rest
@@ -253,90 +265,104 @@ const TableComponent = /*#__PURE__*/(0, _react.forwardRef)((_ref0, ref) => {
253
265
  paginationContent
254
266
  } = sortChildren(children);
255
267
  const scrollStyle = fixedHeader && maxHeight ? {
256
- maxHeight: typeof maxHeight === 'number' ? `${maxHeight + TABLE_HEADER_HEIGHT}px` : `calc(${maxHeight} + ${TABLE_HEADER_HEIGHT}px)`
268
+ maxHeight: typeof maxHeight === 'number' ? `${maxHeight + _useTableScrollbars.TABLE_HEADER_HEIGHT}px` : `calc(${maxHeight} + ${_useTableScrollbars.TABLE_HEADER_HEIGHT}px)`
257
269
  } : undefined;
258
270
  // Custom scrollbar refs (used only in fixed-header mode)
259
271
  const scrollContainerRef = (0, _react.useRef)(null);
260
272
  const scrollAreaRef = (0, _react.useRef)(null);
273
+ const scrollbarRef = (0, _react.useRef)(null);
261
274
  const thumbRef = (0, _react.useRef)(null);
262
- (0, _react.useEffect)(() => {
263
- if (!fixedHeader || !maxHeight) return;
264
- const scrollEl = scrollContainerRef.current;
265
- const thumbEl = thumbRef.current;
266
- if (!scrollEl || !thumbEl) return;
267
- const update = () => {
268
- const {
269
- scrollTop,
270
- scrollHeight,
271
- clientHeight
272
- } = scrollEl;
273
- if (scrollHeight <= clientHeight) {
274
- thumbEl.style.height = '0';
275
- return;
276
- }
277
- const trackHeight = (scrollAreaRef.current?.clientHeight ?? clientHeight) - TABLE_HEADER_HEIGHT - SCROLLBAR_TRACK_OFFSET;
278
- const thumbHeight = Math.max(SCROLLBAR_THUMB_MIN_HEIGHT, clientHeight / scrollHeight * trackHeight);
279
- const thumbTop = scrollTop / (scrollHeight - clientHeight) * (trackHeight - thumbHeight);
280
- thumbEl.style.height = `${thumbHeight}px`;
281
- thumbEl.style.transform = `translateY(${thumbTop}px)`;
282
- };
283
- scrollEl.addEventListener('scroll', update, {
284
- passive: true
285
- });
286
- const observer = new ResizeObserver(update);
287
- observer.observe(scrollEl);
288
- update();
289
- return () => {
290
- scrollEl.removeEventListener('scroll', update);
291
- observer.disconnect();
292
- };
293
- }, [fixedHeader, maxHeight]);
294
- const handleThumbMouseDown = e => {
295
- e.preventDefault();
296
- const scrollEl = scrollContainerRef.current;
297
- const thumbEl = thumbRef.current;
298
- const areaEl = scrollAreaRef.current;
299
- if (!scrollEl || !thumbEl) return;
300
- areaEl?.setAttribute('data-dragging', '');
301
- const startY = e.clientY;
302
- const startScrollTop = scrollEl.scrollTop;
303
- const {
304
- scrollHeight,
305
- clientHeight
306
- } = scrollEl;
307
- const thumbHeight = thumbEl.offsetHeight;
308
- const scrollRatio = (scrollHeight - clientHeight) / (clientHeight - thumbHeight);
309
- const onMove = ev => {
310
- scrollEl.scrollTop = startScrollTop + (ev.clientY - startY) * scrollRatio;
311
- };
312
- const onUp = () => {
313
- areaEl?.removeAttribute('data-dragging');
314
- document.removeEventListener('mousemove', onMove);
315
- document.removeEventListener('mouseup', onUp);
316
- };
317
- document.addEventListener('mousemove', onMove);
318
- document.addEventListener('mouseup', onUp);
275
+ // 가로 스크롤바 refs (horizontalScroll 모드)
276
+ const hScrollContainerRef = (0, _react.useRef)(null);
277
+ const hScrollbarRef = (0, _react.useRef)(null);
278
+ const hThumbRef = (0, _react.useRef)(null);
279
+ const fixedScrollEnabled = !!(fixedHeader && maxHeight);
280
+ const {
281
+ handleThumbMouseDown
282
+ } = (0, _useTableScrollbars.useTableVerticalScrollbar)({
283
+ enabled: fixedScrollEnabled,
284
+ scrollContainerRef,
285
+ scrollAreaRef,
286
+ thumbRef
287
+ });
288
+ const {
289
+ handleHThumbMouseDown
290
+ } = (0, _useTableScrollbars.useTableHorizontalScrollbar)({
291
+ enabled: horizontalScroll,
292
+ hScrollContainerRef,
293
+ hScrollbarRef,
294
+ hThumbRef
295
+ });
296
+ // <colgroup> + <thead> + <tbody> 묶음 — fixed-header 분기와 horizontalScroll 분기 모두에서 재사용
297
+ const renderTable = () => (0, _jsxRuntime.jsxs)("table", {
298
+ className: "ncua-table__table",
299
+ role: "table",
300
+ children: [colGroupContent, headerContent, tableContent]
301
+ });
302
+ // fixed-header scroll-area + scrollbar 래핑, 아니면 <table> 그대로.
303
+ // withScrollbar=false 이면 scrollbar를 제외 — horizontalScroll 분기에서 scrollbar를
304
+ // h-scroll-container 형제 위치에 별도 렌더해 가로 스크롤 시 viewport 우측에 자연 고정.
305
+ const renderScrollableArea = function () {
306
+ let includeVerticalScrollbar = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
307
+ return fixedScrollEnabled ? (0, _jsxRuntime.jsxs)("div", {
308
+ ref: scrollAreaRef,
309
+ className: "ncua-table__scroll-area",
310
+ children: [(0, _jsxRuntime.jsx)("div", {
311
+ ref: scrollContainerRef,
312
+ className: "ncua-table__scroll-container",
313
+ style: scrollStyle,
314
+ children: renderTable()
315
+ }), includeVerticalScrollbar && (0, _jsxRuntime.jsx)("div", {
316
+ ref: scrollbarRef,
317
+ className: "ncua-table__scrollbar",
318
+ "aria-hidden": "true",
319
+ children: (0, _jsxRuntime.jsx)("div", {
320
+ ref: thumbRef,
321
+ className: "ncua-table__scrollbar-thumb",
322
+ onMouseDown: handleThumbMouseDown
323
+ })
324
+ })]
325
+ }) : renderTable();
319
326
  };
320
- if (fixedHeader && maxHeight) {
321
- return (0, _jsxRuntime.jsxs)("div", {
322
- ref: ref,
323
- className: "ncua-table-wrapper",
324
- children: [(0, _jsxRuntime.jsxs)("div", {
325
- className: tableClasses,
326
- ...rest,
327
+ // horizontalScroll=true 외곽 wrapper + FloatingProvider 부착.
328
+ // 핵심 — __h-scroll-container 는 <table>(또는 scroll-area) 만 감싸고, footer/pagination 은
329
+ // 그 바깥에서 항상 고정 위치. 세로 스크롤바는 h-scroll-container 형제로 배치되어
330
+ // 가로 스크롤에 영향받지 않고 .ncua-table 우측에 absolute 고정된다.
331
+ if (horizontalScroll) {
332
+ const resolvedMinWidth = minWidth ?? DEFAULT_HORIZONTAL_SCROLL_MIN_WIDTH;
333
+ // CSS 변수로 전달 — SCSS 에서 max(100%, var(--ncua-table-min-width)) 로 부모 너비를 항상 보장한다.
334
+ // (inline min-width 를 직접 주면 부모보다 작은 값에서 wrapper 가 좁아져 콘텐츠가 깨짐)
335
+ const innerStyle = {
336
+ '--ncua-table-min-width': typeof resolvedMinWidth === 'number' ? `${resolvedMinWidth}px` : resolvedMinWidth
337
+ };
338
+ return (0, _jsxRuntime.jsx)(_FloatingContext.FloatingProvider, {
339
+ value: FLOATING_PORTAL_VALUE,
340
+ children: (0, _jsxRuntime.jsxs)("div", {
341
+ ref: ref,
342
+ className: "ncua-table-wrapper",
343
+ style: WRAPPER_STYLE,
327
344
  children: [(0, _jsxRuntime.jsxs)("div", {
328
- ref: scrollAreaRef,
329
- className: "ncua-table__scroll-area",
330
- children: [(0, _jsxRuntime.jsx)("div", {
331
- ref: scrollContainerRef,
332
- className: "ncua-table__scroll-container",
333
- style: scrollStyle,
334
- children: (0, _jsxRuntime.jsxs)("table", {
335
- className: "ncua-table__table",
336
- role: "table",
337
- children: [colGroupContent, headerContent, tableContent]
338
- })
339
- }), (0, _jsxRuntime.jsx)("div", {
345
+ className: tableClasses,
346
+ ...rest,
347
+ children: [(0, _jsxRuntime.jsxs)("div", {
348
+ ref: hScrollContainerRef,
349
+ className: "ncua-table__h-scroll-container",
350
+ children: [(0, _jsxRuntime.jsx)("div", {
351
+ className: "ncua-table__h-scroll-inner",
352
+ style: innerStyle,
353
+ children: renderScrollableArea(false)
354
+ }), (0, _jsxRuntime.jsx)("div", {
355
+ ref: hScrollbarRef,
356
+ className: "ncua-table__h-scrollbar",
357
+ "aria-hidden": "true",
358
+ children: (0, _jsxRuntime.jsx)("div", {
359
+ ref: hThumbRef,
360
+ className: "ncua-table__h-scrollbar-thumb",
361
+ onMouseDown: handleHThumbMouseDown
362
+ })
363
+ })]
364
+ }), fixedScrollEnabled && (0, _jsxRuntime.jsx)("div", {
365
+ ref: scrollbarRef,
340
366
  className: "ncua-table__scrollbar",
341
367
  "aria-hidden": "true",
342
368
  children: (0, _jsxRuntime.jsx)("div", {
@@ -344,23 +370,19 @@ const TableComponent = /*#__PURE__*/(0, _react.forwardRef)((_ref0, ref) => {
344
370
  className: "ncua-table__scrollbar-thumb",
345
371
  onMouseDown: handleThumbMouseDown
346
372
  })
347
- })]
348
- }), footerContent]
349
- }), paginationContent]
373
+ }), footerContent]
374
+ }), paginationContent]
375
+ })
350
376
  });
351
377
  }
352
- const tableElement = (0, _jsxRuntime.jsxs)("table", {
353
- className: "ncua-table__table",
354
- role: "table",
355
- children: [colGroupContent, headerContent, tableContent]
356
- });
357
378
  return (0, _jsxRuntime.jsxs)("div", {
358
379
  ref: ref,
359
380
  className: "ncua-table-wrapper",
381
+ style: WRAPPER_STYLE,
360
382
  children: [(0, _jsxRuntime.jsxs)("div", {
361
383
  className: tableClasses,
362
384
  ...rest,
363
- children: [tableElement, footerContent]
385
+ children: [renderScrollableArea(), footerContent]
364
386
  }), paginationContent]
365
387
  });
366
388
  });
@@ -0,0 +1,187 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useTableVerticalScrollbar = exports.useTableHorizontalScrollbar = exports.TABLE_HEADER_HEIGHT = exports.SCROLLBAR_TRACK_OFFSET = exports.SCROLLBAR_THUMB_MIN_HEIGHT = exports.H_SCROLLBAR_THUMB_MIN_WIDTH = exports.H_SCROLLBAR_SIDE_GAP = void 0;
7
+ var _react = require("react");
8
+ // ──────────────────────────────────────────────
9
+ // 상수 — Table.tsx 와 _table.scss 양쪽에서 동기화 필요
10
+ // ──────────────────────────────────────────────
11
+ // $table-header-height
12
+ const TABLE_HEADER_HEIGHT = exports.TABLE_HEADER_HEIGHT = 40;
13
+ // 세로/가로 thumb 최소 크기
14
+ const SCROLLBAR_THUMB_MIN_HEIGHT = exports.SCROLLBAR_THUMB_MIN_HEIGHT = 40;
15
+ const H_SCROLLBAR_THUMB_MIN_WIDTH = exports.H_SCROLLBAR_THUMB_MIN_WIDTH = 40;
16
+ // SCSS .ncua-table__h-scrollbar { left/right: var(--spacing-s) = 8px } 와 동기화
17
+ const H_SCROLLBAR_SIDE_GAP = exports.H_SCROLLBAR_SIDE_GAP = 8;
18
+ // 세로 트랙 상하 여백 합계 — top 8 + bottom 8 = 16 (header 회피분 40 은 별도 처리)
19
+ // biome-ignore lint/style/useExportsLast: 상수는 문서 주석과 함께 상단에 정의
20
+ const SCROLLBAR_TRACK_OFFSET = exports.SCROLLBAR_TRACK_OFFSET = 16;
21
+ const startDrag = (e, options) => {
22
+ e.preventDefault();
23
+ const {
24
+ axis,
25
+ scrollEl,
26
+ thumbEl,
27
+ draggingTarget = scrollEl,
28
+ sideGap = 0
29
+ } = options;
30
+ draggingTarget.setAttribute('data-dragging', '');
31
+ if (axis === 'y') {
32
+ const startY = e.clientY;
33
+ const startScrollTop = scrollEl.scrollTop;
34
+ const {
35
+ scrollHeight,
36
+ clientHeight
37
+ } = scrollEl;
38
+ const thumbHeight = thumbEl.offsetHeight;
39
+ const ratio = (scrollHeight - clientHeight) / (clientHeight - thumbHeight);
40
+ const onMove = ev => {
41
+ scrollEl.scrollTop = startScrollTop + (ev.clientY - startY) * ratio;
42
+ };
43
+ const onUp = () => {
44
+ draggingTarget.removeAttribute('data-dragging');
45
+ document.removeEventListener('mousemove', onMove);
46
+ document.removeEventListener('mouseup', onUp);
47
+ };
48
+ document.addEventListener('mousemove', onMove);
49
+ document.addEventListener('mouseup', onUp);
50
+ return;
51
+ }
52
+ const startX = e.clientX;
53
+ const startScrollLeft = scrollEl.scrollLeft;
54
+ const {
55
+ scrollWidth,
56
+ clientWidth
57
+ } = scrollEl;
58
+ const thumbWidth = thumbEl.offsetWidth;
59
+ const trackWidth = clientWidth - sideGap * 2;
60
+ const ratio = (scrollWidth - clientWidth) / (trackWidth - thumbWidth);
61
+ const onMove = ev => {
62
+ scrollEl.scrollLeft = startScrollLeft + (ev.clientX - startX) * ratio;
63
+ };
64
+ const onUp = () => {
65
+ draggingTarget.removeAttribute('data-dragging');
66
+ document.removeEventListener('mousemove', onMove);
67
+ document.removeEventListener('mouseup', onUp);
68
+ };
69
+ document.addEventListener('mousemove', onMove);
70
+ document.addEventListener('mouseup', onUp);
71
+ };
72
+ const useTableVerticalScrollbar = _ref => {
73
+ let {
74
+ enabled,
75
+ scrollContainerRef,
76
+ scrollAreaRef,
77
+ thumbRef
78
+ } = _ref;
79
+ (0, _react.useEffect)(() => {
80
+ if (!enabled) return;
81
+ const scrollEl = scrollContainerRef.current;
82
+ const thumbEl = thumbRef.current;
83
+ if (!scrollEl || !thumbEl) return;
84
+ const update = () => {
85
+ const {
86
+ scrollTop,
87
+ scrollHeight,
88
+ clientHeight
89
+ } = scrollEl;
90
+ if (scrollHeight <= clientHeight) {
91
+ thumbEl.style.height = '0';
92
+ return;
93
+ }
94
+ const trackHeight = (scrollAreaRef.current?.clientHeight ?? clientHeight) - TABLE_HEADER_HEIGHT - SCROLLBAR_TRACK_OFFSET;
95
+ const thumbHeight = Math.max(SCROLLBAR_THUMB_MIN_HEIGHT, clientHeight / scrollHeight * trackHeight);
96
+ const thumbTop = scrollTop / (scrollHeight - clientHeight) * (trackHeight - thumbHeight);
97
+ thumbEl.style.height = `${thumbHeight}px`;
98
+ thumbEl.style.transform = `translateY(${thumbTop}px)`;
99
+ };
100
+ scrollEl.addEventListener('scroll', update, {
101
+ passive: true
102
+ });
103
+ const observer = new ResizeObserver(update);
104
+ observer.observe(scrollEl);
105
+ if (scrollAreaRef.current) observer.observe(scrollAreaRef.current);
106
+ update();
107
+ return () => {
108
+ scrollEl.removeEventListener('scroll', update);
109
+ observer.disconnect();
110
+ };
111
+ }, [enabled, scrollContainerRef, scrollAreaRef, thumbRef]);
112
+ const handleThumbMouseDown = e => {
113
+ const scrollEl = scrollContainerRef.current;
114
+ const thumbEl = thumbRef.current;
115
+ const areaEl = scrollAreaRef.current;
116
+ if (!scrollEl || !thumbEl) return;
117
+ startDrag(e, {
118
+ axis: 'y',
119
+ scrollEl,
120
+ thumbEl,
121
+ draggingTarget: areaEl ?? scrollEl
122
+ });
123
+ };
124
+ return {
125
+ handleThumbMouseDown
126
+ };
127
+ };
128
+ exports.useTableVerticalScrollbar = useTableVerticalScrollbar;
129
+ const useTableHorizontalScrollbar = _ref2 => {
130
+ let {
131
+ enabled,
132
+ hScrollContainerRef,
133
+ hScrollbarRef,
134
+ hThumbRef
135
+ } = _ref2;
136
+ (0, _react.useEffect)(() => {
137
+ if (!enabled) return;
138
+ const hScrollEl = hScrollContainerRef.current;
139
+ const hScrollbarEl = hScrollbarRef.current;
140
+ const hThumbEl = hThumbRef.current;
141
+ if (!hScrollEl || !hScrollbarEl || !hThumbEl) return;
142
+ const update = () => {
143
+ const {
144
+ scrollLeft,
145
+ scrollWidth,
146
+ clientWidth
147
+ } = hScrollEl;
148
+ if (scrollWidth <= clientWidth) {
149
+ hThumbEl.style.width = '0';
150
+ return;
151
+ }
152
+ // transform으로 스크롤 오프셋 보정 — reflow 없이 compositor-only 이동
153
+ hScrollbarEl.style.transform = `translateX(${scrollLeft}px)`;
154
+ hScrollbarEl.style.width = `${clientWidth - H_SCROLLBAR_SIDE_GAP * 2}px`;
155
+ const trackWidth = clientWidth - H_SCROLLBAR_SIDE_GAP * 2;
156
+ const thumbWidth = Math.max(H_SCROLLBAR_THUMB_MIN_WIDTH, clientWidth / scrollWidth * trackWidth);
157
+ const thumbLeft = scrollLeft / (scrollWidth - clientWidth) * (trackWidth - thumbWidth);
158
+ hThumbEl.style.width = `${thumbWidth}px`;
159
+ hThumbEl.style.transform = `translateX(${thumbLeft}px)`;
160
+ };
161
+ hScrollEl.addEventListener('scroll', update, {
162
+ passive: true
163
+ });
164
+ const ro = new ResizeObserver(update);
165
+ ro.observe(hScrollEl);
166
+ update();
167
+ return () => {
168
+ hScrollEl.removeEventListener('scroll', update);
169
+ ro.disconnect();
170
+ };
171
+ }, [enabled, hScrollContainerRef, hScrollbarRef, hThumbRef]);
172
+ const handleHThumbMouseDown = e => {
173
+ const hScrollEl = hScrollContainerRef.current;
174
+ const hThumbEl = hThumbRef.current;
175
+ if (!hScrollEl || !hThumbEl) return;
176
+ startDrag(e, {
177
+ axis: 'x',
178
+ scrollEl: hScrollEl,
179
+ thumbEl: hThumbEl,
180
+ sideGap: H_SCROLLBAR_SIDE_GAP
181
+ });
182
+ };
183
+ return {
184
+ handleHThumbMouseDown
185
+ };
186
+ };
187
+ exports.useTableHorizontalScrollbar = useTableHorizontalScrollbar;
@@ -17,13 +17,6 @@ var _HintText = require("../../shared/hintText/HintText");
17
17
  var _InputBase = require("../input-base/InputBase");
18
18
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
19
19
  const defaultMaxHeight = exports.defaultMaxHeight = 275;
20
- const toggleMultiSelectValue = (currentValue, optionId) => {
21
- const currentValues = Array.isArray(currentValue) ? currentValue : [];
22
- if (currentValues.includes(optionId)) {
23
- return currentValues.filter(v => v !== optionId);
24
- }
25
- return [...currentValues, optionId];
26
- };
27
20
  const notifyFormChange = (register, multiple, newValue) => {
28
21
  if (register?.onChange) {
29
22
  register.onChange({
@@ -55,6 +48,7 @@ const ComboBox = exports.ComboBox = /*#__PURE__*/(0, _react.forwardRef)((_ref, r
55
48
  required = false,
56
49
  multiple = false,
57
50
  showFooterButtons = false,
51
+ maxSelection,
58
52
  onEdit,
59
53
  ...props
60
54
  } = _ref;
@@ -67,7 +61,8 @@ const ComboBox = exports.ComboBox = /*#__PURE__*/(0, _react.forwardRef)((_ref, r
67
61
  const handleOptionSelect = option => {
68
62
  if (disabled) return;
69
63
  if (multiple) {
70
- const newValue = toggleMultiSelectValue(value ?? [], option.id);
64
+ const newValue = tryToggle(option.id, Array.isArray(value) ? value : []);
65
+ if (newValue === null) return;
71
66
  onChange?.(newValue);
72
67
  notifyFormChange(register, multiple, newValue);
73
68
  return;
@@ -144,6 +139,7 @@ const ComboBox = exports.ComboBox = /*#__PURE__*/(0, _react.forwardRef)((_ref, r
144
139
  // 나머지는 useDropdown 훅에서 처리
145
140
  dropdownHandleKeyDown(e);
146
141
  };
142
+ // biome-ignore lint/style/noNonNullAssertion: forwardRef 패턴에서 internalRef는 첫 렌더 후 항상 존재
147
143
  (0, _react.useImperativeHandle)(ref, () => internalRef.current, []);
148
144
  const trailingElement = {
149
145
  type: 'custom',
@@ -173,8 +169,12 @@ const ComboBox = exports.ComboBox = /*#__PURE__*/(0, _react.forwardRef)((_ref, r
173
169
  buttonText: selectAllButtonText,
174
170
  toggleSelectAll,
175
171
  getSelectedTagsData,
176
- removeTag
177
- } = (0, _multiSelect.useMultiSelect)(currentSelectedValues, optionItems);
172
+ removeTag,
173
+ isMaxSelectionActive,
174
+ tryToggle
175
+ } = (0, _multiSelect.useMultiSelect)(currentSelectedValues, optionItems, {
176
+ maxSelection
177
+ });
178
178
  const handleSelectAll = () => {
179
179
  if (!multiple || !onChange) return;
180
180
  const newSelectedValues = toggleSelectAll();
@@ -260,6 +260,7 @@ const ComboBox = exports.ComboBox = /*#__PURE__*/(0, _react.forwardRef)((_ref, r
260
260
  multiple: multiple,
261
261
  showFooterButtons: showFooter,
262
262
  selectAllButtonText: selectAllButtonText,
263
+ showSelectAllAction: !isMaxSelectionActive,
263
264
  onSelectAll: handleSelectAll,
264
265
  onEdit: handleEdit,
265
266
  onComplete: handleComplete,
@@ -139,9 +139,12 @@ const ImageFileInput = exports.ImageFileInput = /*#__PURE__*/(0, _react.forwardR
139
139
  onClick: handleBrowseClick,
140
140
  disabled: disabled,
141
141
  label: imagePreviewTooltipLabel
142
- }), isButtonHovered && !disabled && (0, _jsxRuntime.jsx)(_tooltip.Tooltip, {
142
+ }), (0, _jsxRuntime.jsx)(_tooltip.Tooltip, {
143
143
  content: imagePreviewTooltipLabel,
144
- position: "bottom"
144
+ position: "bottom",
145
+ tooltipType: "black",
146
+ forceVisible: isButtonHovered && !disabled,
147
+ disablePortal: true
145
148
  })]
146
149
  })]
147
150
  });