@ngstarter-ui/components 1.0.21

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 (415) hide show
  1. package/README.md +0 -0
  2. package/fesm2022/ngstarter-ui-components-action-required.mjs +42 -0
  3. package/fesm2022/ngstarter-ui-components-action-required.mjs.map +1 -0
  4. package/fesm2022/ngstarter-ui-components-alert.mjs +132 -0
  5. package/fesm2022/ngstarter-ui-components-alert.mjs.map +1 -0
  6. package/fesm2022/ngstarter-ui-components-announcement.mjs +86 -0
  7. package/fesm2022/ngstarter-ui-components-announcement.mjs.map +1 -0
  8. package/fesm2022/ngstarter-ui-components-autocomplete.mjs +360 -0
  9. package/fesm2022/ngstarter-ui-components-autocomplete.mjs.map +1 -0
  10. package/fesm2022/ngstarter-ui-components-avatar.mjs +235 -0
  11. package/fesm2022/ngstarter-ui-components-avatar.mjs.map +1 -0
  12. package/fesm2022/ngstarter-ui-components-badge.mjs +97 -0
  13. package/fesm2022/ngstarter-ui-components-badge.mjs.map +1 -0
  14. package/fesm2022/ngstarter-ui-components-block-loader.mjs +48 -0
  15. package/fesm2022/ngstarter-ui-components-block-loader.mjs.map +1 -0
  16. package/fesm2022/ngstarter-ui-components-bottom-sheet.mjs +327 -0
  17. package/fesm2022/ngstarter-ui-components-bottom-sheet.mjs.map +1 -0
  18. package/fesm2022/ngstarter-ui-components-breadcrumbs.mjs +209 -0
  19. package/fesm2022/ngstarter-ui-components-breadcrumbs.mjs.map +1 -0
  20. package/fesm2022/ngstarter-ui-components-button-toggle.mjs +175 -0
  21. package/fesm2022/ngstarter-ui-components-button-toggle.mjs.map +1 -0
  22. package/fesm2022/ngstarter-ui-components-button.mjs +70 -0
  23. package/fesm2022/ngstarter-ui-components-button.mjs.map +1 -0
  24. package/fesm2022/ngstarter-ui-components-card-overlay.mjs +49 -0
  25. package/fesm2022/ngstarter-ui-components-card-overlay.mjs.map +1 -0
  26. package/fesm2022/ngstarter-ui-components-card.mjs +199 -0
  27. package/fesm2022/ngstarter-ui-components-card.mjs.map +1 -0
  28. package/fesm2022/ngstarter-ui-components-carousel.mjs +614 -0
  29. package/fesm2022/ngstarter-ui-components-carousel.mjs.map +1 -0
  30. package/fesm2022/ngstarter-ui-components-checkbox.mjs +300 -0
  31. package/fesm2022/ngstarter-ui-components-checkbox.mjs.map +1 -0
  32. package/fesm2022/ngstarter-ui-components-chips.mjs +589 -0
  33. package/fesm2022/ngstarter-ui-components-chips.mjs.map +1 -0
  34. package/fesm2022/ngstarter-ui-components-code-highlighter.mjs +347 -0
  35. package/fesm2022/ngstarter-ui-components-code-highlighter.mjs.map +1 -0
  36. package/fesm2022/ngstarter-ui-components-color-picker.mjs +713 -0
  37. package/fesm2022/ngstarter-ui-components-color-picker.mjs.map +1 -0
  38. package/fesm2022/ngstarter-ui-components-color-scheme.mjs +106 -0
  39. package/fesm2022/ngstarter-ui-components-color-scheme.mjs.map +1 -0
  40. package/fesm2022/ngstarter-ui-components-color-switcher.mjs +72 -0
  41. package/fesm2022/ngstarter-ui-components-color-switcher.mjs.map +1 -0
  42. package/fesm2022/ngstarter-ui-components-command-bar.mjs +57 -0
  43. package/fesm2022/ngstarter-ui-components-command-bar.mjs.map +1 -0
  44. package/fesm2022/ngstarter-ui-components-comment-editor.mjs +1024 -0
  45. package/fesm2022/ngstarter-ui-components-comment-editor.mjs.map +1 -0
  46. package/fesm2022/ngstarter-ui-components-comparison-slider.mjs +177 -0
  47. package/fesm2022/ngstarter-ui-components-comparison-slider.mjs.map +1 -0
  48. package/fesm2022/ngstarter-ui-components-confirm.mjs +85 -0
  49. package/fesm2022/ngstarter-ui-components-confirm.mjs.map +1 -0
  50. package/fesm2022/ngstarter-ui-components-content-editor-code-block.component-Bk6QTli8.mjs +173 -0
  51. package/fesm2022/ngstarter-ui-components-content-editor-code-block.component-Bk6QTli8.mjs.map +1 -0
  52. package/fesm2022/ngstarter-ui-components-content-editor-content-editor-content-editable.directive-Bvfa2dqh.mjs +124 -0
  53. package/fesm2022/ngstarter-ui-components-content-editor-content-editor-content-editable.directive-Bvfa2dqh.mjs.map +1 -0
  54. package/fesm2022/ngstarter-ui-components-content-editor-cursor-controller-4Ak8VqGX.mjs +99 -0
  55. package/fesm2022/ngstarter-ui-components-content-editor-cursor-controller-4Ak8VqGX.mjs.map +1 -0
  56. package/fesm2022/ngstarter-ui-components-content-editor-divider-block.component-C_iRTCPH.mjs +33 -0
  57. package/fesm2022/ngstarter-ui-components-content-editor-divider-block.component-C_iRTCPH.mjs.map +1 -0
  58. package/fesm2022/ngstarter-ui-components-content-editor-embed-block-BbkC_t86.mjs +354 -0
  59. package/fesm2022/ngstarter-ui-components-content-editor-embed-block-BbkC_t86.mjs.map +1 -0
  60. package/fesm2022/ngstarter-ui-components-content-editor-heading-block.component-D9_CxTY1.mjs +114 -0
  61. package/fesm2022/ngstarter-ui-components-content-editor-heading-block.component-D9_CxTY1.mjs.map +1 -0
  62. package/fesm2022/ngstarter-ui-components-content-editor-image-block.component-B4zJyUg1.mjs +146 -0
  63. package/fesm2022/ngstarter-ui-components-content-editor-image-block.component-B4zJyUg1.mjs.map +1 -0
  64. package/fesm2022/ngstarter-ui-components-content-editor-list-block.component-Cv6wx5Xe.mjs +215 -0
  65. package/fesm2022/ngstarter-ui-components-content-editor-list-block.component-Cv6wx5Xe.mjs.map +1 -0
  66. package/fesm2022/ngstarter-ui-components-content-editor-ngstarter-ui-components-content-editor-1Zi2nAX5.mjs +2548 -0
  67. package/fesm2022/ngstarter-ui-components-content-editor-ngstarter-ui-components-content-editor-1Zi2nAX5.mjs.map +1 -0
  68. package/fesm2022/ngstarter-ui-components-content-editor-paragraph-block.component-C9bQvDYU.mjs +110 -0
  69. package/fesm2022/ngstarter-ui-components-content-editor-paragraph-block.component-C9bQvDYU.mjs.map +1 -0
  70. package/fesm2022/ngstarter-ui-components-content-editor-quote-block.component-BbHds2r2.mjs +141 -0
  71. package/fesm2022/ngstarter-ui-components-content-editor-quote-block.component-BbHds2r2.mjs.map +1 -0
  72. package/fesm2022/ngstarter-ui-components-content-editor-table-block.component-DlDh7Fnn.mjs +1604 -0
  73. package/fesm2022/ngstarter-ui-components-content-editor-table-block.component-DlDh7Fnn.mjs.map +1 -0
  74. package/fesm2022/ngstarter-ui-components-content-editor-video-block.component-m4DTihP2.mjs +175 -0
  75. package/fesm2022/ngstarter-ui-components-content-editor-video-block.component-m4DTihP2.mjs.map +1 -0
  76. package/fesm2022/ngstarter-ui-components-content-editor.mjs +2 -0
  77. package/fesm2022/ngstarter-ui-components-content-editor.mjs.map +1 -0
  78. package/fesm2022/ngstarter-ui-components-content-fade.mjs +35 -0
  79. package/fesm2022/ngstarter-ui-components-content-fade.mjs.map +1 -0
  80. package/fesm2022/ngstarter-ui-components-cookie-popup.mjs +107 -0
  81. package/fesm2022/ngstarter-ui-components-cookie-popup.mjs.map +1 -0
  82. package/fesm2022/ngstarter-ui-components-core.mjs +1330 -0
  83. package/fesm2022/ngstarter-ui-components-core.mjs.map +1 -0
  84. package/fesm2022/ngstarter-ui-components-country-select.mjs +489 -0
  85. package/fesm2022/ngstarter-ui-components-country-select.mjs.map +1 -0
  86. package/fesm2022/ngstarter-ui-components-crop.mjs +183 -0
  87. package/fesm2022/ngstarter-ui-components-crop.mjs.map +1 -0
  88. package/fesm2022/ngstarter-ui-components-currency-select.mjs +397 -0
  89. package/fesm2022/ngstarter-ui-components-currency-select.mjs.map +1 -0
  90. package/fesm2022/ngstarter-ui-components-data-view.mjs +1494 -0
  91. package/fesm2022/ngstarter-ui-components-data-view.mjs.map +1 -0
  92. package/fesm2022/ngstarter-ui-components-date-format-select.mjs +154 -0
  93. package/fesm2022/ngstarter-ui-components-date-format-select.mjs.map +1 -0
  94. package/fesm2022/ngstarter-ui-components-datepicker.mjs +1159 -0
  95. package/fesm2022/ngstarter-ui-components-datepicker.mjs.map +1 -0
  96. package/fesm2022/ngstarter-ui-components-dialog.mjs +357 -0
  97. package/fesm2022/ngstarter-ui-components-dialog.mjs.map +1 -0
  98. package/fesm2022/ngstarter-ui-components-divider.mjs +42 -0
  99. package/fesm2022/ngstarter-ui-components-divider.mjs.map +1 -0
  100. package/fesm2022/ngstarter-ui-components-drawer.mjs +132 -0
  101. package/fesm2022/ngstarter-ui-components-drawer.mjs.map +1 -0
  102. package/fesm2022/ngstarter-ui-components-emoji-picker.mjs +245 -0
  103. package/fesm2022/ngstarter-ui-components-emoji-picker.mjs.map +1 -0
  104. package/fesm2022/ngstarter-ui-components-empty-state.mjs +75 -0
  105. package/fesm2022/ngstarter-ui-components-empty-state.mjs.map +1 -0
  106. package/fesm2022/ngstarter-ui-components-expand.mjs +56 -0
  107. package/fesm2022/ngstarter-ui-components-expand.mjs.map +1 -0
  108. package/fesm2022/ngstarter-ui-components-expansion.mjs +193 -0
  109. package/fesm2022/ngstarter-ui-components-expansion.mjs.map +1 -0
  110. package/fesm2022/ngstarter-ui-components-filter-builder.mjs +333 -0
  111. package/fesm2022/ngstarter-ui-components-filter-builder.mjs.map +1 -0
  112. package/fesm2022/ngstarter-ui-components-form-field.mjs +230 -0
  113. package/fesm2022/ngstarter-ui-components-form-field.mjs.map +1 -0
  114. package/fesm2022/ngstarter-ui-components-form-renderer-autocomplete-many-field-BKQVlZHV.mjs +124 -0
  115. package/fesm2022/ngstarter-ui-components-form-renderer-autocomplete-many-field-BKQVlZHV.mjs.map +1 -0
  116. package/fesm2022/ngstarter-ui-components-form-renderer-checkbox-field-CoyKdvhV.mjs +22 -0
  117. package/fesm2022/ngstarter-ui-components-form-renderer-checkbox-field-CoyKdvhV.mjs.map +1 -0
  118. package/fesm2022/ngstarter-ui-components-form-renderer-datepicker-field-Bzc0TPO9.mjs +44 -0
  119. package/fesm2022/ngstarter-ui-components-form-renderer-datepicker-field-Bzc0TPO9.mjs.map +1 -0
  120. package/fesm2022/ngstarter-ui-components-form-renderer-divider-content-CwGzDCZv.mjs +17 -0
  121. package/fesm2022/ngstarter-ui-components-form-renderer-divider-content-CwGzDCZv.mjs.map +1 -0
  122. package/fesm2022/ngstarter-ui-components-form-renderer-image-content-ICTwkZPa.mjs +17 -0
  123. package/fesm2022/ngstarter-ui-components-form-renderer-image-content-ICTwkZPa.mjs.map +1 -0
  124. package/fesm2022/ngstarter-ui-components-form-renderer-input-field-RYxi-Mpw.mjs +35 -0
  125. package/fesm2022/ngstarter-ui-components-form-renderer-input-field-RYxi-Mpw.mjs.map +1 -0
  126. package/fesm2022/ngstarter-ui-components-form-renderer-radio-group-field-Cv3AGpoq.mjs +38 -0
  127. package/fesm2022/ngstarter-ui-components-form-renderer-radio-group-field-Cv3AGpoq.mjs.map +1 -0
  128. package/fesm2022/ngstarter-ui-components-form-renderer-select-field-eLcwI-BY.mjs +39 -0
  129. package/fesm2022/ngstarter-ui-components-form-renderer-select-field-eLcwI-BY.mjs.map +1 -0
  130. package/fesm2022/ngstarter-ui-components-form-renderer-text-content-BjzH_M3-.mjs +24 -0
  131. package/fesm2022/ngstarter-ui-components-form-renderer-text-content-BjzH_M3-.mjs.map +1 -0
  132. package/fesm2022/ngstarter-ui-components-form-renderer-textarea-field-4zH7FTQ1.mjs +37 -0
  133. package/fesm2022/ngstarter-ui-components-form-renderer-textarea-field-4zH7FTQ1.mjs.map +1 -0
  134. package/fesm2022/ngstarter-ui-components-form-renderer-timezone-field-BpH65Hd-.mjs +35 -0
  135. package/fesm2022/ngstarter-ui-components-form-renderer-timezone-field-BpH65Hd-.mjs.map +1 -0
  136. package/fesm2022/ngstarter-ui-components-form-renderer-toggle-field-iyqUrWxt.mjs +22 -0
  137. package/fesm2022/ngstarter-ui-components-form-renderer-toggle-field-iyqUrWxt.mjs.map +1 -0
  138. package/fesm2022/ngstarter-ui-components-form-renderer.mjs +317 -0
  139. package/fesm2022/ngstarter-ui-components-form-renderer.mjs.map +1 -0
  140. package/fesm2022/ngstarter-ui-components-gauge.mjs +44 -0
  141. package/fesm2022/ngstarter-ui-components-gauge.mjs.map +1 -0
  142. package/fesm2022/ngstarter-ui-components-grid.mjs +78 -0
  143. package/fesm2022/ngstarter-ui-components-grid.mjs.map +1 -0
  144. package/fesm2022/ngstarter-ui-components-guided-tour.mjs +736 -0
  145. package/fesm2022/ngstarter-ui-components-guided-tour.mjs.map +1 -0
  146. package/fesm2022/ngstarter-ui-components-headless-stepper.mjs +192 -0
  147. package/fesm2022/ngstarter-ui-components-headless-stepper.mjs.map +1 -0
  148. package/fesm2022/ngstarter-ui-components-icon.mjs +61 -0
  149. package/fesm2022/ngstarter-ui-components-icon.mjs.map +1 -0
  150. package/fesm2022/ngstarter-ui-components-image-designer.mjs +4016 -0
  151. package/fesm2022/ngstarter-ui-components-image-designer.mjs.map +1 -0
  152. package/fesm2022/ngstarter-ui-components-image-placeholder.mjs +20 -0
  153. package/fesm2022/ngstarter-ui-components-image-placeholder.mjs.map +1 -0
  154. package/fesm2022/ngstarter-ui-components-image-resizer.mjs +151 -0
  155. package/fesm2022/ngstarter-ui-components-image-resizer.mjs.map +1 -0
  156. package/fesm2022/ngstarter-ui-components-image-viewer.mjs +349 -0
  157. package/fesm2022/ngstarter-ui-components-image-viewer.mjs.map +1 -0
  158. package/fesm2022/ngstarter-ui-components-image-zoom-viewer.mjs +162 -0
  159. package/fesm2022/ngstarter-ui-components-image-zoom-viewer.mjs.map +1 -0
  160. package/fesm2022/ngstarter-ui-components-incidents.mjs +257 -0
  161. package/fesm2022/ngstarter-ui-components-incidents.mjs.map +1 -0
  162. package/fesm2022/ngstarter-ui-components-inline-text-edit.mjs +179 -0
  163. package/fesm2022/ngstarter-ui-components-inline-text-edit.mjs.map +1 -0
  164. package/fesm2022/ngstarter-ui-components-input-mask.mjs +180 -0
  165. package/fesm2022/ngstarter-ui-components-input-mask.mjs.map +1 -0
  166. package/fesm2022/ngstarter-ui-components-input-validator.mjs +24 -0
  167. package/fesm2022/ngstarter-ui-components-input-validator.mjs.map +1 -0
  168. package/fesm2022/ngstarter-ui-components-input.mjs +152 -0
  169. package/fesm2022/ngstarter-ui-components-input.mjs.map +1 -0
  170. package/fesm2022/ngstarter-ui-components-kanban-board.mjs +156 -0
  171. package/fesm2022/ngstarter-ui-components-kanban-board.mjs.map +1 -0
  172. package/fesm2022/ngstarter-ui-components-kbd.mjs +31 -0
  173. package/fesm2022/ngstarter-ui-components-kbd.mjs.map +1 -0
  174. package/fesm2022/ngstarter-ui-components-layout.mjs +199 -0
  175. package/fesm2022/ngstarter-ui-components-layout.mjs.map +1 -0
  176. package/fesm2022/ngstarter-ui-components-list.mjs +279 -0
  177. package/fesm2022/ngstarter-ui-components-list.mjs.map +1 -0
  178. package/fesm2022/ngstarter-ui-components-logo.mjs +51 -0
  179. package/fesm2022/ngstarter-ui-components-logo.mjs.map +1 -0
  180. package/fesm2022/ngstarter-ui-components-marquee.mjs +76 -0
  181. package/fesm2022/ngstarter-ui-components-marquee.mjs.map +1 -0
  182. package/fesm2022/ngstarter-ui-components-menu.mjs +851 -0
  183. package/fesm2022/ngstarter-ui-components-menu.mjs.map +1 -0
  184. package/fesm2022/ngstarter-ui-components-micro-chart.mjs +928 -0
  185. package/fesm2022/ngstarter-ui-components-micro-chart.mjs.map +1 -0
  186. package/fesm2022/ngstarter-ui-components-navigation.mjs +439 -0
  187. package/fesm2022/ngstarter-ui-components-navigation.mjs.map +1 -0
  188. package/fesm2022/ngstarter-ui-components-notifications.mjs +181 -0
  189. package/fesm2022/ngstarter-ui-components-notifications.mjs.map +1 -0
  190. package/fesm2022/ngstarter-ui-components-number-input.mjs +293 -0
  191. package/fesm2022/ngstarter-ui-components-number-input.mjs.map +1 -0
  192. package/fesm2022/ngstarter-ui-components-option.mjs +157 -0
  193. package/fesm2022/ngstarter-ui-components-option.mjs.map +1 -0
  194. package/fesm2022/ngstarter-ui-components-overlay.mjs +112 -0
  195. package/fesm2022/ngstarter-ui-components-overlay.mjs.map +1 -0
  196. package/fesm2022/ngstarter-ui-components-page-loading-bar.mjs +77 -0
  197. package/fesm2022/ngstarter-ui-components-page-loading-bar.mjs.map +1 -0
  198. package/fesm2022/ngstarter-ui-components-paginator.mjs +297 -0
  199. package/fesm2022/ngstarter-ui-components-paginator.mjs.map +1 -0
  200. package/fesm2022/ngstarter-ui-components-panel.mjs +123 -0
  201. package/fesm2022/ngstarter-ui-components-panel.mjs.map +1 -0
  202. package/fesm2022/ngstarter-ui-components-password-strength.mjs +335 -0
  203. package/fesm2022/ngstarter-ui-components-password-strength.mjs.map +1 -0
  204. package/fesm2022/ngstarter-ui-components-phone-input.mjs +651 -0
  205. package/fesm2022/ngstarter-ui-components-phone-input.mjs.map +1 -0
  206. package/fesm2022/ngstarter-ui-components-pin-input.mjs +193 -0
  207. package/fesm2022/ngstarter-ui-components-pin-input.mjs.map +1 -0
  208. package/fesm2022/ngstarter-ui-components-popover.mjs +302 -0
  209. package/fesm2022/ngstarter-ui-components-popover.mjs.map +1 -0
  210. package/fesm2022/ngstarter-ui-components-progress-bar.mjs +68 -0
  211. package/fesm2022/ngstarter-ui-components-progress-bar.mjs.map +1 -0
  212. package/fesm2022/ngstarter-ui-components-radio-card.mjs +102 -0
  213. package/fesm2022/ngstarter-ui-components-radio-card.mjs.map +1 -0
  214. package/fesm2022/ngstarter-ui-components-radio.mjs +147 -0
  215. package/fesm2022/ngstarter-ui-components-radio.mjs.map +1 -0
  216. package/fesm2022/ngstarter-ui-components-rail-nav.mjs +87 -0
  217. package/fesm2022/ngstarter-ui-components-rail-nav.mjs.map +1 -0
  218. package/fesm2022/ngstarter-ui-components-resizable-container.mjs +74 -0
  219. package/fesm2022/ngstarter-ui-components-resizable-container.mjs.map +1 -0
  220. package/fesm2022/ngstarter-ui-components-screen-loader.mjs +95 -0
  221. package/fesm2022/ngstarter-ui-components-screen-loader.mjs.map +1 -0
  222. package/fesm2022/ngstarter-ui-components-scroll-spy.mjs +219 -0
  223. package/fesm2022/ngstarter-ui-components-scroll-spy.mjs.map +1 -0
  224. package/fesm2022/ngstarter-ui-components-scrollbar-area.mjs +459 -0
  225. package/fesm2022/ngstarter-ui-components-scrollbar-area.mjs.map +1 -0
  226. package/fesm2022/ngstarter-ui-components-segmented.mjs +218 -0
  227. package/fesm2022/ngstarter-ui-components-segmented.mjs.map +1 -0
  228. package/fesm2022/ngstarter-ui-components-select.mjs +496 -0
  229. package/fesm2022/ngstarter-ui-components-select.mjs.map +1 -0
  230. package/fesm2022/ngstarter-ui-components-side-panel.mjs +107 -0
  231. package/fesm2022/ngstarter-ui-components-side-panel.mjs.map +1 -0
  232. package/fesm2022/ngstarter-ui-components-sidebar.mjs +435 -0
  233. package/fesm2022/ngstarter-ui-components-sidebar.mjs.map +1 -0
  234. package/fesm2022/ngstarter-ui-components-sidenav.mjs +354 -0
  235. package/fesm2022/ngstarter-ui-components-sidenav.mjs.map +1 -0
  236. package/fesm2022/ngstarter-ui-components-signature-pad.mjs +452 -0
  237. package/fesm2022/ngstarter-ui-components-signature-pad.mjs.map +1 -0
  238. package/fesm2022/ngstarter-ui-components-skeleton.mjs +22 -0
  239. package/fesm2022/ngstarter-ui-components-skeleton.mjs.map +1 -0
  240. package/fesm2022/ngstarter-ui-components-slide-toggle.mjs +93 -0
  241. package/fesm2022/ngstarter-ui-components-slide-toggle.mjs.map +1 -0
  242. package/fesm2022/ngstarter-ui-components-slider.mjs +481 -0
  243. package/fesm2022/ngstarter-ui-components-slider.mjs.map +1 -0
  244. package/fesm2022/ngstarter-ui-components-snack-bar.mjs +354 -0
  245. package/fesm2022/ngstarter-ui-components-snack-bar.mjs.map +1 -0
  246. package/fesm2022/ngstarter-ui-components-sort.mjs +140 -0
  247. package/fesm2022/ngstarter-ui-components-sort.mjs.map +1 -0
  248. package/fesm2022/ngstarter-ui-components-spinner.mjs +75 -0
  249. package/fesm2022/ngstarter-ui-components-spinner.mjs.map +1 -0
  250. package/fesm2022/ngstarter-ui-components-splash-screen.mjs +93 -0
  251. package/fesm2022/ngstarter-ui-components-splash-screen.mjs.map +1 -0
  252. package/fesm2022/ngstarter-ui-components-split.mjs +948 -0
  253. package/fesm2022/ngstarter-ui-components-split.mjs.map +1 -0
  254. package/fesm2022/ngstarter-ui-components-stepper.mjs +103 -0
  255. package/fesm2022/ngstarter-ui-components-stepper.mjs.map +1 -0
  256. package/fesm2022/ngstarter-ui-components-suggestions.mjs +72 -0
  257. package/fesm2022/ngstarter-ui-components-suggestions.mjs.map +1 -0
  258. package/fesm2022/ngstarter-ui-components-tab-panel.mjs +265 -0
  259. package/fesm2022/ngstarter-ui-components-tab-panel.mjs.map +1 -0
  260. package/fesm2022/ngstarter-ui-components-table.mjs +648 -0
  261. package/fesm2022/ngstarter-ui-components-table.mjs.map +1 -0
  262. package/fesm2022/ngstarter-ui-components-tabs.mjs +591 -0
  263. package/fesm2022/ngstarter-ui-components-tabs.mjs.map +1 -0
  264. package/fesm2022/ngstarter-ui-components-text-editor.mjs +1012 -0
  265. package/fesm2022/ngstarter-ui-components-text-editor.mjs.map +1 -0
  266. package/fesm2022/ngstarter-ui-components-thumbnail-maker.mjs +212 -0
  267. package/fesm2022/ngstarter-ui-components-thumbnail-maker.mjs.map +1 -0
  268. package/fesm2022/ngstarter-ui-components-tiles.mjs +634 -0
  269. package/fesm2022/ngstarter-ui-components-tiles.mjs.map +1 -0
  270. package/fesm2022/ngstarter-ui-components-timeline.mjs +122 -0
  271. package/fesm2022/ngstarter-ui-components-timeline.mjs.map +1 -0
  272. package/fesm2022/ngstarter-ui-components-timepicker.mjs +486 -0
  273. package/fesm2022/ngstarter-ui-components-timepicker.mjs.map +1 -0
  274. package/fesm2022/ngstarter-ui-components-timezone-select.mjs +371 -0
  275. package/fesm2022/ngstarter-ui-components-timezone-select.mjs.map +1 -0
  276. package/fesm2022/ngstarter-ui-components-toolbar.mjs +299 -0
  277. package/fesm2022/ngstarter-ui-components-toolbar.mjs.map +1 -0
  278. package/fesm2022/ngstarter-ui-components-tooltip.mjs +506 -0
  279. package/fesm2022/ngstarter-ui-components-tooltip.mjs.map +1 -0
  280. package/fesm2022/ngstarter-ui-components-tree.mjs +200 -0
  281. package/fesm2022/ngstarter-ui-components-tree.mjs.map +1 -0
  282. package/fesm2022/ngstarter-ui-components-upload.mjs +330 -0
  283. package/fesm2022/ngstarter-ui-components-upload.mjs.map +1 -0
  284. package/fesm2022/ngstarter-ui-components-video-player.mjs +516 -0
  285. package/fesm2022/ngstarter-ui-components-video-player.mjs.map +1 -0
  286. package/fesm2022/ngstarter-ui-components-video-viewer.mjs +218 -0
  287. package/fesm2022/ngstarter-ui-components-video-viewer.mjs.map +1 -0
  288. package/fesm2022/ngstarter-ui-components-visual-builder.mjs +18 -0
  289. package/fesm2022/ngstarter-ui-components-visual-builder.mjs.map +1 -0
  290. package/fesm2022/ngstarter-ui-components.mjs +6 -0
  291. package/fesm2022/ngstarter-ui-components.mjs.map +1 -0
  292. package/package.json +535 -0
  293. package/styles/_common.scss +456 -0
  294. package/styles/_global.scss +91 -0
  295. package/styles/themes/default.scss +2 -0
  296. package/types/ngstarter-ui-components-action-required.d.ts +14 -0
  297. package/types/ngstarter-ui-components-alert.d.ts +50 -0
  298. package/types/ngstarter-ui-components-announcement.d.ts +59 -0
  299. package/types/ngstarter-ui-components-autocomplete.d.ts +83 -0
  300. package/types/ngstarter-ui-components-avatar.d.ts +69 -0
  301. package/types/ngstarter-ui-components-badge.d.ts +38 -0
  302. package/types/ngstarter-ui-components-block-loader.d.ts +21 -0
  303. package/types/ngstarter-ui-components-bottom-sheet.d.ts +149 -0
  304. package/types/ngstarter-ui-components-breadcrumbs.d.ts +104 -0
  305. package/types/ngstarter-ui-components-button-toggle.d.ts +54 -0
  306. package/types/ngstarter-ui-components-button.d.ts +27 -0
  307. package/types/ngstarter-ui-components-card-overlay.d.ts +20 -0
  308. package/types/ngstarter-ui-components-card.d.ts +85 -0
  309. package/types/ngstarter-ui-components-carousel.d.ts +76 -0
  310. package/types/ngstarter-ui-components-checkbox.d.ts +94 -0
  311. package/types/ngstarter-ui-components-chips.d.ts +189 -0
  312. package/types/ngstarter-ui-components-code-highlighter.d.ts +28 -0
  313. package/types/ngstarter-ui-components-color-picker.d.ts +92 -0
  314. package/types/ngstarter-ui-components-color-scheme.d.ts +44 -0
  315. package/types/ngstarter-ui-components-color-switcher.d.ts +26 -0
  316. package/types/ngstarter-ui-components-command-bar.d.ts +28 -0
  317. package/types/ngstarter-ui-components-comment-editor.d.ts +194 -0
  318. package/types/ngstarter-ui-components-comparison-slider.d.ts +42 -0
  319. package/types/ngstarter-ui-components-confirm.d.ts +34 -0
  320. package/types/ngstarter-ui-components-content-editor.d.ts +321 -0
  321. package/types/ngstarter-ui-components-content-fade.d.ts +17 -0
  322. package/types/ngstarter-ui-components-cookie-popup.d.ts +41 -0
  323. package/types/ngstarter-ui-components-core.d.ts +421 -0
  324. package/types/ngstarter-ui-components-country-select.d.ts +78 -0
  325. package/types/ngstarter-ui-components-crop.d.ts +59 -0
  326. package/types/ngstarter-ui-components-currency-select.d.ts +82 -0
  327. package/types/ngstarter-ui-components-data-view.d.ts +391 -0
  328. package/types/ngstarter-ui-components-date-format-select.d.ts +59 -0
  329. package/types/ngstarter-ui-components-datepicker.d.ts +384 -0
  330. package/types/ngstarter-ui-components-dialog.d.ts +115 -0
  331. package/types/ngstarter-ui-components-divider.d.ts +18 -0
  332. package/types/ngstarter-ui-components-drawer.d.ts +32 -0
  333. package/types/ngstarter-ui-components-emoji-picker.d.ts +49 -0
  334. package/types/ngstarter-ui-components-empty-state.d.ts +33 -0
  335. package/types/ngstarter-ui-components-expand.d.ts +26 -0
  336. package/types/ngstarter-ui-components-expansion.d.ts +68 -0
  337. package/types/ngstarter-ui-components-filter-builder.d.ts +106 -0
  338. package/types/ngstarter-ui-components-form-field.d.ts +107 -0
  339. package/types/ngstarter-ui-components-form-renderer.d.ts +121 -0
  340. package/types/ngstarter-ui-components-gauge.d.ts +21 -0
  341. package/types/ngstarter-ui-components-grid.d.ts +45 -0
  342. package/types/ngstarter-ui-components-guided-tour.d.ts +227 -0
  343. package/types/ngstarter-ui-components-headless-stepper.d.ts +65 -0
  344. package/types/ngstarter-ui-components-icon.d.ts +17 -0
  345. package/types/ngstarter-ui-components-image-designer.d.ts +357 -0
  346. package/types/ngstarter-ui-components-image-placeholder.d.ts +8 -0
  347. package/types/ngstarter-ui-components-image-resizer.d.ts +35 -0
  348. package/types/ngstarter-ui-components-image-viewer.d.ts +63 -0
  349. package/types/ngstarter-ui-components-image-zoom-viewer.d.ts +34 -0
  350. package/types/ngstarter-ui-components-incidents.d.ts +119 -0
  351. package/types/ngstarter-ui-components-inline-text-edit.d.ts +39 -0
  352. package/types/ngstarter-ui-components-input-mask.d.ts +36 -0
  353. package/types/ngstarter-ui-components-input-validator.d.ts +5 -0
  354. package/types/ngstarter-ui-components-input.d.ts +53 -0
  355. package/types/ngstarter-ui-components-kanban-board.d.ts +68 -0
  356. package/types/ngstarter-ui-components-kbd.d.ts +13 -0
  357. package/types/ngstarter-ui-components-layout.d.ts +83 -0
  358. package/types/ngstarter-ui-components-list.d.ts +98 -0
  359. package/types/ngstarter-ui-components-logo.d.ts +26 -0
  360. package/types/ngstarter-ui-components-marquee.d.ts +27 -0
  361. package/types/ngstarter-ui-components-menu.d.ts +199 -0
  362. package/types/ngstarter-ui-components-micro-chart.d.ts +195 -0
  363. package/types/ngstarter-ui-components-navigation.d.ts +136 -0
  364. package/types/ngstarter-ui-components-notifications.d.ts +84 -0
  365. package/types/ngstarter-ui-components-number-input.d.ts +99 -0
  366. package/types/ngstarter-ui-components-option.d.ts +61 -0
  367. package/types/ngstarter-ui-components-overlay.d.ts +12 -0
  368. package/types/ngstarter-ui-components-page-loading-bar.d.ts +20 -0
  369. package/types/ngstarter-ui-components-paginator.d.ts +145 -0
  370. package/types/ngstarter-ui-components-panel.d.ts +59 -0
  371. package/types/ngstarter-ui-components-password-strength.d.ts +109 -0
  372. package/types/ngstarter-ui-components-phone-input.d.ts +103 -0
  373. package/types/ngstarter-ui-components-pin-input.d.ts +48 -0
  374. package/types/ngstarter-ui-components-popover.d.ts +94 -0
  375. package/types/ngstarter-ui-components-progress-bar.d.ts +30 -0
  376. package/types/ngstarter-ui-components-radio-card.d.ts +37 -0
  377. package/types/ngstarter-ui-components-radio.d.ts +45 -0
  378. package/types/ngstarter-ui-components-rail-nav.d.ts +36 -0
  379. package/types/ngstarter-ui-components-resizable-container.d.ts +25 -0
  380. package/types/ngstarter-ui-components-screen-loader.d.ts +34 -0
  381. package/types/ngstarter-ui-components-scroll-spy.d.ts +63 -0
  382. package/types/ngstarter-ui-components-scrollbar-area.d.ts +67 -0
  383. package/types/ngstarter-ui-components-segmented.d.ts +65 -0
  384. package/types/ngstarter-ui-components-select.d.ts +126 -0
  385. package/types/ngstarter-ui-components-side-panel.d.ts +42 -0
  386. package/types/ngstarter-ui-components-sidebar.d.ts +143 -0
  387. package/types/ngstarter-ui-components-sidenav.d.ts +86 -0
  388. package/types/ngstarter-ui-components-signature-pad.d.ts +49 -0
  389. package/types/ngstarter-ui-components-skeleton.d.ts +9 -0
  390. package/types/ngstarter-ui-components-slide-toggle.d.ts +41 -0
  391. package/types/ngstarter-ui-components-slider.d.ts +85 -0
  392. package/types/ngstarter-ui-components-snack-bar.d.ts +142 -0
  393. package/types/ngstarter-ui-components-sort.d.ts +66 -0
  394. package/types/ngstarter-ui-components-spinner.d.ts +28 -0
  395. package/types/ngstarter-ui-components-splash-screen.d.ts +31 -0
  396. package/types/ngstarter-ui-components-split.d.ts +210 -0
  397. package/types/ngstarter-ui-components-stepper.d.ts +44 -0
  398. package/types/ngstarter-ui-components-suggestions.d.ts +32 -0
  399. package/types/ngstarter-ui-components-tab-panel.d.ts +96 -0
  400. package/types/ngstarter-ui-components-table.d.ts +277 -0
  401. package/types/ngstarter-ui-components-tabs.d.ts +145 -0
  402. package/types/ngstarter-ui-components-text-editor.d.ts +191 -0
  403. package/types/ngstarter-ui-components-thumbnail-maker.d.ts +35 -0
  404. package/types/ngstarter-ui-components-tiles.d.ts +109 -0
  405. package/types/ngstarter-ui-components-timeline.d.ts +57 -0
  406. package/types/ngstarter-ui-components-timepicker.d.ts +115 -0
  407. package/types/ngstarter-ui-components-timezone-select.d.ts +75 -0
  408. package/types/ngstarter-ui-components-toolbar.d.ts +74 -0
  409. package/types/ngstarter-ui-components-tooltip.d.ts +52 -0
  410. package/types/ngstarter-ui-components-tree.d.ts +60 -0
  411. package/types/ngstarter-ui-components-upload.d.ts +134 -0
  412. package/types/ngstarter-ui-components-video-player.d.ts +67 -0
  413. package/types/ngstarter-ui-components-video-viewer.d.ts +98 -0
  414. package/types/ngstarter-ui-components-visual-builder.d.ts +8 -0
  415. package/types/ngstarter-ui-components.d.ts +2 -0
