@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
@@ -2,8 +2,11 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import { ChevronDown } from '@ncds/ui-admin-icon';
3
3
  import classNames from 'classnames';
4
4
  import { forwardRef, useCallback, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from 'react';
5
+ import { createPortal } from 'react-dom';
5
6
  import { COLOR } from '../../../../constant/color';
6
7
  import { useDropdown, useScrollLock } from '../../../hooks/dropdown';
8
+ import { useFloatingPosition } from '../../../hooks/useFloatingPosition';
9
+ import { usePortalState } from '../../../hooks/usePortalState';
7
10
  import { useMultiSelect } from '../../../utils/dropdown/multiSelect';
8
11
  import { Tag } from '../../feedback-and-status/tag';
9
12
  import { SelectDropdown } from '../../select-dropdown';
@@ -54,7 +57,9 @@ function DisplayValue(_ref) {
54
57
  })]
55
58
  });
56
59
  }
57
- const SelectBox = /*#__PURE__*/forwardRef((_ref2, ref) => {
60
+ const SelectBox = /*#__PURE__*/forwardRef((_ref2, ref
61
+ // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: 옵션/멀티/태그/포탈 등 필수 분기 통합
62
+ ) => {
58
63
  let {
59
64
  placeholder = '선택하세요',
60
65
  disabledPlaceholder = false,
@@ -68,7 +73,9 @@ const SelectBox = /*#__PURE__*/forwardRef((_ref2, ref) => {
68
73
  disabled = false,
69
74
  maxHeight = DEFAULT_MAX_HEIGHT,
70
75
  multiple = false,
76
+ maxSelection,
71
77
  align = 'left',
78
+ usePortal,
72
79
  id,
73
80
  className,
74
81
  children,
@@ -79,6 +86,10 @@ const SelectBox = /*#__PURE__*/forwardRef((_ref2, ref) => {
79
86
  } = _ref2;
80
87
  const internalRef = useRef(null);
81
88
  const dropdownRef = useRef(null);
89
+ const {
90
+ shouldPortal,
91
+ portalContainer
92
+ } = usePortalState(usePortal);
82
93
  const [selectedTags, setSelectedTags] = useState([]);
83
94
  const selectedOption = useMemo(() => {
84
95
  if (multiple) return null;
@@ -92,6 +103,13 @@ const SelectBox = /*#__PURE__*/forwardRef((_ref2, ref) => {
92
103
  }, [multiple, selectedOption, placeholder]);
93
104
  const handleOptionSelect = option => {
94
105
  if (disabled) return;
106
+ if (multiple) {
107
+ const newValue = tryToggle(option.id, Array.isArray(value) ? value : []);
108
+ if (newValue === null) return;
109
+ onChange?.(newValue);
110
+ notifyRegister(register, newValue, multiple);
111
+ return;
112
+ }
95
113
  const newValue = computeNewValue(option, value, multiple);
96
114
  onChange?.(newValue);
97
115
  notifyRegister(register, newValue, multiple);
@@ -134,8 +152,12 @@ const SelectBox = /*#__PURE__*/forwardRef((_ref2, ref) => {
134
152
  buttonText: selectAllButtonText,
135
153
  toggleSelectAll,
136
154
  getSelectedTagsData,
137
- removeTag
138
- } = useMultiSelect(currentSelectedValues, optionItems);
155
+ removeTag,
156
+ isMaxSelectionActive,
157
+ tryToggle
158
+ } = useMultiSelect(currentSelectedValues, optionItems, {
159
+ maxSelection
160
+ });
139
161
  const handleSelectAll = () => {
140
162
  if (!multiple || !onChange) return;
141
163
  const newSelectedValues = toggleSelectAll();
@@ -160,13 +182,53 @@ const SelectBox = /*#__PURE__*/forwardRef((_ref2, ref) => {
160
182
  }
161
183
  };
162
184
  useScrollLock(isOpen, dropdownRef);
185
+ // biome-ignore lint/correctness/useExhaustiveDependencies: optionItems 변경 시 너비 재계산 필요
163
186
  useLayoutEffect(() => {
164
187
  if (autoWidth && isOpen && dropdownRef.current && internalRef.current) {
165
188
  const dropdownWidth = dropdownRef.current.offsetWidth;
166
189
  internalRef.current.style.width = `${dropdownWidth}px`;
167
190
  }
168
191
  }, [autoWidth, isOpen, optionItems]);
192
+ const floatingStyle = useFloatingPosition({
193
+ enabled: shouldPortal,
194
+ isOpen,
195
+ triggerRef: internalRef,
196
+ floatingRef: dropdownRef,
197
+ direction: dropdownDirection,
198
+ align,
199
+ matchTriggerWidth: true
200
+ });
201
+ // biome-ignore lint/style/noNonNullAssertion: forwardRef 패턴에서 internalRef는 항상 존재
169
202
  useImperativeHandle(ref, () => internalRef.current, []);
203
+ const selectDropdownNode = _jsx(SelectDropdown, {
204
+ ref: dropdownRef,
205
+ isOpen: isOpen,
206
+ direction: dropdownDirection,
207
+ size: size,
208
+ options: optionItems,
209
+ value: value,
210
+ focusedIndex: focusedIndex,
211
+ maxHeight: maxHeight,
212
+ listboxId: `selectbox-options-${id || 'default'}`,
213
+ multiple: multiple,
214
+ showFooterButtons: multiple,
215
+ selectAllButtonText: selectAllButtonText,
216
+ showSelectAllAction: !isMaxSelectionActive,
217
+ componentType: "selectbox",
218
+ isKeyboardNavigation: isKeyboardNavigation,
219
+ activeDescendantId: activeDescendantId,
220
+ align: align,
221
+ className: shouldPortal ? 'ncua-select-dropdown--portal' : undefined,
222
+ style: shouldPortal && floatingStyle ? floatingStyle : undefined,
223
+ onOptionSelect: handleDropdownSelect,
224
+ onMouseMove: handleMouseMove,
225
+ onOptionHover: handleOptionHover,
226
+ onSelectAll: handleSelectAll,
227
+ onEdit: handleEdit,
228
+ onComplete: handleComplete,
229
+ children: children
230
+ });
231
+ const portaledDropdown = shouldPortal && portalContainer && isOpen ? /*#__PURE__*/createPortal(selectDropdownNode, portalContainer) : null;
170
232
  return _jsxs(_Fragment, {
171
233
  children: [_jsxs("div", {
172
234
  ref: internalRef,
@@ -205,31 +267,7 @@ const SelectBox = /*#__PURE__*/forwardRef((_ref2, ref) => {
205
267
  'ncua-selectbox__arrow--up': isOpen
206
268
  })
207
269
  })]
208
- }), _jsx(SelectDropdown, {
209
- ref: dropdownRef,
210
- isOpen: isOpen,
211
- direction: dropdownDirection,
212
- size: size,
213
- options: optionItems,
214
- value: value,
215
- focusedIndex: focusedIndex,
216
- maxHeight: maxHeight,
217
- listboxId: `selectbox-options-${id || 'default'}`,
218
- multiple: multiple,
219
- showFooterButtons: multiple,
220
- selectAllButtonText: selectAllButtonText,
221
- componentType: "selectbox",
222
- isKeyboardNavigation: isKeyboardNavigation,
223
- activeDescendantId: activeDescendantId,
224
- align: align,
225
- onOptionSelect: handleDropdownSelect,
226
- onMouseMove: handleMouseMove,
227
- onOptionHover: handleOptionHover,
228
- onSelectAll: handleSelectAll,
229
- onEdit: handleEdit,
230
- onComplete: handleComplete,
231
- children: children
232
- })]
270
+ }), !shouldPortal && selectDropdownNode]
233
271
  }), hintText && _jsx(HintText, {
234
272
  destructive: destructive,
235
273
  className: "ncua-hint-text",
@@ -247,7 +285,7 @@ const SelectBox = /*#__PURE__*/forwardRef((_ref2, ref) => {
247
285
  close: true,
248
286
  onButtonClick: () => handleRemoveTag(tag.id)
249
287
  }, tag.id))
250
- })]
288
+ }), portaledDropdown]
251
289
  });
