@ncds/ui-admin 1.8.25-alpha.0 → 1.8.25-alpha.2

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 (71) hide show
  1. package/dist/cjs/src/components/forms-and-input/combo-box/ComboBox.js +109 -28
  2. package/dist/cjs/src/components/forms-and-input/combo-box/__tests__/ComboBox.portal.test.js +581 -0
  3. package/dist/cjs/src/generated/scoped-css.js +1 -1
  4. package/dist/cjs/src/hooks/__tests__/useFloatingPosition.ssr.test.js +29 -0
  5. package/dist/cjs/src/hooks/__tests__/useFloatingPosition.test.js +322 -0
  6. package/dist/cjs/src/hooks/dropdown/useDropdown.js +2 -1
  7. package/dist/cjs/src/hooks/useFloatingPosition.js +14 -53
  8. package/dist/cjs/src/utils/dropdown/__tests__/dropdownUtils.test.js +316 -0
  9. package/dist/cjs/src/utils/dropdown/dropdownUtils.js +8 -12
  10. package/dist/cjs/src/utils/portal-position/__tests__/portalPosition.test.js +227 -0
  11. package/dist/cjs/src/utils/portal-position/__tests__/portalPosition.tracking.test.js +397 -0
  12. package/dist/cjs/src/utils/portal-position/index.js +16 -0
  13. package/dist/cjs/src/utils/portal-position/portalPosition.js +162 -0
  14. package/dist/esm/src/components/forms-and-input/combo-box/ComboBox.js +109 -28
  15. package/dist/esm/src/components/forms-and-input/combo-box/__tests__/ComboBox.portal.test.js +578 -0
  16. package/dist/esm/src/generated/scoped-css.js +1 -1
  17. package/dist/esm/src/hooks/__tests__/useFloatingPosition.ssr.test.js +26 -0
  18. package/dist/esm/src/hooks/__tests__/useFloatingPosition.test.js +319 -0
  19. package/dist/esm/src/hooks/dropdown/useDropdown.js +2 -1
  20. package/dist/esm/src/hooks/useFloatingPosition.js +15 -54
  21. package/dist/esm/src/utils/dropdown/__tests__/dropdownUtils.test.js +314 -0
  22. package/dist/esm/src/utils/dropdown/dropdownUtils.js +8 -12
  23. package/dist/esm/src/utils/portal-position/__tests__/portalPosition.test.js +225 -0
  24. package/dist/esm/src/utils/portal-position/__tests__/portalPosition.tracking.test.js +394 -0
  25. package/dist/esm/src/utils/portal-position/index.js +1 -0
  26. package/dist/esm/src/utils/portal-position/portalPosition.js +150 -0
  27. package/dist/temp/assets/scripts/notification/const/sizes.d.ts +1 -1
  28. package/dist/temp/src/components/action/button-group/ButtonGroup.d.ts +1 -1
  29. package/dist/temp/src/components/forms-and-input/combo-box/ComboBox.d.ts +6 -0
  30. package/dist/temp/src/components/forms-and-input/combo-box/ComboBox.js +54 -4
  31. package/dist/temp/src/components/forms-and-input/combo-box/__tests__/ComboBox.portal.test.d.ts +1 -0
  32. package/dist/temp/src/components/forms-and-input/combo-box/__tests__/ComboBox.portal.test.js +418 -0
  33. package/dist/temp/src/generated/scoped-css.js +1 -1
  34. package/dist/temp/src/hooks/__tests__/useFloatingPosition.ssr.test.d.ts +1 -0
  35. package/dist/temp/src/hooks/__tests__/useFloatingPosition.ssr.test.js +26 -0
  36. package/dist/temp/src/hooks/__tests__/useFloatingPosition.test.d.ts +1 -0
  37. package/dist/temp/src/hooks/__tests__/useFloatingPosition.test.js +205 -0
  38. package/dist/temp/src/hooks/dropdown/useDropdown.d.ts +3 -1
  39. package/dist/temp/src/hooks/dropdown/useDropdown.js +2 -2
  40. package/dist/temp/src/hooks/dropdown/useDropdownPosition.d.ts +3 -3
  41. package/dist/temp/src/hooks/useFloatingPosition.d.ts +6 -4
  42. package/dist/temp/src/hooks/useFloatingPosition.js +14 -47
  43. package/dist/temp/src/types/dropdown/dropdown.d.ts +2 -1
  44. package/dist/temp/src/utils/dropdown/__tests__/dropdownUtils.test.d.ts +1 -0
  45. package/dist/temp/src/utils/dropdown/__tests__/dropdownUtils.test.js +174 -0
  46. package/dist/temp/src/utils/dropdown/dropdownUtils.js +8 -9
  47. package/dist/temp/src/utils/portal-position/__tests__/portalPosition.test.d.ts +1 -0
  48. package/dist/temp/src/utils/portal-position/__tests__/portalPosition.test.js +181 -0
  49. package/dist/temp/src/utils/portal-position/__tests__/portalPosition.tracking.test.d.ts +1 -0
  50. package/dist/temp/src/utils/portal-position/__tests__/portalPosition.tracking.test.js +301 -0
  51. package/dist/temp/src/utils/portal-position/index.d.ts +1 -0
  52. package/dist/temp/src/utils/portal-position/index.js +1 -0
  53. package/dist/temp/src/utils/portal-position/portalPosition.d.ts +67 -0
  54. package/dist/temp/src/utils/portal-position/portalPosition.js +88 -0
  55. package/dist/types/assets/scripts/notification/const/sizes.d.ts +1 -1
  56. package/dist/types/src/components/action/button-group/ButtonGroup.d.ts +1 -1
  57. package/dist/types/src/components/forms-and-input/combo-box/ComboBox.d.ts +6 -0
  58. package/dist/types/src/components/forms-and-input/combo-box/__tests__/ComboBox.portal.test.d.ts +1 -0
  59. package/dist/types/src/hooks/__tests__/useFloatingPosition.ssr.test.d.ts +1 -0
  60. package/dist/types/src/hooks/__tests__/useFloatingPosition.test.d.ts +1 -0
  61. package/dist/types/src/hooks/dropdown/useDropdown.d.ts +3 -1
  62. package/dist/types/src/hooks/dropdown/useDropdownPosition.d.ts +3 -3
  63. package/dist/types/src/hooks/useFloatingPosition.d.ts +6 -4
  64. package/dist/types/src/types/dropdown/dropdown.d.ts +2 -1
  65. package/dist/types/src/utils/dropdown/__tests__/dropdownUtils.test.d.ts +1 -0
  66. package/dist/types/src/utils/portal-position/__tests__/portalPosition.test.d.ts +1 -0
  67. package/dist/types/src/utils/portal-position/__tests__/portalPosition.tracking.test.d.ts +1 -0
  68. package/dist/types/src/utils/portal-position/index.d.ts +1 -0
  69. package/dist/types/src/utils/portal-position/portalPosition.d.ts +67 -0
  70. package/dist/ui-admin/assets/styles/style.css +13 -1
  71. package/package.json +2 -2
