@cuby-ui/core 0.0.227 → 0.0.231

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 (270) hide show
  1. package/components/button/button.component.d.ts +1 -1
  2. package/components/content-wrapper/content-wrapper.component.d.ts +11 -0
  3. package/components/content-wrapper/index.d.ts +1 -0
  4. package/components/empty-state/empty-state.component.d.ts +7 -0
  5. package/components/empty-state/index.d.ts +1 -0
  6. package/components/ghost-input/ghost-input.component.d.ts +6 -0
  7. package/components/ghost-input/index.d.ts +1 -0
  8. package/components/index.d.ts +3 -0
  9. package/components/sidebar/sidebar-header/sidebar-header.component.d.ts +1 -1
  10. package/components/sidebar/sidebar-navigation-item/sidebar-navigation-item.component.d.ts +1 -1
  11. package/editor/components/editor-attaches-tool/editor-attaches-tool.component.d.ts +44 -0
  12. package/editor/components/editor-attaches-tool/editor-attaches-tool.options.d.ts +17 -0
  13. package/editor/components/editor-attaches-tool/index.d.ts +2 -0
  14. package/editor/components/editor-image-tool/editor-image-tool.component.d.ts +14 -0
  15. package/editor/components/editor-image-tool/editor-image-tool.options.d.ts +26 -0
  16. package/editor/components/editor-image-tool/index.d.ts +2 -0
  17. package/editor/components/editor-tool/editor-tool.component.d.ts +22 -0
  18. package/editor/components/editor-tool-modal/editor-tool-modal.component.d.ts +24 -0
  19. package/editor/components/editor-tool-modal/editor-tool-modal.options.d.ts +8 -0
  20. package/editor/components/editor-tool-modal/index.d.ts +2 -0
  21. package/editor/components/editor-tooltip/editor-tooltip.component.d.ts +16 -0
  22. package/editor/components/editor-tooltip/editor-tooltip.options.d.ts +9 -0
  23. package/editor/components/editor-tooltip/index.d.ts +2 -0
  24. package/editor/components/editor-video-tool/editor-video-tool.component.d.ts +12 -0
  25. package/editor/components/editor-video-tool/editor-video-tool.options.d.ts +26 -0
  26. package/editor/components/editor-video-tool/index.d.ts +2 -0
  27. package/editor/components/index.d.ts +7 -0
  28. package/editor/components/marker-modal/index.d.ts +3 -0
  29. package/editor/components/marker-modal/marker-modal.component.d.ts +62 -0
  30. package/editor/components/marker-modal/marker-modal.interfaces.d.ts +7 -0
  31. package/editor/components/marker-modal/marker-modal.options.d.ts +1 -0
  32. package/editor/components/marker-select/component/select-item/select-option.component.d.ts +7 -0
  33. package/editor/components/marker-select/index.d.ts +2 -0
  34. package/editor/components/marker-select/marker-select.component.d.ts +40 -0
  35. package/editor/components/marker-select/marker-select.options.d.ts +1 -0
  36. package/editor/config/custom-elements.d.ts +2 -0
  37. package/editor/config/editor.config.d.ts +3 -0
  38. package/editor/config/editor.provider.d.ts +2 -0
  39. package/editor/config/index.d.ts +2 -0
  40. package/editor/constants/editor.constants.d.ts +15 -0
  41. package/editor/constants/index.d.ts +1 -0
  42. package/editor/editor.component.d.ts +71 -0
  43. package/editor/events/editor-drag.event.d.ts +2 -0
  44. package/editor/events/editor-keyboard.event.d.ts +2 -0
  45. package/editor/events/editor-modal.event.d.ts +3 -0
  46. package/editor/events/editor-tooltip.event.d.ts +2 -0
  47. package/editor/events/set-editor-events.d.ts +1 -0
  48. package/editor/index.d.ts +9 -0
  49. package/editor/interfaces/angular-element.d.ts +2 -0
  50. package/editor/interfaces/blocks-request-data.d.ts +6 -0
  51. package/editor/interfaces/combined-block-adding-event.d.ts +7 -0
  52. package/editor/interfaces/combined-block-data.d.ts +5 -0
  53. package/editor/interfaces/combined-part-block-data.d.ts +7 -0
  54. package/editor/interfaces/custom-element.d.ts +5 -0
  55. package/editor/interfaces/event-action-data.d.ts +5 -0
  56. package/editor/interfaces/file-response-data.d.ts +10 -0
  57. package/editor/interfaces/full-block-data.d.ts +8 -0
  58. package/editor/interfaces/index.d.ts +14 -0
  59. package/editor/interfaces/main-editor-config.d.ts +15 -0
  60. package/editor/interfaces/mutation-actions.d.ts +5 -0
  61. package/editor/interfaces/parent.d.ts +4 -0
  62. package/editor/interfaces/tools.d.ts +4 -0
  63. package/editor/interfaces/tune.d.ts +6 -0
  64. package/editor/pipes/file-size.pipe.d.ts +9 -0
  65. package/editor/services/editor-service.options.d.ts +8 -0
  66. package/editor/services/editor.service.d.ts +23 -0
  67. package/editor/services/index.d.ts +6 -0
  68. package/editor/services/jtext-api.options.d.ts +20 -0
  69. package/editor/services/jtext-api.service.d.ts +23 -0
  70. package/editor/services/markers-service.options.d.ts +4 -0
  71. package/editor/services/markers.service.d.ts +11 -0
  72. package/editor/tools/attaches.tool.d.ts +28 -0
  73. package/editor/tools/bold.tool.d.ts +11 -0
  74. package/editor/tools/combined-text-block.tool.d.ts +49 -0
  75. package/editor/tools/custom-marker.tool.d.ts +16 -0
  76. package/editor/tools/header.tool.d.ts +8 -0
  77. package/editor/tools/image.tool.d.ts +37 -0
  78. package/editor/tools/index.d.ts +11 -0
  79. package/editor/tools/italic.tool.d.ts +12 -0
  80. package/editor/tools/link-marker.tool.d.ts +15 -0
  81. package/editor/tools/list.tool.d.ts +5 -0
  82. package/editor/tools/marker.tool.d.ts +36 -0
  83. package/editor/tools/role-marker.tool.d.ts +7 -0
  84. package/editor/tools/selection-base.tool.d.ts +24 -0
  85. package/editor/tools/tool-marker.tool.d.ts +7 -0
  86. package/editor/tools/video.tool.d.ts +32 -0
  87. package/editor/utils/create-link-modal.d.ts +3 -0
  88. package/editor/utils/create-tool-modal.d.ts +4 -0
  89. package/editor/utils/create-tooltip.d.ts +8 -0
  90. package/editor/utils/file-uploader.d.ts +26 -0
  91. package/editor/utils/generate-id.d.ts +1 -0
  92. package/editor/utils/index.d.ts +9 -0
  93. package/editor/utils/recalculate-indexes.d.ts +2 -0
  94. package/editor/utils/remove-element-tag-wrapper.d.ts +1 -0
  95. package/editor/utils/split-html.d.ts +1 -0
  96. package/editor/utils/url.validator.d.ts +2 -0
  97. package/editor/widgets/editor-block/editor-block.component.d.ts +22 -0
  98. package/editor/widgets/editor-block/index.d.ts +1 -0
  99. package/editor/widgets/editor-modal/editor-modal.component.d.ts +19 -0
  100. package/editor/widgets/editor-modal/index.d.ts +1 -0
  101. package/editor/widgets/editor-readonly/editor-readonly.component.d.ts +28 -0
  102. package/editor/widgets/editor-readonly/editor-readonly.options.d.ts +5 -0
  103. package/editor/widgets/editor-readonly/index.d.ts +2 -0
  104. package/editor/widgets/index.d.ts +3 -0
  105. package/esm2022/components/breadcrumbs/breadcrumbs.component.mjs +2 -2
  106. package/esm2022/components/content-wrapper/content-wrapper.component.mjs +29 -0
  107. package/esm2022/components/content-wrapper/index.mjs +2 -0
  108. package/esm2022/components/empty-state/empty-state.component.mjs +17 -0
  109. package/esm2022/components/empty-state/index.mjs +2 -0
  110. package/esm2022/components/ghost-input/ghost-input.component.mjs +16 -0
  111. package/esm2022/components/ghost-input/index.mjs +2 -0
  112. package/esm2022/components/index.mjs +4 -1
  113. package/esm2022/directives/tooltip/tooltip-describe.directive.mjs +5 -3
  114. package/esm2022/directives/tooltip/tooltip-position.directive.mjs +6 -3
  115. package/esm2022/directives/tooltip/tooltip.component.mjs +6 -3
  116. package/esm2022/editor/components/editor-attaches-tool/editor-attaches-tool.component.mjs +76 -0
  117. package/esm2022/editor/components/editor-attaches-tool/editor-attaches-tool.options.mjs +2 -0
  118. package/esm2022/editor/components/editor-attaches-tool/index.mjs +3 -0
  119. package/esm2022/editor/components/editor-image-tool/editor-image-tool.component.mjs +43 -0
  120. package/esm2022/editor/components/editor-image-tool/editor-image-tool.options.mjs +2 -0
  121. package/esm2022/editor/components/editor-image-tool/index.mjs +3 -0
  122. package/esm2022/editor/components/editor-tool/editor-tool.component.mjs +74 -0
  123. package/esm2022/editor/components/editor-tool-modal/editor-tool-modal.component.mjs +69 -0
  124. package/esm2022/editor/components/editor-tool-modal/editor-tool-modal.options.mjs +2 -0
  125. package/esm2022/editor/components/editor-tool-modal/index.mjs +3 -0
  126. package/esm2022/editor/components/editor-tooltip/editor-tooltip.component.mjs +45 -0
  127. package/esm2022/editor/components/editor-tooltip/editor-tooltip.options.mjs +2 -0
  128. package/esm2022/editor/components/editor-tooltip/index.mjs +3 -0
  129. package/esm2022/editor/components/editor-video-tool/editor-video-tool.component.mjs +41 -0
  130. package/esm2022/editor/components/editor-video-tool/editor-video-tool.options.mjs +2 -0
  131. package/esm2022/editor/components/editor-video-tool/index.mjs +3 -0
  132. package/esm2022/editor/components/index.mjs +8 -0
  133. package/esm2022/editor/components/marker-modal/index.mjs +3 -0
  134. package/esm2022/editor/components/marker-modal/marker-modal.component.mjs +261 -0
  135. package/esm2022/editor/components/marker-modal/marker-modal.interfaces.mjs +2 -0
  136. package/esm2022/editor/components/marker-modal/marker-modal.options.mjs +2 -0
  137. package/esm2022/editor/components/marker-select/component/select-item/select-option.component.mjs +15 -0
  138. package/esm2022/editor/components/marker-select/index.mjs +3 -0
  139. package/esm2022/editor/components/marker-select/marker-select.component.mjs +155 -0
  140. package/esm2022/editor/components/marker-select/marker-select.options.mjs +2 -0
  141. package/esm2022/editor/config/custom-elements.mjs +32 -0
  142. package/esm2022/editor/config/editor.config.mjs +30 -0
  143. package/esm2022/editor/config/editor.provider.mjs +19 -0
  144. package/esm2022/editor/config/index.mjs +3 -0
  145. package/esm2022/editor/constants/editor.constants.mjs +20 -0
  146. package/esm2022/editor/constants/index.mjs +2 -0
  147. package/esm2022/editor/editor.component.mjs +380 -0
  148. package/esm2022/editor/events/editor-drag.event.mjs +7 -0
  149. package/esm2022/editor/events/editor-keyboard.event.mjs +33 -0
  150. package/esm2022/editor/events/editor-modal.event.mjs +31 -0
  151. package/esm2022/editor/events/editor-tooltip.event.mjs +63 -0
  152. package/esm2022/editor/events/set-editor-events.mjs +11 -0
  153. package/esm2022/editor/i18n/en.json +14 -0
  154. package/esm2022/editor/index.mjs +8 -0
  155. package/esm2022/editor/interfaces/angular-element.mjs +2 -0
  156. package/esm2022/editor/interfaces/blocks-request-data.mjs +2 -0
  157. package/esm2022/editor/interfaces/combined-block-adding-event.mjs +2 -0
  158. package/esm2022/editor/interfaces/combined-block-data.mjs +2 -0
  159. package/esm2022/editor/interfaces/combined-part-block-data.mjs +2 -0
  160. package/esm2022/editor/interfaces/custom-element.mjs +2 -0
  161. package/esm2022/editor/interfaces/event-action-data.mjs +2 -0
  162. package/esm2022/editor/interfaces/file-response-data.mjs +2 -0
  163. package/esm2022/editor/interfaces/full-block-data.mjs +2 -0
  164. package/esm2022/editor/interfaces/index.mjs +14 -0
  165. package/esm2022/editor/interfaces/main-editor-config.mjs +2 -0
  166. package/esm2022/editor/interfaces/mutation-actions.mjs +2 -0
  167. package/esm2022/editor/interfaces/parent.mjs +2 -0
  168. package/esm2022/editor/interfaces/tools.mjs +2 -0
  169. package/esm2022/editor/interfaces/tune.mjs +2 -0
  170. package/esm2022/editor/pipes/file-size.pipe.mjs +25 -0
  171. package/esm2022/editor/services/editor-service.options.mjs +4 -0
  172. package/esm2022/editor/services/editor.service.mjs +138 -0
  173. package/esm2022/editor/services/index.mjs +7 -0
  174. package/esm2022/editor/services/jtext-api.options.mjs +2 -0
  175. package/esm2022/editor/services/jtext-api.service.mjs +50 -0
  176. package/esm2022/editor/services/markers-service.options.mjs +2 -0
  177. package/esm2022/editor/services/markers.service.mjs +79 -0
  178. package/esm2022/editor/tools/attaches.tool.mjs +96 -0
  179. package/esm2022/editor/tools/bold.tool.mjs +33 -0
  180. package/esm2022/editor/tools/combined-text-block.tool.mjs +380 -0
  181. package/esm2022/editor/tools/custom-marker.tool.mjs +88 -0
  182. package/esm2022/editor/tools/header.tool.mjs +16 -0
  183. package/esm2022/editor/tools/image.tool.mjs +157 -0
  184. package/esm2022/editor/tools/index.mjs +12 -0
  185. package/esm2022/editor/tools/italic.tool.mjs +35 -0
  186. package/esm2022/editor/tools/link-marker.tool.mjs +80 -0
  187. package/esm2022/editor/tools/list.tool.mjs +10 -0
  188. package/esm2022/editor/tools/marker.tool.mjs +144 -0
  189. package/esm2022/editor/tools/role-marker.tool.mjs +17 -0
  190. package/esm2022/editor/tools/selection-base.tool.mjs +92 -0
  191. package/esm2022/editor/tools/tool-marker.tool.mjs +14 -0
  192. package/esm2022/editor/tools/video.tool.mjs +132 -0
  193. package/esm2022/editor/utils/create-link-modal.mjs +22 -0
  194. package/esm2022/editor/utils/create-tool-modal.mjs +45 -0
  195. package/esm2022/editor/utils/create-tooltip.mjs +44 -0
  196. package/esm2022/editor/utils/file-uploader.mjs +57 -0
  197. package/esm2022/editor/utils/generate-id.mjs +4 -0
  198. package/esm2022/editor/utils/index.mjs +10 -0
  199. package/esm2022/editor/utils/recalculate-indexes.mjs +32 -0
  200. package/esm2022/editor/utils/remove-element-tag-wrapper.mjs +11 -0
  201. package/esm2022/editor/utils/split-html.mjs +128 -0
  202. package/esm2022/editor/utils/url.validator.mjs +12 -0
  203. package/esm2022/editor/widgets/editor-block/editor-block.component.mjs +63 -0
  204. package/esm2022/editor/widgets/editor-block/index.mjs +2 -0
  205. package/esm2022/editor/widgets/editor-modal/editor-modal.component.mjs +47 -0
  206. package/esm2022/editor/widgets/editor-modal/index.mjs +2 -0
  207. package/esm2022/editor/widgets/editor-readonly/editor-readonly.component.mjs +40 -0
  208. package/esm2022/editor/widgets/editor-readonly/editor-readonly.options.mjs +2 -0
  209. package/esm2022/editor/widgets/editor-readonly/index.mjs +2 -0
  210. package/esm2022/editor/widgets/index.mjs +4 -0
  211. package/esm2022/index.mjs +3 -1
  212. package/esm2022/interceptors/loader.interceptor.mjs +3 -3
  213. package/esm2022/services/loader.options.mjs +2 -2
  214. package/esm2022/services/loader.service.mjs +11 -11
  215. package/esm2022/utils/default-validators/create-default-validators.mjs +12 -0
  216. package/esm2022/utils/default-validators/extra-spaces.options.mjs +11 -0
  217. package/esm2022/utils/default-validators/extra-spaces.validators.mjs +16 -0
  218. package/esm2022/utils/default-validators/index.mjs +2 -0
  219. package/esm2022/utils/index.mjs +2 -1
  220. package/esm2022/widgets/categories/categories.component.mjs +75 -0
  221. package/esm2022/widgets/categories/components/categories-list/categories-list.component.mjs +16 -0
  222. package/esm2022/widgets/categories/components/categories-list/index.mjs +2 -0
  223. package/esm2022/widgets/categories/components/category-form/category-form.component.mjs +79 -0
  224. package/esm2022/widgets/categories/components/category-form/index.mjs +2 -0
  225. package/esm2022/widgets/categories/components/category-item/category-item.component.mjs +123 -0
  226. package/esm2022/widgets/categories/components/category-item/index.mjs +2 -0
  227. package/esm2022/widgets/categories/components/create-category-item/create-category-item.component.mjs +25 -0
  228. package/esm2022/widgets/categories/components/create-category-item/index.mjs +2 -0
  229. package/esm2022/widgets/categories/components/index.mjs +3 -0
  230. package/esm2022/widgets/categories/index.mjs +3 -0
  231. package/esm2022/widgets/categories/services/index.mjs +2 -0
  232. package/esm2022/widgets/categories/services/selected-category.service.mjs +38 -0
  233. package/esm2022/widgets/general-control-error-hint/general-control-error-hint.component.mjs +21 -0
  234. package/esm2022/widgets/general-control-error-hint/index.mjs +2 -0
  235. package/esm2022/widgets/index.mjs +3 -0
  236. package/esm2022/widgets/utility-info/index.mjs +2 -0
  237. package/esm2022/widgets/utility-info/utility-info.component.mjs +246 -0
  238. package/esm2022/widgets/utility-info/utility-info.options.mjs +2 -0
  239. package/fesm2022/cuby-ui-core-en-D3DnyYmu.mjs +29 -0
  240. package/fesm2022/cuby-ui-core-en-D3DnyYmu.mjs.map +1 -0
  241. package/fesm2022/cuby-ui-core.mjs +4069 -67
  242. package/fesm2022/cuby-ui-core.mjs.map +1 -1
  243. package/index.d.ts +2 -0
  244. package/package.json +11 -4
  245. package/services/loader.options.d.ts +2 -2
  246. package/services/loader.service.d.ts +7 -7
  247. package/utils/default-validators/create-default-validators.d.ts +5 -0
  248. package/utils/default-validators/extra-spaces.options.d.ts +2 -0
  249. package/utils/default-validators/extra-spaces.validators.d.ts +3 -0
  250. package/utils/default-validators/index.d.ts +1 -0
  251. package/utils/index.d.ts +1 -0
  252. package/widgets/categories/categories.component.d.ts +24 -0
  253. package/widgets/categories/components/categories-list/categories-list.component.d.ts +7 -0
  254. package/widgets/categories/components/categories-list/index.d.ts +1 -0
  255. package/widgets/categories/components/category-form/category-form.component.d.ts +28 -0
  256. package/widgets/categories/components/category-form/index.d.ts +1 -0
  257. package/widgets/categories/components/category-item/category-item.component.d.ts +40 -0
  258. package/widgets/categories/components/category-item/index.d.ts +1 -0
  259. package/widgets/categories/components/create-category-item/create-category-item.component.d.ts +10 -0
  260. package/widgets/categories/components/create-category-item/index.d.ts +1 -0
  261. package/widgets/categories/components/index.d.ts +2 -0
  262. package/widgets/categories/index.d.ts +2 -0
  263. package/widgets/categories/services/index.d.ts +1 -0
  264. package/widgets/categories/services/selected-category.service.d.ts +18 -0
  265. package/widgets/general-control-error-hint/general-control-error-hint.component.d.ts +9 -0
  266. package/widgets/general-control-error-hint/index.d.ts +1 -0
  267. package/widgets/index.d.ts +2 -0
  268. package/widgets/utility-info/index.d.ts +1 -0
  269. package/widgets/utility-info/utility-info.component.d.ts +53 -0
  270. package/widgets/utility-info/utility-info.options.d.ts +9 -0
@@ -1,23 +1,29 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Component, ChangeDetectionStrategy, inject, Renderer2, input, model, effect, Directive, InjectionToken, Input, HostBinding, ChangeDetectorRef, ElementRef, ViewChild, EventEmitter, Output, NgModule, Injector, Injectable, SkipSelf, Optional, DestroyRef, NgZone, signal, TemplateRef, ContentChildren, HostListener, Self, INJECTOR, forwardRef, ViewContainerRef, computed } from '@angular/core';
2
+ import { Component, ChangeDetectionStrategy, inject, Renderer2, input, model, effect, Directive, InjectionToken, Input, HostBinding, ChangeDetectorRef, ElementRef, ViewChild, EventEmitter, Output, NgModule, Injector, Injectable, SkipSelf, Optional, DestroyRef, NgZone, signal, TemplateRef, ContentChildren, HostListener, Self, INJECTOR, forwardRef, ViewContainerRef, booleanAttribute, computed, Pipe, APP_INITIALIZER, viewChild, afterRender, output } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
- import { CommonModule, DOCUMENT, NgForOf, NgIf, NgComponentOutlet, NgTemplateOutlet } from '@angular/common';
4
+ import { CommonModule, DOCUMENT, NgForOf, NgIf, NgComponentOutlet, NgTemplateOutlet, NgFor, UpperCasePipe, NgClass } from '@angular/common';
5
5
  import * as i1$1 from '@cuby-ui/cdk';
6
- import { CUI_WINDOW, cuiCreateToken, cuiCreateTokenFromFactory, CuiDestroyService, CuiFilterPipe, CuiLetDirective, CuiPopoverService, cuiProvide, CUI_ANIMATION_FRAME, cuiZonefree, EMPTY_CLIENT_RECT, cuiInjectElement, CUI_LOCAL_STORAGE, CUI_IS_WEBKIT, CuiItemDirective, CuiActiveZone, CuiFocusTrapDirective, cuiGetElementObscures, CUI_IS_MOBILE, CuiHoveredService, cuiPure, cuiPointToClientRect, cuiClamp, cuiPx, cuiIfMap, cuiIsPresent, cuiTypedFromEvent, cuiZonefreeScheduler, cuiZoneOptimized, cuiIsNativeFocused, CuiClickOutsideDirective, CuiTargetDirective, cuiGetClosestFocusable, CuiTime, CuiDimensionsObserverDirective, CuiAutoResizingDirective } from '@cuby-ui/cdk';
6
+ import { CUI_WINDOW, cuiCreateToken, cuiCreateTokenFromFactory, CuiDestroyService, CuiFilterPipe, CuiLetDirective, CuiPopoverService, cuiProvide, CUI_ANIMATION_FRAME, cuiZonefree, EMPTY_CLIENT_RECT, cuiInjectElement, CUI_LOCAL_STORAGE, CUI_IS_WEBKIT, CuiItemDirective, CuiActiveZone, CuiFocusTrapDirective, cuiGetElementObscures, CUI_IS_MOBILE, CuiHoveredService, cuiPure, cuiPointToClientRect, cuiClamp, cuiPx, cuiIfMap, cuiIsPresent, cuiTypedFromEvent, cuiZonefreeScheduler, cuiZoneOptimized, cuiIsNativeFocused, CuiClickOutsideDirective, CuiTargetDirective, cuiGetClosestFocusable, CuiTime, CuiDimensionsObserverDirective, CuiAutoResizingDirective, CuiIdService, CuiElementDirective } from '@cuby-ui/cdk';
7
7
  import { DomSanitizer } from '@angular/platform-browser';
8
8
  import { cuiIsIcon, CUI_ICONS } from '@cuby-ui/icons';
9
- import { BehaviorSubject, takeUntil, Observable, merge, distinctUntilChanged, startWith, map, finalize, Subject, switchMap, of, delay, repeat, filter, tap, takeWhile, fromEvent, debounce, timer, skip, take, catchError, throwError } from 'rxjs';
9
+ import { BehaviorSubject, takeUntil, Observable, merge, distinctUntilChanged, startWith, map, finalize, timer, Subject, switchMap, of, delay, repeat, filter, tap, takeWhile, fromEvent, debounce, skip, take, forkJoin, throttleTime, concatMap, toArray, catchError, throwError, pairwise, debounceTime } from 'rxjs';
10
10
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
11
11
  import { trigger, transition, query, animateChild, style, animate, stagger } from '@angular/animations';
12
12
  import * as i2 from '@taiga-ui/polymorpheus';
13
13
  import { PolymorpheusOutlet, PolymorpheusTemplate, PolymorpheusComponent, injectContext } from '@taiga-ui/polymorpheus';
14
- import { __decorate } from 'tslib';
14
+ import { __decorate, __metadata } from 'tslib';
15
15
  import * as i2$1 from '@angular/forms';
16
- import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
16
+ import { Validators, NG_VALUE_ACCESSOR, FormsModule, ReactiveFormsModule, FormControl, NonNullableFormBuilder } from '@angular/forms';
17
17
  import { maskitoParseNumber, maskitoNumberOptionsGenerator, maskitoTimeOptionsGenerator } from '@maskito/kit';
18
18
  import * as i3 from '@maskito/angular';
19
19
  import { MaskitoDirective } from '@maskito/angular';
20
- import { HttpErrorResponse } from '@angular/common/http';
20
+ import EditorJS from '@editorjs/editorjs';
21
+ import Header from '@editorjs/header';
22
+ import List from '@editorjs/list';
23
+ import { TranslocoDirective, TranslocoService } from '@jsverse/transloco';
24
+ import { HttpClient, HttpErrorResponse } from '@angular/common/http';
25
+ import { createCustomElement } from '@angular/elements';
26
+ import { CuiFrameApiService, CuiTreeStructNavigatorApiService } from '@cuby-ui/api';
21
27
 
22
28
  class CuiAccordionComponent {
23
29
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiAccordionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
@@ -761,16 +767,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
761
767
  }]
762
768
  }], ctorParameters: () => [] });
763
769
 
764
- const LoadingState = {
770
+ const CuiLoadingState = {
765
771
  LOADING: 'loading',
766
772
  COMPLETED: 'completed',
767
773
  INITIAL: 'initial'
768
774
  };
769
775
 
770
- class LoaderService {
776
+ class CuiLoaderService {
771
777
  constructor() {
772
778
  this.RESET_TO_INITIAL_TIME = 1000;
773
- this.loaderStateSignal = signal(LoadingState.INITIAL);
779
+ this.loaderStateSignal = signal(CuiLoadingState.INITIAL);
774
780
  this.requestCount = 0;
775
781
  this.loaderState = this.loaderStateSignal.asReadonly();
776
782
  AngularOutsideLoaderService.setInstance(this);
@@ -778,14 +784,14 @@ class LoaderService {
778
784
  setLoading() {
779
785
  this.requestCount++;
780
786
  // need to use without queueMicrotask (error)
781
- queueMicrotask(() => this.loaderStateSignal.set(LoadingState.LOADING));
787
+ queueMicrotask(() => this.loaderStateSignal.set(CuiLoadingState.LOADING));
782
788
  }
783
789
  setCompleted() {
784
790
  this.requestCount = this.requestCount && this.requestCount - 1;
785
791
  if (this.requestCount) {
786
792
  return;
787
793
  }
788
- return this.loaderStateSignal.set(LoadingState.COMPLETED);
794
+ return this.loaderStateSignal.set(CuiLoadingState.COMPLETED);
789
795
  }
790
796
  handleCompletedRequest() {
791
797
  this.setCompleted();
@@ -794,18 +800,18 @@ class LoaderService {
794
800
  if (this.requestCount) {
795
801
  return;
796
802
  }
797
- this.loaderStateSignal.set(LoadingState.INITIAL);
803
+ this.loaderStateSignal.set(CuiLoadingState.INITIAL);
798
804
  }, this.RESET_TO_INITIAL_TIME);
799
805
  }
800
806
  reset() {
801
807
  this.requestCount = 0;
802
808
  this.resetLoadingStateTimerId = undefined;
803
- this.loaderStateSignal.set(LoadingState.INITIAL);
809
+ this.loaderStateSignal.set(CuiLoadingState.INITIAL);
804
810
  }
805
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LoaderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
806
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LoaderService, providedIn: 'root' }); }
811
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiLoaderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
812
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiLoaderService, providedIn: 'root' }); }
807
813
  }
808
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LoaderService, decorators: [{
814
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiLoaderService, decorators: [{
809
815
  type: Injectable,
810
816
  args: [{
811
817
  providedIn: 'root'
@@ -1647,6 +1653,41 @@ function cuiGetDuration(speed) {
1647
1653
  return speed && CUI_ANIMATIONS_DEFAULT_DURATION / speed;
1648
1654
  }
1649
1655
 
1656
+ const LEADING_TRAILING_SPACES_REGEX = /^\s|\s$/;
1657
+ const MULTIPLE_SPACES_REGEX = /\s{2,}/;
1658
+ function hasExtraSpaces(value) {
1659
+ const hasLeadingOrTrailingSpaces = LEADING_TRAILING_SPACES_REGEX.test(value);
1660
+ const hasMultipleSpaces = MULTIPLE_SPACES_REGEX.test(value);
1661
+ if (hasLeadingOrTrailingSpaces || hasMultipleSpaces) {
1662
+ return { extraSpaces: true };
1663
+ }
1664
+ return null;
1665
+ }
1666
+
1667
+ function asyncExtraSpacesValidators(delay) {
1668
+ return ({ value }) => {
1669
+ return timer(delay).pipe(map(() => hasExtraSpaces(value)));
1670
+ };
1671
+ }
1672
+ function syncExtraSpacesValidator() {
1673
+ return ({ errors, value }) => {
1674
+ if (!errors?.['extraSpaces']) {
1675
+ return null;
1676
+ }
1677
+ return hasExtraSpaces(value);
1678
+ };
1679
+ }
1680
+
1681
+ function createDefaultValidators({ maxLength = 100, asyncDelay = 700 } = {}) {
1682
+ // Need to offset because this delay must be before changing value
1683
+ const OFFSET = 1;
1684
+ const adjustedAsyncDelay = asyncDelay - OFFSET;
1685
+ return {
1686
+ validators: [Validators.required, Validators.maxLength(maxLength), syncExtraSpacesValidator()],
1687
+ asyncValidators: [asyncExtraSpacesValidators(adjustedAsyncDelay)]
1688
+ };
1689
+ }
1690
+
1650
1691
  /**
1651
1692
  * A component to display a tooltip
1652
1693
  */
@@ -1864,7 +1905,10 @@ class CuiTooltipPosition extends CuiPositionAccessor {
1864
1905
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.13", type: CuiTooltipPosition, isStandalone: true, inputs: { direction: ["cuiTooltipDirection", "direction"] }, outputs: { directionChange: "cuiTooltipDirectionChange" }, usesInheritance: true, ngImport: i0 }); }
1865
1906
  }
1866
1907
  __decorate([
1867
- cuiPure
1908
+ cuiPure,
1909
+ __metadata("design:type", Function),
1910
+ __metadata("design:paramtypes", [String]),
1911
+ __metadata("design:returntype", void 0)
1868
1912
  ], CuiTooltipPosition.prototype, "emitDirection", null);
1869
1913
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiTooltipPosition, decorators: [{
1870
1914
  type: Directive,
@@ -2089,7 +2133,10 @@ class CuiTooltipComponent {
2089
2133
  `, isInline: true, styles: [":host{padding:4px 8px;font-weight:400;font-size:14px;line-height:20px;overflow-y:auto;position:absolute;max-inline-size:375px;max-block-size:375px;background:var(--cui-gray-900);border-radius:6px;color:var(--cui-gray-0);box-sizing:border-box;font-family:var(--cui-main-font);white-space:pre-line;overflow-wrap:break-word;transform-origin:var(--left) var(--top)}:host:not([style*=top]){visibility:hidden}:host._untouchable{pointer-events:none}\n"], dependencies: [{ kind: "directive", type: PolymorpheusOutlet, selector: "[polymorpheusOutlet]", inputs: ["polymorpheusOutlet", "polymorpheusOutletContext"] }], animations: [cuiFadeIn, cuiScaleIn], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2090
2134
  }
2091
2135
  __decorate([
2092
- cuiPure
2136
+ cuiPure,
2137
+ __metadata("design:type", Function),
2138
+ __metadata("design:paramtypes", [String, String, Number, Number]),
2139
+ __metadata("design:returntype", void 0)
2093
2140
  ], CuiTooltipComponent.prototype, "apply", null);
2094
2141
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiTooltipComponent, decorators: [{
2095
2142
  type: Component,
@@ -2135,7 +2182,9 @@ class CuiTooltipDescribe extends CuiDriver {
2135
2182
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.13", type: CuiTooltipDescribe, isStandalone: true, selector: "[cuiTooltipDescribe]", inputs: { cuiTooltipDescribe: "cuiTooltipDescribe" }, providers: [cuiAsDriver(CuiTooltipDescribe)], usesInheritance: true, ngImport: i0 }); }
2136
2183
  }
2137
2184
  __decorate([
2138
- cuiPure
2185
+ cuiPure,
2186
+ __metadata("design:type", HTMLElement),
2187
+ __metadata("design:paramtypes", [])
2139
2188
  ], CuiTooltipDescribe.prototype, "element", null);
2140
2189
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiTooltipDescribe, decorators: [{
2141
2190
  type: Directive,
@@ -3008,6 +3057,47 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
3008
3057
  }]
3009
3058
  }] });
3010
3059
 
3060
+ class CuiContentWrapperComponent {
3061
+ constructor() {
3062
+ this.DEFAULT_BACKGROUND_COLOR = 'var(--cui-base-0)';
3063
+ this.DEFAULT_GAP = 8;
3064
+ this.backgroundColor = input(this.DEFAULT_BACKGROUND_COLOR);
3065
+ this.gap = input(this.DEFAULT_GAP);
3066
+ }
3067
+ get _backgroundColor() {
3068
+ return this.backgroundColor();
3069
+ }
3070
+ get _gap() {
3071
+ return this.gap();
3072
+ }
3073
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiContentWrapperComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3074
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.2.13", type: CuiContentWrapperComponent, isStandalone: true, selector: "cui-content-wrapper, [cuiContentWrapper]", inputs: { backgroundColor: { classPropertyName: "backgroundColor", publicName: "backgroundColor", isSignal: true, isRequired: false, transformFunction: null }, gap: { classPropertyName: "gap", publicName: "gap", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.background": "this._backgroundColor", "style.gap.px": "this._gap" } }, ngImport: i0, template: "<ng-content />\r\n", styles: [":host{padding:16px;display:flex;flex-direction:column;gap:16px;border-radius:8px}:host:empty{display:contents}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3075
+ }
3076
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiContentWrapperComponent, decorators: [{
3077
+ type: Component,
3078
+ args: [{ selector: 'cui-content-wrapper, [cuiContentWrapper]', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content />\r\n", styles: [":host{padding:16px;display:flex;flex-direction:column;gap:16px;border-radius:8px}:host:empty{display:contents}\n"] }]
3079
+ }], propDecorators: { _backgroundColor: [{
3080
+ type: HostBinding,
3081
+ args: ['style.background']
3082
+ }], _gap: [{
3083
+ type: HostBinding,
3084
+ args: ['style.gap.px']
3085
+ }] } });
3086
+
3087
+ class CuiGhostInputComponent {
3088
+ constructor() {
3089
+ this.isError = input(false, { transform: booleanAttribute });
3090
+ }
3091
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiGhostInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3092
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.2.13", type: CuiGhostInputComponent, isStandalone: true, selector: "input [cuiGhostInput]", inputs: { isError: { classPropertyName: "isError", publicName: "isError", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class._with-error": "isError()" } }, ngImport: i0, template: '', isInline: true, styles: [":host{padding-right:3px;padding-left:3px;width:100%;border:1px solid transparent;border-radius:8px;outline:none;background:none}:host:focus-visible{box-shadow:0 0 0 2px var(--cui-focus);border-color:var(--cui-info)}:host:disabled{opacity:.5}:host::placeholder{color:var(--cui-base-400)}:host._with-error{border-color:var(--cui-danger)}:host._with-error:focus-visible{box-shadow:0 0 0 2px #d92d2040}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3093
+ }
3094
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiGhostInputComponent, decorators: [{
3095
+ type: Component,
3096
+ args: [{ selector: 'input [cuiGhostInput]', standalone: true, template: '', changeDetection: ChangeDetectionStrategy.OnPush, host: {
3097
+ '[class._with-error]': 'isError()'
3098
+ }, styles: [":host{padding-right:3px;padding-left:3px;width:100%;border:1px solid transparent;border-radius:8px;outline:none;background:none}:host:focus-visible{box-shadow:0 0 0 2px var(--cui-focus);border-color:var(--cui-info)}:host:disabled{opacity:.5}:host::placeholder{color:var(--cui-base-400)}:host._with-error{border-color:var(--cui-danger)}:host._with-error:focus-visible{box-shadow:0 0 0 2px #d92d2040}\n"] }]
3099
+ }] });
3100
+
3011
3101
  class CuiInputPasswordComponent {
3012
3102
  constructor() {
3013
3103
  this.changeDetectorRef = inject(ChangeDetectorRef);
@@ -3620,6 +3710,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
3620
3710
  }]
3621
3711
  }] });
3622
3712
 
3713
+ class CuiEmptyStateComponent {
3714
+ constructor() {
3715
+ this.title = input();
3716
+ this.subtitle = input();
3717
+ }
3718
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiEmptyStateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3719
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: CuiEmptyStateComponent, isStandalone: true, selector: "cui-empty-state, [cuiEmptyState]", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, subtitle: { classPropertyName: "subtitle", publicName: "subtitle", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class._with-title": "!!this.title()" } }, ngImport: i0, template: "@if (title(); as title) {\r\n <p class=\"title\">{{ title }}</p>\r\n}\r\n@if (subtitle(); as subtitle) {\r\n <p class=\"subtitle\">{{ subtitle }}</p>\r\n}\r\n<ng-content />\r\n", styles: [":host{--padding-vertical: 24px;--padding-horizontal: 0;display:flex;flex-direction:column;gap:16px;align-items:center;justify-content:center;padding:16px;margin:auto;height:100%;text-align:center}:host._with-title{padding:var(--padding-vertical) var(--padding-horizontal)}.title,.subtitle{margin:0}.title{font-weight:500;font-size:16px;line-height:24px}.subtitle{font-weight:400;font-size:14px;line-height:20px;color:var(--cui-base-500)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3720
+ }
3721
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiEmptyStateComponent, decorators: [{
3722
+ type: Component,
3723
+ args: [{ selector: 'cui-empty-state, [cuiEmptyState]', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, host: {
3724
+ '[class._with-title]': '!!this.title()'
3725
+ }, template: "@if (title(); as title) {\r\n <p class=\"title\">{{ title }}</p>\r\n}\r\n@if (subtitle(); as subtitle) {\r\n <p class=\"subtitle\">{{ subtitle }}</p>\r\n}\r\n<ng-content />\r\n", styles: [":host{--padding-vertical: 24px;--padding-horizontal: 0;display:flex;flex-direction:column;gap:16px;align-items:center;justify-content:center;padding:16px;margin:auto;height:100%;text-align:center}:host._with-title{padding:var(--padding-vertical) var(--padding-horizontal)}.title,.subtitle{margin:0}.title{font-weight:500;font-size:16px;line-height:24px}.subtitle{font-weight:400;font-size:14px;line-height:20px;color:var(--cui-base-500)}\n"] }]
3726
+ }] });
3727
+
3623
3728
  const IS_SIDEBAR_OPENED_STORAGE_KEY = 'is-sidebar-opened';
3624
3729
 
3625
3730
  class CuiRenderDynamicComponentsService {
@@ -3948,64 +4053,3961 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
3948
4053
  }]
3949
4054
  }] });
3950
4055
 
3951
- const cuiXNdjsonInterceptor = (request, next) => {
3952
- if (request.headers.get('Content-Type') !== 'application/x-ndjson') {
3953
- return next(request);
4056
+ const COMBINED_TEXT_BLOCK_PART = 'combined-text-block-part';
4057
+ const COMBINED_TEXT_BLOCK = 'combined-text-block';
4058
+ const COMBINED_TEXT_BLOCK_NAME = 'paragraph';
4059
+ const COMBINED_TEXT_BLOCK_ADDED = 'combinedTextBlockAdded';
4060
+ const COMBINED_TEXT_BLOCK_UPDATED = 'combinedTextBlockUpdated';
4061
+ const COMBINED_TEXT_BLOCK_REMOVED = 'combinedTextBlockRemoved';
4062
+ const SPLIT_MAX_LENGTH = 1000;
4063
+ const SPLIT_LENGTH = 500;
4064
+ const EDITOR_SELECTOR = '[data-editor]';
4065
+ const DEFAULT_PLACEHOLDER = "Type text or '/' for commands...";
4066
+ const DEFAULT_READONLY_PLACEHOLDER = "No 'Description' was provided";
4067
+ const DEFAULT_CONFIG = {
4068
+ tools: {},
4069
+ readOnly: false,
4070
+ autofocus: false
4071
+ };
4072
+ const CuiEditorTranslations = {
4073
+ en: import('./cuby-ui-core-en-D3DnyYmu.mjs'),
4074
+ };
4075
+
4076
+ class CuiHeaderTool extends Header {
4077
+ constructor(data) {
4078
+ super(data);
3954
4079
  }
3955
- return new Observable((observer) => {
3956
- const controller = new AbortController();
3957
- const signal = controller.signal;
3958
- (async () => {
3959
- try {
3960
- const response = await fetch(request.urlWithParams, {
3961
- method: request.method,
3962
- headers: request.headers.keys().reduce((headers, key) => {
3963
- headers[key] = request.headers.get(key);
3964
- return headers;
3965
- }, {}),
3966
- body: request.body ? JSON.stringify(request.body) : null,
3967
- signal
3968
- });
3969
- if (!response.ok) {
3970
- const error = await response.json();
3971
- observer.error(new HttpErrorResponse({ error }));
4080
+ validate() {
4081
+ return true;
4082
+ }
4083
+ render() {
4084
+ return super.render();
4085
+ }
4086
+ save(block) {
4087
+ return super.save(block);
4088
+ }
4089
+ }
4090
+
4091
+ class CuiListTool extends List {
4092
+ constructor(data) {
4093
+ super(data);
4094
+ }
4095
+ render() {
4096
+ return super.render();
4097
+ }
4098
+ }
4099
+
4100
+ class CuiSelectionBase {
4101
+ static get isInline() {
4102
+ return true;
4103
+ }
4104
+ get state() {
4105
+ return this._state;
4106
+ }
4107
+ set state(state) {
4108
+ this._state = state;
4109
+ this.button?.classList.toggle(this.api.styles.inlineToolButtonActive, state);
4110
+ }
4111
+ constructor(data) {
4112
+ this.LIST_CLASS = 'cdx-list__item';
4113
+ this.SELECTED_TEXT_CLASS = '_selected';
4114
+ this.TAG = 'B';
4115
+ this.COMMAND = 'bold';
4116
+ this._state = false;
4117
+ this.api = data.api;
4118
+ }
4119
+ wrap(range) {
4120
+ const { startContainer, endContainer } = range;
4121
+ this.addSelectionToDOM(range, startContainer, endContainer);
4122
+ }
4123
+ unwrap() {
4124
+ document.execCommand(this.COMMAND);
4125
+ }
4126
+ checkState() {
4127
+ this.state = document.queryCommandState(this.COMMAND);
4128
+ return this.state;
4129
+ }
4130
+ surround(range) {
4131
+ if (this.state) {
4132
+ this.unwrap();
4133
+ return;
4134
+ }
4135
+ this.wrap(range);
4136
+ }
4137
+ createElement(text = '') {
4138
+ const element = document.createElement(this.TAG);
4139
+ element.textContent = text;
4140
+ return element;
4141
+ }
4142
+ addSelectionToDOM(range, startBlock, endBlock) {
4143
+ const classes = [this.LIST_CLASS, COMBINED_TEXT_BLOCK_PART];
4144
+ const { className, parent: startParent } = this.getClosestParentWithClass(startBlock, classes);
4145
+ const { parent: endParent } = this.getClosestParentWithClass(endBlock, classes);
4146
+ if (!className || startParent === endParent) {
4147
+ this.addSelectionForOnlyChild(range);
4148
+ return;
4149
+ }
4150
+ this.addSelectionForChildren(startParent, endParent);
4151
+ }
4152
+ addSelectionForOnlyChild(range) {
4153
+ const selectedText = range.extractContents();
4154
+ const selection = this.createElement();
4155
+ selection.appendChild(selectedText);
4156
+ range.insertNode(selection);
4157
+ }
4158
+ addSelectionForChildren(startParent, endParent) {
4159
+ const nodes = this.getSelectedNodesFromDOM(startParent, endParent);
4160
+ nodes.forEach((node) => node.classList.add(this.SELECTED_TEXT_CLASS));
4161
+ document.execCommand(this.COMMAND);
4162
+ nodes.forEach((node) => node.classList.remove(this.SELECTED_TEXT_CLASS));
4163
+ }
4164
+ getSelectedNodesFromDOM(startParent, endParent) {
4165
+ const nodes = [startParent];
4166
+ let next = startParent.nextSibling;
4167
+ while (next && next !== endParent) {
4168
+ nodes.push(next);
4169
+ next = next?.nextSibling || null;
4170
+ }
4171
+ nodes.push(endParent);
4172
+ return nodes;
4173
+ }
4174
+ getClosestParentWithClass(node, classes) {
4175
+ const nodeParent = node.parentElement;
4176
+ let parent = nodeParent;
4177
+ let resultClassName = '';
4178
+ for (const className of classes) {
4179
+ const parentWithClass = parent.closest('.' + className);
4180
+ if (!parentWithClass) {
4181
+ continue;
4182
+ }
4183
+ parent = parentWithClass;
4184
+ resultClassName = className;
4185
+ break;
4186
+ }
4187
+ return { className: resultClassName, parent };
4188
+ }
4189
+ }
4190
+
4191
+ class CuiBoldInlineTool extends CuiSelectionBase {
4192
+ static { this.title = 'Bold'; }
4193
+ static get sanitize() {
4194
+ return {
4195
+ b: {}
4196
+ };
4197
+ }
4198
+ constructor(data) {
4199
+ super(data);
4200
+ this.COMMAND = 'bold';
4201
+ this.CSS = {
4202
+ button: 'ce-inline-tool',
4203
+ buttonActive: 'ce-inline-tool--active',
4204
+ buttonModifier: 'ce-inline-tool--bold'
4205
+ };
4206
+ }
4207
+ render() {
4208
+ this.button = document.createElement('button');
4209
+ this.button.type = 'button';
4210
+ this.button.classList.add(this.CSS.button, this.CSS.buttonModifier);
4211
+ /* eslint-disable */
4212
+ this.button.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
4213
+ <path d="M7.5 10.0002V5.91683C7.5 5.8708 7.53731 5.8335 7.58333 5.8335H8.66667C9.58333 5.8335 11.6667 5.91683 11.6667 7.91683C11.6667 7.91683 11.6667 10.0002 9.16667 10.0002M7.5 10.0002V14.0002C7.5 14.0922 7.57462 14.1668 7.66667 14.1668H10.4167C11.6667 14.1668 12.5 13.3335 12.5 12.0835C12.5 9.754 9.16667 10.0002 9.16667 10.0002M7.5 10.0002H9.16667" stroke="#121315" stroke-width="1.66667" stroke-linecap="round"/>
4214
+ </svg>`;
4215
+ /* eslint-enable */
4216
+ return this.button;
4217
+ }
4218
+ get shortcut() {
4219
+ return 'CMD+B';
4220
+ }
4221
+ }
4222
+
4223
+ class CuiItalicInlineTool extends CuiSelectionBase {
4224
+ static { this.title = 'Italic'; }
4225
+ static get sanitize() {
4226
+ return {
4227
+ i: {}
4228
+ };
4229
+ }
4230
+ constructor(data) {
4231
+ super(data);
4232
+ this.COMMAND = 'italic';
4233
+ this.TAG = 'I';
4234
+ this.CSS = {
4235
+ button: 'ce-inline-tool',
4236
+ buttonActive: 'ce-inline-tool--active',
4237
+ buttonModifier: 'ce-inline-tool--italic'
4238
+ };
4239
+ }
4240
+ render() {
4241
+ this.button = document.createElement('button');
4242
+ this.button.type = 'button';
4243
+ this.button.classList.add(this.CSS.button, this.CSS.buttonModifier);
4244
+ /* eslint-disable */
4245
+ this.button.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
4246
+ <path d="M11.118 8.3335C10.3532 10.6116 9.16797 14.1668 9.16797 14.1668" stroke="#121315" stroke-width="1.66667" stroke-linecap="round"/>
4247
+ <path d="M11.8404 5.8335H11.832" stroke="#121315" stroke-width="1.66667" stroke-linecap="round"/>
4248
+ </svg>`;
4249
+ /* eslint-enable */
4250
+ return this.button;
4251
+ }
4252
+ get shortcut() {
4253
+ return 'CMD+I';
4254
+ }
4255
+ }
4256
+
4257
+ function urlValidator() {
4258
+ return ({ value }) => {
4259
+ try {
4260
+ new URL(value);
4261
+ return null;
4262
+ }
4263
+ catch {
4264
+ return { url: true };
4265
+ }
4266
+ };
4267
+ }
4268
+
4269
+ const BlockConversionToCombined = {
4270
+ paragraph: 'combinedTextBlock'
4271
+ };
4272
+
4273
+ function generateId() {
4274
+ return '_' + Math.random().toString(36).substring(2, 9);
4275
+ }
4276
+
4277
+ class CuiJTextApiService {
4278
+ constructor() {
4279
+ this.httpClient = inject(HttpClient);
4280
+ this.GET_BLOCK_DEFAULT_SIZE = 40;
4281
+ this.JTEXT_URL = 'framer/jtext';
4282
+ this.BLOCK_URL = 'block';
4283
+ this.BLOCKS_URL = 'blocks';
4284
+ this.JTEXT_BLOCK_URL = this.JTEXT_URL + '/' + this.BLOCK_URL;
4285
+ this.JTEXT_BLOCKS_URL = this.JTEXT_URL + '/' + this.BLOCKS_URL;
4286
+ this.options = {};
4287
+ }
4288
+ addOptions(options) {
4289
+ this.options = options ?? {};
4290
+ }
4291
+ createBlock(body) {
4292
+ return this.httpClient.post(this.JTEXT_BLOCK_URL, body, this.options);
4293
+ }
4294
+ updateBlock(body) {
4295
+ return this.httpClient.patch(this.JTEXT_BLOCK_URL, body, this.options);
4296
+ }
4297
+ getBlocks(fragmentId, page = 0, sizeBlock = this.GET_BLOCK_DEFAULT_SIZE) {
4298
+ return this.httpClient.get(`${this.JTEXT_URL}/${fragmentId}`, {
4299
+ params: { page, sizeBlock },
4300
+ headers: { 'Content-Type': 'application/x-ndjson' },
4301
+ observe: 'events',
4302
+ ...this.options
4303
+ });
4304
+ }
4305
+ createBlocks(body) {
4306
+ return this.httpClient.post(this.JTEXT_BLOCKS_URL, body, this.options);
4307
+ }
4308
+ deleteBlock(containerId, blockId) {
4309
+ return this.httpClient.delete(`${this.JTEXT_URL}/${containerId}/${this.BLOCK_URL}/${blockId}`, this.options);
4310
+ }
4311
+ deleteBlocks(containerId, blocksIds) {
4312
+ return this.httpClient.delete(`${this.JTEXT_URL}/${containerId}/${this.BLOCKS_URL}`, {
4313
+ params: { blocksIds },
4314
+ ...this.options
4315
+ });
4316
+ }
4317
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiJTextApiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4318
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiJTextApiService }); }
4319
+ }
4320
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiJTextApiService, decorators: [{
4321
+ type: Injectable
4322
+ }] });
4323
+
4324
+ class CuiEditorService {
4325
+ constructor() {
4326
+ this.destroyRef = inject(DestroyRef);
4327
+ this.jtextService = inject(CuiJTextApiService);
4328
+ }
4329
+ sortEventsByTypes(events) {
4330
+ const blocks = {
4331
+ 'block-removed': [],
4332
+ 'block-added': [],
4333
+ 'block-changed': []
4334
+ };
4335
+ events.forEach((editorEvent) => {
4336
+ if (editorEvent.detail.target.name === COMBINED_TEXT_BLOCK_NAME) {
4337
+ return;
4338
+ }
4339
+ const eventType = editorEvent.type;
4340
+ if (eventType === "block-changed" /* EventActions.update */) {
4341
+ const changedBlock = blocks["block-added" /* EventActions.add */].find((block) => block.detail.target.id === editorEvent.detail.target.id);
4342
+ if (changedBlock) {
3972
4343
  return;
3973
4344
  }
3974
- const reader = response.body.getReader();
3975
- const decoder = new TextDecoder();
3976
- let buffer = '';
3977
- for (;;) {
3978
- const { done, value } = await reader.read();
3979
- if (done) {
3980
- observer.complete();
3981
- return;
3982
- }
3983
- buffer += decoder.decode(value);
3984
- const lines = buffer.split('\n');
3985
- buffer = lines.pop() ?? '';
3986
- lines.forEach((line) => observer.next(JSON.parse(line)));
4345
+ }
4346
+ if (eventType === "block-removed" /* EventActions.remove */) {
4347
+ const len = blocks["block-added" /* EventActions.add */].length;
4348
+ blocks["block-added" /* EventActions.add */] = blocks["block-added" /* EventActions.add */].filter((block) => block.detail.target.id !== editorEvent.detail.target.id);
4349
+ if (len > blocks["block-added" /* EventActions.add */].length) {
4350
+ return;
3987
4351
  }
3988
4352
  }
3989
- catch (error) {
3990
- observer.error(new HttpErrorResponse({ error }));
4353
+ blocks[eventType].push(editorEvent);
4354
+ });
4355
+ return blocks;
4356
+ }
4357
+ collectAddedBlocksRequest(editorId, addedBlocks) {
4358
+ const addBlocksBody = {
4359
+ jtextContainerId: editorId,
4360
+ position: addedBlocks[0]?.index,
4361
+ block: addedBlocks.map((e) => e.block)
4362
+ };
4363
+ const addBlocks$ = addedBlocks.length ? this.jtextService.createBlocks(addBlocksBody) : of([]);
4364
+ return addBlocks$;
4365
+ }
4366
+ collectUpdatedBlocksRequest(updatedBlocks, blockIdsMap) {
4367
+ const updatedBlocksWithId = updatedBlocks.reduce((acc, block) => {
4368
+ const blockWithId = {
4369
+ ...block,
4370
+ id: blockIdsMap.get(block.id)
4371
+ };
4372
+ if (blockWithId.id) {
4373
+ acc.push(blockWithId);
3991
4374
  }
3992
- })();
3993
- return () => controller.abort();
3994
- });
3995
- };
4375
+ return acc;
4376
+ }, []);
4377
+ const updateBlocksArray = updatedBlocksWithId.map((block) => this.jtextService.updateBlock(block));
4378
+ const updateBlocks$ = updatedBlocksWithId.length ? forkJoin(updateBlocksArray) : of([]);
4379
+ return updateBlocks$;
4380
+ }
4381
+ collectRemovedBlocksRequest(editorId, removedBlocksIds, blockIdsMap) {
4382
+ const removedBlocks = removedBlocksIds.reduce((blockIds, blockId) => {
4383
+ const backendID = blockIdsMap.get(blockId);
4384
+ if (backendID) {
4385
+ blockIds.push(backendID);
4386
+ }
4387
+ return blockIds;
4388
+ }, []);
4389
+ const removeBlocks$ = removedBlocks.length ? this.jtextService.deleteBlocks(editorId, removedBlocks) : of();
4390
+ removedBlocks.forEach((removedBlock) => {
4391
+ blockIdsMap.delete(removedBlock);
4392
+ });
4393
+ return removeBlocks$;
4394
+ }
4395
+ getFullBlockData(event, editorData) {
4396
+ const target = event.detail.target;
4397
+ const index = Number(target.holder.dataset['index']);
4398
+ const blockIndex = event.detail.index;
4399
+ const blockType = target.name;
4400
+ const blockId = target.id;
4401
+ const currentBlockByIndex = editorData.blocks[blockIndex];
4402
+ const blockData = currentBlockByIndex?.id === blockId ? editorData.blocks[blockIndex].data : { text: '' };
4403
+ return {
4404
+ index,
4405
+ id: blockId,
4406
+ block: {
4407
+ type: blockType,
4408
+ data: blockData
4409
+ }
4410
+ };
4411
+ }
4412
+ setListenersOnCustomBlockChanges(editor, data) {
4413
+ editor.on(COMBINED_TEXT_BLOCK_ADDED, data.addedCallback);
4414
+ editor.on(COMBINED_TEXT_BLOCK_UPDATED, data.updatedCallback);
4415
+ editor.on(COMBINED_TEXT_BLOCK_REMOVED, data.removedCallback);
4416
+ }
4417
+ setStartBlock(editorId, callback) {
4418
+ const blockId = generateId();
4419
+ const emptyBlock = {
4420
+ type: COMBINED_TEXT_BLOCK_PART,
4421
+ data: {
4422
+ text: '',
4423
+ parentId: blockId,
4424
+ parentType: COMBINED_TEXT_BLOCK_NAME
4425
+ }
4426
+ };
4427
+ const body = {
4428
+ position: 0,
4429
+ block: emptyBlock,
4430
+ jtextContainerId: editorId
4431
+ };
4432
+ this.jtextService
4433
+ .createBlock(body)
4434
+ .pipe(takeUntilDestroyed(this.destroyRef))
4435
+ .subscribe((id) => {
4436
+ emptyBlock.id = id;
4437
+ const block = {
4438
+ id: blockId,
4439
+ type: COMBINED_TEXT_BLOCK_NAME,
4440
+ data: {
4441
+ id: blockId,
4442
+ textBlocks: [emptyBlock]
4443
+ }
4444
+ };
4445
+ callback(block, id);
4446
+ });
4447
+ }
4448
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiEditorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4449
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiEditorService }); }
4450
+ }
4451
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiEditorService, decorators: [{
4452
+ type: Injectable
4453
+ }] });
3996
4454
 
3997
- const cuiLoaderInterceptor = (request, next) => {
3998
- const loaderService = inject(LoaderService);
3999
- if (request.method === 'GET') {
4000
- return next(request);
4455
+ class CuiMarkersService {
4456
+ constructor() {
4457
+ this.roles = [];
4458
+ this.tools = [
4459
+ {
4460
+ id: '0',
4461
+ image: 'blob:https://www.figma.com/f985f4fc-abc6-4727-857e-80633836e2b2',
4462
+ title: 'Шуруповерт',
4463
+ type: "tool" /* MarkerType.tool */
4464
+ },
4465
+ {
4466
+ id: '1',
4467
+ image: 'blob:https://www.figma.com/92ad9b38-566c-4ff6-84ba-0b20b24fef39',
4468
+ title: 'Молоток',
4469
+ type: "tool" /* MarkerType.tool */
4470
+ },
4471
+ {
4472
+ id: '2',
4473
+ image: '/assets/image 545.png',
4474
+ title: 'Лопата',
4475
+ type: "tool" /* MarkerType.tool */
4476
+ },
4477
+ {
4478
+ id: '3',
4479
+ image: '/assets/image 545.png',
4480
+ title: 'Лопата',
4481
+ type: "tool" /* MarkerType.tool */
4482
+ },
4483
+ {
4484
+ id: '4',
4485
+ image: '/assets/image 545.png',
4486
+ title: 'Лопата',
4487
+ type: "tool" /* MarkerType.tool */
4488
+ },
4489
+ {
4490
+ id: '5',
4491
+ image: '/assets/image 545.png',
4492
+ title: 'Лопата',
4493
+ type: "tool" /* MarkerType.tool */
4494
+ },
4495
+ {
4496
+ id: '6',
4497
+ image: '/assets/image 545.png',
4498
+ title: 'Лопата',
4499
+ type: "tool" /* MarkerType.tool */
4500
+ },
4501
+ {
4502
+ id: '7',
4503
+ image: '/assets/image 545.png',
4504
+ title: 'Лопата',
4505
+ type: "tool" /* MarkerType.tool */
4506
+ },
4507
+ {
4508
+ id: '8',
4509
+ image: '/assets/image 545.png',
4510
+ title: 'Лопата',
4511
+ type: "tool" /* MarkerType.tool */
4512
+ }
4513
+ ];
4001
4514
  }
4002
- loaderService.setLoading();
4003
- return next(request).pipe(catchError(throwError), finalize(loaderService.handleCompletedRequest.bind(loaderService)));
4004
- };
4515
+ getMarkersByType(type) {
4516
+ return type === "role" /* MarkerType.role */ ? this.roles : this.tools;
4517
+ }
4518
+ getMarkerObjectByType(type, id) {
4519
+ const markersArray = this.getMarkersByType(type);
4520
+ return markersArray.find((marker) => marker.id === id);
4521
+ }
4522
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiMarkersService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4523
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiMarkersService, providedIn: 'root' }); }
4524
+ }
4525
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiMarkersService, decorators: [{
4526
+ type: Injectable,
4527
+ args: [{
4528
+ providedIn: 'root'
4529
+ }]
4530
+ }] });
4531
+
4532
+ class SelectOptionComponent {
4533
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SelectOptionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4534
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: SelectOptionComponent, isStandalone: true, selector: "cc-select-option", inputs: { tool: "tool" }, ngImport: i0, template: "<ng-container *ngIf=\"tool\">\r\n <img\r\n *ngIf=\"tool.image\"\r\n class=\"image\"\r\n [src]=\"tool.image\"\r\n alt=\"\"\r\n />\r\n <h3 class=\"title\">{{ tool.title }}</h3>\r\n</ng-container>\r\n", styles: [":host{padding:4px 8px;cursor:pointer;display:flex;align-items:center;gap:8px;border-radius:8px}@media (hover: hover){:host:hover{background-color:var(--cui-base-50)}}:host:active{background-color:var(--cui-base-50)}.title{font-weight:400;font-size:14px;line-height:20px;padding-top:2px;padding-bottom:2px;color:var(--cui-base-900)}.image{width:23px;height:23px;object-fit:cover;object-position:center}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4535
+ }
4536
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SelectOptionComponent, decorators: [{
4537
+ type: Component,
4538
+ args: [{ selector: 'cc-select-option', standalone: true, imports: [NgIf], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *ngIf=\"tool\">\r\n <img\r\n *ngIf=\"tool.image\"\r\n class=\"image\"\r\n [src]=\"tool.image\"\r\n alt=\"\"\r\n />\r\n <h3 class=\"title\">{{ tool.title }}</h3>\r\n</ng-container>\r\n", styles: [":host{padding:4px 8px;cursor:pointer;display:flex;align-items:center;gap:8px;border-radius:8px}@media (hover: hover){:host:hover{background-color:var(--cui-base-50)}}:host:active{background-color:var(--cui-base-50)}.title{font-weight:400;font-size:14px;line-height:20px;padding-top:2px;padding-bottom:2px;color:var(--cui-base-900)}.image{width:23px;height:23px;object-fit:cover;object-position:center}\n"] }]
4539
+ }], propDecorators: { tool: [{
4540
+ type: Input,
4541
+ args: [{ required: true }]
4542
+ }] } });
4543
+
4544
+ class MarkerSelectComponent {
4545
+ constructor() {
4546
+ this.document = inject(DOCUMENT);
4547
+ this.destroyRef = inject(DestroyRef);
4548
+ this.cuiClickOutsideDirective = inject(CuiClickOutsideDirective, { self: true });
4549
+ this.element = inject(ElementRef).nativeElement;
4550
+ this.markersService = inject(CuiMarkersService);
4551
+ this.SPACE_BETWEEN_TARGET_AND_LIST = 5;
4552
+ this.isVisible = signal(false);
4553
+ this.isHidden = signal(true);
4554
+ // TODO: set current type
4555
+ this.elements = this.markersService.getMarkersByType("tool" /* MarkerType.tool */);
4556
+ this.targetToggleEventListener = () => {
4557
+ this.isVisible.update((prev) => !prev);
4558
+ if (!this.isVisible()) {
4559
+ return;
4560
+ }
4561
+ this.calculateDropdownPosition();
4562
+ };
4563
+ }
4564
+ set space(value) {
4565
+ this.SPACE_BETWEEN_TARGET_AND_LIST = value;
4566
+ }
4567
+ get hide() {
4568
+ return this.isHidden();
4569
+ }
4570
+ writeValue(value) {
4571
+ this.value = value;
4572
+ }
4573
+ registerOnChange(fn) {
4574
+ this.onChange = fn;
4575
+ }
4576
+ registerOnTouched(fn) {
4577
+ this.onTouched = fn;
4578
+ }
4579
+ onScroll() {
4580
+ this.isVisible.set(false);
4581
+ }
4582
+ ngOnInit() {
4583
+ this.initTargetElementListener();
4584
+ this.initClickOutsideSubscription();
4585
+ this.initOnCloseWhenEditorScroll();
4586
+ }
4587
+ ngOnDestroy() {
4588
+ this.destroyEventListeners();
4589
+ }
4590
+ onToolClick(tool) {
4591
+ this.value = tool;
4592
+ this.onChange(this.value);
4593
+ this.onTouched();
4594
+ // this.isVisible.set(false);
4595
+ }
4596
+ initTargetElementListener() {
4597
+ this.target.addEventListener('click', this.targetToggleEventListener);
4598
+ }
4599
+ initClickOutsideSubscription() {
4600
+ this.cuiClickOutsideDirective.cuiClickOutside.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((target) => {
4601
+ if (this.target.contains(target) || !this.isVisible()) {
4602
+ return;
4603
+ }
4604
+ this.isVisible.set(false);
4605
+ });
4606
+ }
4607
+ initOnCloseWhenEditorScroll() {
4608
+ this.editor = this.element.closest(EDITOR_SELECTOR);
4609
+ this.editor?.addEventListener('scroll', this.onScroll.bind(this));
4610
+ }
4611
+ destroyEventListeners() {
4612
+ this.editor?.removeEventListener('scroll', this.onScroll.bind(this));
4613
+ this.target?.addEventListener('click', this.targetToggleEventListener);
4614
+ }
4615
+ calculateDropdownPosition() {
4616
+ this.isHidden.set(true);
4617
+ setTimeout(() => {
4618
+ const target = this.target;
4619
+ const { bottom: targetRectBottom, left: targetRectLeft } = target.getBoundingClientRect();
4620
+ const { clientHeight: documentClientHeight, clientWidth: documentClientWidth } = this.document.documentElement;
4621
+ const distanceToBottom = documentClientHeight - (targetRectBottom + this.SPACE_BETWEEN_TARGET_AND_LIST);
4622
+ const distanceToRight = documentClientWidth - targetRectLeft;
4623
+ const isListRight = distanceToRight < this.element.offsetWidth;
4624
+ const isListAbove = distanceToBottom < this.element.offsetHeight;
4625
+ this.changePositionY(isListAbove, target.offsetHeight, targetRectBottom);
4626
+ this.changePositionX(isListRight, target.offsetWidth, targetRectLeft);
4627
+ this.isHidden.set(false);
4628
+ });
4629
+ }
4630
+ changePositionX(isListRight, width, left) {
4631
+ if (isListRight) {
4632
+ this.element.style.right = 'auto';
4633
+ this.element.style.left = left;
4634
+ return;
4635
+ }
4636
+ this.element.style.right = left - this.element.offsetWidth + width;
4637
+ this.element.style.left = 'auto';
4638
+ }
4639
+ changePositionY(isListAbove, height, bottom) {
4640
+ if (isListAbove) {
4641
+ this.element.style.top =
4642
+ bottom - this.element.offsetHeight - height - this.SPACE_BETWEEN_TARGET_AND_LIST + 'px';
4643
+ return;
4644
+ }
4645
+ this.element.style.top = bottom + this.SPACE_BETWEEN_TARGET_AND_LIST + 'px';
4646
+ }
4647
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MarkerSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4648
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: MarkerSelectComponent, isStandalone: true, selector: "cc-marker-select", inputs: { target: "target", space: "space" }, host: { properties: { "class._hidden": "this.hide" } }, providers: [
4649
+ {
4650
+ provide: NG_VALUE_ACCESSOR,
4651
+ useExisting: forwardRef(() => MarkerSelectComponent),
4652
+ multi: true
4653
+ }
4654
+ ], hostDirectives: [{ directive: i1$1.CuiClickOutsideDirective }], ngImport: i0, template: "<ng-container *ngIf=\"isVisible()\">\r\n <div\r\n #dropdown\r\n class=\"dropdown\"\r\n >\r\n <header class=\"header\">\r\n <cui-input-text\r\n class=\"header__input\"\r\n cuiTextFieldId=\"estimated\"\r\n cuiTextFieldPlaceholder=\"Search...\"\r\n />\r\n <button\r\n cuiButton\r\n type=\"button\"\r\n appearance=\"ghost\"\r\n size=\"xxs\"\r\n icon=\"cuiIconFiltersLines\"\r\n ></button>\r\n </header>\r\n <div class=\"scrollable-content\">\r\n <cc-select-option\r\n *ngFor=\"let element of elements\"\r\n [class._selected]=\"element.id === value?.id\"\r\n (click)=\"onToolClick(element)\"\r\n [tool]=\"element\"\r\n />\r\n </div>\r\n </div>\r\n</ng-container>\r\n", styles: [":host{position:fixed;z-index:10;left:0}:host._hidden{visibility:hidden}._selected{background-color:var(--cui-base-50)}.dropdown{box-shadow:0 1px 4px #0000000a,0 1px 4px #0000000a;padding-top:3px;padding-bottom:3px;display:flex;flex-direction:column;gap:4px;border-radius:8px;border:1px solid var(--cui-base-200);max-height:350px;width:345px;background:var(--cui-base-0)}.header{padding:4px 5px;display:flex;align-items:center;gap:4px}.header__input{width:100%}.footer{padding:2px 5px}.title{font-weight:400;font-size:14px;line-height:20px;padding:2px 8px;color:var(--cui-base-500);text-transform:uppercase}.scrollable-content{padding-left:5px;overflow:auto}\n"], dependencies: [{ kind: "ngmodule", type: CuiButtonModule }, { kind: "component", type: CuiButtonComponent, selector: "button[cuiButton], a[cuiButton]", inputs: ["shape", "disabled", "isLoaderShown", "icon", "iconRight", "appearance", "size"] }, { kind: "ngmodule", type: CuiContextMenuModule }, { kind: "ngmodule", type: CuiInputModule }, { kind: "component", type: CuiInputTextComponent, selector: "cui-input-text" }, { kind: "directive", type: CuiTextFieldIdDirective, selector: "[cuiTextFieldId]", inputs: ["cuiTextFieldId"] }, { kind: "directive", type: CuiTextFieldPlaceholderDirective, selector: "[cuiTextFieldPlaceholder]", inputs: ["cuiTextFieldPlaceholder"] }, { kind: "ngmodule", type: CuiLabelModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: SelectOptionComponent, selector: "cc-select-option", inputs: ["tool"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4655
+ }
4656
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MarkerSelectComponent, decorators: [{
4657
+ type: Component,
4658
+ args: [{ selector: 'cc-marker-select', imports: [
4659
+ CuiButtonModule,
4660
+ CuiContextMenuModule,
4661
+ CuiInputModule,
4662
+ CuiLabelModule,
4663
+ FormsModule,
4664
+ ReactiveFormsModule,
4665
+ SelectOptionComponent,
4666
+ NgIf,
4667
+ NgFor
4668
+ ], standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, hostDirectives: [CuiClickOutsideDirective], providers: [
4669
+ {
4670
+ provide: NG_VALUE_ACCESSOR,
4671
+ useExisting: forwardRef(() => MarkerSelectComponent),
4672
+ multi: true
4673
+ }
4674
+ ], template: "<ng-container *ngIf=\"isVisible()\">\r\n <div\r\n #dropdown\r\n class=\"dropdown\"\r\n >\r\n <header class=\"header\">\r\n <cui-input-text\r\n class=\"header__input\"\r\n cuiTextFieldId=\"estimated\"\r\n cuiTextFieldPlaceholder=\"Search...\"\r\n />\r\n <button\r\n cuiButton\r\n type=\"button\"\r\n appearance=\"ghost\"\r\n size=\"xxs\"\r\n icon=\"cuiIconFiltersLines\"\r\n ></button>\r\n </header>\r\n <div class=\"scrollable-content\">\r\n <cc-select-option\r\n *ngFor=\"let element of elements\"\r\n [class._selected]=\"element.id === value?.id\"\r\n (click)=\"onToolClick(element)\"\r\n [tool]=\"element\"\r\n />\r\n </div>\r\n </div>\r\n</ng-container>\r\n", styles: [":host{position:fixed;z-index:10;left:0}:host._hidden{visibility:hidden}._selected{background-color:var(--cui-base-50)}.dropdown{box-shadow:0 1px 4px #0000000a,0 1px 4px #0000000a;padding-top:3px;padding-bottom:3px;display:flex;flex-direction:column;gap:4px;border-radius:8px;border:1px solid var(--cui-base-200);max-height:350px;width:345px;background:var(--cui-base-0)}.header{padding:4px 5px;display:flex;align-items:center;gap:4px}.header__input{width:100%}.footer{padding:2px 5px}.title{font-weight:400;font-size:14px;line-height:20px;padding:2px 8px;color:var(--cui-base-500);text-transform:uppercase}.scrollable-content{padding-left:5px;overflow:auto}\n"] }]
4675
+ }], propDecorators: { target: [{
4676
+ type: Input
4677
+ }], space: [{
4678
+ type: Input
4679
+ }], hide: [{
4680
+ type: HostBinding,
4681
+ args: ['class._hidden']
4682
+ }] } });
4683
+
4684
+ const MARKER_SELECT_SELECTOR = 'marker-select';
4685
+
4686
+ class MarkerModalComponent {
4687
+ constructor() {
4688
+ this.element = inject(ElementRef).nativeElement;
4689
+ this.document = inject(DOCUMENT);
4690
+ this.destroyRef = inject(DestroyRef);
4691
+ this.cuiClickOutsideDirective = inject(CuiClickOutsideDirective, { self: true });
4692
+ this.cuiIdService = inject(CuiIdService);
4693
+ this.markersService = inject(CuiMarkersService);
4694
+ this.TITLE_MAX_LENGTH = 100;
4695
+ this.formTitle = signal('');
4696
+ this.isTitleEmpty = computed(() => !this.formTitle().length);
4697
+ this.isTitleMoreThanMaxLength = computed(() => this.formTitle().length > this.TITLE_MAX_LENGTH);
4698
+ this.isTitleInvalid = computed(() => this.isTitleEmpty() || this.isTitleMoreThanMaxLength());
4699
+ this.titleId = this.cuiIdService.generate();
4700
+ this.dataId = this.cuiIdService.generate();
4701
+ this.spaceBetweenTargetAndList = 5;
4702
+ this.startTitle = '';
4703
+ this.isGlobal = false;
4704
+ this.isTool = false;
4705
+ this.saveClicked = new EventEmitter();
4706
+ this.cancelClicked = new EventEmitter();
4707
+ this.isVisible = signal(false);
4708
+ this.isHidden = signal(true);
4709
+ this.targetToggleEventListener = () => {
4710
+ this.isVisible.update((prev) => !prev);
4711
+ if (!this.isVisible()) {
4712
+ return;
4713
+ }
4714
+ this.calculateDropdownPosition();
4715
+ };
4716
+ }
4717
+ set title(value) {
4718
+ this.startTitle = value;
4719
+ this.formTitle.set(value);
4720
+ }
4721
+ set url(value) {
4722
+ this.dynamicDataControl = new FormControl(value, {
4723
+ nonNullable: true,
4724
+ validators: [Validators.required, urlValidator()]
4725
+ });
4726
+ }
4727
+ set tool(value) {
4728
+ const tool = this.markersService.getMarkerObjectByType(value.type, value.id);
4729
+ this.dynamicDataControl = new FormControl(tool, {
4730
+ nonNullable: true,
4731
+ validators: [Validators.required]
4732
+ });
4733
+ }
4734
+ set space(value) {
4735
+ this.spaceBetweenTargetAndList = value;
4736
+ }
4737
+ get isFormInvalid() {
4738
+ return this.dynamicDataControl.invalid || this.isTitleInvalid();
4739
+ }
4740
+ get isDynamicDataErrorShown() {
4741
+ return this.dynamicDataControl.invalid && this.dynamicDataControl.dirty;
4742
+ }
4743
+ get hide() {
4744
+ return this.isHidden();
4745
+ }
4746
+ get fixed() {
4747
+ return this.isGlobal;
4748
+ }
4749
+ ngOnInit() {
4750
+ this.initTargetElementListener();
4751
+ this.initClickOutsideSubscription();
4752
+ this.initOnCloseWhenEditorScroll();
4753
+ }
4754
+ ngOnDestroy() {
4755
+ this.destroyEventListeners();
4756
+ }
4757
+ onTitleLabelClick(element) {
4758
+ const range = document.createRange();
4759
+ const selection = window.getSelection();
4760
+ range.selectNodeContents(element);
4761
+ range.collapse(false);
4762
+ selection?.removeAllRanges();
4763
+ selection?.addRange(range);
4764
+ }
4765
+ onSave() {
4766
+ if (this.isFormInvalid) {
4767
+ return;
4768
+ }
4769
+ this.isVisible.set(false);
4770
+ this.saveClicked.emit({ title: this.formTitle(), data: this.dynamicDataControl.value });
4771
+ }
4772
+ onScroll() {
4773
+ this.isVisible.set(false);
4774
+ }
4775
+ onCancel() {
4776
+ this.isVisible.set(false);
4777
+ this.cancelClicked.emit();
4778
+ }
4779
+ onClearTitle(titleElement) {
4780
+ this.formTitle.set('');
4781
+ titleElement.textContent = '';
4782
+ titleElement.focus();
4783
+ }
4784
+ onTitleChange(event) {
4785
+ if (event.key === 'Enter') {
4786
+ event.preventDefault();
4787
+ return;
4788
+ }
4789
+ const target = event.target;
4790
+ const value = target.textContent;
4791
+ this.formTitle.set(value);
4792
+ }
4793
+ async onTitlePaste(event) {
4794
+ event.stopPropagation();
4795
+ event.preventDefault();
4796
+ if (!this.document) {
4797
+ return;
4798
+ }
4799
+ const value = await window.navigator.clipboard.readText();
4800
+ const target = event.target;
4801
+ this.document.execCommand('insertText', false, value);
4802
+ setTimeout(() => this.formTitle.set(target.textContent));
4803
+ }
4804
+ initTargetElementListener() {
4805
+ this.target.addEventListener('click', this.targetToggleEventListener);
4806
+ }
4807
+ initClickOutsideSubscription() {
4808
+ this.cuiClickOutsideDirective.cuiClickOutside.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((target) => {
4809
+ if (this.element.contains(target) || this.target.contains(target) || !this.isVisible()) {
4810
+ return;
4811
+ }
4812
+ this.isVisible.set(false);
4813
+ });
4814
+ }
4815
+ initOnCloseWhenEditorScroll() {
4816
+ this.editor = this.document.querySelector(EDITOR_SELECTOR);
4817
+ this.editor.addEventListener('scroll', this.onScroll.bind(this));
4818
+ }
4819
+ destroyEventListeners() {
4820
+ this.editor.removeEventListener('scroll', this.onScroll.bind(this));
4821
+ this.target.addEventListener('click', this.targetToggleEventListener);
4822
+ }
4823
+ calculateDropdownPosition() {
4824
+ this.isHidden.set(true);
4825
+ setTimeout(() => {
4826
+ const target = this.target;
4827
+ const { bottom: targetRectBottom, left: targetRectLeft } = target.getBoundingClientRect();
4828
+ const { clientHeight: documentClientHeight, clientWidth: documentClientWidth } = this.document.documentElement;
4829
+ const distanceToBottom = documentClientHeight - (targetRectBottom + this.spaceBetweenTargetAndList);
4830
+ const distanceToRight = documentClientWidth - targetRectLeft;
4831
+ const isListRight = distanceToRight < this.element.offsetWidth;
4832
+ const isListAbove = distanceToBottom < this.element.offsetHeight;
4833
+ this.changePositionY(isListAbove, target.offsetHeight, targetRectBottom);
4834
+ this.changePositionX(isListRight, target.offsetWidth, targetRectLeft);
4835
+ this.isHidden.set(false);
4836
+ });
4837
+ }
4838
+ changePositionX(isListRight, width, left) {
4839
+ if (this.isGlobal) {
4840
+ this.changeGlobalPositionX(isListRight, width, left);
4841
+ return;
4842
+ }
4843
+ if (isListRight) {
4844
+ this.element.style.right = '0';
4845
+ this.element.style.left = 'auto';
4846
+ return;
4847
+ }
4848
+ this.element.style.right = 'auto';
4849
+ this.element.style.left = '0';
4850
+ }
4851
+ changePositionY(isListAbove, height, bottom) {
4852
+ if (this.isGlobal) {
4853
+ this.changeGlobalPositionY(isListAbove, height, bottom);
4854
+ return;
4855
+ }
4856
+ if (isListAbove) {
4857
+ this.element.style.bottom = height + this.spaceBetweenTargetAndList + 'px';
4858
+ this.element.style.top = 'auto';
4859
+ return;
4860
+ }
4861
+ this.element.style.top = height + this.spaceBetweenTargetAndList + 'px';
4862
+ this.element.style.bottom = 'auto';
4863
+ }
4864
+ changeGlobalPositionX(isListRight, width, left) {
4865
+ if (isListRight) {
4866
+ this.element.style.left = left - this.element.offsetWidth + width + 'px';
4867
+ return;
4868
+ }
4869
+ this.element.style.left = left + 'px';
4870
+ }
4871
+ changeGlobalPositionY(isListAbove, height, bottom) {
4872
+ if (isListAbove) {
4873
+ this.element.style.top =
4874
+ bottom - this.element.offsetHeight - height - this.spaceBetweenTargetAndList + 'px';
4875
+ return;
4876
+ }
4877
+ this.element.style.top = bottom + this.spaceBetweenTargetAndList + 'px';
4878
+ }
4879
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MarkerModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4880
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: MarkerModalComponent, isStandalone: true, selector: "ng-component", inputs: { title: "title", url: "url", tool: "tool", isGlobal: "isGlobal", isTool: "isTool", target: "target", space: "space" }, outputs: { saveClicked: "saveClicked", cancelClicked: "cancelClicked" }, host: { properties: { "class._hidden": "this.hide", "class._fixed": "this.fixed" } }, hostDirectives: [{ directive: i1$1.CuiClickOutsideDirective }], ngImport: i0, template: "<ng-container *transloco=\"let t\">\r\n <ng-container *ngIf=\"isVisible()\">\r\n <form\r\n autocomplete=\"off\"\r\n class=\"wrapper\"\r\n >\r\n <cui-form-field>\r\n <!-- eslint-disable-next-line -->\r\n <label\r\n [for]=\"titleId\"\r\n cuiLabel\r\n [isRequired]=\"true\"\r\n (click)=\"onTitleLabelClick(titleElement)\"\r\n >\r\n {{ t('TITLE') }}\r\n </label>\r\n <!-- TODO: \u0435\u0441\u043B\u0438 \u043D\u0430\u0439\u0434\u0435\u0442\u0441\u044F \u0432\u0430\u0440\u0438\u043A \u0441\u0434\u0435\u043B\u0430\u0442\u044C \u0447\u0435\u0440\u0435\u0437 \u0444\u043E\u0440\u043C\u0443 -->\r\n <div\r\n class=\"title\"\r\n [class.title_invalid]=\"isTitleInvalid()\"\r\n >\r\n <div\r\n #titleElement\r\n class=\"title__text\"\r\n contenteditable\r\n attr.data-placeholder=\"{{ t('TITLE') }}...\"\r\n (paste)=\"onTitlePaste($event)\"\r\n (keyup)=\"onTitleChange($event)\"\r\n [innerHTML]=\"startTitle\"\r\n ></div>\r\n <button\r\n type=\"button\"\r\n class=\"title__clear\"\r\n (click)=\"onClearTitle(titleElement)\"\r\n >\r\n <cui-svg\r\n icon=\"cuiIconClear\"\r\n color=\"var(--cui-base-300)\"\r\n class=\"title__icon\"\r\n />\r\n </button>\r\n </div>\r\n\r\n <cui-hint *ngIf=\"isTitleInvalid()\" hintType=\"error\">\r\n <ng-container *ngIf=\"isTitleEmpty()\">\r\n {{ t('FIELD_IS_REQUIRED') }}\r\n </ng-container>\r\n <ng-container *ngIf=\"isTitleMoreThanMaxLength()\">\r\n {{ t('PLEASE_KEEP_FIELD_UNDER_CHARACTERS') }}\r\n </ng-container>\r\n </cui-hint>\r\n </cui-form-field>\r\n <cui-form-field>\r\n <label\r\n [for]=\"dataId\"\r\n cuiLabel\r\n [isRequired]=\"true\"\r\n >\r\n {{ isTool ? t('TOOL') : t('URL') }}\r\n </label>\r\n <ng-container *ngIf=\"dynamicDataControl\">\r\n <ng-container *ngIf=\"isTool; else input\">\r\n <div>\r\n <button\r\n #target=\"elementRef\"\r\n class=\"button tool-button\"\r\n cuiButton\r\n type=\"button\"\r\n cuiElement\r\n appearance=\"outlined-gray\"\r\n size=\"sm\"\r\n >\r\n {{ $any(dynamicDataControl.value)?.title || t('SELECT_TOOL') }}\r\n </button>\r\n </div>\r\n <cc-marker-select\r\n [formControl]=\"dynamicDataControl\"\r\n [target]=\"target.nativeElement\"\r\n />\r\n </ng-container>\r\n <ng-template #input>\r\n <cui-input-text\r\n [cuiTextFieldId]=\"dataId\"\r\n [formControl]=\"dynamicDataControl\"\r\n autocomplete=\"off\"\r\n [cuiTextFieldIsError]=\"isDynamicDataErrorShown\"\r\n cuiTextFieldPlaceholder=\"{{ t('LINK') }}...\"\r\n />\r\n <cui-hint *ngIf=\"isDynamicDataErrorShown\" hintType=\"error\">\r\n <ng-container *ngIf=\"dynamicDataControl.errors?.['required']\">\r\n {{ t('FIELD_IS_REQUIRED') }}\r\n </ng-container>\r\n <ng-container *ngIf=\"dynamicDataControl.errors?.['url']\">\r\n {{ t('INVALID_URL') }}\r\n </ng-container>\r\n </cui-hint>\r\n </ng-template>\r\n </ng-container>\r\n </cui-form-field>\r\n <div class=\"buttons\">\r\n <button\r\n cuiButton\r\n type=\"button\"\r\n appearance=\"outlined-gray\"\r\n size=\"sm\"\r\n (click)=\"onCancel()\"\r\n >\r\n {{ t('CANCEL') }}\r\n </button>\r\n <button\r\n cuiButton\r\n type=\"submit\"\r\n appearance=\"action\"\r\n size=\"sm\"\r\n [disabled]=\"isFormInvalid\"\r\n (click)=\"onSave()\"\r\n >\r\n {{ t('SAVE') }}\r\n </button>\r\n </div>\r\n </form>\r\n </ng-container>\r\n</ng-container>\r\n\r\n", styles: [":host{position:absolute;z-index:1;left:0}:host._fixed{position:fixed}:host._hidden{position:fixed;visibility:hidden}:host ::ng-deep .tool-button{width:100%}:host ::ng-deep .tool-button>span{justify-content:flex-start!important}.wrapper{padding:11px;box-shadow:0 2px 4px -1px #0000000f,0 4px 6px -1px #0000001a;display:flex;flex-direction:column;gap:16px;border-radius:8px;border:1px solid var(--cui-base-200);max-width:450px;background-color:var(--cui-base-0)}.buttons{padding-top:12px;display:flex;justify-content:flex-end;gap:12px}.title{padding:7px 13px;cursor:text;display:flex;align-items:center;gap:8px;border:1px solid var(--cui-base-200);border-radius:8px;width:426px;background:var(--cui-input);color:var(--cui-base-900)}.title:hover{border-color:var(--cui-base-300)}.title:focus-within{outline:none;box-shadow:0 0 0 2px var(--cui-focus);border-color:var(--cui-info)}.title_invalid,.title_invalid:focus-within{box-shadow:none;border-color:var(--cui-danger)}.title__text{flex-grow:1;text-wrap:nowrap;overflow:hidden}.title__text[data-placeholder]:empty:before{content:attr(data-placeholder);position:absolute;color:var(--cui-base-400)}.title__text:focus{outline:none}.title__clear{padding:0;visibility:hidden}.title__icon{width:16px}.title__icon ::ng-deep [stroke]{stroke:var(--cui-base-0)}.title__text:not(:empty)+.title__clear{visibility:visible}\n"], dependencies: [{ kind: "ngmodule", type: CuiButtonModule }, { kind: "component", type: CuiButtonComponent, selector: "button[cuiButton], a[cuiButton]", inputs: ["shape", "disabled", "isLoaderShown", "icon", "iconRight", "appearance", "size"] }, { kind: "directive", type: CuiElementDirective, selector: "[cuiElement]", exportAs: ["elementRef"] }, { kind: "ngmodule", type: CuiFormFieldModule }, { kind: "component", type: CuiFormFieldComponent, selector: "cui-form-field" }, { kind: "ngmodule", type: CuiHintModule }, { kind: "component", type: CuiHintComponent, selector: "cui-hint", inputs: ["hintType"] }, { kind: "ngmodule", type: CuiInputModule }, { kind: "component", type: CuiInputTextComponent, selector: "cui-input-text" }, { kind: "directive", type: CuiTextFieldIdDirective, selector: "[cuiTextFieldId]", inputs: ["cuiTextFieldId"] }, { kind: "directive", type: CuiTextFieldPlaceholderDirective, selector: "[cuiTextFieldPlaceholder]", inputs: ["cuiTextFieldPlaceholder"] }, { kind: "directive", type: CuiTextFieldIsErrorDirective, selector: "[cuiTextFieldIsError]", inputs: ["cuiTextFieldIsError"] }, { kind: "ngmodule", type: CuiLabelModule }, { kind: "component", type: CuiLabelComponent, selector: "label[cuiLabel]", inputs: ["isRequired"] }, { kind: "ngmodule", type: CuiSvgModule }, { kind: "component", type: CuiSvgComponent, selector: "cui-svg[icon]", inputs: ["width", "height", "strokeWidth", "color", "icon"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: MarkerSelectComponent, selector: "cc-marker-select", inputs: ["target", "space"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4881
+ }
4882
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MarkerModalComponent, decorators: [{
4883
+ type: Component,
4884
+ args: [{ standalone: true, imports: [
4885
+ CuiButtonModule,
4886
+ CuiElementDirective,
4887
+ CuiFormFieldModule,
4888
+ CuiHintModule,
4889
+ CuiInputModule,
4890
+ CuiLabelModule,
4891
+ CuiSvgModule,
4892
+ FormsModule,
4893
+ MarkerSelectComponent,
4894
+ ReactiveFormsModule,
4895
+ TranslocoDirective,
4896
+ NgIf
4897
+ ], changeDetection: ChangeDetectionStrategy.OnPush, hostDirectives: [CuiClickOutsideDirective], template: "<ng-container *transloco=\"let t\">\r\n <ng-container *ngIf=\"isVisible()\">\r\n <form\r\n autocomplete=\"off\"\r\n class=\"wrapper\"\r\n >\r\n <cui-form-field>\r\n <!-- eslint-disable-next-line -->\r\n <label\r\n [for]=\"titleId\"\r\n cuiLabel\r\n [isRequired]=\"true\"\r\n (click)=\"onTitleLabelClick(titleElement)\"\r\n >\r\n {{ t('TITLE') }}\r\n </label>\r\n <!-- TODO: \u0435\u0441\u043B\u0438 \u043D\u0430\u0439\u0434\u0435\u0442\u0441\u044F \u0432\u0430\u0440\u0438\u043A \u0441\u0434\u0435\u043B\u0430\u0442\u044C \u0447\u0435\u0440\u0435\u0437 \u0444\u043E\u0440\u043C\u0443 -->\r\n <div\r\n class=\"title\"\r\n [class.title_invalid]=\"isTitleInvalid()\"\r\n >\r\n <div\r\n #titleElement\r\n class=\"title__text\"\r\n contenteditable\r\n attr.data-placeholder=\"{{ t('TITLE') }}...\"\r\n (paste)=\"onTitlePaste($event)\"\r\n (keyup)=\"onTitleChange($event)\"\r\n [innerHTML]=\"startTitle\"\r\n ></div>\r\n <button\r\n type=\"button\"\r\n class=\"title__clear\"\r\n (click)=\"onClearTitle(titleElement)\"\r\n >\r\n <cui-svg\r\n icon=\"cuiIconClear\"\r\n color=\"var(--cui-base-300)\"\r\n class=\"title__icon\"\r\n />\r\n </button>\r\n </div>\r\n\r\n <cui-hint *ngIf=\"isTitleInvalid()\" hintType=\"error\">\r\n <ng-container *ngIf=\"isTitleEmpty()\">\r\n {{ t('FIELD_IS_REQUIRED') }}\r\n </ng-container>\r\n <ng-container *ngIf=\"isTitleMoreThanMaxLength()\">\r\n {{ t('PLEASE_KEEP_FIELD_UNDER_CHARACTERS') }}\r\n </ng-container>\r\n </cui-hint>\r\n </cui-form-field>\r\n <cui-form-field>\r\n <label\r\n [for]=\"dataId\"\r\n cuiLabel\r\n [isRequired]=\"true\"\r\n >\r\n {{ isTool ? t('TOOL') : t('URL') }}\r\n </label>\r\n <ng-container *ngIf=\"dynamicDataControl\">\r\n <ng-container *ngIf=\"isTool; else input\">\r\n <div>\r\n <button\r\n #target=\"elementRef\"\r\n class=\"button tool-button\"\r\n cuiButton\r\n type=\"button\"\r\n cuiElement\r\n appearance=\"outlined-gray\"\r\n size=\"sm\"\r\n >\r\n {{ $any(dynamicDataControl.value)?.title || t('SELECT_TOOL') }}\r\n </button>\r\n </div>\r\n <cc-marker-select\r\n [formControl]=\"dynamicDataControl\"\r\n [target]=\"target.nativeElement\"\r\n />\r\n </ng-container>\r\n <ng-template #input>\r\n <cui-input-text\r\n [cuiTextFieldId]=\"dataId\"\r\n [formControl]=\"dynamicDataControl\"\r\n autocomplete=\"off\"\r\n [cuiTextFieldIsError]=\"isDynamicDataErrorShown\"\r\n cuiTextFieldPlaceholder=\"{{ t('LINK') }}...\"\r\n />\r\n <cui-hint *ngIf=\"isDynamicDataErrorShown\" hintType=\"error\">\r\n <ng-container *ngIf=\"dynamicDataControl.errors?.['required']\">\r\n {{ t('FIELD_IS_REQUIRED') }}\r\n </ng-container>\r\n <ng-container *ngIf=\"dynamicDataControl.errors?.['url']\">\r\n {{ t('INVALID_URL') }}\r\n </ng-container>\r\n </cui-hint>\r\n </ng-template>\r\n </ng-container>\r\n </cui-form-field>\r\n <div class=\"buttons\">\r\n <button\r\n cuiButton\r\n type=\"button\"\r\n appearance=\"outlined-gray\"\r\n size=\"sm\"\r\n (click)=\"onCancel()\"\r\n >\r\n {{ t('CANCEL') }}\r\n </button>\r\n <button\r\n cuiButton\r\n type=\"submit\"\r\n appearance=\"action\"\r\n size=\"sm\"\r\n [disabled]=\"isFormInvalid\"\r\n (click)=\"onSave()\"\r\n >\r\n {{ t('SAVE') }}\r\n </button>\r\n </div>\r\n </form>\r\n </ng-container>\r\n</ng-container>\r\n\r\n", styles: [":host{position:absolute;z-index:1;left:0}:host._fixed{position:fixed}:host._hidden{position:fixed;visibility:hidden}:host ::ng-deep .tool-button{width:100%}:host ::ng-deep .tool-button>span{justify-content:flex-start!important}.wrapper{padding:11px;box-shadow:0 2px 4px -1px #0000000f,0 4px 6px -1px #0000001a;display:flex;flex-direction:column;gap:16px;border-radius:8px;border:1px solid var(--cui-base-200);max-width:450px;background-color:var(--cui-base-0)}.buttons{padding-top:12px;display:flex;justify-content:flex-end;gap:12px}.title{padding:7px 13px;cursor:text;display:flex;align-items:center;gap:8px;border:1px solid var(--cui-base-200);border-radius:8px;width:426px;background:var(--cui-input);color:var(--cui-base-900)}.title:hover{border-color:var(--cui-base-300)}.title:focus-within{outline:none;box-shadow:0 0 0 2px var(--cui-focus);border-color:var(--cui-info)}.title_invalid,.title_invalid:focus-within{box-shadow:none;border-color:var(--cui-danger)}.title__text{flex-grow:1;text-wrap:nowrap;overflow:hidden}.title__text[data-placeholder]:empty:before{content:attr(data-placeholder);position:absolute;color:var(--cui-base-400)}.title__text:focus{outline:none}.title__clear{padding:0;visibility:hidden}.title__icon{width:16px}.title__icon ::ng-deep [stroke]{stroke:var(--cui-base-0)}.title__text:not(:empty)+.title__clear{visibility:visible}\n"] }]
4898
+ }], propDecorators: { title: [{
4899
+ type: Input
4900
+ }], url: [{
4901
+ type: Input
4902
+ }], tool: [{
4903
+ type: Input
4904
+ }], isGlobal: [{
4905
+ type: Input
4906
+ }], isTool: [{
4907
+ type: Input
4908
+ }], target: [{
4909
+ type: Input
4910
+ }], space: [{
4911
+ type: Input
4912
+ }], saveClicked: [{
4913
+ type: Output
4914
+ }], cancelClicked: [{
4915
+ type: Output
4916
+ }], hide: [{
4917
+ type: HostBinding,
4918
+ args: ['class._hidden']
4919
+ }], fixed: [{
4920
+ type: HostBinding,
4921
+ args: ['class._fixed']
4922
+ }] } });
4923
+
4924
+ const MARKER_MODAL_SELECTOR = 'cc-marker-modal';
4925
+
4926
+ function createLinkModal(tooltip, link) {
4927
+ const linkModal = document.createElement(MARKER_MODAL_SELECTOR);
4928
+ const button = tooltip.querySelector('.edit');
4929
+ linkModal.url = link.href;
4930
+ linkModal.title = link.innerText;
4931
+ linkModal.target = button;
4932
+ linkModal.space = 15;
4933
+ linkModal.addEventListener('saveClicked', (event) => {
4934
+ const customEvent = event;
4935
+ if (typeof customEvent.detail.data === 'string') {
4936
+ link.setAttribute('href', customEvent.detail.data);
4937
+ }
4938
+ link.innerHTML = customEvent.detail.title;
4939
+ tooltip.remove();
4940
+ });
4941
+ linkModal.addEventListener('cancelClicked', () => {
4942
+ tooltip.remove();
4943
+ });
4944
+ return linkModal;
4945
+ }
4946
+
4947
+ class EditorToolModalComponent {
4948
+ set marker(value) {
4949
+ this.calculateModalPosition(value);
4950
+ }
4951
+ get _isHidden() {
4952
+ return this.isHidden();
4953
+ }
4954
+ get _isFullscreen() {
4955
+ return this.isFullscreen();
4956
+ }
4957
+ constructor() {
4958
+ this.element = inject(ElementRef).nativeElement;
4959
+ this.window = inject(CUI_WINDOW);
4960
+ this.cuiClickOutsideDirective = inject(CuiClickOutsideDirective, { self: true });
4961
+ this.SPACE_BETWEEN_TARGET_AND_LIST = 10;
4962
+ this.isFullscreen = signal(false);
4963
+ this.isHidden = signal(true);
4964
+ this.closed = new EventEmitter();
4965
+ this.initClickOutsideSubscription();
4966
+ }
4967
+ onCloseModal() {
4968
+ this.closed.emit();
4969
+ }
4970
+ onMaximizeModal() {
4971
+ this.isFullscreen.update((prev) => !prev);
4972
+ }
4973
+ initClickOutsideSubscription() {
4974
+ this.cuiClickOutsideDirective.cuiClickOutside
4975
+ .pipe(skip(1), takeUntilDestroyed())
4976
+ .subscribe(() => this.onCloseModal());
4977
+ }
4978
+ calculateModalPosition(marker) {
4979
+ const { bottom, left } = marker.getBoundingClientRect();
4980
+ setTimeout(() => {
4981
+ const modalWidth = this.element.offsetWidth;
4982
+ this.element.style.top = bottom + this.window.scrollY + this.SPACE_BETWEEN_TARGET_AND_LIST + 'px';
4983
+ this.element.style.left = left + this.window.scrollX + marker.offsetWidth / 2 - modalWidth / 2 + 'px';
4984
+ this.isHidden.set(false);
4985
+ });
4986
+ }
4987
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EditorToolModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4988
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: EditorToolModalComponent, isStandalone: true, selector: "ng-component", inputs: { tool: "tool", marker: "marker" }, outputs: { closed: "closed" }, host: { properties: { "class._hidden": "this._isHidden", "class._fullscreen": "this._isFullscreen" } }, hostDirectives: [{ directive: i1$1.CuiClickOutsideDirective }], ngImport: i0, template: "<div class=\"triangle\"></div>\r\n<div class=\"wrapper\">\r\n <header class=\"header\">\r\n <h3 class=\"title\">{{ tool.title }}</h3>\r\n <div class=\"header__buttons\">\r\n <!-- TODO: replace icon with 'maximize' -->\r\n <button\r\n cuiButton\r\n type=\"button\"\r\n appearance=\"ghost\"\r\n size=\"xxs\"\r\n icon=\"cuiIconArrowSortSm\"\r\n (click)=\"onMaximizeModal()\"\r\n ></button>\r\n <button\r\n cuiButton\r\n type=\"button\"\r\n appearance=\"ghost\"\r\n size=\"xxs\"\r\n icon=\"cuiIconX\"\r\n (click)=\"onCloseModal()\"\r\n ></button>\r\n </div>\r\n </header>\r\n <div class=\"content\">\r\n <div class=\"info\">\r\n <!-- TODO: \u0431\u0443\u0434\u0435\u0442 \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0430-->\r\n <p class=\"info__item\">\r\n <span class=\"info__field\">\u0422\u0438\u043F:</span>\r\n <span class=\"info__title\">{{ tool.title }}</span>\r\n </p>\r\n <p class=\"info__item\">\r\n <span class=\"info__field\">\u0421\u0442\u0440\u0430\u043D\u0430 \u043F\u0440\u043E\u0438\u0437\u0432\u043E\u0434\u0438\u0442\u0435\u043B\u044C:</span>\r\n <span class=\"info__title\">{{ tool.title }}</span>\r\n </p>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".content{padding-right:23px;padding-left:23px;padding-bottom:7px;font-weight:400;font-size:14px;line-height:20px;font-family:var(--cui-main-font);max-height:415px;overflow-y:auto}:host{position:absolute;z-index:10;left:50%;top:30px;min-height:100px;max-width:450px}:host._fullscreen{position:fixed;top:0!important;left:0!important;max-width:none;height:100vh;width:100%;transform:none}:host._fullscreen .content{max-height:calc(100% - 56px)}:host._hidden{visibility:hidden}.triangle{position:absolute;top:-7px;left:50%;width:14px;height:14px;border-radius:2px;border:1px solid var(--cui-base-200);background:var(--cui-base-0);transform:translate(-50%) rotate(45deg)}.wrapper{position:relative;border-radius:8px;border:1px solid var(--cui-base-200);background:var(--cui-base-0);height:100%}.header{padding:8.2px 15px 8px;display:flex;align-items:flex-end;justify-content:space-between;gap:16px;margin-bottom:12px}.title{font-weight:500;font-size:14px;line-height:20px;padding-top:2px;padding-bottom:2px;text-wrap:nowrap;text-overflow:ellipsis;overflow:hidden;color:var(--cui-base-900)}.info{display:flex;flex-direction:column;gap:8px}.info__item{display:flex;gap:8px}.info__field{font-weight:400;font-size:16px;line-height:24px;text-wrap:nowrap;color:var(--cui-gray-600)}.info__title{font-weight:500;font-size:16px;line-height:24px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;color:var(--cui-base-900)}\n"], dependencies: [{ kind: "ngmodule", type: CuiButtonModule }, { kind: "component", type: CuiButtonComponent, selector: "button[cuiButton], a[cuiButton]", inputs: ["shape", "disabled", "isLoaderShown", "icon", "iconRight", "appearance", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4989
+ }
4990
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EditorToolModalComponent, decorators: [{
4991
+ type: Component,
4992
+ args: [{ standalone: true, imports: [CuiButtonModule], changeDetection: ChangeDetectionStrategy.OnPush, hostDirectives: [CuiClickOutsideDirective], template: "<div class=\"triangle\"></div>\r\n<div class=\"wrapper\">\r\n <header class=\"header\">\r\n <h3 class=\"title\">{{ tool.title }}</h3>\r\n <div class=\"header__buttons\">\r\n <!-- TODO: replace icon with 'maximize' -->\r\n <button\r\n cuiButton\r\n type=\"button\"\r\n appearance=\"ghost\"\r\n size=\"xxs\"\r\n icon=\"cuiIconArrowSortSm\"\r\n (click)=\"onMaximizeModal()\"\r\n ></button>\r\n <button\r\n cuiButton\r\n type=\"button\"\r\n appearance=\"ghost\"\r\n size=\"xxs\"\r\n icon=\"cuiIconX\"\r\n (click)=\"onCloseModal()\"\r\n ></button>\r\n </div>\r\n </header>\r\n <div class=\"content\">\r\n <div class=\"info\">\r\n <!-- TODO: \u0431\u0443\u0434\u0435\u0442 \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0430-->\r\n <p class=\"info__item\">\r\n <span class=\"info__field\">\u0422\u0438\u043F:</span>\r\n <span class=\"info__title\">{{ tool.title }}</span>\r\n </p>\r\n <p class=\"info__item\">\r\n <span class=\"info__field\">\u0421\u0442\u0440\u0430\u043D\u0430 \u043F\u0440\u043E\u0438\u0437\u0432\u043E\u0434\u0438\u0442\u0435\u043B\u044C:</span>\r\n <span class=\"info__title\">{{ tool.title }}</span>\r\n </p>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".content{padding-right:23px;padding-left:23px;padding-bottom:7px;font-weight:400;font-size:14px;line-height:20px;font-family:var(--cui-main-font);max-height:415px;overflow-y:auto}:host{position:absolute;z-index:10;left:50%;top:30px;min-height:100px;max-width:450px}:host._fullscreen{position:fixed;top:0!important;left:0!important;max-width:none;height:100vh;width:100%;transform:none}:host._fullscreen .content{max-height:calc(100% - 56px)}:host._hidden{visibility:hidden}.triangle{position:absolute;top:-7px;left:50%;width:14px;height:14px;border-radius:2px;border:1px solid var(--cui-base-200);background:var(--cui-base-0);transform:translate(-50%) rotate(45deg)}.wrapper{position:relative;border-radius:8px;border:1px solid var(--cui-base-200);background:var(--cui-base-0);height:100%}.header{padding:8.2px 15px 8px;display:flex;align-items:flex-end;justify-content:space-between;gap:16px;margin-bottom:12px}.title{font-weight:500;font-size:14px;line-height:20px;padding-top:2px;padding-bottom:2px;text-wrap:nowrap;text-overflow:ellipsis;overflow:hidden;color:var(--cui-base-900)}.info{display:flex;flex-direction:column;gap:8px}.info__item{display:flex;gap:8px}.info__field{font-weight:400;font-size:16px;line-height:24px;text-wrap:nowrap;color:var(--cui-gray-600)}.info__title{font-weight:500;font-size:16px;line-height:24px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;color:var(--cui-base-900)}\n"] }]
4993
+ }], ctorParameters: () => [], propDecorators: { tool: [{
4994
+ type: Input,
4995
+ args: [{ required: true }]
4996
+ }], marker: [{
4997
+ type: Input
4998
+ }], closed: [{
4999
+ type: Output
5000
+ }], _isHidden: [{
5001
+ type: HostBinding,
5002
+ args: ['class._hidden']
5003
+ }], _isFullscreen: [{
5004
+ type: HostBinding,
5005
+ args: ['class._fullscreen']
5006
+ }] } });
5007
+
5008
+ const EDITOR_TOOL_MODAL_SELECTOR = 'cc-editor-tool-modal';
5009
+
5010
+ class EditorTooltipComponent {
5011
+ constructor() {
5012
+ // TODO: Удалить класс
5013
+ this.BUTTONS_OPTIONS = new Map([
5014
+ ['copy', { icon: 'cuiIconCopy', handler: (event) => this.copyClicked.emit(event) }],
5015
+ ['edit', { icon: 'cuiIconEdit', handler: (event) => this.editClicked.emit(event), class: 'edit' }],
5016
+ ['delete', { icon: 'cuiIconTrash', handler: (event) => this.deleteClicked.emit(event) }]
5017
+ ]);
5018
+ this._options = ['edit', 'delete'];
5019
+ this.buttons = this.getButtonsFromOptions(this._options);
5020
+ this.copyClicked = new EventEmitter();
5021
+ this.editClicked = new EventEmitter();
5022
+ this.deleteClicked = new EventEmitter();
5023
+ }
5024
+ set options(value) {
5025
+ this._options = value;
5026
+ this.buttons = this.getButtonsFromOptions(value);
5027
+ }
5028
+ getButtonsFromOptions(options) {
5029
+ return options.map((option) => this.BUTTONS_OPTIONS.get(option));
5030
+ }
5031
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EditorTooltipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
5032
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: EditorTooltipComponent, isStandalone: true, selector: "ng-component", inputs: { title: "title", options: "options" }, outputs: { copyClicked: "copyClicked", editClicked: "editClicked", deleteClicked: "deleteClicked" }, ngImport: i0, template: "<h3 class=\"title\">{{ title }}</h3>\r\n<div class=\"buttons-container\">\r\n <ng-container *ngFor=\"let button of buttons\">\r\n <div class=\"divider\"></div>\r\n <!-- TODO: class \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0443\u0434\u0430\u043B\u0451\u043D \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043C-->\r\n <button\r\n class=\"button\"\r\n cuiButton\r\n type=\"button\"\r\n appearance=\"ghost\"\r\n size=\"xxs\"\r\n [icon]=\"button.icon\"\r\n [class]=\"button.class\"\r\n (click)=\"button.handler($event)\"\r\n ></button>\r\n </ng-container>\r\n</div>\r\n", styles: [":host{padding:4px 6px;box-shadow:0 4px 6px -2px #0000000d,0 10px 15px -3px #0000001a;font-weight:400;font-size:14px;line-height:20px;position:fixed;z-index:12;left:0;top:0;display:flex;align-items:center;gap:12px;border-radius:4px;font-family:var(--cui-main-font);background:var(--cui-gray-800)}.title{font-weight:400;font-size:14px;line-height:20px;max-width:300px;text-wrap:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--cui-gray-0)}.divider{width:1px;height:24px;background:var(--cui-gray-500)}.buttons-container{display:flex;align-items:center;gap:4px}.button{--cui-base-50: rgba(255 255 255 / 10%);--cui-base-500: var(--cui-gray-0)}\n"], dependencies: [{ kind: "ngmodule", type: CuiButtonModule }, { kind: "component", type: CuiButtonComponent, selector: "button[cuiButton], a[cuiButton]", inputs: ["shape", "disabled", "isLoaderShown", "icon", "iconRight", "appearance", "size"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
5033
+ }
5034
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EditorTooltipComponent, decorators: [{
5035
+ type: Component,
5036
+ args: [{ standalone: true, imports: [CuiButtonModule, NgFor], changeDetection: ChangeDetectionStrategy.OnPush, template: "<h3 class=\"title\">{{ title }}</h3>\r\n<div class=\"buttons-container\">\r\n <ng-container *ngFor=\"let button of buttons\">\r\n <div class=\"divider\"></div>\r\n <!-- TODO: class \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0443\u0434\u0430\u043B\u0451\u043D \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043C-->\r\n <button\r\n class=\"button\"\r\n cuiButton\r\n type=\"button\"\r\n appearance=\"ghost\"\r\n size=\"xxs\"\r\n [icon]=\"button.icon\"\r\n [class]=\"button.class\"\r\n (click)=\"button.handler($event)\"\r\n ></button>\r\n </ng-container>\r\n</div>\r\n", styles: [":host{padding:4px 6px;box-shadow:0 4px 6px -2px #0000000d,0 10px 15px -3px #0000001a;font-weight:400;font-size:14px;line-height:20px;position:fixed;z-index:12;left:0;top:0;display:flex;align-items:center;gap:12px;border-radius:4px;font-family:var(--cui-main-font);background:var(--cui-gray-800)}.title{font-weight:400;font-size:14px;line-height:20px;max-width:300px;text-wrap:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--cui-gray-0)}.divider{width:1px;height:24px;background:var(--cui-gray-500)}.buttons-container{display:flex;align-items:center;gap:4px}.button{--cui-base-50: rgba(255 255 255 / 10%);--cui-base-500: var(--cui-gray-0)}\n"] }]
5037
+ }], propDecorators: { title: [{
5038
+ type: Input,
5039
+ args: [{ required: true }]
5040
+ }], options: [{
5041
+ type: Input
5042
+ }], copyClicked: [{
5043
+ type: Output
5044
+ }], editClicked: [{
5045
+ type: Output
5046
+ }], deleteClicked: [{
5047
+ type: Output
5048
+ }] } });
5049
+
5050
+ const EDITOR_TOOLTIP_SELECTOR = 'cc-editor-tooltip';
5051
+
5052
+ class EditorToolComponent {
5053
+ constructor() {
5054
+ this.window = inject(CUI_WINDOW);
5055
+ this.document = inject(DOCUMENT);
5056
+ this.readOnly = false;
5057
+ this.isLoading = false;
5058
+ this.fileSelected = new EventEmitter();
5059
+ this.captionChanged = new EventEmitter();
5060
+ this.previousValue = this.caption;
5061
+ }
5062
+ get isCaptionShown() {
5063
+ return !this.readOnly || !!this.caption;
5064
+ }
5065
+ onSelectFile() {
5066
+ this.fileSelected.emit();
5067
+ }
5068
+ onTitleChange(event) {
5069
+ const target = event.currentTarget;
5070
+ if (target.innerHTML === '<br>') {
5071
+ target.innerHTML = '';
5072
+ }
5073
+ const value = target.innerHTML;
5074
+ if (this.previousValue === value) {
5075
+ return;
5076
+ }
5077
+ this.previousValue = value;
5078
+ this.captionChanged.emit(value);
5079
+ }
5080
+ async onTitlePaste(event) {
5081
+ event.stopPropagation();
5082
+ event.preventDefault();
5083
+ if (!this.document) {
5084
+ return;
5085
+ }
5086
+ const value = await this.window.navigator.clipboard.readText();
5087
+ const target = event.target;
5088
+ this.document.execCommand('insertText', false, value);
5089
+ setTimeout(() => this.captionChanged.emit(target.textContent));
5090
+ }
5091
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EditorToolComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
5092
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: EditorToolComponent, selector: "ng-component", inputs: { api: "api", preview: "preview", caption: "caption", buttonContent: "buttonContent", readOnly: "readOnly", isLoading: "isLoading" }, outputs: { fileSelected: "fileSelected", captionChanged: "captionChanged" }, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
5093
+ }
5094
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EditorToolComponent, decorators: [{
5095
+ type: Component,
5096
+ args: [{
5097
+ template: '',
5098
+ changeDetection: ChangeDetectionStrategy.OnPush
5099
+ }]
5100
+ }], propDecorators: { api: [{
5101
+ type: Input,
5102
+ args: [{ required: true }]
5103
+ }], preview: [{
5104
+ type: Input,
5105
+ args: [{ required: true }]
5106
+ }], caption: [{
5107
+ type: Input,
5108
+ args: [{ required: true }]
5109
+ }], buttonContent: [{
5110
+ type: Input,
5111
+ args: [{ required: true }]
5112
+ }], readOnly: [{
5113
+ type: Input
5114
+ }], isLoading: [{
5115
+ type: Input
5116
+ }], fileSelected: [{
5117
+ type: Output
5118
+ }], captionChanged: [{
5119
+ type: Output
5120
+ }] } });
5121
+
5122
+ class FileSizePipe {
5123
+ constructor() {
5124
+ this.SIZES = ['Bytes', 'KB', 'MB', 'GB'];
5125
+ this.BYTES_IN_KILOBYTE = 1024;
5126
+ }
5127
+ transform(bytes) {
5128
+ if (isNaN(bytes) || bytes === 0) {
5129
+ return '0 Bytes';
5130
+ }
5131
+ const index = Math.floor(Math.log(bytes) / Math.log(this.BYTES_IN_KILOBYTE));
5132
+ return `${parseFloat((bytes / Math.pow(this.BYTES_IN_KILOBYTE, index)).toFixed(1))} ${this.SIZES[index]}`;
5133
+ }
5134
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FileSizePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
5135
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.13", ngImport: i0, type: FileSizePipe, isStandalone: true, name: "fileSize" }); }
5136
+ }
5137
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FileSizePipe, decorators: [{
5138
+ type: Pipe,
5139
+ args: [{
5140
+ name: 'fileSize',
5141
+ standalone: true
5142
+ }]
5143
+ }] });
5144
+
5145
+ class EditorAttachesToolComponent extends EditorToolComponent {
5146
+ constructor() {
5147
+ super(...arguments);
5148
+ this.Extensions = {
5149
+ doc: '#1483E9',
5150
+ docx: '#1483E9',
5151
+ odt: '#1483E9',
5152
+ pdf: '#DB2F2F',
5153
+ rtf: '#744FDC',
5154
+ tex: '#5a5a5b',
5155
+ txt: '#5a5a5b',
5156
+ pptx: '#E35200',
5157
+ ppt: '#E35200',
5158
+ mp3: '#eab456',
5159
+ mp4: '#f676a6',
5160
+ xls: '#11AE3D',
5161
+ html: '#2988f0',
5162
+ htm: '#2988f0',
5163
+ png: '#AA2284',
5164
+ jpg: '#D13359',
5165
+ jpeg: '#D13359',
5166
+ gif: '#f6af76',
5167
+ zip: '#4f566f',
5168
+ rar: '#4f566f',
5169
+ exe: '#e26f6f',
5170
+ svg: '#bf5252',
5171
+ key: '#00B2FF',
5172
+ sketch: '#FFC700',
5173
+ ai: '#FB601D',
5174
+ psd: '#388ae5',
5175
+ dmg: '#e26f6f',
5176
+ json: '#2988f0',
5177
+ csv: '#11AE3D'
5178
+ };
5179
+ }
5180
+ get color() {
5181
+ return this.Extensions[this.file?.extension];
5182
+ }
5183
+ get isShowLoadButton() {
5184
+ return !this.file && !this.isCaptionShown && !this.isLoading;
5185
+ }
5186
+ onPreventEnter(event) {
5187
+ if (this.checkKey(event)) {
5188
+ return;
5189
+ }
5190
+ event.preventDefault();
5191
+ event.stopPropagation();
5192
+ }
5193
+ checkKey(event) {
5194
+ return event.key !== 'Enter';
5195
+ }
5196
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EditorAttachesToolComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
5197
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: EditorAttachesToolComponent, isStandalone: true, selector: "ng-component", inputs: { file: "file", title: "title" }, host: { properties: { "class._hidden": "isShowLoadButton" } }, usesInheritance: true, ngImport: i0, template: "<ng-container *ngIf=\"!isLoading; else preloader\">\r\n <ng-container *transloco=\"let t\">\r\n <div *ngIf=\"file; else buttonTemplate\" class=\"file\">\r\n <div\r\n class=\"icon\"\r\n [style.backgroundColor]=\"color\"\r\n >\r\n {{ file.extension | uppercase }}\r\n </div>\r\n <div class=\"info\">\r\n <div\r\n class=\"title\"\r\n attr.data-placeholder=\"{{ t('FILE_TITLE') }}...\"\r\n [innerHTML]=\"title\"\r\n [attr.contenteditable]=\"!readOnly\"\r\n (paste)=\"onTitlePaste($event)\"\r\n (keydown)=\"onPreventEnter($event)\"\r\n (keyup)=\"onTitleChange($event)\"\r\n ></div>\r\n <div *ngIf=\"file.size; let size\" class=\"size\">{{ size | fileSize }}</div>\r\n </div>\r\n <a\r\n class=\"download\"\r\n [href]=\"file.url\"\r\n target=\"_blank\"\r\n download\r\n >\r\n <cui-svg icon=\"cuiIconChevronDownSm\" />\r\n </a>\r\n </div>\r\n <ng-template #buttonTemplate>\r\n <button\r\n [class]=\"['select-btn', this.api.styles.button]\"\r\n (click)=\"onSelectFile()\"\r\n type=\"button\"\r\n >\r\n <cui-svg icon=\"cuiIconPaperclipSm\" />\r\n &nbsp;{{ buttonContent }}\r\n </button>\r\n </ng-template>\r\n </ng-container>\r\n</ng-container>\r\n\r\n<ng-template #preloader>\r\n <div class=\"wrapper\">\r\n <div class=\"preloader\"></div>\r\n </div>\r\n</ng-template>\r\n\r\n", styles: [":host{padding-top:6px;padding-bottom:6px;font-weight:400;font-size:14px;line-height:20px;font-family:var(--cui-main-font);display:block}:host._hidden{display:none}.file{padding:10px 12px;display:flex;justify-content:space-between;align-items:center;gap:8px;border-radius:10px;border:1px solid var(--cui-base-200);background-color:var(--cui-base-10)}.info{display:flex;flex-direction:column;gap:2px;width:85%}.icon{padding:6px 2px;font-weight:500;font-size:12px;line-height:14px;display:flex;align-items:flex-end;border-radius:8px;width:35px;height:35px;color:var(--cui-gray-0)}.title{font-weight:400;font-size:14px;line-height:20px;outline:none}.size{font-weight:400;font-size:13px;line-height:16px;color:var(--cui-base-500)}.download{padding:6px;margin-left:auto;border-radius:8px;color:var(--cui-base-0);background:var(--cui-base-50)}.wrapper{display:flex;flex-direction:column;margin-bottom:10px;border:1px solid var(--cui-base-200);border-radius:10px;min-height:50px;background-color:var(--cui-base-0)}.wrapper._loaded{min-height:auto}.preloader{width:30px;height:30px;border-radius:50%;background-size:cover;margin:auto;position:relative;background-position:center center}@keyframes preloader-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.preloader:after{content:\"\";position:absolute;z-index:3;width:30px;height:30px;border-radius:50%;border:2px solid var(--cui-base-200);border-top-color:var(--cui-blue-600);left:50%;top:50%;margin-top:-15px;margin-left:-15px;animation:preloader-spin 2s infinite linear;box-sizing:border-box}.title[data-placeholder]:empty:before{content:attr(data-placeholder);position:absolute;color:var(--cui-base-400)}.select-btn{display:flex;align-items:center;justify-content:center;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CuiSvgModule }, { kind: "component", type: CuiSvgComponent, selector: "cui-svg[icon]", inputs: ["width", "height", "strokeWidth", "color", "icon"] }, { kind: "pipe", type: FileSizePipe, name: "fileSize" }, { kind: "ngmodule", type: FormsModule }, { kind: "pipe", type: UpperCasePipe, name: "uppercase" }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
5198
+ }
5199
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EditorAttachesToolComponent, decorators: [{
5200
+ type: Component,
5201
+ args: [{ standalone: true, imports: [CuiSvgModule, FileSizePipe, FormsModule, UpperCasePipe, NgIf, TranslocoDirective], changeDetection: ChangeDetectionStrategy.OnPush, host: {
5202
+ '[class._hidden]': 'isShowLoadButton'
5203
+ }, template: "<ng-container *ngIf=\"!isLoading; else preloader\">\r\n <ng-container *transloco=\"let t\">\r\n <div *ngIf=\"file; else buttonTemplate\" class=\"file\">\r\n <div\r\n class=\"icon\"\r\n [style.backgroundColor]=\"color\"\r\n >\r\n {{ file.extension | uppercase }}\r\n </div>\r\n <div class=\"info\">\r\n <div\r\n class=\"title\"\r\n attr.data-placeholder=\"{{ t('FILE_TITLE') }}...\"\r\n [innerHTML]=\"title\"\r\n [attr.contenteditable]=\"!readOnly\"\r\n (paste)=\"onTitlePaste($event)\"\r\n (keydown)=\"onPreventEnter($event)\"\r\n (keyup)=\"onTitleChange($event)\"\r\n ></div>\r\n <div *ngIf=\"file.size; let size\" class=\"size\">{{ size | fileSize }}</div>\r\n </div>\r\n <a\r\n class=\"download\"\r\n [href]=\"file.url\"\r\n target=\"_blank\"\r\n download\r\n >\r\n <cui-svg icon=\"cuiIconChevronDownSm\" />\r\n </a>\r\n </div>\r\n <ng-template #buttonTemplate>\r\n <button\r\n [class]=\"['select-btn', this.api.styles.button]\"\r\n (click)=\"onSelectFile()\"\r\n type=\"button\"\r\n >\r\n <cui-svg icon=\"cuiIconPaperclipSm\" />\r\n &nbsp;{{ buttonContent }}\r\n </button>\r\n </ng-template>\r\n </ng-container>\r\n</ng-container>\r\n\r\n<ng-template #preloader>\r\n <div class=\"wrapper\">\r\n <div class=\"preloader\"></div>\r\n </div>\r\n</ng-template>\r\n\r\n", styles: [":host{padding-top:6px;padding-bottom:6px;font-weight:400;font-size:14px;line-height:20px;font-family:var(--cui-main-font);display:block}:host._hidden{display:none}.file{padding:10px 12px;display:flex;justify-content:space-between;align-items:center;gap:8px;border-radius:10px;border:1px solid var(--cui-base-200);background-color:var(--cui-base-10)}.info{display:flex;flex-direction:column;gap:2px;width:85%}.icon{padding:6px 2px;font-weight:500;font-size:12px;line-height:14px;display:flex;align-items:flex-end;border-radius:8px;width:35px;height:35px;color:var(--cui-gray-0)}.title{font-weight:400;font-size:14px;line-height:20px;outline:none}.size{font-weight:400;font-size:13px;line-height:16px;color:var(--cui-base-500)}.download{padding:6px;margin-left:auto;border-radius:8px;color:var(--cui-base-0);background:var(--cui-base-50)}.wrapper{display:flex;flex-direction:column;margin-bottom:10px;border:1px solid var(--cui-base-200);border-radius:10px;min-height:50px;background-color:var(--cui-base-0)}.wrapper._loaded{min-height:auto}.preloader{width:30px;height:30px;border-radius:50%;background-size:cover;margin:auto;position:relative;background-position:center center}@keyframes preloader-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.preloader:after{content:\"\";position:absolute;z-index:3;width:30px;height:30px;border-radius:50%;border:2px solid var(--cui-base-200);border-top-color:var(--cui-blue-600);left:50%;top:50%;margin-top:-15px;margin-left:-15px;animation:preloader-spin 2s infinite linear;box-sizing:border-box}.title[data-placeholder]:empty:before{content:attr(data-placeholder);position:absolute;color:var(--cui-base-400)}.select-btn{display:flex;align-items:center;justify-content:center;width:100%}\n"] }]
5204
+ }], propDecorators: { file: [{
5205
+ type: Input,
5206
+ args: [{ required: true }]
5207
+ }], title: [{
5208
+ type: Input,
5209
+ args: [{ required: true }]
5210
+ }] } });
5211
+
5212
+ const EDITOR_ATTACHES_TOOL_SELECTOR = 'cc-editor-attaches-tool';
5213
+
5214
+ class EditorImageToolComponent extends EditorToolComponent {
5215
+ constructor() {
5216
+ super(...arguments);
5217
+ this.isLoaded = signal(false);
5218
+ this.tunesSignal = signal({});
5219
+ }
5220
+ set tunes(tunes) {
5221
+ this.tunesSignal.set(tunes);
5222
+ }
5223
+ get isShowLoadButton() {
5224
+ return !this.image && !this.isCaptionShown && !this.isLoading;
5225
+ }
5226
+ onPreventEnter(event) {
5227
+ if (this.checkKey(event)) {
5228
+ return;
5229
+ }
5230
+ event.stopPropagation();
5231
+ }
5232
+ checkKey(event) {
5233
+ return (event.key !== 'Backspace' && event.key !== 'Enter') || event.shiftKey;
5234
+ }
5235
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EditorImageToolComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
5236
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: EditorImageToolComponent, isStandalone: true, selector: "ng-component", inputs: { image: "image", tunes: "tunes" }, host: { properties: { "class._hidden": "isShowLoadButton" } }, usesInheritance: true, ngImport: i0, template: "<ng-container *ngIf=\"!isLoading; else preloader\">\r\n <ng-container *transloco=\"let t\">\r\n <ng-container *ngIf=\"image; else buttonTemplate\">\r\n <div\r\n class=\"wrapper\"\r\n [ngClass]=\"tunesSignal()\"\r\n [class._loaded]=\"isLoaded()\"\r\n >\r\n <img\r\n class=\"image\"\r\n [src]=\"image\"\r\n alt=\"Image\"\r\n />\r\n </div>\r\n <div\r\n *ngIf=\"isCaptionShown\"\r\n class=\"caption cdx-input\"\r\n [attr.contenteditable]=\"!readOnly\"\r\n attr.data-placeholder=\"{{ t('CAPTION') }}...\"\r\n (paste)=\"onTitlePaste($event)\"\r\n (keydown)=\"onPreventEnter($event)\"\r\n (keyup)=\"onTitleChange($event)\"\r\n [innerHTML]=\"caption\"\r\n ></div>\r\n </ng-container>\r\n <ng-template #buttonTemplate>\r\n <button\r\n #button\r\n type=\"button\"\r\n [class]=\"['select-btn', this.api.styles.button]\"\r\n (click)=\"onSelectFile()\"\r\n >\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"20\"\r\n height=\"20\"\r\n viewBox=\"0 0 20 20\"\r\n fill=\"none\"\r\n >\r\n <path\r\n d=\"M12.5013 4.1665H7.5013C5.66035 4.1665 4.16797 5.65889 4.16797 7.49984V12.4998C4.16797 14.3408 5.66035 15.8332 7.5013 15.8332H12.5013C14.3423 15.8332 15.8346 14.3408 15.8346 12.4998V7.49984C15.8346 5.65889 14.3423 4.1665 12.5013 4.1665Z\"\r\n stroke=\"#121315\"\r\n stroke-width=\"1.66667\"\r\n />\r\n <path\r\n d=\"M4.28125 12.7665L7.24033 9.63825C7.52263 9.33617 7.90546 9.1665 8.30463 9.1665C8.70377 9.1665 9.0866 9.33617 9.36893 9.63825L12.8208 13.3332M11.3154 11.7218L12.5092 10.444C12.7914 10.1419 13.1743 9.97217 13.5734 9.97217C13.9726 9.97217 14.3554 10.1419 14.6378 10.444L15.699 11.636\"\r\n stroke=\"#121315\"\r\n stroke-width=\"1.66667\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n <path\r\n d=\"M11.4805 7.77783H11.4879\"\r\n stroke=\"#121315\"\r\n stroke-width=\"1.66667\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </svg>\r\n &nbsp;{{ buttonContent }}\r\n </button>\r\n </ng-template>\r\n </ng-container>\r\n</ng-container>\r\n<ng-template #preloader>\r\n <div class=\"wrapper\">\r\n <div class=\"preloader\">\r\n <img\r\n *ngIf=\"preview\"\r\n class=\"preloader__image\"\r\n [src]=\"preview\"\r\n alt=\"Preloader\"\r\n />\r\n </div>\r\n </div>\r\n</ng-template>\r\n\r\n", styles: [":host{padding-top:6px;padding-bottom:6px;font-weight:400;font-size:14px;line-height:20px;font-family:var(--cui-main-font);display:block}:host ::ng-deep .cdx-input{border:1px solid var(--cui-base-200);background:transparent;box-shadow:none}:host ::ng-deep .play{margin:auto}:host ::ng-deep .play path{fill:var(--cui-base-0);stroke:var(--cui-base-300)}:host._hidden{display:none}.image{display:block;max-width:100%;width:fit-content;height:250px}.wrapper{display:flex;flex-direction:column;margin-bottom:10px;border:1px solid var(--cui-base-200);border-radius:3px;min-height:200px;background-color:var(--cui-base-0)}.wrapper._loaded{min-height:auto}.wrapper.stretched .image{width:100%;height:auto}.wrapper.center .image{margin:auto}.preloader{width:50px;height:50px;border-radius:50%;background-size:cover;margin:auto;position:relative;background-color:var(--cui-base-200);background-position:center center}@keyframes preloader-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.preloader__image{width:50px;height:50px;border-radius:50%}.preloader:after{content:\"\";position:absolute;z-index:3;width:60px;height:60px;border-radius:50%;border:2px solid var(--cui-base-200);border-top-color:var(--cui-blue-600);left:50%;top:50%;margin-top:-30px;margin-left:-30px;animation:preloader-spin 2s infinite linear;box-sizing:border-box}.caption[data-placeholder]:empty:before{content:attr(data-placeholder);position:absolute;color:var(--cui-base-400)}.select-btn{display:flex;align-items:center;justify-content:center;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CuiSvgModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
5237
+ }
5238
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EditorImageToolComponent, decorators: [{
5239
+ type: Component,
5240
+ args: [{ standalone: true, imports: [CuiSvgModule, FormsModule, NgClass, NgIf, TranslocoDirective], changeDetection: ChangeDetectionStrategy.OnPush, host: {
5241
+ '[class._hidden]': 'isShowLoadButton'
5242
+ }, template: "<ng-container *ngIf=\"!isLoading; else preloader\">\r\n <ng-container *transloco=\"let t\">\r\n <ng-container *ngIf=\"image; else buttonTemplate\">\r\n <div\r\n class=\"wrapper\"\r\n [ngClass]=\"tunesSignal()\"\r\n [class._loaded]=\"isLoaded()\"\r\n >\r\n <img\r\n class=\"image\"\r\n [src]=\"image\"\r\n alt=\"Image\"\r\n />\r\n </div>\r\n <div\r\n *ngIf=\"isCaptionShown\"\r\n class=\"caption cdx-input\"\r\n [attr.contenteditable]=\"!readOnly\"\r\n attr.data-placeholder=\"{{ t('CAPTION') }}...\"\r\n (paste)=\"onTitlePaste($event)\"\r\n (keydown)=\"onPreventEnter($event)\"\r\n (keyup)=\"onTitleChange($event)\"\r\n [innerHTML]=\"caption\"\r\n ></div>\r\n </ng-container>\r\n <ng-template #buttonTemplate>\r\n <button\r\n #button\r\n type=\"button\"\r\n [class]=\"['select-btn', this.api.styles.button]\"\r\n (click)=\"onSelectFile()\"\r\n >\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"20\"\r\n height=\"20\"\r\n viewBox=\"0 0 20 20\"\r\n fill=\"none\"\r\n >\r\n <path\r\n d=\"M12.5013 4.1665H7.5013C5.66035 4.1665 4.16797 5.65889 4.16797 7.49984V12.4998C4.16797 14.3408 5.66035 15.8332 7.5013 15.8332H12.5013C14.3423 15.8332 15.8346 14.3408 15.8346 12.4998V7.49984C15.8346 5.65889 14.3423 4.1665 12.5013 4.1665Z\"\r\n stroke=\"#121315\"\r\n stroke-width=\"1.66667\"\r\n />\r\n <path\r\n d=\"M4.28125 12.7665L7.24033 9.63825C7.52263 9.33617 7.90546 9.1665 8.30463 9.1665C8.70377 9.1665 9.0866 9.33617 9.36893 9.63825L12.8208 13.3332M11.3154 11.7218L12.5092 10.444C12.7914 10.1419 13.1743 9.97217 13.5734 9.97217C13.9726 9.97217 14.3554 10.1419 14.6378 10.444L15.699 11.636\"\r\n stroke=\"#121315\"\r\n stroke-width=\"1.66667\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n <path\r\n d=\"M11.4805 7.77783H11.4879\"\r\n stroke=\"#121315\"\r\n stroke-width=\"1.66667\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </svg>\r\n &nbsp;{{ buttonContent }}\r\n </button>\r\n </ng-template>\r\n </ng-container>\r\n</ng-container>\r\n<ng-template #preloader>\r\n <div class=\"wrapper\">\r\n <div class=\"preloader\">\r\n <img\r\n *ngIf=\"preview\"\r\n class=\"preloader__image\"\r\n [src]=\"preview\"\r\n alt=\"Preloader\"\r\n />\r\n </div>\r\n </div>\r\n</ng-template>\r\n\r\n", styles: [":host{padding-top:6px;padding-bottom:6px;font-weight:400;font-size:14px;line-height:20px;font-family:var(--cui-main-font);display:block}:host ::ng-deep .cdx-input{border:1px solid var(--cui-base-200);background:transparent;box-shadow:none}:host ::ng-deep .play{margin:auto}:host ::ng-deep .play path{fill:var(--cui-base-0);stroke:var(--cui-base-300)}:host._hidden{display:none}.image{display:block;max-width:100%;width:fit-content;height:250px}.wrapper{display:flex;flex-direction:column;margin-bottom:10px;border:1px solid var(--cui-base-200);border-radius:3px;min-height:200px;background-color:var(--cui-base-0)}.wrapper._loaded{min-height:auto}.wrapper.stretched .image{width:100%;height:auto}.wrapper.center .image{margin:auto}.preloader{width:50px;height:50px;border-radius:50%;background-size:cover;margin:auto;position:relative;background-color:var(--cui-base-200);background-position:center center}@keyframes preloader-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.preloader__image{width:50px;height:50px;border-radius:50%}.preloader:after{content:\"\";position:absolute;z-index:3;width:60px;height:60px;border-radius:50%;border:2px solid var(--cui-base-200);border-top-color:var(--cui-blue-600);left:50%;top:50%;margin-top:-30px;margin-left:-30px;animation:preloader-spin 2s infinite linear;box-sizing:border-box}.caption[data-placeholder]:empty:before{content:attr(data-placeholder);position:absolute;color:var(--cui-base-400)}.select-btn{display:flex;align-items:center;justify-content:center;width:100%}\n"] }]
5243
+ }], propDecorators: { image: [{
5244
+ type: Input,
5245
+ args: [{ required: true }]
5246
+ }], tunes: [{
5247
+ type: Input
5248
+ }] } });
5249
+
5250
+ const EDITOR_IMAGE_TOOL_SELECTOR = 'cc-editor-image-tool';
5251
+
5252
+ class EditorVideoToolComponent extends EditorToolComponent {
5253
+ constructor() {
5254
+ super(...arguments);
5255
+ this.isLoaded = signal(false);
5256
+ }
5257
+ get isShowLoadButton() {
5258
+ return !this.video && !this.isCaptionShown && !this.isLoading;
5259
+ }
5260
+ onPlay() {
5261
+ this.isLoaded.set(true);
5262
+ }
5263
+ onPreventEnter(event) {
5264
+ if (this.checkKey(event)) {
5265
+ return;
5266
+ }
5267
+ event.stopPropagation();
5268
+ }
5269
+ checkKey(event) {
5270
+ return (event.key !== 'Backspace' && event.key !== 'Enter') || event.shiftKey;
5271
+ }
5272
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EditorVideoToolComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
5273
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: EditorVideoToolComponent, isStandalone: true, selector: "ng-component", inputs: { video: "video" }, host: { properties: { "class._hidden": "isShowLoadButton" } }, usesInheritance: true, ngImport: i0, template: "<ng-container *transloco=\"let t\">\r\n <ng-container *ngIf=\"!isLoading; else preloader\">\r\n <ng-container *ngIf=\"video; else buttonTemplate\">\r\n <div\r\n class=\"wrapper\"\r\n [class._loaded]=\"isLoaded()\"\r\n >\r\n <video\r\n *ngIf=\"isLoaded(); else playButtonTemplate\"\r\n class=\"video\"\r\n [src]=\"video\"\r\n controls\r\n autoplay\r\n ></video>\r\n\r\n <ng-template #playButtonTemplate>\r\n <button\r\n type=\"button\"\r\n class=\"play\"\r\n (click)=\"onPlay()\"\r\n >\r\n <cui-svg\r\n class=\"play\"\r\n icon=\"cuiIconPlayCircleSm\"\r\n [height]=\"72\"\r\n [width]=\"72\"\r\n [strokeWidth]=\"0.5\"\r\n />\r\n </button>\r\n </ng-template>\r\n </div>\r\n\r\n <div\r\n *ngIf=\"isCaptionShown\"\r\n class=\"caption cdx-input\"\r\n [attr.contenteditable]=\"!readOnly\"\r\n attr.data-placeholder=\"{{ t('CAPTION') }}...\"\r\n (paste)=\"onTitlePaste($event)\"\r\n (keydown)=\"onPreventEnter($event)\"\r\n (keyup)=\"onTitleChange($event)\"\r\n [innerHTML]=\"caption\"\r\n ></div>\r\n </ng-container>\r\n\r\n <ng-template #buttonTemplate>\r\n <button\r\n type=\"button\"\r\n [class]=\"['select-btn', this.api.styles.button]\"\r\n (click)=\"onSelectFile()\"\r\n >\r\n <cui-svg icon=\"cuiIconPlayCircle\" />\r\n &nbsp;{{ buttonContent }}\r\n </button>\r\n </ng-template>\r\n </ng-container>\r\n</ng-container>\r\n\r\n\r\n<ng-template #preloader>\r\n <div class=\"wrapper\">\r\n <div class=\"preloader\">\r\n <img\r\n *ngIf=\"preview\"\r\n class=\"preloader__image\"\r\n [src]=\"preview\"\r\n alt=\"Preloader\"\r\n />\r\n </div>\r\n </div>\r\n</ng-template>\r\n\r\n\r\n", styles: [":host{font-weight:400;font-size:14px;line-height:20px;padding-top:6px;padding-bottom:6px;font-family:var(--cui-main-font);display:block}:host ::ng-deep .cdx-input{border:1px solid var(--cui-base-200);background:transparent;box-shadow:none}:host ::ng-deep .play{margin:auto}:host ::ng-deep .play path{fill:var(--cui-base-0);stroke:var(--cui-base-300)}:host._hidden{display:none}.wrapper{display:flex;flex-direction:column;margin-bottom:10px;border:1px solid var(--cui-base-200);border-radius:3px;min-height:200px;background-color:var(--cui-base-0)}.wrapper._loaded{min-height:auto}.video{display:block;max-width:100%}.preloader{width:50px;height:50px;border-radius:50%;background-size:cover;margin:auto;position:relative;background-color:var(--cui-base-200);background-position:center center}@keyframes preloader-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.preloader__image{width:50px;height:50px;border-radius:50%}.preloader:after{content:\"\";position:absolute;z-index:3;width:60px;height:60px;border-radius:50%;border:2px solid var(--cui-base-200);border-top-color:var(--cui-blue-600);left:50%;top:50%;margin-top:-30px;margin-left:-30px;animation:preloader-spin 2s infinite linear;box-sizing:border-box}.caption[data-placeholder]:empty:before{content:attr(data-placeholder);position:absolute;color:var(--cui-base-400)}.select-btn{display:flex;align-items:center;justify-content:center;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CuiSvgModule }, { kind: "component", type: CuiSvgComponent, selector: "cui-svg[icon]", inputs: ["width", "height", "strokeWidth", "color", "icon"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
5274
+ }
5275
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: EditorVideoToolComponent, decorators: [{
5276
+ type: Component,
5277
+ args: [{ standalone: true, imports: [CuiSvgModule, FormsModule, NgIf, TranslocoDirective], changeDetection: ChangeDetectionStrategy.OnPush, host: {
5278
+ '[class._hidden]': 'isShowLoadButton'
5279
+ }, template: "<ng-container *transloco=\"let t\">\r\n <ng-container *ngIf=\"!isLoading; else preloader\">\r\n <ng-container *ngIf=\"video; else buttonTemplate\">\r\n <div\r\n class=\"wrapper\"\r\n [class._loaded]=\"isLoaded()\"\r\n >\r\n <video\r\n *ngIf=\"isLoaded(); else playButtonTemplate\"\r\n class=\"video\"\r\n [src]=\"video\"\r\n controls\r\n autoplay\r\n ></video>\r\n\r\n <ng-template #playButtonTemplate>\r\n <button\r\n type=\"button\"\r\n class=\"play\"\r\n (click)=\"onPlay()\"\r\n >\r\n <cui-svg\r\n class=\"play\"\r\n icon=\"cuiIconPlayCircleSm\"\r\n [height]=\"72\"\r\n [width]=\"72\"\r\n [strokeWidth]=\"0.5\"\r\n />\r\n </button>\r\n </ng-template>\r\n </div>\r\n\r\n <div\r\n *ngIf=\"isCaptionShown\"\r\n class=\"caption cdx-input\"\r\n [attr.contenteditable]=\"!readOnly\"\r\n attr.data-placeholder=\"{{ t('CAPTION') }}...\"\r\n (paste)=\"onTitlePaste($event)\"\r\n (keydown)=\"onPreventEnter($event)\"\r\n (keyup)=\"onTitleChange($event)\"\r\n [innerHTML]=\"caption\"\r\n ></div>\r\n </ng-container>\r\n\r\n <ng-template #buttonTemplate>\r\n <button\r\n type=\"button\"\r\n [class]=\"['select-btn', this.api.styles.button]\"\r\n (click)=\"onSelectFile()\"\r\n >\r\n <cui-svg icon=\"cuiIconPlayCircle\" />\r\n &nbsp;{{ buttonContent }}\r\n </button>\r\n </ng-template>\r\n </ng-container>\r\n</ng-container>\r\n\r\n\r\n<ng-template #preloader>\r\n <div class=\"wrapper\">\r\n <div class=\"preloader\">\r\n <img\r\n *ngIf=\"preview\"\r\n class=\"preloader__image\"\r\n [src]=\"preview\"\r\n alt=\"Preloader\"\r\n />\r\n </div>\r\n </div>\r\n</ng-template>\r\n\r\n\r\n", styles: [":host{font-weight:400;font-size:14px;line-height:20px;padding-top:6px;padding-bottom:6px;font-family:var(--cui-main-font);display:block}:host ::ng-deep .cdx-input{border:1px solid var(--cui-base-200);background:transparent;box-shadow:none}:host ::ng-deep .play{margin:auto}:host ::ng-deep .play path{fill:var(--cui-base-0);stroke:var(--cui-base-300)}:host._hidden{display:none}.wrapper{display:flex;flex-direction:column;margin-bottom:10px;border:1px solid var(--cui-base-200);border-radius:3px;min-height:200px;background-color:var(--cui-base-0)}.wrapper._loaded{min-height:auto}.video{display:block;max-width:100%}.preloader{width:50px;height:50px;border-radius:50%;background-size:cover;margin:auto;position:relative;background-color:var(--cui-base-200);background-position:center center}@keyframes preloader-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.preloader__image{width:50px;height:50px;border-radius:50%}.preloader:after{content:\"\";position:absolute;z-index:3;width:60px;height:60px;border-radius:50%;border:2px solid var(--cui-base-200);border-top-color:var(--cui-blue-600);left:50%;top:50%;margin-top:-30px;margin-left:-30px;animation:preloader-spin 2s infinite linear;box-sizing:border-box}.caption[data-placeholder]:empty:before{content:attr(data-placeholder);position:absolute;color:var(--cui-base-400)}.select-btn{display:flex;align-items:center;justify-content:center;width:100%}\n"] }]
5280
+ }], propDecorators: { video: [{
5281
+ type: Input,
5282
+ args: [{ required: true }]
5283
+ }] } });
5284
+
5285
+ const EDITOR_VIDEO_TOOL_SELECTOR = 'cc-editor-video-tool';
5286
+
5287
+ function createSelect(marker, tooltip) {
5288
+ const select = document.createElement(MARKER_SELECT_SELECTOR);
5289
+ const button = tooltip.querySelector('.edit');
5290
+ select.space = 8;
5291
+ select.target = button;
5292
+ select.addEventListener('toolClick', (event) => onToolClick(marker, tooltip, event));
5293
+ return select;
5294
+ }
5295
+ function createToolModal(marker, tooltip) {
5296
+ const toolModal = document.createElement(MARKER_MODAL_SELECTOR);
5297
+ const button = tooltip.querySelector('.edit');
5298
+ const toolId = marker.dataset['id'];
5299
+ const toolType = marker.dataset['type'];
5300
+ toolModal.title = marker.innerText;
5301
+ toolModal.target = button;
5302
+ toolModal.isTool = true;
5303
+ toolModal.tool = {
5304
+ id: toolId,
5305
+ type: toolType
5306
+ };
5307
+ toolModal.space = 8;
5308
+ toolModal.addEventListener('saveClicked', (event) => {
5309
+ const customEvent = event;
5310
+ const data = customEvent.detail.data;
5311
+ if (data && typeof data !== 'string') {
5312
+ marker.setAttribute('data-id', data.id);
5313
+ marker.setAttribute('data-type', data.type);
5314
+ }
5315
+ marker.innerHTML = customEvent.detail.title;
5316
+ tooltip.remove();
5317
+ });
5318
+ toolModal.addEventListener('cancelClicked', () => {
5319
+ tooltip.remove();
5320
+ });
5321
+ return toolModal;
5322
+ }
5323
+ function onToolClick(marker, tooltip, event) {
5324
+ event.stopPropagation();
5325
+ const customEvent = event;
5326
+ const tool = customEvent.detail;
5327
+ marker.dataset['id'] = tool.id;
5328
+ tooltip.remove();
5329
+ }
5330
+
5331
+ function removeElementTagWrapper(element) {
5332
+ const parent = element.parentElement;
5333
+ const innerElementNodes = element.childNodes;
5334
+ let node;
5335
+ while (innerElementNodes.length) {
5336
+ node = innerElementNodes.item(0);
5337
+ parent?.insertBefore(node, element);
5338
+ }
5339
+ element.remove();
5340
+ }
5341
+
5342
+ const tooltipMap = {
5343
+ MARK: createMarkerTooltip,
5344
+ A: createLinkTooltip
5345
+ };
5346
+ function createMarkerTooltip(marker) {
5347
+ const tooltip = createTooltip(marker, marker.innerText);
5348
+ setTimeout(() => {
5349
+ const select = createToolModal(marker, tooltip);
5350
+ tooltip.append(select);
5351
+ });
5352
+ return tooltip;
5353
+ }
5354
+ function createLinkTooltip(link) {
5355
+ const linkElement = link;
5356
+ const options = ['copy', 'edit', 'delete'];
5357
+ const linkUrl = linkElement.href;
5358
+ const tooltip = createTooltip(linkElement, linkUrl, options);
5359
+ tooltip.addEventListener('copyClicked', () => {
5360
+ window?.navigator.clipboard.writeText(linkUrl);
5361
+ });
5362
+ setTimeout(() => {
5363
+ const linkModal = createLinkModal(tooltip, linkElement);
5364
+ tooltip.append(linkModal);
5365
+ });
5366
+ return tooltip;
5367
+ }
5368
+ function createTooltip(element, title, options) {
5369
+ const tooltip = document.createElement(EDITOR_TOOLTIP_SELECTOR);
5370
+ tooltip.title = title;
5371
+ if (options) {
5372
+ tooltip.options = options;
5373
+ }
5374
+ tooltip.addEventListener('deleteClicked', (event) => {
5375
+ event.stopPropagation();
5376
+ removeElementTagWrapper(element);
5377
+ tooltip.remove();
5378
+ });
5379
+ return tooltip;
5380
+ }
5381
+
5382
+ var CuiFileUploaderStatus;
5383
+ (function (CuiFileUploaderStatus) {
5384
+ CuiFileUploaderStatus["Loading"] = "loading";
5385
+ CuiFileUploaderStatus["Completed"] = "completed";
5386
+ })(CuiFileUploaderStatus || (CuiFileUploaderStatus = {}));
5387
+ class CuiFileUploader {
5388
+ constructor(config, onUpload, onError) {
5389
+ this.REQUEST_METHOD = 'POST';
5390
+ this.selectFile = ({ fileSelected }) => {
5391
+ const input = document.createElement('input');
5392
+ const types = this.config?.types || '*';
5393
+ input.type = 'file';
5394
+ input.accept = types;
5395
+ input.onchange = () => {
5396
+ const files = input.files;
5397
+ if (!files?.length) {
5398
+ return;
5399
+ }
5400
+ this.getFile(files, fileSelected);
5401
+ };
5402
+ input.click();
5403
+ };
5404
+ this.config = config;
5405
+ this.onUpload = onUpload;
5406
+ this.onError = onError;
5407
+ }
5408
+ getFile(files, fileSelected) {
5409
+ const file = files.item(0);
5410
+ if (!file) {
5411
+ return;
5412
+ }
5413
+ fileSelected(file);
5414
+ }
5415
+ uploadFile(file) {
5416
+ const formData = new FormData();
5417
+ const formField = this.config.field || 'file';
5418
+ formData.append(formField, file);
5419
+ if (!this.config.endpoint) {
5420
+ return;
5421
+ }
5422
+ this.config.load(CuiFileUploaderStatus.Loading);
5423
+ const upload = fetch(this.config.endpoint, {
5424
+ headers: this.config.additionalRequestHeaders,
5425
+ method: this.REQUEST_METHOD,
5426
+ body: formData
5427
+ });
5428
+ upload
5429
+ .then((response) => response.json())
5430
+ .then((response) => this.onUpload(response, file))
5431
+ .catch(() => this.onError())
5432
+ .finally(() => this.config.load(CuiFileUploaderStatus.Completed));
5433
+ }
5434
+ uploadByUrl(url) {
5435
+ this.onUpload({ success: 1, file: { url } });
5436
+ }
5437
+ }
5438
+
5439
+ function recalculateIndexes(blocksApi) {
5440
+ if (!blocksApi) {
5441
+ return;
5442
+ }
5443
+ const blocks = blocksApi.getBlocksCount();
5444
+ let index = 0;
5445
+ for (let i = 0; i < blocks; i++) {
5446
+ const block = blocksApi.getBlockByIndex(i);
5447
+ if (!block) {
5448
+ continue;
5449
+ }
5450
+ const blockElement = block?.holder;
5451
+ const subblocks = blockElement.querySelectorAll('.' + COMBINED_TEXT_BLOCK_PART);
5452
+ blockElement.setAttribute('data-index', String(index));
5453
+ if (!subblocks.length) {
5454
+ index++;
5455
+ continue;
5456
+ }
5457
+ subblocks.forEach((subblock) => {
5458
+ const subBlockIndex = subblock.getAttribute('data-index');
5459
+ const indexAsNumber = subBlockIndex ? Number(subBlockIndex) : null;
5460
+ if (indexAsNumber !== null && indexAsNumber === index) {
5461
+ index++;
5462
+ return;
5463
+ }
5464
+ subblock.setAttribute('data-index', String(index));
5465
+ index++;
5466
+ });
5467
+ }
5468
+ }
5469
+
5470
+ const unsplittableTags = { mark: true, a: true };
5471
+ const PART_LENGTH_MEASUREMENT_ERROR = 20;
5472
+ const BR_TAG = '<br>';
5473
+ function splitHTML(input, maxLength = SPLIT_LENGTH) {
5474
+ const parts = [];
5475
+ const tagNames = [];
5476
+ const tags = [];
5477
+ let currentPart = '';
5478
+ let index = 0;
5479
+ // remove specsymbols
5480
+ input = input.replaceAll('&nbsp;', ' ');
5481
+ while (input.length > index) {
5482
+ while (currentPart.length < maxLength && input.length > index) {
5483
+ if (checkIsBrTag(input, index)) {
5484
+ // when br tag
5485
+ if (currentPart.length + BR_TAG.length > maxLength) {
5486
+ parts.push(currentPart);
5487
+ currentPart = BR_TAG;
5488
+ }
5489
+ else {
5490
+ currentPart += BR_TAG;
5491
+ }
5492
+ index += BR_TAG.length - 1;
5493
+ }
5494
+ else if (checkIsEndOfTag(input, index)) {
5495
+ // when tag ends
5496
+ const tagName = getEndTag(tagNames.pop());
5497
+ tags.pop();
5498
+ if ((currentPart + tagName).length > maxLength) {
5499
+ parts.push(currentPart);
5500
+ currentPart = '';
5501
+ }
5502
+ else {
5503
+ currentPart += tagName;
5504
+ }
5505
+ index += tagName.length - 1;
5506
+ }
5507
+ else if (input[index] === '<') {
5508
+ // when tag starts
5509
+ const { tag, tagName, newIndex } = getTagAndTagName(input, index);
5510
+ index = newIndex;
5511
+ if (checkIsLengthEnough(currentPart, tag)) {
5512
+ currentPart = switchPartWhenUnclosedTagsExist(tagNames, tags, parts, currentPart);
5513
+ }
5514
+ currentPart += tag;
5515
+ if (!unsplittableTags[tagName]) {
5516
+ tagNames.push(tagName);
5517
+ tags.push(tag);
5518
+ }
5519
+ }
5520
+ else {
5521
+ // other symbols
5522
+ currentPart += input[index];
5523
+ }
5524
+ index += 1;
5525
+ }
5526
+ currentPart = switchPartWhenUnclosedTagsExist(tagNames, tags, parts, currentPart);
5527
+ }
5528
+ return parts;
5529
+ }
5530
+ function switchPartWhenUnclosedTagsExist(tagNames, tags, parts, currentPart) {
5531
+ if (!tagNames.length) {
5532
+ parts.push(currentPart);
5533
+ return '';
5534
+ }
5535
+ let closeAllTags = '';
5536
+ for (let i = tagNames.length - 1; i >= 0; i -= 1) {
5537
+ closeAllTags += getEndTag(tagNames[i]);
5538
+ }
5539
+ currentPart += closeAllTags;
5540
+ parts.push(currentPart);
5541
+ currentPart = tags.reduce((openTags, tag) => (openTags += tag), '');
5542
+ return currentPart;
5543
+ }
5544
+ function getTagAndTagName(input, index) {
5545
+ let tag = '';
5546
+ let tagName = '';
5547
+ tag += input[index];
5548
+ index += 1;
5549
+ while (input[index] !== ' ' && input[index] !== '>') {
5550
+ tag += input[index];
5551
+ tagName += input[index];
5552
+ index += 1;
5553
+ }
5554
+ while (input[index] !== '>') {
5555
+ tag += input[index];
5556
+ index += 1;
5557
+ }
5558
+ tag += input[index];
5559
+ [tag, index] = getFullTag(input, index, tag, tagName);
5560
+ return { tag, tagName, newIndex: index };
5561
+ }
5562
+ function getFullTag(input, index, tag, tagName) {
5563
+ if (!unsplittableTags[tagName]) {
5564
+ return [tag, index];
5565
+ }
5566
+ let fullTag = tag;
5567
+ index += 1;
5568
+ while (!checkIsEndOfTag(input, index)) {
5569
+ fullTag += input[index];
5570
+ index += 1;
5571
+ }
5572
+ const endTag = getEndTag(tagName);
5573
+ index += endTag.length - 1;
5574
+ return [fullTag + endTag, index];
5575
+ }
5576
+ function checkIsLengthEnough(currentPart, tag) {
5577
+ return currentPart.length + tag.length + PART_LENGTH_MEASUREMENT_ERROR > SPLIT_LENGTH;
5578
+ }
5579
+ function getEndTag(tagName) {
5580
+ return '</' + tagName + '>';
5581
+ }
5582
+ function checkIsEndOfTag(input, index) {
5583
+ return input[index] === '<' && input[index + 1] === '/';
5584
+ }
5585
+ function checkIsBrTag(input, index) {
5586
+ let tag = '';
5587
+ if (input[index] !== '<') {
5588
+ return false;
5589
+ }
5590
+ while (input[index] && input[index] !== '>') {
5591
+ tag += input[index];
5592
+ index += 1;
5593
+ }
5594
+ return tag + '>' === BR_TAG;
5595
+ }
5596
+
5597
+ class CuiImageTool {
5598
+ get Tunes() {
5599
+ return [
5600
+ {
5601
+ name: 'stretched',
5602
+ title: 'Stretch image',
5603
+ toggle: true
5604
+ },
5605
+ {
5606
+ name: 'center',
5607
+ title: 'Center image',
5608
+ toggle: true
5609
+ }
5610
+ ];
5611
+ }
5612
+ static get isReadOnlySupported() {
5613
+ return true;
5614
+ }
5615
+ static get toolbox() {
5616
+ return {
5617
+ /* eslint-disable */
5618
+ icon: `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
5619
+ <path d="M12.5013 4.1665H7.5013C5.66035 4.1665 4.16797 5.65889 4.16797 7.49984V12.4998C4.16797 14.3408 5.66035 15.8332 7.5013 15.8332H12.5013C14.3423 15.8332 15.8346 14.3408 15.8346 12.4998V7.49984C15.8346 5.65889 14.3423 4.1665 12.5013 4.1665Z" stroke="#121315" stroke-width="1.66667"/>
5620
+ <path d="M4.28125 12.7665L7.24033 9.63825C7.52263 9.33617 7.90546 9.1665 8.30463 9.1665C8.70377 9.1665 9.0866 9.33617 9.36893 9.63825L12.8208 13.3332M11.3154 11.7218L12.5092 10.444C12.7914 10.1419 13.1743 9.97217 13.5734 9.97217C13.9726 9.97217 14.3554 10.1419 14.6378 10.444L15.699 11.636" stroke="#121315" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"/>
5621
+ <path d="M11.4805 7.77783H11.4879" stroke="#121315" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"/>
5622
+ </svg>`,
5623
+ /* eslint-enable */
5624
+ title: 'Image'
5625
+ };
5626
+ }
5627
+ static get pasteConfig() {
5628
+ return {
5629
+ tags: [
5630
+ {
5631
+ img: { src: true }
5632
+ }
5633
+ ],
5634
+ files: {
5635
+ mimeTypes: ['image/*']
5636
+ }
5637
+ };
5638
+ }
5639
+ constructor(options) {
5640
+ this.selectedFile = null;
5641
+ this.onSelectFile = () => {
5642
+ return this.uploader.selectFile({
5643
+ fileSelected: (file) => {
5644
+ const url = URL.createObjectURL(file);
5645
+ this.imageTool.preview = url;
5646
+ this.imageTool.isLoading = true;
5647
+ this.selectedFile = file;
5648
+ this.uploader.uploadFile(file);
5649
+ }
5650
+ });
5651
+ };
5652
+ const { api, readOnly, config, data, block } = options;
5653
+ this.blockApi = block;
5654
+ this.api = api;
5655
+ this.readOnly = readOnly;
5656
+ this.config = {
5657
+ load: config?.load ?? (() => { }),
5658
+ field: config?.field ?? 'image',
5659
+ types: config?.types ?? 'image/*',
5660
+ endpoint: config?.endpoint ?? '',
5661
+ buttonContent: config?.buttonContent ?? this.api.i18n.t('Select an Image'),
5662
+ additionalRequestHeaders: config?.additionalRequestHeaders || {},
5663
+ };
5664
+ this.uploader = new CuiFileUploader(this.config, this.onUpload.bind(this), this.uploadingFailed.bind(this));
5665
+ this.data = data;
5666
+ this.data.tunes = this.data.tunes || {};
5667
+ }
5668
+ async onPaste(event) {
5669
+ const actions = {
5670
+ tag: this.pasteByTag.bind(this),
5671
+ file: this.pasteByFile.bind(this)
5672
+ };
5673
+ const key = event.type;
5674
+ this.imageTool.isLoading = true;
5675
+ actions[key](event);
5676
+ }
5677
+ pasteByFile(event) {
5678
+ const file = event.detail.file;
5679
+ this.selectedFile = file;
5680
+ this.uploader.uploadFile(file);
5681
+ }
5682
+ pasteByTag(event) {
5683
+ const file = event.detail.data.src;
5684
+ this.selectedFile = file;
5685
+ this.uploader.uploadByUrl(file);
5686
+ }
5687
+ appendCallback() {
5688
+ this.onSelectFile();
5689
+ }
5690
+ render() {
5691
+ this.imageTool = document.createElement(EDITOR_IMAGE_TOOL_SELECTOR);
5692
+ this.imageTool.api = this.api;
5693
+ this.imageTool.image = this.data.file?.url || '';
5694
+ this.imageTool.caption = this.data.caption || '';
5695
+ this.imageTool.tunes = this.data.tunes;
5696
+ this.imageTool.readOnly = this.readOnly;
5697
+ this.imageTool.buttonContent = this.config.buttonContent;
5698
+ this.imageTool.addEventListener('fileSelected', this.onSelectFile);
5699
+ this.imageTool.addEventListener('captionChanged', this.changeCaption.bind(this));
5700
+ return this.imageTool;
5701
+ }
5702
+ renderSettings() {
5703
+ return this.Tunes.map((tune) => ({
5704
+ icon: tune.icon,
5705
+ label: this.api.i18n.t(tune.title),
5706
+ name: tune.name,
5707
+ toggle: tune.toggle,
5708
+ isActive: this.data.tunes[tune.name],
5709
+ onActivate: () => this.tuneToggled(tune.name)
5710
+ }));
5711
+ }
5712
+ save() {
5713
+ return this.data;
5714
+ }
5715
+ removed() {
5716
+ this.imageTool.removeEventListener('fileSelected', this.onSelectFile);
5717
+ this.imageTool.removeEventListener('captionChanged', this.changeCaption);
5718
+ }
5719
+ changeCaption(event) {
5720
+ const customEvent = event;
5721
+ const value = customEvent.detail;
5722
+ this.data.caption = value;
5723
+ this.blockApi?.dispatchChange();
5724
+ }
5725
+ set image(file) {
5726
+ this.data.file = file || {};
5727
+ if (file && file.url) {
5728
+ this.imageTool.image = file.url;
5729
+ }
5730
+ }
5731
+ onUpload(response) {
5732
+ if (!response.success || !response.file || !this.selectedFile) {
5733
+ this.uploadingFailed();
5734
+ return;
5735
+ }
5736
+ const url = this.selectedFile instanceof File ? window.URL.createObjectURL(this.selectedFile) : this.selectedFile;
5737
+ this.data.file = response.file;
5738
+ this.imageTool.image = url;
5739
+ this.imageTool.isLoading = false;
5740
+ }
5741
+ uploadingFailed() {
5742
+ this.imageTool.image = '';
5743
+ this.imageTool.isLoading = false;
5744
+ }
5745
+ tuneToggled(tuneName) {
5746
+ const value = !(this.data.tunes[tuneName] || false);
5747
+ this.data.tunes[tuneName] = value;
5748
+ this.imageTool.tunes = { ...this.data.tunes };
5749
+ }
5750
+ }
5751
+
5752
+ class CuiVideoTool {
5753
+ static get isReadOnlySupported() {
5754
+ return true;
5755
+ }
5756
+ static get toolbox() {
5757
+ return {
5758
+ icon: CUI_ICONS.cuiIconPlayCircle,
5759
+ title: 'Video'
5760
+ };
5761
+ }
5762
+ static get pasteConfig() {
5763
+ return {
5764
+ tags: ['video'],
5765
+ patterns: {
5766
+ video: /https?:\/\/\S+\.(mp4)$/i
5767
+ },
5768
+ files: {
5769
+ mimeTypes: ['video/*']
5770
+ }
5771
+ };
5772
+ }
5773
+ constructor(options) {
5774
+ this.selectedFile = null;
5775
+ this.onSelectFile = () => {
5776
+ return this.uploader.selectFile({
5777
+ fileSelected: (file) => {
5778
+ const url = URL.createObjectURL(file);
5779
+ this.getCaptureFromVideo(url);
5780
+ this.videoTool.isLoading = true;
5781
+ this.selectedFile = file;
5782
+ this.uploader.uploadFile(file);
5783
+ }
5784
+ });
5785
+ };
5786
+ const { api, readOnly, config, data, block } = options;
5787
+ this.blockApi = block;
5788
+ this.api = api;
5789
+ this.readOnly = readOnly;
5790
+ this.config = {
5791
+ load: config?.load ?? (() => { }),
5792
+ field: config?.field ?? 'video',
5793
+ types: config?.types ?? 'video/*',
5794
+ endpoint: config?.endpoint ?? '',
5795
+ buttonContent: config?.buttonContent ?? this.api.i18n.t('Select a Video'),
5796
+ additionalRequestHeaders: config?.additionalRequestHeaders ?? {},
5797
+ };
5798
+ this.uploader = new CuiFileUploader(this.config, this.onUpload.bind(this), this.uploadingFailed.bind(this));
5799
+ this.data = data;
5800
+ }
5801
+ async onPaste(event) {
5802
+ if (event.type !== 'file') {
5803
+ return;
5804
+ }
5805
+ const file = event.detail.file;
5806
+ this.videoTool.isLoading = true;
5807
+ this.selectedFile = file;
5808
+ this.uploader.uploadFile(file);
5809
+ }
5810
+ appendCallback() {
5811
+ this.onSelectFile();
5812
+ }
5813
+ render() {
5814
+ this.videoTool = document.createElement(EDITOR_VIDEO_TOOL_SELECTOR);
5815
+ this.videoTool.api = this.api;
5816
+ this.videoTool.video = this.data.file?.url || '';
5817
+ this.videoTool.caption = this.data.caption || '';
5818
+ this.videoTool.readOnly = this.readOnly;
5819
+ this.videoTool.buttonContent = this.config.buttonContent;
5820
+ this.videoTool.addEventListener('fileSelected', this.onSelectFile);
5821
+ this.videoTool.addEventListener('captionChanged', this.changeCaption.bind(this));
5822
+ return this.videoTool;
5823
+ }
5824
+ save() {
5825
+ return this.data;
5826
+ }
5827
+ removed() {
5828
+ this.videoTool.removeEventListener('fileSelected', this.onSelectFile);
5829
+ this.videoTool.removeEventListener('captionChanged', this.changeCaption);
5830
+ }
5831
+ changeCaption(event) {
5832
+ const customEvent = event;
5833
+ const value = customEvent.detail;
5834
+ this.data.caption = value;
5835
+ this.blockApi?.dispatchChange();
5836
+ }
5837
+ set video(file) {
5838
+ this.data.file = file || {};
5839
+ if (file && file.url) {
5840
+ this.videoTool.video = file.url;
5841
+ }
5842
+ }
5843
+ onUpload(response) {
5844
+ if (!response.success || !response.file || !this.selectedFile) {
5845
+ this.uploadingFailed();
5846
+ return;
5847
+ }
5848
+ const url = this.selectedFile instanceof File ? window.URL.createObjectURL(this.selectedFile) : this.selectedFile;
5849
+ this.data.file = response.file;
5850
+ this.videoTool.video = url;
5851
+ this.videoTool.isLoading = false;
5852
+ }
5853
+ uploadingFailed() {
5854
+ this.videoTool.video = '';
5855
+ this.videoTool.isLoading = false;
5856
+ }
5857
+ getCaptureFromVideo(url) {
5858
+ const canvas = document.createElement('canvas');
5859
+ const video = document.createElement('video');
5860
+ video.src = url;
5861
+ video.currentTime = 1;
5862
+ canvas.width = 120;
5863
+ canvas.height = 120;
5864
+ video.onloadeddata = () => {
5865
+ const context = canvas.getContext('2d');
5866
+ if (!context) {
5867
+ return;
5868
+ }
5869
+ context.drawImage(video, 0, 0, canvas.width, canvas.height);
5870
+ canvas.toBlob((blob) => {
5871
+ if (!blob) {
5872
+ return;
5873
+ }
5874
+ this.videoTool.preview = URL.createObjectURL(blob);
5875
+ });
5876
+ };
5877
+ video.load();
5878
+ }
5879
+ }
5880
+
5881
+ class CuiAttachesTool {
5882
+ static get isReadOnlySupported() {
5883
+ return true;
5884
+ }
5885
+ static get toolbox() {
5886
+ return {
5887
+ icon: CUI_ICONS.cuiIconPaperclipSm,
5888
+ title: 'File'
5889
+ };
5890
+ }
5891
+ constructor(options) {
5892
+ this.selectedFile = null;
5893
+ this.onSelectFile = () => {
5894
+ return this.uploader.selectFile({
5895
+ fileSelected: (file) => {
5896
+ this.attachesTool.isLoading = true;
5897
+ this.selectedFile = file;
5898
+ this.uploader.uploadFile(file);
5899
+ }
5900
+ });
5901
+ };
5902
+ const { api, readOnly, config, data, block } = options;
5903
+ this.blockApi = block;
5904
+ this.api = api;
5905
+ this.readOnly = readOnly;
5906
+ this.config = {
5907
+ load: config?.load ?? (() => { }),
5908
+ field: config?.field ?? 'file',
5909
+ types: config?.types ?? '*',
5910
+ endpoint: config?.endpoint ?? '',
5911
+ buttonContent: config?.buttonContent ?? this.api.i18n.t('Select a File'),
5912
+ additionalRequestHeaders: config?.additionalRequestHeaders ?? {},
5913
+ };
5914
+ this.uploader = new CuiFileUploader(this.config, this.onUpload.bind(this), this.uploadingFailed.bind(this));
5915
+ this.data = data;
5916
+ }
5917
+ appendCallback() {
5918
+ this.onSelectFile();
5919
+ }
5920
+ render() {
5921
+ this.attachesTool = document.createElement(EDITOR_ATTACHES_TOOL_SELECTOR);
5922
+ this.attachesTool.api = this.api;
5923
+ this.attachesTool.file = this.data.file ?? '';
5924
+ this.attachesTool.title = this.data.title ?? '';
5925
+ this.attachesTool.readOnly = this.readOnly;
5926
+ this.attachesTool.buttonContent = this.config.buttonContent;
5927
+ this.attachesTool.addEventListener('fileSelected', this.onSelectFile);
5928
+ this.attachesTool.addEventListener('captionChanged', this.changeCaption.bind(this));
5929
+ return this.attachesTool;
5930
+ }
5931
+ save() {
5932
+ return this.data;
5933
+ }
5934
+ removed() {
5935
+ this.attachesTool.removeEventListener('fileSelected', this.onSelectFile);
5936
+ this.attachesTool.removeEventListener('captionChanged', this.changeCaption);
5937
+ }
5938
+ changeCaption(event) {
5939
+ const customEvent = event;
5940
+ const value = customEvent.detail;
5941
+ this.data.title = value;
5942
+ this.blockApi?.dispatchChange();
5943
+ }
5944
+ set file(file) {
5945
+ this.data.title = file.name;
5946
+ this.data.file = {
5947
+ name: file.name,
5948
+ extension: file.name?.split('.').pop(),
5949
+ size: file.size,
5950
+ url: file.url
5951
+ };
5952
+ this.attachesTool.file = { ...this.data.file };
5953
+ this.attachesTool.title = file.name;
5954
+ }
5955
+ onUpload(response) {
5956
+ if (!response.success || !response.file || !this.selectedFile) {
5957
+ this.uploadingFailed();
5958
+ return;
5959
+ }
5960
+ this.file = {
5961
+ name: this.selectedFile.name,
5962
+ extension: this.selectedFile.name.split('.').pop(),
5963
+ size: this.selectedFile.size,
5964
+ url: response.file.url
5965
+ };
5966
+ this.attachesTool.isLoading = false;
5967
+ }
5968
+ uploadingFailed() {
5969
+ this.attachesTool.file = undefined;
5970
+ this.attachesTool.isLoading = false;
5971
+ }
5972
+ }
5973
+
5974
+ var RangeContainer;
5975
+ (function (RangeContainer) {
5976
+ RangeContainer["start"] = "startContainer";
5977
+ RangeContainer["end"] = "endContainer";
5978
+ })(RangeContainer || (RangeContainer = {}));
5979
+ class CuiMarkerTool {
5980
+ static get isInline() {
5981
+ return true;
5982
+ }
5983
+ get state() {
5984
+ return this._state;
5985
+ }
5986
+ set state(state) {
5987
+ this._state = state;
5988
+ this.button?.classList.toggle(this.api.styles.inlineToolButtonActive, state);
5989
+ }
5990
+ constructor(data) {
5991
+ this.LIST_CLASS = 'cdx-list__item';
5992
+ this.DEFAULT_CLASS = 'marker';
5993
+ this.DIV = 'div';
5994
+ this.TAG = 'MARK';
5995
+ this.CLASS = 'tool-marker';
5996
+ this._state = false;
5997
+ this.api = data.api;
5998
+ }
5999
+ render() {
6000
+ this.button = document.createElement('button');
6001
+ this.button.type = 'button';
6002
+ this.button.classList.add(this.api.styles.inlineToolButton);
6003
+ this.range = window.getSelection()?.getRangeAt(0).cloneRange();
6004
+ return this.button;
6005
+ }
6006
+ surround() {
6007
+ if (this.state) {
6008
+ this.api.inlineToolbar.close();
6009
+ this.unwrap();
6010
+ return;
6011
+ }
6012
+ this.markerModal.title = this.range.toString();
6013
+ }
6014
+ wrap(range) {
6015
+ const { startContainer, endContainer } = range;
6016
+ const selectedText = range.extractContents();
6017
+ const mark = this.createElement();
6018
+ mark.appendChild(selectedText);
6019
+ this.removeNestedMarkers(mark, this.DEFAULT_CLASS);
6020
+ this.addMarkerToDOM(range, mark, startContainer, endContainer);
6021
+ this.removeExternalMarkers(range, this.DEFAULT_CLASS);
6022
+ this.removeEmptyMarkers(range);
6023
+ this.api.selection.expandToTag(mark);
6024
+ }
6025
+ unwrap() {
6026
+ const mark = this.api.selection.findParentTag(this.TAG, this.CLASS);
6027
+ if (!mark) {
6028
+ return;
6029
+ }
6030
+ removeElementTagWrapper(mark);
6031
+ }
6032
+ createElement(text = '') {
6033
+ const element = document.createElement(this.TAG);
6034
+ element.classList.add(this.DEFAULT_CLASS);
6035
+ element.textContent = text;
6036
+ return element;
6037
+ }
6038
+ addMarkerToDOM(range, mark, startBlock, endBlock) {
6039
+ const classes = [this.LIST_CLASS, COMBINED_TEXT_BLOCK_PART];
6040
+ const { className, parent: startParent } = this.getClosestParentWithClass(startBlock, classes);
6041
+ const { parent: endParent } = this.getClosestParentWithClass(endBlock, classes);
6042
+ if (!className || startParent === endParent) {
6043
+ range.insertNode(mark);
6044
+ return;
6045
+ }
6046
+ this.removeAllParentsFromMarker(mark, className);
6047
+ startParent?.append(mark);
6048
+ }
6049
+ removeEmptyMarkers(range) {
6050
+ range.commonAncestorContainer.childNodes.forEach((node) => {
6051
+ if (node.nodeName !== this.TAG) {
6052
+ return;
6053
+ }
6054
+ if (node.textContent?.length) {
6055
+ return;
6056
+ }
6057
+ node.remove();
6058
+ });
6059
+ }
6060
+ removeExternalMarkers(range, className) {
6061
+ const startContainer = this.getElementFromContainerNode(range, RangeContainer.start, className);
6062
+ const endContainer = this.getElementFromContainerNode(range, RangeContainer.end, className);
6063
+ const startElement = startContainer?.closest('.' + className);
6064
+ const endElement = endContainer?.closest('.' + className);
6065
+ if (startElement !== endElement || !startElement?.classList.contains(className)) {
6066
+ return;
6067
+ }
6068
+ const marker = startElement;
6069
+ removeElementTagWrapper(marker);
6070
+ }
6071
+ removeNestedMarkers(element, selector) {
6072
+ const markers = element.querySelectorAll('.' + selector);
6073
+ markers.forEach((node) => {
6074
+ const marker = node;
6075
+ removeElementTagWrapper(marker);
6076
+ });
6077
+ }
6078
+ getElementFromContainerNode(range, key, className) {
6079
+ const container = range[key];
6080
+ if (container?.classList?.contains(className)) {
6081
+ return container;
6082
+ }
6083
+ return container.parentElement;
6084
+ }
6085
+ removeAllParentsFromMarker(mark, className) {
6086
+ const innerMarkerNodes = [];
6087
+ mark.childNodes.forEach((node) => {
6088
+ innerMarkerNodes.push(node);
6089
+ });
6090
+ innerMarkerNodes.forEach((node) => {
6091
+ const element = node;
6092
+ const isBlock = element.classList?.contains(className);
6093
+ if (!isBlock) {
6094
+ return;
6095
+ }
6096
+ removeElementTagWrapper(element);
6097
+ });
6098
+ }
6099
+ getClosestParentWithClass(node, classes) {
6100
+ const nodeParent = node.parentElement;
6101
+ let parent = nodeParent;
6102
+ let resultClassName = '';
6103
+ for (const className of classes) {
6104
+ const parentWithClass = parent.closest('.' + className);
6105
+ if (!parentWithClass) {
6106
+ continue;
6107
+ }
6108
+ parent = parentWithClass;
6109
+ resultClassName = className;
6110
+ break;
6111
+ }
6112
+ return { className: resultClassName, parent };
6113
+ }
6114
+ }
6115
+
6116
+ class CuiLinkMarker extends CuiMarkerTool {
6117
+ static get sanitize() {
6118
+ return {
6119
+ a: {
6120
+ href: true,
6121
+ class: true,
6122
+ target: true,
6123
+ contenteditable: true
6124
+ }
6125
+ };
6126
+ }
6127
+ constructor(data) {
6128
+ super(data);
6129
+ this.TAG = 'A';
6130
+ }
6131
+ render() {
6132
+ super.render();
6133
+ /* eslint-disable */
6134
+ this.button.innerHTML = `<svg width="20" height="15" viewBox="-3 -3 24 19" fill="none" xmlns="http://www.w3.org/2000/svg">
6135
+ <path d="M18.2813 1.22405C17.9329 0.874451 17.5189 0.597062 17.0631 0.407792C16.6073 0.218522 16.1186 0.121094 15.625 0.121094C15.1315 0.121094 14.6428 0.218522 14.187 0.407792C13.7312 0.597062 13.3172 0.874451 12.9688 1.22405L13.8563 2.11155C14.089 1.87886 14.3652 1.69429 14.6692 1.56836C14.9733 1.44243 15.2991 1.37762 15.6282 1.37762C15.9572 1.37762 16.2831 1.44243 16.5871 1.56836C16.8911 1.69429 17.1674 1.87886 17.4 2.11155C17.6327 2.34424 17.8173 2.62047 17.9432 2.92449C18.0692 3.22851 18.134 3.55436 18.134 3.88343C18.134 4.21249 18.0692 4.53834 17.9432 4.84236C17.8173 5.14638 17.6327 5.42261 17.4 5.6553L12.4 10.6553C11.9309 11.1252 11.2944 11.3896 10.6304 11.3901C9.96638 11.3907 9.32935 11.1275 8.85942 10.6584C8.38949 10.1893 8.12515 9.55275 8.12457 8.88876C8.12398 8.22476 8.38719 7.58773 8.85629 7.1178L9.73754 6.2303L8.85629 5.3428L7.96879 6.2303C7.61919 6.57869 7.3418 6.99266 7.15253 7.44848C6.96326 7.9043 6.86583 8.393 6.86583 8.88655C6.86583 9.3801 6.96326 9.8688 7.15253 10.3246C7.3418 10.7804 7.61919 11.1944 7.96879 11.5428C8.67597 12.2409 9.63134 12.6298 10.625 12.624C11.1205 12.6261 11.6114 12.5299 12.0695 12.3411C12.5276 12.1523 12.9437 11.8746 13.2938 11.524L18.2938 6.52405C18.9944 5.81927 19.3866 4.86522 19.3842 3.87146C19.3819 2.87771 18.9852 1.92552 18.2813 1.22405Z" fill="#595E6A"/>
6136
+ <path d="M2.61879 12.5115C2.38541 12.2793 2.20022 12.0031 2.07386 11.6991C1.94749 11.395 1.88244 11.069 1.88244 10.7397C1.88244 10.4104 1.94749 10.0844 2.07386 9.78028C2.20022 9.47621 2.38541 9.2001 2.61879 8.9678L7.61879 3.9678C7.85109 3.73442 8.1272 3.54923 8.43127 3.42287C8.73534 3.2965 9.06138 3.23145 9.39067 3.23145C9.71995 3.23145 10.046 3.2965 10.3501 3.42287C10.6541 3.54923 10.9302 3.73442 11.1625 3.9678C11.3944 4.20193 11.577 4.48022 11.6994 4.78619C11.8218 5.09215 11.8815 5.41958 11.875 5.74905C11.8769 6.07955 11.8133 6.40715 11.6878 6.7129C11.5623 7.01865 11.3774 7.29647 11.1438 7.5303L9.81879 8.87405L10.7063 9.76155L12.0313 8.43655C12.7366 7.73124 13.1328 6.77463 13.1328 5.77718C13.1328 4.77972 12.7366 3.82311 12.0313 3.1178C11.326 2.41249 10.3694 2.01625 9.37192 2.01625C8.37446 2.01625 7.41785 2.41249 6.71254 3.1178L1.71254 8.1178C1.362 8.4663 1.08382 8.88066 0.893994 9.33706C0.704168 9.79346 0.606445 10.2829 0.606445 10.7772C0.606445 11.2715 0.704168 11.7609 0.893994 12.2173C1.08382 12.6737 1.362 13.088 1.71254 13.4365C2.42431 14.1293 3.38185 14.5115 4.37504 14.499C5.37698 14.5 6.33862 14.1046 7.05004 13.399L6.16254 12.5115C5.93025 12.7449 5.65413 12.9301 5.35006 13.0565C5.04599 13.1829 4.71995 13.2479 4.39067 13.2479C4.06138 13.2479 3.73534 13.1829 3.43127 13.0565C3.1272 12.9301 2.85109 12.7449 2.61879 12.5115Z" fill="#595E6A"/>
6137
+ </svg>
6138
+ `;
6139
+ /* eslint-enable */
6140
+ return this.button;
6141
+ }
6142
+ renderActions() {
6143
+ this.dropdown = document.createElement(this.DIV);
6144
+ if (this.state) {
6145
+ return this.dropdown;
6146
+ }
6147
+ const linkModal = this.createLinkModal();
6148
+ this.dropdown.append(linkModal);
6149
+ return this.dropdown;
6150
+ }
6151
+ wrapLink(range, markerData) {
6152
+ const { startContainer, endContainer } = range;
6153
+ const url = markerData.data?.toString();
6154
+ const link = this.createElement(url, markerData.title);
6155
+ range.extractContents();
6156
+ this.addMarkerToDOM(range, link, startContainer, endContainer);
6157
+ this.removeExternalMarkers(range, this.DEFAULT_CLASS);
6158
+ this.removeEmptyMarkers(range);
6159
+ this.api.selection.expandToTag(link);
6160
+ }
6161
+ unwrap() {
6162
+ const mark = this.api.selection.findParentTag(this.TAG);
6163
+ if (!mark) {
6164
+ return;
6165
+ }
6166
+ removeElementTagWrapper(mark);
6167
+ }
6168
+ createElement(url = '', text = '') {
6169
+ const link = super.createElement(text);
6170
+ link.href = url;
6171
+ link.contentEditable = 'false';
6172
+ link.target = '_blank';
6173
+ return link;
6174
+ }
6175
+ checkState() {
6176
+ const link = this.api.selection.findParentTag(this.TAG);
6177
+ this.state = !!link;
6178
+ }
6179
+ createLinkModal() {
6180
+ this.markerModal = document.createElement(MARKER_MODAL_SELECTOR);
6181
+ this.markerModal.url = '';
6182
+ this.markerModal.target = this.button;
6183
+ this.markerModal.isGlobal = true;
6184
+ this.markerModal.addEventListener('saveClicked', (event) => {
6185
+ const customEvent = event;
6186
+ const data = customEvent.detail;
6187
+ this.wrapLink(this.range, data);
6188
+ });
6189
+ return this.markerModal;
6190
+ }
6191
+ }
6192
+
6193
+ class CuiCustomMarkerTool extends CuiMarkerTool {
6194
+ static get sanitize() {
6195
+ return {
6196
+ mark: {
6197
+ class: true,
6198
+ 'data-id': true,
6199
+ 'data-type': true,
6200
+ contenteditable: true
6201
+ }
6202
+ };
6203
+ }
6204
+ constructor(data) {
6205
+ super(data);
6206
+ }
6207
+ wrapTool(range, markerData) {
6208
+ const { startContainer, endContainer } = range;
6209
+ if (markerData.data && typeof markerData.data !== 'string') {
6210
+ this.id = markerData.data.id;
6211
+ this.type = markerData.data.type;
6212
+ }
6213
+ const mark = this.createElement(markerData.title);
6214
+ range.extractContents();
6215
+ this.removeNestedMarkers(mark, this.DEFAULT_CLASS);
6216
+ this.addMarkerToDOM(range, mark, startContainer, endContainer);
6217
+ this.removeExternalMarkers(range, this.DEFAULT_CLASS);
6218
+ this.removeEmptyMarkers(range);
6219
+ this.api.selection.expandToTag(mark);
6220
+ }
6221
+ onToolButtonClick(event) {
6222
+ const range = window.getSelection()?.getRangeAt(0);
6223
+ if (range) {
6224
+ return;
6225
+ }
6226
+ event.stopImmediatePropagation();
6227
+ }
6228
+ render() {
6229
+ super.render();
6230
+ this.button.onclick = this.onToolButtonClick.bind(this);
6231
+ return this.button;
6232
+ }
6233
+ renderActions() {
6234
+ this.dropdown = document.createElement(this.DIV);
6235
+ if (this.state) {
6236
+ return this.dropdown;
6237
+ }
6238
+ const markerSelect = this.createLinkModal();
6239
+ this.dropdown.append(markerSelect);
6240
+ return this.dropdown;
6241
+ }
6242
+ createElement(text = '') {
6243
+ const element = super.createElement(text);
6244
+ element.contentEditable = 'false';
6245
+ element.classList.add(this.CLASS);
6246
+ element.setAttribute('data-id', this.id);
6247
+ element.setAttribute('data-type', this.type);
6248
+ return element;
6249
+ }
6250
+ checkState(select) {
6251
+ const range = select.getRangeAt(0);
6252
+ const mark = this.api.selection.findParentTag(this.TAG);
6253
+ const isCorrectTool = mark?.classList.contains(this.CLASS);
6254
+ if (!mark || !isCorrectTool) {
6255
+ this.state = false;
6256
+ return;
6257
+ }
6258
+ const startContainer = range.startContainer;
6259
+ const endContainer = range.endContainer;
6260
+ const isStartMarker = mark.contains(startContainer);
6261
+ const isEndMarker = mark.contains(endContainer);
6262
+ this.state = isStartMarker && isEndMarker && isStartMarker === isEndMarker;
6263
+ }
6264
+ createLinkModal() {
6265
+ this.markerModal = document.createElement(MARKER_MODAL_SELECTOR);
6266
+ this.markerModal.tool = { id: '', title: '', type: undefined };
6267
+ this.markerModal.target = this.button;
6268
+ this.markerModal.isTool = true;
6269
+ this.markerModal.isGlobal = true;
6270
+ this.markerModal.addEventListener('saveClicked', (event) => {
6271
+ const customEvent = event;
6272
+ const data = customEvent.detail;
6273
+ this.wrapTool(this.range, data);
6274
+ });
6275
+ return this.markerModal;
6276
+ }
6277
+ }
6278
+
6279
+ class CuiRoleMarker extends CuiCustomMarkerTool {
6280
+ constructor(data) {
6281
+ super(data);
6282
+ this.CLASS = 'role-marker';
6283
+ }
6284
+ render() {
6285
+ super.render();
6286
+ /* eslint-disable */
6287
+ this.button.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="-3 -3 24 24" fill="none">
6288
+ <path d="M13.3335 17.5V15.8333C13.3335 14.9493 12.9823 14.1014 12.3572 13.4763C11.7321 12.8512 10.8842 12.5 10.0002 12.5H4.16683C3.28277 12.5 2.43493 12.8512 1.80981 13.4763C1.18469 14.1014 0.833496 14.9493 0.833496 15.8333V17.5M16.6668 6.66667V11.6667M19.1668 9.16667H14.1668M10.4168 5.83333C10.4168 7.67428 8.92445 9.16667 7.0835 9.16667C5.24255 9.16667 3.75016 7.67428 3.75016 5.83333C3.75016 3.99238 5.24255 2.5 7.0835 2.5C8.92445 2.5 10.4168 3.99238 10.4168 5.83333Z" stroke="#595E6A" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
6289
+ </svg>`;
6290
+ /* eslint-enable */
6291
+ return this.button;
6292
+ }
6293
+ }
6294
+
6295
+ class CuiToolMarker extends CuiCustomMarkerTool {
6296
+ constructor(data) {
6297
+ super(data);
6298
+ this.CLASS = 'tool-marker';
6299
+ }
6300
+ render() {
6301
+ super.render();
6302
+ this.button.innerHTML =
6303
+ '<svg width="20" height="20" viewBox="-2 -3 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="technologies-tools"><path id="Vector" d="M16.3581 15.3966L16.3581 11.4729C16.3581 11.4158 16.3469 11.3592 16.325 11.3064C16.3031 11.2536 16.2711 11.2056 16.2307 11.1652C16.1903 11.1248 16.1423 11.0928 16.0895 11.0709C16.0368 11.0491 15.9802 11.0378 15.923 11.0378H13.2574L13.2593 11.0372C13.2007 11.0348 13.1422 11.0443 13.0874 11.0651C13.0326 11.0859 12.9825 11.1176 12.9402 11.1582C12.898 11.1989 12.8643 11.2476 12.8414 11.3016C12.8184 11.3556 12.8066 11.4136 12.8067 11.4723L12.8067 15.3972M14.584 11.0334V5.8334M16.3582 15.1022L16.3582 17.0647C16.3583 17.1234 16.3465 17.1814 16.3235 17.2354C16.3006 17.2893 16.2669 17.3381 16.2247 17.3787C16.1824 17.4194 16.1323 17.4511 16.0775 17.4719C16.0227 17.4927 15.9642 17.5022 15.9056 17.4998L15.9075 17.4992H13.2419C13.1847 17.4992 13.1282 17.4879 13.0754 17.466C13.0226 17.4442 12.9746 17.4121 12.9342 17.3717C12.8938 17.3313 12.8618 17.2834 12.8399 17.2306C12.818 17.1778 12.8068 17.1212 12.8068 17.0641L12.8068 15.1022M5.59636 9.88719L5.59636 15.9284C5.59627 16.0872 5.62748 16.2445 5.68821 16.3912C5.74895 16.5379 5.838 16.6713 5.9503 16.7836C6.06259 16.8959 6.19591 16.9849 6.34265 17.0456C6.48938 17.1064 6.64665 17.1376 6.80545 17.1375C7.12589 17.1375 7.43318 17.0101 7.65976 16.7836C7.88634 16.557 8.01365 16.2497 8.0137 15.9293L8.01284 9.88719C9.29329 9.32793 10.4298 8.05047 10.4298 6.56367C10.4302 5.07729 9.22194 3.54264 8.01284 3.241L8.01327 5.83907L6.8046 7.2887L5.59636 5.83864L5.59636 3.241C4.38769 3.54306 3.17902 5.07729 3.17902 6.5641C3.17944 8.05048 4.31591 9.32793 5.59636 9.88719ZM14.9916 5.56545L14.1253 5.56545L13.2589 4.69909L13.6921 2.5332L15.4248 2.5332L15.858 4.69909L14.9916 5.56545Z" stroke="#595E6A" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></g></svg>';
6304
+ return this.button;
6305
+ }
6306
+ }
6307
+
6308
+ class CuiCombinedTextBlockTool {
6309
+ constructor(options) {
6310
+ this.TAG = 'span';
6311
+ this.DEBOUNCE_TIME = 350;
6312
+ this.MAX_CHILD_COUNT_FOR_EMPTY = 1;
6313
+ this.PLACEHOLDER_ATTRIBUTE_NAME = 'placeholderActive';
6314
+ this.mutationConfig = {
6315
+ subtree: true,
6316
+ childList: true,
6317
+ characterData: true
6318
+ };
6319
+ this.changes = new Map();
6320
+ this.getMutationCallback = (wait) => {
6321
+ let timeoutId = null;
6322
+ return () => {
6323
+ if (timeoutId) {
6324
+ clearTimeout(timeoutId);
6325
+ }
6326
+ timeoutId = setTimeout(() => this.handleMutations(), wait);
6327
+ };
6328
+ };
6329
+ const body = options;
6330
+ const data = body.data;
6331
+ this.readOnly = body.readOnly;
6332
+ this.placeholder = this.getPlaceholder(body.config);
6333
+ this.api = body.api;
6334
+ this.data = {
6335
+ id: data.id || generateId(),
6336
+ textBlocks: data.textBlocks || []
6337
+ };
6338
+ this.convertDefaultDataToCustom(data);
6339
+ }
6340
+ static get isInline() {
6341
+ return false;
6342
+ }
6343
+ static get isReadOnlySupported() {
6344
+ return true;
6345
+ }
6346
+ static get enableLineBreaks() {
6347
+ return false;
6348
+ }
6349
+ static get toolbox() {
6350
+ return {
6351
+ icon: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M8 9V7.2C8 7.08954 8.08954 7 8.2 7L12 7M16 9V7.2C16 7.08954 15.9105 7 15.8 7L12 7M12 7L12 17M12 17H10M12 17H14"></path></svg>',
6352
+ title: 'Text'
6353
+ };
6354
+ }
6355
+ static get pasteConfig() {
6356
+ return {
6357
+ tags: ['P']
6358
+ };
6359
+ }
6360
+ onPaste(event) {
6361
+ if (event.type !== 'tag') {
6362
+ return;
6363
+ }
6364
+ const text = event.detail.data.textContent;
6365
+ this.data.textBlocks.splice(this.data.textBlocks.length - 1, 1, this.getBlockPartObject(generateId(), text));
6366
+ this.update(this.data.textBlocks);
6367
+ }
6368
+ render() {
6369
+ this.wrapper = document.createElement('div');
6370
+ this.wrapper.classList.add(COMBINED_TEXT_BLOCK);
6371
+ this.wrapper.dataset[this.PLACEHOLDER_ATTRIBUTE_NAME] = this.api.i18n.t(this.placeholder);
6372
+ if (!this.readOnly) {
6373
+ this.wrapper.contentEditable = 'true';
6374
+ }
6375
+ if (!this.data.textBlocks.length) {
6376
+ this.data.textBlocks.push(this.getBlockPartObject(generateId(), ''));
6377
+ }
6378
+ this.update(this.data.textBlocks);
6379
+ this.checkIsEditorEmpty();
6380
+ if (!this.readOnly) {
6381
+ const callback = this.getMutationCallback(this.DEBOUNCE_TIME);
6382
+ this.observer = new MutationObserver(this.onMutationEvent.bind(this, callback));
6383
+ this.observer.observe(this.wrapper, this.mutationConfig);
6384
+ }
6385
+ return this.wrapper;
6386
+ }
6387
+ merge(blocksData) {
6388
+ if (!this.wrapper) {
6389
+ return;
6390
+ }
6391
+ let blocksTextContent = '';
6392
+ this.data.textBlocks = [];
6393
+ blocksData.forEach((block) => {
6394
+ blocksTextContent += block.data.text;
6395
+ });
6396
+ for (let i = 0; i < this.wrapper.childNodes.length; i++) {
6397
+ const node = this.wrapper.childNodes.item(i);
6398
+ if (!(node instanceof HTMLSpanElement)) {
6399
+ return;
6400
+ }
6401
+ i--;
6402
+ blocksTextContent = node.innerHTML + blocksTextContent;
6403
+ node.remove();
6404
+ }
6405
+ const parts = blocksTextContent.length < SPLIT_MAX_LENGTH ? [blocksTextContent] : splitHTML(blocksTextContent);
6406
+ parts.forEach((part) => {
6407
+ const blockObject = this.getBlockPartObject(generateId(), part);
6408
+ this.data.textBlocks.push(blockObject);
6409
+ });
6410
+ this.update(this.data.textBlocks);
6411
+ }
6412
+ save(blockContent) {
6413
+ const textBlocks = [];
6414
+ blockContent.querySelectorAll(this.TAG).forEach((span) => {
6415
+ textBlocks.push(this.getBlockPartObject(span.dataset['id'], span.innerHTML));
6416
+ });
6417
+ return textBlocks;
6418
+ }
6419
+ removed() {
6420
+ this.observer?.disconnect();
6421
+ const blockIds = new Set();
6422
+ this.data.textBlocks.forEach((block) => {
6423
+ blockIds.add(block.id || '');
6424
+ });
6425
+ this.removeBlocks(blockIds);
6426
+ }
6427
+ onMutationEvent(callback, mutationList) {
6428
+ if (mutationList.length === 0) {
6429
+ return;
6430
+ }
6431
+ mutationList.forEach((mutation) => {
6432
+ if (mutation.removedNodes.length) {
6433
+ this.changes.set(generateId(), mutation);
6434
+ return;
6435
+ }
6436
+ this.changes.set(mutation.target, mutation);
6437
+ });
6438
+ callback(mutationList);
6439
+ this.checkIsEditorEmpty();
6440
+ }
6441
+ handleMutations() {
6442
+ const mutationsList = [...this.changes.values()];
6443
+ const { updatedElements, removedElementsIds } = this.getMutationActions(mutationsList);
6444
+ const splitedParts = [];
6445
+ updatedElements.forEach((element) => {
6446
+ const elementContent = element.innerHTML;
6447
+ if (elementContent.length < SPLIT_MAX_LENGTH) {
6448
+ return;
6449
+ }
6450
+ const parts = splitHTML(elementContent);
6451
+ parts.forEach((part, index) => {
6452
+ if (index === 0) {
6453
+ return;
6454
+ }
6455
+ const blockId = generateId();
6456
+ const textElement = this.createBlock(blockId, part);
6457
+ splitedParts.push(textElement);
6458
+ });
6459
+ element.innerHTML = parts[0];
6460
+ element.after(...splitedParts);
6461
+ });
6462
+ this.addBlocks(splitedParts, updatedElements);
6463
+ this.updateBlocks(updatedElements);
6464
+ this.removeBlocks(removedElementsIds);
6465
+ this.changes.clear();
6466
+ }
6467
+ getNextIndex() {
6468
+ recalculateIndexes(this.api.blocks);
6469
+ const index = this.api.blocks.getCurrentBlockIndex();
6470
+ const block = this.api.blocks.getBlockByIndex(index);
6471
+ const dataIndex = Number(block?.holder.dataset['index']);
6472
+ const selection = window.getSelection();
6473
+ const range = selection?.rangeCount ? selection.getRangeAt(0) : null;
6474
+ const caretPosition = range?.startOffset ?? 1;
6475
+ let nextBlockIndex = dataIndex;
6476
+ if (caretPosition !== 0) {
6477
+ const blockContainer = block?.holder.querySelector('.' + COMBINED_TEXT_BLOCK);
6478
+ const childrenCount = blockContainer?.children?.length ? blockContainer?.children?.length - 1 : 0;
6479
+ nextBlockIndex = dataIndex + childrenCount + 1;
6480
+ }
6481
+ if (!nextBlockIndex) {
6482
+ nextBlockIndex ||= 0;
6483
+ }
6484
+ return nextBlockIndex;
6485
+ }
6486
+ getBlockPartObject(blockId, text) {
6487
+ return {
6488
+ id: blockId,
6489
+ type: COMBINED_TEXT_BLOCK_PART,
6490
+ data: {
6491
+ text,
6492
+ parentId: this.data.id,
6493
+ parentType: COMBINED_TEXT_BLOCK_NAME
6494
+ }
6495
+ };
6496
+ }
6497
+ getMutationActions(mutationList) {
6498
+ const updatedElements = new Set();
6499
+ const removedElementsIds = new Set();
6500
+ const changedOutsideElements = [];
6501
+ this.lastBlockElement = undefined;
6502
+ mutationList.forEach((mutation) => {
6503
+ this.handleUpdatedBlocks(mutation, updatedElements, changedOutsideElements);
6504
+ this.handleRemovedBlocks(mutation, removedElementsIds);
6505
+ });
6506
+ if (this.lastBlockElement) {
6507
+ const lastBlockElement = this.lastBlockElement;
6508
+ lastBlockElement.append(...changedOutsideElements);
6509
+ this.setCaretToBlocksEnd(lastBlockElement);
6510
+ }
6511
+ return {
6512
+ updatedElements,
6513
+ removedElementsIds
6514
+ };
6515
+ }
6516
+ setCaretToBlocksEnd(block) {
6517
+ const selection = window.getSelection();
6518
+ const range = document.createRange();
6519
+ range.setStart(block, block.childNodes.length);
6520
+ selection?.removeAllRanges();
6521
+ selection?.addRange(range);
6522
+ }
6523
+ handleUpdatedBlocks(mutation, updatedElements, outsideChanges) {
6524
+ let element = mutation.target;
6525
+ if (mutation.target.nodeType === Node.TEXT_NODE) {
6526
+ element = mutation.target.parentElement;
6527
+ }
6528
+ const span = element?.closest('.' + COMBINED_TEXT_BLOCK_PART);
6529
+ if (span) {
6530
+ updatedElements.add(span);
6531
+ return;
6532
+ }
6533
+ this.handleChangesOutsideBlock(element, outsideChanges);
6534
+ }
6535
+ handleChangesOutsideBlock(element, outsideChanges) {
6536
+ if (!element || this.lastBlockElement) {
6537
+ return;
6538
+ }
6539
+ element.childNodes.forEach((block) => {
6540
+ const blockElement = block;
6541
+ if (blockElement.classList?.contains(COMBINED_TEXT_BLOCK_PART)) {
6542
+ this.lastBlockElement = blockElement;
6543
+ return;
6544
+ }
6545
+ outsideChanges.push(block);
6546
+ });
6547
+ }
6548
+ addBlocks(splicedParts, updatedElements) {
6549
+ if (!splicedParts.length) {
6550
+ return;
6551
+ }
6552
+ const addedBlocks = splicedParts.map((block) => {
6553
+ const blockId = block.dataset['id'];
6554
+ return {
6555
+ id: blockId,
6556
+ type: COMBINED_TEXT_BLOCK_PART,
6557
+ data: {
6558
+ text: block.innerHTML,
6559
+ parentId: this.data.id,
6560
+ parentType: COMBINED_TEXT_BLOCK_NAME
6561
+ }
6562
+ };
6563
+ });
6564
+ const previousElement = updatedElements.values().next().value;
6565
+ const id = previousElement?.dataset['id'];
6566
+ const index = Number(previousElement?.dataset['index']) + 1;
6567
+ const blockIndex = this.data.textBlocks.findIndex((block) => block.id === id);
6568
+ this.data.textBlocks.splice(blockIndex, 0, ...addedBlocks);
6569
+ this.api.events.emit(COMBINED_TEXT_BLOCK_ADDED, {
6570
+ index,
6571
+ blockIndex,
6572
+ blocks: addedBlocks,
6573
+ data: this.data.textBlocks
6574
+ });
6575
+ }
6576
+ updateBlocks(updatedElements) {
6577
+ if (!updatedElements.size) {
6578
+ return;
6579
+ }
6580
+ const updatedBlocks = [...updatedElements.values()].map((block) => {
6581
+ return {
6582
+ id: block.dataset['id'],
6583
+ type: COMBINED_TEXT_BLOCK_PART,
6584
+ data: {
6585
+ text: block.innerHTML,
6586
+ parentId: this.data.id,
6587
+ parentType: COMBINED_TEXT_BLOCK_NAME
6588
+ }
6589
+ };
6590
+ });
6591
+ this.api.events.emit(COMBINED_TEXT_BLOCK_UPDATED, updatedBlocks);
6592
+ }
6593
+ handleRemovedBlocks(mutation, removedElementsIds) {
6594
+ if (mutation.removedNodes.length === 0) {
6595
+ return;
6596
+ }
6597
+ mutation.removedNodes.forEach((node) => {
6598
+ if (!(node instanceof HTMLElement)) {
6599
+ return;
6600
+ }
6601
+ const blockId = node.dataset['id'];
6602
+ if (!blockId) {
6603
+ return;
6604
+ }
6605
+ removedElementsIds.add(blockId);
6606
+ });
6607
+ }
6608
+ removeBlocks(ids) {
6609
+ if (!ids.size) {
6610
+ return;
6611
+ }
6612
+ const removedElementIds = [...ids.values()];
6613
+ this.data.textBlocks = this.data.textBlocks.filter((block) => !ids.has(block.id || ''));
6614
+ this.api.events.emit(COMBINED_TEXT_BLOCK_REMOVED, removedElementIds);
6615
+ }
6616
+ update(blocks) {
6617
+ if (!blocks.length) {
6618
+ return;
6619
+ }
6620
+ blocks.forEach((block) => {
6621
+ const textElement = this.createBlock(block.id || generateId(), block.data.text);
6622
+ if (!this.wrapper) {
6623
+ return;
6624
+ }
6625
+ if (this.wrapper.querySelector('.' + COMBINED_TEXT_BLOCK_PART)) {
6626
+ this.wrapper.append(textElement);
6627
+ return;
6628
+ }
6629
+ this.wrapper.replaceChildren(textElement);
6630
+ });
6631
+ setTimeout(() => {
6632
+ this.api.events.emit(COMBINED_TEXT_BLOCK_ADDED, {
6633
+ blocks
6634
+ });
6635
+ });
6636
+ }
6637
+ createBlock(id, text) {
6638
+ const textElement = document.createElement(this.TAG);
6639
+ textElement.classList.add(COMBINED_TEXT_BLOCK_PART);
6640
+ textElement.innerHTML = text;
6641
+ textElement.dataset['id'] = id;
6642
+ return textElement;
6643
+ }
6644
+ convertDefaultDataToCustom(data) {
6645
+ if (Array.isArray(data)) {
6646
+ this.data.textBlocks = data.map((block) => {
6647
+ block.id = generateId();
6648
+ block.data.parentId = this.data.id;
6649
+ return block;
6650
+ });
6651
+ }
6652
+ if (!data.text) {
6653
+ return;
6654
+ }
6655
+ const fragment = document.createRange().createContextualFragment(data.text);
6656
+ let elementContent = '';
6657
+ fragment.childNodes.forEach((node) => {
6658
+ if (node.nodeType === Node.TEXT_NODE) {
6659
+ elementContent += node.textContent;
6660
+ return;
6661
+ }
6662
+ elementContent += node.innerHTML;
6663
+ });
6664
+ const parts = elementContent.length < SPLIT_MAX_LENGTH ? [elementContent] : splitHTML(elementContent);
6665
+ parts.forEach((part) => {
6666
+ const blockObject = this.getBlockPartObject(generateId(), part);
6667
+ this.data.textBlocks.push(blockObject);
6668
+ });
6669
+ }
6670
+ checkIsEditorEmpty() {
6671
+ if (!this.wrapper || this.wrapper.children.length > this.MAX_CHILD_COUNT_FOR_EMPTY) {
6672
+ return;
6673
+ }
6674
+ const item = this.wrapper.children.item(0);
6675
+ const isItemEmpty = !item.textContent?.length;
6676
+ this.wrapper.dataset['empty'] = `${isItemEmpty}`;
6677
+ }
6678
+ getPlaceholder(config) {
6679
+ if (this.readOnly) {
6680
+ return config.readonlyPlaceholder ?? DEFAULT_READONLY_PLACEHOLDER;
6681
+ }
6682
+ return config.placeholder ?? DEFAULT_PLACEHOLDER;
6683
+ }
6684
+ }
6685
+
6686
+ const getEditorConfig = (id, config = DEFAULT_CONFIG) => ({
6687
+ holder: id,
6688
+ logLevel: 'ERROR',
6689
+ readOnly: config.readOnly,
6690
+ autofocus: config.autofocus,
6691
+ tools: {
6692
+ paragraph: {
6693
+ class: CuiCombinedTextBlockTool,
6694
+ inlineToolbar: true,
6695
+ config: {
6696
+ placeholder: config.placeholder,
6697
+ readonlyPlaceholder: config.readonlyPlaceholder
6698
+ }
6699
+ },
6700
+ link: {
6701
+ class: CuiLinkMarker
6702
+ },
6703
+ bold: {
6704
+ class: CuiBoldInlineTool
6705
+ },
6706
+ italic: {
6707
+ class: CuiItalicInlineTool
6708
+ },
6709
+ ...config.tools
6710
+ },
6711
+ defaultBlock: COMBINED_TEXT_BLOCK_NAME
6712
+ });
6713
+
6714
+ const EDITOR_CUSTOM_ELEMENTS = [
6715
+ {
6716
+ selector: EDITOR_TOOLTIP_SELECTOR,
6717
+ component: EditorTooltipComponent
6718
+ },
6719
+ {
6720
+ selector: MARKER_SELECT_SELECTOR,
6721
+ component: MarkerSelectComponent
6722
+ },
6723
+ {
6724
+ selector: EDITOR_TOOL_MODAL_SELECTOR,
6725
+ component: EditorToolModalComponent
6726
+ },
6727
+ {
6728
+ selector: MARKER_MODAL_SELECTOR,
6729
+ component: MarkerModalComponent
6730
+ },
6731
+ {
6732
+ selector: EDITOR_VIDEO_TOOL_SELECTOR,
6733
+ component: EditorVideoToolComponent
6734
+ },
6735
+ {
6736
+ selector: EDITOR_IMAGE_TOOL_SELECTOR,
6737
+ component: EditorImageToolComponent
6738
+ },
6739
+ {
6740
+ selector: EDITOR_ATTACHES_TOOL_SELECTOR,
6741
+ component: EditorAttachesToolComponent
6742
+ }
6743
+ ];
6744
+
6745
+ function cuiProvideEditor() {
6746
+ return [
6747
+ {
6748
+ provide: APP_INITIALIZER,
6749
+ useFactory: (injector) => () => {
6750
+ EDITOR_CUSTOM_ELEMENTS.forEach(({ component, selector }) => {
6751
+ const element = createCustomElement(component, { injector });
6752
+ window.customElements.define(selector, element);
6753
+ });
6754
+ },
6755
+ deps: [Injector],
6756
+ multi: true,
6757
+ },
6758
+ ];
6759
+ }
6760
+
6761
+ function setEditorDragEvents(editorElement, signal) {
6762
+ editorElement.addEventListener('dragstart', dragstartListener, { signal });
6763
+ }
6764
+ function dragstartListener(event) {
6765
+ event.preventDefault();
6766
+ }
6767
+
6768
+ const FIRST_CHILD_SELECTOR = '_selected';
6769
+ function setEditorKeyboardEvents(editorElement, signal) {
6770
+ editorElement.addEventListener('keydown', keydownListener, { signal });
6771
+ }
6772
+ function keydownListener(event) {
6773
+ const target = event.target;
6774
+ const block = target.closest(`.${COMBINED_TEXT_BLOCK}`);
6775
+ if (!block) {
6776
+ return;
6777
+ }
6778
+ const selection = window.getSelection();
6779
+ const ranges = selection?.rangeCount;
6780
+ if (!ranges || !checkIsBlockFullySelected(block)) {
6781
+ return;
6782
+ }
6783
+ const firstChild = block?.firstElementChild;
6784
+ firstChild?.classList.add(FIRST_CHILD_SELECTOR);
6785
+ setTimeout(() => firstChild?.classList.remove(FIRST_CHILD_SELECTOR));
6786
+ }
6787
+ function checkIsBlockFullySelected(blockElement) {
6788
+ const selection = window.getSelection();
6789
+ if (!selection || selection.rangeCount === 0) {
6790
+ return false;
6791
+ }
6792
+ const range = selection.getRangeAt(0);
6793
+ const startBlock = range.startContainer.parentElement?.closest('.' + COMBINED_TEXT_BLOCK_PART);
6794
+ const endBlock = range.endContainer.parentElement?.closest('.' + COMBINED_TEXT_BLOCK_PART);
6795
+ const isStartAtBlockStart = startBlock === blockElement.firstChild && range.startOffset === 0;
6796
+ const isEndAtBlockEnd = endBlock === blockElement.lastChild;
6797
+ return isStartAtBlockStart && isEndAtBlockEnd;
6798
+ }
6799
+
6800
+ function setEditorInfoModalEvents(editorElement, signal) {
6801
+ editorElement?.addEventListener('pointerup', pointerUpListener, { signal });
6802
+ }
6803
+ function pointerUpListener(event) {
6804
+ const selection = window.getSelection();
6805
+ if (selection && selection.toString().length > 0) {
6806
+ return;
6807
+ }
6808
+ const target = event.target;
6809
+ const marker = target.closest('.marker');
6810
+ if (!marker) {
6811
+ return;
6812
+ }
6813
+ onMarkerClick(marker);
6814
+ }
6815
+ function onMarkerClick(marker) {
6816
+ const id = marker.dataset['id'];
6817
+ const type = marker.dataset['type'];
6818
+ if (!(id && type)) {
6819
+ return;
6820
+ }
6821
+ const toolModal = document.createElement(EDITOR_TOOL_MODAL_SELECTOR);
6822
+ toolModal.tool = { id, type, title: 'Молоток КУБИПРО Ультра MAX 3000' };
6823
+ toolModal.marker = marker;
6824
+ toolModal.addEventListener('closed', function onCloseModal() {
6825
+ toolModal.remove();
6826
+ });
6827
+ document.body.append(toolModal);
6828
+ }
6829
+
6830
+ const TOOLTIP_POSITION_X = 5;
6831
+ const TOOLTIP_POSITION_Y = 40;
6832
+ const TOOLTIP_SAFE_RIGHT_SHIFT = 10;
6833
+ const TOOLTIP_DEBOUNCE_TIME = 500;
6834
+ const CLOSE_TOOLTIP_DEBOUNCE_TIME = 50;
6835
+ let tooltip;
6836
+ let timeoutId;
6837
+ let closeTimeoutId;
6838
+ const closeTooltipHandler = () => closeTooltip();
6839
+ function closeTooltip(callback) {
6840
+ clearTimeout(closeTimeoutId);
6841
+ closeTimeoutId = setTimeout(() => {
6842
+ clearTimeout(timeoutId);
6843
+ tooltip?.remove();
6844
+ callback?.();
6845
+ }, CLOSE_TOOLTIP_DEBOUNCE_TIME);
6846
+ }
6847
+ const debouncedEvent = (event, marker, target) => {
6848
+ clearTimeout(timeoutId);
6849
+ timeoutId = setTimeout(() => {
6850
+ if (tooltip && tooltip?.contains(target)) {
6851
+ return;
6852
+ }
6853
+ closeTooltip(() => openTooltip(event, marker));
6854
+ }, TOOLTIP_DEBOUNCE_TIME);
6855
+ };
6856
+ function openTooltip(event, marker) {
6857
+ const type = marker.tagName;
6858
+ tooltip = tooltipMap[type](marker);
6859
+ tooltip.style.visibility = 'hidden';
6860
+ document.body.append(tooltip);
6861
+ setTimeout(() => {
6862
+ const positionX = event.clientX;
6863
+ const positionY = event.clientY;
6864
+ const rightX = document.documentElement.clientWidth - positionX;
6865
+ const rightShiftDiffX = tooltip.offsetWidth - rightX;
6866
+ const rightShiftX = rightShiftDiffX > 0 ? rightShiftDiffX + TOOLTIP_SAFE_RIGHT_SHIFT : 0;
6867
+ tooltip.style.top = positionY - TOOLTIP_POSITION_Y + 'px';
6868
+ tooltip.style.left = positionX + TOOLTIP_POSITION_X - rightShiftX + 'px';
6869
+ tooltip.style.visibility = 'visible';
6870
+ });
6871
+ }
6872
+ function setEditorTooltipEvents(signal) {
6873
+ document.body.addEventListener('mousemove', mouseMoveListener, { signal });
6874
+ document.body.addEventListener('mouseleave', closeTooltipHandler, { signal });
6875
+ }
6876
+ function mouseMoveListener(event) {
6877
+ const target = event.target;
6878
+ const marker = target.closest('.marker');
6879
+ if (tooltip?.contains(target)) {
6880
+ clearTimeout(timeoutId);
6881
+ clearTimeout(closeTimeoutId);
6882
+ return;
6883
+ }
6884
+ if (!marker) {
6885
+ closeTooltip();
6886
+ return;
6887
+ }
6888
+ clearTimeout(closeTimeoutId);
6889
+ debouncedEvent(event, marker, target);
6890
+ }
6891
+
6892
+ function setEditorEvents(editorElement, signal) {
6893
+ setEditorTooltipEvents(signal);
6894
+ setEditorInfoModalEvents(editorElement, signal);
6895
+ setEditorDragEvents(editorElement, signal);
6896
+ setEditorKeyboardEvents(editorElement, signal);
6897
+ }
6898
+
6899
+ class CuiEditorComponent {
6900
+ constructor() {
6901
+ this.destroy = inject(DestroyRef);
6902
+ this.editorService = inject(CuiEditorService);
6903
+ this.jTextService = inject(CuiJTextApiService);
6904
+ this.POOLING_DELAY = 100;
6905
+ this.ELEMENT_SPACE_TO_BOTTOM = 150;
6906
+ this.SCROLL_THROTTLE_TIME = 200;
6907
+ this.isReadonly = computed(() => this.config?.readOnly);
6908
+ this.emptyQueue = new Subject();
6909
+ this.editorEmpty = new EventEmitter();
6910
+ this.config = DEFAULT_CONFIG;
6911
+ this.requestSize = 40;
6912
+ this.isSkipCombinedBlockOnChange = [];
6913
+ this.isFirst = true;
6914
+ this.isChanging = false;
6915
+ this.isSkip = false;
6916
+ this.isRequested = false;
6917
+ this.isDestroyed = false;
6918
+ this.blockIdsMap = new Map();
6919
+ this.combinedBlocks = new Map();
6920
+ this.index = 0;
6921
+ this.page = 0;
6922
+ this.addedBlocks = [];
6923
+ this.updatedBlocks = [];
6924
+ this.removedBlocksIds = [];
6925
+ this.changesQueue = [];
6926
+ this.abortController = new AbortController();
6927
+ }
6928
+ ngOnChanges(changes) {
6929
+ if (changes['editorID'] || changes['config']) {
6930
+ this.initEditorChanges();
6931
+ }
6932
+ }
6933
+ ngOnDestroy() {
6934
+ this.isDestroyed = true;
6935
+ this.destroyEditor();
6936
+ }
6937
+ onScrollEvent(element) {
6938
+ const overallHeight = element.scrollHeight - this.ELEMENT_SPACE_TO_BOTTOM;
6939
+ const currentHeight = element.scrollTop + element.clientHeight;
6940
+ if (currentHeight < overallHeight || this.isRequested) {
6941
+ return;
6942
+ }
6943
+ this.isRequested = true;
6944
+ const size = this.requestSize;
6945
+ let blocksCount = 0;
6946
+ this.getBlocks(this.page, size)
6947
+ .pipe(tap((blocks) => (blocksCount = blocks.length)), finalize(() => {
6948
+ this.isRequested = false;
6949
+ if (blocksCount >= size) {
6950
+ return;
6951
+ }
6952
+ this.scrollSubscription.unsubscribe();
6953
+ }))
6954
+ .subscribe();
6955
+ this.page++;
6956
+ }
6957
+ async onEditorChange(_, event) {
6958
+ if (this.isReadonly()) {
6959
+ return;
6960
+ }
6961
+ if (!Array.isArray(event)) {
6962
+ event = [event];
6963
+ }
6964
+ recalculateIndexes(this.editor.blocks);
6965
+ if (this.isChanging) {
6966
+ this.changesQueue.unshift(event);
6967
+ }
6968
+ this.startChanges(event);
6969
+ this.editorEmpty.emit(this.checkIsEmpty());
6970
+ }
6971
+ onAddedCombinedBlock(data) {
6972
+ if (this.isSkipCombinedBlockOnChange.length) {
6973
+ this.isSkipCombinedBlockOnChange.pop();
6974
+ return;
6975
+ }
6976
+ const blocksWithoutId = data.blocks.map((block) => ({
6977
+ block: { ...block, id: undefined },
6978
+ id: block.id
6979
+ }));
6980
+ this.addedBlocks.push(...blocksWithoutId);
6981
+ }
6982
+ onUpdatedCombinedBlock(updatedBlocks) {
6983
+ if (!updatedBlocks.length) {
6984
+ return;
6985
+ }
6986
+ this.updatedBlocks.push(...updatedBlocks);
6987
+ }
6988
+ onRemovedCombinedBlock(blockIds) {
6989
+ if (!blockIds.length) {
6990
+ return;
6991
+ }
6992
+ this.removedBlocksIds.push(...blockIds);
6993
+ }
6994
+ initEditorChanges() {
6995
+ this.jTextService.addOptions(this.config.requestOptions);
6996
+ this.editor = this.initEditor(this.editorID);
6997
+ this.editor.isReady.then(() => {
6998
+ this.editorElement = this.editorRef.nativeElement;
6999
+ this.initEditorEvents(this.editorElement);
7000
+ this.initScrollObserver();
7001
+ this.startPooling(this.requestSize);
7002
+ this.setListenersOnCustomBlockChanges();
7003
+ });
7004
+ }
7005
+ initEditor(id) {
7006
+ const config = this.config;
7007
+ this.destroyEditor();
7008
+ this.editor = new EditorJS({
7009
+ ...getEditorConfig(id, config),
7010
+ onChange: this.onEditorChange.bind(this)
7011
+ });
7012
+ return this.editor;
7013
+ }
7014
+ initScrollObserver() {
7015
+ const element = this.config?.element ?? this.editorElement;
7016
+ const scrollObserver = fromEvent(element, 'scroll');
7017
+ this.scrollSubscription = scrollObserver
7018
+ .pipe(takeUntilDestroyed(this.destroy), throttleTime(this.SCROLL_THROTTLE_TIME, undefined, {
7019
+ leading: true,
7020
+ trailing: true
7021
+ }), map(() => this.onScrollEvent(element)))
7022
+ .subscribe();
7023
+ }
7024
+ initEditorEvents(element) {
7025
+ const readOnly = this.isReadonly();
7026
+ if (readOnly) {
7027
+ return;
7028
+ }
7029
+ setEditorEvents(element, this.abortController.signal);
7030
+ }
7031
+ startPooling(size) {
7032
+ const scrollElement = this.config?.element ?? this.editorElement;
7033
+ const withoutPreload = this.config?.withoutPreload;
7034
+ this.poolingSubscription = timer(0, this.POOLING_DELAY)
7035
+ .pipe(concatMap(() => this.getBlocks(this.page, size).pipe(delay(this.POOLING_DELAY))), tap(() => this.page++), takeWhile((blocks) => !withoutPreload &&
7036
+ scrollElement.scrollHeight <= scrollElement.clientHeight &&
7037
+ blocks.length >= size), finalize(() => {
7038
+ if (this.isDestroyed) {
7039
+ return;
7040
+ }
7041
+ this.setStartBlock();
7042
+ }))
7043
+ .subscribe();
7044
+ }
7045
+ destroyEditor() {
7046
+ this.abortController.abort();
7047
+ this.resetData();
7048
+ // TODO: в рандом кейсах падает ошибка если убрать проверку на вызов destroy
7049
+ this.editor?.destroy?.();
7050
+ }
7051
+ setListenersOnCustomBlockChanges() {
7052
+ this.editorService.setListenersOnCustomBlockChanges(this.editor, {
7053
+ removedCallback: this.onRemovedCombinedBlock.bind(this),
7054
+ updatedCallback: this.onUpdatedCombinedBlock.bind(this),
7055
+ addedCallback: this.onAddedCombinedBlock.bind(this)
7056
+ });
7057
+ }
7058
+ async startChanges(event) {
7059
+ if (this.isSkip || this.isChanging || !this.editor) {
7060
+ this.isSkip = false;
7061
+ return;
7062
+ }
7063
+ this.isChanging = true;
7064
+ const editorOutput = await this.editor.save();
7065
+ const events = event.filter((data) => data.detail.target.name !== COMBINED_TEXT_BLOCK_NAME);
7066
+ const blocks = this.editorService.sortEventsByTypes(events);
7067
+ const { addBlocks$, addedBlocks } = this.collectAddedBlocksRequest(blocks, editorOutput);
7068
+ this.addedBlocks = [];
7069
+ addBlocks$
7070
+ .pipe(tap((blockIds) => this.setBlockIdsToMap(blockIds, addedBlocks)), concatMap(() => this.collectUpdatedBlocksRequest(blocks, editorOutput)), concatMap(() => this.collectRemovedBlocksRequest(blocks)))
7071
+ .subscribe({
7072
+ complete: () => this.startNextChange(),
7073
+ error: () => this.startNextChange()
7074
+ });
7075
+ }
7076
+ startNextChange() {
7077
+ this.isChanging = false;
7078
+ const nextEvents = this.changesQueue.pop();
7079
+ if (nextEvents) {
7080
+ this.startChanges(nextEvents);
7081
+ }
7082
+ this.emptyQueue.next(null);
7083
+ }
7084
+ collectAddedBlocksRequest(blocks, editorOutput) {
7085
+ const defaultBlocksWithIndex = blocks["block-added" /* EventActions.add */].map((addedBlock) => this.editorService.getFullBlockData(addedBlock, editorOutput));
7086
+ const combinedBlocksWithIndex = this.addedBlocks.map((block) => {
7087
+ const element = this.editorElement.querySelector(`[data-id="${block.id}"]`);
7088
+ const index = Number(element?.dataset['index']);
7089
+ return { ...block, index };
7090
+ });
7091
+ const addedBlocks = [...defaultBlocksWithIndex, ...combinedBlocksWithIndex].sort((first, second) => first.index - second.index);
7092
+ const addBlocks$ = this.editorService.collectAddedBlocksRequest(this.editorID, addedBlocks);
7093
+ return {
7094
+ addedBlocks,
7095
+ addBlocks$
7096
+ };
7097
+ }
7098
+ collectUpdatedBlocksRequest(blocks, editorOutput) {
7099
+ blocks["block-changed" /* EventActions.update */].forEach((updateBlock) => {
7100
+ const { id, block } = this.editorService.getFullBlockData(updateBlock, editorOutput);
7101
+ block.id = id;
7102
+ this.updatedBlocks.push(block);
7103
+ });
7104
+ const updateBlocks$ = this.editorService.collectUpdatedBlocksRequest(this.updatedBlocks, this.blockIdsMap);
7105
+ this.updatedBlocks = [];
7106
+ return updateBlocks$;
7107
+ }
7108
+ collectRemovedBlocksRequest(blocks) {
7109
+ blocks["block-removed" /* EventActions.remove */].forEach((block) => {
7110
+ const id = block.detail.target.id;
7111
+ this.removedBlocksIds.push(id);
7112
+ });
7113
+ const removeBlocks$ = this.editorService.collectRemovedBlocksRequest(this.editorID, this.removedBlocksIds, this.blockIdsMap);
7114
+ this.removedBlocksIds = [];
7115
+ return removeBlocks$;
7116
+ }
7117
+ getBlocks(page = 0, size = 40) {
7118
+ let combinedBlock;
7119
+ return this.jTextService.getBlocks(this.editorID, page, size).pipe(takeUntilDestroyed(this.destroy), finalize(() => {
7120
+ if (combinedBlock) {
7121
+ this.addCombinedBlock(combinedBlock);
7122
+ combinedBlock = null;
7123
+ }
7124
+ recalculateIndexes(this.editor.blocks);
7125
+ }), map((block) => {
7126
+ if (block.type === COMBINED_TEXT_BLOCK_PART) {
7127
+ const blockData = block.data;
7128
+ if (combinedBlock && blockData.parentId !== combinedBlock?.id) {
7129
+ this.addCombinedBlock(combinedBlock);
7130
+ combinedBlock = null;
7131
+ }
7132
+ combinedBlock = this.setCombinedBlock(block);
7133
+ return;
7134
+ }
7135
+ if (combinedBlock) {
7136
+ this.addCombinedBlock(combinedBlock);
7137
+ combinedBlock = null;
7138
+ }
7139
+ this.addBlock(block);
7140
+ }), toArray());
7141
+ }
7142
+ addBlock(block) {
7143
+ if (typeof block.type !== 'string') {
7144
+ return;
7145
+ }
7146
+ this.blockIdsMap.set(block.id, block.id);
7147
+ this.insert(block);
7148
+ }
7149
+ addCombinedBlock(combinedBlock) {
7150
+ this.isSkipCombinedBlockOnChange.push(true);
7151
+ const block = this.editor.blocks.getById(combinedBlock.id || '');
7152
+ if (block) {
7153
+ this.editor.blocks.update(block.id, combinedBlock.data);
7154
+ return;
7155
+ }
7156
+ this.insert(combinedBlock);
7157
+ }
7158
+ insert(block) {
7159
+ this.checkFirst(block);
7160
+ this.index++;
7161
+ }
7162
+ checkFirst(block) {
7163
+ if (!this.isFirst) {
7164
+ this.isSkip = true;
7165
+ this.editor.blocks.insert(block.type, block.data, {}, this.index, false, false, block.id);
7166
+ return;
7167
+ }
7168
+ // TODO: есть варик что что то пойдет не так
7169
+ this.editor.blocks.render({ blocks: [block] }).then(() => this.isSkip = false);
7170
+ this.isFirst = false;
7171
+ }
7172
+ setCombinedBlock(block) {
7173
+ const combinedBlockData = block.data;
7174
+ const parent = this.combinedBlocks.get(combinedBlockData.parentId);
7175
+ this.blockIdsMap.set(block.id, block.id);
7176
+ if (parent) {
7177
+ const parentData = parent.data;
7178
+ parentData.textBlocks.push(block);
7179
+ return parent;
7180
+ }
7181
+ const parentObject = {
7182
+ id: combinedBlockData.parentId,
7183
+ type: COMBINED_TEXT_BLOCK_NAME,
7184
+ data: {
7185
+ id: combinedBlockData.parentId,
7186
+ textBlocks: [block]
7187
+ }
7188
+ };
7189
+ this.combinedBlocks.set(combinedBlockData.parentId, parentObject);
7190
+ return parentObject;
7191
+ }
7192
+ setBlockIdsToMap(blockIds, addedBlocks) {
7193
+ if (!blockIds.length) {
7194
+ return;
7195
+ }
7196
+ addedBlocks.forEach((blockData, index) => {
7197
+ this.blockIdsMap.set(blockData.id, blockIds[index]);
7198
+ });
7199
+ }
7200
+ setStartBlock() {
7201
+ if (this.blockIdsMap.size) {
7202
+ this.setFocus();
7203
+ this.editorEmpty.emit(this.checkIsEmpty());
7204
+ return;
7205
+ }
7206
+ if (this.isReadonly()) {
7207
+ this.editor.render({ blocks: [] });
7208
+ return;
7209
+ }
7210
+ this.editorService.setStartBlock(this.editorID, async (block, id) => {
7211
+ this.blockIdsMap.set(id, id);
7212
+ this.isSkipCombinedBlockOnChange.push(true);
7213
+ await this.editor.render({ blocks: [block] });
7214
+ this.setFocus();
7215
+ recalculateIndexes(this.editor.blocks);
7216
+ });
7217
+ }
7218
+ setFocus() {
7219
+ if (!this.config?.autofocus) {
7220
+ return;
7221
+ }
7222
+ this.editor.caret.focus();
7223
+ }
7224
+ checkIsEmpty() {
7225
+ const MIN_BLOCKS_COUNT = 1;
7226
+ const REDACTOR_SELECTOR = '.codex-editor__redactor';
7227
+ const redactor = this.editorElement.querySelector(REDACTOR_SELECTOR);
7228
+ const blocksCount = redactor?.childElementCount ?? 0;
7229
+ return blocksCount <= MIN_BLOCKS_COUNT && !redactor?.textContent;
7230
+ }
7231
+ resetData() {
7232
+ this.scrollSubscription?.unsubscribe();
7233
+ this.poolingSubscription?.unsubscribe();
7234
+ this.isSkipCombinedBlockOnChange = [];
7235
+ this.isFirst = true;
7236
+ this.isChanging = false;
7237
+ this.isSkip = false;
7238
+ this.isRequested = false;
7239
+ this.blockIdsMap = new Map();
7240
+ this.combinedBlocks = new Map();
7241
+ this.index = 0;
7242
+ this.page = 0;
7243
+ this.addedBlocks = [];
7244
+ this.updatedBlocks = [];
7245
+ this.removedBlocksIds = [];
7246
+ this.changesQueue = [];
7247
+ this.abortController = new AbortController();
7248
+ }
7249
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7250
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: CuiEditorComponent, isStandalone: true, selector: "cui-editor", inputs: { editorID: "editorID", config: "config", requestSize: "requestSize" }, outputs: { editorEmpty: "editorEmpty" }, providers: [CuiEditorService, CuiJTextApiService], viewQueries: [{ propertyName: "editorRef", first: true, predicate: ["editor"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\r\n #editor\r\n [id]=\"editorID\"\r\n [class._readonly]=\"config.readOnly\"\r\n data-editor\r\n></div>\r\n", styles: [":host{--textColor: var(--cui-base-900);--menuBackground: var(--cui-base-0);--menuBorder: var(--cui-base-200);--menuItemHover: var(--cui-base-10);--menuItemBackground: var(cui-base-900);--menuIconBackground: var(--cui-base-50);--menuIconHover: var(--cui-base-10);font-weight:400;font-size:14px;line-height:20px;font-family:var(--cui-main-font)}:host ::ng-deep .ce-popover{--color-background: var(--menuBackground);--color-text-primary: var(--textColor);--color-border: var(--menuBorder);--color-border-icon: var(--menuBorder);--color-background-item: var(--menuItemBackground);--color-background-item-hover: var(--menuItemHover)}:host ::ng-deep .ce-popover__search{background:var(--menuIconBackground)}:host ::ng-deep .ce-popover .ce-popover-item__icon{background:var(--menuIconBackground)}:host ::ng-deep .ce-conversion-toolbar{background-color:var(--menuBackground);border-color:var(--menuBorder)}:host ::ng-deep .ce-conversion-toolbar__tools{padding:0 6px 6px}:host ::ng-deep .ce-conversion-tool{padding:3px;border-radius:6px}:host ::ng-deep .ce-conversion-tool__icon{border:1px solid var(--menuBorder);background-color:var(--menuIconBackground);box-shadow:none}:host ::ng-deep .ce-conversion-tool:hover{background-color:var(--menuItemHover)}:host ::ng-deep .ce-conversion-tool:hover .ce-conversion-tool__icon{border-color:var(--menuIconHover)}:host ::ng-deep .combined-text-block{padding:.4em 0;line-height:1.6em;outline:none}:host ::ng-deep .combined-text-block .combined-text-block-part{outline:none}:host ::ng-deep .combined-text-block .combined-text-block-part:only-child,:host ::ng-deep .combined-text-block .combined-text-block-part._selected{display:list-item}:host ::ng-deep .combined-text-block .combined-text-block-part:only-child::marker,:host ::ng-deep .combined-text-block .combined-text-block-part._selected::marker{content:\"\"}:host ::ng-deep .image-tool__image{border:1px solid var(--cui-base-200);background-color:var(--cui-base-0)}:host ::ng-deep .image-tool__image-preloader{background-color:var(--cui-base-200)}:host ::ng-deep .image-tool__image-preloader:after{border:1px solid var(--cui-base-200);border-top:1px solid var(--cui-blue-600)}:host ::ng-deep .cdx-button{border:1px solid var(--cui-base-200);color:var(--textColor);background-color:var(--cui-base-0);box-shadow:none}:host ::ng-deep .ce-inline-toolbar{border-color:var(--cui-base-100);color:var(--textColor);background-color:var(--cui-base-0)}:host ::ng-deep .ce-inline-toolbar__dropdown:hover{background-color:var(--cui-base-100)}:host ::ng-deep .ce-inline-tool:hover{background-color:var(--cui-base-100)}:host ::ng-deep .ce-toolbar__plus,:host ::ng-deep .ce-toolbar__settings-btn{color:var(--cui-base-500)}:host ::ng-deep .ce-toolbar__plus:hover,:host ::ng-deep .ce-toolbar__settings-btn:hover{background-color:var(--cui-base-100)}:host ::ng-deep .ce-toolbar__actions{right:100%}:host ::ng-deep .ce-toolbar__content{max-width:none}:host ::ng-deep .ce-block--selected .ce-block__content{background-color:var(--cui-base-200)}:host ::ng-deep .ce-block__content{max-width:100%}:host ::ng-deep .ce-block:only-of-type .combined-text-block[data-placeholder-active][data-empty=true]:before{content:attr(data-placeholder-active);position:absolute;color:var(--cui-base-400)}:host ::ng-deep [data-editor]{padding-right:4px;width:100%;height:100%;min-height:200px;overflow:hidden auto;scrollbar-gutter:stable}:host ::ng-deep [data-editor] .codex-editor{margin-left:60px}:host ::ng-deep [data-editor] .codex-editor--narrow .ce-popover{right:auto}:host ::ng-deep [data-editor] .codex-editor__redactor{margin-right:auto;padding-bottom:260px!important}:host ::ng-deep [data-editor]._readonly{min-height:auto}:host ::ng-deep [data-editor]._readonly .codex-editor{margin:auto}:host ::ng-deep [data-editor]._readonly .codex-editor__redactor{padding-bottom:0!important}:host ::ng-deep [data-editor]._readonly .combined-text-block{padding:0}:host ::ng-deep [data-editor] [data-item-name=move-up],:host ::ng-deep [data-editor] [data-item-name=move-down],:host ::ng-deep [data-editor] [data-tool=paragraph]{display:none}:host ::ng-deep [data-editor] *::selection{background:var(--cui-base-200)}:host ::ng-deep [data-editor] a{color:var(--cui-light-blue-600)}:host ::ng-deep .marker{cursor:pointer;text-decoration:underline;color:var(--cui-light-blue-600);background-color:transparent}:host ::ng-deep .tool-marker,:host ::ng-deep .role-marker{margin:0 5px}:host ::ng-deep .tool-marker{color:#e97c00}:host ::ng-deep .role-marker{color:#8803f1}.form{height:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7251
+ }
7252
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiEditorComponent, decorators: [{
7253
+ type: Component,
7254
+ args: [{ selector: 'cui-editor', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, providers: [CuiEditorService, CuiJTextApiService], template: "<div\r\n #editor\r\n [id]=\"editorID\"\r\n [class._readonly]=\"config.readOnly\"\r\n data-editor\r\n></div>\r\n", styles: [":host{--textColor: var(--cui-base-900);--menuBackground: var(--cui-base-0);--menuBorder: var(--cui-base-200);--menuItemHover: var(--cui-base-10);--menuItemBackground: var(cui-base-900);--menuIconBackground: var(--cui-base-50);--menuIconHover: var(--cui-base-10);font-weight:400;font-size:14px;line-height:20px;font-family:var(--cui-main-font)}:host ::ng-deep .ce-popover{--color-background: var(--menuBackground);--color-text-primary: var(--textColor);--color-border: var(--menuBorder);--color-border-icon: var(--menuBorder);--color-background-item: var(--menuItemBackground);--color-background-item-hover: var(--menuItemHover)}:host ::ng-deep .ce-popover__search{background:var(--menuIconBackground)}:host ::ng-deep .ce-popover .ce-popover-item__icon{background:var(--menuIconBackground)}:host ::ng-deep .ce-conversion-toolbar{background-color:var(--menuBackground);border-color:var(--menuBorder)}:host ::ng-deep .ce-conversion-toolbar__tools{padding:0 6px 6px}:host ::ng-deep .ce-conversion-tool{padding:3px;border-radius:6px}:host ::ng-deep .ce-conversion-tool__icon{border:1px solid var(--menuBorder);background-color:var(--menuIconBackground);box-shadow:none}:host ::ng-deep .ce-conversion-tool:hover{background-color:var(--menuItemHover)}:host ::ng-deep .ce-conversion-tool:hover .ce-conversion-tool__icon{border-color:var(--menuIconHover)}:host ::ng-deep .combined-text-block{padding:.4em 0;line-height:1.6em;outline:none}:host ::ng-deep .combined-text-block .combined-text-block-part{outline:none}:host ::ng-deep .combined-text-block .combined-text-block-part:only-child,:host ::ng-deep .combined-text-block .combined-text-block-part._selected{display:list-item}:host ::ng-deep .combined-text-block .combined-text-block-part:only-child::marker,:host ::ng-deep .combined-text-block .combined-text-block-part._selected::marker{content:\"\"}:host ::ng-deep .image-tool__image{border:1px solid var(--cui-base-200);background-color:var(--cui-base-0)}:host ::ng-deep .image-tool__image-preloader{background-color:var(--cui-base-200)}:host ::ng-deep .image-tool__image-preloader:after{border:1px solid var(--cui-base-200);border-top:1px solid var(--cui-blue-600)}:host ::ng-deep .cdx-button{border:1px solid var(--cui-base-200);color:var(--textColor);background-color:var(--cui-base-0);box-shadow:none}:host ::ng-deep .ce-inline-toolbar{border-color:var(--cui-base-100);color:var(--textColor);background-color:var(--cui-base-0)}:host ::ng-deep .ce-inline-toolbar__dropdown:hover{background-color:var(--cui-base-100)}:host ::ng-deep .ce-inline-tool:hover{background-color:var(--cui-base-100)}:host ::ng-deep .ce-toolbar__plus,:host ::ng-deep .ce-toolbar__settings-btn{color:var(--cui-base-500)}:host ::ng-deep .ce-toolbar__plus:hover,:host ::ng-deep .ce-toolbar__settings-btn:hover{background-color:var(--cui-base-100)}:host ::ng-deep .ce-toolbar__actions{right:100%}:host ::ng-deep .ce-toolbar__content{max-width:none}:host ::ng-deep .ce-block--selected .ce-block__content{background-color:var(--cui-base-200)}:host ::ng-deep .ce-block__content{max-width:100%}:host ::ng-deep .ce-block:only-of-type .combined-text-block[data-placeholder-active][data-empty=true]:before{content:attr(data-placeholder-active);position:absolute;color:var(--cui-base-400)}:host ::ng-deep [data-editor]{padding-right:4px;width:100%;height:100%;min-height:200px;overflow:hidden auto;scrollbar-gutter:stable}:host ::ng-deep [data-editor] .codex-editor{margin-left:60px}:host ::ng-deep [data-editor] .codex-editor--narrow .ce-popover{right:auto}:host ::ng-deep [data-editor] .codex-editor__redactor{margin-right:auto;padding-bottom:260px!important}:host ::ng-deep [data-editor]._readonly{min-height:auto}:host ::ng-deep [data-editor]._readonly .codex-editor{margin:auto}:host ::ng-deep [data-editor]._readonly .codex-editor__redactor{padding-bottom:0!important}:host ::ng-deep [data-editor]._readonly .combined-text-block{padding:0}:host ::ng-deep [data-editor] [data-item-name=move-up],:host ::ng-deep [data-editor] [data-item-name=move-down],:host ::ng-deep [data-editor] [data-tool=paragraph]{display:none}:host ::ng-deep [data-editor] *::selection{background:var(--cui-base-200)}:host ::ng-deep [data-editor] a{color:var(--cui-light-blue-600)}:host ::ng-deep .marker{cursor:pointer;text-decoration:underline;color:var(--cui-light-blue-600);background-color:transparent}:host ::ng-deep .tool-marker,:host ::ng-deep .role-marker{margin:0 5px}:host ::ng-deep .tool-marker{color:#e97c00}:host ::ng-deep .role-marker{color:#8803f1}.form{height:100%}\n"] }]
7255
+ }], propDecorators: { editorRef: [{
7256
+ type: ViewChild,
7257
+ args: ['editor']
7258
+ }], editorEmpty: [{
7259
+ type: Output
7260
+ }], editorID: [{
7261
+ type: Input,
7262
+ args: [{ required: true }]
7263
+ }], config: [{
7264
+ type: Input
7265
+ }], requestSize: [{
7266
+ type: Input
7267
+ }] } });
7268
+
7269
+ class CuiEditorReadonlyComponent {
7270
+ constructor() {
7271
+ this.isShowMore = signal(false);
7272
+ this.isMoreButtonShown = signal(false);
7273
+ this.editorConfig = computed(() => ({ readOnly: true, withoutPreload: true, ...this.config() }));
7274
+ this.editor = viewChild.required('editor');
7275
+ this.editorId = input.required();
7276
+ this.config = input.required();
7277
+ this.buttonTemplate = input.required();
7278
+ this.shortHeight = input(68);
7279
+ this.initEditorIdEffect();
7280
+ this.initReadEditorProperty();
7281
+ }
7282
+ onShow(editor) {
7283
+ editor.editorElement.scrollTo(0, 0);
7284
+ this.isShowMore.update((prev) => !prev);
7285
+ }
7286
+ initReadEditorProperty() {
7287
+ afterRender({
7288
+ read: () => this.isMoreButtonShown.set(this.editor().editorElement?.scrollHeight > this.shortHeight())
7289
+ });
7290
+ }
7291
+ initEditorIdEffect() {
7292
+ effect(() => {
7293
+ this.editorId();
7294
+ this.isShowMore.set(false);
7295
+ }, { allowSignalWrites: true });
7296
+ }
7297
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiEditorReadonlyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7298
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: CuiEditorReadonlyComponent, isStandalone: true, selector: "cui-editor-readonly", inputs: { editorId: { classPropertyName: "editorId", publicName: "editorId", isSignal: true, isRequired: true, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, buttonTemplate: { classPropertyName: "buttonTemplate", publicName: "buttonTemplate", isSignal: true, isRequired: true, transformFunction: null }, shortHeight: { classPropertyName: "shortHeight", publicName: "shortHeight", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "editor", first: true, predicate: ["editor"], descendants: true, isSignal: true }], ngImport: i0, template: "<cui-editor\r\n #editor\r\n class=\"editor\"\r\n [class.editor_opened]=\"isShowMore()\"\r\n [editorID]=\"editorId()\"\r\n [config]=\"editorConfig()\"\r\n/>\r\n@if (isMoreButtonShown()) {\r\n <button class=\"c-button\" (click)=\"onShow(editor)\">\r\n <ng-container [ngTemplateOutlet]=\"buttonTemplate()\" [ngTemplateOutletContext]=\"{ $implicit: isShowMore }\"></ng-container>\r\n </button>\r\n}\r\n", styles: [":host{--height: 68px;--fullHeight: 500px;display:flex;flex-direction:column;gap:8px}:host .editor{display:block;max-height:var(--height);overflow:hidden}:host .editor ::ng-deep [data-editor]{overflow:hidden}:host .editor_opened{max-height:var(--fullHeight)}:host .editor_opened ::ng-deep [data-editor]{max-height:var(--fullHeight);overflow:hidden auto}.c-button{padding:0}\n"], dependencies: [{ kind: "component", type: CuiEditorComponent, selector: "cui-editor", inputs: ["editorID", "config", "requestSize"], outputs: ["editorEmpty"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7299
+ }
7300
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiEditorReadonlyComponent, decorators: [{
7301
+ type: Component,
7302
+ args: [{ selector: 'cui-editor-readonly', standalone: true, imports: [CuiEditorComponent, NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<cui-editor\r\n #editor\r\n class=\"editor\"\r\n [class.editor_opened]=\"isShowMore()\"\r\n [editorID]=\"editorId()\"\r\n [config]=\"editorConfig()\"\r\n/>\r\n@if (isMoreButtonShown()) {\r\n <button class=\"c-button\" (click)=\"onShow(editor)\">\r\n <ng-container [ngTemplateOutlet]=\"buttonTemplate()\" [ngTemplateOutletContext]=\"{ $implicit: isShowMore }\"></ng-container>\r\n </button>\r\n}\r\n", styles: [":host{--height: 68px;--fullHeight: 500px;display:flex;flex-direction:column;gap:8px}:host .editor{display:block;max-height:var(--height);overflow:hidden}:host .editor ::ng-deep [data-editor]{overflow:hidden}:host .editor_opened{max-height:var(--fullHeight)}:host .editor_opened ::ng-deep [data-editor]{max-height:var(--fullHeight);overflow:hidden auto}.c-button{padding:0}\n"] }]
7303
+ }], ctorParameters: () => [] });
7304
+
7305
+ class CuiEditorModalComponent {
7306
+ constructor() {
7307
+ this.isOpen = signal(false);
7308
+ this.isButtonDisabled = signal(false);
7309
+ this.title = input.required();
7310
+ this.buttonTemplate = input();
7311
+ this.config = input.required();
7312
+ this.editorId = input();
7313
+ this.editorCreated = output();
7314
+ this.modalClosed = output();
7315
+ }
7316
+ onModalOpen() {
7317
+ this.isButtonDisabled.set(true);
7318
+ if (this.editorId()) {
7319
+ this.open();
7320
+ return;
7321
+ }
7322
+ this.editorCreated.emit();
7323
+ }
7324
+ open() {
7325
+ this.isOpen.set(true);
7326
+ }
7327
+ close() {
7328
+ this.isButtonDisabled.set(false);
7329
+ this.isOpen.set(false);
7330
+ this.modalClosed.emit();
7331
+ }
7332
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiEditorModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7333
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: CuiEditorModalComponent, isStandalone: true, selector: "cui-editor-modal", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, buttonTemplate: { classPropertyName: "buttonTemplate", publicName: "buttonTemplate", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, editorId: { classPropertyName: "editorId", publicName: "editorId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { editorCreated: "editorCreated", modalClosed: "modalClosed" }, ngImport: i0, template: "@if (buttonTemplate(); as template) {\r\n <button\r\n type=\"button\"\r\n class=\"button\"\r\n (click)=\"onModalOpen()\"\r\n >\r\n <ng-container [ngTemplateOutlet]=\"template\" />\r\n </button>\r\n} @else {\r\n <button\r\n class=\"description\"\r\n cuiButton\r\n type=\"button\"\r\n appearance=\"outlined-gray\"\r\n icon=\"cuiIconRichText\"\r\n size=\"sm\"\r\n (click)=\"onModalOpen()\"\r\n [disabled]=\"isButtonDisabled()\"\r\n >\r\n @if (editorId()) {\r\n <span class=\"description__text _created\">{{ 'Description' }}</span>\r\n <cui-svg\r\n class=\"description__icon\"\r\n icon=\"cuiIconEdit\"\r\n color=\"var(--cui-base-500)\"\r\n />\r\n } @else {\r\n <cui-svg\r\n class=\"description__icon\"\r\n icon=\"cuiIconPlus\"\r\n color=\"var(--cui-light-blue-600)\"\r\n />\r\n <span class=\"description__text\">{{ 'Add description' }}</span>\r\n }\r\n </button>\r\n}\r\n@if (isOpen()) {\r\n <div class=\"wrapper\">\r\n @if (editorId(); as id) {\r\n <header class=\"header\">\r\n <div class=\"info\">\r\n <button\r\n cuiButton\r\n type=\"button\"\r\n icon=\"cuiIconChevronLeft\"\r\n size=\"xxs\"\r\n appearance=\"secondary\"\r\n shape=\"rounded\"\r\n (click)=\"close()\"\r\n ></button>\r\n <h1 class=\"title\">{{ title() }}</h1>\r\n </div>\r\n <div class=\"actions\">\r\n <!-- <cui-loader /> -->\r\n <button\r\n type=\"button\"\r\n cuiButton\r\n size=\"xs\"\r\n (click)=\"close()\"\r\n >\r\n {{ 'Done' }}\r\n </button>\r\n </div>\r\n </header>\r\n\r\n <section class=\"section\">\r\n <cui-editor\r\n #editorComponent\r\n class=\"editor\"\r\n [editorID]=\"id\"\r\n [config]=\"config()\"\r\n />\r\n </section>\r\n }\r\n </div>\r\n}\r\n", styles: [":host ::ng-deep .delete{width:max-content}:host ::ng-deep .delete .c-content{display:flex;align-items:center;gap:4px;color:var(--cui-danger)}:host ::ng-deep .description .c-content{display:flex;align-items:center;gap:4px}.button{padding:0}.description{width:max-content}.description__text{color:var(--cui-light-blue-600)}.description__text._created{color:var(--cui-base-900)}.description__icon{padding:4px}.wrapper{position:fixed;z-index:10;inset:0;background-color:var(--cui-base-0)}.header{display:flex;justify-content:space-between;padding:8px 16px;border-bottom:.5px solid var(--cui-base-200);background:var(--cui-base-0)}.info,.actions{display:flex;gap:12px;align-items:center}.section{padding-right:24px;padding-left:24px;padding-top:24px;height:calc(100% - 50px);overflow:hidden}.title{font-weight:500;font-size:14px;line-height:20px;margin:0}.editor{padding-right:32px;padding-left:32px;padding-top:32px;display:block;margin:0 auto;max-width:750px;height:100%}\n"], dependencies: [{ kind: "component", type: CuiEditorComponent, selector: "cui-editor", inputs: ["editorID", "config", "requestSize"], outputs: ["editorEmpty"] }, { kind: "ngmodule", type: CuiButtonModule }, { kind: "component", type: CuiButtonComponent, selector: "button[cuiButton], a[cuiButton]", inputs: ["shape", "disabled", "isLoaderShown", "icon", "iconRight", "appearance", "size"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: CuiSvgModule }, { kind: "component", type: CuiSvgComponent, selector: "cui-svg[icon]", inputs: ["width", "height", "strokeWidth", "color", "icon"] }] }); }
7334
+ }
7335
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiEditorModalComponent, decorators: [{
7336
+ type: Component,
7337
+ args: [{ selector: 'cui-editor-modal', imports: [
7338
+ CuiEditorComponent,
7339
+ CuiButtonModule,
7340
+ NgTemplateOutlet,
7341
+ CuiSvgModule
7342
+ ], standalone: true, template: "@if (buttonTemplate(); as template) {\r\n <button\r\n type=\"button\"\r\n class=\"button\"\r\n (click)=\"onModalOpen()\"\r\n >\r\n <ng-container [ngTemplateOutlet]=\"template\" />\r\n </button>\r\n} @else {\r\n <button\r\n class=\"description\"\r\n cuiButton\r\n type=\"button\"\r\n appearance=\"outlined-gray\"\r\n icon=\"cuiIconRichText\"\r\n size=\"sm\"\r\n (click)=\"onModalOpen()\"\r\n [disabled]=\"isButtonDisabled()\"\r\n >\r\n @if (editorId()) {\r\n <span class=\"description__text _created\">{{ 'Description' }}</span>\r\n <cui-svg\r\n class=\"description__icon\"\r\n icon=\"cuiIconEdit\"\r\n color=\"var(--cui-base-500)\"\r\n />\r\n } @else {\r\n <cui-svg\r\n class=\"description__icon\"\r\n icon=\"cuiIconPlus\"\r\n color=\"var(--cui-light-blue-600)\"\r\n />\r\n <span class=\"description__text\">{{ 'Add description' }}</span>\r\n }\r\n </button>\r\n}\r\n@if (isOpen()) {\r\n <div class=\"wrapper\">\r\n @if (editorId(); as id) {\r\n <header class=\"header\">\r\n <div class=\"info\">\r\n <button\r\n cuiButton\r\n type=\"button\"\r\n icon=\"cuiIconChevronLeft\"\r\n size=\"xxs\"\r\n appearance=\"secondary\"\r\n shape=\"rounded\"\r\n (click)=\"close()\"\r\n ></button>\r\n <h1 class=\"title\">{{ title() }}</h1>\r\n </div>\r\n <div class=\"actions\">\r\n <!-- <cui-loader /> -->\r\n <button\r\n type=\"button\"\r\n cuiButton\r\n size=\"xs\"\r\n (click)=\"close()\"\r\n >\r\n {{ 'Done' }}\r\n </button>\r\n </div>\r\n </header>\r\n\r\n <section class=\"section\">\r\n <cui-editor\r\n #editorComponent\r\n class=\"editor\"\r\n [editorID]=\"id\"\r\n [config]=\"config()\"\r\n />\r\n </section>\r\n }\r\n </div>\r\n}\r\n", styles: [":host ::ng-deep .delete{width:max-content}:host ::ng-deep .delete .c-content{display:flex;align-items:center;gap:4px;color:var(--cui-danger)}:host ::ng-deep .description .c-content{display:flex;align-items:center;gap:4px}.button{padding:0}.description{width:max-content}.description__text{color:var(--cui-light-blue-600)}.description__text._created{color:var(--cui-base-900)}.description__icon{padding:4px}.wrapper{position:fixed;z-index:10;inset:0;background-color:var(--cui-base-0)}.header{display:flex;justify-content:space-between;padding:8px 16px;border-bottom:.5px solid var(--cui-base-200);background:var(--cui-base-0)}.info,.actions{display:flex;gap:12px;align-items:center}.section{padding-right:24px;padding-left:24px;padding-top:24px;height:calc(100% - 50px);overflow:hidden}.title{font-weight:500;font-size:14px;line-height:20px;margin:0}.editor{padding-right:32px;padding-left:32px;padding-top:32px;display:block;margin:0 auto;max-width:750px;height:100%}\n"] }]
7343
+ }] });
7344
+
7345
+ class CuiEditorBlockComponent {
7346
+ constructor() {
7347
+ this.skipFirstValidation = true;
7348
+ this.editorConfig = signal(null);
7349
+ this.isDescriptionModalOpen = signal(false);
7350
+ this.isDescriptionEmpty = signal(false);
7351
+ this.editorContainer = viewChild('editorContainer', {
7352
+ read: ElementRef
7353
+ });
7354
+ this.title = input.required();
7355
+ this.editorId = input.required();
7356
+ this.config = input.required();
7357
+ this.required = input(false);
7358
+ this.editorEmpty = output();
7359
+ this.initEditorConfig();
7360
+ }
7361
+ onToggleDescriptionModal() {
7362
+ this.isDescriptionModalOpen.update((prev) => !prev);
7363
+ }
7364
+ onDescriptionChange(value) {
7365
+ this.editorEmpty.emit(value);
7366
+ if (this.skipFirstValidation) {
7367
+ this.skipFirstValidation = false;
7368
+ return;
7369
+ }
7370
+ this.isDescriptionEmpty.set(value);
7371
+ }
7372
+ initEditorConfig() {
7373
+ const effectRef = effect(() => {
7374
+ const element = this.editorContainer()?.nativeElement;
7375
+ if (!element) {
7376
+ return;
7377
+ }
7378
+ this.editorConfig.set({ ...this.config(), element });
7379
+ effectRef.destroy();
7380
+ }, { allowSignalWrites: true });
7381
+ }
7382
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiEditorBlockComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7383
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: CuiEditorBlockComponent, isStandalone: true, selector: "cui-editor-block", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, editorId: { classPropertyName: "editorId", publicName: "editorId", isSignal: true, isRequired: true, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { editorEmpty: "editorEmpty" }, viewQueries: [{ propertyName: "editorContainer", first: true, predicate: ["editorContainer"], descendants: true, read: ElementRef, isSignal: true }], ngImport: i0, template: "<ng-container *transloco=\"let t\">\r\n <div class=\"wrapper\">\r\n <span class=\"title\">\r\n {{ t('DESCRIPTION') }}\r\n @if (required()) {\r\n <span class=\"title__required\">*</span>\r\n }\r\n </span>\r\n <ng-template #button>\r\n <button\r\n [cuiTooltip]=\"t('EXPAND_EDITOR_TO_FULLSCREEN')\"\r\n cuiButton\r\n size=\"xxs\"\r\n type=\"button\"\r\n appearance=\"ghost\"\r\n icon=\"cuiIconMaximizeSm\"\r\n (click)=\"onToggleDescriptionModal()\"\r\n ></button>\r\n </ng-template>\r\n <cui-editor-modal\r\n [title]=\"title()\"\r\n [editorId]=\"editorId()\"\r\n [buttonTemplate]=\"button\"\r\n [config]=\"config()\"\r\n (modalClosed)=\"onToggleDescriptionModal()\"\r\n />\r\n </div>\r\n <div\r\n #editorContainer\r\n cuiContentWrapper\r\n class=\"editor\"\r\n [class.editor_invalid]=\"required() && isDescriptionEmpty()\"\r\n >\r\n @if (!isDescriptionModalOpen() && editorConfig()) {\r\n <cui-editor\r\n #editorComponent\r\n [editorID]=\"editorId()\"\r\n [config]=\"editorConfig()!\"\r\n (editorEmpty)=\"onDescriptionChange($event)\"\r\n />\r\n }\r\n </div>\r\n @if (required() && isDescriptionEmpty()) {\r\n <cui-hint hintType=\"error\">{{ t('DESCRIPTION_IS_REQUIRED') }}</cui-hint>\r\n }\r\n</ng-container>\r\n", styles: [":host{padding:16px;display:flex;flex-direction:column;gap:8px;background:var(--cui-base-10);border-radius:8px}.wrapper{display:flex;gap:8px;align-items:center;justify-content:space-between}.editor{padding-top:16px;padding-bottom:16px;display:block;max-height:650px;overflow:auto}.editor_invalid{border:1px solid var(--cui-danger)}.title{font-weight:500;font-size:14px;line-height:20px}.title__required{color:var(--cui-danger)}\n"], dependencies: [{ kind: "ngmodule", type: CuiButtonModule }, { kind: "component", type: CuiButtonComponent, selector: "button[cuiButton], a[cuiButton]", inputs: ["shape", "disabled", "isLoaderShown", "icon", "iconRight", "appearance", "size"] }, { kind: "component", type: CuiEditorModalComponent, selector: "cui-editor-modal", inputs: ["title", "buttonTemplate", "config", "editorId"], outputs: ["editorCreated", "modalClosed"] }, { kind: "component", type: CuiEditorComponent, selector: "cui-editor", inputs: ["editorID", "config", "requestSize"], outputs: ["editorEmpty"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: CuiContentWrapperComponent, selector: "cui-content-wrapper, [cuiContentWrapper]", inputs: ["backgroundColor", "gap"] }, { kind: "directive", type: CuiTooltipDirective, selector: "[cuiTooltip]:not(ng-container):not(ng-template)", inputs: ["cuiTooltipContext", "cuiTooltipAppearance", "cuiTooltip"] }, { kind: "ngmodule", type: CuiHintModule }, { kind: "component", type: CuiHintComponent, selector: "cui-hint", inputs: ["hintType"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7384
+ }
7385
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiEditorBlockComponent, decorators: [{
7386
+ type: Component,
7387
+ args: [{ selector: 'cui-editor-block', imports: [
7388
+ CuiButtonModule,
7389
+ CuiEditorModalComponent,
7390
+ CuiEditorComponent,
7391
+ TranslocoDirective,
7392
+ CuiContentWrapperComponent,
7393
+ CuiTooltip,
7394
+ CuiHintModule
7395
+ ], standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t\">\r\n <div class=\"wrapper\">\r\n <span class=\"title\">\r\n {{ t('DESCRIPTION') }}\r\n @if (required()) {\r\n <span class=\"title__required\">*</span>\r\n }\r\n </span>\r\n <ng-template #button>\r\n <button\r\n [cuiTooltip]=\"t('EXPAND_EDITOR_TO_FULLSCREEN')\"\r\n cuiButton\r\n size=\"xxs\"\r\n type=\"button\"\r\n appearance=\"ghost\"\r\n icon=\"cuiIconMaximizeSm\"\r\n (click)=\"onToggleDescriptionModal()\"\r\n ></button>\r\n </ng-template>\r\n <cui-editor-modal\r\n [title]=\"title()\"\r\n [editorId]=\"editorId()\"\r\n [buttonTemplate]=\"button\"\r\n [config]=\"config()\"\r\n (modalClosed)=\"onToggleDescriptionModal()\"\r\n />\r\n </div>\r\n <div\r\n #editorContainer\r\n cuiContentWrapper\r\n class=\"editor\"\r\n [class.editor_invalid]=\"required() && isDescriptionEmpty()\"\r\n >\r\n @if (!isDescriptionModalOpen() && editorConfig()) {\r\n <cui-editor\r\n #editorComponent\r\n [editorID]=\"editorId()\"\r\n [config]=\"editorConfig()!\"\r\n (editorEmpty)=\"onDescriptionChange($event)\"\r\n />\r\n }\r\n </div>\r\n @if (required() && isDescriptionEmpty()) {\r\n <cui-hint hintType=\"error\">{{ t('DESCRIPTION_IS_REQUIRED') }}</cui-hint>\r\n }\r\n</ng-container>\r\n", styles: [":host{padding:16px;display:flex;flex-direction:column;gap:8px;background:var(--cui-base-10);border-radius:8px}.wrapper{display:flex;gap:8px;align-items:center;justify-content:space-between}.editor{padding-top:16px;padding-bottom:16px;display:block;max-height:650px;overflow:auto}.editor_invalid{border:1px solid var(--cui-danger)}.title{font-weight:500;font-size:14px;line-height:20px}.title__required{color:var(--cui-danger)}\n"] }]
7396
+ }], ctorParameters: () => [] });
7397
+
7398
+ const cuiXNdjsonInterceptor = (request, next) => {
7399
+ if (request.headers.get('Content-Type') !== 'application/x-ndjson') {
7400
+ return next(request);
7401
+ }
7402
+ return new Observable((observer) => {
7403
+ const controller = new AbortController();
7404
+ const signal = controller.signal;
7405
+ (async () => {
7406
+ try {
7407
+ const response = await fetch(request.urlWithParams, {
7408
+ method: request.method,
7409
+ headers: request.headers.keys().reduce((headers, key) => {
7410
+ headers[key] = request.headers.get(key);
7411
+ return headers;
7412
+ }, {}),
7413
+ body: request.body ? JSON.stringify(request.body) : null,
7414
+ signal
7415
+ });
7416
+ if (!response.ok) {
7417
+ const error = await response.json();
7418
+ observer.error(new HttpErrorResponse({ error }));
7419
+ return;
7420
+ }
7421
+ const reader = response.body.getReader();
7422
+ const decoder = new TextDecoder();
7423
+ let buffer = '';
7424
+ for (;;) {
7425
+ const { done, value } = await reader.read();
7426
+ if (done) {
7427
+ observer.complete();
7428
+ return;
7429
+ }
7430
+ buffer += decoder.decode(value);
7431
+ const lines = buffer.split('\n');
7432
+ buffer = lines.pop() ?? '';
7433
+ lines.forEach((line) => observer.next(JSON.parse(line)));
7434
+ }
7435
+ }
7436
+ catch (error) {
7437
+ observer.error(new HttpErrorResponse({ error }));
7438
+ }
7439
+ })();
7440
+ return () => controller.abort();
7441
+ });
7442
+ };
7443
+
7444
+ const cuiLoaderInterceptor = (request, next) => {
7445
+ const loaderService = inject(CuiLoaderService);
7446
+ if (request.method === 'GET') {
7447
+ return next(request);
7448
+ }
7449
+ loaderService.setLoading();
7450
+ return next(request).pipe(catchError(throwError), finalize(loaderService.handleCompletedRequest.bind(loaderService)));
7451
+ };
7452
+
7453
+ class CuiGeneralControlErrorHintComponent {
7454
+ constructor() {
7455
+ this.control = input.required();
7456
+ this.isVisible = input();
7457
+ }
7458
+ get isInvalid() {
7459
+ return this.isVisible() ?? (this.control().invalid && this.control().dirty);
7460
+ }
7461
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiGeneralControlErrorHintComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7462
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: CuiGeneralControlErrorHintComponent, isStandalone: true, selector: "cui-general-control-error-hint", inputs: { control: { classPropertyName: "control", publicName: "control", isSignal: true, isRequired: true, transformFunction: null }, isVisible: { classPropertyName: "isVisible", publicName: "isVisible", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<ng-container *transloco=\"let t\">\r\n @if (isInvalid) {\r\n @if (control().errors; as errors) {\r\n <cui-hint hintType=\"error\">\r\n @if (errors['required']) {\r\n {{ t('FIELD_IS_REQUIRED') }}\r\n } @else if (errors['maxlength']) {\r\n {{ t('PLEASE_KEEP_FIELD_UNDER_CHARACTERS', { value: errors['maxlength'].requiredLength }) }}\r\n } @else if (errors['extraSpaces']) {\r\n {{ t('MUST_BE_WITHOUT_EXTRA_SPACES') }}\r\n } @else if (errors['min']) {\r\n {{ t('MIN_VALUE_MUST_BE_MORE_THAN', { value: errors['min'].min }) }}\r\n } @else if (errors['max']) {\r\n {{ t('MAX_VALUE_MUST_BE_LESS_THAN', { value: errors['max'].max }) }}\r\n }\r\n </cui-hint>\r\n }\r\n }\r\n</ng-container>\r\n", styles: [":host{display:inline-block}:host:empty{display:none}\n"], dependencies: [{ kind: "ngmodule", type: CuiHintModule }, { kind: "component", type: CuiHintComponent, selector: "cui-hint", inputs: ["hintType"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }], changeDetection: i0.ChangeDetectionStrategy.Default }); }
7463
+ }
7464
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiGeneralControlErrorHintComponent, decorators: [{
7465
+ type: Component,
7466
+ args: [{ selector: 'cui-general-control-error-hint', imports: [CuiHintModule, TranslocoDirective], standalone: true, changeDetection: ChangeDetectionStrategy.Default, template: "<ng-container *transloco=\"let t\">\r\n @if (isInvalid) {\r\n @if (control().errors; as errors) {\r\n <cui-hint hintType=\"error\">\r\n @if (errors['required']) {\r\n {{ t('FIELD_IS_REQUIRED') }}\r\n } @else if (errors['maxlength']) {\r\n {{ t('PLEASE_KEEP_FIELD_UNDER_CHARACTERS', { value: errors['maxlength'].requiredLength }) }}\r\n } @else if (errors['extraSpaces']) {\r\n {{ t('MUST_BE_WITHOUT_EXTRA_SPACES') }}\r\n } @else if (errors['min']) {\r\n {{ t('MIN_VALUE_MUST_BE_MORE_THAN', { value: errors['min'].min }) }}\r\n } @else if (errors['max']) {\r\n {{ t('MAX_VALUE_MUST_BE_LESS_THAN', { value: errors['max'].max }) }}\r\n }\r\n </cui-hint>\r\n }\r\n }\r\n</ng-container>\r\n", styles: [":host{display:inline-block}:host:empty{display:none}\n"] }]
7467
+ }] });
7468
+
7469
+ class CuiUtilityInfoComponent {
7470
+ get controls() {
7471
+ return this.form.controls;
7472
+ }
7473
+ get isTitleError() {
7474
+ return this.controls.title.invalid && this.controls.title.dirty;
7475
+ }
7476
+ get isDescriptionError() {
7477
+ return this.controls.description.invalid && this.controls.description.dirty;
7478
+ }
7479
+ constructor() {
7480
+ this.destroy = inject(DestroyRef);
7481
+ this.formBuilder = inject(NonNullableFormBuilder);
7482
+ this.translocoService = inject(TranslocoService);
7483
+ this.frameApiService = inject(CuiFrameApiService);
7484
+ this.cuiAlertService = inject(CuiAlertService);
7485
+ this.cuiIdService = inject(CuiIdService);
7486
+ this.CONTROL_DELAY = 500;
7487
+ this.MAX_FILE_SIZE = 20971520;
7488
+ this.titleId = this.cuiIdService.generate();
7489
+ this.descriptionId = this.cuiIdService.generate();
7490
+ this.form = this.formBuilder.group({
7491
+ title: this.formBuilder.control('', createDefaultValidators({ asyncDelay: this.CONTROL_DELAY })),
7492
+ description: this.formBuilder.control('', createDefaultValidators({ asyncDelay: this.CONTROL_DELAY }))
7493
+ });
7494
+ this.isDescriptionModalOpen = signal(false);
7495
+ this.isDescriptionEmpty = signal(false);
7496
+ this.editorId = signal(null);
7497
+ this.thumbnail = signal(null);
7498
+ this.thumbnailUrl = computed(() => {
7499
+ const thumbnail = this.thumbnail();
7500
+ if (thumbnail?.resource) {
7501
+ return thumbnail.resource;
7502
+ }
7503
+ return this.baseResourceUrl() + thumbnail.fileId;
7504
+ });
7505
+ this.uploadButtonName = computed(() => {
7506
+ const thumbnail = this.thumbnail();
7507
+ if (thumbnail?.name) {
7508
+ return this.translocoService.translate('REPLACE_FILE');
7509
+ }
7510
+ return this.translocoService.translate('UPLOAD_FILE');
7511
+ });
7512
+ this.heading = null;
7513
+ this.title = input.required();
7514
+ this.framerId = input.required();
7515
+ this.baseResourceUrl = input.required();
7516
+ this.config = input.required();
7517
+ this.formChanged = output();
7518
+ this.isFormValidChanged = output();
7519
+ this.initUtilityEffect();
7520
+ }
7521
+ onSelectFile() {
7522
+ const input = document.createElement('input');
7523
+ input.type = 'file';
7524
+ input.accept = 'image/jpg, image/jpeg, image/png, video/mp4';
7525
+ input.onchange = () => {
7526
+ const files = input.files;
7527
+ if (!files?.length) {
7528
+ return;
7529
+ }
7530
+ this.getFile(files);
7531
+ };
7532
+ input.click();
7533
+ }
7534
+ onEditorEmpty(isEmpty) {
7535
+ this.isDescriptionEmpty.set(isEmpty);
7536
+ this.isFormValidChanged.emit(this.checkFormValidation());
7537
+ }
7538
+ onRemoveThumbnail() {
7539
+ const frameId = this.framerId();
7540
+ const fragmentId = this.thumbnail()?.id;
7541
+ if (!frameId || !fragmentId) {
7542
+ return;
7543
+ }
7544
+ this.frameApiService.deleteResource(frameId, fragmentId).subscribe(() => {
7545
+ this.thumbnail.update((prev) => ({ ...prev, fileId: null, name: null, resource: null }));
7546
+ });
7547
+ }
7548
+ onToggleDescriptionModal() {
7549
+ this.isDescriptionModalOpen.update((prev) => !prev);
7550
+ }
7551
+ initUtilityEffect() {
7552
+ const effectRef = effect(() => {
7553
+ const title = this.title();
7554
+ if (!title) {
7555
+ return;
7556
+ }
7557
+ this.initTitleSubscriptions();
7558
+ this.initFrameFragments();
7559
+ effectRef.destroy();
7560
+ });
7561
+ }
7562
+ initTitleSubscriptions() {
7563
+ this.form.patchValue({ title: this.title() });
7564
+ this.form.statusChanges
7565
+ .pipe(takeUntilDestroyed(this.destroy))
7566
+ .subscribe(() => this.isFormValidChanged.emit(this.checkFormValidation()));
7567
+ this.form.valueChanges
7568
+ .pipe(takeUntilDestroyed(this.destroy), startWith(this.form.value), pairwise(), debounceTime(this.CONTROL_DELAY), map(([prev, current]) => this.compareFormValues([prev, current])))
7569
+ .subscribe((value) => {
7570
+ this.formChanged.emit(value);
7571
+ });
7572
+ }
7573
+ initFrameFragments() {
7574
+ const frameId = this.framerId();
7575
+ if (!frameId) {
7576
+ return;
7577
+ }
7578
+ this.frameApiService.getFrame(frameId).subscribe((frame) => {
7579
+ frame.fragments.forEach((fragment) => {
7580
+ if (fragment.type === "J_TEXT" /* FragmentType.jText */) {
7581
+ this.editorId.set(fragment?.id);
7582
+ }
7583
+ if (fragment.type === "RESOURCE_FILE" /* FragmentType.resourceFile */) {
7584
+ this.setResourceFile(fragment);
7585
+ }
7586
+ });
7587
+ });
7588
+ }
7589
+ compareFormValues([prevGroup, currentGruop]) {
7590
+ const keys = Object.keys(currentGruop);
7591
+ const changedFields = {};
7592
+ keys.forEach((key) => {
7593
+ const prev = prevGroup[key];
7594
+ const current = currentGruop[key];
7595
+ if (prev === current) {
7596
+ return;
7597
+ }
7598
+ changedFields[key] = current;
7599
+ });
7600
+ return changedFields;
7601
+ }
7602
+ setResourceFile(resource) {
7603
+ const url = this.baseResourceUrl() + resource.fileId;
7604
+ this.thumbnail.set(resource);
7605
+ if (!url || resource?.name?.split('.').pop() !== 'mp4') {
7606
+ return;
7607
+ }
7608
+ this.getCaptureFromVideo(url);
7609
+ }
7610
+ getFile(files) {
7611
+ const file = files.item(0);
7612
+ if (!file) {
7613
+ return;
7614
+ }
7615
+ if (file.size > this.MAX_FILE_SIZE) {
7616
+ this.cuiAlertService
7617
+ .open(this.translocoService.translate('INVALID_FILE_SIZE'), {
7618
+ status: 'error'
7619
+ })
7620
+ .subscribe();
7621
+ return;
7622
+ }
7623
+ const isVideo = file.name.split('.').at(-1) === 'mp4';
7624
+ const url = URL.createObjectURL(file);
7625
+ if (isVideo) {
7626
+ this.getCaptureFromVideo(url, file);
7627
+ }
7628
+ else {
7629
+ this.thumbnail.update((prev) => ({ ...prev, name: file.name, resource: url }));
7630
+ }
7631
+ this.uploadFile(file);
7632
+ }
7633
+ uploadFile(file) {
7634
+ const frameId = this.framerId();
7635
+ const fragmentId = this.thumbnail()?.id;
7636
+ if (!frameId || !fragmentId) {
7637
+ return;
7638
+ }
7639
+ const formData = new FormData();
7640
+ formData.append('resource', file);
7641
+ this.frameApiService.uploadResource(formData, frameId, fragmentId).subscribe();
7642
+ }
7643
+ getCaptureFromVideo(url, file) {
7644
+ const canvas = document.createElement('canvas');
7645
+ const video = document.createElement('video');
7646
+ video.src = url;
7647
+ video.currentTime = 1;
7648
+ canvas.width = 184;
7649
+ canvas.height = 120;
7650
+ video.onloadeddata = () => {
7651
+ const context = canvas.getContext('2d');
7652
+ if (!context) {
7653
+ return;
7654
+ }
7655
+ context.drawImage(video, 0, 0, canvas.width, canvas.height);
7656
+ canvas.toBlob((blob) => {
7657
+ if (!blob) {
7658
+ return;
7659
+ }
7660
+ const videoCaptureUrl = URL.createObjectURL(blob);
7661
+ this.thumbnail.update((prev) => ({
7662
+ ...prev,
7663
+ name: (file?.name || prev?.name),
7664
+ resource: videoCaptureUrl
7665
+ }));
7666
+ });
7667
+ };
7668
+ video.load();
7669
+ }
7670
+ checkFormValidation() {
7671
+ console.log(this.isDescriptionEmpty(), this.form.invalid);
7672
+ return !this.isDescriptionEmpty() && !this.form.invalid;
7673
+ }
7674
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiUtilityInfoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7675
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: CuiUtilityInfoComponent, isStandalone: true, selector: "cui-utility-info", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, framerId: { classPropertyName: "framerId", publicName: "framerId", isSignal: true, isRequired: true, transformFunction: null }, baseResourceUrl: { classPropertyName: "baseResourceUrl", publicName: "baseResourceUrl", isSignal: true, isRequired: true, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { formChanged: "formChanged", isFormValidChanged: "isFormValidChanged" }, ngImport: i0, template: "<ng-container *transloco=\"let t\">\r\n <section class=\"content\">\r\n <cui-form-field>\r\n <label cuiLabel [isRequired]=\"true\" [for]=\"titleId\">\r\n {{ t('TITLE') }}\r\n </label>\r\n <cui-input-text\r\n [cuiTextFieldId]=\"titleId\"\r\n [cuiTextFieldPlaceholder]=\"t('ADD_TITLE')\"\r\n [cuiTextFieldIsError]=\"isTitleError\"\r\n [formControl]=\"form.controls.title\"\r\n />\r\n @if (isTitleError) {\r\n <cui-general-control-error-hint [control]=\"form.controls.title\" [isVisible]=\"true\" />\r\n }\r\n </cui-form-field>\r\n <cui-form-field>\r\n <label cuiLabel [isRequired]=\"true\" [for]=\"descriptionId\">\r\n {{ t('SHORT_DESCRIPTION') }}\r\n </label>\r\n <cui-input-text\r\n [cuiTextFieldId]=\"descriptionId\"\r\n cuiTextFieldPlaceholder=\"{{t('SHORT_DESCRIPTION')}}...\"\r\n [cuiTextFieldIsError]=\"isDescriptionError\"\r\n [formControl]=\"form.controls.description\"\r\n />\r\n @if (isDescriptionError) {\r\n <cui-general-control-error-hint [control]=\"form.controls.description\" [isVisible]=\"true\" />\r\n }\r\n </cui-form-field>\r\n <section class=\"file\">\r\n <span class=\"title\">{{ t('THUMBNAIL') }}</span>\r\n <div class=\"content__upload\">\r\n <div class=\"content__upload-file\">\r\n @if (thumbnail()?.name; as fileId) {\r\n <div class=\"image\">\r\n <span class=\"image__name\">{{ thumbnail()?.name }}</span>\r\n <!-- TODO: ngSrc -->\r\n <img class=\"image__view\" [src]=\"thumbnailUrl()\" height=\"120\" width=\"184\" alt=\"Thumbnail\" />\r\n </div>\r\n }\r\n <button type=\"button\" cuiButton appearance=\"outlined-gray\" size=\"xxs\" icon=\"cuiIconUpload\"\r\n (click)=\"onSelectFile()\">\r\n {{ uploadButtonName() }}\r\n </button>\r\n @if (thumbnail()?.name) {\r\n <button class=\"content__remove-button\" cuiButton appearance=\"link\" size=\"sm\" type=\"button\"\r\n (click)=\"onRemoveThumbnail()\">\r\n {{ t('REMOVE') }}\r\n </button>\r\n }\r\n <span class=\"content__accepted\">\r\n {{ t('ACCEPTED') }}: JPG, JPEG, PNG, MP4 {{ t('UP_TO') }} 20MB\r\n </span>\r\n </div>\r\n </div>\r\n </section>\r\n @if (editorId(); as editorId) {\r\n <cui-editor-block\r\n [title]=\"form.controls.title.value || title()\"\r\n [config]=\"config()\"\r\n [editorId]=\"editorId\"\r\n [required]=\"true\"\r\n (editorEmpty)=\"onEditorEmpty($event)\"\r\n ></cui-editor-block>\r\n }\r\n </section>\r\n</ng-container>\r\n", styles: ["::ng-deep cui-dialog:has(.instruction-description-modal){inset:0;margin:auto;transform:none!important}:host{display:block}.title{font-weight:500;font-size:14px;line-height:20px;display:flex;gap:2px}.title_required{color:var(--cui-danger)}.content{display:flex;flex-direction:column;gap:16px;padding:16px 24px}.content__upload{padding:12px 16px;border-radius:8px;border:1px solid var(--cui-base-200);background:var(--cui-base-10)}.content__accepted{color:var(--cui-base-500)}.content__upload-file{display:flex;align-items:center;gap:8px}.content__upload-file input[type=file]{display:none}.content__remove-button ::ng-deep .c-content{color:var(--cui-danger)!important}.file{display:flex;flex-direction:column;gap:4px}.description_invalid{border:1px solid var(--cui-danger)}.image{position:relative;display:inline-block}.image__view{border-radius:8px;object-fit:cover}.image__name{position:absolute;top:6px;left:14px;color:var(--cui-base-0);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:170px;z-index:1}.image:after{content:\"\";position:absolute;top:0;left:0;width:100%;height:100%;background-color:#0003;z-index:0;pointer-events:none;border-radius:8px}.button-save{margin-left:auto}.instruction-description-modal{text-transform:none}.empty{padding:16px;color:var(--cui-base-500);text-align:center}\n"], dependencies: [{ kind: "ngmodule", type: i0.forwardRef(() => CuiAccordionModule) }, { kind: "ngmodule", type: i0.forwardRef(() => CuiButtonModule) }, { kind: "component", type: i0.forwardRef(() => CuiButtonComponent), selector: "button[cuiButton], a[cuiButton]", inputs: ["shape", "disabled", "isLoaderShown", "icon", "iconRight", "appearance", "size"] }, { kind: "ngmodule", type: i0.forwardRef(() => CuiFormFieldModule) }, { kind: "component", type: i0.forwardRef(() => CuiFormFieldComponent), selector: "cui-form-field" }, { kind: "ngmodule", type: i0.forwardRef(() => CuiHintModule) }, { kind: "ngmodule", type: i0.forwardRef(() => CuiInputModule) }, { kind: "component", type: i0.forwardRef(() => CuiInputTextComponent), selector: "cui-input-text" }, { kind: "directive", type: i0.forwardRef(() => CuiTextFieldIdDirective), selector: "[cuiTextFieldId]", inputs: ["cuiTextFieldId"] }, { kind: "directive", type: i0.forwardRef(() => CuiTextFieldPlaceholderDirective), selector: "[cuiTextFieldPlaceholder]", inputs: ["cuiTextFieldPlaceholder"] }, { kind: "directive", type: i0.forwardRef(() => CuiTextFieldIsErrorDirective), selector: "[cuiTextFieldIsError]", inputs: ["cuiTextFieldIsError"] }, { kind: "ngmodule", type: i0.forwardRef(() => CuiLabelModule) }, { kind: "component", type: i0.forwardRef(() => CuiLabelComponent), selector: "label[cuiLabel]", inputs: ["isRequired"] }, { kind: "component", type: i0.forwardRef(() => CuiEditorBlockComponent), selector: "cui-editor-block", inputs: ["title", "editorId", "config", "required"], outputs: ["editorEmpty"] }, { kind: "component", type: i0.forwardRef(() => CuiGeneralControlErrorHintComponent), selector: "cui-general-control-error-hint", inputs: ["control", "isVisible"] }, { kind: "ngmodule", type: i0.forwardRef(() => ReactiveFormsModule) }, { kind: "directive", type: i0.forwardRef(() => i2$1.NgControlStatus), selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i0.forwardRef(() => i2$1.FormControlDirective), selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i0.forwardRef(() => TranslocoDirective), selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7676
+ }
7677
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiUtilityInfoComponent, decorators: [{
7678
+ type: Component,
7679
+ args: [{ selector: 'cui-utility-info', imports: [
7680
+ CuiAccordionModule,
7681
+ CuiButtonModule,
7682
+ CuiFormFieldModule,
7683
+ CuiHintModule,
7684
+ CuiInputModule,
7685
+ CuiLabelModule,
7686
+ forwardRef(() => CuiEditorBlockComponent),
7687
+ CuiGeneralControlErrorHintComponent,
7688
+ ReactiveFormsModule,
7689
+ TranslocoDirective,
7690
+ CuiTooltip
7691
+ ], standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t\">\r\n <section class=\"content\">\r\n <cui-form-field>\r\n <label cuiLabel [isRequired]=\"true\" [for]=\"titleId\">\r\n {{ t('TITLE') }}\r\n </label>\r\n <cui-input-text\r\n [cuiTextFieldId]=\"titleId\"\r\n [cuiTextFieldPlaceholder]=\"t('ADD_TITLE')\"\r\n [cuiTextFieldIsError]=\"isTitleError\"\r\n [formControl]=\"form.controls.title\"\r\n />\r\n @if (isTitleError) {\r\n <cui-general-control-error-hint [control]=\"form.controls.title\" [isVisible]=\"true\" />\r\n }\r\n </cui-form-field>\r\n <cui-form-field>\r\n <label cuiLabel [isRequired]=\"true\" [for]=\"descriptionId\">\r\n {{ t('SHORT_DESCRIPTION') }}\r\n </label>\r\n <cui-input-text\r\n [cuiTextFieldId]=\"descriptionId\"\r\n cuiTextFieldPlaceholder=\"{{t('SHORT_DESCRIPTION')}}...\"\r\n [cuiTextFieldIsError]=\"isDescriptionError\"\r\n [formControl]=\"form.controls.description\"\r\n />\r\n @if (isDescriptionError) {\r\n <cui-general-control-error-hint [control]=\"form.controls.description\" [isVisible]=\"true\" />\r\n }\r\n </cui-form-field>\r\n <section class=\"file\">\r\n <span class=\"title\">{{ t('THUMBNAIL') }}</span>\r\n <div class=\"content__upload\">\r\n <div class=\"content__upload-file\">\r\n @if (thumbnail()?.name; as fileId) {\r\n <div class=\"image\">\r\n <span class=\"image__name\">{{ thumbnail()?.name }}</span>\r\n <!-- TODO: ngSrc -->\r\n <img class=\"image__view\" [src]=\"thumbnailUrl()\" height=\"120\" width=\"184\" alt=\"Thumbnail\" />\r\n </div>\r\n }\r\n <button type=\"button\" cuiButton appearance=\"outlined-gray\" size=\"xxs\" icon=\"cuiIconUpload\"\r\n (click)=\"onSelectFile()\">\r\n {{ uploadButtonName() }}\r\n </button>\r\n @if (thumbnail()?.name) {\r\n <button class=\"content__remove-button\" cuiButton appearance=\"link\" size=\"sm\" type=\"button\"\r\n (click)=\"onRemoveThumbnail()\">\r\n {{ t('REMOVE') }}\r\n </button>\r\n }\r\n <span class=\"content__accepted\">\r\n {{ t('ACCEPTED') }}: JPG, JPEG, PNG, MP4 {{ t('UP_TO') }} 20MB\r\n </span>\r\n </div>\r\n </div>\r\n </section>\r\n @if (editorId(); as editorId) {\r\n <cui-editor-block\r\n [title]=\"form.controls.title.value || title()\"\r\n [config]=\"config()\"\r\n [editorId]=\"editorId\"\r\n [required]=\"true\"\r\n (editorEmpty)=\"onEditorEmpty($event)\"\r\n ></cui-editor-block>\r\n }\r\n </section>\r\n</ng-container>\r\n", styles: ["::ng-deep cui-dialog:has(.instruction-description-modal){inset:0;margin:auto;transform:none!important}:host{display:block}.title{font-weight:500;font-size:14px;line-height:20px;display:flex;gap:2px}.title_required{color:var(--cui-danger)}.content{display:flex;flex-direction:column;gap:16px;padding:16px 24px}.content__upload{padding:12px 16px;border-radius:8px;border:1px solid var(--cui-base-200);background:var(--cui-base-10)}.content__accepted{color:var(--cui-base-500)}.content__upload-file{display:flex;align-items:center;gap:8px}.content__upload-file input[type=file]{display:none}.content__remove-button ::ng-deep .c-content{color:var(--cui-danger)!important}.file{display:flex;flex-direction:column;gap:4px}.description_invalid{border:1px solid var(--cui-danger)}.image{position:relative;display:inline-block}.image__view{border-radius:8px;object-fit:cover}.image__name{position:absolute;top:6px;left:14px;color:var(--cui-base-0);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:170px;z-index:1}.image:after{content:\"\";position:absolute;top:0;left:0;width:100%;height:100%;background-color:#0003;z-index:0;pointer-events:none;border-radius:8px}.button-save{margin-left:auto}.instruction-description-modal{text-transform:none}.empty{padding:16px;color:var(--cui-base-500);text-align:center}\n"] }]
7692
+ }], ctorParameters: () => [] });
7693
+
7694
+ class CuiSelectedCategoryService {
7695
+ constructor() {
7696
+ this.editingIdSignal = signal(null);
7697
+ this.creatingIdSignal = signal(null);
7698
+ this.categorySignal = signal(null);
7699
+ this.editingId = this.editingIdSignal.asReadonly();
7700
+ this.creatingId = this.creatingIdSignal.asReadonly();
7701
+ this.category = this.categorySignal.asReadonly();
7702
+ }
7703
+ setCurrentCategory(category) {
7704
+ this.categorySignal.set(category);
7705
+ }
7706
+ setEditingId(id) {
7707
+ this.editingIdSignal.set(id);
7708
+ this.clearCreatingId();
7709
+ }
7710
+ setCreatingId(id) {
7711
+ this.creatingIdSignal.set(id);
7712
+ this.clearEditingId();
7713
+ }
7714
+ clearEditingId() {
7715
+ this.editingIdSignal.set('');
7716
+ }
7717
+ clearCreatingId() {
7718
+ this.creatingIdSignal.set('');
7719
+ }
7720
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiSelectedCategoryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
7721
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiSelectedCategoryService, providedIn: 'root' }); }
7722
+ }
7723
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiSelectedCategoryService, decorators: [{
7724
+ type: Injectable,
7725
+ args: [{
7726
+ providedIn: 'root'
7727
+ }]
7728
+ }] });
7729
+
7730
+ class CuiCategoryFormComponent {
7731
+ get isTitleInvalid() {
7732
+ return this.titleControl.invalid && this.titleControl.dirty;
7733
+ }
7734
+ get isSubmitButtonDisabled() {
7735
+ return this.isDisabled() || this.form.invalid;
7736
+ }
7737
+ constructor() {
7738
+ this.nonNullableFormBuilder = inject(NonNullableFormBuilder);
7739
+ this.form = this.nonNullableFormBuilder.group({
7740
+ title: ['', createDefaultValidators({ asyncDelay: 0 })]
7741
+ });
7742
+ this.titleControl = this.form.controls.title;
7743
+ this.isDisabled = input(false);
7744
+ this.defaultTitle = input('');
7745
+ this.created = output();
7746
+ this.canceled = output();
7747
+ this.input = viewChild.required('input', { read: (ElementRef) });
7748
+ this.initInputDisableStateSubscription();
7749
+ }
7750
+ ngOnInit() {
7751
+ this.initDefaultTitle();
7752
+ this.initInputFocus();
7753
+ }
7754
+ onHostClick(event) {
7755
+ event.stopPropagation();
7756
+ }
7757
+ onSubmit() {
7758
+ if (this.form.invalid) {
7759
+ return;
7760
+ }
7761
+ this.created.emit(this.form.value.title);
7762
+ }
7763
+ onCancel(event) {
7764
+ event.stopPropagation();
7765
+ this.canceled.emit();
7766
+ }
7767
+ initInputDisableStateSubscription() {
7768
+ effect(() => {
7769
+ if (this.isDisabled()) {
7770
+ this.titleControl.disable();
7771
+ return;
7772
+ }
7773
+ this.titleControl.enable();
7774
+ });
7775
+ }
7776
+ initDefaultTitle() {
7777
+ this.form.patchValue({ title: this.defaultTitle() });
7778
+ }
7779
+ initInputFocus() {
7780
+ Promise.resolve().then(() => this.input().nativeElement.focus());
7781
+ }
7782
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiCategoryFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7783
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "18.2.13", type: CuiCategoryFormComponent, isStandalone: true, selector: "cui-category-form", inputs: { isDisabled: { classPropertyName: "isDisabled", publicName: "isDisabled", isSignal: true, isRequired: false, transformFunction: null }, defaultTitle: { classPropertyName: "defaultTitle", publicName: "defaultTitle", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { created: "created", canceled: "canceled" }, host: { listeners: { "click": "onHostClick($event)" } }, viewQueries: [{ propertyName: "input", first: true, predicate: ["input"], descendants: true, read: ElementRef, isSignal: true }], ngImport: i0, template: "<ng-container *transloco=\"let t\">\r\n <form\r\n [formGroup]=\"form\"\r\n class=\"form\"\r\n (ngSubmit)=\"onSubmit()\"\r\n >\r\n <div class=\"input\">\r\n <input\r\n #input\r\n cuiGhostInput\r\n formControlName=\"title\"\r\n type=\"text\"\r\n placeholder=\"{{ t('ADD_CATEGORY_NAME') }}...\"\r\n [isError]=\"isTitleInvalid\"\r\n (keyup)=\"$event.preventDefault()\"\r\n />\r\n <cui-general-control-error-hint [control]=\"titleControl\" />\r\n </div>\r\n <button\r\n cuiIconButton\r\n type=\"submit\"\r\n icon=\"cuiIconCheck\"\r\n color=\"var(--cui-success)\"\r\n [disabled]=\"isSubmitButtonDisabled\"\r\n class=\"button\"\r\n ></button>\r\n </form>\r\n <button\r\n cuiIconButton\r\n type=\"button\"\r\n icon=\"cuiIconXCircle\"\r\n color=\"var(--cui-danger)\"\r\n (click)=\"onCancel($event)\"\r\n [disabled]=\"isDisabled()\"\r\n class=\"button\"\r\n ></button>\r\n</ng-container>\r\n", styles: [":host{padding-top:2px;padding-bottom:2px;display:flex;gap:4px;flex-grow:1}.form,.input{flex-grow:1}.form{display:flex;gap:4px}.input{display:flex;flex-direction:column;gap:4px;align-items:flex-start}.button{width:28px}.button:disabled{opacity:.5}\n"], dependencies: [{ kind: "ngmodule", type: CuiFormFieldModule }, { kind: "ngmodule", type: CuiHintModule }, { kind: "ngmodule", type: CuiIconButtonModule }, { kind: "component", type: CuiIconButtonComponent, selector: "button[cuiIconButton][icon], a[cuiIconButton][icon]", inputs: ["icon", "color", "hoverColor"] }, { kind: "component", type: CuiGeneralControlErrorHintComponent, selector: "cui-general-control-error-hint", inputs: ["control", "isVisible"] }, { kind: "component", type: CuiGhostInputComponent, selector: "input [cuiGhostInput]", inputs: ["isError"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2$1.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: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7784
+ }
7785
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiCategoryFormComponent, decorators: [{
7786
+ type: Component,
7787
+ args: [{ selector: 'cui-category-form', imports: [
7788
+ CuiFormFieldModule,
7789
+ CuiHintModule,
7790
+ CuiIconButtonModule,
7791
+ CuiGeneralControlErrorHintComponent,
7792
+ CuiGhostInputComponent,
7793
+ ReactiveFormsModule,
7794
+ TranslocoDirective
7795
+ ], standalone: true, host: {
7796
+ '(click)': 'onHostClick($event)'
7797
+ }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t\">\r\n <form\r\n [formGroup]=\"form\"\r\n class=\"form\"\r\n (ngSubmit)=\"onSubmit()\"\r\n >\r\n <div class=\"input\">\r\n <input\r\n #input\r\n cuiGhostInput\r\n formControlName=\"title\"\r\n type=\"text\"\r\n placeholder=\"{{ t('ADD_CATEGORY_NAME') }}...\"\r\n [isError]=\"isTitleInvalid\"\r\n (keyup)=\"$event.preventDefault()\"\r\n />\r\n <cui-general-control-error-hint [control]=\"titleControl\" />\r\n </div>\r\n <button\r\n cuiIconButton\r\n type=\"submit\"\r\n icon=\"cuiIconCheck\"\r\n color=\"var(--cui-success)\"\r\n [disabled]=\"isSubmitButtonDisabled\"\r\n class=\"button\"\r\n ></button>\r\n </form>\r\n <button\r\n cuiIconButton\r\n type=\"button\"\r\n icon=\"cuiIconXCircle\"\r\n color=\"var(--cui-danger)\"\r\n (click)=\"onCancel($event)\"\r\n [disabled]=\"isDisabled()\"\r\n class=\"button\"\r\n ></button>\r\n</ng-container>\r\n", styles: [":host{padding-top:2px;padding-bottom:2px;display:flex;gap:4px;flex-grow:1}.form,.input{flex-grow:1}.form{display:flex;gap:4px}.input{display:flex;flex-direction:column;gap:4px;align-items:flex-start}.button{width:28px}.button:disabled{opacity:.5}\n"] }]
7798
+ }], ctorParameters: () => [] });
7799
+
7800
+ class CuiCreateCategoryItemComponent {
7801
+ constructor() {
7802
+ this.created = output();
7803
+ this.canceled = output();
7804
+ this.isDisabled = input(false);
7805
+ }
7806
+ onSubmit(title) {
7807
+ this.created.emit(title);
7808
+ }
7809
+ onCancel() {
7810
+ this.canceled.emit();
7811
+ }
7812
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiCreateCategoryItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7813
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.2.13", type: CuiCreateCategoryItemComponent, isStandalone: true, selector: "cui-create-category-item", inputs: { isDisabled: { classPropertyName: "isDisabled", publicName: "isDisabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { created: "created", canceled: "canceled" }, ngImport: i0, template: "<cui-svg\r\n icon=\"cuiIconFolder\"\r\n color=\"var(--cui-base-500)\"\r\n class=\"icon\"\r\n/>\r\n<cui-category-form\r\n [isDisabled]=\"isDisabled()\"\r\n (created)=\"onSubmit($event)\"\r\n (canceled)=\"onCancel()\"\r\n/>\r\n", styles: [":host{padding-right:4px;padding-left:4px;display:flex;gap:4px;align-items:flex-start;min-height:32px}.icon{padding:6px 2px}\n"], dependencies: [{ kind: "ngmodule", type: CuiSvgModule }, { kind: "component", type: CuiSvgComponent, selector: "cui-svg[icon]", inputs: ["width", "height", "strokeWidth", "color", "icon"] }, { kind: "component", type: CuiCategoryFormComponent, selector: "cui-category-form", inputs: ["isDisabled", "defaultTitle"], outputs: ["created", "canceled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7814
+ }
7815
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiCreateCategoryItemComponent, decorators: [{
7816
+ type: Component,
7817
+ args: [{ selector: 'cui-create-category-item', imports: [CuiSvgModule, CuiCategoryFormComponent], standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<cui-svg\r\n icon=\"cuiIconFolder\"\r\n color=\"var(--cui-base-500)\"\r\n class=\"icon\"\r\n/>\r\n<cui-category-form\r\n [isDisabled]=\"isDisabled()\"\r\n (created)=\"onSubmit($event)\"\r\n (canceled)=\"onCancel()\"\r\n/>\r\n", styles: [":host{padding-right:4px;padding-left:4px;display:flex;gap:4px;align-items:flex-start;min-height:32px}.icon{padding:6px 2px}\n"] }]
7818
+ }] });
7819
+
7820
+ class CuiCategoryItemComponent {
7821
+ constructor() {
7822
+ this.treeStructNavigatorApiService = inject(CuiTreeStructNavigatorApiService);
7823
+ this.selectedCategoryService = inject(CuiSelectedCategoryService);
7824
+ this.isStageCreationLoading = signal(false);
7825
+ this.stageStorageChildren = signal([]);
7826
+ this.areChildrenOpened = signal(false);
7827
+ this.openCloseButtonIcon = computed(() => this.areChildrenOpened() ? 'cuiIconChevronDown' : 'cuiIconChevronRight');
7828
+ this.doChildrenExist = computed(() => this.stageStorage().children.length || this.stageStorageChildren().length);
7829
+ this.isOpenCloseButtonHidden = computed(() => !this.doChildrenExist());
7830
+ this.stageStorageIcon = computed(() => this.areChildrenOpened() && this.doChildrenExist() ? 'cuiIconFolderOpen' : 'cuiIconFolder');
7831
+ this.isSubcategoryCreating = signal(false);
7832
+ this.isSubcategoryCreationLoading = signal(false);
7833
+ this.alignItems = computed(() => (this.isTitleEdit() ? 'flex-start' : 'center'));
7834
+ this.isTitleEdit = computed(() => this.selectedCategoryService.editingId() === this.stageStorage().id);
7835
+ this.isCreateCategoryControlVisible = computed(() => (this.selectedCategoryService.creatingId() === this.stageStorage().id && this.isSubcategoryCreating()) ||
7836
+ this.isSubcategoryCreationLoading());
7837
+ this.stageStorage = input.required();
7838
+ this.categoryTitle = signal('');
7839
+ this.category = computed(() => ({
7840
+ ...this.stageStorage(),
7841
+ title: this.categoryTitle() || this.stageStorage().title
7842
+ }));
7843
+ this.initStageStorageChildren();
7844
+ }
7845
+ onSelectCategory() {
7846
+ this.selectedCategoryService.setCurrentCategory(this.category());
7847
+ }
7848
+ onToggleChildren(event) {
7849
+ event.stopPropagation();
7850
+ this.areChildrenOpened.update((value) => !value);
7851
+ if (this.areChildrenOpened()) {
7852
+ return;
7853
+ }
7854
+ this.isSubcategoryCreating.set(false);
7855
+ }
7856
+ onTitleChanged(title) {
7857
+ this.onCancelTitleEdit();
7858
+ if (title === this.category().title) {
7859
+ return;
7860
+ }
7861
+ this.treeStructNavigatorApiService.updateTitle(this.stageStorage().id, title).subscribe(() => {
7862
+ this.categoryTitle.set(title);
7863
+ if (this.category().id === this.selectedCategoryService.category()?.id) {
7864
+ this.selectedCategoryService.setCurrentCategory(this.category());
7865
+ }
7866
+ });
7867
+ }
7868
+ onStartTitleEdit(event) {
7869
+ event?.stopPropagation();
7870
+ this.selectedCategoryService.setEditingId(this.stageStorage().id);
7871
+ this.onCreatingSubcategoryCanceled();
7872
+ }
7873
+ onCancelTitleEdit() {
7874
+ this.selectedCategoryService.clearEditingId();
7875
+ }
7876
+ onStartCreatingSubcategory(event) {
7877
+ event.stopPropagation();
7878
+ this.isSubcategoryCreating.set(true);
7879
+ this.areChildrenOpened.set(true);
7880
+ this.selectedCategoryService.setCreatingId(this.stageStorage().id);
7881
+ }
7882
+ onCreateNewSubcategoryCategory(title) {
7883
+ this.isSubcategoryCreating.set(false);
7884
+ this.isSubcategoryCreationLoading.set(true);
7885
+ this.treeStructNavigatorApiService
7886
+ .createStageStorageToParent(this.stageStorage().id, title)
7887
+ .pipe(finalize(this.isSubcategoryCreationLoading.set.bind(this.isSubcategoryCreationLoading, false)))
7888
+ .subscribe((stateStorage) => {
7889
+ this.stageStorageChildren.update((value) => [...value, stateStorage]);
7890
+ });
7891
+ }
7892
+ onCreatingSubcategoryCanceled() {
7893
+ this.isSubcategoryCreating.set(false);
7894
+ this.selectedCategoryService.clearCreatingId();
7895
+ }
7896
+ initStageStorageChildren() {
7897
+ effect(() => {
7898
+ if (!this.areChildrenOpened() || this.stageStorageChildren().length) {
7899
+ return;
7900
+ }
7901
+ const stageStorage = this.stageStorage();
7902
+ const stageStorageChildren = stageStorage.children;
7903
+ if (!stageStorageChildren.length) {
7904
+ return;
7905
+ }
7906
+ if (typeof stageStorageChildren[0] !== 'string') {
7907
+ this.stageStorageChildren.set(stageStorageChildren);
7908
+ return;
7909
+ }
7910
+ this.treeStructNavigatorApiService.getStageStoragesByParent(stageStorage.id).subscribe((storage) => {
7911
+ this.stageStorageChildren.update((prevStageStorages) => prevStageStorages ? [...prevStageStorages, storage] : [storage]);
7912
+ });
7913
+ }, { allowSignalWrites: true });
7914
+ }
7915
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiCategoryItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7916
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: CuiCategoryItemComponent, isStandalone: true, selector: "cui-category-item", inputs: { stageStorage: { classPropertyName: "stageStorage", publicName: "stageStorage", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<ng-container *cuiLet=\"category() as stage\">\r\n <button\r\n type=\"button\"\r\n [style.align-items]=\"alignItems()\"\r\n [disabled]=\"isStageCreationLoading()\"\r\n class=\"category\"\r\n (click)=\"onSelectCategory()\"\r\n >\r\n <button\r\n type=\"button\"\r\n ccFlexContainerDirective\r\n class=\"category__open-close-button\"\r\n [class.category__open-close-button_hidden]=\"isOpenCloseButtonHidden()\"\r\n (click)=\"onToggleChildren($event)\"\r\n >\r\n <cui-svg\r\n [icon]=\"openCloseButtonIcon()\"\r\n color=\"var(--cui-base-500)\"\r\n />\r\n </button>\r\n <cui-svg\r\n [icon]=\"stageStorageIcon()\"\r\n color=\"var(--cui-base-500)\"\r\n class=\"icon\"\r\n />\r\n @if (isTitleEdit()) {\r\n <cui-category-form\r\n [defaultTitle]=\"stage.title\"\r\n (created)=\"onTitleChanged($event)\"\r\n (canceled)=\"onCancelTitleEdit()\"\r\n />\r\n } @else {\r\n <span class=\"category__title\">{{ stage.title }}</span>\r\n\r\n <button\r\n cuiButton\r\n type=\"button\"\r\n appearance=\"ghost\"\r\n size=\"xxs\"\r\n icon=\"cuiIconEdit\"\r\n class=\"category__add-subcategory-button\"\r\n (click)=\"onStartTitleEdit($event)\"\r\n ></button>\r\n <button\r\n cuiButton\r\n type=\"button\"\r\n appearance=\"ghost\"\r\n size=\"xxs\"\r\n icon=\"cuiIconPlus\"\r\n class=\"category__add-subcategory-button\"\r\n (click)=\"onStartCreatingSubcategory($event)\"\r\n ></button>\r\n }\r\n </button>\r\n <div\r\n [hidden]=\"!areChildrenOpened()\"\r\n class=\"list-wrapper\"\r\n >\r\n <cui-categories-list [stageStorages]=\"stageStorageChildren()\" />\r\n @if (isCreateCategoryControlVisible()) {\r\n <cui-create-category-item\r\n class=\"create-category\"\r\n [isDisabled]=\"isSubcategoryCreationLoading()\"\r\n (created)=\"onCreateNewSubcategoryCategory($event)\"\r\n (canceled)=\"onCreatingSubcategoryCanceled()\"\r\n />\r\n }\r\n </div>\r\n</ng-container>\r\n", styles: [".category{display:flex;gap:4px;padding:2px 4px;width:100%;min-height:32px;border-radius:8px}@media (hover: hover){.category:hover{background:var(--cui-base-10)}}.category:active{background:var(--cui-base-10)}.category__open-close-button{padding:2px;border-radius:4px;margin:4px 0}@media (hover: hover){.category__open-close-button:hover{background:var(--cui-base-100)}}.category__open-close-button:active{background:var(--cui-base-100)}.category__open-close-button_hidden{visibility:hidden}.category__title{flex:1;text-align:start;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.category__add-subcategory-button{--cui-base-50: var(--cui-base-200)}.list-wrapper{padding-left:8px}.create-category{margin-left:24px}.icon{padding-right:2px;padding-left:2px;height:28px}\n"], dependencies: [{ kind: "ngmodule", type: i0.forwardRef(() => CuiButtonModule) }, { kind: "component", type: i0.forwardRef(() => CuiButtonComponent), selector: "button[cuiButton], a[cuiButton]", inputs: ["shape", "disabled", "isLoaderShown", "icon", "iconRight", "appearance", "size"] }, { kind: "ngmodule", type: i0.forwardRef(() => CuiIconButtonModule) }, { kind: "directive", type: i0.forwardRef(() => CuiLetDirective), selector: "[cuiLet]", inputs: ["cuiLet"] }, { kind: "ngmodule", type: i0.forwardRef(() => CuiSvgModule) }, { kind: "component", type: i0.forwardRef(() => CuiSvgComponent), selector: "cui-svg[icon]", inputs: ["width", "height", "strokeWidth", "color", "icon"] }, { kind: "component", type: i0.forwardRef(() => CuiCategoryFormComponent), selector: "cui-category-form", inputs: ["isDisabled", "defaultTitle"], outputs: ["created", "canceled"] }, { kind: "component", type: i0.forwardRef(() => CuiCreateCategoryItemComponent), selector: "cui-create-category-item", inputs: ["isDisabled"], outputs: ["created", "canceled"] }, { kind: "component", type: i0.forwardRef(() => CuiCategoriesListComponent), selector: "cui-categories-list", inputs: ["stageStorages"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7917
+ }
7918
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiCategoryItemComponent, decorators: [{
7919
+ type: Component,
7920
+ args: [{ selector: 'cui-category-item', imports: [
7921
+ CuiButtonModule,
7922
+ CuiIconButtonModule,
7923
+ CuiLetDirective,
7924
+ CuiSvgModule,
7925
+ CuiCategoryFormComponent,
7926
+ CuiCreateCategoryItemComponent,
7927
+ forwardRef(() => CuiCategoriesListComponent)
7928
+ ], standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *cuiLet=\"category() as stage\">\r\n <button\r\n type=\"button\"\r\n [style.align-items]=\"alignItems()\"\r\n [disabled]=\"isStageCreationLoading()\"\r\n class=\"category\"\r\n (click)=\"onSelectCategory()\"\r\n >\r\n <button\r\n type=\"button\"\r\n ccFlexContainerDirective\r\n class=\"category__open-close-button\"\r\n [class.category__open-close-button_hidden]=\"isOpenCloseButtonHidden()\"\r\n (click)=\"onToggleChildren($event)\"\r\n >\r\n <cui-svg\r\n [icon]=\"openCloseButtonIcon()\"\r\n color=\"var(--cui-base-500)\"\r\n />\r\n </button>\r\n <cui-svg\r\n [icon]=\"stageStorageIcon()\"\r\n color=\"var(--cui-base-500)\"\r\n class=\"icon\"\r\n />\r\n @if (isTitleEdit()) {\r\n <cui-category-form\r\n [defaultTitle]=\"stage.title\"\r\n (created)=\"onTitleChanged($event)\"\r\n (canceled)=\"onCancelTitleEdit()\"\r\n />\r\n } @else {\r\n <span class=\"category__title\">{{ stage.title }}</span>\r\n\r\n <button\r\n cuiButton\r\n type=\"button\"\r\n appearance=\"ghost\"\r\n size=\"xxs\"\r\n icon=\"cuiIconEdit\"\r\n class=\"category__add-subcategory-button\"\r\n (click)=\"onStartTitleEdit($event)\"\r\n ></button>\r\n <button\r\n cuiButton\r\n type=\"button\"\r\n appearance=\"ghost\"\r\n size=\"xxs\"\r\n icon=\"cuiIconPlus\"\r\n class=\"category__add-subcategory-button\"\r\n (click)=\"onStartCreatingSubcategory($event)\"\r\n ></button>\r\n }\r\n </button>\r\n <div\r\n [hidden]=\"!areChildrenOpened()\"\r\n class=\"list-wrapper\"\r\n >\r\n <cui-categories-list [stageStorages]=\"stageStorageChildren()\" />\r\n @if (isCreateCategoryControlVisible()) {\r\n <cui-create-category-item\r\n class=\"create-category\"\r\n [isDisabled]=\"isSubcategoryCreationLoading()\"\r\n (created)=\"onCreateNewSubcategoryCategory($event)\"\r\n (canceled)=\"onCreatingSubcategoryCanceled()\"\r\n />\r\n }\r\n </div>\r\n</ng-container>\r\n", styles: [".category{display:flex;gap:4px;padding:2px 4px;width:100%;min-height:32px;border-radius:8px}@media (hover: hover){.category:hover{background:var(--cui-base-10)}}.category:active{background:var(--cui-base-10)}.category__open-close-button{padding:2px;border-radius:4px;margin:4px 0}@media (hover: hover){.category__open-close-button:hover{background:var(--cui-base-100)}}.category__open-close-button:active{background:var(--cui-base-100)}.category__open-close-button_hidden{visibility:hidden}.category__title{flex:1;text-align:start;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.category__add-subcategory-button{--cui-base-50: var(--cui-base-200)}.list-wrapper{padding-left:8px}.create-category{margin-left:24px}.icon{padding-right:2px;padding-left:2px;height:28px}\n"] }]
7929
+ }], ctorParameters: () => [] });
7930
+
7931
+ class CuiCategoriesListComponent {
7932
+ constructor() {
7933
+ this.stageStorages = input.required();
7934
+ }
7935
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiCategoriesListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7936
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: CuiCategoriesListComponent, isStandalone: true, selector: "cui-categories-list", inputs: { stageStorages: { classPropertyName: "stageStorages", publicName: "stageStorages", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "@for (stageStorage of stageStorages(); track stageStorage.id) {\r\n <cui-category-item [stageStorage]=\"stageStorage\" />\r\n}\r\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: i0.forwardRef(() => CuiIconButtonModule) }, { kind: "ngmodule", type: i0.forwardRef(() => CuiSvgModule) }, { kind: "component", type: i0.forwardRef(() => CuiCategoryItemComponent), selector: "cui-category-item", inputs: ["stageStorage"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7937
+ }
7938
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiCategoriesListComponent, decorators: [{
7939
+ type: Component,
7940
+ args: [{ selector: 'cui-categories-list', imports: [CuiIconButtonModule, CuiSvgModule, forwardRef(() => CuiCategoryItemComponent)], standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "@for (stageStorage of stageStorages(); track stageStorage.id) {\r\n <cui-category-item [stageStorage]=\"stageStorage\" />\r\n}\r\n", styles: [":host{display:block}\n"] }]
7941
+ }] });
7942
+
7943
+ class CuiCategoriesComponent {
7944
+ constructor() {
7945
+ this.treeStructNavigatorApiService = inject(CuiTreeStructNavigatorApiService);
7946
+ this.selectedCategoryService = inject(CuiSelectedCategoryService);
7947
+ this.stageStorages = signal(null);
7948
+ this.isCategoryCreating = signal(false);
7949
+ this.isCategoryCreationLoading = signal(false);
7950
+ this.isCreateCategoryControlVisible = computed(() => (this.selectedCategoryService.creatingId() === this.treeStructType() && this.isCategoryCreating()) ||
7951
+ this.isCategoryCreationLoading());
7952
+ this.dropdown = viewChild.required('dropdown');
7953
+ this.treeStructType = input.required();
7954
+ this.buttonId = input();
7955
+ this.disabled = input(false, { transform: booleanAttribute });
7956
+ this.initSelectCategoryEffect();
7957
+ }
7958
+ onOpenStageStorages() {
7959
+ this.selectedCategoryService.clearCreatingId();
7960
+ this.selectedCategoryService.clearEditingId();
7961
+ if (this.stageStorages()?.length) {
7962
+ return;
7963
+ }
7964
+ this.treeStructNavigatorApiService.getStageStorages(this.treeStructType()).subscribe((stageStorage) => {
7965
+ this.stageStorages.update((prevStageStorages) => prevStageStorages ? [...prevStageStorages, stageStorage] : [stageStorage]);
7966
+ });
7967
+ }
7968
+ onStartCreatingNewCategory() {
7969
+ this.isCategoryCreating.set(true);
7970
+ this.selectedCategoryService.setCreatingId(this.treeStructType());
7971
+ }
7972
+ onCreateNewCategory(title) {
7973
+ this.isCategoryCreating.set(false);
7974
+ this.selectedCategoryService.clearCreatingId();
7975
+ this.isCategoryCreationLoading.set(true);
7976
+ this.treeStructNavigatorApiService
7977
+ .createStageStorage(title, this.treeStructType())
7978
+ .pipe(finalize(this.isCategoryCreationLoading.set.bind(this, false)))
7979
+ .subscribe((stateStorage) => this.stageStorages.update((value) => [...(value || []), stateStorage]));
7980
+ }
7981
+ onCreatingCategoryCanceled() {
7982
+ this.isCategoryCreating.set(false);
7983
+ this.selectedCategoryService.clearCreatingId();
7984
+ }
7985
+ initSelectCategoryEffect() {
7986
+ effect(() => {
7987
+ this.selectedCategoryService.category();
7988
+ this.dropdown().close();
7989
+ }, { allowSignalWrites: true });
7990
+ }
7991
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiCategoriesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7992
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: CuiCategoriesComponent, isStandalone: true, selector: "cui-categories", inputs: { treeStructType: { classPropertyName: "treeStructType", publicName: "treeStructType", isSignal: true, isRequired: true, transformFunction: null }, buttonId: { classPropertyName: "buttonId", publicName: "buttonId", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "dropdown", first: true, predicate: ["dropdown"], descendants: true, isSignal: true }], ngImport: i0, template: "<button\r\n [attr.id]=\"buttonId()\"\r\n #dropdown=\"cuiDropdown\"\r\n [cuiDropdown]=\"dropdownContent\"\r\n orientation=\"stretch\"\r\n type=\"button\"\r\n class=\"target\"\r\n [disabled]=\"disabled()\"\r\n (click)=\"onOpenStageStorages()\"\r\n>\r\n <ng-content />\r\n</button>\r\n\r\n<ng-template #dropdownContent>\r\n <cui-dropdown-wrapper\r\n *transloco=\"let t\"\r\n [title]=\"t('SELECT_OR_CREATE_CATEGORY')\"\r\n width=\"100%\"\r\n class=\"dropdown-wrapper\"\r\n >\r\n <ng-container *cuiLet=\"stageStorages() as stageStorages\">\r\n @if (stageStorages && stageStorages?.length) {\r\n <cui-categories-list [stageStorages]=\"stageStorages\" />\r\n }\r\n @if (isCreateCategoryControlVisible()) {\r\n <cui-create-category-item\r\n class=\"create-category\"\r\n [isDisabled]=\"isCategoryCreationLoading()\"\r\n (created)=\"onCreateNewCategory($event)\"\r\n (canceled)=\"onCreatingCategoryCanceled()\"\r\n />\r\n } @else if (!stageStorages?.length) {\r\n <cui-empty-state\r\n class=\"empty\"\r\n [subtitle]=\"t('NO_CATEGORY_TO_VIEW_YET')\"\r\n />\r\n }\r\n </ng-container>\r\n <button\r\n ccDropdownFooterContent\r\n cuiButton\r\n type=\"button\"\r\n appearance=\"ghost\"\r\n size=\"xxs\"\r\n icon=\"cuiIconPlus\"\r\n (click)=\"onStartCreatingNewCategory()\"\r\n >\r\n {{ t('NEW_CATEGORY') }}\r\n </button>\r\n </cui-dropdown-wrapper>\r\n</ng-template>\r\n", styles: ["::ng-deep .dropdown-wrapper .scrollable-content{flex:1;display:flex;flex-direction:column}.target{display:block;padding:0;width:100%;border-radius:8px;border:1px solid transparent}.target:focus{box-shadow:0 0 0 2px var(--cui-focus);border:1px solid var(--cui-info)}.target:disabled{cursor:default}.create-category{margin-left:24px}.empty{margin:auto}.dropdown-wrapper{display:block;height:350px}\n"], dependencies: [{ kind: "ngmodule", type: CuiButtonModule }, { kind: "component", type: CuiButtonComponent, selector: "button[cuiButton], a[cuiButton]", inputs: ["shape", "disabled", "isLoaderShown", "icon", "iconRight", "appearance", "size"] }, { kind: "directive", type: CuiLetDirective, selector: "[cuiLet]", inputs: ["cuiLet"] }, { kind: "directive", type: CuiDropdownDirective, selector: "[cuiDropdown]", inputs: ["cuiDropdown", "orientation"], outputs: ["isOpened"], exportAs: ["cuiDropdown"] }, { kind: "component", type: CuiDropdownWrapperComponent, selector: "cui-dropdown-wrapper", inputs: ["title", "width"] }, { kind: "component", type: CuiEmptyStateComponent, selector: "cui-empty-state, [cuiEmptyState]", inputs: ["title", "subtitle"] }, { kind: "component", type: CuiCreateCategoryItemComponent, selector: "cui-create-category-item", inputs: ["isDisabled"], outputs: ["created", "canceled"] }, { kind: "component", type: CuiCategoriesListComponent, selector: "cui-categories-list", inputs: ["stageStorages"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7993
+ }
7994
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CuiCategoriesComponent, decorators: [{
7995
+ type: Component,
7996
+ args: [{ selector: 'cui-categories', imports: [
7997
+ CuiButtonModule,
7998
+ CuiLetDirective,
7999
+ CuiDropdownDirective,
8000
+ CuiDropdownWrapperComponent,
8001
+ CuiEmptyStateComponent,
8002
+ CuiCreateCategoryItemComponent,
8003
+ CuiCategoriesListComponent,
8004
+ TranslocoDirective
8005
+ ], standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<button\r\n [attr.id]=\"buttonId()\"\r\n #dropdown=\"cuiDropdown\"\r\n [cuiDropdown]=\"dropdownContent\"\r\n orientation=\"stretch\"\r\n type=\"button\"\r\n class=\"target\"\r\n [disabled]=\"disabled()\"\r\n (click)=\"onOpenStageStorages()\"\r\n>\r\n <ng-content />\r\n</button>\r\n\r\n<ng-template #dropdownContent>\r\n <cui-dropdown-wrapper\r\n *transloco=\"let t\"\r\n [title]=\"t('SELECT_OR_CREATE_CATEGORY')\"\r\n width=\"100%\"\r\n class=\"dropdown-wrapper\"\r\n >\r\n <ng-container *cuiLet=\"stageStorages() as stageStorages\">\r\n @if (stageStorages && stageStorages?.length) {\r\n <cui-categories-list [stageStorages]=\"stageStorages\" />\r\n }\r\n @if (isCreateCategoryControlVisible()) {\r\n <cui-create-category-item\r\n class=\"create-category\"\r\n [isDisabled]=\"isCategoryCreationLoading()\"\r\n (created)=\"onCreateNewCategory($event)\"\r\n (canceled)=\"onCreatingCategoryCanceled()\"\r\n />\r\n } @else if (!stageStorages?.length) {\r\n <cui-empty-state\r\n class=\"empty\"\r\n [subtitle]=\"t('NO_CATEGORY_TO_VIEW_YET')\"\r\n />\r\n }\r\n </ng-container>\r\n <button\r\n ccDropdownFooterContent\r\n cuiButton\r\n type=\"button\"\r\n appearance=\"ghost\"\r\n size=\"xxs\"\r\n icon=\"cuiIconPlus\"\r\n (click)=\"onStartCreatingNewCategory()\"\r\n >\r\n {{ t('NEW_CATEGORY') }}\r\n </button>\r\n </cui-dropdown-wrapper>\r\n</ng-template>\r\n", styles: ["::ng-deep .dropdown-wrapper .scrollable-content{flex:1;display:flex;flex-direction:column}.target{display:block;padding:0;width:100%;border-radius:8px;border:1px solid transparent}.target:focus{box-shadow:0 0 0 2px var(--cui-focus);border:1px solid var(--cui-info)}.target:disabled{cursor:default}.create-category{margin-left:24px}.empty{margin:auto}.dropdown-wrapper{display:block;height:350px}\n"] }]
8006
+ }], ctorParameters: () => [] });
4005
8007
 
4006
8008
  /**
4007
8009
  * Generated bundle index. Do not edit.
4008
8010
  */
4009
8011
 
4010
- export { AngularOutsideLoaderService, CUI_ALERTS, CUI_ALERT_CONTEXT, CUI_ALERT_DEFAULT_OPTIONS, CUI_ALERT_OPTIONS, CUI_ANIMATIONS_DEFAULT_DURATION, CUI_BANNER_DEFAULT_OPTIONS, CUI_BANNER_OPTIONS, CUI_BUTTON_DEFAULT_OPTIONS, CUI_BUTTON_OPTIONS, CUI_DEFAULT_THEME, CUI_DIALOGS, CUI_DIALOG_CONTEXT, CUI_DIALOG_DEFAULT_OPTIONS, CUI_DIALOG_OPTIONS, CUI_INPUT_TIME_DEFAULT_OPTIONS, CUI_INPUT_TIME_OPTIONS, CUI_NOTIFICATION_DEFAULT_OPTIONS, CUI_NOTIFICATION_ICONS, CUI_NOTIFICATION_ICON_OPTIONS, CUI_NOTIFICATION_ICON_OPTIONS_DEFAULT_MODE, CUI_NOTIFICATION_ICON_OPTIONS_LIGHT_MODE, CUI_NOTIFICATION_OPTIONS, CUI_ROOT_SELECTOR, CUI_TAB_ACTIVATE, CUI_TEXT_FIELD_CONTROLLER, CUI_TEXT_FIELD_ICON_LEFT, CUI_TEXT_FIELD_ID, CUI_TEXT_FIELD_IS_ERROR, CUI_TEXT_FIELD_PLACEHOLDER, CUI_TEXT_FIELD_SIZE, CUI_TEXT_FILED_CONTROLLER_PROVIDER, CUI_THEME, CUI_THEME_STORAGE_DEFAULT_KEY, CUI_THEME_STORAGE_KEY, CUI_TOOLTIP_COMPONENT, CUI_TOOLTIP_DEFAULT_OPTIONS, CUI_TOOLTIP_DIRECTIONS, CUI_TOOLTIP_OPTIONS, CUI_TOOLTIP_PROVIDERS, CuiAccordionComponent, CuiAccordionDirective, CuiAccordionItemComponent, CuiAccordionModule, CuiAlertComponent, CuiAlertModule, CuiAlertService, CuiAlertsComponent, CuiBadgeComponent, CuiBadgeModule, CuiBannerComponent, CuiBannerModule, CuiBreadcrumbComponent, CuiBreadcrumbsComponent, CuiBreadcrumbsModule, CuiButtonComponent, CuiButtonGroupComponent, CuiButtonGroupModule, CuiButtonModule, CuiCardWrapperComponent, CuiCheckboxComponent, CuiCheckboxModule, CuiContextMenuComponent, CuiContextMenuModule, CuiDialogActionsComponent, CuiDialogComponent, CuiDialogHeaderComponent, CuiDialogModule, CuiDialogService, CuiDialogsComponent, CuiDropdownDirective, CuiDropdownWrapperComponent, CuiFormFieldComponent, CuiFormFieldModule, CuiHintComponent, CuiHintModule, CuiIconButtonComponent, CuiIconButtonModule, CuiInputModule, CuiInputNumberComponent, CuiInputNumberModule, CuiInputPasswordComponent, CuiInputPasswordModule, CuiInputTextComponent, CuiInputTimeComponent, CuiInputTimeModule, CuiLabelComponent, CuiLabelModule, CuiLayoutComponent, CuiLetterBoxComponent, CuiNotificationComponent, CuiNotificationModule, CuiPositionService, CuiRadioComponent, CuiRadioModule, CuiRenderDynamicComponentsComponent, CuiRenderDynamicComponentsService, CuiRootComponent, CuiRootModule, CuiSelectComponent, CuiSelectModule, CuiSidebarContainerComponent, CuiSidebarHeaderComponent, CuiSidebarNavigationComponent, CuiSidebarNavigationContainerComponent, CuiSidebarNavigationItemComponent, CuiSidebarService, CuiSvgComponent, CuiSvgModule, CuiTabComponent, CuiTabsComponent, CuiTabsModule, CuiTextFieldController, CuiTextFieldControllerModule, CuiTextFieldIconLeftDirective, CuiTextFieldIdDirective, CuiTextFieldIsErrorDirective, CuiTextFieldPlaceholderDirective, CuiTextFieldSizeDirective, CuiTextareaComponent, CuiTextareaModule, CuiThemeService, CuiToggleComponent, CuiToggleModule, CuiTooltip, CuiTooltipComponent, CuiTooltipDescribe, CuiTooltipDirective, CuiTooltipDriver, CuiTooltipHost, CuiTooltipHover, CuiTooltipManual, CuiTooltipOptionsDirective, CuiTooltipOverflow, CuiTooltipPointer, CuiTooltipPosition, CuiTooltipService, CuiTooltipUnstyled, CuiTooltipUnstyledComponent, CuiTooltips, CuiVisualViewportService, LoaderService, LoadingState, cuiGetDuration, cuiIsObscured, cuiLoaderInterceptor, cuiOverrideOptions, cuiRemoveSpaces, cuiReplace, cuiToAnimationOptions, cuiTooltipOptionsProvider, cuiXNdjsonInterceptor };
8012
+ export { AngularOutsideLoaderService, CUI_ALERTS, CUI_ALERT_CONTEXT, CUI_ALERT_DEFAULT_OPTIONS, CUI_ALERT_OPTIONS, CUI_ANIMATIONS_DEFAULT_DURATION, CUI_BANNER_DEFAULT_OPTIONS, CUI_BANNER_OPTIONS, CUI_BUTTON_DEFAULT_OPTIONS, CUI_BUTTON_OPTIONS, CUI_DEFAULT_THEME, CUI_DIALOGS, CUI_DIALOG_CONTEXT, CUI_DIALOG_DEFAULT_OPTIONS, CUI_DIALOG_OPTIONS, CUI_INPUT_TIME_DEFAULT_OPTIONS, CUI_INPUT_TIME_OPTIONS, CUI_NOTIFICATION_DEFAULT_OPTIONS, CUI_NOTIFICATION_ICONS, CUI_NOTIFICATION_ICON_OPTIONS, CUI_NOTIFICATION_ICON_OPTIONS_DEFAULT_MODE, CUI_NOTIFICATION_ICON_OPTIONS_LIGHT_MODE, CUI_NOTIFICATION_OPTIONS, CUI_ROOT_SELECTOR, CUI_TAB_ACTIVATE, CUI_TEXT_FIELD_CONTROLLER, CUI_TEXT_FIELD_ICON_LEFT, CUI_TEXT_FIELD_ID, CUI_TEXT_FIELD_IS_ERROR, CUI_TEXT_FIELD_PLACEHOLDER, CUI_TEXT_FIELD_SIZE, CUI_TEXT_FILED_CONTROLLER_PROVIDER, CUI_THEME, CUI_THEME_STORAGE_DEFAULT_KEY, CUI_THEME_STORAGE_KEY, CUI_TOOLTIP_COMPONENT, CUI_TOOLTIP_DEFAULT_OPTIONS, CUI_TOOLTIP_DIRECTIONS, CUI_TOOLTIP_OPTIONS, CUI_TOOLTIP_PROVIDERS, CuiAccordionComponent, CuiAccordionDirective, CuiAccordionItemComponent, CuiAccordionModule, CuiAlertComponent, CuiAlertModule, CuiAlertService, CuiAlertsComponent, CuiAttachesTool, CuiBadgeComponent, CuiBadgeModule, CuiBannerComponent, CuiBannerModule, CuiBreadcrumbComponent, CuiBreadcrumbsComponent, CuiBreadcrumbsModule, CuiButtonComponent, CuiButtonGroupComponent, CuiButtonGroupModule, CuiButtonModule, CuiCardWrapperComponent, CuiCategoriesComponent, CuiCheckboxComponent, CuiCheckboxModule, CuiContentWrapperComponent, CuiContextMenuComponent, CuiContextMenuModule, CuiDialogActionsComponent, CuiDialogComponent, CuiDialogHeaderComponent, CuiDialogModule, CuiDialogService, CuiDialogsComponent, CuiDropdownDirective, CuiDropdownWrapperComponent, CuiEditorBlockComponent, CuiEditorComponent, CuiEditorModalComponent, CuiEditorReadonlyComponent, CuiEditorTranslations, CuiEmptyStateComponent, CuiFileUploaderStatus, CuiFormFieldComponent, CuiFormFieldModule, CuiGhostInputComponent, CuiHeaderTool, CuiHintComponent, CuiHintModule, CuiIconButtonComponent, CuiIconButtonModule, CuiImageTool, CuiInputModule, CuiInputNumberComponent, CuiInputNumberModule, CuiInputPasswordComponent, CuiInputPasswordModule, CuiInputTextComponent, CuiInputTimeComponent, CuiInputTimeModule, CuiLabelComponent, CuiLabelModule, CuiLayoutComponent, CuiLetterBoxComponent, CuiLinkMarker, CuiListTool, CuiLoaderService, CuiLoadingState, CuiNotificationComponent, CuiNotificationModule, CuiPositionService, CuiRadioComponent, CuiRadioModule, CuiRenderDynamicComponentsComponent, CuiRenderDynamicComponentsService, CuiRoleMarker, CuiRootComponent, CuiRootModule, CuiSelectComponent, CuiSelectModule, CuiSelectedCategoryService, CuiSidebarContainerComponent, CuiSidebarHeaderComponent, CuiSidebarNavigationComponent, CuiSidebarNavigationContainerComponent, CuiSidebarNavigationItemComponent, CuiSidebarService, CuiSvgComponent, CuiSvgModule, CuiTabComponent, CuiTabsComponent, CuiTabsModule, CuiTextFieldController, CuiTextFieldControllerModule, CuiTextFieldIconLeftDirective, CuiTextFieldIdDirective, CuiTextFieldIsErrorDirective, CuiTextFieldPlaceholderDirective, CuiTextFieldSizeDirective, CuiTextareaComponent, CuiTextareaModule, CuiThemeService, CuiToggleComponent, CuiToggleModule, CuiToolMarker, CuiTooltip, CuiTooltipComponent, CuiTooltipDescribe, CuiTooltipDirective, CuiTooltipDriver, CuiTooltipHost, CuiTooltipHover, CuiTooltipManual, CuiTooltipOptionsDirective, CuiTooltipOverflow, CuiTooltipPointer, CuiTooltipPosition, CuiTooltipService, CuiTooltipUnstyled, CuiTooltipUnstyledComponent, CuiTooltips, CuiUtilityInfoComponent, CuiVideoTool, CuiVisualViewportService, createDefaultValidators, cuiGetDuration, cuiIsObscured, cuiLoaderInterceptor, cuiOverrideOptions, cuiProvideEditor, cuiRemoveSpaces, cuiReplace, cuiToAnimationOptions, cuiTooltipOptionsProvider, cuiXNdjsonInterceptor };
4011
8013
  //# sourceMappingURL=cuby-ui-core.mjs.map