252
290
  });
253
291
  SelectBox.displayName = 'SelectBox';
@@ -36,7 +36,10 @@ export * from './forms-and-input/toggle';
36
36
  export * from './image-and-icons/dot';
37
37
  export * from './image-and-icons/featured-icon';
38
38
  // Layout
39
+ export * from './layout/block-container';
40
+ export * from './layout/block-header';
39
41
  export * from './layout/divider';
42
+ export * from './layout/page-title';
40
43
  // Navigation
41
44
  export * from './navigation/bread-crumb';
42
45
  export * from './navigation/horizontal-tab';
@@ -0,0 +1,31 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import classNames from 'classnames';
3
+ const BlockContainerBase = _ref => {
4
+ let {
5
+ children,
6
+ className,
7
+ ...rest
8
+ } = _ref;
9
+ return _jsx("section", {
10
+ className: classNames('ncua-block-container', className),
11
+ ...rest,
12
+ children: children
13
+ });
14
+ };
15
+ BlockContainerBase.displayName = 'BlockContainer';
16
+ const Body = _ref2 => {
17
+ let {
18
+ children,
19
+ className,
20
+ ...rest
21
+ } = _ref2;
22
+ return _jsx("div", {
23
+ className: classNames('ncua-block-container__body', className),
24
+ ...rest,
25
+ children: children
26
+ });
27
+ };
28
+ Body.displayName = 'BlockContainer.Body';
29
+ export const BlockContainer = Object.assign(BlockContainerBase, {
30
+ Body
31
+ });
@@ -0,0 +1 @@
1
+ export * from './BlockContainer';
@@ -0,0 +1,100 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ChevronDown, ChevronUp } from '@ncds/ui-admin-icon';
3
+ import classNames from 'classnames';
4
+ import { Tooltip } from '../../overlays/tooltip/Tooltip';
5
+ const ICON_SIZE = 24;
6
+ const CollapsibleButton = _ref => {
7
+ let {
8
+ expanded,
9
+ onToggle
10
+ } = _ref;
11
+ return _jsx("button", {
12
+ type: "button",
13
+ className: "ncua-block-header__collapsible-btn",
14
+ onClick: onToggle,
15
+ "aria-expanded": expanded,
16
+ children: expanded ? _jsx(ChevronUp, {
17
+ width: ICON_SIZE,
18
+ height: ICON_SIZE,
19
+ color: "var(--gray-300)"
20
+ }) : _jsx(ChevronDown, {
21
+ width: ICON_SIZE,
22
+ height: ICON_SIZE,
23
+ color: "var(--gray-300)"
24
+ })
25
+ });
26
+ };
27
+ const BlockHeader = _ref2 => {
28
+ let {
29
+ title,
30
+ tooltip,
31
+ action,
32
+ showDivider = true,
33
+ badge,
34
+ description,
35
+ collapsible,
36
+ showRequiredNotice = false,
37
+ controlStrip,
38
+ children,
39
+ className,
40
+ ...rest
41
+ } = _ref2;
42
+ const hasColumnLayout = !!description;
43
+ const hasTabChildren = !!children;
44
+ const hasControlStrip = !!controlStrip;
45
+ const isCollapsed = !!collapsible && !collapsible.expanded;
46
+ return _jsxs("header", {
47
+ className: classNames('ncua-block-header', {
48
+ 'ncua-block-header--column': hasColumnLayout,
49
+ 'ncua-block-header--no-divider': !showDivider || hasTabChildren || isCollapsed,
50
+ 'ncua-block-header--has-tab': hasTabChildren && !isCollapsed,
51
+ 'ncua-block-header--has-control-strip': hasControlStrip,
52
+ 'ncua-block-header--is-required': showRequiredNotice
53
+ }, className),
54
+ ...rest,
55
+ children: [_jsxs("div", {
56
+ className: "ncua-block-header__row",
57
+ children: [_jsxs("div", {
58
+ className: "ncua-block-header__title-area",
59
+ children: [_jsx("span", {
60
+ className: "ncua-block-header__title",
61
+ children: title
62
+ }), tooltip && _jsx(Tooltip, {
63
+ content: tooltip,
64
+ size: "sm",
65
+ position: "top",
66
+ hideArrow: true,
67
+ iconType: "fill"
68
+ }), badge && _jsx("span", {
69
+ className: "ncua-block-header__badge",
70
+ children: badge
71
+ })]
72
+ }), _jsxs("div", {
73
+ className: "ncua-block-header__action-area",
74
+ children: [showRequiredNotice && _jsxs("span", {
75
+ className: "ncua-block-header__required-notice",
76
+ children: [_jsx("span", {
77
+ className: "ncua-block-header__required-notice--red",
78
+ children: "* \uB294 \uD544\uC218 \uC785\uB825"
79
+ }), _jsx("span", {
80
+ className: "ncua-block-header__required-notice--gray",
81
+ children: " \uD56D\uBAA9\uC785\uB2C8\uB2E4."
82
+ })]
83
+ }), action, collapsible && _jsx(CollapsibleButton, {
84
+ ...collapsible
85
+ })]
86
+ })]
87
+ }), hasColumnLayout && _jsx("p", {
88
+ className: "ncua-block-header__description",
89
+ children: description
90
+ }), hasControlStrip && _jsx("div", {
91
+ className: "ncua-block-header__control-strip",
92
+ children: controlStrip
93
+ }), hasTabChildren && !isCollapsed && _jsx("div", {
94
+ className: "ncua-block-header__tabs",
95
+ children: children
96
+ })]
97
+ });
98
+ };
99
+ BlockHeader.displayName = 'BlockHeader';
100
+ export { BlockHeader };
@@ -0,0 +1,49 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import classNames from 'classnames';
3
+ import { Tooltip } from '../../overlays/tooltip/Tooltip';
4
+ const SubTitle = _ref => {
5
+ let {
6
+ title,
7
+ size = 'sm',
8
+ tooltip,
9
+ description,
10
+ error,
11
+ action,
12
+ required = false,
13
+ className,
14
+ ...rest
15
+ } = _ref;
16
+ return _jsxs("div", {
17
+ className: classNames('ncua-sub-title', `ncua-sub-title--${size}`, className),
18
+ ...rest,
19
+ children: [_jsxs("div", {
20
+ className: "ncua-sub-title__title-row",
21
+ children: [_jsxs("div", {
22
+ className: "ncua-sub-title__title-area",
23
+ children: [required && _jsx("span", {
24
+ className: "ncua-sub-title__required-marker",
25
+ children: "*"
26
+ }), _jsx("span", {
27
+ className: "ncua-sub-title__title",
28
+ children: title
29
+ }), tooltip && _jsx(Tooltip, {
30
+ content: tooltip,
31
+ size: "sm",
32
+ position: "right",
33
+ hideArrow: true
34
+ })]
35
+ }), action && _jsx("div", {
36
+ className: "ncua-sub-title__action",
37
+ children: action
38
+ })]
39
+ }), description && _jsx("p", {
40
+ className: "ncua-sub-title__description",
41
+ children: description
42
+ }), error && _jsx("p", {
43
+ className: "ncua-sub-title__error",
44
+ children: error
45
+ })]
46
+ });
47
+ };
48
+ SubTitle.displayName = 'BlockHeader.SubTitle';
49
+ export { SubTitle };
@@ -0,0 +1,2 @@
1
+ export * from './BlockHeader';
2
+ export * from './SubTitle';
@@ -0,0 +1,88 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ChevronLeft, ChevronRight } from '@ncds/ui-admin-icon';
3
+ import classNames from 'classnames';
4
+ import { Fragment } from 'react';
5
+ import { Button } from '../../action/button/Button';
6
+ const renderBreadcrumb = items => _jsx("nav", {
7
+ className: "ncua-page-title__breadcrumb",
8
+ "aria-label": "breadcrumb",
9
+ children: items.map((item, i) =>
10
+ // biome-ignore lint/suspicious/noArrayIndexKey: breadcrumb items may have duplicate labels
11
+ _jsx(Fragment, {
12
+ children: i < items.length - 1 ? _jsxs(_Fragment, {
13
+ children: [_jsx("span", {
14
+ className: "ncua-page-title__breadcrumb-item",
15
+ children: item.href ? _jsx("a", {
16
+ href: item.href,
17
+ children: item.label
18
+ }) : item.label
19
+ }), _jsx(ChevronRight, {
20
+ className: "ncua-page-title__breadcrumb-separator"
21
+ })]
22
+ }) : _jsx("span", {
23
+ className: "ncua-page-title__breadcrumb-current",
24
+ children: item.label
25
+ })
26
+ }, i))
27
+ });
28
+ const renderBackButton = onBack => _jsx(Button, {
29
+ label: "",
30
+ hierarchy: "secondary-gray",
31
+ size: "xs",
32
+ onlyIcon: true,
33
+ leadingIcon: {
34
+ type: 'icon',
35
+ icon: ChevronLeft
36
+ },
37
+ onClick: onBack,
38
+ "aria-label": "\uC774\uC804 \uD398\uC774\uC9C0\uB85C \uB3CC\uC544\uAC00\uAE30",
39
+ className: "ncua-page-title__back-btn"
40
+ });
41
+ const PageTitle = _ref => {
42
+ let {
43
+ title,
44
+ variant = 'default',
45
+ breadcrumbItems,
46
+ onBack,
47
+ guideButton,
48
+ primaryAction,
49
+ secondaryAction,
50
+ className,
51
+ ...rest
52
+ } = _ref;
53
+ const isFixed = variant === 'fixed' || variant === 'fixed-detail';
54
+ const isDetail = variant === 'detail' || variant === 'fixed-detail';
55
+ const hasBreadcrumb = !isFixed && breadcrumbItems && breadcrumbItems.length > 0;
56
+ return _jsx("header", {
57
+ className: classNames('ncua-page-title', {
58
+ 'ncua-page-title--fixed': isFixed
59
+ }, className),
60
+ ...rest,
61
+ children: _jsx("div", {
62
+ className: "ncua-page-title__page-header",
63
+ children: _jsxs("div", {
64
+ className: classNames('ncua-page-title__header', {
65
+ 'ncua-page-title__header--has-breadcrumb': hasBreadcrumb
66
+ }),
67
+ children: [_jsxs("div", {
68
+ className: "ncua-page-title__container",
69
+ children: [hasBreadcrumb && renderBreadcrumb(breadcrumbItems), _jsxs("div", {
70
+ className: "ncua-page-title__title-row",
71
+ children: [isDetail && onBack && renderBackButton(onBack), _jsx("h1", {
72
+ className: "ncua-page-title__title",
73
+ children: title
74
+ }), guideButton && _jsx("div", {
75
+ className: "ncua-page-title__guide-btn",
76
+ children: guideButton
77
+ })]
78
+ })]
79
+ }), (secondaryAction || primaryAction) && _jsxs("div", {
80
+ className: "ncua-page-title__actions",
81
+ children: [secondaryAction, primaryAction]
82
+ })]
83
+ })
84
+ })
85
+ });
86
+ };
87
+ PageTitle.displayName = 'PageTitle';
88
+ export { PageTitle };
@@ -0,0 +1 @@
1
+ export * from './PageTitle';
@@ -7,6 +7,9 @@ import { autoScrollForElements } from '@atlaskit/pragmatic-drag-and-drop-auto-sc
7
7
  import { attachClosestEdge, extractClosestEdge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';
8
8
  import { DotsGrid02, DotsVertical, Eye, EyeOff } from '@ncds/ui-admin-icon';
9
9
  import { useEffect, useLayoutEffect, useRef, useState } from 'react';
10
+ import { createPortal } from 'react-dom';
11
+ import { useFloatingPosition } from '../../../hooks/useFloatingPosition';
12
+ import { usePortalState } from '../../../hooks/usePortalState';
10
13
  import { Button } from '../../action/button';
11
14
  import { applyDraftToItems, arrayReorderByEdge, hasDraftChanged, initDraftState } from './utils';
12
15
  const DROPDOWN_ID_RADIX = 36;
@@ -143,6 +146,7 @@ const SortableConfigItem = _ref => {
143
146
  })]