@@ -0,0 +1,2548 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Injectable, inject, Component, model, input, output, Renderer2, signal, computed, Input as Input$1, InjectionToken, EventEmitter, HostListener, Output, Directive, PLATFORM_ID, ElementRef, EnvironmentInjector, ChangeDetectorRef, numberAttribute, runInInjectionContext, effect, forwardRef, ChangeDetectionStrategy } from '@angular/core';
3
+ import { Button } from '@ngstarter-ui/components/button';
4
+ import { Icon } from '@ngstarter-ui/components/icon';
5
+ import { Menu, MenuItem, MenuTrigger, MenuHeading } from '@ngstarter-ui/components/menu';
6
+ import { DialogRef, DialogContent, DialogTitle, DialogActions, DialogClose, DIALOG_DATA, Dialog } from '@ngstarter-ui/components/dialog';
7
+ import { Input } from '@ngstarter-ui/components/input';
8
+ import { FormField, Label, Hint } from '@ngstarter-ui/components/form-field';
9
+ import * as i1 from '@angular/forms';
10
+ import { FormBuilder, Validators, ReactiveFormsModule, FormsModule } from '@angular/forms';
11
+ import { SlideToggle } from '@ngstarter-ui/components/slide-toggle';
12
+ import { DOCUMENT, isPlatformBrowser, isPlatformServer, NgComponentOutlet, AsyncPipe } from '@angular/common';
13
+ import { Tooltip } from '@ngstarter-ui/components/tooltip';
14
+ import { v7 } from 'uuid';
15
+ import { signalStore, withState, withMethods, patchState } from '@ngrx/signals';
16
+ import { moveItemInArray, CdkDrag, CdkDropList, CdkDragHandle, CdkDragPlaceholder } from '@angular/cdk/drag-drop';
17
+ import { ConfirmManager } from '@ngstarter-ui/components/confirm';
18
+ import { CdkMonitorFocus } from '@angular/cdk/a11y';
19
+ import { ComponentPortal } from '@angular/cdk/portal';
20
+ import { Subject, fromEvent } from 'rxjs';
21
+ import { throttleTime, shareReplay, auditTime, map, startWith, distinctUntilChanged } from 'rxjs/operators';
22
+ import * as i1$1 from '@angular/cdk/overlay';
23
+ import SelectionArea from '@viselect/vanilla';
24
+ import { PopoverTriggerForDirective, Popover } from '@ngstarter-ui/components/popover';
25
+ import { SelectionModel } from '@angular/cdk/collections';
26
+ import { ListItemTitle, ListItemIcon, ListItem, List } from '@ngstarter-ui/components/list';
27
+
28
+ class TextHighlightService {
29
+ savedRange = null;
30
+ constructor() { }
31
+ saveCurrentSelection() {
32
+ const selection = window.getSelection();
33
+ const range = this.getCurrentRangeInternal(selection);
34
+ this.savedRange = range ? range.cloneRange() : null;
35
+ // // console.log('TextHighlightService: Выделение сохранено/очищено.');
36
+ }
37
+ restoreSelection() {
38
+ if (!this.savedRange) {
39
+ // // console.warn('TextHighlightService: Нет сохраненного выделения для восстановления.');
40
+ return;
41
+ }
42
+ const selection = window.getSelection();
43
+ if (!selection) {
44
+ // // console.error('TextHighlightService: Не удалось получить window.getSelection() для восстановления.');
45
+ this.savedRange = null;
46
+ return;
47
+ }
48
+ if (this.savedRange.startContainer.isConnected && this.savedRange.endContainer.isConnected) {
49
+ try {
50
+ selection.removeAllRanges();
51
+ selection.addRange(this.savedRange);
52
+ // // console.log('TextHighlightService: Выделение восстановлено.');
53
+ }
54
+ catch (e) {
55
+ // // console.error('TextHighlightService: Ошибка при восстановлении выделения:', e);
56
+ this.savedRange = null;
57
+ }
58
+ }
59
+ else {
60
+ // // console.warn('TextHighlightService: Сохраненный диапазон стал невалидным, восстановление невозможно.');
61
+ this.savedRange = null;
62
+ }
63
+ }
64
+ /**
65
+ * Wraps current selection with specified tag, applying styles, classes, and attributes.
66
+ * If the selection EXACTLY MATCHES THE BOUNDARIES of an existing tag of the same type,
67
+ * then styles, classes, and attributes are ADDED/OVERWRITTEN on that existing tag.
68
+ * Otherwise, a new wrapper is always created.
69
+ * DOES NOT attempt to "cut" elements.
70
+ */
71
+ wrapSelection(tagName, styles, classNames, attrs) {
72
+ const selection = window.getSelection();
73
+ const range = this.getCurrentRangeInternal(selection);
74
+ if (!range || !selection) {
75
+ // // console.warn('TextHighlightService (wrapSelection): Нет валидного выделения.');
76
+ return;
77
+ }
78
+ const normalizedTagName = tagName.toLowerCase();
79
+ const exactExistingContainer = this.findExactWrappingElement(range, normalizedTagName);
80
+ if (exactExistingContainer) {
81
+ this.applyStylesAttributesAndClasses(exactExistingContainer, styles, classNames, attrs);
82
+ selection.removeAllRanges();
83
+ const newExactRange = document.createRange();
84
+ newExactRange.selectNodeContents(exactExistingContainer);
85
+ selection.addRange(newExactRange);
86
+ // // console.log(`TextHighlightService (wrapSelection): Модифицирован существующий элемент <${normalizedTagName}>.`);
87
+ }
88
+ else {
89
+ this.wrapRange(selection, range, normalizedTagName, styles, classNames, attrs);
90
+ // // console.log(`TextHighlightService (wrapSelection): Создана новая обертка <${normalizedTagName}>.`);
91
+ }
92
+ }
93
+ /**
94
+ * "Smart" wrapping:
95
+ * - If the selection exactly covers an existing element of the same type -> modifies it.
96
+ * - If the selection is partially inside an inline element of the same type -> splits it and wraps the selected part.
97
+ * - In other cases -> creates a new wrapper.
98
+ */
99
+ wrapOrSplitInlineSelection(tagName, styles, classNames, attrs) {
100
+ const selection = window.getSelection();
101
+ const range = this.getCurrentRangeInternal(selection);
102
+ if (!range || !selection) {
103
+ // // console.warn('TextHighlightService (wrapOrSplitInlineSelection): Нет валидного выделения.');
104
+ return;
105
+ }
106
+ const normalizedTagName = tagName.toLowerCase();
107
+ const exactContainer = this.findExactWrappingElement(range, normalizedTagName);
108
+ if (exactContainer) {
109
+ this.applyStylesAttributesAndClasses(exactContainer, styles, classNames, attrs);
110
+ selection.removeAllRanges();
111
+ const newExactRange = document.createRange();
112
+ newExactRange.selectNodeContents(exactContainer);
113
+ selection.addRange(newExactRange);
114
+ // // console.log(`TextHighlightService (wrapOrSplitInlineSelection): Модифицирован существующий <${normalizedTagName}>.`);
115
+ return;
116
+ }
117
+ const containingAncestor = this.findContainingAncestor(range, normalizedTagName);
118
+ if (containingAncestor && this.isInlineElement(containingAncestor)) {
119
+ // // console.log(`TextHighlightService (wrapOrSplitInlineSelection): Попытка разделить inline <${normalizedTagName}>.`);
120
+ this.splitInlineElementAndApplyToSelection(selection, range, containingAncestor, normalizedTagName, styles, classNames, attrs);
121
+ return;
122
+ }
123
+ // // console.log(`TextHighlightService (wrapOrSplitInlineSelection): Создаем новую обертку <${normalizedTagName}>.`);
124
+ this.wrapRange(selection, range, normalizedTagName, styles, classNames, attrs);
125
+ }
126
+ unwrapSelection(tagName) {
127
+ const selection = window.getSelection();
128
+ const range = this.getCurrentRangeInternal(selection);
129
+ if (!range || !selection)
130
+ return;
131
+ const normalizedTagName = tagName.toLowerCase();
132
+ const elementToUnwrap = this.findExactWrappingElement(range, normalizedTagName)
133
+ ?? this.findContainingAncestor(range, normalizedTagName);
134
+ if (elementToUnwrap) {
135
+ this.unwrapElementAndReselect(selection, elementToUnwrap);
136
+ // // console.log(`TextHighlightService (unwrapSelection): <${normalizedTagName}> развернут.`);
137
+ }
138
+ else {
139
+ // // console.warn(`TextHighlightService (unwrapSelection): Не найден <${normalizedTagName}> для разворачивания.`);
140
+ }
141
+ }
142
+ toggleWrapSelection(tagName, styles, classNames, attrs) {
143
+ const range = this.getCurrentRange();
144
+ if (!range)
145
+ return;
146
+ const normalizedTagName = tagName.toLowerCase();
147
+ const elementToUnwrap = this.findExactWrappingElement(range, normalizedTagName)
148
+ ?? this.findContainingAncestor(range, normalizedTagName);
149
+ if (elementToUnwrap) {
150
+ this.unwrapSelection(normalizedTagName);
151
+ }
152
+ else {
153
+ this.wrapOrSplitInlineSelection(normalizedTagName, styles, classNames, attrs);
154
+ }
155
+ }
156
+ isSelectionWrappedInTag(tagName) {
157
+ const range = this.getCurrentRange();
158
+ if (!range)
159
+ return false;
160
+ const normalizedTagName = tagName.toLowerCase();
161
+ const containingElement = this.findContainingAncestor(range, normalizedTagName);
162
+ return !!containingElement;
163
+ }
164
+ getCurrentRange() {
165
+ const selection = window.getSelection();
166
+ return this.getCurrentRangeInternal(selection);
167
+ }
168
+ findClosestBlockAncestor(requiredClassName) {
169
+ const range = this.getCurrentRange();
170
+ if (!range)
171
+ return null;
172
+ let node = range.commonAncestorContainer;
173
+ const trimmedClassName = requiredClassName?.trim();
174
+ while (node && node !== document.body && node !== document) {
175
+ if (node.nodeType === Node.ELEMENT_NODE) {
176
+ const element = node;
177
+ if (!this.isInlineElement(element)) {
178
+ if (!trimmedClassName || element.classList.contains(trimmedClassName)) {
179
+ return element;
180
+ }
181
+ }
182
+ }
183
+ node = node.parentNode;
184
+ }
185
+ if (document.body && document.body.contains(range.commonAncestorContainer)) {
186
+ if (!this.isInlineElement(document.body)) {
187
+ if (!trimmedClassName || document.body.classList.contains(trimmedClassName)) {
188
+ return document.body;
189
+ }
190
+ }
191
+ }
192
+ return null;
193
+ }
194
+ setTextAlignment(alignment) {
195
+ const blockAncestor = this.findClosestBlockAncestor();
196
+ if (!blockAncestor)
197
+ return;
198
+ if (alignment && alignment.trim() !== '') {
199
+ blockAncestor.style.textAlign = alignment;
200
+ blockAncestor.setAttribute('data-props-text-alignment', alignment);
201
+ }
202
+ else {
203
+ blockAncestor.style.textAlign = '';
204
+ blockAncestor.removeAttribute('data-props-text-alignment');
205
+ }
206
+ }
207
+ unwrapElementByClassAndSelectContents(className) {
208
+ if (!className || !className.trim())
209
+ return;
210
+ const trimmedClassName = className.trim();
211
+ const selector = `.${trimmedClassName}`;
212
+ const elementToUnwrap = document.querySelector(selector);
213
+ if (!elementToUnwrap)
214
+ return;
215
+ const parent = elementToUnwrap.parentNode;
216
+ if (!parent)
217
+ return;
218
+ const firstChildToSelect = elementToUnwrap.firstChild;
219
+ const lastChildToSelect = elementToUnwrap.lastChild;
220
+ while (elementToUnwrap.firstChild) {
221
+ parent.insertBefore(elementToUnwrap.firstChild, elementToUnwrap);
222
+ }
223
+ parent.removeChild(elementToUnwrap);
224
+ const selection = window.getSelection();
225
+ if (!selection)
226
+ return;
227
+ selection.removeAllRanges();
228
+ if (firstChildToSelect && lastChildToSelect && firstChildToSelect.isConnected && lastChildToSelect.isConnected) {
229
+ try {
230
+ const newRange = document.createRange();
231
+ newRange.setStartBefore(firstChildToSelect);
232
+ newRange.setEndAfter(lastChildToSelect);
233
+ selection.addRange(newRange);
234
+ }
235
+ catch (e) { /* ... */ }
236
+ }
237
+ }
238
+ getContainingAncestorByTagName(tagName) {
239
+ const range = this.getCurrentRange();
240
+ if (!range)
241
+ return null;
242
+ const normalizedTagName = tagName.toLowerCase();
243
+ return this.findContainingAncestor(range, normalizedTagName);
244
+ }
245
+ clearSelectionFormatting() {
246
+ const selection = window.getSelection();
247
+ const range = this.getCurrentRangeInternal(selection);
248
+ if (!range || !selection)
249
+ return;
250
+ try {
251
+ const selectedContents = range.extractContents();
252
+ const plainText = selectedContents.textContent || '';
253
+ const textNode = document.createTextNode(plainText);
254
+ range.insertNode(textNode);
255
+ selection.removeAllRanges();
256
+ const newRange = document.createRange();
257
+ newRange.selectNodeContents(textNode);
258
+ selection.addRange(newRange);
259
+ }
260
+ catch (e) {
261
+ selection.removeAllRanges();
262
+ }
263
+ }
264
+ getCurrentRangeInternal(selection) {
265
+ if (!selection || selection.rangeCount === 0)
266
+ return null;
267
+ const range = selection.getRangeAt(0);
268
+ if (range.collapsed || !range.toString().trim())
269
+ return null;
270
+ return range;
271
+ }
272
+ findExactWrappingElement(range, tagName) {
273
+ const commonAncestor = range.commonAncestorContainer;
274
+ let candidateElement = (commonAncestor.nodeType === Node.ELEMENT_NODE && commonAncestor.tagName.toLowerCase() === tagName)
275
+ ? commonAncestor
276
+ : this.findClosestAncestorByTagName(commonAncestor, tagName);
277
+ if (!candidateElement)
278
+ return null;
279
+ const elementRange = document.createRange();
280
+ try {
281
+ elementRange.selectNodeContents(candidateElement);
282
+ if (range.compareBoundaryPoints(Range.START_TO_START, elementRange) === 0 &&
283
+ range.compareBoundaryPoints(Range.END_TO_END, elementRange) === 0) {
284
+ return candidateElement;
285
+ }
286
+ }
287
+ catch (e) { /*// console.error("Error in findExactWrappingElement:", e);*/ }
288
+ return null;
289
+ }
290
+ findContainingAncestor(range, tagName) {
291
+ let node = range.commonAncestorContainer;
292
+ while (node && node !== document.body && node !== document) {
293
+ if (node.nodeType === Node.ELEMENT_NODE) {
294
+ const element = node;
295
+ if (element.tagName.toLowerCase() === tagName) {
296
+ const elementRange = document.createRange();
297
+ try {
298
+ elementRange.selectNodeContents(element);
299
+ if (range.compareBoundaryPoints(Range.START_TO_START, elementRange) >= 0 &&
300
+ range.compareBoundaryPoints(Range.END_TO_END, elementRange) <= 0) {
301
+ return element;
302
+ }
303
+ }
304
+ catch (e) { /*// console.error("Error in findContainingAncestor:", e); */ }
305
+ }
306
+ }
307
+ node = node.parentNode;
308
+ }
309
+ return null;
310
+ }
311
+ findClosestAncestorByTagName(node, tagName) {
312
+ let currentNode = node;
313
+ while (currentNode && currentNode !== document.body && currentNode !== document) {
314
+ if (currentNode.nodeType === Node.ELEMENT_NODE && currentNode.tagName.toLowerCase() === tagName) {
315
+ return currentNode;
316
+ }
317
+ currentNode = currentNode.parentNode;
318
+ }
319
+ return null;
320
+ }
321
+ findClosestAncestorByClassName(node, className) {
322
+ let currentNode = node;
323
+ const trimmedClassName = className.trim();
324
+ if (!trimmedClassName)
325
+ return null;
326
+ while (currentNode && currentNode !== document.body && currentNode !== document) {
327
+ if (currentNode.nodeType === Node.ELEMENT_NODE && currentNode.classList.contains(trimmedClassName)) {
328
+ return currentNode;
329
+ }
330
+ currentNode = currentNode.parentNode;
331
+ }
332
+ return null;
333
+ }
334
+ applyStylesAttributesAndClasses(element, styles, classNames, attrs) {
335
+ if (styles) {
336
+ for (const styleName in styles) {
337
+ if (Object.prototype.hasOwnProperty.call(styles, styleName)) {
338
+ // @ts-ignore
339
+ if (styles[styleName] !== undefined && isNaN(Number(styleName))) {
340
+ try {
341
+ element.style[styleName] = styles[styleName];
342
+ }
343
+ catch (e) { /* ... */ }
344
+ }
345
+ }
346
+ }
347
+ }
348
+ if (classNames && classNames.length > 0) {
349
+ const validClasses = classNames.filter(cn => cn && cn.trim());
350
+ if (validClasses.length > 0) {
351
+ element.classList.add(...validClasses);
352
+ }
353
+ }
354
+ if (attrs) {
355
+ for (const attrName in attrs) {
356
+ if (Object.prototype.hasOwnProperty.call(attrs, attrName)) {
357
+ const attrValue = attrs[attrName];
358
+ if (attrValue === null) {
359
+ element.removeAttribute(attrName);
360
+ }
361
+ else if (attrValue !== undefined) {
362
+ element.setAttribute(attrName, attrValue);
363
+ }
364
+ }
365
+ }
366
+ }
367
+ }
368
+ wrapRange(selection, range, tagName, styles, classNames, attrs) {
369
+ try {
370
+ const wrapperElement = document.createElement(tagName);
371
+ this.applyStylesAttributesAndClasses(wrapperElement, styles, classNames, attrs);
372
+ const selectedContents = range.extractContents();
373
+ wrapperElement.appendChild(selectedContents);
374
+ range.insertNode(wrapperElement);
375
+ selection.removeAllRanges();
376
+ const newRange = document.createRange();
377
+ newRange.selectNodeContents(wrapperElement);
378
+ selection.addRange(newRange);
379
+ }
380
+ catch (e) {
381
+ selection.removeAllRanges();
382
+ }
383
+ }
384
+ createMarker(id) {
385
+ const marker = document.createElement('span');
386
+ marker.id = id;
387
+ marker.style.display = 'none';
388
+ marker.setAttribute('data-selection-marker', 'true');
389
+ return marker;
390
+ }
391
+ unwrapElementAndReselect(selection, elementToUnwrap) {
392
+ const parent = elementToUnwrap.parentNode;
393
+ if (!parent)
394
+ return;
395
+ const startMarkerId = `__sel_start_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`;
396
+ const endMarkerId = `__sel_end_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`;
397
+ let markersInserted = false;
398
+ const originalRange = this.getCurrentRangeInternal(selection);
399
+ try {
400
+ if (originalRange) {
401
+ const startMarker = this.createMarker(startMarkerId);
402
+ const endMarker = this.createMarker(endMarkerId);
403
+ const rangeEnd = originalRange.cloneRange();
404
+ rangeEnd.collapse(false);
405
+ rangeEnd.insertNode(endMarker);
406
+ const rangeStart = originalRange.cloneRange();
407
+ rangeStart.collapse(true);
408
+ rangeStart.insertNode(startMarker);
409
+ markersInserted = true;
410
+ selection.removeAllRanges();
411
+ }
412
+ }
413
+ catch (e) {
414
+ markersInserted = false;
415
+ if (selection)
416
+ selection.removeAllRanges();
417
+ }
418
+ if (markersInserted || !originalRange) {
419
+ while (elementToUnwrap.firstChild) {
420
+ parent.insertBefore(elementToUnwrap.firstChild, elementToUnwrap);
421
+ }
422
+ parent.removeChild(elementToUnwrap);
423
+ }
424
+ else {
425
+ return;
426
+ }
427
+ if (markersInserted) {
428
+ const startMarker = document.getElementById(startMarkerId);
429
+ const endMarker = document.getElementById(endMarkerId);
430
+ if (startMarker?.parentNode && endMarker?.parentNode) {
431
+ try {
432
+ const newRange = document.createRange();
433
+ newRange.setStartAfter(startMarker);
434
+ newRange.setEndBefore(endMarker);
435
+ const currentSelection = window.getSelection();
436
+ if (currentSelection) {
437
+ currentSelection.removeAllRanges();
438
+ currentSelection.addRange(newRange);
439
+ }
440
+ }
441
+ catch (e) {
442
+ window.getSelection()?.removeAllRanges();
443
+ }
444
+ finally {
445
+ startMarker.parentNode.removeChild(startMarker);
446
+ endMarker.parentNode.removeChild(endMarker);
447
+ }
448
+ }
449
+ else {
450
+ document.getElementById(startMarkerId)?.remove();
451
+ document.getElementById(endMarkerId)?.remove();
452
+ window.getSelection()?.removeAllRanges();
453
+ }
454
+ }
455
+ else {
456
+ window.getSelection()?.removeAllRanges();
457
+ }
458
+ }
459
+ isInlineElement(element) {
460
+ if (!element)
461
+ return false;
462
+ const display = window.getComputedStyle(element).display;
463
+ return display.startsWith('inline');
464
+ }
465
+ splitInlineElementAndApplyToSelection(selection, selectedRange, existingElement, newTagName, newWrapperStyles, newWrapperClassNames, newWrapperAttrs) {
466
+ const parent = existingElement.parentNode;
467
+ if (!parent) {
468
+ this.wrapRange(selection, selectedRange, newTagName, newWrapperStyles, newWrapperClassNames, newWrapperAttrs);
469
+ return;
470
+ }
471
+ const newWrapperForSelection = document.createElement(newTagName);
472
+ this.applyStylesAttributesAndClasses(newWrapperForSelection, newWrapperStyles, newWrapperClassNames, newWrapperAttrs);
473
+ const originalElementAttributes = {};
474
+ for (let i = 0; i < existingElement.attributes.length; i++) {
475
+ const attr = existingElement.attributes[i];
476
+ originalElementAttributes[attr.name] = attr.value;
477
+ }
478
+ const prefixRange = document.createRange();
479
+ prefixRange.setStart(existingElement, 0); // От начала содержимого existingElement
480
+ try {
481
+ prefixRange.setEnd(selectedRange.startContainer, selectedRange.startOffset);
482
+ }
483
+ catch (e) {
484
+ // Если selectedRange.startContainer не является потомком existingElement, это может вызвать ошибку.
485
+ // В таком случае, префиксной части нет или она не может быть корректно определена этим способом.
486
+ // console.warn("Error setting prefixRange end:", e);
487
+ prefixRange.setEnd(existingElement, 0); // Схлопываем в начало
488
+ }
489
+ let prefixElementClone = null;
490
+ if (!prefixRange.collapsed) {
491
+ try {
492
+ const prefixFragment = prefixRange.extractContents();
493
+ prefixElementClone = document.createElement(existingElement.tagName);
494
+ for (const attrName in originalElementAttributes) {
495
+ if (Object.prototype.hasOwnProperty.call(originalElementAttributes, attrName)) {
496
+ prefixElementClone.setAttribute(attrName, originalElementAttributes[attrName]);
497
+ }
498
+ }
499
+ prefixElementClone.appendChild(prefixFragment);
500
+ }
501
+ catch (e) {
502
+ // console.error("Error extracting/creating prefix:", e);
503
+ prefixElementClone = null; // Не удалось создать префикс
504
+ }
505
+ }
506
+ // Извлекаем выделенное содержимое ДО работы с суффиксом, так как selectedRange может стать невалидным
507
+ let selectedFragment;
508
+ try {
509
+ if (selectedRange.commonAncestorContainer.isConnected && !selectedRange.collapsed) {
510
+ selectedFragment = selectedRange.extractContents();
511
+ }
512
+ else {
513
+ selectedFragment = document.createDocumentFragment(); // Пустой, если не удалось извлечь
514
+ }
515
+ }
516
+ catch (e) {
517
+ // console.error("Error extracting selectedFragment:", e);
518
+ selectedFragment = document.createDocumentFragment();
519
+ }
520
+ let suffixElementClone = null;
521
+ // То, что осталось в existingElement после извлечения префикса и выделенной части, - это суффикс
522
+ if (existingElement.hasChildNodes()) {
523
+ suffixElementClone = document.createElement(existingElement.tagName);
524
+ for (const attrName in originalElementAttributes) {
525
+ if (Object.prototype.hasOwnProperty.call(originalElementAttributes, attrName)) {
526
+ suffixElementClone.setAttribute(attrName, originalElementAttributes[attrName]);
527
+ }
528
+ }
529
+ while (existingElement.firstChild) {
530
+ suffixElementClone.appendChild(existingElement.firstChild);
531
+ }
532
+ }
533
+ newWrapperForSelection.appendChild(selectedFragment);
534
+ const insertBeforeOriginal = existingElement;
535
+ if (prefixElementClone) {
536
+ parent.insertBefore(prefixElementClone, insertBeforeOriginal);
537
+ }
538
+ parent.insertBefore(newWrapperForSelection, insertBeforeOriginal);
539
+ if (suffixElementClone) {
540
+ parent.insertBefore(suffixElementClone, insertBeforeOriginal);
541
+ }
542
+ parent.removeChild(existingElement);
543
+ selection.removeAllRanges();
544
+ const finalRange = document.createRange();
545
+ finalRange.selectNodeContents(newWrapperForSelection);
546
+ selection.addRange(finalRange);
547
+ }
548
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: TextHighlightService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
549
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: TextHighlightService, providedIn: 'root' });
550
+ }
551
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: TextHighlightService, decorators: [{
552
+ type: Injectable,
553
+ args: [{
554
+ providedIn: 'root'
555
+ }]
556
+ }], ctorParameters: () => [] });
557
+
558
+ class AddLinkDialog {
559
+ _dialogRef = inject(DialogRef);
560
+ _formBuilder = inject(FormBuilder);
561
+ form = this._formBuilder.group({
562
+ href: [''],
563
+ openInNewTab: [true, [Validators.required]]
564
+ });
565
+ cancel() {
566
+ this._dialogRef.close(false);
567
+ }
568
+ add() {
569
+ this._dialogRef.close(this.form.value);
570
+ }
571
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: AddLinkDialog, deps: [], target: i0.ɵɵFactoryTarget.Component });
572
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.4", type: AddLinkDialog, isStandalone: true, selector: "ngs-add-link", ngImport: i0, template: "<h1 ngs-dialog-title>Add link</h1>\n<ngs-dialog-content [formGroup]=\"form\" class=\"!overflow-hidden\">\n <ngs-form-field class=\"w-full\">\n <ngs-label>Href (Url, Tel or other)</ngs-label>\n <input ngsInput type=\"text\" formControlName=\"href\">\n </ngs-form-field>\n <ngs-slide-toggle formControlName=\"openInNewTab\">Open link in a new tab</ngs-slide-toggle>\n</ngs-dialog-content>\n<ngs-dialog-actions>\n <button ngsButton (click)=\"cancel()\">Cancel</button>\n <button ngsButton=\"filled\"\n [ngs-dialog-close]=\"true\"\n [disabled]=\"form.invalid\" (click)=\"add()\">Add</button>\n</ngs-dialog-actions>\n", styles: [""], dependencies: [{ kind: "component", type: DialogContent, selector: "ngs-dialog-content,[ngs-dialog-content],[ngsDialogContent]" }, { kind: "component", type: FormField, selector: "ngs-form-field", inputs: ["subscriptHiddenIfEmpty"], exportAs: ["ngsFormField"] }, { kind: "directive", type: Input, selector: "input[ngsInput], textarea[ngsInput]", inputs: ["id", "placeholder", "required", "disabled", "readonly", "errorStateMatcher"], exportAs: ["ngsInput"] }, { kind: "component", type: DialogTitle, selector: "ngs-dialog-title, [ngs-dialog-title], [ngsDialogTitle]", inputs: ["id"], exportAs: ["ngsDialogTitle"] }, { kind: "component", type: DialogActions, selector: "ngs-dialog-actions, [ngs-dialog-actions], [ngsDialogActions]", inputs: ["align"] }, { kind: "component", type: Button, selector: " button[ngsButton], button[ngsIconButton], a[ngsButton], a[ngsIconButton] ", inputs: ["ngsButton", "ngsIconButton", "loading", "disabled", "disabledInteractive", "disableRipple", "reverse", "fullWidth", "hideTextOnMobile"], exportAs: ["ngsButton"] }, { kind: "directive", type: DialogClose, selector: "[ngs-dialog-close], [ngsDialogClose]", inputs: ["ngs-dialog-close", "ngsDialogClose", "ariaLabel", "type"], exportAs: ["ngsDialogClose"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: Label, selector: "ngs-label" }, { kind: "component", type: SlideToggle, selector: "ngs-slide-toggle", inputs: ["id", "name", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "disabled", "disableRipple", "tabIndex", "hideIcon", "color", "checked"], outputs: ["disabledChange", "checkedChange", "change", "toggleChange"], exportAs: ["ngsSlideToggle"] }] });
573
+ }
574
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: AddLinkDialog, decorators: [{
575
+ type: Component,
576
+ args: [{ selector: 'ngs-add-link', imports: [
577
+ DialogContent,
578
+ FormField,
579
+ Input,
580
+ DialogTitle,
581
+ DialogActions,
582
+ Button,
583
+ DialogClose,
584
+ ReactiveFormsModule,
585
+ Label,
586
+ SlideToggle
587
+ ], template: "<h1 ngs-dialog-title>Add link</h1>\n<ngs-dialog-content [formGroup]=\"form\" class=\"!overflow-hidden\">\n <ngs-form-field class=\"w-full\">\n <ngs-label>Href (Url, Tel or other)</ngs-label>\n <input ngsInput type=\"text\" formControlName=\"href\">\n </ngs-form-field>\n <ngs-slide-toggle formControlName=\"openInNewTab\">Open link in a new tab</ngs-slide-toggle>\n</ngs-dialog-content>\n<ngs-dialog-actions>\n <button ngsButton (click)=\"cancel()\">Cancel</button>\n <button ngsButton=\"filled\"\n [ngs-dialog-close]=\"true\"\n [disabled]=\"form.invalid\" (click)=\"add()\">Add</button>\n</ngs-dialog-actions>\n" }]
588
+ }] });
589
+
590
+ class EditLinkDialog {
591
+ _dialogRef = inject(DialogRef);
592
+ _dialogData = inject(DIALOG_DATA);
593
+ _formBuilder = inject(FormBuilder);
594
+ form = this._formBuilder.group({
595
+ href: [this._dialogData.href],
596
+ openInNewTab: [this._dialogData.openInNewTab, [Validators.required]]
597
+ });
598
+ cancel() {
599
+ this._dialogRef.close(false);
600
+ }
601
+ add() {
602
+ this._dialogRef.close(this.form.value);
603
+ }
604
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: EditLinkDialog, deps: [], target: i0.ɵɵFactoryTarget.Component });
605
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.4", type: EditLinkDialog, isStandalone: true, selector: "ngs-edit-link", ngImport: i0, template: "<h1 ngs-dialog-title>Edit link</h1>\n<ngs-dialog-content [formGroup]=\"form\" class=\"!overflow-hidden\">\n <ngs-form-field class=\"w-full\">\n <ngs-label>Href (Url, Tel or other)</ngs-label>\n <input ngsInput type=\"text\" formControlName=\"href\">\n <ngs-hint>To delete the link, clear this field and apply</ngs-hint>\n </ngs-form-field>\n <ngs-slide-toggle formControlName=\"openInNewTab\" class=\"mt-5\">Open link in a new tab</ngs-slide-toggle>\n</ngs-dialog-content>\n<ngs-dialog-actions>\n <button ngsButton (click)=\"cancel()\">Cancel</button>\n <button ngsButton=\"filled\"\n [ngs-dialog-close]=\"true\"\n [disabled]=\"form.invalid\" (click)=\"add()\">Apply</button>\n</ngs-dialog-actions>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "component", type: Button, selector: " button[ngsButton], button[ngsIconButton], a[ngsButton], a[ngsIconButton] ", inputs: ["ngsButton", "ngsIconButton", "loading", "disabled", "disabledInteractive", "disableRipple", "reverse", "fullWidth", "hideTextOnMobile"], exportAs: ["ngsButton"] }, { kind: "component", type: DialogActions, selector: "ngs-dialog-actions, [ngs-dialog-actions], [ngsDialogActions]", inputs: ["align"] }, { kind: "component", type: DialogContent, selector: "ngs-dialog-content,[ngs-dialog-content],[ngsDialogContent]" }, { kind: "component", type: DialogTitle, selector: "ngs-dialog-title, [ngs-dialog-title], [ngsDialogTitle]", inputs: ["id"], exportAs: ["ngsDialogTitle"] }, { kind: "component", type: FormField, selector: "ngs-form-field", inputs: ["subscriptHiddenIfEmpty"], exportAs: ["ngsFormField"] }, { kind: "directive", type: Input, selector: "input[ngsInput], textarea[ngsInput]", inputs: ["id", "placeholder", "required", "disabled", "readonly", "errorStateMatcher"], exportAs: ["ngsInput"] }, { kind: "component", type: Label, selector: "ngs-label" }, { kind: "component", type: SlideToggle, selector: "ngs-slide-toggle", inputs: ["id", "name", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "disabled", "disableRipple", "tabIndex", "hideIcon", "color", "checked"], outputs: ["disabledChange", "checkedChange", "change", "toggleChange"], exportAs: ["ngsSlideToggle"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: DialogClose, selector: "[ngs-dialog-close], [ngsDialogClose]", inputs: ["ngs-dialog-close", "ngsDialogClose", "ariaLabel", "type"], exportAs: ["ngsDialogClose"] }, { kind: "component", type: Hint, selector: "ngs-hint", inputs: ["align"] }] });
606
+ }
607
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: EditLinkDialog, decorators: [{
608
+ type: Component,
609
+ args: [{ selector: 'ngs-edit-link', imports: [
610
+ FormsModule,
611
+ Button,
612
+ DialogActions,
613
+ DialogContent,
614
+ DialogTitle,
615
+ FormField,
616
+ Input,
617
+ Label,
618
+ SlideToggle,
619
+ ReactiveFormsModule,
620
+ DialogClose,
621
+ Hint
622
+ ], template: "<h1 ngs-dialog-title>Edit link</h1>\n<ngs-dialog-content [formGroup]=\"form\" class=\"!overflow-hidden\">\n <ngs-form-field class=\"w-full\">\n <ngs-label>Href (Url, Tel or other)</ngs-label>\n <input ngsInput type=\"text\" formControlName=\"href\">\n <ngs-hint>To delete the link, clear this field and apply</ngs-hint>\n </ngs-form-field>\n <ngs-slide-toggle formControlName=\"openInNewTab\" class=\"mt-5\">Open link in a new tab</ngs-slide-toggle>\n</ngs-dialog-content>\n<ngs-dialog-actions>\n <button ngsButton (click)=\"cancel()\">Cancel</button>\n <button ngsButton=\"filled\"\n [ngs-dialog-close]=\"true\"\n [disabled]=\"form.invalid\" (click)=\"add()\">Apply</button>\n</ngs-dialog-actions>\n" }]
623
+ }] });
624
+
625
+ class TextColorComponent {
626
+ recentlyUsed = model(localStorage ? JSON.parse(localStorage.getItem('ngsContentEditorRecentlyUsedTextColor') || '[]') : [], ...(ngDevMode ? [{ debugName: "recentlyUsed" }] : /* istanbul ignore next */ []));
627
+ selectedTextColor = model(null, ...(ngDevMode ? [{ debugName: "selectedTextColor" }] : /* istanbul ignore next */ []));
628
+ selectedBackgroundColor = model(null, ...(ngDevMode ? [{ debugName: "selectedBackgroundColor" }] : /* istanbul ignore next */ []));
629
+ textColors = input([
630
+ {
631
+ name: 'Default',
632
+ color: '',
633
+ type: 'text'
634
+ },
635
+ {
636
+ name: 'Gray',
637
+ color: '#7f7f7f',
638
+ type: 'text'
639
+ },
640
+ {
641
+ name: 'Brown',
642
+ color: '#ae2012',
643
+ type: 'text'
644
+ },
645
+ {
646
+ name: 'Orange',
647
+ color: '#fb5607',
648
+ type: 'text'
649
+ },
650
+ {
651
+ name: 'Yellow',
652
+ color: '#ffa200',
653
+ type: 'text'
654
+ },
655
+ {
656
+ name: 'Green',
657
+ color: '#40916c',
658
+ type: 'text'
659
+ },
660
+ {
661
+ name: 'Blue',
662
+ color: '#00bbf9',
663
+ type: 'text'
664
+ },
665
+ {
666
+ name: 'Purple',
667
+ color: '#907ad6',
668
+ type: 'text'
669
+ },
670
+ {
671
+ name: 'Pink',
672
+ color: '#fa3faf',
673
+ type: 'text'
674
+ },
675
+ {
676
+ name: 'Red',
677
+ color: '#ef233c',
678
+ type: 'text'
679
+ }
680
+ ], ...(ngDevMode ? [{ debugName: "textColors" }] : /* istanbul ignore next */ []));
681
+ backgroundColors = input([
682
+ {
683
+ name: 'Default',
684
+ color: '',
685
+ type: 'background'
686
+ },
687
+ {
688
+ name: 'Gray',
689
+ color: '#e9ecef',
690
+ type: 'background'
691
+ },
692
+ {
693
+ name: 'Brown',
694
+ color: '#ffe0c0',
695
+ type: 'background'
696
+ },
697
+ {
698
+ name: 'Orange',
699
+ color: '#ffd8c6',
700
+ type: 'background'
701
+ },
702
+ {
703
+ name: 'Yellow',
704
+ color: '#fff3b0',
705
+ type: 'background'
706
+ },
707
+ {
708
+ name: 'Green',
709
+ color: '#eff6e0',
710
+ type: 'background'
711
+ },
712
+ {
713
+ name: 'Blue',
714
+ color: '#edf6f9',
715
+ type: 'background'
716
+ },
717
+ {
718
+ name: 'Purple',
719
+ color: '#e0aaff',
720
+ type: 'background'
721
+ },
722
+ {
723
+ name: 'Pink',
724
+ color: '#fae0ec',
725
+ type: 'background'
726
+ },
727
+ {
728
+ name: 'Red',
729
+ color: '#ffdccc',
730
+ type: 'background'
731
+ }
732
+ ], ...(ngDevMode ? [{ debugName: "backgroundColors" }] : /* istanbul ignore next */ []));
733
+ textColorChanged = output();
734
+ backgroundColorChanged = output();
735
+ selectRecentlyColor(color) {
736
+ if (color.type === 'text') {
737
+ this.selectTextColor(color);
738
+ }
739
+ else if (color.type === 'background') {
740
+ this.selectBackgroundColor(color);
741
+ }
742
+ }
743
+ selectTextColor(color) {
744
+ this.selectedTextColor.set(color);
745
+ this.textColorChanged.emit(color.color);
746
+ this._addToRecently(color);
747
+ }
748
+ selectBackgroundColor(color) {
749
+ this.selectedBackgroundColor.set(color);
750
+ this.backgroundColorChanged.emit(color.color);
751
+ this._addToRecently(color);
752
+ }
753
+ _addToRecently(color) {
754
+ const hasRecentlyUsed = this.recentlyUsed()
755
+ .filter(recentlyColor => recentlyColor.name === color.name && recentlyColor.type === color.type)
756
+ .length > 0;
757
+ if (hasRecentlyUsed) {
758
+ return;
759
+ }
760
+ let colors = [...this.recentlyUsed()];
761
+ colors = colors.length >= 5 ? colors.slice(1, 5) : colors;
762
+ this.recentlyUsed.set([...colors, color]);
763
+ localStorage.setItem('ngsContentEditorRecentlyUsedTextColor', JSON.stringify(this.recentlyUsed()));
764
+ }
765
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: TextColorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
766
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: TextColorComponent, isStandalone: true, selector: "ngs-text-color", inputs: { recentlyUsed: { classPropertyName: "recentlyUsed", publicName: "recentlyUsed", isSignal: true, isRequired: false, transformFunction: null }, selectedTextColor: { classPropertyName: "selectedTextColor", publicName: "selectedTextColor", isSignal: true, isRequired: false, transformFunction: null }, selectedBackgroundColor: { classPropertyName: "selectedBackgroundColor", publicName: "selectedBackgroundColor", isSignal: true, isRequired: false, transformFunction: null }, textColors: { classPropertyName: "textColors", publicName: "textColors", isSignal: true, isRequired: false, transformFunction: null }, backgroundColors: { classPropertyName: "backgroundColors", publicName: "backgroundColors", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { recentlyUsed: "recentlyUsedChange", selectedTextColor: "selectedTextColorChange", selectedBackgroundColor: "selectedBackgroundColorChange", textColorChanged: "textColorChanged", backgroundColorChanged: "backgroundColorChanged" }, ngImport: i0, template: "@if (recentlyUsed().length > 0) {\n <div class=\"mb-5\">\n <div class=\"text-xs text-neutral-700 text-semibold\">Recently colors</div>\n <div class=\"flex gap-2 flex-wrap mt-3\">\n @for (recentlyColor of recentlyUsed(); track recentlyColor) {\n @if (recentlyColor.type === 'text') {\n <button class=\"rounded-sm border border-border size-7 flex-none flex items-center justify-center cursor-pointer\"\n [style.color]=\"recentlyColor.color\" [ngsTooltip]=\"recentlyColor.name\"\n (click)=\"selectRecentlyColor(recentlyColor)\">\n <ngs-icon name=\"fluent:text-field-24-regular\"/>\n </button>\n } @else if (recentlyColor.type === 'background') {\n <button class=\"rounded-sm border border-border size-7 flex-none flex items-center justify-center cursor-pointer\"\n [style.background-color]=\"recentlyColor.color\" [ngsTooltip]=\"recentlyColor.name\"\n (click)=\"selectRecentlyColor(recentlyColor)\">\n </button>\n }\n }\n </div>\n </div>\n}\n\n<div class=\"mb-5\">\n <div class=\"text-xs text-neutral-700 text-semibold\">Text color</div>\n <div class=\"flex gap-2 flex-wrap mt-3\">\n @for (textColor of textColors(); track $index) {\n <button class=\"rounded-sm border border-border size-7 flex-none flex items-center justify-center cursor-pointer\n [&.is-selected]:outline [&.is-selected]:outline-primary\"\n [style.color]=\"textColor.color\" [ngsTooltip]=\"textColor.name\"\n [class.is-selected]=\"selectedTextColor()?.color === textColor.color\"\n (click)=\"selectTextColor(textColor)\">\n <ngs-icon name=\"fluent:text-field-24-regular\"/>\n </button>\n }\n </div>\n</div>\n\n<div>\n <div class=\"text-xs text-neutral-700 text-semibold\">Background color</div>\n <div class=\"flex gap-2 flex-wrap mt-3\">\n @for (backgroundColor of backgroundColors(); track $index) {\n <button class=\"rounded-sm border border-border size-7 flex-none flex items-center justify-center cursor-pointer\n [&.is-selected]:outline [&.is-selected]:outline-primary\"\n [style.background-color]=\"backgroundColor.color\" [ngsTooltip]=\"backgroundColor.name\"\n [class.is-selected]=\"selectedBackgroundColor()?.color === backgroundColor.color\"\n (click)=\"selectBackgroundColor(backgroundColor)\">\n </button>\n }\n </div>\n</div>\n", styles: [":host{display:block;width:172px}\n"], dependencies: [{ kind: "component", type: Icon, selector: "ngs-icon", inputs: ["name"], exportAs: ["ngsIcon"] }, { kind: "directive", type: Tooltip, selector: "[ngsTooltip]", inputs: ["ngsTooltip", "ngsTooltipPosition", "ngsTooltipClass", "ngsTooltipShowDelay", "ngsTooltipHideDelay", "ngsTooltipOffset", "ngsTooltipPositionAtOrigin", "ngsTooltipDisabled"], exportAs: ["ngsTooltip"] }] });
767
+ }
768
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: TextColorComponent, decorators: [{
769
+ type: Component,
770
+ args: [{ selector: 'ngs-text-color', imports: [
771
+ Icon,
772
+ Tooltip
773
+ ], template: "@if (recentlyUsed().length > 0) {\n <div class=\"mb-5\">\n <div class=\"text-xs text-neutral-700 text-semibold\">Recently colors</div>\n <div class=\"flex gap-2 flex-wrap mt-3\">\n @for (recentlyColor of recentlyUsed(); track recentlyColor) {\n @if (recentlyColor.type === 'text') {\n <button class=\"rounded-sm border border-border size-7 flex-none flex items-center justify-center cursor-pointer\"\n [style.color]=\"recentlyColor.color\" [ngsTooltip]=\"recentlyColor.name\"\n (click)=\"selectRecentlyColor(recentlyColor)\">\n <ngs-icon name=\"fluent:text-field-24-regular\"/>\n </button>\n } @else if (recentlyColor.type === 'background') {\n <button class=\"rounded-sm border border-border size-7 flex-none flex items-center justify-center cursor-pointer\"\n [style.background-color]=\"recentlyColor.color\" [ngsTooltip]=\"recentlyColor.name\"\n (click)=\"selectRecentlyColor(recentlyColor)\">\n </button>\n }\n }\n </div>\n </div>\n}\n\n<div class=\"mb-5\">\n <div class=\"text-xs text-neutral-700 text-semibold\">Text color</div>\n <div class=\"flex gap-2 flex-wrap mt-3\">\n @for (textColor of textColors(); track $index) {\n <button class=\"rounded-sm border border-border size-7 flex-none flex items-center justify-center cursor-pointer\n [&.is-selected]:outline [&.is-selected]:outline-primary\"\n [style.color]=\"textColor.color\" [ngsTooltip]=\"textColor.name\"\n [class.is-selected]=\"selectedTextColor()?.color === textColor.color\"\n (click)=\"selectTextColor(textColor)\">\n <ngs-icon name=\"fluent:text-field-24-regular\"/>\n </button>\n }\n </div>\n</div>\n\n<div>\n <div class=\"text-xs text-neutral-700 text-semibold\">Background color</div>\n <div class=\"flex gap-2 flex-wrap mt-3\">\n @for (backgroundColor of backgroundColors(); track $index) {\n <button class=\"rounded-sm border border-border size-7 flex-none flex items-center justify-center cursor-pointer\n [&.is-selected]:outline [&.is-selected]:outline-primary\"\n [style.background-color]=\"backgroundColor.color\" [ngsTooltip]=\"backgroundColor.name\"\n [class.is-selected]=\"selectedBackgroundColor()?.color === backgroundColor.color\"\n (click)=\"selectBackgroundColor(backgroundColor)\">\n </button>\n }\n </div>\n</div>\n", styles: [":host{display:block;width:172px}\n"] }]
774
+ }], propDecorators: { recentlyUsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "recentlyUsed", required: false }] }, { type: i0.Output, args: ["recentlyUsedChange"] }], selectedTextColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedTextColor", required: false }] }, { type: i0.Output, args: ["selectedTextColorChange"] }], selectedBackgroundColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedBackgroundColor", required: false }] }, { type: i0.Output, args: ["selectedBackgroundColorChange"] }], textColors: [{ type: i0.Input, args: [{ isSignal: true, alias: "textColors", required: false }] }], backgroundColors: [{ type: i0.Input, args: [{ isSignal: true, alias: "backgroundColors", required: false }] }], textColorChanged: [{ type: i0.Output, args: ["textColorChanged"] }], backgroundColorChanged: [{ type: i0.Output, args: ["backgroundColorChanged"] }] } });
775
+
776
+ class CommandBarComponent {
777
+ _document = inject(DOCUMENT);
778
+ _textHighlightService = inject(TextHighlightService);
779
+ _renderer = inject(Renderer2);
780
+ _dialog = inject(Dialog);
781
+ observedElement = null;
782
+ props = signal([], ...(ngDevMode ? [{ debugName: "props" }] : /* istanbul ignore next */ []));
783
+ alignment = computed(() => {
784
+ const alignment = this.props().find(prop => prop.name === 'text-alignment');
785
+ return alignment?.value || 'left';
786
+ }, ...(ngDevMode ? [{ debugName: "alignment" }] : /* istanbul ignore next */ []));
787
+ ngOnInit() {
788
+ this._extractProps();
789
+ }
790
+ toggleBold() {
791
+ this._textHighlightService.toggleWrapSelection('strong');
792
+ }
793
+ toggleItalic() {
794
+ this._textHighlightService.toggleWrapSelection('em');
795
+ }
796
+ toggleCode() {
797
+ this._textHighlightService.toggleWrapSelection('code', undefined, ['code']);
798
+ }
799
+ toggleStrike() {
800
+ this._textHighlightService.toggleWrapSelection('s');
801
+ }
802
+ toggleUnderline() {
803
+ this._textHighlightService.toggleWrapSelection('u');
804
+ }
805
+ toggleSuperscript() {
806
+ this._textHighlightService.toggleWrapSelection('sup');
807
+ }
808
+ toggleSubscript() {
809
+ this._textHighlightService.toggleWrapSelection('sub');
810
+ }
811
+ isLinkActive() {
812
+ const fakeSelection = this._document.querySelector('.link-selection');
813
+ if (fakeSelection) {
814
+ return true;
815
+ }
816
+ return this._textHighlightService.isSelectionWrappedInTag('a');
817
+ }
818
+ isActive(tagName) {
819
+ return this._textHighlightService.isSelectionWrappedInTag(tagName);
820
+ }
821
+ setTextAlignment(alignment) {
822
+ this._textHighlightService.setTextAlignment(alignment);
823
+ this._extractProps();
824
+ }
825
+ isTextAlignment(alignment) {
826
+ return this.alignment() === alignment;
827
+ }
828
+ addLink() {
829
+ this._textHighlightService.toggleWrapSelection('span', undefined, ['link-selection']);
830
+ const dialogRef = this._dialog.open(AddLinkDialog, {
831
+ width: '500px',
832
+ disableClose: true,
833
+ hasBackdrop: true
834
+ });
835
+ dialogRef.afterClosed().subscribe((res) => {
836
+ this._textHighlightService.unwrapElementByClassAndSelectContents('link-selection');
837
+ if (res && res.href) {
838
+ this._textHighlightService.toggleWrapSelection('a', undefined, ['link'], {
839
+ href: res.href,
840
+ target: res.openInNewTab ? '_blank' : '_self'
841
+ });
842
+ }
843
+ });
844
+ }
845
+ editLink() {
846
+ const link = this._textHighlightService.getContainingAncestorByTagName('a');
847
+ this._textHighlightService.toggleWrapSelection('span', undefined, ['link-selection']);
848
+ if (!link) {
849
+ return;
850
+ }
851
+ const dialogRef = this._dialog.open(EditLinkDialog, {
852
+ data: {
853
+ href: link.getAttribute('href'),
854
+ openInNewTab: link.getAttribute('target') === '_blank',
855
+ },
856
+ width: '500px',
857
+ disableClose: true,
858
+ hasBackdrop: true
859
+ });
860
+ dialogRef.afterClosed().subscribe((res) => {
861
+ this._textHighlightService.unwrapElementByClassAndSelectContents('link-selection');
862
+ if (res) {
863
+ if (res.href) {
864
+ this._renderer.setAttribute(link, 'href', res.href);
865
+ this._renderer.setAttribute(link, 'target', res.openInNewTab ? '_blank' : '_self');
866
+ }
867
+ else {
868
+ this._textHighlightService.toggleWrapSelection('a');
869
+ }
870
+ }
871
+ });
872
+ }
873
+ onMenuOpen() {
874
+ this._textHighlightService.wrapSelection('span', undefined, ['text-selection']);
875
+ }
876
+ onMenuClose() {
877
+ let textSelectionElement = this._document.querySelector('.text-selection');
878
+ if (textSelectionElement) {
879
+ if (textSelectionElement.style.color || textSelectionElement.style.backgroundColor) {
880
+ this._renderer.removeClass(textSelectionElement, 'text-selection');
881
+ }
882
+ else {
883
+ this._textHighlightService.unwrapElementByClassAndSelectContents('text-selection');
884
+ }
885
+ }
886
+ }
887
+ preventMenuClose(event) {
888
+ event.stopPropagation();
889
+ event.preventDefault();
890
+ }
891
+ onTextColorChanged(color) {
892
+ let textSelectionElement = this._document.querySelector('.text-selection');
893
+ if (color) {
894
+ this._renderer.setStyle(textSelectionElement, 'color', color);
895
+ }
896
+ else {
897
+ this._renderer.removeStyle(textSelectionElement, 'color');
898
+ }
899
+ }
900
+ onBackgroundColorChanged(color) {
901
+ let textSelectionElement = this._document.querySelector('.text-selection');
902
+ if (color) {
903
+ this._renderer.setStyle(textSelectionElement, 'backgroundColor', color);
904
+ }
905
+ else {
906
+ this._renderer.removeStyle(textSelectionElement, 'backgroundColor');
907
+ }
908
+ }
909
+ _extractProps() {
910
+ if (!this.observedElement) {
911
+ return;
912
+ }
913
+ const props = [];
914
+ for (const attribute of this.observedElement.attributes) {
915
+ if (!attribute.name.startsWith('data-props-')) {
916
+ continue;
917
+ }
918
+ const prop = {
919
+ name: attribute.name.replace('data-props-', ''),
920
+ value: attribute.value
921
+ };
922
+ props.push(prop);
923
+ }
924
+ this.props.set(props);
925
+ }
926
+ ngOnDestroy() {
927
+ this._textHighlightService.unwrapElementByClassAndSelectContents('link-selection');
928
+ this._unwrapTextSelection();
929
+ }
930
+ _unwrapTextSelection() {
931
+ let textSelectionElement = this._document.querySelector('.text-selection');
932
+ if (textSelectionElement) {
933
+ if (!textSelectionElement.style.color && !textSelectionElement.style.backgroundColor) {
934
+ this._textHighlightService.unwrapElementByClassAndSelectContents('text-selection');
935
+ }
936
+ else {
937
+ this._renderer.removeClass(textSelectionElement, 'text-selection');
938
+ }
939
+ }
940
+ }
941
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: CommandBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
942
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: CommandBarComponent, isStandalone: true, selector: "ngs-command-bar", inputs: { observedElement: "observedElement" }, host: { classAttribute: "ngs-command-bar" }, ngImport: i0, template: "<div class=\"flex items-center gap-1\">\n <button ngsIconButton (click)=\"toggleBold()\"\n [class.is-active]=\"isActive('strong')\">\n <ngs-icon name=\"fluent:text-bold-24-regular\"/>\n </button>\n <button ngsIconButton (click)=\"toggleItalic()\"\n [class.is-active]=\"isActive('em')\">\n <ngs-icon name=\"fluent:text-italic-24-regular\"/>\n </button>\n <button ngsIconButton (click)=\"toggleStrike()\"\n [class.is-active]=\"isActive('s')\">\n <ngs-icon name=\"fluent:text-strikethrough-24-regular\"/>\n </button>\n <button ngsIconButton (click)=\"toggleUnderline()\"\n [class.is-active]=\"isActive('u')\">\n <ngs-icon name=\"fluent:text-underline-24-regular\"/>\n </button>\n <button ngsIconButton (click)=\"toggleSuperscript()\"\n [class.is-active]=\"isActive('sup')\">\n <ngs-icon name=\"fluent:text-superscript-24-regular\"/>\n </button>\n <button ngsIconButton (click)=\"toggleSubscript()\"\n [class.is-active]=\"isActive('sub')\">\n <ngs-icon name=\"fluent:text-subscript-24-regular\"/>\n </button>\n <button ngsIconButton (click)=\"toggleCode()\"\n [class.is-active]=\"isActive('code')\">\n <ngs-icon name=\"fluent:code-24-regular\"/>\n </button>\n\n @if (isLinkActive()) {\n <button ngsIconButton (click)=\"editLink()\">\n <ngs-icon name=\"fluent:link-24-regular\"/>\n </button>\n } @else {\n <button ngsIconButton (click)=\"addLink()\">\n <ngs-icon name=\"fluent:link-add-24-regular\"/>\n </button>\n }\n <button ngsIconButton [ngsMenuTriggerFor]=\"alignMenu\">\n @switch (alignment()) {\n @case ('left') {\n <ngs-icon name=\"fluent:text-align-left-24-regular\"/>\n }\n @case ('center') {\n <ngs-icon name=\"fluent:text-align-center-24-regular\"/>\n }\n @case ('right') {\n <ngs-icon name=\"fluent:text-align-right-24-regular\"/>\n }\n }\n </button>\n <button ngsIconButton [ngsMenuTriggerFor]=\"formatColorText\" (menuOpened)=\"onMenuOpen()\">\n <ngs-icon name=\"fluent:text-color-24-regular\"/>\n </button>\n</div>\n\n<ngs-menu #alignMenu=\"ngsMenu\">\n <button class=\"[&.is-active]:!bg-secondary-container\"\n [class.is-active]=\"isTextAlignment('left')\"\n ngs-menu-item\n (click)=\"setTextAlignment('left')\">\n <ngs-icon name=\"fluent:text-align-left-24-regular\"/>\n Align Left\n </button>\n <button class=\"[&.is-active]:!bg-secondary-container\"\n [class.is-active]=\"isTextAlignment('center')\"\n ngs-menu-item\n (click)=\"setTextAlignment('center')\">\n <ngs-icon name=\"fluent:text-align-center-24-regular\"/>\n Align Center\n </button>\n <button class=\"[&.is-active]:!bg-secondary-container\"\n [class.is-active]=\"isTextAlignment('right')\"\n ngs-menu-item (click)=\"setTextAlignment('right')\">\n <ngs-icon name=\"fluent:text-align-right-24-regular\"/>\n Align Right\n </button>\n</ngs-menu>\n\n<ngs-menu #formatColorText=\"ngsMenu\" (closed)=\"onMenuClose()\">\n <div class=\"px-4 py-3\" (mousedown)=\"preventMenuClose($event)\">\n <ngs-text-color (textColorChanged)=\"onTextColorChanged($event)\"\n (backgroundColorChanged)=\"onBackgroundColorChanged($event)\"/>\n </div>\n</ngs-menu>\n", styles: [":host{background:var(--color-surface-container);border-radius:calc(var(--spacing, .25rem) * 3);padding:calc(var(--spacing, .25rem) * 1);box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a}:host button.is-active{background:var(--color-surface-container-highest);color:var(--color-primary)}\n/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "component", type: Button, selector: " button[ngsButton], button[ngsIconButton], a[ngsButton], a[ngsIconButton] ", inputs: ["ngsButton", "ngsIconButton", "loading", "disabled", "disabledInteractive", "disableRipple", "reverse", "fullWidth", "hideTextOnMobile"], exportAs: ["ngsButton"] }, { kind: "component", type: Icon, selector: "ngs-icon", inputs: ["name"], exportAs: ["ngsIcon"] }, { kind: "component", type: Menu, selector: "ngs-menu", inputs: ["role", "classList", "xPosition", "yPosition"], outputs: ["closed"], exportAs: ["ngsMenu"] }, { kind: "component", type: MenuItem, selector: "ngs-menu-item, [ngs-menu-item]", inputs: ["disabled", "role", "selected"], outputs: ["_triggered"], exportAs: ["ngsMenuItem"] }, { kind: "directive", type: MenuTrigger, selector: "[ngsMenuTriggerFor]", inputs: ["ngsMenuTriggerFor", "ngsMenuTriggerData", "ngsMenuDisabled", "xPosition", "yPosition", "ngsMenuTriggerRestoreFocus"], outputs: ["menuOpened", "menuClosed"], exportAs: ["ngsMenuTrigger"] }, { kind: "component", type: TextColorComponent, selector: "ngs-text-color", inputs: ["recentlyUsed", "selectedTextColor", "selectedBackgroundColor", "textColors", "backgroundColors"], outputs: ["recentlyUsedChange", "selectedTextColorChange", "selectedBackgroundColorChange", "textColorChanged", "backgroundColorChanged"] }] });
943
+ }
944
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: CommandBarComponent, decorators: [{
945
+ type: Component,
946
+ args: [{ selector: 'ngs-command-bar', imports: [
947
+ Button,
948
+ Icon,
949
+ Menu,
950
+ MenuItem,
951
+ MenuTrigger,
952
+ TextColorComponent
953
+ ], host: {
954
+ 'class': 'ngs-command-bar'
955
+ }, template: "<div class=\"flex items-center gap-1\">\n <button ngsIconButton (click)=\"toggleBold()\"\n [class.is-active]=\"isActive('strong')\">\n <ngs-icon name=\"fluent:text-bold-24-regular\"/>\n </button>\n <button ngsIconButton (click)=\"toggleItalic()\"\n [class.is-active]=\"isActive('em')\">\n <ngs-icon name=\"fluent:text-italic-24-regular\"/>\n </button>\n <button ngsIconButton (click)=\"toggleStrike()\"\n [class.is-active]=\"isActive('s')\">\n <ngs-icon name=\"fluent:text-strikethrough-24-regular\"/>\n </button>\n <button ngsIconButton (click)=\"toggleUnderline()\"\n [class.is-active]=\"isActive('u')\">\n <ngs-icon name=\"fluent:text-underline-24-regular\"/>\n </button>\n <button ngsIconButton (click)=\"toggleSuperscript()\"\n [class.is-active]=\"isActive('sup')\">\n <ngs-icon name=\"fluent:text-superscript-24-regular\"/>\n </button>\n <button ngsIconButton (click)=\"toggleSubscript()\"\n [class.is-active]=\"isActive('sub')\">\n <ngs-icon name=\"fluent:text-subscript-24-regular\"/>\n </button>\n <button ngsIconButton (click)=\"toggleCode()\"\n [class.is-active]=\"isActive('code')\">\n <ngs-icon name=\"fluent:code-24-regular\"/>\n </button>\n\n @if (isLinkActive()) {\n <button ngsIconButton (click)=\"editLink()\">\n <ngs-icon name=\"fluent:link-24-regular\"/>\n </button>\n } @else {\n <button ngsIconButton (click)=\"addLink()\">\n <ngs-icon name=\"fluent:link-add-24-regular\"/>\n </button>\n }\n <button ngsIconButton [ngsMenuTriggerFor]=\"alignMenu\">\n @switch (alignment()) {\n @case ('left') {\n <ngs-icon name=\"fluent:text-align-left-24-regular\"/>\n }\n @case ('center') {\n <ngs-icon name=\"fluent:text-align-center-24-regular\"/>\n }\n @case ('right') {\n <ngs-icon name=\"fluent:text-align-right-24-regular\"/>\n }\n }\n </button>\n <button ngsIconButton [ngsMenuTriggerFor]=\"formatColorText\" (menuOpened)=\"onMenuOpen()\">\n <ngs-icon name=\"fluent:text-color-24-regular\"/>\n </button>\n</div>\n\n<ngs-menu #alignMenu=\"ngsMenu\">\n <button class=\"[&.is-active]:!bg-secondary-container\"\n [class.is-active]=\"isTextAlignment('left')\"\n ngs-menu-item\n (click)=\"setTextAlignment('left')\">\n <ngs-icon name=\"fluent:text-align-left-24-regular\"/>\n Align Left\n </button>\n <button class=\"[&.is-active]:!bg-secondary-container\"\n [class.is-active]=\"isTextAlignment('center')\"\n ngs-menu-item\n (click)=\"setTextAlignment('center')\">\n <ngs-icon name=\"fluent:text-align-center-24-regular\"/>\n Align Center\n </button>\n <button class=\"[&.is-active]:!bg-secondary-container\"\n [class.is-active]=\"isTextAlignment('right')\"\n ngs-menu-item (click)=\"setTextAlignment('right')\">\n <ngs-icon name=\"fluent:text-align-right-24-regular\"/>\n Align Right\n </button>\n</ngs-menu>\n\n<ngs-menu #formatColorText=\"ngsMenu\" (closed)=\"onMenuClose()\">\n <div class=\"px-4 py-3\" (mousedown)=\"preventMenuClose($event)\">\n <ngs-text-color (textColorChanged)=\"onTextColorChanged($event)\"\n (backgroundColorChanged)=\"onBackgroundColorChanged($event)\"/>\n </div>\n</ngs-menu>\n", styles: [":host{background:var(--color-surface-container);border-radius:calc(var(--spacing, .25rem) * 3);padding:calc(var(--spacing, .25rem) * 1);box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a}:host button.is-active{background:var(--color-surface-container-highest);color:var(--color-primary)}\n/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */\n"] }]
956
+ }], propDecorators: { observedElement: [{
957
+ type: Input$1
958
+ }] } });
959
+
960
+ const CONTENT_BUILDER = new InjectionToken('CONTENT_BUILDER');
961
+ const CONTENT_EDITOR_BLOCK = new InjectionToken('CONTENT_EDITOR_BLOCK');
962
+
963
+ const initialState = {
964
+ focusedBlockId: null,
965
+ activeBlockId: null,
966
+ blocks: []
967
+ };
968
+ const ContentBuilderStore = signalStore(withState(initialState), withMethods((store) => ({
969
+ setFocusedBlockId(focusedBlockId) {
970
+ patchState(store, (state) => ({ focusedBlockId }));
971
+ },
972
+ setActiveBlockId(activeBlockId) {
973
+ patchState(store, (state) => ({ activeBlockId }));
974
+ },
975
+ setBlocks(blocks) {
976
+ patchState(store, (state) => ({ blocks }));
977
+ },
978
+ addBlock(dataBlock, index) {
979
+ patchState(store, (state) => {
980
+ const blocks = [...state.blocks];
981
+ blocks.splice(index, 0, dataBlock);
982
+ return {
983
+ blocks
984
+ };
985
+ });
986
+ },
987
+ deleteBlock(blockId, index) {
988
+ patchState(store, (state) => {
989
+ const blocks = [...state.blocks];
990
+ blocks.splice(index, 1);
991
+ return {
992
+ blocks
993
+ };
994
+ });
995
+ },
996
+ updateBlock(blockId, data) {
997
+ patchState(store, (state) => {
998
+ const blocks = [...state.blocks];
999
+ const index = blocks.findIndex(block => block.id === blockId);
1000
+ if (index !== -1) {
1001
+ blocks[index] = {
1002
+ ...blocks[index],
1003
+ ...data
1004
+ };
1005
+ }
1006
+ return {
1007
+ blocks
1008
+ };
1009
+ });
1010
+ },
1011
+ moveBlock(fromIndex, toIndex) {
1012
+ patchState(store, (state) => {
1013
+ const newBlocks = [...state.blocks];
1014
+ const [movedItem] = newBlocks.splice(fromIndex, 1);
1015
+ newBlocks.splice(toIndex, 0, movedItem);
1016
+ return {
1017
+ ...state,
1018
+ blocks: newBlocks,
1019
+ };
1020
+ });
1021
+ },
1022
+ })));
1023
+
1024
+ // src/app/text-selection-popup.directive.ts
1025
+ const POPUP_VERTICAL_OFFSET = 8;
1026
+ class TextSelectionPopupDirective {
1027
+ overlay;
1028
+ viewContainerRef;
1029
+ elementRef;
1030
+ renderer;
1031
+ overlayContainer;
1032
+ ngZone;
1033
+ targetComponent;
1034
+ closestContentObserverClass = null;
1035
+ tagSelected = new EventEmitter();
1036
+ overlayRef = null;
1037
+ hostElement;
1038
+ currentSelectionRange = null;
1039
+ documentClickListener = null;
1040
+ positionStrategy = null;
1041
+ scrollListener = null;
1042
+ scrollSubject = new Subject();
1043
+ scrollSubscription = null;
1044
+ constructor(overlay, viewContainerRef, elementRef, renderer, overlayContainer, ngZone) {
1045
+ this.overlay = overlay;
1046
+ this.viewContainerRef = viewContainerRef;
1047
+ this.elementRef = elementRef;
1048
+ this.renderer = renderer;
1049
+ this.overlayContainer = overlayContainer;
1050
+ this.ngZone = ngZone;
1051
+ this.hostElement = this.elementRef.nativeElement;
1052
+ this.scrollSubscription = this.scrollSubject.pipe(throttleTime(50, undefined, { leading: true, trailing: true })).subscribe(() => {
1053
+ this.updatePopupPositionOnScroll();
1054
+ });
1055
+ }
1056
+ onDocumentClickHostListener(event) {
1057
+ if (event.target.closest('.cdk-overlay-container')) {
1058
+ return;
1059
+ }
1060
+ this.processSelection();
1061
+ }
1062
+ onDocumentKeyDown(event) {
1063
+ if (!this.overlayRef)
1064
+ return;
1065
+ if (this.isEventInsidePopup(event))
1066
+ return;
1067
+ const ignoredKeys = [
1068
+ 'Shift', 'Control', 'Alt', 'Meta', 'CapsLock',
1069
+ 'Escape', 'Tab',
1070
+ 'ArrowDown', 'ArrowUp', 'ArrowLeft', 'ArrowRight',
1071
+ 'Home', 'End', 'PageUp', 'PageDown',
1072
+ 'Insert', 'ContextMenu',
1073
+ 'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9', 'F10', 'F11', 'F12'
1074
+ ];
1075
+ if (ignoredKeys.includes(event.key)) {
1076
+ setTimeout(() => this.processSelection(), 0);
1077
+ return;
1078
+ }
1079
+ if (event.target.closest('.cdk-overlay-container')) {
1080
+ return;
1081
+ }
1082
+ this.closePopup();
1083
+ }
1084
+ processSelection() {
1085
+ const selection = window.getSelection();
1086
+ if (!selection || selection.isCollapsed || selection.rangeCount === 0) {
1087
+ if (this.overlayRef && !this.isFocusInsidePopup()) {
1088
+ this.closePopup();
1089
+ }
1090
+ this.currentSelectionRange = null;
1091
+ return;
1092
+ }
1093
+ const range = selection.getRangeAt(0);
1094
+ if (!this.hostElement.contains(range.startContainer) || !this.hostElement.contains(range.endContainer)) {
1095
+ this.closePopupIfNeeded();
1096
+ this.currentSelectionRange = null;
1097
+ return;
1098
+ }
1099
+ let observedElement = null;
1100
+ if (this.closestContentObserverClass) {
1101
+ observedElement = this.findClosestElementWithClass(range.startContainer, this.closestContentObserverClass);
1102
+ if (!observedElement) {
1103
+ this.closePopupIfNeeded();
1104
+ this.currentSelectionRange = null;
1105
+ return;
1106
+ }
1107
+ }
1108
+ const selectedText = selection.toString().trim();
1109
+ if (selectedText) {
1110
+ const selectionRects = range.getClientRects();
1111
+ if (selectionRects.length > 0) {
1112
+ const startRect = selectionRects[0];
1113
+ const lastRect = selectionRects[selectionRects.length - 1];
1114
+ const hostRect = this.hostElement.getBoundingClientRect();
1115
+ const hostCenterX = hostRect.left + hostRect.width / 2;
1116
+ const selectionStartX = startRect.left;
1117
+ const selectionEndX = lastRect.right;
1118
+ const selectionCenterX = selectionStartX + (selectionEndX - selectionStartX) / 2;
1119
+ const alignRight = selectionCenterX >= hostCenterX;
1120
+ const scrollX = document.body.scrollLeft;
1121
+ const scrollY = document.body.scrollTop;
1122
+ const anchorX = selectionStartX + scrollX;
1123
+ const endX = selectionEndX + scrollX;
1124
+ const anchorY = startRect.top + scrollY;
1125
+ const containingTagName = this.getContainingTagName(range);
1126
+ const newRange = range.cloneRange();
1127
+ if (!this.overlayRef || !this.areRangesEqual(this.currentSelectionRange, newRange)) {
1128
+ this.closePopupIfNeeded();
1129
+ this.currentSelectionRange = newRange;
1130
+ this.showPopup({ x: anchorX, y: anchorY }, endX, alignRight, observedElement);
1131
+ this.tagSelected.emit(containingTagName);
1132
+ }
1133
+ }
1134
+ else {
1135
+ this.closePopupIfNeeded();
1136
+ this.currentSelectionRange = null;
1137
+ }
1138
+ }
1139
+ else {
1140
+ this.closePopupIfNeeded();
1141
+ this.currentSelectionRange = null;
1142
+ }
1143
+ }
1144
+ showPopup(anchorPosition, selectionEndX, alignRight, observedElement) {
1145
+ if (!this.targetComponent || this.overlayRef)
1146
+ return;
1147
+ this.positionStrategy = this.overlay.position().global();
1148
+ this.positionStrategy.left(`${anchorPosition.x}px`).top(`${anchorPosition.y}px`);
1149
+ this.overlayRef = this.overlay.create({
1150
+ positionStrategy: this.positionStrategy,
1151
+ hasBackdrop: false,
1152
+ scrollStrategy: this.overlay.scrollStrategies.noop(),
1153
+ });
1154
+ const portal = new ComponentPortal(this.targetComponent, this.viewContainerRef);
1155
+ const componentRef = this.overlayRef.attach(portal);
1156
+ if (componentRef.instance && 'observedElement' in componentRef.instance) {
1157
+ componentRef.instance.observedElement = observedElement;
1158
+ }
1159
+ if (this.overlayRef) {
1160
+ Promise.resolve().then(() => {
1161
+ if (this.overlayRef && this.positionStrategy) {
1162
+ try {
1163
+ const overlayElement = this.overlayRef.overlayElement;
1164
+ const popupHeight = overlayElement.offsetHeight;
1165
+ const popupWidth = overlayElement.offsetWidth;
1166
+ if (popupHeight > 0 && popupWidth > 0) {
1167
+ const correctTop = anchorPosition.y - popupHeight - POPUP_VERTICAL_OFFSET;
1168
+ const correctLeft = alignRight ? selectionEndX - popupWidth : anchorPosition.x;
1169
+ this.positionStrategy.left(`${correctLeft}px`).top(`${correctTop}px`);
1170
+ this.overlayRef.updatePosition();
1171
+ }
1172
+ }
1173
+ catch (e) {
1174
+ console.error("Error correcting initial popup position:", e);
1175
+ }
1176
+ this.addDocumentClickListener();
1177
+ this.addScrollListener();
1178
+ }
1179
+ });
1180
+ }
1181
+ }
1182
+ closePopupIfNeeded() {
1183
+ if (this.overlayRef) {
1184
+ this.closePopup();
1185
+ }
1186
+ }
1187
+ closePopup() {
1188
+ if (!this.overlayRef)
1189
+ return;
1190
+ this.overlayRef.dispose();
1191
+ this.overlayRef = null;
1192
+ this.positionStrategy = null;
1193
+ this.currentSelectionRange = null;
1194
+ this.removeDocumentClickListener();
1195
+ this.removeScrollListener();
1196
+ }
1197
+ addScrollListener() {
1198
+ if (this.scrollListener)
1199
+ return;
1200
+ this.ngZone.runOutsideAngular(() => {
1201
+ this.scrollListener = this.renderer.listen(document, 'scroll', (event) => {
1202
+ this.scrollSubject.next();
1203
+ });
1204
+ });
1205
+ }
1206
+ removeScrollListener() {
1207
+ if (this.scrollListener) {
1208
+ this.scrollListener();
1209
+ this.scrollListener = null;
1210
+ }
1211
+ }
1212
+ updatePopupPositionOnScroll() {
1213
+ if (!this.overlayRef || !this.positionStrategy || !this.currentSelectionRange)
1214
+ return;
1215
+ try {
1216
+ const selectionRects = this.currentSelectionRange.getClientRects();
1217
+ if (selectionRects.length > 0) {
1218
+ const startRect = selectionRects[0];
1219
+ const lastRect = selectionRects[selectionRects.length - 1];
1220
+ const hostRect = this.hostElement.getBoundingClientRect();
1221
+ const hostCenterX = hostRect.left + hostRect.width / 2;
1222
+ const selectionStartX = startRect.left;
1223
+ const selectionEndX = lastRect.right;
1224
+ const selectionCenterX = selectionStartX + (selectionEndX - selectionStartX) / 2;
1225
+ const alignRight = selectionCenterX >= hostCenterX;
1226
+ const scrollX = document.body.scrollLeft;
1227
+ const scrollY = document.body.scrollTop;
1228
+ const textTop = startRect.top + scrollY;
1229
+ const popupElement = this.overlayRef.overlayElement;
1230
+ const popupHeight = popupElement.offsetHeight;
1231
+ const popupWidth = popupElement.offsetWidth;
1232
+ let newX;
1233
+ if (alignRight) {
1234
+ newX = (lastRect.right + scrollX) - popupWidth;
1235
+ }
1236
+ else {
1237
+ newX = startRect.left + scrollX;
1238
+ }
1239
+ const newY = textTop - popupHeight - POPUP_VERTICAL_OFFSET;
1240
+ this.ngZone.run(() => {
1241
+ if (this.overlayRef && this.positionStrategy) {
1242
+ this.positionStrategy.left(`${newX}px`).top(`${newY}px`);
1243
+ this.overlayRef.updatePosition();
1244
+ }
1245
+ });
1246
+ }
1247
+ else {
1248
+ this.ngZone.run(() => this.closePopup());
1249
+ }
1250
+ }
1251
+ catch (e) {
1252
+ console.error("Error updating popup position on scroll:", e);
1253
+ this.ngZone.run(() => this.closePopup());
1254
+ }
1255
+ }
1256
+ findClosestElementWithClass(startNode, className) {
1257
+ let currentNode = startNode;
1258
+ const hostParent = this.hostElement.parentNode;
1259
+ while (currentNode && currentNode !== hostParent && currentNode !== document.body && currentNode !== document.documentElement) {
1260
+ if (currentNode instanceof Element && currentNode.classList.contains(className)) {
1261
+ return currentNode;
1262
+ }
1263
+ currentNode = currentNode.parentNode;
1264
+ }
1265
+ if (this.hostElement.classList.contains(className)) {
1266
+ return this.hostElement;
1267
+ }
1268
+ return null;
1269
+ }
1270
+ getContainingTagName(range) {
1271
+ let container = range.commonAncestorContainer;
1272
+ while (container && container.nodeType !== Node.ELEMENT_NODE) {
1273
+ container = container.parentNode;
1274
+ }
1275
+ return container instanceof Element ? container.tagName : null;
1276
+ }
1277
+ addDocumentClickListener() {
1278
+ if (this.documentClickListener)
1279
+ return;
1280
+ this.documentClickListener = this.renderer.listen(document, 'click', (event) => {
1281
+ this.handleDocumentClick(event);
1282
+ });
1283
+ }
1284
+ removeDocumentClickListener() {
1285
+ if (this.documentClickListener) {
1286
+ this.documentClickListener();
1287
+ this.documentClickListener = null;
1288
+ }
1289
+ }
1290
+ handleDocumentClick(event) {
1291
+ if (!this.overlayRef || !event.target)
1292
+ return;
1293
+ const clickedElement = event.target;
1294
+ if (this.isEventInsidePopup(event))
1295
+ return;
1296
+ const overlayContainerElement = this.overlayContainer.getContainerElement();
1297
+ if (overlayContainerElement.contains(clickedElement))
1298
+ return;
1299
+ this.closePopup();
1300
+ }
1301
+ isEventInsidePopup(event) {
1302
+ if (!this.overlayRef?.overlayElement || !event.target)
1303
+ return false;
1304
+ return this.overlayRef.overlayElement.contains(event.target);
1305
+ }
1306
+ isClickInsidePopup(node) {
1307
+ return !!this.overlayRef?.overlayElement?.contains(node);
1308
+ }
1309
+ isFocusInsidePopup() {
1310
+ if (!this.overlayRef?.overlayElement || !document.activeElement)
1311
+ return false;
1312
+ return this.overlayRef.overlayElement.contains(document.activeElement);
1313
+ }
1314
+ areRangesEqual(r1, r2) {
1315
+ if (!r1 || !r2)
1316
+ return r1 === r2;
1317
+ return (r1.commonAncestorContainer === r2.commonAncestorContainer &&
1318
+ r1.startContainer === r2.startContainer &&
1319
+ r1.endContainer === r2.endContainer &&
1320
+ r1.startOffset === r2.startOffset &&
1321
+ r1.endOffset === r2.endOffset);
1322
+ }
1323
+ ngOnDestroy() {
1324
+ this.closePopup();
1325
+ if (this.scrollSubscription) {
1326
+ this.scrollSubscription.unsubscribe();
1327
+ this.scrollSubscription = null;
1328
+ }
1329
+ this.removeDocumentClickListener();
1330
+ this.removeScrollListener();
1331
+ }
1332
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: TextSelectionPopupDirective, deps: [{ token: i1$1.Overlay }, { token: i0.ViewContainerRef }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i1$1.OverlayContainer }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Directive });
1333
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.4", type: TextSelectionPopupDirective, isStandalone: true, selector: "[ngsTextSelectionPopup]", inputs: { targetComponent: "targetComponent", closestContentObserverClass: "closestContentObserverClass" }, outputs: { tagSelected: "tagSelected" }, host: { listeners: { "document:click": "onDocumentClickHostListener($event)", "document:keydown": "onDocumentKeyDown($event)" } }, ngImport: i0 });
1334
+ }
1335
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: TextSelectionPopupDirective, decorators: [{
1336
+ type: Directive,
1337
+ args: [{
1338
+ selector: '[ngsTextSelectionPopup]',
1339
+ standalone: true,
1340
+ }]
1341
+ }], ctorParameters: () => [{ type: i1$1.Overlay }, { type: i0.ViewContainerRef }, { type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i1$1.OverlayContainer }, { type: i0.NgZone }], propDecorators: { targetComponent: [{
1342
+ type: Input$1
1343
+ }], closestContentObserverClass: [{
1344
+ type: Input$1
1345
+ }], tagSelected: [{
1346
+ type: Output
1347
+ }], onDocumentClickHostListener: [{
1348
+ type: HostListener,
1349
+ args: ['document:click', ['$event']]
1350
+ }], onDocumentKeyDown: [{
1351
+ type: HostListener,
1352
+ args: ['document:keydown', ['$event']]
1353
+ }] } });
1354
+
1355
+ /**
1356
+ * Directive to enable mouse-drag selection of child blocks inside a container.
1357
+ *
1358
+ * Behavior:
1359
+ * - Drag can be started only from an area that is NOT inside a block (matched by `blockSelector`).
1360
+ * - While dragging, the directive creates a dynamic selection rectangle element with the
1361
+ * class `selectionAreaClass` (default: `ngs-textContent-builder-selection-area`).
1362
+ * - Any block that intersects the selection rectangle receives `selectedClass` (default: `is-selected`).
1363
+ * When the block leaves the selection area, the class is removed.
1364
+ */
1365
+ class BlockSelectionDirective {
1366
+ document = inject(DOCUMENT);
1367
+ _platformId = inject(PLATFORM_ID);
1368
+ contentBuilder = inject(CONTENT_BUILDER);
1369
+ /** CSS selector for selectable blocks. Defaults to `.block`. */
1370
+ blockSelector = input('.block-content', ...(ngDevMode ? [{ debugName: "blockSelector" }] : /* istanbul ignore next */ []));
1371
+ autoScrollContainerSelector = input(null, ...(ngDevMode ? [{ debugName: "autoScrollContainerSelector" }] : /* istanbul ignore next */ []));
1372
+ /** CSS class applied to the dynamic selection rectangle element. */
1373
+ selectionAreaClass = input('selection-area', ...(ngDevMode ? [{ debugName: "selectionAreaClass" }] : /* istanbul ignore next */ []));
1374
+ /**
1375
+ * List of CSS class names to ignore when starting selection.
1376
+ * If the mousedown target or any of its ancestors (via closest) contains any of
1377
+ * these classes, the selection will NOT start. Class names can be provided with
1378
+ * or without leading dot (e.g., 'toolbar-button' or '.toolbar-button').
1379
+ */
1380
+ ignoreClasses = input(['.block-controls'], ...(ngDevMode ? [{ debugName: "ignoreClasses" }] : /* istanbul ignore next */ []));
1381
+ elRef = inject(ElementRef);
1382
+ host = this.elRef.nativeElement;
1383
+ selection = null;
1384
+ // Track only blockIds we toggled via drag selection to avoid interfering with other selection sources
1385
+ selectedSet = new Set();
1386
+ constructor() {
1387
+ if (isPlatformBrowser(this._platformId)) {
1388
+ this.selection = new SelectionArea({
1389
+ selectables: [this.blockSelector()],
1390
+ boundaries: [this.host],
1391
+ container: this.host,
1392
+ features: {
1393
+ touch: false,
1394
+ range: true,
1395
+ deselectOnBlur: true,
1396
+ singleTap: {
1397
+ allow: true,
1398
+ intersect: 'native'
1399
+ }
1400
+ },
1401
+ selectionAreaClass: this.selectionAreaClass()
1402
+ }).on('beforestart', ({ event }) => {
1403
+ const targetEl = event?.target;
1404
+ if (this.isInIgnoredArea(targetEl) || targetEl?.closest(this.blockSelector())) {
1405
+ return false;
1406
+ }
1407
+ if (event) {
1408
+ event.preventDefault();
1409
+ }
1410
+ return true;
1411
+ }).on('stop', () => {
1412
+ this.contentBuilder.isSelectionOfBlocksActive.set(false);
1413
+ }).on('start', ({ store, event }) => {
1414
+ this.contentBuilder.isSelectionOfBlocksActive.set(true);
1415
+ const activeElement = this.document.activeElement;
1416
+ if (activeElement && (activeElement.tagName === 'INPUT' || activeElement.tagName === 'TEXTAREA' || activeElement.isContentEditable)) {
1417
+ activeElement.blur();
1418
+ }
1419
+ this.host.focus();
1420
+ if (event && !event.ctrlKey && !event.metaKey) {
1421
+ this.contentBuilder.unselectSelectedBlocks();
1422
+ this.selectedSet.clear();
1423
+ }
1424
+ }).on('move', ({ store: { changed: { added, removed } } }) => {
1425
+ added.forEach(el => {
1426
+ const blockEl = el.closest('.block');
1427
+ const blockId = blockEl?.getAttribute('data-block-id');
1428
+ if (blockId) {
1429
+ this.contentBuilder.selectBlock(blockId, true);
1430
+ this.selectedSet.add(blockId);
1431
+ }
1432
+ });
1433
+ removed.forEach(el => {
1434
+ const blockEl = el.closest('.block');
1435
+ const blockId = blockEl?.getAttribute('data-block-id');
1436
+ if (blockId && this.selectedSet.has(blockId)) {
1437
+ this.contentBuilder.unselectBlock(blockId);
1438
+ this.selectedSet.delete(blockId);
1439
+ }
1440
+ });
1441
+ });
1442
+ }
1443
+ }
1444
+ ngOnDestroy() {
1445
+ this.selection?.destroy();
1446
+ }
1447
+ isInIgnoredArea(target) {
1448
+ const list = this.ignoreClasses();
1449
+ if (!target || !Array.isArray(list) || list.length === 0)
1450
+ return false;
1451
+ const normalized = list
1452
+ .map(c => (c ?? '').toString().trim())
1453
+ .filter(Boolean)
1454
+ .map(c => c.startsWith('.') ? c.slice(1) : c);
1455
+ if (normalized.length === 0)
1456
+ return false;
1457
+ let el = target;
1458
+ // Traverse up through ancestors to emulate "closest" semantics for class names
1459
+ while (el) {
1460
+ for (const cls of normalized) {
1461
+ if (el.classList && el.classList.contains(cls))
1462
+ return true;
1463
+ }
1464
+ el = el.parentElement;
1465
+ }
1466
+ return false;
1467
+ }
1468
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: BlockSelectionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1469
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.4", type: BlockSelectionDirective, isStandalone: true, selector: "[ngsBlockSelection]", inputs: { blockSelector: { classPropertyName: "blockSelector", publicName: "blockSelector", isSignal: true, isRequired: false, transformFunction: null }, autoScrollContainerSelector: { classPropertyName: "autoScrollContainerSelector", publicName: "autoScrollContainerSelector", isSignal: true, isRequired: false, transformFunction: null }, selectionAreaClass: { classPropertyName: "selectionAreaClass", publicName: "selectionAreaClass", isSignal: true, isRequired: false, transformFunction: null }, ignoreClasses: { classPropertyName: "ignoreClasses", publicName: "ignoreClasses", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
1470
+ }
1471
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: BlockSelectionDirective, decorators: [{
1472
+ type: Directive,
1473
+ args: [{
1474
+ selector: '[ngsBlockSelection]'
1475
+ }]
1476
+ }], ctorParameters: () => [], propDecorators: { blockSelector: [{ type: i0.Input, args: [{ isSignal: true, alias: "blockSelector", required: false }] }], autoScrollContainerSelector: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoScrollContainerSelector", required: false }] }], selectionAreaClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionAreaClass", required: false }] }], ignoreClasses: [{ type: i0.Input, args: [{ isSignal: true, alias: "ignoreClasses", required: false }] }] } });
1477
+
1478
+ class ContentBuilderComponent {
1479
+ _platformId = inject(PLATFORM_ID);
1480
+ _store = inject(ContentBuilderStore);
1481
+ elRef = inject((ElementRef));
1482
+ envInjector = inject(EnvironmentInjector);
1483
+ cdr = inject(ChangeDetectorRef);
1484
+ confirmManager = inject(ConfirmManager);
1485
+ _resolvedScrollContainer = null;
1486
+ _scrollEffect;
1487
+ _scrollSubject = new Subject();
1488
+ _scrollBindSub = null;
1489
+ _scroll$ = null;
1490
+ get scrollContainerScrolled() {
1491
+ if (!this._scroll$) {
1492
+ this._scroll$ = this._scrollSubject.asObservable().pipe(shareReplay(1));
1493
+ }
1494
+ return this._scroll$;
1495
+ }
1496
+ blockDefs = signal([
1497
+ {
1498
+ component: () => import('./ngstarter-ui-components-content-editor-divider-block.component-C_iRTCPH.mjs').then(c => c.DividerBlockComponent),
1499
+ type: 'divider',
1500
+ options: {},
1501
+ empty: () => {
1502
+ return {
1503
+ content: null,
1504
+ settings: {}
1505
+ };
1506
+ }
1507
+ },
1508
+ {
1509
+ component: () => import('./ngstarter-ui-components-content-editor-paragraph-block.component-C9bQvDYU.mjs').then(c => c.ParagraphBlockComponent),
1510
+ type: 'paragraph',
1511
+ options: {},
1512
+ empty: () => {
1513
+ return {
1514
+ content: '',
1515
+ props: [],
1516
+ settings: {}
1517
+ };
1518
+ }
1519
+ },
1520
+ {
1521
+ component: () => import('./ngstarter-ui-components-content-editor-code-block.component-Bk6QTli8.mjs').then(c => c.CodeBlockComponent),
1522
+ type: 'code',
1523
+ options: {},
1524
+ empty: () => {
1525
+ return {
1526
+ content: '',
1527
+ settings: {
1528
+ language: 'none',
1529
+ }
1530
+ };
1531
+ }
1532
+ },
1533
+ {
1534
+ component: () => import('./ngstarter-ui-components-content-editor-heading-block.component-D9_CxTY1.mjs').then(c => c.HeadingBlockComponent),
1535
+ type: 'heading',
1536
+ options: {},
1537
+ empty: () => {
1538
+ return {
1539
+ content: '',
1540
+ props: [],
1541
+ settings: {
1542
+ level: 2
1543
+ }
1544
+ };
1545
+ }
1546
+ },
1547
+ {
1548
+ component: () => import('./ngstarter-ui-components-content-editor-image-block.component-B4zJyUg1.mjs').then(c => c.ImageBlockComponent),
1549
+ type: 'image',
1550
+ options: {
1551
+ uploadFn: (file, base64) => {
1552
+ return new Promise((resolve) => {
1553
+ resolve(base64);
1554
+ });
1555
+ }
1556
+ },
1557
+ empty: () => {
1558
+ return {
1559
+ content: {
1560
+ src: '',
1561
+ alt: ''
1562
+ },
1563
+ settings: {
1564
+ alignment: 'center',
1565
+ width: 'auto',
1566
+ height: 'auto',
1567
+ align: 'center',
1568
+ natualWidth: 'auto',
1569
+ naturalHeight: 'auto'
1570
+ }
1571
+ };
1572
+ }
1573
+ },
1574
+ {
1575
+ component: () => import('./ngstarter-ui-components-content-editor-video-block.component-m4DTihP2.mjs').then(c => c.VideoBlockComponent),
1576
+ type: 'video',
1577
+ options: {
1578
+ uploadFn: (file, base64) => {
1579
+ return new Promise((resolve) => {
1580
+ resolve(base64);
1581
+ });
1582
+ }
1583
+ },
1584
+ empty: () => {
1585
+ return {
1586
+ content: {
1587
+ src: '',
1588
+ caption: '',
1589
+ orientation: 'landscape'
1590
+ },
1591
+ settings: {
1592
+ alignment: 'center',
1593
+ width: 'auto',
1594
+ height: 'auto',
1595
+ align: 'center',
1596
+ natualWidth: 'auto',
1597
+ naturalHeight: 'auto'
1598
+ }
1599
+ };
1600
+ }
1601
+ },
1602
+ {
1603
+ component: () => import('./ngstarter-ui-components-content-editor-list-block.component-Cv6wx5Xe.mjs').then(c => c.ListBlockComponent),
1604
+ type: 'bulletList',
1605
+ options: {},
1606
+ empty: () => {
1607
+ return {
1608
+ content: [],
1609
+ settings: {
1610
+ listStyle: 'bullet'
1611
+ }
1612
+ };
1613
+ }
1614
+ },
1615
+ {
1616
+ component: () => import('./ngstarter-ui-components-content-editor-list-block.component-Cv6wx5Xe.mjs').then(c => c.ListBlockComponent),
1617
+ type: 'orderedList',
1618
+ options: {},
1619
+ empty: () => {
1620
+ return {
1621
+ content: [],
1622
+ settings: {
1623
+ listStyle: 'ordered'
1624
+ }
1625
+ };
1626
+ }
1627
+ },
1628
+ {
1629
+ component: () => import('./ngstarter-ui-components-content-editor-table-block.component-DlDh7Fnn.mjs').then(c => c.TableBlockComponent),
1630
+ type: 'table',
1631
+ options: {},
1632
+ empty: () => {
1633
+ return {
1634
+ content: [
1635
+ [
1636
+ {
1637
+ content: '',
1638
+ props: [],
1639
+ styles: {},
1640
+ options: {
1641
+ colspan: 1,
1642
+ rowspan: 1
1643
+ },
1644
+ },
1645
+ {
1646
+ content: '',
1647
+ props: [],
1648
+ styles: {},
1649
+ options: {
1650
+ colspan: 1,
1651
+ rowspan: 1
1652
+ }
1653
+ },
1654
+ {
1655
+ content: '',
1656
+ props: [],
1657
+ styles: {},
1658
+ options: {
1659
+ colspan: 1,
1660
+ rowspan: 1
1661
+ }
1662
+ }
1663
+ ],
1664
+ [
1665
+ {
1666
+ content: '',
1667
+ props: [],
1668
+ styles: {},
1669
+ options: {
1670
+ colspan: 1,
1671
+ rowspan: 1
1672
+ }
1673
+ },
1674
+ {
1675
+ content: '',
1676
+ props: [],
1677
+ options: {
1678
+ colspan: 1,
1679
+ rowspan: 1
1680
+ }
1681
+ },
1682
+ {
1683
+ content: '',
1684
+ props: [],
1685
+ styles: {},
1686
+ options: {
1687
+ colspan: 1,
1688
+ rowspan: 1
1689
+ }
1690
+ }
1691
+ ],
1692
+ ],
1693
+ settings: {}
1694
+ };
1695
+ }
1696
+ },
1697
+ {
1698
+ component: () => import('./ngstarter-ui-components-content-editor-quote-block.component-BbHds2r2.mjs').then(c => c.QuoteBlockComponent),
1699
+ type: 'quote',
1700
+ options: {},
1701
+ empty: () => {
1702
+ return {
1703
+ content: {
1704
+ cite: {
1705
+ content: '',
1706
+ props: []
1707
+ },
1708
+ caption: {
1709
+ content: '',
1710
+ props: []
1711
+ }
1712
+ },
1713
+ settings: {}
1714
+ };
1715
+ }
1716
+ },
1717
+ {
1718
+ component: () => import('./ngstarter-ui-components-content-editor-embed-block-BbkC_t86.mjs').then(c => c.EmbedBlock),
1719
+ type: 'embed',
1720
+ options: {},
1721
+ empty: () => {
1722
+ return {
1723
+ content: {
1724
+ url: '',
1725
+ type: ''
1726
+ },
1727
+ settings: {}
1728
+ };
1729
+ }
1730
+ },
1731
+ ], ...(ngDevMode ? [{ debugName: "blockDefs" }] : /* istanbul ignore next */ []));
1732
+ content = input([], ...(ngDevMode ? [{ debugName: "content" }] : /* istanbul ignore next */ []));
1733
+ contentChangedDelay = input(500, { ...(ngDevMode ? { debugName: "contentChangedDelay" } : /* istanbul ignore next */ {}), transform: numberAttribute });
1734
+ suggestions = input([
1735
+ {
1736
+ type: 'heading',
1737
+ title: 'Headings',
1738
+ },
1739
+ {
1740
+ type: 'item',
1741
+ title: 'Heading 1',
1742
+ description: 'Top-level heading',
1743
+ iconName: 'fluent:text-header-1-24-regular',
1744
+ hotKeys: 'ALT + 1',
1745
+ blockType: 'heading',
1746
+ blockSettings: {
1747
+ level: 1
1748
+ }
1749
+ },
1750
+ {
1751
+ type: 'item',
1752
+ title: 'Heading 2',
1753
+ description: 'Key section heading',
1754
+ iconName: 'fluent:text-header-2-24-regular',
1755
+ hotKeys: 'ALT + 2',
1756
+ blockType: 'heading',
1757
+ blockSettings: {
1758
+ level: 2
1759
+ }
1760
+ },
1761
+ {
1762
+ type: 'item',
1763
+ title: 'Heading 3',
1764
+ description: 'Subsection and group heading',
1765
+ iconName: 'fluent:text-header-3-24-regular',
1766
+ hotKeys: 'ALT + 3',
1767
+ blockType: 'heading',
1768
+ blockSettings: {
1769
+ level: 3
1770
+ }
1771
+ },
1772
+ {
1773
+ type: 'heading',
1774
+ title: 'Basic blocks',
1775
+ },
1776
+ {
1777
+ type: 'item',
1778
+ title: 'Paragraph',
1779
+ description: 'The body of your document',
1780
+ iconName: 'fluent:text-paragraph-24-regular',
1781
+ hotKeys: 'ALT + 0',
1782
+ blockType: 'paragraph',
1783
+ blockSettings: {}
1784
+ },
1785
+ {
1786
+ type: 'item',
1787
+ title: 'Numbered List',
1788
+ description: 'List with ordered items',
1789
+ iconName: 'fluent:text-bullet-list-tree-24-regular',
1790
+ hotKeys: 'ALT + 0',
1791
+ blockType: 'orderedList',
1792
+ blockSettings: {}
1793
+ },
1794
+ {
1795
+ type: 'item',
1796
+ title: 'Bullet List',
1797
+ description: 'List with unordered items',
1798
+ iconName: 'fluent:text-bullet-list-ltr-24-regular',
1799
+ hotKeys: 'ALT + 0',
1800
+ blockType: 'bulletList',
1801
+ blockSettings: {}
1802
+ },
1803
+ {
1804
+ type: 'item',
1805
+ title: 'Quote',
1806
+ description: 'Quote or excerpt',
1807
+ iconName: 'fluent:text-quote-24-regular',
1808
+ hotKeys: 'ALT + 0',
1809
+ blockType: 'quote',
1810
+ blockSettings: {}
1811
+ },
1812
+ {
1813
+ type: 'item',
1814
+ title: 'Code',
1815
+ description: 'The code block with syntax highlighting',
1816
+ iconName: 'fluent:code-24-regular',
1817
+ hotKeys: 'ALT + 0',
1818
+ blockType: 'code',
1819
+ blockSettings: {}
1820
+ },
1821
+ {
1822
+ type: 'item',
1823
+ title: 'Divider',
1824
+ description: 'Visually divide blocks',
1825
+ iconName: 'fluent:minimize-24-regular',
1826
+ hotKeys: 'ALT + 0',
1827
+ blockType: 'divider',
1828
+ blockSettings: {}
1829
+ },
1830
+ {
1831
+ type: 'item',
1832
+ title: 'Table',
1833
+ description: 'Table with editable cells',
1834
+ iconName: 'fluent:table-24-regular',
1835
+ hotKeys: 'ALT + 0',
1836
+ blockType: 'table',
1837
+ blockSettings: {}
1838
+ },
1839
+ {
1840
+ type: 'heading',
1841
+ title: 'Media',
1842
+ },
1843
+ {
1844
+ type: 'item',
1845
+ title: 'Image',
1846
+ description: 'Image with caption',
1847
+ iconName: 'fluent:image-24-regular',
1848
+ hotKeys: 'ALT + 0',
1849
+ blockType: 'image',
1850
+ blockSettings: {}
1851
+ },
1852
+ {
1853
+ type: 'item',
1854
+ title: 'Video',
1855
+ description: 'Video with caption',
1856
+ iconName: 'fluent:video-24-regular',
1857
+ hotKeys: 'ALT + 0',
1858
+ blockType: 'video',
1859
+ blockSettings: {}
1860
+ },
1861
+ {
1862
+ type: 'heading',
1863
+ title: 'Embeds',
1864
+ },
1865
+ {
1866
+ type: 'item',
1867
+ title: 'Embed',
1868
+ description: 'For PDFs, Google Maps and more',
1869
+ iconName: 'fluent:window-24-regular',
1870
+ hotKeys: 'ALT + 0',
1871
+ blockType: 'embed',
1872
+ blockSettings: {
1873
+ width: null,
1874
+ height: null
1875
+ }
1876
+ },
1877
+ ], ...(ngDevMode ? [{ debugName: "suggestions" }] : /* istanbul ignore next */ []));
1878
+ options = input({}, ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
1879
+ scrollContainer = input(...(ngDevMode ? [undefined, { debugName: "scrollContainer" }] : /* istanbul ignore next */ []));
1880
+ contentChanged = output();
1881
+ focusChanged = new EventEmitter();
1882
+ _content = signal([], ...(ngDevMode ? [{ debugName: "_content" }] : /* istanbul ignore next */ []));
1883
+ blockDefsMap = new Map();
1884
+ blockDefsOptionsMap = new Map();
1885
+ _blockDragging = signal(false, ...(ngDevMode ? [{ debugName: "_blockDragging" }] : /* istanbul ignore next */ []));
1886
+ isSelectionOfBlocksActive = signal(false, ...(ngDevMode ? [{ debugName: "isSelectionOfBlocksActive" }] : /* istanbul ignore next */ []));
1887
+ _oldContent = signal({}, ...(ngDevMode ? [{ debugName: "_oldContent" }] : /* istanbul ignore next */ []));
1888
+ selectedBlocksModel = new SelectionModel(true);
1889
+ commandBar = CommandBarComponent;
1890
+ get api() {
1891
+ return {
1892
+ focusChanged: new EventEmitter(),
1893
+ };
1894
+ }
1895
+ // Build helper maps: component map and merged options map
1896
+ buildBlockDefMaps() {
1897
+ const overrides = this.options() || {};
1898
+ this.blockDefsMap = new Map();
1899
+ this.blockDefsOptionsMap = new Map();
1900
+ this.blockDefs().forEach((def) => {
1901
+ if (!this.blockDefsMap.has(def.type)) {
1902
+ this.blockDefsMap.set(def.type, def.component());
1903
+ }
1904
+ const merged = {
1905
+ ...(def.options || {}),
1906
+ ...(overrides[def.type] || {})
1907
+ };
1908
+ this.blockDefsOptionsMap.set(def.type, merged);
1909
+ });
1910
+ }
1911
+ getBlockDefOption(type, key) {
1912
+ return this.blockDefsOptionsMap.get(type)[key];
1913
+ }
1914
+ ngOnInit() {
1915
+ const content = this.content();
1916
+ if (content.length > 0) {
1917
+ const lastItem = content[content.length - 1];
1918
+ if (lastItem.type !== 'paragraph' || (lastItem.type === 'paragraph' && lastItem.content !== '')) {
1919
+ content.push(this._createBlock('paragraph'));
1920
+ }
1921
+ }
1922
+ else {
1923
+ content.push(this._createBlock('paragraph'));
1924
+ }
1925
+ this._content.set(content);
1926
+ this._oldContent.set(this._content());
1927
+ // Build block component map and merged options map
1928
+ this.buildBlockDefMaps();
1929
+ this._store.setBlocks(JSON.parse(JSON.stringify(content)));
1930
+ if (isPlatformServer(this._platformId)) {
1931
+ return;
1932
+ }
1933
+ if (content.length === 1) {
1934
+ this.focusBlock(content[0].id);
1935
+ }
1936
+ }
1937
+ ngAfterViewInit() {
1938
+ if (isPlatformServer(this._platformId)) {
1939
+ return;
1940
+ }
1941
+ // Initial resolve after view init
1942
+ this._resolvedScrollContainer = this._computeScrollContainer();
1943
+ // Привязываем подписку на скролл к текущему контейнеру
1944
+ this._rebindScrollListener();
1945
+ // Watch for changes of the input selector and recompute when it changes.
1946
+ // Create the signal effect within a valid injection context to satisfy Angular's requirement.
1947
+ runInInjectionContext(this.envInjector, () => {
1948
+ this._scrollEffect = effect(() => {
1949
+ const _selector = this.scrollContainer();
1950
+ this._resolvedScrollContainer = this._computeScrollContainer();
1951
+ // Перепривязка слушателя при смене контейнера
1952
+ this._rebindScrollListener();
1953
+ }, ...(ngDevMode ? [{ debugName: "_scrollEffect" }] : /* istanbul ignore next */ []));
1954
+ });
1955
+ }
1956
+ /**
1957
+ * Public accessor for the resolved scroll container. If not computed yet, it will compute now.
1958
+ */
1959
+ getScrollContainer() {
1960
+ if (isPlatformServer(this._platformId)) {
1961
+ return {};
1962
+ }
1963
+ if (!this._resolvedScrollContainer) {
1964
+ this._resolvedScrollContainer = this._computeScrollContainer();
1965
+ }
1966
+ return this._resolvedScrollContainer || window;
1967
+ }
1968
+ /**
1969
+ * Resolves the scroll container element according to the following rules:
1970
+ * - If `scrollContainer` input is provided, uses `closest(selector)` starting from the host element.
1971
+ * - If not provided or `closest` returned null, automatically finds the first scrollable parent by walking up the DOM.
1972
+ * - Fallback to `document.scrollingElement` or `window` if nothing suitable found.
1973
+ */
1974
+ _computeScrollContainer() {
1975
+ if (isPlatformServer(this._platformId)) {
1976
+ return null;
1977
+ }
1978
+ const host = this.elRef?.nativeElement;
1979
+ if (!host) {
1980
+ return (document.scrollingElement || window);
1981
+ }
1982
+ const selector = this.scrollContainer();
1983
+ if (selector && typeof selector === 'string') {
1984
+ try {
1985
+ const matched = host.closest(selector);
1986
+ if (matched) {
1987
+ return matched;
1988
+ }
1989
+ }
1990
+ catch (_) {
1991
+ // If selector is invalid, ignore and fallback to auto detection
1992
+ }
1993
+ }
1994
+ // Auto-detect by traversing parents
1995
+ let parent = host.parentElement;
1996
+ while (parent) {
1997
+ if (this._isElementScrollable(parent)) {
1998
+ return parent;
1999
+ }
2000
+ parent = parent.parentElement;
2001
+ }
2002
+ return (document.scrollingElement || window);
2003
+ }
2004
+ _isElementScrollable(el) {
2005
+ const style = getComputedStyle(el);
2006
+ const overflowY = style.overflowY;
2007
+ const overflowX = style.overflowX;
2008
+ const canScrollY = (overflowY === 'auto' || overflowY === 'scroll' || overflowY === 'overlay') && el.scrollHeight > el.clientHeight;
2009
+ const canScrollX = (overflowX === 'auto' || overflowX === 'scroll' || overflowX === 'overlay') && el.scrollWidth > el.clientWidth;
2010
+ return canScrollY || canScrollX;
2011
+ }
2012
+ _rebindScrollListener() {
2013
+ if (isPlatformServer(this._platformId)) {
2014
+ return;
2015
+ }
2016
+ // Отписываемся от предыдущего контейнера, если был
2017
+ if (this._scrollBindSub) {
2018
+ try {
2019
+ this._scrollBindSub.unsubscribe();
2020
+ }
2021
+ catch {
2022
+ }
2023
+ this._scrollBindSub = null;
2024
+ }
2025
+ const container = this._resolvedScrollContainer ?? this._computeScrollContainer();
2026
+ if (!container) {
2027
+ return;
2028
+ }
2029
+ // Формируем источник скролла
2030
+ const getTop = () => {
2031
+ if (container instanceof Window) {
2032
+ return container.scrollY || container.pageYOffset || 0;
2033
+ }
2034
+ return container.scrollTop || 0;
2035
+ };
2036
+ const source$ = fromEvent(container, 'scroll').pipe(auditTime(50), map(() => getTop()), startWith(getTop()), distinctUntilChanged());
2037
+ // Подписка: проксируем значения в общий Subject
2038
+ this._scrollBindSub = source$.subscribe(top => {
2039
+ this._scrollSubject.next(top);
2040
+ });
2041
+ }
2042
+ // удалён дубликат ngOnDestroy — см. реализацию в конце класса
2043
+ appendBlock(type, focus = true) {
2044
+ this.insertBlock(type, this._content().length, {}, focus);
2045
+ }
2046
+ insertBlock(type, index, options, focus = true, content) {
2047
+ const isLastIndex = index === this._content().length;
2048
+ const newBlock = this._createBlock(type, options, content);
2049
+ if (focus) {
2050
+ this.focusBlock(newBlock.id);
2051
+ }
2052
+ this._content.update((data) => {
2053
+ return [...data.slice(0, index), newBlock, ...data.slice(index)];
2054
+ });
2055
+ this._store.addBlock(newBlock, index);
2056
+ if (isLastIndex && this._content()[index].type !== 'paragraph') {
2057
+ this.appendBlock('paragraph', false);
2058
+ }
2059
+ this.emitContentChangeEvent();
2060
+ return newBlock;
2061
+ }
2062
+ _createBlock(type, settings = {}, content) {
2063
+ const blockDef = this.blockDefs().find(blockDefItem => blockDefItem.type === type);
2064
+ const empty = blockDef.empty();
2065
+ if (settings) {
2066
+ empty.settings = {
2067
+ ...empty.settings,
2068
+ ...settings
2069
+ };
2070
+ }
2071
+ if (content !== undefined) {
2072
+ empty.content = content;
2073
+ }
2074
+ return {
2075
+ id: v7(),
2076
+ type: blockDef.type,
2077
+ isEmpty: content === undefined || content === '' || (Array.isArray(content) && content.length === 0),
2078
+ ...empty
2079
+ };
2080
+ }
2081
+ addBlock(type, options, index = -1) {
2082
+ if (index === -1) {
2083
+ if (this._store.activeBlockId()) {
2084
+ index = this._content().findIndex(dataBlock => dataBlock.id === this._store.activeBlockId()) + 1;
2085
+ }
2086
+ else {
2087
+ index = this._content().length;
2088
+ }
2089
+ }
2090
+ this.insertBlock(type, index, options);
2091
+ }
2092
+ duplicateBlock(blockId) {
2093
+ const index = this._content().findIndex(dataBlock => dataBlock.id === blockId);
2094
+ if (index === -1) {
2095
+ return;
2096
+ }
2097
+ const original = this._content()[index];
2098
+ // Deep clone mutable fields to avoid shared references
2099
+ const clonedContent = original.content != null ? JSON.parse(JSON.stringify(original.content)) : original.content;
2100
+ const clonedSettings = original.settings != null ? JSON.parse(JSON.stringify(original.settings)) : original.settings;
2101
+ const clonedProps = original.props != null ? JSON.parse(JSON.stringify(original.props)) : original.props;
2102
+ const duplicated = {
2103
+ ...original,
2104
+ id: v7(),
2105
+ isEmpty: false,
2106
+ content: clonedContent,
2107
+ settings: clonedSettings,
2108
+ props: clonedProps,
2109
+ };
2110
+ const insertIndex = index + 1;
2111
+ this._content.update((data) => {
2112
+ data.splice(insertIndex, 0, duplicated);
2113
+ return data;
2114
+ });
2115
+ this._store.addBlock(duplicated, insertIndex);
2116
+ this.focusBlock(duplicated.id);
2117
+ this.emitContentChangeEvent();
2118
+ }
2119
+ duplicateSelectedBlocks(popover) {
2120
+ const selectedIds = [...this.selectedBlocksModel.selected];
2121
+ if (!selectedIds.length)
2122
+ return;
2123
+ // Process in visual order (top to bottom)
2124
+ const ordered = selectedIds
2125
+ .map(id => ({ id, index: this._content().findIndex(b => b.id === id) }))
2126
+ .filter(x => x.index !== -1)
2127
+ .sort((a, b) => a.index - b.index)
2128
+ .map(x => x.id);
2129
+ const newIds = [];
2130
+ for (const id of ordered) {
2131
+ // Get current index of the original before duplicating
2132
+ const idx = this._content().findIndex(b => b.id === id);
2133
+ if (idx === -1)
2134
+ continue;
2135
+ this.duplicateBlock(id);
2136
+ // After duplication, the new block is placed right after the original
2137
+ const newBlock = this._content()[idx + 1];
2138
+ if (newBlock) {
2139
+ newIds.push(newBlock.id);
2140
+ }
2141
+ }
2142
+ // Select duplicated blocks
2143
+ this.selectedBlocksModel.clear();
2144
+ if (newIds.length) {
2145
+ this.selectedBlocksModel.select(...newIds);
2146
+ }
2147
+ this.cdr.markForCheck();
2148
+ }
2149
+ deleteBlock(blockId) {
2150
+ if (this._content().length === 1) {
2151
+ return;
2152
+ }
2153
+ const index = this._content().findIndex(dataBlock => dataBlock.id === blockId);
2154
+ if (index !== -1) {
2155
+ this._content.update(data => {
2156
+ data.splice(index, 1);
2157
+ return data;
2158
+ });
2159
+ this._store.deleteBlock(blockId, index);
2160
+ const prevBlock = this._content()[index - 1];
2161
+ if (prevBlock) {
2162
+ this.focusBlock(prevBlock.id);
2163
+ }
2164
+ this.emitContentChangeEvent();
2165
+ }
2166
+ }
2167
+ setBlockProps(id, props) {
2168
+ const data = this._content();
2169
+ const index = data.findIndex((dataBlock) => dataBlock.id === id);
2170
+ data[index].props = props;
2171
+ this.emitContentChangeEvent();
2172
+ }
2173
+ insertEmptyBlock(index) {
2174
+ this.insertBlock('paragraph', index + 1);
2175
+ this.emitContentChangeEvent();
2176
+ }
2177
+ focusBlock(id) {
2178
+ this._store.setFocusedBlockId(id);
2179
+ this.focusChanged.emit();
2180
+ }
2181
+ isBlockFocused(id) {
2182
+ return this._store.focusedBlockId() === id;
2183
+ }
2184
+ isActiveBlock(id) {
2185
+ return this._store.activeBlockId() === id;
2186
+ }
2187
+ drop(event) {
2188
+ moveItemInArray(this._content(), event.previousIndex, event.currentIndex);
2189
+ this._store.moveBlock(event.previousIndex, event.currentIndex);
2190
+ this.emitContentChangeEvent();
2191
+ }
2192
+ onTagSelected(tagName) {
2193
+ // console.log('Tag selected event received:', tagName);
2194
+ }
2195
+ getData() {
2196
+ return this._store.blocks();
2197
+ }
2198
+ emitContentChangeEvent() {
2199
+ this.contentChanged.emit(this.getData());
2200
+ }
2201
+ selectBlock(blockId, multiple = false) {
2202
+ if (!multiple) {
2203
+ this.selectedBlocksModel.clear();
2204
+ }
2205
+ this.selectedBlocksModel.select(blockId);
2206
+ this.cdr.markForCheck();
2207
+ }
2208
+ unselectBlock(blockId) {
2209
+ this.selectedBlocksModel.deselect(blockId);
2210
+ this.cdr.markForCheck();
2211
+ }
2212
+ unselectSelectedBlocks() {
2213
+ this.selectedBlocksModel.clear();
2214
+ this.cdr.markForCheck();
2215
+ }
2216
+ isBlockSelected(blockId) {
2217
+ return this.selectedBlocksModel.isSelected(blockId);
2218
+ }
2219
+ deleteSelectedBlocks(popover) {
2220
+ const selectedIds = [...this.selectedBlocksModel.selected];
2221
+ if (!selectedIds.length) {
2222
+ return;
2223
+ }
2224
+ const confirmRef = this.confirmManager.open({
2225
+ title: 'Delete blocks',
2226
+ description: 'This action cannot be undone. Selected blocks will be deleted.'
2227
+ });
2228
+ confirmRef.confirmed.subscribe(() => {
2229
+ // Delete from bottom to top to keep indexes stable
2230
+ const toDelete = selectedIds
2231
+ .map(id => ({ id, index: this._content().findIndex(b => b.id === id) }))
2232
+ .filter(x => x.index !== -1)
2233
+ .sort((a, b) => b.index - a.index);
2234
+ for (const item of toDelete) {
2235
+ this.deleteBlock(item.id);
2236
+ }
2237
+ this.unselectSelectedBlocks();
2238
+ });
2239
+ }
2240
+ _onKeyDown(event) {
2241
+ if ((event.key === 'Delete' || event.key === 'Backspace') && this.selectedBlocksModel.hasValue()) {
2242
+ const target = event.target;
2243
+ const isInput = target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable;
2244
+ // If we are in an input/contenteditable, only delete if multiple blocks are selected
2245
+ // or if it's not a Backspace (to avoid deleting text while trying to delete blocks)
2246
+ // Actually, if blocks are selected, they usually have a blue background and the user intent is likely to delete blocks.
2247
+ // But if there's only ONE block selected AND we are typing in it, we probably want to delete text.
2248
+ if (isInput && this.selectedBlocksModel.selected.length === 1) {
2249
+ // Let the default behavior happen for text editing
2250
+ return;
2251
+ }
2252
+ event.preventDefault();
2253
+ this.deleteSelectedBlocks();
2254
+ }
2255
+ }
2256
+ onDragStarted(event, block) {
2257
+ this._blockDragging.set(true);
2258
+ }
2259
+ onDragEnded(event, block) {
2260
+ this._blockDragging.set(false);
2261
+ }
2262
+ addBlockFromSuggestionMenu(suggestionsMenu, type, options) {
2263
+ suggestionsMenu.closed.emit('click');
2264
+ this.addBlock(type, options);
2265
+ }
2266
+ preventMenuClose(event) {
2267
+ event.stopPropagation();
2268
+ event.preventDefault();
2269
+ }
2270
+ setActiveBlockId(event, id) {
2271
+ event.stopPropagation();
2272
+ event.preventDefault();
2273
+ this._store.setActiveBlockId(id);
2274
+ this._store.setFocusedBlockId(id);
2275
+ this.focusChanged.emit();
2276
+ }
2277
+ onFocusChange(origin, dataBlock) {
2278
+ }
2279
+ onSuggestionsMenuOpen() {
2280
+ }
2281
+ onSuggestionsMenuClose(reason) {
2282
+ if (!reason) {
2283
+ this._store.setFocusedBlockId(this._store.activeBlockId());
2284
+ this.focusChanged.emit();
2285
+ }
2286
+ // need some delay to prevent the flickering
2287
+ setTimeout(() => this._store.setActiveBlockId(null), 250);
2288
+ }
2289
+ ngOnDestroy() {
2290
+ if (isPlatformServer(this._platformId)) {
2291
+ return;
2292
+ }
2293
+ if (this._scrollBindSub) {
2294
+ try {
2295
+ this._scrollBindSub.unsubscribe();
2296
+ }
2297
+ catch {
2298
+ }
2299
+ this._scrollBindSub = null;
2300
+ }
2301
+ if (this._scrollEffect) {
2302
+ try {
2303
+ this._scrollEffect.destroy();
2304
+ }
2305
+ catch {
2306
+ }
2307
+ this._scrollEffect = undefined;
2308
+ }
2309
+ try {
2310
+ this._scrollSubject.complete();
2311
+ }
2312
+ catch {
2313
+ }
2314
+ this._scroll$ = null;
2315
+ }
2316
+ onSettingsPopoverClose() {
2317
+ }
2318
+ _onPaste(event) {
2319
+ const target = event.target;
2320
+ const isInsideCodeBlock = target.closest('.ngs-code-block') ||
2321
+ target.closest('.cm-editor') ||
2322
+ target.closest('.cm-content') ||
2323
+ target.classList.contains('cm-content') ||
2324
+ target.classList.contains('cm-line');
2325
+ if (isInsideCodeBlock) {
2326
+ return;
2327
+ }
2328
+ const html = event.clipboardData?.getData('text/html');
2329
+ const text = event.clipboardData?.getData('text/plain');
2330
+ if (!html && !text) {
2331
+ return;
2332
+ }
2333
+ // Check if we are pasting into a block that should handle its own paste (like code block)
2334
+ // but might not have been caught by target.closest if it's currently empty or has different structure.
2335
+ const activeBlockId = this._store.activeBlockId() || this._store.focusedBlockId();
2336
+ if (activeBlockId) {
2337
+ const activeBlock = this._content().find(b => b.id === activeBlockId);
2338
+ if (activeBlock?.type === 'code') {
2339
+ return;
2340
+ }
2341
+ }
2342
+ event.preventDefault();
2343
+ event.stopPropagation();
2344
+ let index = this._content().length;
2345
+ if (activeBlockId) {
2346
+ const activeIndex = this._content().findIndex(b => b.id === activeBlockId);
2347
+ if (activeIndex !== -1) {
2348
+ index = activeIndex + 1;
2349
+ }
2350
+ }
2351
+ if (html) {
2352
+ this._handleHtmlPaste(html, index);
2353
+ }
2354
+ else if (text) {
2355
+ this._handleTextPaste(text, index);
2356
+ }
2357
+ }
2358
+ _handleTextPaste(text, index) {
2359
+ const lines = text.split(/\r?\n/);
2360
+ if (lines.length === 1) {
2361
+ this.insertBlock('paragraph', index, {}, false, text);
2362
+ }
2363
+ else {
2364
+ // If it looks like code (has indentation or common code characters), insert as a single code block
2365
+ const isCodeLike = text.includes('{') || text.includes('}') || text.includes(';') || text.includes(' ') || text.includes('\t');
2366
+ if (isCodeLike) {
2367
+ this.insertBlock('code', index, { language: 'none' }, false, text);
2368
+ return;
2369
+ }
2370
+ lines.forEach((line, i) => {
2371
+ if (line.trim().length > 0) {
2372
+ this.insertBlock('paragraph', index + i, {}, false, line);
2373
+ }
2374
+ });
2375
+ }
2376
+ }
2377
+ _handleHtmlPaste(html, index) {
2378
+ const parser = new DOMParser();
2379
+ const doc = parser.parseFromString(html, 'text/html');
2380
+ const body = doc.body;
2381
+ let currentIndex = index;
2382
+ Array.from(body.children).forEach(node => {
2383
+ const block = this._mapNodeToBlock(node);
2384
+ if (block) {
2385
+ this.insertBlock(block.type, currentIndex, block.settings, false, block.content);
2386
+ currentIndex++;
2387
+ }
2388
+ });
2389
+ }
2390
+ _mapNodeToBlock(node) {
2391
+ const tag = node.tagName.toLowerCase();
2392
+ switch (tag) {
2393
+ case 'h1':
2394
+ case 'h2':
2395
+ case 'h3':
2396
+ case 'h4':
2397
+ case 'h5':
2398
+ case 'h6':
2399
+ return {
2400
+ type: 'heading',
2401
+ settings: { level: parseInt(tag.substring(1)) },
2402
+ content: node.innerHTML
2403
+ };
2404
+ case 'p':
2405
+ return {
2406
+ type: 'paragraph',
2407
+ settings: {},
2408
+ content: node.innerHTML
2409
+ };
2410
+ case 'ul':
2411
+ return {
2412
+ type: 'bulletList',
2413
+ settings: { listStyle: 'bullet' },
2414
+ content: this._mapListItems(node)
2415
+ };
2416
+ case 'ol':
2417
+ return {
2418
+ type: 'orderedList',
2419
+ settings: { listStyle: 'ordered' },
2420
+ content: this._mapListItems(node)
2421
+ };
2422
+ case 'img':
2423
+ return {
2424
+ type: 'image',
2425
+ settings: {},
2426
+ content: {
2427
+ src: node.getAttribute('src') || '',
2428
+ alt: node.getAttribute('alt') || ''
2429
+ }
2430
+ };
2431
+ case 'video':
2432
+ return {
2433
+ type: 'video',
2434
+ settings: {},
2435
+ content: {
2436
+ src: node.getAttribute('src') || '',
2437
+ caption: node.getAttribute('title') || ''
2438
+ }
2439
+ };
2440
+ case 'blockquote':
2441
+ return {
2442
+ type: 'quote',
2443
+ settings: {},
2444
+ content: node.innerHTML
2445
+ };
2446
+ case 'pre':
2447
+ const codeNode = node.querySelector('code');
2448
+ const content = (codeNode || node).textContent || '';
2449
+ return {
2450
+ type: 'code',
2451
+ settings: { language: 'none' },
2452
+ content: content.replace(/\r\n/g, '\n').replace(/\r/g, '\n').trimEnd()
2453
+ };
2454
+ case 'hr':
2455
+ return {
2456
+ type: 'divider',
2457
+ settings: {}
2458
+ };
2459
+ default:
2460
+ if (node.textContent?.trim()) {
2461
+ return {
2462
+ type: 'paragraph',
2463
+ settings: {},
2464
+ content: node.innerHTML
2465
+ };
2466
+ }
2467
+ return null;
2468
+ }
2469
+ }
2470
+ _mapListItems(node) {
2471
+ return Array.from(node.children)
2472
+ .filter(child => child.tagName.toLowerCase() === 'li')
2473
+ .map(li => ({
2474
+ content: li.innerHTML,
2475
+ children: []
2476
+ }));
2477
+ }
2478
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ContentBuilderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2479
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: ContentBuilderComponent, isStandalone: true, selector: "ngs-content-builder", inputs: { content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, contentChangedDelay: { classPropertyName: "contentChangedDelay", publicName: "contentChangedDelay", isSignal: true, isRequired: false, transformFunction: null }, suggestions: { classPropertyName: "suggestions", publicName: "suggestions", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, scrollContainer: { classPropertyName: "scrollContainer", publicName: "scrollContainer", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { contentChanged: "contentChanged" }, host: { attributes: { "tabindex": "0" }, listeners: { "paste": "_onPaste($event)", "keydown": "_onKeyDown($event)" }, properties: { "class.is-block-dragging": "_blockDragging()", "class.is-selection-of-blocks-active": "isSelectionOfBlocksActive()", "class.select-none": "isSelectionOfBlocksActive()", "style.user-select": "isSelectionOfBlocksActive() ? \"none\" : null" }, classAttribute: "ngs-content-builder" }, providers: [
2480
+ ContentBuilderStore,
2481
+ {
2482
+ provide: CONTENT_BUILDER,
2483
+ useExisting: forwardRef(() => ContentBuilderComponent)
2484
+ }
2485
+ ], exportAs: ["ngsContentBuilder"], hostDirectives: [{ directive: BlockSelectionDirective, inputs: ["autoScrollContainerSelector", "autoScrollContainerSelector"] }], ngImport: i0, template: "<div class=\"container py-4\">\n <div class=\"content\"\n cdkDropList\n ngsTextSelectionPopup\n closestContentObserverClass=\"ngs-content-editor-content-editable\"\n [targetComponent]=\"commandBar\"\n (tagSelected)=\"onTagSelected($event)\"\n (cdkDropListDropped)=\"drop($event)\">\n @for (contentBlock of _content(); track contentBlock.id) {\n <div class=\"block\"\n [attr.data-block-id]=\"contentBlock.id\"\n [class.is-focused]=\"isBlockFocused(contentBlock.id)\"\n [class.is-active]=\"isActiveBlock(contentBlock.id)\"\n cdkDrag\n cdkDragLockAxis=\"y\"\n cdkMonitorSubtreeFocus\n (cdkDragStarted)=\"onDragStarted($event, contentBlock)\"\n (cdkDragEnded)=\"onDragEnded($event, contentBlock)\"\n (cdkFocusChange)=\"onFocusChange($event, contentBlock)\">\n <div class=\"block-controls\" [class.is-settings-popover-open]=\"settingsTrigger.api.isOpen()\">\n <button class=\"block-control\">\n <ngs-icon name=\"fluent:add-24-regular\"\n (mousedown)=\"setActiveBlockId($event, contentBlock.id)\"\n [ngsMenuTriggerFor]=\"suggestionsMenu\"\n [ngsMenuTriggerRestoreFocus]=\"false\"\n (menuOpened)=\"onSuggestionsMenuOpen()\"\n (menuClosed)=\"onSuggestionsMenuClose($event)\"/>\n </button>\n <div class=\"block-control block-control-drag\"\n (click)=\"selectBlock(contentBlock.id)\"\n [ngsPopoverTriggerFor]=\"settingsPopover\"\n (closed)=\"onSettingsPopoverClose()\"\n #settingsTrigger=\"ngsPopoverTriggerFor\"\n hasBackdrop\n position=\"before-center\">\n <button cdkDragHandle\n trigger=\"hover\"\n closeOnOriginClick\n closeOnOriginMouseLeave\n #dragTrigger=\"ngsPopoverTriggerFor\"\n [ngsPopoverTriggerFor]=\"dragControlTooltip\"\n position=\"below-center\"\n (mousedown)=\"dragTrigger.api.close()\"\n delay=\"1000\" class=\"w-full h-full flex items-center justify-center\">\n <ngs-icon name=\"fluent:re-order-dots-vertical-24-regular\"/>\n </button>\n </div>\n <ng-template #dragControlTooltip>\n <div class=\"bg-neutral-900 text-xs flex flex-col gap-0.5 rounded-lg items-center px-2 py-1.5 font-medium\">\n <div>\n <div class=\"text-neutral-100\">Drag <span class=\"text-neutral-400\">to move</span></div>\n </div>\n <div>\n <div class=\"text-neutral-100\">Click <span class=\"text-neutral-400\">to open menu</span></div>\n </div>\n </div>\n </ng-template>\n </div>\n <div class=\"block-content\" [class.is-selected]=\"isBlockSelected(contentBlock.id)\">\n <div class=\"drag-placeholder\" *cdkDragPlaceholder></div>\n <ng-container [ngComponentOutlet]=\"blockDefsMap.get(contentBlock.type) | async\"\n [ngComponentOutletInputs]=\"{\n id: contentBlock.id,\n content: contentBlock.content,\n settings: contentBlock.settings,\n index: $index\n }\"/>\n </div>\n </div>\n }\n </div>\n</div>\n\n<ngs-popover #settingsPopover=\"ngsPopover\">\n <div class=\"px-2 py-0 w-72 settings-popover\">\n <ngs-list>\n <ngs-list-item (click)=\"duplicateSelectedBlocks(settingsPopover)\">\n <ngs-icon name=\"fluent:copy-24-regular\" ngsListItemIcon/>\n <div ngsListItemTitle>Duplicate</div>\n </ngs-list-item>\n <ngs-list-item (click)=\"deleteSelectedBlocks(settingsPopover)\">\n <ngs-icon name=\"fluent:delete-24-regular\" ngsListItemIcon/>\n <div ngsListItemTitle>Delete</div>\n </ngs-list-item>\n </ngs-list>\n </div>\n</ngs-popover>\n\n<ngs-menu #suggestionsMenu=\"ngsMenu\">\n <div (click)=\"preventMenuClose($event)\">\n @for (suggestionItem of suggestions(); track $index; let first = $first) {\n @switch (suggestionItem.type) {\n @case ('heading') {\n <ngs-menu-heading>{{ suggestionItem.title }}</ngs-menu-heading>\n }\n @case ('item') {\n <button ngs-menu-item (click)=\"addBlockFromSuggestionMenu(suggestionsMenu, suggestionItem.blockType, suggestionItem.blockOptions)\">\n <div class=\"h-full flex items-center gap-3 py-2\">\n <div class=\"size-9 flex items-center rounded-lg justify-center bg-surface-container\">\n <ngs-icon [name]=\"suggestionItem.iconName\" class=\"!me-0\"/>\n </div>\n <div class=\"grow min-w-[200px]\">\n <div>{{ suggestionItem.title }}</div>\n <div class=\"text-2xs text-neutral-500\">{{ suggestionItem.description }}</div>\n </div>\n @if (suggestionItem.hotKeys) {\n <div class=\"ms-auto bg-surface-container-highest rounded-full h-5\n text-4xs px-2 flex items-center font-bold\">{{ suggestionItem.hotKeys }}</div>\n }\n </div>\n </button>\n }\n }\n }\n </div>\n</ngs-menu>\n", styles: [":host{--ngs-content-builder-content-width: 704px;outline:none}:host ::ng-deep .link-selection,:host ::ng-deep .text-selection{display:inline-block;background:var(--color-secondary-fixed)}:host.is-block-dragging{cursor:grabbing}:host .container{display:flex;width:820px;min-height:200px;height:100%;padding:calc(var(--spacing, .25rem) * 5) calc(var(--spacing, .25rem) * 5) calc(var(--spacing, .25rem) * 5) 0;margin:0 auto;outline:none}:host .content{flex-grow:1;width:calc(var(--ngs-content-builder-content-width) + calc(var(--spacing, .25rem) * 10))}:host .block{position:relative;flex:none;padding:calc(var(--spacing, .25rem) * 1) 0;display:flex;align-items:center}:host .block:not(:has(.block-content.is-selected)):hover .block-content{background:var(--color-neutral-50)}:host:not(.is-block-dragging) .block:hover .block-controls,:host:not(.is-block-dragging) .block.is-active .block-controls{opacity:1}:host .block-content{position:relative;flex-grow:1;padding:calc(var(--spacing, .25rem) * 3)}:host .block-content.is-selected{background:var(--color-primary-100)}:host ::ng-deep .selection-area{background:var(--color-primary-100);opacity:.4;border:1px solid var(--color-primary);border-radius:.25rem}:host ::ng-deep .ngs-content-editor-content-editable{-webkit-user-select:text;user-select:text}:host.select-none ::ng-deep .ngs-content-editor-content-editable,:host.is-selection-of-blocks-active ::ng-deep .ngs-content-editor-content-editable{-webkit-user-select:none!important;user-select:none!important}:host .block-controls{left:0;display:flex;align-items:center;color:var(--color-neutral-500);width:calc(var(--spacing, .25rem) * 18);padding:0 calc(var(--spacing, .25rem) * 2);opacity:0;flex:none}:host .block-controls.is-settings-popover-open{opacity:1}:host .block-controls.is-settings-popover-open .block-control:not(.block-control-drag){opacity:0}:host .block-control{cursor:pointer;width:calc(var(--spacing, .25rem) * 7);height:calc(var(--spacing, .25rem) * 7);flex:none;border-radius:.5rem;display:inline-flex;align-items:center;justify-content:center}:host .block-control:hover{background:var(--color-surface-container-low);color:var(--color-on-surface)}:host .block-control-drag button{cursor:grab}:host .drag-placeholder{height:calc(var(--spacing, .25rem) * 8);flex:none;position:relative}:host .drag-placeholder:before{position:absolute;left:calc(var(--spacing, .25rem) * 18);display:block;right:0;content:\"\";height:calc(var(--spacing, .25rem) * 2);top:50%;transform:translateY(-50%);background:var(--color-primary-300);border-radius:calc(var(--spacing, .25rem) * .5)}:host ::ng-deep code{color:var(--color-primary)}.cdk-drag.cdk-drag-preview{overflow:hidden;display:flex;align-items:center;color:var(--color-neutral-500);width:calc(var(--spacing, .25rem) * 18);padding:0 calc(var(--spacing, .25rem) * 2)}.cdk-drag.cdk-drag-preview .block-control{width:calc(var(--spacing, .25rem) * 7);height:calc(var(--spacing, .25rem) * 7);flex:none;border-radius:.5rem;display:inline-flex;align-items:center;justify-content:center;cursor:grabbing}.cdk-drag.cdk-drag-preview .block-control:first-child{opacity:0}.cdk-drag.cdk-drag-preview .block-control:last-child{color:var(--color-on-surface)}.cdk-drag.cdk-drag-preview .block-content{opacity:0}.settings-popover{--ngs-list-list-item-one-line-container-height: calc(var(--spacing, .25rem) * 10)}\n/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "component", type: Icon, selector: "ngs-icon", inputs: ["name"], exportAs: ["ngsIcon"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "directive", type: CdkDragPlaceholder, selector: "ng-template[cdkDragPlaceholder]", inputs: ["data"] }, { kind: "component", type: Menu, selector: "ngs-menu", inputs: ["role", "classList", "xPosition", "yPosition"], outputs: ["closed"], exportAs: ["ngsMenu"] }, { kind: "component", type: MenuItem, selector: "ngs-menu-item, [ngs-menu-item]", inputs: ["disabled", "role", "selected"], outputs: ["_triggered"], exportAs: ["ngsMenuItem"] }, { kind: "directive", type: MenuTrigger, selector: "[ngsMenuTriggerFor]", inputs: ["ngsMenuTriggerFor", "ngsMenuTriggerData", "ngsMenuDisabled", "xPosition", "yPosition", "ngsMenuTriggerRestoreFocus"], outputs: ["menuOpened", "menuClosed"], exportAs: ["ngsMenuTrigger"] }, { kind: "directive", type: CdkMonitorFocus, selector: "[cdkMonitorElementFocus], [cdkMonitorSubtreeFocus]", outputs: ["cdkFocusChange"], exportAs: ["cdkMonitorFocus"] }, { kind: "directive", type: TextSelectionPopupDirective, selector: "[ngsTextSelectionPopup]", inputs: ["targetComponent", "closestContentObserverClass"], outputs: ["tagSelected"] }, { kind: "directive", type: PopoverTriggerForDirective, selector: "[ngsPopoverTriggerFor]", inputs: ["ngsPopoverTriggerFor", "ngsPopoverContext", "trigger", "position", "delay", "origin", "closeOnOriginClick", "closeOnOriginMouseLeave", "hasBackdrop"], outputs: ["opened", "closed"], exportAs: ["ngsPopoverTriggerFor"] }, { kind: "component", type: Popover, selector: "ngs-popover", exportAs: ["ngsPopover"] }, { kind: "directive", type: ListItemTitle, selector: "[ngsListItemTitle]" }, { kind: "directive", type: ListItemIcon, selector: "[ngsListItemIcon]" }, { kind: "component", type: ListItem, selector: "ngs-list-item, a[ngs-list-item], button[ngs-list-item]", inputs: ["disabled", "lines"], exportAs: ["ngsListItem"] }, { kind: "component", type: List, selector: "ngs-list", inputs: ["disabled", "disableRipple"], exportAs: ["ngsList"] }, { kind: "component", type: MenuHeading, selector: "ngs-menu-heading" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2486
+ }
2487
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ContentBuilderComponent, decorators: [{
2488
+ type: Component,
2489
+ args: [{ selector: 'ngs-content-builder', exportAs: 'ngsContentBuilder', imports: [
2490
+ Icon,
2491
+ NgComponentOutlet,
2492
+ AsyncPipe,
2493
+ CdkDrag,
2494
+ CdkDropList,
2495
+ CdkDragHandle,
2496
+ CdkDragPlaceholder,
2497
+ Menu,
2498
+ MenuItem,
2499
+ MenuTrigger,
2500
+ CdkMonitorFocus,
2501
+ TextSelectionPopupDirective,
2502
+ PopoverTriggerForDirective,
2503
+ Popover,
2504
+ ListItemTitle,
2505
+ ListItemIcon,
2506
+ ListItem,
2507
+ List,
2508
+ MenuHeading
2509
+ ], hostDirectives: [
2510
+ {
2511
+ directive: BlockSelectionDirective,
2512
+ inputs: [
2513
+ 'autoScrollContainerSelector',
2514
+ ]
2515
+ }
2516
+ ], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
2517
+ ContentBuilderStore,
2518
+ {
2519
+ provide: CONTENT_BUILDER,
2520
+ useExisting: forwardRef(() => ContentBuilderComponent)
2521
+ }
2522
+ ], host: {
2523
+ 'class': 'ngs-content-builder',
2524
+ '[class.is-block-dragging]': '_blockDragging()',
2525
+ '[class.is-selection-of-blocks-active]': 'isSelectionOfBlocksActive()',
2526
+ '[class.select-none]': 'isSelectionOfBlocksActive()',
2527
+ '[style.user-select]': 'isSelectionOfBlocksActive() ? "none" : null',
2528
+ 'tabindex': '0',
2529
+ '(paste)': '_onPaste($event)',
2530
+ '(keydown)': '_onKeyDown($event)',
2531
+ }, template: "<div class=\"container py-4\">\n <div class=\"content\"\n cdkDropList\n ngsTextSelectionPopup\n closestContentObserverClass=\"ngs-content-editor-content-editable\"\n [targetComponent]=\"commandBar\"\n (tagSelected)=\"onTagSelected($event)\"\n (cdkDropListDropped)=\"drop($event)\">\n @for (contentBlock of _content(); track contentBlock.id) {\n <div class=\"block\"\n [attr.data-block-id]=\"contentBlock.id\"\n [class.is-focused]=\"isBlockFocused(contentBlock.id)\"\n [class.is-active]=\"isActiveBlock(contentBlock.id)\"\n cdkDrag\n cdkDragLockAxis=\"y\"\n cdkMonitorSubtreeFocus\n (cdkDragStarted)=\"onDragStarted($event, contentBlock)\"\n (cdkDragEnded)=\"onDragEnded($event, contentBlock)\"\n (cdkFocusChange)=\"onFocusChange($event, contentBlock)\">\n <div class=\"block-controls\" [class.is-settings-popover-open]=\"settingsTrigger.api.isOpen()\">\n <button class=\"block-control\">\n <ngs-icon name=\"fluent:add-24-regular\"\n (mousedown)=\"setActiveBlockId($event, contentBlock.id)\"\n [ngsMenuTriggerFor]=\"suggestionsMenu\"\n [ngsMenuTriggerRestoreFocus]=\"false\"\n (menuOpened)=\"onSuggestionsMenuOpen()\"\n (menuClosed)=\"onSuggestionsMenuClose($event)\"/>\n </button>\n <div class=\"block-control block-control-drag\"\n (click)=\"selectBlock(contentBlock.id)\"\n [ngsPopoverTriggerFor]=\"settingsPopover\"\n (closed)=\"onSettingsPopoverClose()\"\n #settingsTrigger=\"ngsPopoverTriggerFor\"\n hasBackdrop\n position=\"before-center\">\n <button cdkDragHandle\n trigger=\"hover\"\n closeOnOriginClick\n closeOnOriginMouseLeave\n #dragTrigger=\"ngsPopoverTriggerFor\"\n [ngsPopoverTriggerFor]=\"dragControlTooltip\"\n position=\"below-center\"\n (mousedown)=\"dragTrigger.api.close()\"\n delay=\"1000\" class=\"w-full h-full flex items-center justify-center\">\n <ngs-icon name=\"fluent:re-order-dots-vertical-24-regular\"/>\n </button>\n </div>\n <ng-template #dragControlTooltip>\n <div class=\"bg-neutral-900 text-xs flex flex-col gap-0.5 rounded-lg items-center px-2 py-1.5 font-medium\">\n <div>\n <div class=\"text-neutral-100\">Drag <span class=\"text-neutral-400\">to move</span></div>\n </div>\n <div>\n <div class=\"text-neutral-100\">Click <span class=\"text-neutral-400\">to open menu</span></div>\n </div>\n </div>\n </ng-template>\n </div>\n <div class=\"block-content\" [class.is-selected]=\"isBlockSelected(contentBlock.id)\">\n <div class=\"drag-placeholder\" *cdkDragPlaceholder></div>\n <ng-container [ngComponentOutlet]=\"blockDefsMap.get(contentBlock.type) | async\"\n [ngComponentOutletInputs]=\"{\n id: contentBlock.id,\n content: contentBlock.content,\n settings: contentBlock.settings,\n index: $index\n }\"/>\n </div>\n </div>\n }\n </div>\n</div>\n\n<ngs-popover #settingsPopover=\"ngsPopover\">\n <div class=\"px-2 py-0 w-72 settings-popover\">\n <ngs-list>\n <ngs-list-item (click)=\"duplicateSelectedBlocks(settingsPopover)\">\n <ngs-icon name=\"fluent:copy-24-regular\" ngsListItemIcon/>\n <div ngsListItemTitle>Duplicate</div>\n </ngs-list-item>\n <ngs-list-item (click)=\"deleteSelectedBlocks(settingsPopover)\">\n <ngs-icon name=\"fluent:delete-24-regular\" ngsListItemIcon/>\n <div ngsListItemTitle>Delete</div>\n </ngs-list-item>\n </ngs-list>\n </div>\n</ngs-popover>\n\n<ngs-menu #suggestionsMenu=\"ngsMenu\">\n <div (click)=\"preventMenuClose($event)\">\n @for (suggestionItem of suggestions(); track $index; let first = $first) {\n @switch (suggestionItem.type) {\n @case ('heading') {\n <ngs-menu-heading>{{ suggestionItem.title }}</ngs-menu-heading>\n }\n @case ('item') {\n <button ngs-menu-item (click)=\"addBlockFromSuggestionMenu(suggestionsMenu, suggestionItem.blockType, suggestionItem.blockOptions)\">\n <div class=\"h-full flex items-center gap-3 py-2\">\n <div class=\"size-9 flex items-center rounded-lg justify-center bg-surface-container\">\n <ngs-icon [name]=\"suggestionItem.iconName\" class=\"!me-0\"/>\n </div>\n <div class=\"grow min-w-[200px]\">\n <div>{{ suggestionItem.title }}</div>\n <div class=\"text-2xs text-neutral-500\">{{ suggestionItem.description }}</div>\n </div>\n @if (suggestionItem.hotKeys) {\n <div class=\"ms-auto bg-surface-container-highest rounded-full h-5\n text-4xs px-2 flex items-center font-bold\">{{ suggestionItem.hotKeys }}</div>\n }\n </div>\n </button>\n }\n }\n }\n </div>\n</ngs-menu>\n", styles: [":host{--ngs-content-builder-content-width: 704px;outline:none}:host ::ng-deep .link-selection,:host ::ng-deep .text-selection{display:inline-block;background:var(--color-secondary-fixed)}:host.is-block-dragging{cursor:grabbing}:host .container{display:flex;width:820px;min-height:200px;height:100%;padding:calc(var(--spacing, .25rem) * 5) calc(var(--spacing, .25rem) * 5) calc(var(--spacing, .25rem) * 5) 0;margin:0 auto;outline:none}:host .content{flex-grow:1;width:calc(var(--ngs-content-builder-content-width) + calc(var(--spacing, .25rem) * 10))}:host .block{position:relative;flex:none;padding:calc(var(--spacing, .25rem) * 1) 0;display:flex;align-items:center}:host .block:not(:has(.block-content.is-selected)):hover .block-content{background:var(--color-neutral-50)}:host:not(.is-block-dragging) .block:hover .block-controls,:host:not(.is-block-dragging) .block.is-active .block-controls{opacity:1}:host .block-content{position:relative;flex-grow:1;padding:calc(var(--spacing, .25rem) * 3)}:host .block-content.is-selected{background:var(--color-primary-100)}:host ::ng-deep .selection-area{background:var(--color-primary-100);opacity:.4;border:1px solid var(--color-primary);border-radius:.25rem}:host ::ng-deep .ngs-content-editor-content-editable{-webkit-user-select:text;user-select:text}:host.select-none ::ng-deep .ngs-content-editor-content-editable,:host.is-selection-of-blocks-active ::ng-deep .ngs-content-editor-content-editable{-webkit-user-select:none!important;user-select:none!important}:host .block-controls{left:0;display:flex;align-items:center;color:var(--color-neutral-500);width:calc(var(--spacing, .25rem) * 18);padding:0 calc(var(--spacing, .25rem) * 2);opacity:0;flex:none}:host .block-controls.is-settings-popover-open{opacity:1}:host .block-controls.is-settings-popover-open .block-control:not(.block-control-drag){opacity:0}:host .block-control{cursor:pointer;width:calc(var(--spacing, .25rem) * 7);height:calc(var(--spacing, .25rem) * 7);flex:none;border-radius:.5rem;display:inline-flex;align-items:center;justify-content:center}:host .block-control:hover{background:var(--color-surface-container-low);color:var(--color-on-surface)}:host .block-control-drag button{cursor:grab}:host .drag-placeholder{height:calc(var(--spacing, .25rem) * 8);flex:none;position:relative}:host .drag-placeholder:before{position:absolute;left:calc(var(--spacing, .25rem) * 18);display:block;right:0;content:\"\";height:calc(var(--spacing, .25rem) * 2);top:50%;transform:translateY(-50%);background:var(--color-primary-300);border-radius:calc(var(--spacing, .25rem) * .5)}:host ::ng-deep code{color:var(--color-primary)}.cdk-drag.cdk-drag-preview{overflow:hidden;display:flex;align-items:center;color:var(--color-neutral-500);width:calc(var(--spacing, .25rem) * 18);padding:0 calc(var(--spacing, .25rem) * 2)}.cdk-drag.cdk-drag-preview .block-control{width:calc(var(--spacing, .25rem) * 7);height:calc(var(--spacing, .25rem) * 7);flex:none;border-radius:.5rem;display:inline-flex;align-items:center;justify-content:center;cursor:grabbing}.cdk-drag.cdk-drag-preview .block-control:first-child{opacity:0}.cdk-drag.cdk-drag-preview .block-control:last-child{color:var(--color-on-surface)}.cdk-drag.cdk-drag-preview .block-content{opacity:0}.settings-popover{--ngs-list-list-item-one-line-container-height: calc(var(--spacing, .25rem) * 10)}\n/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */\n"] }]
2532
+ }], propDecorators: { content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: false }] }], contentChangedDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentChangedDelay", required: false }] }], suggestions: [{ type: i0.Input, args: [{ isSignal: true, alias: "suggestions", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], scrollContainer: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollContainer", required: false }] }], contentChanged: [{ type: i0.Output, args: ["contentChanged"] }] } });
2533
+
2534
+ class ContentViewerComponent {
2535
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ContentViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2536
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.4", type: ContentViewerComponent, isStandalone: true, selector: "ngs-content-viewer", ngImport: i0, template: "<p>content-viewer works!</p>\n", styles: [""] });
2537
+ }
2538
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ContentViewerComponent, decorators: [{
2539
+ type: Component,
2540
+ args: [{ selector: 'ngs-content-viewer', imports: [], template: "<p>content-viewer works!</p>\n" }]
2541
+ }] });
2542
+
2543
+ /**
2544
+ * Generated bundle index. Do not edit.
2545
+ */
2546
+
2547
+ export { BlockSelectionDirective as B, ContentBuilderStore as C, TextSelectionPopupDirective as T, CONTENT_BUILDER as a, CONTENT_EDITOR_BLOCK as b, CommandBarComponent as c, ContentBuilderComponent as d, ContentViewerComponent as e };
2548
+ //# sourceMappingURL=ngstarter-ui-components-content-editor-ngstarter-ui-components-content-editor-1Zi2nAX5.mjs.map