@ncds/ui-admin 1.8.4 → 1.8.6

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 (187) 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/forms-and-input/slider/Slider.js +2 -3
  23. package/dist/cjs/src/components/overlays/dropdown/Dropdown.js +47 -19
  24. package/dist/cjs/src/components/overlays/notification/CalloutNotification.js +25 -0
  25. package/dist/cjs/src/components/overlays/notification/FloatingNotification.js +86 -13
  26. package/dist/cjs/src/components/overlays/notification/Notification.js +7 -0
  27. package/dist/cjs/src/components/overlays/notification/host.js +12 -0
  28. package/dist/cjs/src/components/overlays/tooltip/Tooltip.js +57 -44
  29. package/dist/cjs/src/components/select-dropdown/SelectDropdown.js +2 -1
  30. package/dist/cjs/src/contexts/FloatingContext.js +11 -0
  31. package/dist/cjs/src/contexts/index.js +16 -0
  32. package/dist/cjs/src/hooks/index.js +11 -0
  33. package/dist/cjs/src/hooks/useFloatingPosition.js +78 -0
  34. package/dist/cjs/src/hooks/usePortalState.js +17 -0
  35. package/dist/cjs/src/types/component-meta.js +8 -1
  36. package/dist/cjs/src/utils/dropdown/maxSelection.js +35 -0
  37. package/dist/cjs/src/utils/dropdown/multiSelect.js +72 -15
  38. package/dist/esm/assets/scripts/featuredIcon.js +80 -0
  39. package/dist/esm/assets/scripts/notification/FloatingNotification.js +171 -0
  40. package/dist/esm/assets/scripts/notification/FullWidthNotification.js +126 -0
  41. package/dist/esm/assets/scripts/notification/MessageNotification.js +152 -0
  42. package/dist/esm/assets/scripts/notification/Notification.js +113 -0
  43. package/dist/esm/assets/scripts/notification/const/classNames.js +44 -0
  44. package/dist/esm/assets/scripts/notification/const/icons.js +25 -0
  45. package/dist/esm/assets/scripts/notification/const/index.js +4 -0
  46. package/dist/esm/assets/scripts/notification/const/sizes.js +40 -0
  47. package/dist/esm/assets/scripts/notification/const/types.js +8 -0
  48. package/dist/esm/assets/scripts/notification/index.js +10 -0
  49. package/dist/esm/assets/scripts/notification/positionSync.js +171 -0
  50. package/dist/esm/assets/scripts/notification/utils.js +109 -0
  51. package/dist/esm/assets/scripts/shared/ButtonCloseX.js +37 -0
  52. package/dist/esm/assets/scripts/utils/sanitize.js +31 -0
  53. package/dist/esm/src/components/data-display/data-grid/DataGrid.js +5 -1
  54. package/dist/esm/src/components/data-display/table/Table.js +118 -96
  55. package/dist/esm/src/components/data-display/table/useTableScrollbars.js +179 -0
  56. package/dist/esm/src/components/forms-and-input/combo-box/ComboBox.js +11 -10
  57. package/dist/esm/src/components/forms-and-input/image-file-input/ImageFileInput.js +5 -2
  58. package/dist/esm/src/components/forms-and-input/select-box/SelectBox.js +67 -29
  59. package/dist/esm/src/components/forms-and-input/slider/Slider.js +1 -2
  60. package/dist/esm/src/components/overlays/dropdown/Dropdown.js +47 -19
  61. package/dist/esm/src/components/overlays/notification/CalloutNotification.js +19 -0
  62. package/dist/esm/src/components/overlays/notification/FloatingNotification.js +86 -14
  63. package/dist/esm/src/components/overlays/notification/Notification.js +7 -0
  64. package/dist/esm/src/components/overlays/notification/host.js +9 -0
  65. package/dist/esm/src/components/overlays/tooltip/Tooltip.js +58 -45
  66. package/dist/esm/src/components/select-dropdown/SelectDropdown.js +2 -1
  67. package/dist/esm/src/contexts/FloatingContext.js +4 -0
  68. package/dist/esm/src/contexts/index.js +1 -0
  69. package/dist/esm/src/hooks/index.js +1 -0
  70. package/dist/esm/src/hooks/useFloatingPosition.js +71 -0
  71. package/dist/esm/src/hooks/usePortalState.js +10 -0
  72. package/dist/esm/src/types/component-meta.js +5 -1
  73. package/dist/esm/src/utils/dropdown/maxSelection.js +27 -0
  74. package/dist/esm/src/utils/dropdown/multiSelect.js +70 -14
  75. package/dist/temp/assets/scripts/featuredIcon.d.ts +22 -0
  76. package/dist/temp/assets/scripts/featuredIcon.js +79 -0
  77. package/dist/temp/assets/scripts/notification/FloatingNotification.d.ts +24 -0
  78. package/dist/temp/assets/scripts/notification/FloatingNotification.js +156 -0
  79. package/dist/temp/assets/scripts/notification/FullWidthNotification.d.ts +21 -0
  80. package/dist/temp/assets/scripts/notification/FullWidthNotification.js +111 -0
  81. package/dist/temp/assets/scripts/notification/MessageNotification.d.ts +22 -0
  82. package/dist/temp/assets/scripts/notification/MessageNotification.js +140 -0
  83. package/dist/temp/assets/scripts/notification/Notification.d.ts +22 -0
  84. package/dist/temp/assets/scripts/notification/Notification.js +112 -0
  85. package/dist/temp/assets/scripts/notification/const/classNames.d.ts +43 -0
  86. package/dist/temp/assets/scripts/notification/const/classNames.js +44 -0
  87. package/dist/temp/assets/scripts/notification/const/icons.d.ts +25 -0
  88. package/dist/temp/assets/scripts/notification/const/icons.js +25 -0
  89. package/dist/temp/assets/scripts/notification/const/index.d.ts +5 -0
  90. package/dist/temp/assets/scripts/notification/const/index.js +4 -0
  91. package/dist/temp/assets/scripts/notification/const/sizes.d.ts +32 -0
  92. package/dist/temp/assets/scripts/notification/const/sizes.js +40 -0
  93. package/dist/temp/assets/scripts/notification/const/types.d.ts +19 -0
  94. package/dist/temp/assets/scripts/notification/const/types.js +8 -0
  95. package/dist/temp/assets/scripts/notification/index.d.ts +8 -0
  96. package/dist/temp/assets/scripts/notification/index.js +10 -0
  97. package/dist/temp/assets/scripts/notification/positionSync.d.ts +50 -0
  98. package/dist/temp/assets/scripts/notification/positionSync.js +170 -0
  99. package/dist/temp/assets/scripts/notification/utils.d.ts +8 -0
  100. package/dist/temp/assets/scripts/notification/utils.js +115 -0
  101. package/dist/temp/assets/scripts/shared/ButtonCloseX.d.ts +5 -0
  102. package/dist/temp/assets/scripts/shared/ButtonCloseX.js +33 -0
  103. package/dist/temp/assets/scripts/utils/sanitize.d.ts +22 -0
  104. package/dist/temp/assets/scripts/utils/sanitize.js +31 -0
  105. package/dist/temp/src/components/data-display/data-grid/DataGrid.js +1 -1
  106. package/dist/temp/src/components/data-display/data-grid/DataGrid.types.d.ts +7 -0
  107. package/dist/temp/src/components/data-display/table/Table.d.ts +4 -1
  108. package/dist/temp/src/components/data-display/table/Table.js +53 -68
  109. package/dist/temp/src/components/data-display/table/types.d.ts +18 -0
  110. package/dist/temp/src/components/data-display/table/useTableScrollbars.d.ts +25 -0
  111. package/dist/temp/src/components/data-display/table/useTableScrollbars.js +136 -0
  112. package/dist/temp/src/components/forms-and-input/combo-box/ComboBox.d.ts +8 -0
  113. package/dist/temp/src/components/forms-and-input/combo-box/ComboBox.js +7 -11
  114. package/dist/temp/src/components/forms-and-input/image-file-input/ImageFileInput.js +1 -1
  115. package/dist/temp/src/components/forms-and-input/select-box/SelectBox.d.ts +13 -0
  116. package/dist/temp/src/components/forms-and-input/select-box/SelectBox.js +30 -3
  117. package/dist/temp/src/components/forms-and-input/slider/Slider.d.ts +0 -1
  118. package/dist/temp/src/components/forms-and-input/slider/Slider.js +0 -1
  119. package/dist/temp/src/components/overlays/dropdown/Dropdown.d.ts +5 -0
  120. package/dist/temp/src/components/overlays/dropdown/Dropdown.js +35 -11
  121. package/dist/temp/src/components/overlays/notification/CalloutNotification.d.ts +9 -0
  122. package/dist/temp/src/components/overlays/notification/CalloutNotification.js +6 -0
  123. package/dist/temp/src/components/overlays/notification/FloatingNotification.d.ts +15 -0
  124. package/dist/temp/src/components/overlays/notification/FloatingNotification.js +81 -13
  125. package/dist/temp/src/components/overlays/notification/Notification.d.ts +18 -3
  126. package/dist/temp/src/components/overlays/notification/Notification.js +4 -0
  127. package/dist/temp/src/components/overlays/notification/host.d.ts +9 -0
  128. package/dist/temp/src/components/overlays/notification/host.js +9 -0
  129. package/dist/temp/src/components/overlays/tooltip/Tooltip.d.ts +5 -1
  130. package/dist/temp/src/components/overlays/tooltip/Tooltip.js +25 -22
  131. package/dist/temp/src/components/select-dropdown/SelectDropdown.d.ts +6 -0
  132. package/dist/temp/src/components/select-dropdown/SelectDropdown.js +2 -2
  133. package/dist/temp/src/contexts/FloatingContext.d.ts +6 -0
  134. package/dist/temp/src/contexts/FloatingContext.js +4 -0
  135. package/dist/temp/src/contexts/index.d.ts +1 -0
  136. package/dist/temp/src/contexts/index.js +1 -0
  137. package/dist/temp/src/hooks/index.d.ts +1 -0
  138. package/dist/temp/src/hooks/index.js +1 -0
  139. package/dist/temp/src/hooks/useFloatingPosition.d.ts +19 -0
  140. package/dist/temp/src/hooks/useFloatingPosition.js +55 -0
  141. package/dist/temp/src/hooks/usePortalState.d.ts +6 -0
  142. package/dist/temp/src/hooks/usePortalState.js +7 -0
  143. package/dist/temp/src/types/component-meta.d.ts +6 -2
  144. package/dist/temp/src/types/component-meta.js +14 -1
  145. package/dist/temp/src/utils/dropdown/maxSelection.d.ts +24 -0
  146. package/dist/temp/src/utils/dropdown/maxSelection.js +28 -0
  147. package/dist/temp/src/utils/dropdown/multiSelect.d.ts +42 -2
  148. package/dist/temp/src/utils/dropdown/multiSelect.js +66 -13
  149. package/dist/types/assets/scripts/featuredIcon.d.ts +22 -0
  150. package/dist/types/assets/scripts/notification/FloatingNotification.d.ts +24 -0
  151. package/dist/types/assets/scripts/notification/FullWidthNotification.d.ts +21 -0
  152. package/dist/types/assets/scripts/notification/MessageNotification.d.ts +22 -0
  153. package/dist/types/assets/scripts/notification/Notification.d.ts +22 -0
  154. package/dist/types/assets/scripts/notification/const/classNames.d.ts +43 -0
  155. package/dist/types/assets/scripts/notification/const/icons.d.ts +25 -0
  156. package/dist/types/assets/scripts/notification/const/index.d.ts +5 -0
  157. package/dist/types/assets/scripts/notification/const/sizes.d.ts +32 -0
  158. package/dist/types/assets/scripts/notification/const/types.d.ts +19 -0
  159. package/dist/types/assets/scripts/notification/index.d.ts +8 -0
  160. package/dist/types/assets/scripts/notification/positionSync.d.ts +50 -0
  161. package/dist/types/assets/scripts/notification/utils.d.ts +8 -0
  162. package/dist/types/assets/scripts/shared/ButtonCloseX.d.ts +5 -0
  163. package/dist/types/assets/scripts/utils/sanitize.d.ts +22 -0
  164. package/dist/types/src/components/data-display/data-grid/DataGrid.types.d.ts +7 -0
  165. package/dist/types/src/components/data-display/table/Table.d.ts +4 -1
  166. package/dist/types/src/components/data-display/table/types.d.ts +18 -0
  167. package/dist/types/src/components/data-display/table/useTableScrollbars.d.ts +25 -0
  168. package/dist/types/src/components/forms-and-input/combo-box/ComboBox.d.ts +8 -0
  169. package/dist/types/src/components/forms-and-input/select-box/SelectBox.d.ts +13 -0
  170. package/dist/types/src/components/forms-and-input/slider/Slider.d.ts +0 -1
  171. package/dist/types/src/components/overlays/dropdown/Dropdown.d.ts +5 -0
  172. package/dist/types/src/components/overlays/notification/CalloutNotification.d.ts +9 -0
  173. package/dist/types/src/components/overlays/notification/FloatingNotification.d.ts +15 -0
  174. package/dist/types/src/components/overlays/notification/Notification.d.ts +18 -3
  175. package/dist/types/src/components/overlays/notification/host.d.ts +9 -0
  176. package/dist/types/src/components/overlays/tooltip/Tooltip.d.ts +5 -1
  177. package/dist/types/src/components/select-dropdown/SelectDropdown.d.ts +6 -0
  178. package/dist/types/src/contexts/FloatingContext.d.ts +6 -0
  179. package/dist/types/src/contexts/index.d.ts +1 -0
  180. package/dist/types/src/hooks/index.d.ts +1 -0
  181. package/dist/types/src/hooks/useFloatingPosition.d.ts +19 -0
  182. package/dist/types/src/hooks/usePortalState.d.ts +6 -0
  183. package/dist/types/src/types/component-meta.d.ts +6 -2
  184. package/dist/types/src/utils/dropdown/maxSelection.d.ts +24 -0
  185. package/dist/types/src/utils/dropdown/multiSelect.d.ts +42 -2
  186. package/dist/ui-admin/assets/styles/style.css +312 -64
  187. package/package.json +1 -1