144
147
  });
145
148
  };
149
+ // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: 액션/설정 두 variant 통합 + drag-and-drop 필수 분기
146
150
  export const Dropdown = props => {
147
151
  const {
148
152
  trigger,
@@ -151,14 +155,28 @@ export const Dropdown = props => {
151
155
  groups,
152
156
  className,
153
157
  opened = false,
154
- closeOnClickOutside = true
158
+ closeOnClickOutside = true,
159
+ usePortal
155
160
  } = props;
156
161
  const variant = props.variant ?? 'action';
157
162
  const closeOnClickItem = variant === 'action' ? props.closeOnClickItem ?? true : false;
158
163
  const [isOpen, setIsOpen] = useState(opened);
159
164
  const dropdownRef = useRef(null);
160
165
  const triggerRef = useRef(null);
166
+ const menuRef = useRef(null);
161
167
  const menuItemsRef = useRef(null);
168
+ const {
169
+ shouldPortal,
170
+ portalContainer
171
+ } = usePortalState(usePortal);
172
+ const floatingStyle = useFloatingPosition({
173
+ enabled: shouldPortal,
174
+ isOpen,
175
+ triggerRef,
176
+ floatingRef: menuRef,
177
+ direction: 'down',
178
+ align
179
+ });
162
180
  const dropdownIdRef = useRef(`ncua-dropdown-${Math.random().toString(DROPDOWN_ID_RADIX).slice(DROPDOWN_ID_SLICE_START, DROPDOWN_ID_SLICE_END)}`);
163
181
  const dropdownId = dropdownIdRef.current;
164
182
  useEffect(() => {
@@ -221,7 +239,10 @@ export const Dropdown = props => {
221
239
  triggerRef.current?.focus();
222
240
  };
223
241
  const handleClickOutside = event => {
224
- if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
242
+ const target = event.target;
243
+ const insideContainer = dropdownRef.current?.contains(target) ?? false;
244
+ const insidePortaledMenu = menuRef.current?.contains(target) ?? false;
245
+ if (!insideContainer && !insidePortaledMenu) {
225
246
  setIsOpen(false);
226
247
  }
227
248
  };
@@ -233,6 +254,7 @@ export const Dropdown = props => {
233
254
  }
234
255
  }
235
256
  };
257
+ // biome-ignore lint/correctness/useExhaustiveDependencies: handleClickOutside는 안정적 참조
236
258
  useEffect(() => {
237
259
  if (closeOnClickOutside) {
238
260
  document.addEventListener('mousedown', handleClickOutside);
@@ -242,6 +264,7 @@ export const Dropdown = props => {
242
264
  }
243
265
  }, [closeOnClickOutside]);
244
266
  // ESC 키로 닫고 trigger로 포커스 복귀
267
+ // biome-ignore lint/correctness/useExhaustiveDependencies: closeAndRestoreFocus는 안정적 참조
245
268
  useEffect(() => {
246
269
  if (!isOpen) return;
247
270
  const handleEsc = event => {
@@ -422,25 +445,30 @@ export const Dropdown = props => {
422
445
  });
423
446
  };
424
447
  const dropdownClasses = ['ncua-dropdown', className, align === 'right' ? 'ncua-dropdown--right' : ''].filter(Boolean).join(' ');
448
+ const menuClasses = ['ncua-dropdown__menu', shouldPortal ? 'ncua-dropdown__menu--portal' : ''].filter(Boolean).join(' ');
449
+ const menuNode = isOpen ? _jsxs("div", {
450
+ ref: menuRef,
451
+ className: menuClasses,
452
+ role: variant === 'config' ? 'dialog' : 'menu',
453
+ "aria-label": variant === 'config' ? '설정' : undefined,
454
+ style: shouldPortal && floatingStyle ? floatingStyle : undefined,
455
+ children: [renderHeader(), _jsx("div", {
456
+ ref: menuItemsRef,
457
+ className: "ncua-dropdown__menu-items",
458
+ children: groups.map(group => {
459
+ // config variant uses draft.order to drive the rendered order
460
+ const orderedItems = variant === 'config' && draft ? draft.order.map(id => group.items.find(i => i.id === id)).filter(i => i !== undefined) : group.items;
461
+ return _jsx("div", {
462
+ className: "ncua-dropdown__group",
463
+ children: orderedItems.map(item => variant === 'config' ? renderConfigItem(item, group.sortable === true) : renderActionItem(item))
464
+ }, group.items[0]?.id);
465
+ })
466
+ }), renderFooter()]
467
+ }) : null;
468
+ const portaledMenu = shouldPortal && portalContainer && menuNode ? /*#__PURE__*/createPortal(menuNode, portalContainer) : null;
425
469
  return _jsxs("div", {
426
470
  className: dropdownClasses,
427
471
  ref: dropdownRef,
428
- children: [renderTrigger(), isOpen && _jsxs("div", {
429
- className: "ncua-dropdown__menu",
430
- role: variant === 'config' ? 'dialog' : 'menu',
431
- "aria-label": variant === 'config' ? '설정' : undefined,
432
- children: [renderHeader(), _jsx("div", {
433
- ref: menuItemsRef,
434
- className: "ncua-dropdown__menu-items",
435
- children: groups.map(group => {
436
- // config variant uses draft.order to drive the rendered order
437
- const orderedItems = variant === 'config' && draft ? draft.order.map(id => group.items.find(i => i.id === id)).filter(i => i !== undefined) : group.items;
438
- return _jsx("div", {
439
- className: "ncua-dropdown__group",
440
- children: orderedItems.map(item => variant === 'config' ? renderConfigItem(item, group.sortable === true) : renderActionItem(item))
441
- }, group.items[0]?.id);
442
- })
443
- }), renderFooter()]
444
- })]
472
+ children: [renderTrigger(), !shouldPortal && menuNode, portaledMenu]
445
473
  });
446
474
  };
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import classNames from 'classnames';
3
+ import { forwardRef } from 'react';
4
+ const CalloutNotification = /*#__PURE__*/forwardRef((_ref, ref) => {
5
+ let {
6
+ color = 'neutral',
7
+ className,
8
+ title,
9
+ ...rest
10
+ } = _ref;
11
+ return _jsx("div", {
12
+ ref: ref,
13
+ className: classNames('ncua-callout-notification', `ncua-callout-notification--${color}`, className),
14
+ ...rest,
15
+ children: title
16
+ });
17
+ });
18
+ CalloutNotification.displayName = 'CalloutNotification';
19
+ export { CalloutNotification };