@@ -8,7 +8,10 @@ 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 _reactDom = require("react-dom");
11
12
  var _dropdown = require("../../../hooks/dropdown");
13
+ var _useFloatingPosition = require("../../../hooks/useFloatingPosition");
14
+ var _usePortalState = require("../../../hooks/usePortalState");
12
15
  var _multiSelect = require("../../../utils/dropdown/multiSelect");
13
16
  var _button = require("../../action/button");
14
17
  var _tag = require("../../feedback-and-status/tag");
@@ -27,7 +30,49 @@ const notifyFormChange = (register, multiple, newValue) => {
27
30
  });
28
31
  }
29
32
  };
30
- const ComboBox = exports.ComboBox = /*#__PURE__*/(0, _react.forwardRef)((_ref, ref) => {
33
+ /**
34
+ * Portal 모드에서만 패널에 `--portal` 클래스와 fixed 좌표를 얹는다.
35
+ * floatingStyle 이 null 인 초기 레이아웃 직전에는 클래스만 붙지만,
36
+ * useLayoutEffect 가 paint 전에 좌표를 채우므로 빈 fixed 가 노출되지 않는다.
37
+ */
38
+ const resolvePortalPanelBinding = (shouldPortal, floatingStyle) => {
39
+ if (!shouldPortal) {
40
+ return {};
41
+ }
42
+ return {
43
+ className: 'ncua-select-dropdown--portal',
44
+ style: floatingStyle ?? undefined
45
+ };
46
+ };
47
+ /**
48
+ * 패널 노드를 인라인·Portal 두 마운트 지점 중 한 곳에만 넘긴다. 양쪽에 두면 dropdownRef 가
49
+ * 나중 노드로 덮여 외부 클릭 판정과 키보드 스크롤이 유령 노드를 가리키게 된다.
50
+ */
51
+ const resolveDropdownMounts = _ref => {
52
+ let {
53
+ node,
54
+ shouldPortal,
55
+ portalContainer,
56
+ isOpen
57
+ } = _ref;
58
+ if (!shouldPortal) {
59
+ return {
60
+ inlineDropdown: node,
61
+ portaledDropdown: null
62
+ };
63
+ }
64
+ if (!portalContainer || !isOpen) {
65
+ return {
66
+ inlineDropdown: null,
67
+ portaledDropdown: null
68
+ };
69
+ }
70
+ return {
71
+ inlineDropdown: null,
72
+ portaledDropdown: /*#__PURE__*/(0, _reactDom.createPortal)(node, portalContainer)
73
+ };
74
+ };
75
+ const ComboBox = exports.ComboBox = /*#__PURE__*/(0, _react.forwardRef)((_ref2, ref) => {
31
76
  let {
32
77
  placeholder = '검색하세요',
33
78
  id,
@@ -51,11 +96,19 @@ const ComboBox = exports.ComboBox = /*#__PURE__*/(0, _react.forwardRef)((_ref, r
51
96
  maxSelection,
52
97
  onEdit,
53
98
  onComplete,
99
+ usePortal = false,
54
100
  ...props
55
- } = _ref;
101
+ } = _ref2;
56
102
  const internalRef = (0, _react.useRef)(null);
103
+ // 인라인 패널의 offset parent 가 __content 다. Portal 좌표도 같은 박스를 기준으로 잡아야
104
+ // label·hintText 가 있을 때 두 모드의 패널 위치가 어긋나지 않는다.
105
+ const contentRef = (0, _react.useRef)(null);
57
106
  const dropdownRef = (0, _react.useRef)(null);
58
107
  const inputRef = (0, _react.useRef)(null);
108
+ const {
109
+ shouldPortal,
110
+ portalContainer
111
+ } = (0, _usePortalState.usePortalState)(usePortal);
59
112
  const [inputValue, setInputValue] = (0, _react.useState)(searchValue);
60
113
  const [showAllItems, setShowAllItems] = (0, _react.useState)(false);
61
114
  const [selectedTags, setSelectedTags] = (0, _react.useState)([]);
@@ -108,6 +161,9 @@ const ComboBox = exports.ComboBox = /*#__PURE__*/(0, _react.forwardRef)((_ref, r
108
161
  } = (0, _dropdown.useDropdown)({
109
162
  triggerRef: internalRef,
110
163
  dropdownRef,
164
+ // Portal 모드에서는 hintText 등으로 root 가 content 보다 아래까지 차지할 수 있어
165
+ // internalRef 기준 direction 판정이 잘못될 수 있다. contentRef 로 교정한다.
166
+ positionRef: shouldPortal ? contentRef : undefined,
111
167
  maxHeight,
112
168
  itemCount: optionItems.length,
113
169
  optionItems: optionItems,
@@ -140,6 +196,14 @@ const ComboBox = exports.ComboBox = /*#__PURE__*/(0, _react.forwardRef)((_ref, r
140
196
  // 나머지는 useDropdown 훅에서 처리
141
197
  dropdownHandleKeyDown(e);
142
198
  };
199
+ const floatingStyle = (0, _useFloatingPosition.useFloatingPosition)({
200
+ enabled: shouldPortal,
201
+ isOpen,
202
+ triggerRef: contentRef,
203
+ floatingRef: dropdownRef,
204
+ direction: dropdownDirection,
205
+ matchTriggerWidth: true
206
+ });
143
207
  // biome-ignore lint/style/noNonNullAssertion: forwardRef 패턴에서 internalRef는 첫 렌더 후 항상 존재
144
208
  (0, _react.useImperativeHandle)(ref, () => internalRef.current, []);
145
209
  const trailingElement = {
@@ -210,6 +274,47 @@ const ComboBox = exports.ComboBox = /*#__PURE__*/(0, _react.forwardRef)((_ref, r
210
274
  const showFooter = multiple || showFooterButtons;
211
275
  const hiddenInputValue = multiple ? JSON.stringify(value || []) : String(value || '');
212
276
  const hasTags = selectedTags.length > 0;
277
+ const {
278
+ className: portalPanelClassName,
279
+ style: portalPanelStyle
280
+ } = resolvePortalPanelBinding(shouldPortal, floatingStyle);
281
+ const selectDropdownNode = (0, _jsxRuntime.jsxs)(_selectDropdown.SelectDropdown, {
282
+ ref: dropdownRef,
283
+ isOpen: isOpen,
284
+ direction: dropdownDirection,
285
+ size: size,
286
+ options: displayedOptions,
287
+ value: value,
288
+ focusedIndex: focusedIndex,
289
+ maxHeight: maxHeight,
290
+ listboxId: comboboxId,
291
+ onOptionSelect: handleDropdownSelect,
292
+ onMouseMove: handleMouseMove,
293
+ isKeyboardNavigation: isKeyboardNavigation,
294
+ multiple: multiple,
295
+ showFooterButtons: showFooter,
296
+ selectAllButtonText: selectAllButtonText,
297
+ showSelectAllAction: !isMaxSelectionActive,
298
+ onSelectAll: handleSelectAll,
299
+ onEdit: handleEdit,
300
+ onComplete: handleComplete,
301
+ componentType: "combobox",
302
+ className: portalPanelClassName,
303
+ style: portalPanelStyle,
304
+ children: [showNoResults ? (0, _jsxRuntime.jsx)("li", {
305
+ className: "ncua-select-dropdown__no-results",
306
+ children: "\uC77C\uCE58\uD558\uB294 \uACB0\uACFC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."
307
+ }) : null, children]
308
+ });
309
+ const {
310
+ inlineDropdown,
311
+ portaledDropdown
312
+ } = resolveDropdownMounts({
313
+ node: selectDropdownNode,
314
+ shouldPortal,
315
+ portalContainer,
316
+ isOpen
317
+ });
213
318
  return (0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
214
319
  children: [(0, _jsxRuntime.jsxs)("div", {
215
320
  ref: internalRef,
@@ -220,6 +325,7 @@ const ComboBox = exports.ComboBox = /*#__PURE__*/(0, _react.forwardRef)((_ref, r
220
325
  }, className),
221
326
  ...props,
222
327
  children: [(0, _jsxRuntime.jsxs)("div", {
328
+ ref: contentRef,
223
329
  className: "ncua-combobox__content",
224
330
  children: [(0, _jsxRuntime.jsx)(_InputBase.InputBase, {
225
331
  ref: inputRef,
@@ -246,32 +352,7 @@ const ComboBox = exports.ComboBox = /*#__PURE__*/(0, _react.forwardRef)((_ref, r
246
352
  setInputValue('');
247
353
  onSearch?.('');
248
354
  }
249
- }), (0, _jsxRuntime.jsxs)(_selectDropdown.SelectDropdown, {
250
- ref: dropdownRef,
251
- isOpen: isOpen,
252
- direction: dropdownDirection,
253
- size: size,
254
- options: displayedOptions,
255
- value: value,
256
- focusedIndex: focusedIndex,
257
- maxHeight: maxHeight,
258
- listboxId: comboboxId,
259
- onOptionSelect: handleDropdownSelect,
260
- onMouseMove: handleMouseMove,
261
- isKeyboardNavigation: isKeyboardNavigation,
262
- multiple: multiple,
263
- showFooterButtons: showFooter,
264
- selectAllButtonText: selectAllButtonText,
265
- showSelectAllAction: !isMaxSelectionActive,
266
- onSelectAll: handleSelectAll,
267
- onEdit: handleEdit,
268
- onComplete: handleComplete,
269
- componentType: "combobox",
270
- children: [showNoResults ? (0, _jsxRuntime.jsx)("li", {
271
- className: "ncua-select-dropdown__no-results",
272
- children: "\uC77C\uCE58\uD558\uB294 \uACB0\uACFC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."
273
- }) : null, children]
274
- })]
355
+ }), inlineDropdown, portaledDropdown]
275
356
  }), register && (0, _jsxRuntime.jsx)("input", {
276
357
  type: "hidden",
277
358
  ...register,