@@ -0,0 +1,55 @@
1
+ import { useLayoutEffect, useState } from 'react';
2
+ const FLOATING_Z_INDEX = 1500;
3
+ export const useFloatingPosition = ({ enabled, isOpen, triggerRef, floatingRef, direction, offset = 4, align = 'left', matchTriggerWidth = false, }) => {
4
+ const [style, setStyle] = useState(null);
5
+ useLayoutEffect(() => {
6
+ if (!enabled || !isOpen) {
7
+ setStyle(null);
8
+ return;
9
+ }
10
+ const trigger = triggerRef.current;
11
+ if (!trigger)
12
+ return;
13
+ const calculatePosition = (trigger, floatingHeight, floatingWidth) => {
14
+ const top = direction === 'up' ? trigger.top - floatingHeight - offset : trigger.bottom + offset;
15
+ const left = align === 'right' ? trigger.right - floatingWidth : trigger.left;
16
+ return { top, left };
17
+ };
18
+ const update = () => {
19
+ const t = triggerRef.current;
20
+ const f = floatingRef.current;
21
+ if (!t)
22
+ return;
23
+ const r = t.getBoundingClientRect();
24
+ const floatingHeight = f?.offsetHeight ?? 0;
25
+ const floatingWidth = matchTriggerWidth ? r.width : (f?.offsetWidth ?? r.width);
26
+ const { top, left } = calculatePosition(r, floatingHeight, floatingWidth);
27
+ // matchTriggerWidth=true: width는 max-content(콘텐츠 자연 너비), min-width만 trigger 너비로 보장.
28
+ // 옵션이 짧으면 trigger 너비, 길면 자연 확장 — 기존 absolute 모드와 동일한 UX.
29
+ setStyle({
30
+ position: 'fixed',
31
+ top,
32
+ left,
33
+ zIndex: FLOATING_Z_INDEX,
34
+ ...(matchTriggerWidth ? { minWidth: r.width } : {}),
35
+ });
36
+ };
37
+ update();
38
+ window.addEventListener('scroll', update, true);
39
+ window.addEventListener('resize', update);
40
+ const triggerObserver = new ResizeObserver(update);
41
+ triggerObserver.observe(trigger);
42
+ let floatingObserver;
43
+ if (floatingRef.current) {
44
+ floatingObserver = new ResizeObserver(update);
45
+ floatingObserver.observe(floatingRef.current);
46
+ }
47
+ return () => {
48
+ window.removeEventListener('scroll', update, true);
49
+ window.removeEventListener('resize', update);
50
+ triggerObserver.disconnect();
51
+ floatingObserver?.disconnect();
52
+ };
53
+ }, [enabled, isOpen, direction, offset, align, matchTriggerWidth, triggerRef, floatingRef]);
54
+ return style;
55
+ };
@@ -0,0 +1,6 @@
1
+ type UsePortalStateResult = {
2
+ shouldPortal: boolean;
3
+ portalContainer: HTMLElement | null;
4
+ };
5
+ export declare const usePortalState: (usePortalProp?: boolean) => UsePortalStateResult;
6
+ export {};
@@ -0,0 +1,7 @@
1
+ import { useFloatingContext } from '../contexts/FloatingContext';
2
+ export const usePortalState = (usePortalProp) => {
3
+ const floatingContext = useFloatingContext();
4
+ const shouldPortal = usePortalProp ?? floatingContext?.preferPortal ?? false;
5
+ const portalContainer = floatingContext?.portalContainer ?? (typeof document !== 'undefined' ? document.body : null);
6
+ return { shouldPortal, portalContainer };
7
+ };
@@ -1,6 +1,10 @@
1
1
  /** AI 에이전트용 컴포넌트 메타데이터 타입 */
