@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,50 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.CLASS_NAMES = void 0;
7
+ // CSS class names
8
+ const CLASS_NAMES = exports.CLASS_NAMES = {
9
+ FULL_WIDTH: {
10
+ BASE: 'ncua-full-width-notification',
11
+ CONTAINER: 'ncua-full-width-notification__container',
12
+ CONTENT: 'ncua-full-width-notification__content',
13
+ CONTENT_WRAPPER: 'ncua-full-width-notification__content-wrapper',
14
+ ICON: 'ncua-full-width-notification__icon',
15
+ TEXT_CONTAINER: 'ncua-full-width-notification__text-container',
16
+ TITLE: 'ncua-full-width-notification__title',
17
+ SUPPORTING_TEXT: 'ncua-full-width-notification__supporting-text',
18
+ ACTIONS_CONTAINER: 'ncua-full-width-notification__actions-container',
19
+ ACTIONS: 'ncua-full-width-notification__actions',
20
+ CLOSE_BUTTON: 'ncua-full-width-notification__close-button'
21
+ },
22
+ FLOATING: {
23
+ BASE: 'ncua-floating-notification',
24
+ CONTAINER: 'ncua-floating-notification__container',
25
+ CONTENT: 'ncua-floating-notification__content',
26
+ TEXT_CONTAINER: 'ncua-floating-notification__text-container',
27
+ TITLE_WRAPPER: 'ncua-floating-notification__title-wrapper',
28
+ TITLE: 'ncua-floating-notification__title',
29
+ SUPPORTING_TEXT: 'ncua-floating-notification__supporting-text',
30
+ ACTIONS: 'ncua-floating-notification__actions',
31
+ CLOSE_BUTTON: 'ncua-floating-notification__close-button'
32
+ },
33
+ MESSAGE: {
34
+ BASE: 'ncua-message-notification',
35
+ CONTAINER: 'ncua-message-notification__container',
36
+ CONTENT: 'ncua-message-notification__content',
37
+ CONTENT_WRAPPER: 'ncua-message-notification__content-wrapper',
38
+ ICON: 'ncua-message-notification__icon',
39
+ TEXT_CONTAINER: 'ncua-message-notification__text-container',
40
+ TITLE: 'ncua-message-notification__title',
41
+ SUPPORTING_TEXT: 'ncua-message-notification__supporting-text',
42
+ ACTIONS_CONTAINER: 'ncua-message-notification__actions-container',
43
+ ACTIONS: 'ncua-message-notification__actions',
44
+ HIDE_LINK: 'ncua-message-notification__hide-link',
45
+ CLOSE_BUTTON: 'ncua-message-notification__close-button'
46
+ },
47
+ COMMON: {
48
+ ACTION_BUTTON: 'ncua-notification__action-button'
49
+ }
50
+ };
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.SVG_ICONS = exports.ICON_MAP = exports.FULL_WIDTH_ICON_MAP = exports.FLOATING_ICON_MAP = void 0;
7
+ // SVG 아이콘들 (크기는 동적으로 설정)
8
+ const SVG_ICONS = exports.SVG_ICONS = {
9
+ 'pin-02': size => `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" fill="none" viewBox="0 0 24 24" stroke="none"><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.377 15.616 2.72 21.273m8.974-14.631-1.56 1.56a2 2 0 0 1-.264.242 1 1 0 0 1-.207.111c-.082.032-.17.05-.347.085l-3.665.733c-.952.19-1.428.286-1.65.537a1 1 0 0 0-.243.8c.046.333.39.677 1.076 1.363l7.086 7.086c.686.687 1.03 1.03 1.362 1.076a1 1 0 0 0 .801-.242c.251-.223.346-.7.537-1.651l.733-3.665c.035-.176.053-.265.085-.347a1 1 0 0 1 .11-.207c.051-.072.115-.136.242-.263l1.561-1.561c.082-.082.122-.122.167-.158q.06-.047.126-.085c.05-.029.103-.051.208-.097l2.495-1.069c.727-.312 1.091-.467 1.256-.72a1 1 0 0 0 .144-.747c-.06-.295-.34-.575-.9-1.135l-5.142-5.143c-.56-.56-.84-.84-1.135-.9a1 1 0 0 0-.748.145c-.252.165-.407.529-.72 1.256l-1.068 2.495a2 2 0 0 1-.097.208 1 1 0 0 1-.085.126 2 2 0 0 1-.158.167"></path></svg>`,
10
+ 'alert-triangle': size => `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" fill="none" viewBox="0 0 24 24" stroke="none"><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v4m0 4h.01M10.615 3.892 2.39 18.098c-.456.788-.684 1.182-.65 1.506a1 1 0 0 0 .406.705c.263.191.718.191 1.629.191h16.45c.91 0 1.365 0 1.628-.191a1 1 0 0 0 .407-.705c.034-.324-.195-.718-.65-1.506L13.383 3.892c-.454-.785-.681-1.178-.978-1.31a1 1 0 0 0-.812 0c-.297.132-.524.525-.979 1.31"></path></svg>`,
11
+ 'alert-circle': size => `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" fill="none" viewBox="0 0 24 24" stroke="none"><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M22 12c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2s10 4.477 10 10"></path></svg>`,
12
+ 'check-circle': size => `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" fill="none" viewBox="0 0 24 24" stroke="none"><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m7.5 12 3 3 6-6m5.5 3c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2s10 4.477 10 10"></path></svg>`,
13
+ 'info-circle': size => `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" fill="none" viewBox="0 0 24 24" stroke="none" color="#5720B7" class="ncua-full-width-notification__icon"><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 16v-4m0-4h.01M22 12c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2s10 4.477 10 10"></path></svg>`,
14
+ 'message-chat-square': size => `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" fill="none" viewBox="0 0 24 24" stroke="none" color="#0C111D" class="ncua-full-width-notification__icon"><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m10 15-3.075 3.114c-.43.434-.644.651-.828.666a.5.5 0 0 1-.421-.172c-.12-.14-.12-.446-.12-1.056v-1.56c0-.548-.449-.944-.99-1.024v0a3 3 0 0 1-2.534-2.533C2 12.219 2 11.96 2 11.445V6.8c0-1.68 0-2.52.327-3.162a3 3 0 0 1 1.311-1.311C4.28 2 5.12 2 6.8 2h7.4c1.68 0 2.52 0 3.162.327a3 3 0 0 1 1.311 1.311C19 4.28 19 5.12 19 6.8V11m0 11-2.176-1.513c-.306-.213-.46-.32-.626-.395a2 2 0 0 0-.462-.145c-.18-.033-.367-.033-.74-.033H13.2c-1.12 0-1.68 0-2.108-.218a2 2 0 0 1-.874-.874C10 18.394 10 17.834 10 16.714V14.2c0-1.12 0-1.68.218-2.108a2 2 0 0 1 .874-.874C11.52 11 12.08 11 13.2 11h5.6c1.12 0 1.68 0 2.108.218a2 2 0 0 1 .874.874C22 12.52 22 13.08 22 14.2v2.714c0 .932 0 1.398-.152 1.766a2 2 0 0 1-1.083 1.082c-.367.152-.833.152-1.765.152z"></path></svg>`,
15
+ 'x-close': size => `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" fill="none" viewBox="0 0 24 24" stroke="none"><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18 6 6 18M6 6l12 12"></path></svg>`
16
+ };
17
+ const FLOATING_ICON_MAP = exports.FLOATING_ICON_MAP = {
18
+ neutral: SVG_ICONS['pin-02'],
19
+ error: SVG_ICONS['alert-triangle'],
20
+ warning: SVG_ICONS['alert-circle'],
21
+ success: SVG_ICONS['check-circle']
22
+ // info는 floating에서는 지원하지 않음
23
+ };
24
+ const FULL_WIDTH_ICON_MAP = exports.FULL_WIDTH_ICON_MAP = {
25
+ neutral: SVG_ICONS['message-chat-square'],
26
+ error: SVG_ICONS['alert-triangle'],
27
+ warning: SVG_ICONS['alert-triangle'],
28
+ success: SVG_ICONS['check-circle'],
29
+ info: SVG_ICONS['info-circle']
30
+ };
31
+ const ICON_MAP = exports.ICON_MAP = FULL_WIDTH_ICON_MAP;
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "CLASS_NAMES", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _classNames.CLASS_NAMES;
10
+ }
11
+ });
12
+ Object.defineProperty(exports, "CLOSE_BUTTON_SIZES", {
13
+ enumerable: true,
14
+ get: function () {
15
+ return _sizes.CLOSE_BUTTON_SIZES;
16
+ }
17
+ });
18
+ Object.defineProperty(exports, "CLOSE_BUTTON_SVG_SIZES", {
19
+ enumerable: true,
20
+ get: function () {
21
+ return _sizes.CLOSE_BUTTON_SVG_SIZES;
22
+ }
23
+ });
24
+ Object.defineProperty(exports, "FEATURED_ICON_SIZES", {
25
+ enumerable: true,
26
+ get: function () {
27
+ return _sizes.FEATURED_ICON_SIZES;
28
+ }
29
+ });
30
+ Object.defineProperty(exports, "FLOATING_ICON_MAP", {
31
+ enumerable: true,
32
+ get: function () {
33
+ return _icons.FLOATING_ICON_MAP;
34
+ }
35
+ });
36
+ Object.defineProperty(exports, "FULL_WIDTH_ICON_MAP", {
37
+ enumerable: true,
38
+ get: function () {
39
+ return _icons.FULL_WIDTH_ICON_MAP;
40
+ }
41
+ });
42
+ Object.defineProperty(exports, "FULL_WIDTH_SIZES", {
43
+ enumerable: true,
44
+ get: function () {
45
+ return _sizes.FULL_WIDTH_SIZES;
46
+ }
47
+ });
48
+ Object.defineProperty(exports, "ICON_MAP", {
49
+ enumerable: true,
50
+ get: function () {
51
+ return _icons.ICON_MAP;
52
+ }
53
+ });
54
+ Object.defineProperty(exports, "ICON_PIXEL_SIZES", {
55
+ enumerable: true,
56
+ get: function () {
57
+ return _sizes.ICON_PIXEL_SIZES;
58
+ }
59
+ });
60
+ Object.defineProperty(exports, "MESSAGE_CLOSE_ICON_COLORS", {
61
+ enumerable: true,
62
+ get: function () {
63
+ return _types.MESSAGE_CLOSE_ICON_COLORS;
64
+ }
65
+ });
66
+ Object.defineProperty(exports, "MESSAGE_SIZES", {
67
+ enumerable: true,
68
+ get: function () {
69
+ return _sizes.MESSAGE_SIZES;
70
+ }
71
+ });
72
+ Object.defineProperty(exports, "SVG_ICONS", {
73
+ enumerable: true,
74
+ get: function () {
75
+ return _icons.SVG_ICONS;
76
+ }
77
+ });
78
+ Object.defineProperty(exports, "getSizes", {
79
+ enumerable: true,
80
+ get: function () {
81
+ return _sizes.getSizes;
82
+ }
83
+ });
84
+ var _icons = require("./icons");
85
+ var _classNames = require("./classNames");
86
+ var _sizes = require("./sizes");
87
+ var _types = require("./types");
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getSizes = exports.MESSAGE_SIZES = exports.ICON_PIXEL_SIZES = exports.FULL_WIDTH_SIZES = exports.FEATURED_ICON_SIZES = exports.CLOSE_BUTTON_SVG_SIZES = exports.CLOSE_BUTTON_SIZES = void 0;
7
+ // 알림 컴포넌트 사이즈 관련 상수들
8
+ // FeaturedIcon 사이즈
9
+ const FEATURED_ICON_SIZES = exports.FEATURED_ICON_SIZES = {
10
+ MOBILE: 'md',
11
+ DESKTOP: 'sm'
12
+ };
13
+ // SVG 아이콘 픽셀 사이즈
14
+ const ICON_PIXEL_SIZES = exports.ICON_PIXEL_SIZES = {
15
+ MOBILE: '20',
16
+ DESKTOP: '16',
17
+ FULL_WIDTH: '16' // Full-width는 항상 고정
18
+ };
19
+ // 닫기 버튼 사이즈
20
+ const CLOSE_BUTTON_SIZES = exports.CLOSE_BUTTON_SIZES = {
21
+ MOBILE: 'sm',
22
+ DESKTOP: 'xs'
23
+ };
24
+ // 닫기 버튼 SVG 픽셀 사이즈
25
+ const CLOSE_BUTTON_SVG_SIZES = exports.CLOSE_BUTTON_SVG_SIZES = {
26
+ xs: 16,
27
+ sm: 20
28
+ };
29
+ // Full-width 알림 고정 사이즈
30
+ const FULL_WIDTH_SIZES = exports.FULL_WIDTH_SIZES = {
31
+ ICON: '16',
32
+ CLOSE_BUTTON: '20'
33
+ };
34
+ // Message 알림 고정 사이즈
35
+ const MESSAGE_SIZES = exports.MESSAGE_SIZES = {
36
+ FEATURED_ICON: 'lg',
37
+ ICON_PIXEL: '24',
38
+ CLOSE_BUTTON: '20'
39
+ };
40
+ // 사이즈 유틸리티 함수들
41
+ const getSizes = exports.getSizes = {
42
+ featuredIcon: isMobile => isMobile ? FEATURED_ICON_SIZES.MOBILE : FEATURED_ICON_SIZES.DESKTOP,
43
+ iconPixel: isMobile => isMobile ? ICON_PIXEL_SIZES.MOBILE : ICON_PIXEL_SIZES.DESKTOP,
44
+ closeButton: isMobile => isMobile ? CLOSE_BUTTON_SIZES.MOBILE : CLOSE_BUTTON_SIZES.DESKTOP,
45
+ closeButtonSvg: size => CLOSE_BUTTON_SVG_SIZES[size]
46
+ };
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.MESSAGE_CLOSE_ICON_COLORS = void 0;
7
+ // Message Notification 닫기 버튼 아이콘 색상 맵
8
+ const MESSAGE_CLOSE_ICON_COLORS = exports.MESSAGE_CLOSE_ICON_COLORS = {
9
+ neutral: '#6B7280',
10
+ error: '#EF4444',
11
+ warning: '#F97316',
12
+ success: '#16A34A',
13
+ info: '#6B7280' // info는 message 타입에서 지원하지 않지만 fallback용
14
+ };
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ var _exportNames = {
7
+ CLASS_NAMES: true,
8
+ FLOATING_ICON_MAP: true,
9
+ FULL_WIDTH_ICON_MAP: true,
10
+ ICON_MAP: true,
11
+ SVG_ICONS: true,
12
+ FloatingNotification: true,
13
+ FullWidthNotification: true,
14
+ MessageNotification: true,
15
+ Notification: true,
16
+ mountFloatingNotificationHost: true,
17
+ startPositionSync: true,
18
+ stopPositionSync: true,
19
+ syncNow: true
20
+ };
21
+ Object.defineProperty(exports, "CLASS_NAMES", {
22
+ enumerable: true,
23
+ get: function () {
24
+ return _const.CLASS_NAMES;
25
+ }
26
+ });
27
+ Object.defineProperty(exports, "FLOATING_ICON_MAP", {
28
+ enumerable: true,
29
+ get: function () {
30
+ return _const.FLOATING_ICON_MAP;
31
+ }
32
+ });
33
+ Object.defineProperty(exports, "FULL_WIDTH_ICON_MAP", {
34
+ enumerable: true,
35
+ get: function () {
36
+ return _const.FULL_WIDTH_ICON_MAP;
37
+ }
38
+ });
39
+ Object.defineProperty(exports, "FloatingNotification", {
40
+ enumerable: true,
41
+ get: function () {
42
+ return _FloatingNotification.FloatingNotification;
43
+ }
44
+ });
45
+ Object.defineProperty(exports, "FullWidthNotification", {
46
+ enumerable: true,
47
+ get: function () {
48
+ return _FullWidthNotification.FullWidthNotification;
49
+ }
50
+ });
51
+ Object.defineProperty(exports, "ICON_MAP", {
52
+ enumerable: true,
53
+ get: function () {
54
+ return _const.ICON_MAP;
55
+ }
56
+ });
57
+ Object.defineProperty(exports, "MessageNotification", {
58
+ enumerable: true,
59
+ get: function () {
60
+ return _MessageNotification.MessageNotification;
61
+ }
62
+ });
63
+ Object.defineProperty(exports, "Notification", {
64
+ enumerable: true,
65
+ get: function () {
66
+ return _Notification.NcuaNotification;
67
+ }
68
+ });
69
+ Object.defineProperty(exports, "SVG_ICONS", {
70
+ enumerable: true,
71
+ get: function () {
72
+ return _const.SVG_ICONS;
73
+ }
74
+ });
75
+ Object.defineProperty(exports, "mountFloatingNotificationHost", {
76
+ enumerable: true,
77
+ get: function () {
78
+ return _positionSync.mountFloatingNotificationHost;
79
+ }
80
+ });
81
+ Object.defineProperty(exports, "startPositionSync", {
82
+ enumerable: true,
83
+ get: function () {
84
+ return _positionSync.startPositionSync;
85
+ }
86
+ });
87
+ Object.defineProperty(exports, "stopPositionSync", {
88
+ enumerable: true,
89
+ get: function () {
90
+ return _positionSync.stopPositionSync;
91
+ }
92
+ });
93
+ Object.defineProperty(exports, "syncNow", {
94
+ enumerable: true,
95
+ get: function () {
96
+ return _positionSync.syncNow;
97
+ }
98
+ });
99
+ var _const = require("./const");
100
+ var _FloatingNotification = require("./FloatingNotification");
101
+ var _FullWidthNotification = require("./FullWidthNotification");
102
+ var _MessageNotification = require("./MessageNotification");
103
+ var _Notification = require("./Notification");
104
+ var _positionSync = require("./positionSync");
105
+ var _utils = require("./utils");
106
+ Object.keys(_utils).forEach(function (key) {
107
+ if (key === "default" || key === "__esModule") return;
108
+ if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
109
+ if (key in exports && exports[key] === _utils[key]) return;
110
+ Object.defineProperty(exports, key, {
111
+ enumerable: true,
112
+ get: function () {
113
+ return _utils[key];
114
+ }
115
+ });
116
+ });
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.mountFloatingNotificationHost = mountFloatingNotificationHost;
7
+ exports.startPositionSync = startPositionSync;
8
+ exports.stopPositionSync = stopPositionSync;
9
+ exports.syncNow = syncNow;
10
+ /**
11
+ * Floating Notification 호스트 싱글톤 + 위치 동기화
12
+ *
13
+ * 본 모듈은 다음 두 가지 책임을 가진다:
14
+ * 1. `.ncua-floating-notification-host` 싱글톤을 document.body 에 생성·재사용 (mountFloatingNotificationHost).
15
+ * 2. `.ncua-page-title` 의 rect.bottom 을 추적해 `--ncua-page-title-bottom` CSS 변수로 갱신.
16
+ *
17
+ * 두 책임을 한 파일에 두는 이유: 호스트가 처음 생성될 때 positionSync 가 함께 시작되며,
18
+ * React 측 훅과 vanilla 측 `NcuaNotification.show()` 가 동일 함수를 공유해 호스트 생성 로직이
19
+ * 한 곳에서만 유지되도록 한다.
20
+ *
21
+ * NCDS DES-SPEC-027 §5.1
22
+ * · Toast top 좌표 = PageTitle.bottom + 16px (viewport 기준).
23
+ * · PageTitle 이 sticky 로 Default/Fixed 변형 사이 높이가 변동(120/56px)하므로 단순 height
24
+ * 가 아닌 getBoundingClientRect().bottom 을 기준으로 동적 계산해야 한다.
25
+ *
26
+ * 동작 특성:
27
+ * - 다중 호출 idempotent. ensure/start 가 여러 번 호출되어도 호스트와 리스너는 한 벌만.
28
+ * - scroll/resize 는 rAF 로 throttle.
29
+ * - PageTitle 추가/제거를 MutationObserver 로 감지해 재바인딩 — body subtree 변경마다
30
+ * 호출되므로 콜백 자체도 rAF 로 한 프레임당 한 번만 querySelector 가 돌도록 보호.
31
+ * - SSR 가드: window/document 미정의 환경에서 ensure/start 는 no-op.
32
+ *
33
+ * 내부 상태는 모듈 최상단에 흩어진 `let` 대신 한 객체로 묶어 테스트/HMR 에서 일괄 초기화·검사하기
34
+ * 쉽도록 한다. 외부에는 함수만 노출되므로 캡슐화는 유지된다.
35
+ */
36
+ const CSS_VAR = '--ncua-page-title-bottom';
37
+ const PAGE_TITLE_SELECTOR = '.ncua-page-title';
38
+ const HOST_CLASS_NAME = 'ncua-floating-notification-host';
39
+ // add/remove EventListener 의 옵션 객체를 동일 참조로 사용해 capture/passive 미스매치를 차단.
40
+ const SCROLL_OPTIONS = {
41
+ passive: true,
42
+ capture: true
43
+ };
44
+ const RESIZE_OPTIONS = {
45
+ passive: true
46
+ };
47
+ const state = {
48
+ started: false,
49
+ rafId: null,
50
+ rebindRafId: null,
51
+ pageTitle: null,
52
+ resizeObserver: null,
53
+ mutationObserver: null
54
+ };
55
+ /** window/document 가 사용 가능한 브라우저 환경인지 — SSR/Node 가드. */
56
+ function isBrowserEnv() {
57
+ return typeof window !== 'undefined' && typeof document !== 'undefined';
58
+ }
59
+ function readBottomPx() {
60
+ if (!state.pageTitle) state.pageTitle = document.querySelector(PAGE_TITLE_SELECTOR);
61
+ if (!state.pageTitle) return 0;
62
+ const rect = state.pageTitle.getBoundingClientRect();
63
+ // viewport 기준 음수는 0으로 클램프 (PageTitle이 스크롤되어 시야에서 벗어난 경우)
64
+ return Math.max(0, Math.round(rect.bottom));
65
+ }
66
+ function flush() {
67
+ document.documentElement.style.setProperty(CSS_VAR, `${readBottomPx()}px`);
68
+ state.rafId = null;
69
+ }
70
+ function schedule() {
71
+ if (state.rafId !== null) return;
72
+ state.rafId = window.requestAnimationFrame(flush);
73
+ }
74
+ /** 현재 cached pageTitle 이 여전히 DOM 에 연결되어 있는지 — body subtree 변경 시 빠른 early-return. */
75
+ function pageTitleStillInDom() {
76
+ return state.pageTitle?.isConnected ?? false;
77
+ }
78
+ function rebindPageTitle() {
79
+ state.rebindRafId = null;
80
+ if (pageTitleStillInDom()) return;
81
+ const next = document.querySelector(PAGE_TITLE_SELECTOR);
82
+ if (next === state.pageTitle) return;
83
+ state.pageTitle = next;
84
+ if (state.resizeObserver) {
85
+ state.resizeObserver.disconnect();
86
+ // box: 'content-box' 일관성 — startPositionSync 의 첫 observe 와 동일 옵션.
87
+ if (state.pageTitle) state.resizeObserver.observe(state.pageTitle, {
88
+ box: 'content-box'
89
+ });
90
+ }
91
+ schedule();
92
+ }
93
+ /**
94
+ * MutationObserver 콜백 — body subtree 의 모든 변경마다 즉시 querySelector 를 돌리면 비싸므로
95
+ * 프레임당 한 번으로 throttle. 캐시된 pageTitle 이 아직 DOM 에 있으면 rebindPageTitle 안에서
96
+ * 추가 비용 없이 early-return 한다.
97
+ */
98
+ function scheduleRebind() {
99
+ if (state.rebindRafId !== null) return;
100
+ state.rebindRafId = window.requestAnimationFrame(rebindPageTitle);
101
+ }
102
+ /**
103
+ * `.ncua-floating-notification-host` 싱글톤을 보장한다.
104
+ * **side-effect 함수** — 단순 조회가 아니라 다음을 모두 수행:
105
+ * · document.body 에 `<div class="ncua-floating-notification-host">` 를 (필요 시) append
106
+ * · 첫 호출 시 startPositionSync() 로 window scroll/resize/MutationObserver/ResizeObserver 부착
107
+ * · 한 번 만든 호스트는 페이지 lifetime 동안 유지 — 컴포넌트 언마운트 시에도 제거하지 않는다
108
+ * (다음 토스트의 mount 비용을 줄이기 위해 의도된 설계)
109
+ *
110
+ * React 측 hook 과 vanilla 측 `NcuaNotification.show()` 가 모두 이 함수를 사용해 호스트 생성
111
+ * 진입점이 한 곳만 존재한다.
112
+ *
113
+ * @returns 생성되었거나 이미 존재하는 호스트 엘리먼트. SSR 환경에서는 null.
114
+ */
115
+ function mountFloatingNotificationHost() {
116
+ if (!isBrowserEnv()) return null;
117
+ let host = document.querySelector(`.${HOST_CLASS_NAME}`);
118
+ if (!host) {
119
+ host = document.createElement('div');
120
+ host.className = HOST_CLASS_NAME;
121
+ // 호스트는 layout container 일 뿐 — live region 책임은 각 토스트 카드의 role 에 위임.
122
+ document.body.appendChild(host);
123
+ startPositionSync();
124
+ }
125
+ return host;
126
+ }
127
+ /**
128
+ * PageTitle ↔ Floating Host 위치 동기화 시작 (idempotent).
129
+ * `mountFloatingNotificationHost()` 가 자동 호출하므로 일반 사용자는 직접 부를 필요 없음.
130
+ * SSR/테스트에서 수동 제어가 필요할 때만 export 됨.
131
+ */
132
+ function startPositionSync() {
133
+ if (state.started || !isBrowserEnv()) return;
134
+ state.started = true;
135
+ state.pageTitle = document.querySelector(PAGE_TITLE_SELECTOR);
136
+ window.addEventListener('scroll', schedule, SCROLL_OPTIONS);
137
+ window.addEventListener('resize', schedule, RESIZE_OPTIONS);
138
+ if (typeof ResizeObserver !== 'undefined') {
139
+ state.resizeObserver = new ResizeObserver(schedule);
140
+ // box: 'content-box' 명시 — border/padding 변경으로 인한 콜백 재호출 회피 (DOM mutation 무한 루프 방지).
141
+ if (state.pageTitle) state.resizeObserver.observe(state.pageTitle, {
142
+ box: 'content-box'
143
+ });
144
+ }
145
+ if (typeof MutationObserver !== 'undefined') {
146
+ state.mutationObserver = new MutationObserver(scheduleRebind);
147
+ state.mutationObserver.observe(document.body, {
148
+ childList: true,
149
+ subtree: true
150
+ });
151
+ }
152
+ // 첫 동기화
153
+ flush();
154
+ }
155
+ /** 동기화 중단 + 리소스 해제. 테스트 종료/HMR 정리 등에 사용. */
156
+ function stopPositionSync() {
157
+ if (!state.started) return;
158
+ state.started = false;
159
+ window.removeEventListener('scroll', schedule, SCROLL_OPTIONS);
160
+ window.removeEventListener('resize', schedule, RESIZE_OPTIONS);
161
+ state.resizeObserver?.disconnect();
162
+ state.resizeObserver = null;
163
+ state.mutationObserver?.disconnect();
164
+ state.mutationObserver = null;
165
+ if (state.rafId !== null) {
166
+ window.cancelAnimationFrame(state.rafId);
167
+ state.rafId = null;
168
+ }
169
+ if (state.rebindRafId !== null) {
170
+ window.cancelAnimationFrame(state.rebindRafId);
171
+ state.rebindRafId = null;
172
+ }
173
+ state.pageTitle = null;
174
+ // 정리 시 CSS 변수도 초기 상태로 되돌림
175
+ document.documentElement.style.removeProperty(CSS_VAR);
176
+ }
177
+ /** 외부에서 PageTitle.bottom 값을 강제로 다시 측정해 반영하고 싶을 때. */
178
+ function syncNow() {
179
+ flush();
180
+ }
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.bindNotificationEvents = bindNotificationEvents;
7
+ exports.buildClassName = buildClassName;
8
+ exports.createWrapperElement = createWrapperElement;
9
+ exports.isMobile = void 0;
10
+ exports.renderActions = renderActions;
11
+ exports.renderSupportingText = renderSupportingText;
12
+ exports.setupAutoClose = setupAutoClose;
13
+ var _breakpoint = require("../../../src/constant/breakpoint");
14
+ var _const = require("./const");
15
+ // 공통 유틸리티 함수들
16
+ function createWrapperElement(baseClass, color, className) {
17
+ const wrapper = document.createElement('div');
18
+ wrapper.className = buildClassName(baseClass, color, className);
19
+ wrapper.setAttribute('role', 'alert');
20
+ return wrapper;
21
+ }
22
+ function buildClassName(baseClass, color, className) {
23
+ const classes = [baseClass, `${baseClass}--${color}`];
24
+ if (className) {
25
+ classes.push(className);
26
+ }
27
+ return classes.join(' ');
28
+ }
29
+ /**
30
+ * http/https 프로토콜만 허용한다.
31
+ * javascript:, data:, file: 등 위험 프로토콜로 인한 XSS / 외부 페이로드 로딩을 차단.
32
+ */
33
+ function isSafeUrl(url) {
34
+ try {
35
+ const parsed = new URL(url, window.location.origin);
36
+ return parsed.protocol === 'http:' || parsed.protocol === 'https:';
37
+ } catch {
38
+ return false;
39
+ }
40
+ }
41
+ /**
42
+ * HTML 속성 값에 안전하게 삽입하기 위한 최소 이스케이프.
43
+ * 본문(body)이 아닌 속성 컨텍스트에서의 따옴표 탈출(`" onclick="..."`)을 방지.
44
+ */
45
+ function escapeHtmlAttr(str) {
46
+ return str.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/'/g, '&#39;');
47
+ }
48
+ function renderSupportingText(supportingText, className, supportTextLink) {
49
+ if (!supportingText) return '';
50
+ // 본문(supportingText) 자체는 이 함수의 호출 결과가 wrapper.innerHTML에
51
+ // 들어가기 전에 DOMPurify로 sanitize되므로 별도 이스케이프하지 않는다.
52
+ // 이렇게 해야 <br>, <strong> 등 서식용 태그가 그대로 동작한다.
53
+ if (supportTextLink && isSafeUrl(supportTextLink)) {
54
+ const safeLink = escapeHtmlAttr(supportTextLink);
55
+ return `<a href="${safeLink}" class="ncua-full-width-notification__link" rel="noopener noreferrer" target="_blank"><span class="${className}">${supportingText}</span></a>`;
56
+ }
57
+ // unsafe URL이거나 link가 없으면 링크 없이 텍스트만 렌더링
58
+ return `<span class="${className}">${supportingText}</span>`;
59
+ }
60
+ function renderActions(actions, wrapperClass) {
61
+ // 액션이 없으면 빈 문자열 반환
62
+ if (!actions || actions.length === 0) {
63
+ return '';
64
+ }
65
+ const buttonsHtml = actions.map(action => {
66
+ const buttonHtml = `
67
+ <button
68
+ class="ncua-btn ncua-btn--sm ncua-btn--${action.hierarchy || 'text'}"
69
+ data-action="${action.label}-${action.hierarchy}"
70
+ >
71
+ ${action.label}
72
+ </button>`;
73
+ return buttonHtml;
74
+ }).join('');
75
+ return `<div class="${wrapperClass}">${buttonsHtml}</div>`;
76
+ }
77
+ // 공통 이벤트 처리
78
+ function bindNotificationEvents(element, actions, onClose, onRemove) {
79
+ // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: 닫기/액션 버튼 분기를 한 핸들러에 묶는 기존 구조를 유지. 분리 리팩토링은 별도 작업 범위.
80
+ element.addEventListener('click', event => {
81
+ const target = event.target;
82
+ // 닫기 버튼 클릭 처리
83
+ if (target.matches(`.${_const.CLASS_NAMES.FULL_WIDTH.CLOSE_BUTTON}, .${_const.CLASS_NAMES.FLOATING.CLOSE_BUTTON}`) || target.closest(`.${_const.CLASS_NAMES.FULL_WIDTH.CLOSE_BUTTON}, .${_const.CLASS_NAMES.FLOATING.CLOSE_BUTTON}`) || target.closest(`.${_const.CLASS_NAMES.MESSAGE.CLOSE_BUTTON}`)) {
84
+ onClose?.();
85
+ onRemove?.();
86
+ return;
87
+ }
88
+ // 액션 버튼 클릭 처리
89
+ const actionButton = target.closest('.ncua-btn[data-action]');
90
+ if (actionButton && actions) {
91
+ const actionData = actionButton.getAttribute('data-action');
92
+ if (actionData) {
93
+ let matchedAction = null;
94
+ for (const action of actions) {
95
+ const expectedDataAction = `${action.label}-${action.hierarchy || 'link'}`;
96
+ if (actionData === expectedDataAction) {
97
+ matchedAction = action;
98
+ break;
99
+ }
100
+ }
101
+ if (matchedAction?.onClick) {
102
+ matchedAction.onClick();
103
+ }
104
+ }
105
+ }
106
+ });
107
+ }
108
+ // 자동 닫기 설정
109
+ function setupAutoClose(autoClose, onClose, onRemove) {
110
+ if (autoClose > 0) {
111
+ return window.setTimeout(() => {
112
+ onClose?.();
113
+ onRemove?.();
114
+ }, autoClose);
115
+ }
116
+ return undefined;
117
+ }
118
+ // Mobile detection utility
119
+ const isMobile = () => {
120
+ return window.innerWidth <= Number.parseInt(_breakpoint.BREAKPOINT.mobile, 10);
121
+ };
122
+ exports.isMobile = isMobile;