2
- /** 컴포넌트 카테고리 — `src/components/` 하위 디렉토리명과 동일 */
3
- export type ComponentCategory = 'action' | 'data-display' | 'feedback-and-status' | 'forms-and-input' | 'image-and-icons' | 'layout' | 'navigation' | 'overlays';
2
+ /**
3
+ * 컴포넌트 카테고리 `src/components/` 하위 디렉토리명과 동일.
4
+ * 타입과 런타임 값을 한 곳에서 정의해 추가/변경 시 동기화 누락을 막는다.
5
+ */
6
+ export declare const COMPONENT_CATEGORIES: readonly ["action", "data-display", "feedback-and-status", "forms-and-input", "image-and-icons", "layout", "navigation", "overlays"];
7
+ export type ComponentCategory = (typeof COMPONENT_CATEGORIES)[number];
4
8
  export interface ComponentMeta {
5
9
  category: ComponentCategory;
6
10
  aliases: string[];
@@ -1,2 +1,15 @@
1
1
  /** AI 에이전트용 컴포넌트 메타데이터 타입 */
2
- export {};
2
+ /**
3
+ * 컴포넌트 카테고리 — `src/components/` 하위 디렉토리명과 동일.
4
+ * 타입과 런타임 값을 한 곳에서 정의해 추가/변경 시 동기화 누락을 막는다.
5
+ */
6
+ export const COMPONENT_CATEGORIES = [
7
+ 'action',
8
+ 'data-display',
9
+ 'feedback-and-status',
10
+ 'forms-and-input',
11
+ 'image-and-icons',
12
+ 'layout',
13
+ 'navigation',
14
+ 'overlays',
15
+ ];
@@ -0,0 +1,24 @@
1
+ /**
2
+ * SelectBox / ComboBox 공통 — 최대 선택 개수 제한 활성 여부 판정.
3
+ *
4
+ * React 훅(`useMultiSelect`)과 vanilla 드롭다운(`DropdownModel`)가 동일 로직을 공유하므로
5
+ * 두 곳에 정의가 갈라지지 않도록 단일 source-of-truth로 둔다.
6
+ *
7
+ * **계약**
8
+ * - `0` 이상의 정수 → 활성 (단, `0`은 모든 새 선택을 차단하는 의미)
9
+ * - 음수 / 비정수 / `undefined` / `null` → 비활성 (제한 없는 것과 동일)
10
+ *
11
+ * `0`을 활성으로 보는 이유: 호출자가 `maxSelection={0}`을 명시적으로 전달했을 때
12
+ * "선택 자체를 막겠다"는 의도로 해석하기 위함. 음수는 일반적으로 "값 없음"의 sentinel이므로 비활성.
13
+ */
14
+ export declare const isMaxSelectionLimitActive: (maxSelection?: number | null) => maxSelection is number;
15
+ /**
16
+ * 현재 선택 길이가 최대치에 도달했는지 단일 함수로 판정.
17
+ *
18
+ * 호출 측에서 `>=`을 직접 작성하지 않도록 의미를 노출하고, type predicate가 내부에서 적용되어
19
+ * `maxSelection`의 narrowing이 보장된다 (외부 predicate 호출로 인한 narrowing 누락 방지).
20
+ *
21
+ * - 제한 비활성(음수 / null / undefined / 비정수): 항상 `false`.
22
+ * - 활성: `currentLength >= maxSelection`.
23
+ */
24
+ export declare const isMaxSelectionReached: (currentLength: number, maxSelection?: number | null) => boolean;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * SelectBox / ComboBox 공통 — 최대 선택 개수 제한 활성 여부 판정.
3
+ *
4
+ * React 훅(`useMultiSelect`)과 vanilla 드롭다운(`DropdownModel`)가 동일 로직을 공유하므로
5
+ * 두 곳에 정의가 갈라지지 않도록 단일 source-of-truth로 둔다.
6
+ *
7
+ * **계약**
8
+ * - `0` 이상의 정수 → 활성 (단, `0`은 모든 새 선택을 차단하는 의미)
9
+ * - 음수 / 비정수 / `undefined` / `null` → 비활성 (제한 없는 것과 동일)
10
+ *
11
+ * `0`을 활성으로 보는 이유: 호출자가 `maxSelection={0}`을 명시적으로 전달했을 때
12
+ * "선택 자체를 막겠다"는 의도로 해석하기 위함. 음수는 일반적으로 "값 없음"의 sentinel이므로 비활성.
13
+ */
14
+ export const isMaxSelectionLimitActive = (maxSelection) => typeof maxSelection === 'number' && Number.isInteger(maxSelection) && maxSelection >= 0;
15
+ /**
16
+ * 현재 선택 길이가 최대치에 도달했는지 단일 함수로 판정.
17
+ *
18
+ * 호출 측에서 `>=`을 직접 작성하지 않도록 의미를 노출하고, type predicate가 내부에서 적용되어
19
+ * `maxSelection`의 narrowing이 보장된다 (외부 predicate 호출로 인한 narrowing 누락 방지).
20
+ *
21
+ * - 제한 비활성(음수 / null / undefined / 비정수): 항상 `false`.
22
+ * - 활성: `currentLength >= maxSelection`.
23
+ */
24
+ export const isMaxSelectionReached = (currentLength, maxSelection) => {
25
+ if (!isMaxSelectionLimitActive(maxSelection))
26
+ return false;
27
+ return currentLength >= maxSelection;
28
+ };
@@ -19,13 +19,53 @@ export declare const getSelectedTags: (selectedValues: (string | number)[], opti
19
19
  * 태그 제거 시 선택값에서 해당 ID를 제거하는 유틸 함수
20
20
  */
21
21
  export declare const removeTagFromSelected: (selectedValues: (string | number)[], tagIdToRemove: string | number) => (string | number)[];
22
+ export interface UseMultiSelectOptions {
23
+ /** 전체 선택 버튼의 라벨 (default: '전체 선택') */
24
+ selectText?: string;
25
+ /** 전체 해제 버튼의 라벨 (default: '전체 해제') */
26
+ deselectText?: string;
27
+ /**
28
+ * 최대 선택 가능 개수 (선택).
29
+ * - `0` 이상의 정수: 제한 활성 (`isMaxSelectionActive: true`).
30
+ * - `0`은 모든 새 선택을 차단한다 (이미 선택된 항목 해제는 정상 동작).
31
+ * - 양수는 해당 개수 도달 후 추가 선택을 무시한다.
32
+ * - 음수 / 비정수 / `null` / `undefined`: 제한 없음.
33
+ */
34
+ maxSelection?: number | null;
35
+ }
22
36
  /**
23
- * 전체 선택 관련 로직을 번에 처리하는 커스텀 훅
37
+ * 최대 선택 개수 관련 응집을 별도 훅으로 분리.
38
+ *
39
+ * - `isMaxSelectionActive`: 제한 활성 여부.
40
+ * - `isMaxReached`: 현재 선택 길이가 최대치에 도달했는지.
41
+ * - `canAdd(currentLength)`: 새 항목 추가가 허용되는지 (도달 시 `false`).
42
+ *
43
+ * 도메인 규칙(`>=` 비교 등)을 외부로 노출하지 않고 헬퍼를 통해 의미만 반환한다.
44
+ * `useMultiSelect`가 내부에서 사용하지만, 단독으로도 필요한 호출자가 쓸 수 있게 export한다.
24
45
  */
25
- export declare const useMultiSelect: (selectedValues: (string | number)[], options: MultiSelectOption[], selectText?: string, deselectText?: string) => {
46
+ export declare const useMaxSelection: (selectedValues: (string | number)[], maxSelection?: number | null) => {
47
+ isMaxSelectionActive: boolean;
48
+ isMaxReached: boolean;
49
+ canAdd: (currentLength: number) => boolean;
50
+ };
51
+ /**
52
+ * 전체 선택 관련 로직을 한 번에 처리하는 커스텀 훅.
53
+ *
54
+ * 시그니처는 호출자가 maxSelection만 지정하더라도 텍스트 라벨을 건너뛰지 않도록 옵션 객체로 받는다.
55
+ *
56
+ * **반환의 `tryToggle`**: multiple 토글 결과를 직접 돌려준다.
57
+ * - 새 배열 반환: 정상 토글 (추가 또는 해제).
58
+ * - `null` 반환: 최대 개수 도달로 추가가 차단됨 (호출자는 변경 없이 종료해야 함).
59
+ *
60
+ * 호출자가 `>= maxSelection` 같은 도메인 규칙을 직접 검사하지 않도록 결과만 노출한다.
61
+ */
62
+ export declare const useMultiSelect: (selectedValues: (string | number)[], options: MultiSelectOption[], config?: UseMultiSelectOptions) => {
26
63
  isAllSelected: boolean;
27
64
  buttonText: string;
28
65
  toggleSelectAll: () => (string | number)[];
29
66
  getSelectedTagsData: () => SelectedTag[];
30
67
  removeTag: (tagId: string | number) => (string | number)[];
68
+ isMaxSelectionActive: boolean;
69
+ isMaxReached: boolean;
70
+ tryToggle: (optionId: string | number, currentArray: (string | number)[] | undefined) => (string | number)[] | null;
31
71
  };
@@ -1,3 +1,5 @@
1
+ import { useCallback, useMemo } from 'react';
2
+ import { isMaxSelectionLimitActive, isMaxSelectionReached } from './maxSelection';
1
3
  /**
2
4
  * 전체 선택 상태를 확인하는 유틸 함수
3
5
  */
@@ -42,25 +44,76 @@ export const removeTagFromSelected = (selectedValues, tagIdToRemove) => {
42
44
  return selectedValues.filter((id) => id !== tagIdToRemove);
43
45
  };
44
46
  /**
45
- * 전체 선택 관련 로직을 번에 처리하는 커스텀 훅
47
+ * 최대 선택 개수 관련 응집을 별도 훅으로 분리.
48
+ *
49
+ * - `isMaxSelectionActive`: 제한 활성 여부.
50
+ * - `isMaxReached`: 현재 선택 길이가 최대치에 도달했는지.
51
+ * - `canAdd(currentLength)`: 새 항목 추가가 허용되는지 (도달 시 `false`).
52
+ *
53
+ * 도메인 규칙(`>=` 비교 등)을 외부로 노출하지 않고 헬퍼를 통해 의미만 반환한다.
54
+ * `useMultiSelect`가 내부에서 사용하지만, 단독으로도 필요한 호출자가 쓸 수 있게 export한다.
46
55
  */
47
- export const useMultiSelect = (selectedValues, options, selectText, deselectText) => {
56
+ export const useMaxSelection = (selectedValues, maxSelection) => {
57
+ const isMaxSelectionActive = isMaxSelectionLimitActive(maxSelection);
58
+ const isMaxReached = isMaxSelectionReached(selectedValues.length, maxSelection);
59
+ const canAdd = useCallback((currentLength) => !isMaxSelectionReached(currentLength, maxSelection), [maxSelection]);
60
+ return { isMaxSelectionActive, isMaxReached, canAdd };
61
+ };
62
+ /**
63
+ * 전체 선택 관련 로직을 한 번에 처리하는 커스텀 훅.
64
+ *
65
+ * 시그니처는 호출자가 maxSelection만 지정하더라도 텍스트 라벨을 건너뛰지 않도록 옵션 객체로 받는다.
66
+ *
67
+ * **반환의 `tryToggle`**: multiple 토글 결과를 직접 돌려준다.
68
+ * - 새 배열 반환: 정상 토글 (추가 또는 해제).
69
+ * - `null` 반환: 최대 개수 도달로 추가가 차단됨 (호출자는 변경 없이 종료해야 함).
70
+ *
71
+ * 호출자가 `>= maxSelection` 같은 도메인 규칙을 직접 검사하지 않도록 결과만 노출한다.
72
+ */
73
+ export const useMultiSelect = (selectedValues, options, config = {}) => {
74
+ const { selectText, deselectText, maxSelection } = config;
48
75
  const isAllSelected = isAllItemsSelected(selectedValues, options);
49
76
  const buttonText = getSelectAllButtonText(selectedValues, options, selectText, deselectText);
50
- const toggleSelectAll = () => {
51
- return handleSelectAllItems(selectedValues, options);
52
- };
53
- const getSelectedTagsData = () => {
54
- return getSelectedTags(selectedValues, options);
55
- };
56
- const removeTag = (tagId) => {
57
- return removeTagFromSelected(selectedValues, tagId);
58
- };
59
- return {
77
+ const { isMaxSelectionActive, isMaxReached, canAdd } = useMaxSelection(selectedValues, maxSelection);
78
+ const toggleSelectAll = useCallback(() => handleSelectAllItems(selectedValues, options), [selectedValues, options]);
79
+ const getSelectedTagsData = useCallback(() => getSelectedTags(selectedValues, options), [selectedValues, options]);
80
+ const removeTag = useCallback((tagId) => removeTagFromSelected(selectedValues, tagId), [selectedValues]);
81
+ /**
82
+ * multiple 선택 토글을 한 번에 처리한다.
83
+ * - 이미 포함된 항목: 해제 (배열에서 제거하여 반환).
84
+ * - 미포함 항목: 추가 시도. 최대치 도달이면 `null` 반환(차단).
85
+ *
86
+ * 호출 측은 `null` 여부만 확인하면 되며 maxSelection 도메인 규칙을 알 필요가 없다.
87
+ */
88
+ const tryToggle = useCallback((optionId, currentArray) => {
89
+ const base = Array.isArray(currentArray) ? currentArray : [];
90
+ const idx = base.indexOf(optionId);
91
+ if (idx > -1) {
92
+ const next = [...base];
93
+ next.splice(idx, 1);
94
+ return next;
95
+ }
96
+ if (!canAdd(base.length))
97
+ return null;
98
+ return [...base, optionId];
99
+ }, [canAdd]);
100
+ return useMemo(() => ({
101
+ isAllSelected,
102
+ buttonText,
103
+ toggleSelectAll,
104
+ getSelectedTagsData,
105
+ removeTag,
106
+ isMaxSelectionActive,
107
+ isMaxReached,
108
+ tryToggle,
109
+ }), [
60
110
  isAllSelected,
61
111
  buttonText,
62
112
  toggleSelectAll,
63
113
  getSelectedTagsData,
64
114
  removeTag,
65
- };
115
+ isMaxSelectionActive,
116
+ isMaxReached,
117
+ tryToggle,
118
+ ]);
66
119
  };
@@ -0,0 +1,22 @@
1
+ export type FeaturedIconTheme = 'light-circle' | 'dark-circle' | 'outline-circle' | 'square-outline';
2
+ export type FeaturedIconColor = 'neutral' | 'error' | 'warning' | 'success';
3
+ export type FeaturedIconSize = 'sm' | 'md' | 'lg' | 'xl';
4
+ export interface FeaturedIconOptions {
5
+ svgString: string;
6
+ theme?: FeaturedIconTheme;
7
+ color?: FeaturedIconColor;
8
+ size?: FeaturedIconSize;
9
+ className?: string;
10
+ }
11
+ export declare class FeaturedIcon {
12
+ private element;
13
+ private options;
14
+ constructor(options: FeaturedIconOptions);
15
+ private createElement;
16
+ private addSizeToSvg;
17
+ getElement(): HTMLElement;
18
+ updateColor(color: FeaturedIconColor): void;
19
+ updateSize(size: FeaturedIconSize): void;
20
+ destroy(): void;
21
+ static create(options: FeaturedIconOptions): FeaturedIcon;
22
+ }
@@ -0,0 +1,24 @@
1
+ import type { BaseNotificationOptions } from './const';
2
+ export interface FloatingNotificationOptions extends BaseNotificationOptions {
3
+ type?: 'floating';
4
+ }
5
+ export declare class FloatingNotification {
6
+ private element;
7
+ private options;
8
+ private autoCloseTimer?;
9
+ private featuredIcon?;
10
+ private mobileCleanup?;
11
+ constructor(options: FloatingNotificationOptions);
12
+ private createElement;
13
+ private buildTemplate;
14
+ private renderCloseButton;
15
+ private setupMobileListener;
16
+ private updateMobileStyles;
17
+ private bindEvents;
18
+ private setupAutoClose;
19
+ getElement(): HTMLElement;
20
+ appendTo(parent: HTMLElement): void;
21
+ remove(): void;
22
+ destroy(): void;
23
+ static create(options: FloatingNotificationOptions): FloatingNotification;
24
+ }
@@ -0,0 +1,21 @@
1
+ import type { BaseNotificationOptions } from './const';
2
+ export interface FullWidthNotificationOptions extends BaseNotificationOptions {
3
+ type?: 'full-width';
4
+ }
5
+ export declare class FullWidthNotification {
6
+ private element;
7
+ private options;
8
+ private autoCloseTimer?;
9
+ constructor(options: FullWidthNotificationOptions);
10
+ private createElement;
11
+ private buildTemplate;
12
+ private renderHidePermanentlyButton;
13
+ private renderCloseButton;
14
+ private bindEvents;
15
+ private setupAutoClose;
16
+ getElement(): HTMLElement;
17
+ appendTo(parent: HTMLElement): void;
18
+ remove(): void;
19
+ destroy(): void;
20
+ static create(options: FullWidthNotificationOptions): FullWidthNotification;
21
+ }
@@ -0,0 +1,22 @@
1
+ import type { BaseNotificationOptions } from './const';
2
+ export interface MessageNotificationOptions extends BaseNotificationOptions {
3
+ type?: 'message';
4
+ }
5
+ export declare class MessageNotification {
6
+ private element;
7
+ private options;
8
+ private autoCloseTimer?;
9
+ private featuredIcon?;
10
+ constructor(options: MessageNotificationOptions);
11
+ private createElement;
12
+ private buildTemplate;
13
+ private renderHidePermanentlyButton;
14
+ private renderCloseButton;
15
+ private bindEvents;
16
+ private setupAutoClose;
17
+ getElement(): HTMLElement;
18
+ appendTo(parent: HTMLElement): void;
19
+ remove(): void;
20
+ destroy(): void;
21
+ static create(options: MessageNotificationOptions): MessageNotification;
22
+ }
@@ -0,0 +1,22 @@
1
+ import type { BaseNotificationOptions, NotificationColor } from './const';
2
+ export interface NotificationOptions extends BaseNotificationOptions {
3
+ type?: 'full-width' | 'floating' | 'message';
4
+ }
5
+ export declare class NcuaNotification {
6
+ private instance;
7
+ private resolvedType;
8
+ constructor(options: NotificationOptions);
9
+ getElement(): HTMLElement;
10
+ appendTo(parent: HTMLElement): void;
11
+ remove(): void;
12
+ destroy(): void;
13
+ show(parent?: HTMLElement): void;
14
+ static create(options: NotificationOptions): NcuaNotification;
15
+ static createWithColor(color: NotificationColor, title: string, supportingText?: string, options?: Partial<NotificationOptions>): NcuaNotification;
16
+ static success(title: string, supportingText?: string, options?: Partial<NotificationOptions>): NcuaNotification;
17
+ static error(title: string, supportingText?: string, options?: Partial<NotificationOptions>): NcuaNotification;
18
+ static warning(title: string, supportingText?: string, options?: Partial<NotificationOptions>): NcuaNotification;
19
+ static info(title: string, supportingText?: string, options?: Partial<NotificationOptions>): NcuaNotification;
20
+ static neutral(title: string, supportingText?: string, options?: Partial<NotificationOptions>): NcuaNotification;
21
+ static showFullWidth(options: Omit<NotificationOptions, 'type'>): NcuaNotification;
22
+ }
@@ -0,0 +1,43 @@
1
+ export declare const CLASS_NAMES: {
2
+ readonly FULL_WIDTH: {
3
+ readonly BASE: "ncua-full-width-notification";
4
+ readonly CONTAINER: "ncua-full-width-notification__container";
5
+ readonly CONTENT: "ncua-full-width-notification__content";
6
+ readonly CONTENT_WRAPPER: "ncua-full-width-notification__content-wrapper";
7
+ readonly ICON: "ncua-full-width-notification__icon";
8
+ readonly TEXT_CONTAINER: "ncua-full-width-notification__text-container";
9
+ readonly TITLE: "ncua-full-width-notification__title";
10
+ readonly SUPPORTING_TEXT: "ncua-full-width-notification__supporting-text";
11
+ readonly ACTIONS_CONTAINER: "ncua-full-width-notification__actions-container";
12
+ readonly ACTIONS: "ncua-full-width-notification__actions";
13
+ readonly CLOSE_BUTTON: "ncua-full-width-notification__close-button";
14
+ };
15
+ readonly FLOATING: {
16
+ readonly BASE: "ncua-floating-notification";
17
+ readonly CONTAINER: "ncua-floating-notification__container";
18
+ readonly CONTENT: "ncua-floating-notification__content";
19
+ readonly TEXT_CONTAINER: "ncua-floating-notification__text-container";
20
+ readonly TITLE_WRAPPER: "ncua-floating-notification__title-wrapper";
21
+ readonly TITLE: "ncua-floating-notification__title";
22
+ readonly SUPPORTING_TEXT: "ncua-floating-notification__supporting-text";
23
+ readonly ACTIONS: "ncua-floating-notification__actions";
24
+ readonly CLOSE_BUTTON: "ncua-floating-notification__close-button";
25
+ };
26
+ readonly MESSAGE: {
27
+ readonly BASE: "ncua-message-notification";
28
+ readonly CONTAINER: "ncua-message-notification__container";
29
+ readonly CONTENT: "ncua-message-notification__content";
30
+ readonly CONTENT_WRAPPER: "ncua-message-notification__content-wrapper";
31
+ readonly ICON: "ncua-message-notification__icon";
32
+ readonly TEXT_CONTAINER: "ncua-message-notification__text-container";
33
+ readonly TITLE: "ncua-message-notification__title";
34
+ readonly SUPPORTING_TEXT: "ncua-message-notification__supporting-text";
35
+ readonly ACTIONS_CONTAINER: "ncua-message-notification__actions-container";
36
+ readonly ACTIONS: "ncua-message-notification__actions";
37
+ readonly HIDE_LINK: "ncua-message-notification__hide-link";
38
+ readonly CLOSE_BUTTON: "ncua-message-notification__close-button";
39
+ };
40
+ readonly COMMON: {
41
+ readonly ACTION_BUTTON: "ncua-notification__action-button";
42
+ };
43
+ };
@@ -0,0 +1,25 @@
1
+ import type { NotificationColor } from './types';
2
+ export declare const SVG_ICONS: {
3
+ readonly 'pin-02': (size: string) => string;
4
+ readonly 'alert-triangle': (size: string) => string;
5
+ readonly 'alert-circle': (size: string) => string;
6
+ readonly 'check-circle': (size: string) => string;
7
+ readonly 'info-circle': (size: string) => string;
8
+ readonly 'message-chat-square': (size: string) => string;
9
+ readonly 'x-close': (size: string) => string;
10
+ };
11
+ export declare const FLOATING_ICON_MAP: Partial<Record<NotificationColor, (size: string) => string>>;
12
+ export declare const FULL_WIDTH_ICON_MAP: {
13
+ readonly neutral: (size: string) => string;
14
+ readonly error: (size: string) => string;
15
+ readonly warning: (size: string) => string;
16
+ readonly success: (size: string) => string;
17
+ readonly info: (size: string) => string;
18
+ };
19
+ export declare const ICON_MAP: {
20
+ readonly neutral: (size: string) => string;
21
+ readonly error: (size: string) => string;
22
+ readonly warning: (size: string) => string;
23
+ readonly success: (size: string) => string;
24
+ readonly info: (size: string) => string;
25
+ };
@@ -0,0 +1,5 @@
1
+ export type { NotificationColor, NotificationHierarchy, NotificationAction, BaseNotificationOptions } from './types';
2
+ export { SVG_ICONS, FLOATING_ICON_MAP, FULL_WIDTH_ICON_MAP, ICON_MAP } from './icons';
3
+ export { CLASS_NAMES } from './classNames';
4
+ export { FEATURED_ICON_SIZES, ICON_PIXEL_SIZES, CLOSE_BUTTON_SIZES, CLOSE_BUTTON_SVG_SIZES, FULL_WIDTH_SIZES, MESSAGE_SIZES, getSizes, } from './sizes';
5
+ export { MESSAGE_CLOSE_ICON_COLORS } from './types';
@@ -0,0 +1,32 @@
1
+ export declare const FEATURED_ICON_SIZES: {
2
+ readonly MOBILE: "md";
3
+ readonly DESKTOP: "sm";
4
+ };
5
+ export declare const ICON_PIXEL_SIZES: {
6
+ readonly MOBILE: "20";
7
+ readonly DESKTOP: "16";
8
+ readonly FULL_WIDTH: "16";
9
+ };
10
+ export declare const CLOSE_BUTTON_SIZES: {
11
+ readonly MOBILE: "sm";
12
+ readonly DESKTOP: "xs";
13
+ };
14
+ export declare const CLOSE_BUTTON_SVG_SIZES: {
15
+ readonly xs: 16;
16
+ readonly sm: 20;
17
+ };
18
+ export declare const FULL_WIDTH_SIZES: {
19
+ readonly ICON: "16";
20
+ readonly CLOSE_BUTTON: "20";
21
+ };
22
+ export declare const MESSAGE_SIZES: {
23
+ readonly FEATURED_ICON: "lg";
24
+ readonly ICON_PIXEL: "24";
25
+ readonly CLOSE_BUTTON: "20";
26
+ };
27
+ export declare const getSizes: {
28
+ readonly featuredIcon: (isMobile: boolean) => "sm" | "md";
29
+ readonly iconPixel: (isMobile: boolean) => "20" | "16";
30
+ readonly closeButton: (isMobile: boolean) => "xs" | "sm";
31
+ readonly closeButtonSvg: (size: keyof typeof CLOSE_BUTTON_SVG_SIZES) => 16 | 20;
32
+ };
@@ -0,0 +1,19 @@
1
+ export type NotificationColor = 'neutral' | 'error' | 'warning' | 'success' | 'info';
2
+ export type NotificationHierarchy = 'link' | 'link-gray';
3
+ export interface NotificationAction {
4
+ label: string;
5
+ onClick: () => void;
6
+ hierarchy?: NotificationHierarchy;
7
+ }
8
+ export interface BaseNotificationOptions {
9
+ title: string;
10
+ supportingText?: string;
11
+ color?: NotificationColor;
12
+ onClose?: () => void;
13
+ className?: string;
14
+ actions?: NotificationAction[];
15
+ autoClose?: number;
16
+ supportTextLink?: string;
17
+ onHidePermanently?: () => void;
18
+ }
19
+ export declare const MESSAGE_CLOSE_ICON_COLORS: Record<NotificationColor, string>;
@@ -0,0 +1,8 @@
1
+ export type { BaseNotificationOptions, NotificationAction, NotificationColor, NotificationHierarchy } from './const';
2
+ export { CLASS_NAMES, FLOATING_ICON_MAP, FULL_WIDTH_ICON_MAP, ICON_MAP, SVG_ICONS } from './const';
3
+ export { FloatingNotification, type FloatingNotificationOptions } from './FloatingNotification';
4
+ export { FullWidthNotification, type FullWidthNotificationOptions } from './FullWidthNotification';
5
+ export { MessageNotification, type MessageNotificationOptions } from './MessageNotification';
6
+ export { NcuaNotification as Notification, type NotificationOptions } from './Notification';
7
+ export { mountFloatingNotificationHost, startPositionSync, stopPositionSync, syncNow, } from './positionSync';
8
+ export * from './utils';
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Floating Notification 호스트 싱글톤 + 위치 동기화
3
+ *
4
+ * 본 모듈은 다음 두 가지 책임을 가진다:
5
+ * 1. `.ncua-floating-notification-host` 싱글톤을 document.body 에 생성·재사용 (mountFloatingNotificationHost).
6
+ * 2. `.ncua-page-title` 의 rect.bottom 을 추적해 `--ncua-page-title-bottom` CSS 변수로 갱신.
7
+ *
8
+ * 두 책임을 한 파일에 두는 이유: 호스트가 처음 생성될 때 positionSync 가 함께 시작되며,
9
+ * React 측 훅과 vanilla 측 `NcuaNotification.show()` 가 동일 함수를 공유해 호스트 생성 로직이
10
+ * 한 곳에서만 유지되도록 한다.
11
+ *
12
+ * NCDS DES-SPEC-027 §5.1
13
+ * · Toast top 좌표 = PageTitle.bottom + 16px (viewport 기준).
14
+ * · PageTitle 이 sticky 로 Default/Fixed 변형 사이 높이가 변동(120/56px)하므로 단순 height
15
+ * 가 아닌 getBoundingClientRect().bottom 을 기준으로 동적 계산해야 한다.
16
+ *
17
+ * 동작 특성:
18
+ * - 다중 호출 idempotent. ensure/start 가 여러 번 호출되어도 호스트와 리스너는 한 벌만.
19
+ * - scroll/resize 는 rAF 로 throttle.
20
+ * - PageTitle 추가/제거를 MutationObserver 로 감지해 재바인딩 — body subtree 변경마다
21
+ * 호출되므로 콜백 자체도 rAF 로 한 프레임당 한 번만 querySelector 가 돌도록 보호.
22
+ * - SSR 가드: window/document 미정의 환경에서 ensure/start 는 no-op.
23
+ *
24
+ * 내부 상태는 모듈 최상단에 흩어진 `let` 대신 한 객체로 묶어 테스트/HMR 에서 일괄 초기화·검사하기
25
+ * 쉽도록 한다. 외부에는 함수만 노출되므로 캡슐화는 유지된다.
26
+ */
27
+ /**
28
+ * `.ncua-floating-notification-host` 싱글톤을 보장한다.
29
+ * **side-effect 함수** — 단순 조회가 아니라 다음을 모두 수행:
30
+ * · document.body 에 `<div class="ncua-floating-notification-host">` 를 (필요 시) append
31
+ * · 첫 호출 시 startPositionSync() 로 window scroll/resize/MutationObserver/ResizeObserver 부착
32
+ * · 한 번 만든 호스트는 페이지 lifetime 동안 유지 — 컴포넌트 언마운트 시에도 제거하지 않는다
33
+ * (다음 토스트의 mount 비용을 줄이기 위해 의도된 설계)
34
+ *
35
+ * React 측 hook 과 vanilla 측 `NcuaNotification.show()` 가 모두 이 함수를 사용해 호스트 생성
36
+ * 진입점이 한 곳만 존재한다.
37
+ *
38
+ * @returns 생성되었거나 이미 존재하는 호스트 엘리먼트. SSR 환경에서는 null.
39
+ */
40
+ export declare function mountFloatingNotificationHost(): HTMLElement | null;
41
+ /**
42
+ * PageTitle ↔ Floating Host 위치 동기화 시작 (idempotent).
43
+ * `mountFloatingNotificationHost()` 가 자동 호출하므로 일반 사용자는 직접 부를 필요 없음.
44
+ * SSR/테스트에서 수동 제어가 필요할 때만 export 됨.
45
+ */
46
+ export declare function startPositionSync(): void;
47
+ /** 동기화 중단 + 리소스 해제. 테스트 종료/HMR 정리 등에 사용. */
48
+ export declare function stopPositionSync(): void;
49
+ /** 외부에서 PageTitle.bottom 값을 강제로 다시 측정해 반영하고 싶을 때. */
50
+ export declare function syncNow(): void;
@@ -0,0 +1,8 @@
1
+ import type { NotificationAction, NotificationColor } from './const';
2
+ export declare function createWrapperElement(baseClass: string, color: NotificationColor, className?: string): HTMLElement;
3
+ export declare function buildClassName(baseClass: string, color: NotificationColor, className?: string): string;
4
+ export declare function renderSupportingText(supportingText?: string, className?: string, supportTextLink?: string): string;
5
+ export declare function renderActions(actions: NotificationAction[], wrapperClass: string): string;
6
+ export declare function bindNotificationEvents(element: HTMLElement, actions: NotificationAction[], onClose?: () => void, onRemove?: () => void): void;
7
+ export declare function setupAutoClose(autoClose: number, onClose?: () => void, onRemove?: () => void): number | undefined;
8
+ export declare const isMobile: () => boolean;
@@ -0,0 +1,5 @@
1
+ export type ButtonCloseXSize = 'xs' | 'sm' | 'md' | 'lg';
2
+ export type ButtonCloseXTheme = 'dark' | 'light';
3
+ export declare const SVG_SIZE: Record<ButtonCloseXSize, number>;
4
+ export declare const X_CLOSE_SVG: (size: string) => string;
5
+ export declare function ButtonCloseX(size: ButtonCloseXSize, theme?: ButtonCloseXTheme, additionalClasses?: string, ariaLabel?: string, onClick?: () => void): string;