@prolibu-suite/cobalt-core 0.2.0 → 0.3.0

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 (590) hide show
  1. package/custom-elements.json +15675 -11199
  2. package/dist/cjs/co-accordion.cjs.entry.js +3 -3
  3. package/dist/cjs/co-app-shell.cjs.entry.js +4 -4
  4. package/dist/cjs/co-autocomplete.cjs.entry.js +10 -7
  5. package/dist/cjs/co-avatar-group.cjs.entry.js +77 -0
  6. package/dist/cjs/co-avatar.cjs.entry.js +6 -4
  7. package/dist/cjs/co-badge.cjs.entry.js +2 -2
  8. package/dist/cjs/co-bottom-sheet.cjs.entry.js +325 -0
  9. package/dist/cjs/co-button-group.cjs.entry.js +3 -3
  10. package/dist/cjs/co-button.cjs.entry.js +6 -6
  11. package/dist/cjs/co-calendar-month.cjs.entry.js +381 -0
  12. package/dist/cjs/co-calendar_3.cjs.entry.js +11 -11
  13. package/dist/cjs/co-card.cjs.entry.js +3 -3
  14. package/dist/cjs/co-checkbox-group.cjs.entry.js +5 -5
  15. package/dist/cjs/co-checkbox.cjs.entry.js +5 -5
  16. package/dist/cjs/co-chip.cjs.entry.js +11 -8
  17. package/dist/cjs/co-color-picker.cjs.entry.js +7 -5
  18. package/dist/cjs/co-column-picker.cjs.entry.js +3 -3
  19. package/dist/cjs/co-combobox.cjs.entry.js +7 -7
  20. package/dist/cjs/co-command-search.cjs.entry.js +151 -12
  21. package/dist/cjs/co-data-table-pagination.cjs.entry.js +5 -5
  22. package/dist/cjs/co-data-table.cjs.entry.js +25 -11
  23. package/dist/cjs/co-date-picker.cjs.entry.js +2 -2
  24. package/dist/cjs/co-date-range-picker.cjs.entry.js +3 -3
  25. package/dist/cjs/co-date-range.cjs.entry.js +2 -2
  26. package/dist/cjs/co-empty-state.cjs.entry.js +2 -2
  27. package/dist/cjs/co-event-calendar.cjs.entry.js +318 -0
  28. package/dist/cjs/co-fab.cjs.entry.js +3 -3
  29. package/dist/cjs/co-file-field.cjs.entry.js +8 -8
  30. package/dist/cjs/co-helper-text.cjs.entry.js +3 -3
  31. package/dist/cjs/co-icon-button.cjs.entry.js +5 -5
  32. package/dist/cjs/co-icon.cjs.entry.js +33 -25
  33. package/dist/cjs/co-input.cjs.entry.js +6 -6
  34. package/dist/cjs/co-json-field.cjs.entry.js +10 -6
  35. package/dist/cjs/co-lightbox.cjs.entry.js +5 -5
  36. package/dist/cjs/co-list-footer.cjs.entry.js +25 -0
  37. package/dist/cjs/co-list-item.cjs.entry.js +60 -4
  38. package/dist/cjs/co-loader_2.cjs.entry.js +293 -0
  39. package/dist/cjs/co-menu-divider.cjs.entry.js +2 -2
  40. package/dist/cjs/co-menu-item.cjs.entry.js +17 -10
  41. package/dist/cjs/co-menu.cjs.entry.js +2 -2
  42. package/dist/cjs/co-modal.cjs.entry.js +16 -4
  43. package/dist/cjs/co-navbar.cjs.entry.js +3 -3
  44. package/dist/cjs/co-number-field.cjs.entry.js +18 -6
  45. package/dist/cjs/co-page-header.cjs.entry.js +2 -2
  46. package/dist/cjs/co-phone-field.cjs.entry.js +6 -4
  47. package/dist/cjs/co-popover.cjs.entry.js +45 -14
  48. package/dist/cjs/co-progress-bar.cjs.entry.js +8 -4
  49. package/dist/cjs/co-progress-circle.cjs.entry.js +3 -3
  50. package/dist/cjs/co-radio-group.cjs.entry.js +4 -4
  51. package/dist/cjs/co-radio.cjs.entry.js +4 -4
  52. package/dist/cjs/co-rating.cjs.entry.js +4 -4
  53. package/dist/cjs/co-ref-field.cjs.entry.js +36 -13
  54. package/dist/cjs/co-rich-text-editor.cjs.entry.js +1879 -33
  55. package/dist/cjs/co-rich-text-toolbar.cjs.entry.js +995 -71
  56. package/dist/cjs/co-rich-text-viewer.cjs.entry.js +55 -19
  57. package/dist/cjs/co-row.cjs.entry.js +3 -3
  58. package/dist/cjs/co-select.cjs.entry.js +8 -8
  59. package/dist/cjs/co-separator.cjs.entry.js +2 -2
  60. package/dist/cjs/co-sidebar-nav.cjs.entry.js +29 -9
  61. package/dist/cjs/co-sidebar.cjs.entry.js +3 -3
  62. package/dist/cjs/co-skeleton.cjs.entry.js +26 -0
  63. package/dist/cjs/co-slider.cjs.entry.js +3 -3
  64. package/dist/cjs/co-switch.cjs.entry.js +6 -6
  65. package/dist/cjs/co-tab-group.cjs.entry.js +2 -2
  66. package/dist/cjs/co-tab.cjs.entry.js +3 -3
  67. package/dist/cjs/co-tags-field.cjs.entry.js +19 -13
  68. package/dist/cjs/co-textarea.cjs.entry.js +11 -7
  69. package/dist/cjs/co-toast.cjs.entry.js +2 -2
  70. package/dist/cjs/co-toggle-button-group.cjs.entry.js +4 -4
  71. package/dist/cjs/co-toggle-button.cjs.entry.js +4 -4
  72. package/dist/cjs/co-tooltip.cjs.entry.js +51 -16
  73. package/dist/cjs/co-transfer-list.cjs.entry.js +3 -3
  74. package/dist/cjs/co-video.cjs.entry.js +839 -0
  75. package/dist/cjs/cobalt.cjs.js +2 -2
  76. package/dist/cjs/fieldChip-CDIMz_Y6.js +7 -0
  77. package/dist/cjs/{index-CaEJnpZe.js → index-5NdsiFjZ.js} +14509 -6317
  78. package/dist/cjs/{index-DoFnrUVH.js → index-BumlM92r.js} +45 -21
  79. package/dist/cjs/loader.cjs.js +2 -2
  80. package/dist/cjs/overlayAfterClose-BdeXrhVY.js +12 -0
  81. package/dist/{esm/sanitizer-DcK0GGZC.js → cjs/purify.es-DX41ZWS2.js} +3 -107
  82. package/dist/cjs/{requiredMark-DA6y-4rp.js → requiredMark-CqMGt1H1.js} +1 -1
  83. package/dist/cjs/richTextI18n-B7ktXg3M.js +382 -0
  84. package/dist/cjs/toolbar-config-3PlT-3zm.js +216 -0
  85. package/dist/cjs/tz-Dgom0W69.js +127 -0
  86. package/dist/cobalt/cobalt.css +1 -1
  87. package/dist/cobalt/cobalt.esm.js +1 -1
  88. package/dist/cobalt/p-0a506c9d.entry.js +1 -0
  89. package/dist/cobalt/p-0bb55163.entry.js +1 -0
  90. package/dist/cobalt/{p-6404bd21.entry.js → p-0e8c0d87.entry.js} +1 -1
  91. package/dist/cobalt/p-12e2c2c4.entry.js +1 -0
  92. package/dist/cobalt/p-136ad468.entry.js +1 -0
  93. package/dist/cobalt/{p-654bbc2a.entry.js → p-14b59277.entry.js} +1 -1
  94. package/dist/cobalt/p-1531d3c9.entry.js +1 -0
  95. package/dist/cobalt/p-1774d211.entry.js +1 -0
  96. package/dist/cobalt/p-180e1106.entry.js +1 -0
  97. package/dist/cobalt/p-1a07c23c.entry.js +1 -0
  98. package/dist/cobalt/p-1dc9c49e.entry.js +1 -0
  99. package/dist/cobalt/p-1f747e45.entry.js +1 -0
  100. package/dist/cobalt/p-201eaf35.entry.js +1 -0
  101. package/dist/cobalt/p-260101ab.entry.js +1 -0
  102. package/dist/cobalt/p-279bf91c.entry.js +1 -0
  103. package/dist/cobalt/p-29be61a9.entry.js +1 -0
  104. package/dist/cobalt/p-2d2ce434.entry.js +1 -0
  105. package/dist/cobalt/{p-aa63812a.entry.js → p-2f86e1e0.entry.js} +1 -1
  106. package/dist/cobalt/{p-522fcdb7.entry.js → p-31ab9a46.entry.js} +1 -1
  107. package/dist/cobalt/{p-fe9e85b6.entry.js → p-37595103.entry.js} +1 -1
  108. package/dist/cobalt/{p-def448e4.entry.js → p-377c2ccc.entry.js} +1 -1
  109. package/dist/cobalt/p-3863ea91.entry.js +1 -0
  110. package/dist/cobalt/p-3a257cb0.entry.js +1 -0
  111. package/dist/cobalt/p-3e187456.entry.js +1 -0
  112. package/dist/cobalt/{p-5d01bd4d.entry.js → p-4431faac.entry.js} +1 -1
  113. package/dist/cobalt/{p-54f26e95.entry.js → p-4504f7b0.entry.js} +1 -1
  114. package/dist/cobalt/{p-f8728b21.entry.js → p-456fa86f.entry.js} +1 -1
  115. package/dist/cobalt/{p-3f9b3fcb.entry.js → p-4871690e.entry.js} +1 -1
  116. package/dist/cobalt/{p-d17e1444.entry.js → p-4c01d984.entry.js} +1 -1
  117. package/dist/cobalt/p-51a53177.entry.js +1 -0
  118. package/dist/cobalt/p-52de17da.entry.js +1 -0
  119. package/dist/cobalt/p-5890e4d1.entry.js +1 -0
  120. package/dist/cobalt/{p-f2c5cb74.entry.js → p-58a53421.entry.js} +1 -1
  121. package/dist/cobalt/p-62274eba.entry.js +1 -0
  122. package/dist/cobalt/p-635b03d5.entry.js +1 -0
  123. package/dist/cobalt/p-64ddee92.entry.js +1 -0
  124. package/dist/cobalt/p-65af5017.entry.js +1 -0
  125. package/dist/cobalt/p-69d4c0c8.entry.js +1 -0
  126. package/dist/cobalt/p-6c480916.entry.js +1 -0
  127. package/dist/cobalt/p-6d1217c3.entry.js +1 -0
  128. package/dist/cobalt/{p-f0e8fa7d.entry.js → p-6e808b3a.entry.js} +1 -1
  129. package/dist/cobalt/{p-f97ad9ad.entry.js → p-70b14b05.entry.js} +1 -1
  130. package/dist/cobalt/{p-97c20011.entry.js → p-790d384e.entry.js} +1 -1
  131. package/dist/cobalt/p-8012e152.entry.js +1 -0
  132. package/dist/cobalt/p-80b27203.entry.js +1 -0
  133. package/dist/cobalt/p-867c1465.entry.js +1 -0
  134. package/dist/cobalt/p-86a143d7.entry.js +1 -0
  135. package/dist/cobalt/{p-e8b58332.entry.js → p-8d59f5ad.entry.js} +1 -1
  136. package/dist/cobalt/p-8d7fdb9d.entry.js +1 -0
  137. package/dist/cobalt/{p-7f818368.entry.js → p-8dc1dab8.entry.js} +1 -1
  138. package/dist/cobalt/{p-beb9c11d.entry.js → p-8e1dc062.entry.js} +1 -1
  139. package/dist/cobalt/p-929e647f.entry.js +1 -0
  140. package/dist/cobalt/p-92bd9b29.entry.js +1 -0
  141. package/dist/cobalt/p-93046365.entry.js +1 -0
  142. package/dist/cobalt/p-98ab5f3f.entry.js +1 -0
  143. package/dist/cobalt/{p-c87285b6.entry.js → p-9a04ca90.entry.js} +1 -1
  144. package/dist/cobalt/{p-7ef766c6.entry.js → p-9a088515.entry.js} +1 -1
  145. package/dist/cobalt/p-9abbd436.entry.js +1 -0
  146. package/dist/cobalt/p-9d69c067.entry.js +1 -0
  147. package/dist/cobalt/p-B-ckjCUA.js +1 -0
  148. package/dist/cobalt/p-B2QLgWrz.js +2 -0
  149. package/dist/cobalt/p-B6JZk8fL.js +1 -0
  150. package/dist/cobalt/p-BZJ7NCm5.js +1 -0
  151. package/dist/cobalt/p-CYsftTKf.js +2 -0
  152. package/dist/cobalt/p-CegCk7FL.js +1 -0
  153. package/dist/cobalt/p-Ch1jfwZ2.js +1 -0
  154. package/dist/cobalt/p-ChibIpZv.js +1 -0
  155. package/dist/cobalt/p-afb7e19e.entry.js +1 -0
  156. package/dist/cobalt/{p-b758c2e6.entry.js → p-b6f20268.entry.js} +1 -1
  157. package/dist/cobalt/{p-bb07da22.entry.js → p-ba90e871.entry.js} +1 -1
  158. package/dist/cobalt/p-c10697e1.entry.js +1 -0
  159. package/dist/cobalt/p-c4f59532.entry.js +1 -0
  160. package/dist/cobalt/{p-1e0282b8.entry.js → p-cb235aa7.entry.js} +1 -1
  161. package/dist/cobalt/p-cfb36943.entry.js +1 -0
  162. package/dist/cobalt/p-d809bd44.entry.js +1 -0
  163. package/dist/cobalt/p-e53861e4.entry.js +1 -0
  164. package/dist/cobalt/p-e54dd404.entry.js +1 -0
  165. package/dist/cobalt/{p-01fc77c4.entry.js → p-eb18fdbf.entry.js} +1 -1
  166. package/dist/cobalt/{p-95d14878.entry.js → p-eb73052a.entry.js} +1 -1
  167. package/dist/cobalt/{p-273afd93.entry.js → p-ef7d4ae3.entry.js} +1 -1
  168. package/dist/cobalt/p-f4063c41.entry.js +1 -0
  169. package/dist/cobalt/p-oImf-7fN.js +1 -0
  170. package/dist/cobalt/{p-CyYF8IJE.js → p-tPYikBRJ.js} +1 -1
  171. package/dist/collection/collection-manifest.json +10 -3
  172. package/dist/collection/components/co-accordion/co-accordion.js +2 -2
  173. package/dist/collection/components/co-app-shell/co-app-shell.css +79 -6
  174. package/dist/collection/components/co-app-shell/co-app-shell.js +2 -2
  175. package/dist/collection/components/co-autocomplete/co-autocomplete.css +28 -1
  176. package/dist/collection/components/co-autocomplete/co-autocomplete.js +27 -4
  177. package/dist/collection/components/co-avatar/co-avatar.css +38 -1
  178. package/dist/collection/components/co-avatar/co-avatar.js +23 -2
  179. package/dist/collection/components/co-avatar-group/co-avatar-group.css +86 -0
  180. package/dist/collection/components/co-avatar-group/co-avatar-group.js +224 -0
  181. package/dist/collection/components/co-badge/co-badge.js +1 -1
  182. package/dist/collection/components/co-bottom-sheet/co-bottom-sheet.css +136 -0
  183. package/dist/collection/components/co-bottom-sheet/co-bottom-sheet.js +507 -0
  184. package/dist/collection/components/co-button/co-button.css +40 -7
  185. package/dist/collection/components/co-button/co-button.js +26 -7
  186. package/dist/collection/components/co-button-group/co-button-group.js +2 -2
  187. package/dist/collection/components/co-calendar/co-calendar.js +1 -1
  188. package/dist/collection/components/co-calendar-month/co-calendar-month.css +231 -0
  189. package/dist/collection/components/co-calendar-month/co-calendar-month.js +594 -0
  190. package/dist/collection/components/co-card/co-card.js +2 -2
  191. package/dist/collection/components/co-checkbox/co-checkbox.css +7 -1
  192. package/dist/collection/components/co-checkbox/co-checkbox.js +3 -3
  193. package/dist/collection/components/co-checkbox-group/co-checkbox-group.css +7 -1
  194. package/dist/collection/components/co-checkbox-group/co-checkbox-group.js +3 -3
  195. package/dist/collection/components/co-chip/co-chip.css +27 -7
  196. package/dist/collection/components/co-chip/co-chip.js +52 -10
  197. package/dist/collection/components/co-color-picker/co-color-picker.css +35 -1
  198. package/dist/collection/components/co-color-picker/co-color-picker.js +24 -2
  199. package/dist/collection/components/co-column-picker/co-column-picker.js +2 -2
  200. package/dist/collection/components/co-combobox/co-combobox.css +7 -47
  201. package/dist/collection/components/co-combobox/co-combobox.js +4 -4
  202. package/dist/collection/components/co-command-search/co-command-search.css +163 -1
  203. package/dist/collection/components/co-command-search/co-command-search.js +355 -14
  204. package/dist/collection/components/co-command-search/commandSearchGroup.js +17 -0
  205. package/dist/collection/components/co-command-search/commandSearchLogic.js +27 -0
  206. package/dist/collection/components/co-data-table/co-data-table.css +37 -1
  207. package/dist/collection/components/co-data-table/co-data-table.js +25 -11
  208. package/dist/collection/components/co-data-table-pagination/co-data-table-pagination.js +4 -4
  209. package/dist/collection/components/co-date-field/co-date-field.css +7 -1
  210. package/dist/collection/components/co-date-field/co-date-field.js +4 -4
  211. package/dist/collection/components/co-date-range/co-date-range.js +1 -1
  212. package/dist/collection/components/co-date-range-picker/co-date-range-picker.css +7 -1
  213. package/dist/collection/components/co-drawer/co-drawer.css +1 -0
  214. package/dist/collection/components/co-drawer/co-drawer.js +2 -2
  215. package/dist/collection/components/co-empty-state/co-empty-state.js +1 -1
  216. package/dist/collection/components/co-event-calendar/co-event-calendar.css +146 -0
  217. package/dist/collection/components/co-event-calendar/co-event-calendar.js +620 -0
  218. package/dist/collection/components/co-fab/co-fab.js +2 -2
  219. package/dist/collection/components/co-file-field/co-file-field.css +7 -1
  220. package/dist/collection/components/co-file-field/co-file-field.js +5 -5
  221. package/dist/collection/components/co-helper-text/co-helper-text.js +2 -2
  222. package/dist/collection/components/co-icon/co-icon.js +7 -37
  223. package/dist/collection/components/co-icon/iconLoader.js +39 -0
  224. package/dist/collection/components/co-icon-button/co-icon-button.css +19 -8
  225. package/dist/collection/components/co-icon-button/co-icon-button.js +23 -4
  226. package/dist/collection/components/co-input/co-input.css +7 -1
  227. package/dist/collection/components/co-input/co-input.js +3 -3
  228. package/dist/collection/components/co-json-field/co-json-field.css +25 -1
  229. package/dist/collection/components/co-json-field/co-json-field.js +27 -3
  230. package/dist/collection/components/co-lightbox/co-lightbox.js +4 -4
  231. package/dist/collection/components/co-list-footer/co-list-footer.css +50 -0
  232. package/dist/collection/components/co-list-footer/co-list-footer.js +149 -0
  233. package/dist/collection/components/co-list-item/co-list-item.css +7 -0
  234. package/dist/collection/components/co-list-item/co-list-item.js +65 -2
  235. package/dist/collection/components/co-loader/co-loader.css +9 -0
  236. package/dist/collection/components/co-menu/co-menu.js +1 -1
  237. package/dist/collection/components/co-menu-divider/co-menu-divider.js +1 -1
  238. package/dist/collection/components/co-menu-item/co-menu-item.css +18 -0
  239. package/dist/collection/components/co-menu-item/co-menu-item.js +15 -8
  240. package/dist/collection/components/co-modal/co-modal.css +42 -2
  241. package/dist/collection/components/co-modal/co-modal.js +42 -2
  242. package/dist/collection/components/co-navbar/co-navbar.js +2 -2
  243. package/dist/collection/components/co-number-field/co-number-field.css +19 -1
  244. package/dist/collection/components/co-number-field/co-number-field.js +34 -3
  245. package/dist/collection/components/co-overlay/co-overlay.css +15 -1
  246. package/dist/collection/components/co-overlay/co-overlay.js +266 -1
  247. package/dist/collection/components/co-overlay/focusTrap.js +53 -0
  248. package/dist/collection/components/co-overlay/overlayAfterClose.js +8 -0
  249. package/dist/collection/components/co-page-header/co-page-header.js +1 -1
  250. package/dist/collection/components/co-phone-field/co-phone-field.css +30 -2
  251. package/dist/collection/components/co-phone-field/co-phone-field.js +23 -1
  252. package/dist/collection/components/co-popover/co-popover.css +9 -0
  253. package/dist/collection/components/co-popover/co-popover.js +43 -12
  254. package/dist/collection/components/co-progress-bar/co-progress-bar.css +22 -0
  255. package/dist/collection/components/co-progress-bar/co-progress-bar.js +26 -2
  256. package/dist/collection/components/co-progress-circle/co-progress-circle.js +2 -2
  257. package/dist/collection/components/co-radio/co-radio.js +3 -3
  258. package/dist/collection/components/co-radio-group/co-radio-group.js +3 -3
  259. package/dist/collection/components/co-rating/co-rating.js +3 -3
  260. package/dist/collection/components/co-ref-field/co-ref-field.css +64 -6
  261. package/dist/collection/components/co-ref-field/co-ref-field.js +0 -0
  262. package/dist/collection/components/co-rich-text-editor/co-rich-text-editor.css +1125 -41
  263. package/dist/collection/components/co-rich-text-editor/co-rich-text-editor.js +2008 -53
  264. package/dist/collection/components/co-rich-text-toolbar/co-rich-text-toolbar.css +791 -9
  265. package/dist/collection/components/co-rich-text-toolbar/co-rich-text-toolbar.js +1071 -71
  266. package/dist/collection/components/co-rich-text-viewer/co-rich-text-viewer.css +78 -0
  267. package/dist/collection/components/co-rich-text-viewer/co-rich-text-viewer.js +46 -41
  268. package/dist/collection/components/co-row/co-row.js +2 -2
  269. package/dist/collection/components/co-select/co-select.css +7 -1
  270. package/dist/collection/components/co-select/co-select.js +5 -5
  271. package/dist/collection/components/co-separator/co-separator.js +1 -1
  272. package/dist/collection/components/co-sidebar/co-sidebar.js +2 -2
  273. package/dist/collection/components/co-sidebar-nav/co-sidebar-nav.css +99 -12
  274. package/dist/collection/components/co-sidebar-nav/co-sidebar-nav.js +28 -8
  275. package/dist/collection/components/co-skeleton/co-skeleton.css +28 -0
  276. package/dist/collection/components/co-skeleton/co-skeleton.js +97 -0
  277. package/dist/collection/components/co-slider/co-slider.js +2 -2
  278. package/dist/collection/components/co-switch/co-switch.css +9 -1
  279. package/dist/collection/components/co-switch/co-switch.js +3 -3
  280. package/dist/collection/components/co-tab/co-tab.js +2 -2
  281. package/dist/collection/components/co-tab-group/co-tab-group.js +1 -1
  282. package/dist/collection/components/co-tags-field/co-tags-field.css +39 -1
  283. package/dist/collection/components/co-tags-field/co-tags-field.js +36 -10
  284. package/dist/collection/components/co-textarea/co-textarea.css +26 -1
  285. package/dist/collection/components/co-textarea/co-textarea.js +28 -4
  286. package/dist/collection/components/co-toast/co-toast.js +1 -1
  287. package/dist/collection/components/co-toggle-button/co-toggle-button.css +26 -4
  288. package/dist/collection/components/co-toggle-button/co-toggle-button.js +3 -3
  289. package/dist/collection/components/co-toggle-button-group/co-toggle-button-group.css +16 -12
  290. package/dist/collection/components/co-toggle-button-group/co-toggle-button-group.js +2 -2
  291. package/dist/collection/components/co-tooltip/co-tooltip.css +8 -0
  292. package/dist/collection/components/co-tooltip/co-tooltip.js +69 -14
  293. package/dist/collection/components/co-transfer-list/co-transfer-list.js +2 -2
  294. package/dist/collection/components/co-video/co-video.css +497 -0
  295. package/dist/collection/components/co-video/co-video.js +1772 -0
  296. package/dist/collection/utils/fieldChip.js +2 -0
  297. package/dist/collection/utils/icon-config.js +12 -0
  298. package/dist/collection/utils/richTextI18n.js +378 -0
  299. package/dist/collection/utils/sheetGesture.js +53 -0
  300. package/dist/components/co-accordion.js +1 -1
  301. package/dist/components/co-app-shell.js +1 -1
  302. package/dist/components/co-autocomplete.js +1 -1
  303. package/dist/components/co-avatar-group.d.ts +11 -0
  304. package/dist/components/co-avatar-group.js +1 -0
  305. package/dist/components/co-avatar.js +1 -1
  306. package/dist/components/co-badge.js +1 -1
  307. package/dist/components/co-bottom-sheet.d.ts +11 -0
  308. package/dist/components/co-bottom-sheet.js +1 -0
  309. package/dist/components/co-button-group.js +1 -1
  310. package/dist/components/co-button.js +1 -1
  311. package/dist/components/co-calendar-month.d.ts +11 -0
  312. package/dist/components/co-calendar-month.js +1 -0
  313. package/dist/components/co-calendar.js +1 -1
  314. package/dist/components/co-card.js +1 -1
  315. package/dist/components/co-checkbox-group.js +1 -1
  316. package/dist/components/co-checkbox.js +1 -1
  317. package/dist/components/co-chip.js +1 -1
  318. package/dist/components/co-color-picker.js +1 -1
  319. package/dist/components/co-column-picker.js +1 -1
  320. package/dist/components/co-combobox.js +1 -1
  321. package/dist/components/co-command-search.js +1 -1
  322. package/dist/components/co-data-table-pagination.js +1 -1
  323. package/dist/components/co-data-table.js +1 -1
  324. package/dist/components/co-date-field.js +1 -1
  325. package/dist/components/co-date-picker.js +1 -1
  326. package/dist/components/co-date-range-picker.js +1 -1
  327. package/dist/components/co-date-range.js +1 -1
  328. package/dist/components/co-drawer.js +1 -1
  329. package/dist/components/co-empty-state.js +1 -1
  330. package/dist/components/co-event-calendar.d.ts +11 -0
  331. package/dist/components/co-event-calendar.js +1 -0
  332. package/dist/components/co-fab.js +1 -1
  333. package/dist/components/co-file-field.js +1 -1
  334. package/dist/components/co-helper-text.js +1 -1
  335. package/dist/components/co-icon-button.js +1 -1
  336. package/dist/components/co-icon.js +1 -1
  337. package/dist/components/co-input.js +1 -1
  338. package/dist/components/co-json-field.js +1 -1
  339. package/dist/components/co-lightbox.js +1 -1
  340. package/dist/components/co-list-footer.d.ts +11 -0
  341. package/dist/components/co-list-footer.js +1 -0
  342. package/dist/components/co-list-item.js +1 -1
  343. package/dist/components/co-loader.js +1 -1
  344. package/dist/components/co-menu-divider.js +1 -1
  345. package/dist/components/co-menu-item.js +1 -1
  346. package/dist/components/co-menu.js +1 -1
  347. package/dist/components/co-modal.js +1 -1
  348. package/dist/components/co-navbar.js +1 -1
  349. package/dist/components/co-number-field.js +1 -1
  350. package/dist/components/co-overlay.js +1 -1
  351. package/dist/components/co-page-header.js +1 -1
  352. package/dist/components/co-phone-field.js +1 -1
  353. package/dist/components/co-popover.js +1 -1
  354. package/dist/components/co-progress-bar.js +1 -1
  355. package/dist/components/co-progress-circle.js +1 -1
  356. package/dist/components/co-radio-group.js +1 -1
  357. package/dist/components/co-radio.js +1 -1
  358. package/dist/components/co-rating.js +1 -1
  359. package/dist/components/co-ref-field.js +1 -1
  360. package/dist/components/co-rich-text-editor.js +1 -1
  361. package/dist/components/co-rich-text-toolbar.js +1 -1
  362. package/dist/components/co-rich-text-viewer.js +1 -1
  363. package/dist/components/co-row.js +1 -1
  364. package/dist/components/co-select.js +1 -1
  365. package/dist/components/co-separator.js +1 -1
  366. package/dist/components/co-sidebar-nav.js +1 -1
  367. package/dist/components/co-sidebar.js +1 -1
  368. package/dist/components/co-skeleton.d.ts +11 -0
  369. package/dist/components/co-skeleton.js +1 -0
  370. package/dist/components/co-slider.js +1 -1
  371. package/dist/components/co-switch.js +1 -1
  372. package/dist/components/co-tab-group.js +1 -1
  373. package/dist/components/co-tab.js +1 -1
  374. package/dist/components/co-tags-field.js +1 -1
  375. package/dist/components/co-textarea.js +1 -1
  376. package/dist/components/co-toast.js +1 -1
  377. package/dist/components/co-toggle-button-group.js +1 -1
  378. package/dist/components/co-toggle-button.js +1 -1
  379. package/dist/components/co-tooltip.js +1 -1
  380. package/dist/components/co-transfer-list.js +1 -1
  381. package/dist/components/co-video.d.ts +11 -0
  382. package/dist/components/co-video.js +1 -0
  383. package/dist/components/index.js +1 -1
  384. package/dist/components/p-B2QLgWrz.js +2 -0
  385. package/dist/components/{p-BeWXpX8I.js → p-B7vGYFbO.js} +1 -1
  386. package/dist/components/p-BB2OaYKF.js +1 -0
  387. package/dist/components/p-BFeE_fiq.js +1 -0
  388. package/dist/components/p-BNKz39GA.js +1 -0
  389. package/dist/components/p-Ba4v1NXo.js +1 -0
  390. package/dist/components/p-C_ULDaks.js +1 -0
  391. package/dist/components/p-CegCk7FL.js +1 -0
  392. package/dist/components/p-ChibIpZv.js +1 -0
  393. package/dist/components/p-D3Y_ti3Q.js +1 -0
  394. package/dist/components/{p-DObrQi5F.js → p-DKh8ZK4U.js} +1 -1
  395. package/dist/components/{p-C9tHLXKS.js → p-DeZxp9vb.js} +1 -1
  396. package/dist/components/p-DvhR3H61.js +1 -0
  397. package/dist/components/p-DxCFMMfY.js +1 -0
  398. package/dist/components/{p-OGpfa9Yd.js → p-DzoNGEDU.js} +1 -1
  399. package/dist/components/p-EPZfLt5l.js +1 -0
  400. package/dist/components/p-FMnqPWcM.js +1 -0
  401. package/dist/components/p-Hzh9U2cM.js +1 -0
  402. package/dist/components/p-WZ06pT2Y.js +1 -0
  403. package/dist/components/p-tloAgDin.js +1 -0
  404. package/dist/esm/co-accordion.entry.js +3 -3
  405. package/dist/esm/co-app-shell.entry.js +4 -4
  406. package/dist/esm/co-autocomplete.entry.js +10 -7
  407. package/dist/esm/co-avatar-group.entry.js +75 -0
  408. package/dist/esm/co-avatar.entry.js +6 -4
  409. package/dist/esm/co-badge.entry.js +2 -2
  410. package/dist/esm/co-bottom-sheet.entry.js +323 -0
  411. package/dist/esm/co-button-group.entry.js +3 -3
  412. package/dist/esm/co-button.entry.js +6 -6
  413. package/dist/esm/co-calendar-month.entry.js +379 -0
  414. package/dist/esm/co-calendar_3.entry.js +12 -12
  415. package/dist/esm/co-card.entry.js +3 -3
  416. package/dist/esm/co-checkbox-group.entry.js +5 -5
  417. package/dist/esm/co-checkbox.entry.js +5 -5
  418. package/dist/esm/co-chip.entry.js +11 -8
  419. package/dist/esm/co-color-picker.entry.js +7 -5
  420. package/dist/esm/co-column-picker.entry.js +3 -3
  421. package/dist/esm/co-combobox.entry.js +7 -7
  422. package/dist/esm/co-command-search.entry.js +151 -12
  423. package/dist/esm/co-data-table-pagination.entry.js +5 -5
  424. package/dist/esm/co-data-table.entry.js +25 -11
  425. package/dist/esm/co-date-picker.entry.js +2 -2
  426. package/dist/esm/co-date-range-picker.entry.js +4 -4
  427. package/dist/esm/co-date-range.entry.js +2 -2
  428. package/dist/esm/co-empty-state.entry.js +2 -2
  429. package/dist/esm/co-event-calendar.entry.js +316 -0
  430. package/dist/esm/co-fab.entry.js +3 -3
  431. package/dist/esm/co-file-field.entry.js +8 -8
  432. package/dist/esm/co-helper-text.entry.js +3 -3
  433. package/dist/esm/co-icon-button.entry.js +5 -5
  434. package/dist/esm/co-icon.entry.js +33 -25
  435. package/dist/esm/co-input.entry.js +6 -6
  436. package/dist/esm/co-json-field.entry.js +10 -6
  437. package/dist/esm/co-lightbox.entry.js +5 -5
  438. package/dist/esm/co-list-footer.entry.js +23 -0
  439. package/dist/esm/co-list-item.entry.js +60 -4
  440. package/dist/esm/co-loader_2.entry.js +290 -0
  441. package/dist/esm/co-menu-divider.entry.js +2 -2
  442. package/dist/esm/co-menu-item.entry.js +17 -10
  443. package/dist/esm/co-menu.entry.js +2 -2
  444. package/dist/esm/co-modal.entry.js +16 -4
  445. package/dist/esm/co-navbar.entry.js +3 -3
  446. package/dist/esm/co-number-field.entry.js +18 -6
  447. package/dist/esm/co-page-header.entry.js +2 -2
  448. package/dist/esm/co-phone-field.entry.js +6 -4
  449. package/dist/esm/co-popover.entry.js +45 -14
  450. package/dist/esm/co-progress-bar.entry.js +8 -4
  451. package/dist/esm/co-progress-circle.entry.js +3 -3
  452. package/dist/esm/co-radio-group.entry.js +4 -4
  453. package/dist/esm/co-radio.entry.js +4 -4
  454. package/dist/esm/co-rating.entry.js +4 -4
  455. package/dist/esm/co-ref-field.entry.js +36 -13
  456. package/dist/esm/co-rich-text-editor.entry.js +1879 -33
  457. package/dist/esm/co-rich-text-toolbar.entry.js +995 -71
  458. package/dist/esm/co-rich-text-viewer.entry.js +55 -19
  459. package/dist/esm/co-row.entry.js +3 -3
  460. package/dist/esm/co-select.entry.js +8 -8
  461. package/dist/esm/co-separator.entry.js +2 -2
  462. package/dist/esm/co-sidebar-nav.entry.js +29 -9
  463. package/dist/esm/co-sidebar.entry.js +3 -3
  464. package/dist/esm/co-skeleton.entry.js +24 -0
  465. package/dist/esm/co-slider.entry.js +3 -3
  466. package/dist/esm/co-switch.entry.js +6 -6
  467. package/dist/esm/co-tab-group.entry.js +2 -2
  468. package/dist/esm/co-tab.entry.js +3 -3
  469. package/dist/esm/co-tags-field.entry.js +19 -13
  470. package/dist/esm/co-textarea.entry.js +11 -7
  471. package/dist/esm/co-toast.entry.js +2 -2
  472. package/dist/esm/co-toggle-button-group.entry.js +4 -4
  473. package/dist/esm/co-toggle-button.entry.js +4 -4
  474. package/dist/esm/co-tooltip.entry.js +51 -16
  475. package/dist/esm/co-transfer-list.entry.js +3 -3
  476. package/dist/esm/co-video.entry.js +837 -0
  477. package/dist/esm/cobalt.js +3 -3
  478. package/dist/esm/{dates-CyYF8IJE.js → dates-tPYikBRJ.js} +1 -1
  479. package/dist/esm/fieldChip-GPikjpYw.js +5 -0
  480. package/dist/esm/{index-BKmfyPZK.js → index-CYsftTKf.js} +45 -21
  481. package/dist/esm/{index-BjAqSidM.js → index-w_Wxgclf.js} +14508 -6305
  482. package/dist/esm/loader.js +3 -3
  483. package/dist/esm/overlayAfterClose-Ch1jfwZ2.js +10 -0
  484. package/dist/{cjs/sanitizer-CjHZAkOm.js → esm/purify.es-B2QLgWrz.js} +1 -110
  485. package/dist/esm/{requiredMark-DFvtYtkE.js → requiredMark-CEbXKHcU.js} +1 -1
  486. package/dist/esm/richTextI18n-B-ckjCUA.js +380 -0
  487. package/dist/esm/toolbar-config-ChibIpZv.js +212 -0
  488. package/dist/esm/tz-B6JZk8fL.js +119 -0
  489. package/dist/types/components/co-autocomplete/co-autocomplete.d.ts +2 -0
  490. package/dist/types/components/co-avatar/co-avatar.d.ts +2 -0
  491. package/dist/types/components/co-avatar-group/co-avatar-group.d.ts +33 -0
  492. package/dist/types/components/co-bottom-sheet/co-bottom-sheet.d.ts +81 -0
  493. package/dist/types/components/co-button/co-button.d.ts +3 -1
  494. package/dist/types/components/co-calendar-month/co-calendar-month.d.ts +83 -0
  495. package/dist/types/components/co-chip/co-chip.d.ts +7 -2
  496. package/dist/types/components/co-color-picker/co-color-picker.d.ts +2 -0
  497. package/dist/types/components/co-command-search/co-command-search.d.ts +39 -6
  498. package/dist/types/components/co-command-search/commandSearchGroup.d.ts +20 -0
  499. package/dist/types/components/co-command-search/commandSearchLogic.d.ts +17 -0
  500. package/dist/types/components/co-data-table/co-data-table.d.ts +2 -1
  501. package/dist/types/components/co-event-calendar/co-event-calendar.d.ts +110 -0
  502. package/dist/types/components/co-icon/co-icon.d.ts +1 -1
  503. package/dist/types/components/co-icon/iconLoader.d.ts +6 -0
  504. package/dist/types/components/co-icon-button/co-icon-button.d.ts +2 -0
  505. package/dist/types/components/co-json-field/co-json-field.d.ts +3 -0
  506. package/dist/types/components/co-list-footer/co-list-footer.d.ts +26 -0
  507. package/dist/types/components/co-list-item/co-list-item.d.ts +11 -0
  508. package/dist/types/components/co-modal/co-modal.d.ts +6 -0
  509. package/dist/types/components/co-number-field/co-number-field.d.ts +13 -0
  510. package/dist/types/components/co-overlay/co-overlay.d.ts +45 -0
  511. package/dist/types/components/co-overlay/focusTrap.d.ts +20 -0
  512. package/dist/types/components/co-overlay/overlayAfterClose.d.ts +5 -0
  513. package/dist/types/components/co-phone-field/co-phone-field.d.ts +2 -0
  514. package/dist/types/components/co-popover/co-popover.d.ts +9 -0
  515. package/dist/types/components/co-progress-bar/co-progress-bar.d.ts +2 -0
  516. package/dist/types/components/co-ref-field/co-ref-field.d.ts +17 -2
  517. package/dist/types/components/co-rich-text-editor/co-rich-text-editor.d.ts +161 -9
  518. package/dist/types/components/co-rich-text-toolbar/co-rich-text-toolbar.d.ts +119 -13
  519. package/dist/types/components/co-rich-text-viewer/co-rich-text-viewer.d.ts +1 -14
  520. package/dist/types/components/co-skeleton/co-skeleton.d.ts +13 -0
  521. package/dist/types/components/co-tags-field/co-tags-field.d.ts +2 -0
  522. package/dist/types/components/co-textarea/co-textarea.d.ts +3 -0
  523. package/dist/types/components/co-tooltip/co-tooltip.d.ts +12 -0
  524. package/dist/types/components/co-video/co-video.d.ts +203 -0
  525. package/dist/types/components.d.ts +1729 -72
  526. package/dist/types/utils/fieldChip.d.ts +37 -0
  527. package/dist/types/utils/icon-config.d.ts +11 -0
  528. package/dist/types/utils/richTextI18n.d.ts +130 -0
  529. package/dist/types/utils/sheetGesture.d.ts +31 -0
  530. package/package.json +3 -2
  531. package/dist/cjs/co-loader.cjs.entry.js +0 -34
  532. package/dist/cjs/co-overlay.cjs.entry.js +0 -23
  533. package/dist/cobalt/p-0a6d8061.entry.js +0 -1
  534. package/dist/cobalt/p-0bf288cd.entry.js +0 -1
  535. package/dist/cobalt/p-136bdbd2.entry.js +0 -1
  536. package/dist/cobalt/p-15708d32.entry.js +0 -1
  537. package/dist/cobalt/p-1578b019.entry.js +0 -1
  538. package/dist/cobalt/p-23d48581.entry.js +0 -1
  539. package/dist/cobalt/p-2718ff27.entry.js +0 -1
  540. package/dist/cobalt/p-2b4d8535.entry.js +0 -1
  541. package/dist/cobalt/p-3190d715.entry.js +0 -1
  542. package/dist/cobalt/p-41228dce.entry.js +0 -1
  543. package/dist/cobalt/p-44672953.entry.js +0 -1
  544. package/dist/cobalt/p-53ce9023.entry.js +0 -1
  545. package/dist/cobalt/p-5e7141aa.entry.js +0 -1
  546. package/dist/cobalt/p-5f905739.entry.js +0 -1
  547. package/dist/cobalt/p-6678ac0a.entry.js +0 -1
  548. package/dist/cobalt/p-66a912dd.entry.js +0 -1
  549. package/dist/cobalt/p-6759ee1c.entry.js +0 -1
  550. package/dist/cobalt/p-69a40bfd.entry.js +0 -1
  551. package/dist/cobalt/p-6a6a62cb.entry.js +0 -1
  552. package/dist/cobalt/p-6d43b6cd.entry.js +0 -1
  553. package/dist/cobalt/p-759c3dd0.entry.js +0 -1
  554. package/dist/cobalt/p-782f729f.entry.js +0 -1
  555. package/dist/cobalt/p-83b89bf8.entry.js +0 -1
  556. package/dist/cobalt/p-88dc561a.entry.js +0 -1
  557. package/dist/cobalt/p-8c27aff7.entry.js +0 -1
  558. package/dist/cobalt/p-996179f7.entry.js +0 -1
  559. package/dist/cobalt/p-9c533830.entry.js +0 -1
  560. package/dist/cobalt/p-9d89bf47.entry.js +0 -1
  561. package/dist/cobalt/p-BKmfyPZK.js +0 -2
  562. package/dist/cobalt/p-BchB6Hdr.js +0 -1
  563. package/dist/cobalt/p-DcK0GGZC.js +0 -2
  564. package/dist/cobalt/p-Qqq8fysz.js +0 -1
  565. package/dist/cobalt/p-aa17c70b.entry.js +0 -1
  566. package/dist/cobalt/p-ad4c1b41.entry.js +0 -1
  567. package/dist/cobalt/p-ae4d3207.entry.js +0 -1
  568. package/dist/cobalt/p-af64da37.entry.js +0 -1
  569. package/dist/cobalt/p-c6a242e4.entry.js +0 -1
  570. package/dist/cobalt/p-cd57e8b4.entry.js +0 -1
  571. package/dist/cobalt/p-ce3a535f.entry.js +0 -1
  572. package/dist/cobalt/p-d958566a.entry.js +0 -1
  573. package/dist/cobalt/p-dd873bf8.entry.js +0 -1
  574. package/dist/cobalt/p-e4de8865.entry.js +0 -1
  575. package/dist/cobalt/p-eba0bf7f.entry.js +0 -1
  576. package/dist/cobalt/p-fad3605d.entry.js +0 -1
  577. package/dist/cobalt/p-ff2690e5.entry.js +0 -1
  578. package/dist/components/p-BXdfh__-.js +0 -1
  579. package/dist/components/p-BchB6Hdr.js +0 -1
  580. package/dist/components/p-BiW0ubLs.js +0 -1
  581. package/dist/components/p-CaMgu2_g.js +0 -1
  582. package/dist/components/p-DBhNS7JD.js +0 -1
  583. package/dist/components/p-DPi_U-Kl.js +0 -1
  584. package/dist/components/p-DcK0GGZC.js +0 -2
  585. package/dist/components/p-MiSJXuBx.js +0 -1
  586. package/dist/components/p-Sgn-2g8m.js +0 -1
  587. package/dist/components/p-jDjfGZJp.js +0 -1
  588. package/dist/components/p-o8hrDIKe.js +0 -1
  589. package/dist/esm/co-loader.entry.js +0 -32
  590. package/dist/esm/co-overlay.entry.js +0 -21
@@ -1,7 +1,10 @@
1
- import { r as registerInstance, c as createEvent, h, a as getElement } from './index-BKmfyPZK.js';
2
- import { R as RequiredMark } from './requiredMark-DFvtYtkE.js';
1
+ import { r as registerInstance, c as createEvent, h, a as getElement } from './index-CYsftTKf.js';
2
+ import { R as RichText } from './index-w_Wxgclf.js';
3
+ import { g as getRichTextStrings } from './richTextI18n-B-ckjCUA.js';
4
+ import './purify.es-B2QLgWrz.js';
5
+ import './toolbar-config-ChibIpZv.js';
3
6
 
4
- const coRichTextEditorCss = () => `co-rich-text-editor{display:block;font-family:var(--co-font-family-primary);font-size:var(--co-font-size-14);letter-spacing:var(--co-font-letter-spacing-body)}.co-rich-text-editor{display:flex;flex-direction:column;gap:var(--co-spacing-sm2, 6px)}.co-rich-text-editor__labels{display:flex;align-items:center;justify-content:space-between;padding:0 var(--co-spacing-xs);gap:var(--co-spacing-sm2, 6px)}.co-rich-text-editor__label,.co-rich-text-editor__secondary-label{color:var(--co-semantic-text-secondary);font-size:var(--co-font-size-14);font-weight:400;line-height:1}.co-rich-text-editor__box{display:flex;flex-direction:column;background:var(--co-semantic-surface-secondary);border:1px solid var(--co-semantic-border-subtle);border-radius:var(--co-border-radius-xs);transition:border-color 0.15s ease, box-shadow 0.15s ease;overflow:hidden}.co-rich-text-editor--focused .co-rich-text-editor__box{border-color:var(--co-semantic-border-focus, var(--co-color-primary-azul));box-shadow:0 0 0 3px var(--co-semantic-border-focus-ring, rgba(37, 99, 235, 0.15))}.co-rich-text-editor--error .co-rich-text-editor__box{border-color:var(--co-color-status-error)}.co-rich-text-editor--success .co-rich-text-editor__box{border-color:var(--co-color-status-success)}.co-rich-text-editor--disabled .co-rich-text-editor__box,.co-rich-text-editor--readonly .co-rich-text-editor__box{opacity:0.7;cursor:not-allowed}.co-rich-text-editor--loading .co-rte-content{min-height:96px;background:linear-gradient(90deg, var(--co-semantic-surface-secondary) 0%, var(--co-semantic-surface-hover, rgba(0, 0, 0, 0.04)) 50%, var(--co-semantic-surface-secondary) 100%);background-size:200% 100%;animation:co-rte-skeleton 1.2s ease-in-out infinite}@keyframes co-rte-skeleton{0%{background-position:200% 0}100%{background-position:-200% 0}}.co-rte-content{padding:var(--co-spacing-md) var(--co-spacing-md);min-height:96px;color:var(--co-semantic-text-default)}.co-rte-content .ProseMirror{outline:none;min-height:72px;line-height:1.5}.co-rte-content .ProseMirror p{margin:0 0 var(--co-spacing-sm) 0}.co-rte-content .ProseMirror p:last-child{margin-bottom:0}.co-rte-content .ProseMirror h2,.co-rte-content .ProseMirror h3,.co-rte-content .ProseMirror h4{margin:var(--co-spacing-md) 0 var(--co-spacing-sm);font-weight:600;line-height:1.3}.co-rte-content .ProseMirror h2{font-size:var(--co-font-size-20, 20px)}.co-rte-content .ProseMirror h3{font-size:var(--co-font-size-16, 16px)}.co-rte-content .ProseMirror ul,.co-rte-content .ProseMirror ol{padding-left:var(--co-spacing-xl);margin:0 0 var(--co-spacing-sm) 0}.co-rte-content .ProseMirror blockquote{border-left:3px solid var(--co-semantic-border-default, var(--co-semantic-border-subtle));padding-left:var(--co-spacing-md);margin:0 0 var(--co-spacing-sm) 0;color:var(--co-semantic-text-secondary)}.co-rte-content .ProseMirror a{color:var(--co-color-primary-azul);text-decoration:underline}.co-rte-content .ProseMirror img{max-width:100%;height:auto;border-radius:var(--co-border-radius-xs);margin:var(--co-spacing-sm) 0}.co-rte-content .ProseMirror img.ProseMirror-selectednode{outline:2px solid var(--co-semantic-border-focus, var(--co-color-primary-azul))}.co-rte-content .ProseMirror code{font-family:var(--co-font-family-mono);font-size:0.9em;background:var(--co-semantic-surface-hover, rgba(0, 0, 0, 0.06));padding:0.1em 0.3em;border-radius:var(--co-border-radius-xxs)}.co-rte-content .ProseMirror p.is-editor-empty:first-child::before{content:attr(data-placeholder);color:var(--co-semantic-text-muted);float:left;height:0;pointer-events:none}.co-rte-content .co-rte-variable,.co-rte-content .co-rte-mention{display:inline-block;padding:0.05em 0.4em;border-radius:var(--co-border-radius-xxs);background:var(--co-color-primary-azul);color:var(--co-color-base-blanco, #fff);font-size:0.9em;white-space:nowrap}.co-rte-content .co-rte-mention{background:var(--co-color-primary-verde)}.co-rich-text-editor__footer{display:flex;align-items:center;justify-content:space-between;gap:var(--co-spacing-sm);padding:0 var(--co-spacing-xs);min-height:0}.co-rich-text-editor__helper{display:flex;align-items:center;gap:var(--co-spacing-xs);color:var(--co-semantic-text-secondary);font-size:var(--co-font-size-12, 12px)}.co-rich-text-editor__helper--error{color:var(--co-color-status-error)}.co-rich-text-editor__helper--success{color:var(--co-color-status-success)}.co-rich-text-editor__count{margin-left:auto;color:var(--co-semantic-text-muted);font-size:var(--co-font-size-12, 12px)}co-rich-text-editor[layout='horizontal'] .co-rich-text-editor{display:grid;grid-template-columns:var(--co-field-label-width, max-content) 1fr;align-items:start;column-gap:var(--co-spacing-md);row-gap:var(--co-spacing-sm2)}co-rich-text-editor[layout='horizontal'] .co-rich-text-editor__labels{grid-column:1;grid-row:1;padding-top:var(--co-spacing-sm2);min-width:0}co-rich-text-editor[layout='horizontal'] .co-rich-text-editor__label{white-space:normal}co-rich-text-editor[layout='horizontal'] .co-rich-text-editor>:not(.co-rich-text-editor__labels){grid-column:2;min-width:0}.co-field-required{margin-left:2px;color:var(--co-color-status-error)}.co-field-required__caption{margin-left:4px;color:var(--co-semantic-text-muted);font-size:var(--co-font-size-12);font-weight:400}.co-field-required__caption::before{content:var(--co-field-required-text, ' (required)')}`;
7
+ const coRichTextEditorCss = () => `co-rich-text-editor{display:block;font-family:var(--co-font-family-primary);font-size:var(--co-font-size-14);letter-spacing:var(--co-font-letter-spacing-body)}.co-rich-text-editor{display:flex;flex-direction:column;gap:var(--co-spacing-sm2, 6px)}.co-rich-text-editor__labels{display:flex;align-items:center;justify-content:space-between;padding:0 var(--co-spacing-xs);gap:var(--co-spacing-sm2, 6px)}.co-rich-text-editor__label,.co-rich-text-editor__secondary-label{color:var(--co-semantic-text-secondary);font-size:var(--co-font-size-14);font-weight:400;line-height:1}.co-rich-text-editor__frame{display:flex;flex-direction:column;background:var(--co-semantic-surface-secondary);border:1px solid var(--co-semantic-border-subtle);border-radius:var(--co-border-radius-xs);transition:border-color 0.15s ease, box-shadow 0.15s ease;min-height:0;flex:1;position:relative;overflow:visible}.co-rich-text-editor__box{display:flex;flex-direction:column;min-height:0;flex:1;position:relative;overflow-y:auto;overflow-x:hidden}.co-rich-text-editor--focused .co-rich-text-editor__frame{border-color:var(--co-semantic-border-focus, var(--co-color-base-negro, #1a1a1a));box-shadow:0 0 0 3px var(--co-semantic-border-focus-ring, rgba(37, 99, 235, 0.15))}.co-rich-text-editor--error .co-rich-text-editor__frame{border-color:var(--co-color-status-error)}.co-rich-text-editor--success .co-rich-text-editor__frame{border-color:var(--co-color-status-success)}.co-rich-text-editor--disabled .co-rich-text-editor__frame,.co-rich-text-editor--readonly .co-rich-text-editor__frame{opacity:0.7;cursor:not-allowed}.co-rich-text-editor--loading .co-rte-content{min-height:96px;background:linear-gradient(90deg, var(--co-semantic-surface-secondary) 0%, var(--co-semantic-surface-hover, rgba(0, 0, 0, 0.04)) 50%, var(--co-semantic-surface-secondary) 100%);background-size:200% 100%;animation:co-rte-skeleton 1.2s ease-in-out infinite}@keyframes co-rte-skeleton{0%{background-position:200% 0}100%{background-position:-200% 0}}.co-rich-text-editor__toolbar{position:relative;flex-shrink:0;z-index:60}.co-rte-content{min-height:96px;color:var(--co-semantic-text-default);flex:1 0 auto;display:flex;flex-direction:column}.co-rte-content .ProseMirror{outline:none;flex:1 0 auto;line-height:1.5;padding:var(--co-spacing-md);box-sizing:border-box}.co-rte-content .ProseMirror p{margin:0 0 var(--co-spacing-sm) 0}.co-rte-content .ProseMirror p:last-child{margin-bottom:0}.co-rte-content .ProseMirror>p{margin-bottom:var(--co-spacing-sm) !important}.co-rte-content .ProseMirror>p:last-child{margin-bottom:0 !important}.co-rte-content .ProseMirror [style*="text-align: justify"]{text-align-last:left}.co-rte-content .ProseMirror [style*="text-align: center"]{text-align:center}.co-rte-content .ProseMirror [style*="text-align: right"]{text-align:right}.co-rte-content .ProseMirror h1,.co-rte-content .ProseMirror h2,.co-rte-content .ProseMirror h3,.co-rte-content .ProseMirror h4{margin:var(--co-spacing-md) 0 var(--co-spacing-sm);font-weight:600;line-height:1.3}.co-rte-content .ProseMirror h1{font-size:var(--co-font-size-28, 28px)}.co-rte-content .ProseMirror h2{font-size:var(--co-font-size-20, 20px)}.co-rte-content .ProseMirror h3{font-size:var(--co-font-size-16, 16px)}.co-rte-content .ProseMirror ul,.co-rte-content .ProseMirror ol{padding-left:var(--co-spacing-xl);margin:0 0 var(--co-spacing-sm) 0}.co-rte-content .ProseMirror ul[data-type="taskList"]{list-style:none;padding-left:0;margin:0 0 var(--co-spacing-sm) 0}.co-rte-content .ProseMirror ul[data-type="taskList"] li{display:flex;align-items:flex-start;gap:var(--co-spacing-sm, 8px)}.co-rte-content .ProseMirror ul[data-type="taskList"] li>label{flex:0 0 auto;margin-top:0.15em;user-select:none}.co-rte-content .ProseMirror ul[data-type="taskList"] li>div{flex:1 1 auto;min-width:0}.co-rte-content .ProseMirror ul[data-type="taskList"] li>div>p{margin:0}.co-rte-content .ProseMirror ul[data-type="taskList"] input[type="checkbox"]{width:16px;height:16px;cursor:pointer;accent-color:var(--co-color-base-negro, #1a1a1a)}.co-rte-content .ProseMirror ul[data-type="taskList"][data-variant="strike"] li[data-checked="true"]>div{text-decoration:line-through;color:var(--co-semantic-text-muted, #999)}.co-rte-content .ProseMirror ul[data-type="taskList"][data-variant="plain"] li[data-checked="true"]>div{text-decoration:none}.co-rte-content .ProseMirror blockquote{border-left:3px solid var(--co-semantic-border-default, var(--co-semantic-border-subtle));padding-left:var(--co-spacing-md);margin:0 0 var(--co-spacing-sm) 0;color:var(--co-semantic-text-secondary)}.co-rte-content .ProseMirror a{color:var(--co-color-base-negro, #1a1a1a);text-decoration:underline;text-underline-offset:2px}.co-rte-content .ProseMirror img{max-width:100%;height:auto;border-radius:var(--co-border-radius-xs);margin:var(--co-spacing-sm) 0;cursor:default;-webkit-user-drag:none;user-select:none}.co-rte-content .ProseMirror img.ProseMirror-selectednode{outline:2px solid var(--co-color-base-negro, #1a1a1a)}.co-rte-content [data-resize-container].ProseMirror-selectednode{outline:2px solid var(--co-color-base-negro, #1a1a1a);outline-offset:0px;border-radius:0}.co-rte-content [data-resize-container]{position:relative;display:inline-block;width:fit-content;max-width:100%;margin:var(--co-spacing-sm) 0;line-height:0}.co-rte-content [data-resize-container][data-resize-state="true"]{outline:2px solid var(--co-color-base-negro, #1a1a1a);outline-offset:0px;border-radius:0}.co-rte-content [data-resize-wrapper]{position:relative;display:inline-block;line-height:0}.co-rte-content [data-resize-handle]{width:10px;height:10px;background:var(--co-color-base-negro, #1a1a1a);border:1.5px solid #fff;border-radius:50%;box-shadow:0 0 2px rgba(0, 0, 0, 0.3);z-index:5;opacity:0;pointer-events:none}.co-rte-content [data-resize-container][data-resize-state="true"] [data-resize-handle],.co-rte-content [data-resize-container].ProseMirror-selectednode [data-resize-handle]{opacity:1;pointer-events:auto}.co-rte-content [data-resize-handle="top-left"]{cursor:nw-resize}.co-rte-content [data-resize-handle="top-right"]{cursor:ne-resize}.co-rte-content [data-resize-handle="bottom-left"]{cursor:sw-resize}.co-rte-content [data-resize-handle="bottom-right"]{cursor:se-resize}.co-rte-content [data-resize-handle="top"],.co-rte-content [data-resize-handle="bottom"]{width:30px;height:6px;border-radius:3px;left:50% !important;transform:translateX(-50%)}.co-rte-content [data-resize-handle="top"]{cursor:n-resize}.co-rte-content [data-resize-handle="bottom"]{cursor:s-resize}.co-rte-content [data-resize-handle="left"],.co-rte-content [data-resize-handle="right"]{width:6px;height:30px;border-radius:3px;top:50% !important;transform:translateY(-50%)}.co-rte-content [data-resize-handle="left"]{cursor:w-resize}.co-rte-content [data-resize-handle="right"]{cursor:e-resize}.co-rte-content [data-resize-container] img{max-width:100%;display:block;border-radius:0;margin:0}.co-rte-content .ProseMirror hr{border:none;border-top:1px solid var(--co-semantic-border-default, #e0e0e0);margin:var(--co-spacing-lg) 0}.co-rte-content .ProseMirror code{font-family:var(--co-font-family-mono);font-size:0.9em;background:var(--co-semantic-surface-hover, rgba(0, 0, 0, 0.06));padding:0.1em 0.3em;border-radius:var(--co-border-radius-xxs)}.co-rte-content .ProseMirror pre{font-family:var(--co-font-family-mono);font-size:0.9em;background:var(--co-semantic-surface-hover, rgba(0, 0, 0, 0.06));padding:var(--co-spacing-md);border-radius:var(--co-border-radius-xs);overflow-x:auto;margin:var(--co-spacing-sm) 0}.co-rte-content .ProseMirror pre code{background:none;padding:0;border-radius:0}.co-rte-content .ProseMirror p.is-editor-empty:first-child::before{content:attr(data-placeholder);color:var(--co-semantic-text-muted);float:left;height:0;pointer-events:none}.co-rte-content .co-rte-variable,.co-rte-content .co-rte-mention{display:inline-block;padding:0.05em 0.4em;border-radius:var(--co-border-radius-xxs);background:var(--co-color-base-negro, #1a1a1a);color:var(--co-color-base-blanco, #fff);font-size:0.9em;white-space:nowrap}.co-rte-content .co-rte-mention{background:var(--co-color-primary-verde)}.co-rich-text-editor__footer{display:flex;align-items:center;justify-content:space-between;gap:var(--co-spacing-sm);padding:0 var(--co-spacing-xs);min-height:0}.co-rich-text-editor__helper{display:flex;align-items:center;gap:var(--co-spacing-xs);color:var(--co-semantic-text-secondary);font-size:var(--co-font-size-12, 12px)}.co-rich-text-editor__helper--error{color:var(--co-color-status-error)}.co-rich-text-editor__helper--success{color:var(--co-color-status-success)}.co-rich-text-editor__count{margin-left:auto;color:var(--co-semantic-text-muted);font-size:var(--co-font-size-12, 12px)}.co-rte-bubble.co-rte-bubble--suppressed{display:none !important}.co-rte-bubble{position:absolute;z-index:50;display:flex;flex-direction:row;align-items:center;gap:2px;padding:var(--co-spacing-xs, 4px) var(--co-spacing-sm, 8px);background:var(--co-semantic-surface-secondary, #fff);border:1px solid var(--co-semantic-border-default, #e0e0e0);border-radius:var(--co-border-radius-xs, 8px);box-shadow:0 4px 16px rgba(0, 0, 0, 0.12);user-select:none;white-space:nowrap}.co-rte-bubble__drag-handle{display:flex;align-items:center;justify-content:center;cursor:grab;color:var(--co-semantic-text-muted, #999);width:18px;height:28px;margin:0 2px 0 0;flex-shrink:0}.co-rte-bubble__drag-handle:hover{color:var(--co-semantic-text-secondary, #555)}.co-rte-bubble__drag-handle:active{cursor:grabbing}.co-rte-bubble__row{display:flex;align-items:center;gap:2px;flex-wrap:nowrap}.co-rte-bubble__btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:none;border-radius:var(--co-border-radius-xxs, 4px);background:transparent;color:var(--co-semantic-text-default, #333);cursor:pointer}.co-rte-bubble__btn:hover:not(.co-rte-bubble__btn--active){background:var(--co-semantic-surface-hover, rgba(0, 0, 0, 0.06))}.co-rte-bubble__btn--active{background:var(--co-color-base-negro, #1a1a1a);color:var(--co-color-base-blanco, #fff)}.co-rte-bubble__btn--active:hover{background:var(--co-color-base-negro, #333)}.co-rte-bubble__sep{display:inline-block;width:1px;height:18px;margin:0 4px;background:var(--co-semantic-border-default, rgba(0, 0, 0, 0.12));flex-shrink:0}.co-rte-bubble__select{position:relative}.co-rte-bubble__select-trigger{display:flex;align-items:center;gap:2px;height:28px;padding:0 6px;border:1px solid transparent;border-radius:var(--co-border-radius-xxs, 4px);background:transparent;color:var(--co-semantic-text-default, #333);font-family:var(--co-font-family-primary);font-size:11px;cursor:pointer;white-space:nowrap;transition:background 0.12s, border-color 0.12s}.co-rte-bubble__select-trigger:hover{background:var(--co-semantic-surface-hover, #f5f5f5);border-color:var(--co-semantic-border-default, #e0e0e0)}.co-rte-bubble__select-label{max-width:72px;overflow:hidden;text-overflow:ellipsis}.co-rte-bubble__select--font .co-rte-bubble__select-label{max-width:110px}.co-rte-bubble__select-dropdown{position:absolute;bottom:100%;left:0;z-index:120;min-width:100px;max-height:260px;overflow-y:auto;padding:var(--co-spacing-xxs, 2px);background:var(--co-semantic-surface-secondary, #fff);border:1px solid var(--co-semantic-border-default, #e0e0e0);border-radius:var(--co-border-radius-xxs, 4px);box-shadow:0 4px 16px rgba(0, 0, 0, 0.12);margin-bottom:4px;white-space:normal}.co-rte-bubble__select-dropdown[data-position="above"]{bottom:100%;top:auto;margin-bottom:4px;margin-top:0}.co-rte-bubble__select-dropdown[data-position="below"]{top:100%;bottom:auto;margin-top:4px;margin-bottom:0}.co-rte-bubble__select-option{display:block;width:100%;padding:4px 8px;border:none;border-radius:3px;background:transparent;color:var(--co-semantic-text-default, #333);font-family:var(--co-font-family-primary);font-size:12px;text-align:left;cursor:pointer;white-space:nowrap}.co-rte-bubble__select-option:hover{background:var(--co-semantic-surface-hover, #f5f5f5)}.co-rte-bubble__select-dropdown--font{min-width:200px;max-height:320px;overflow:hidden;overflow-y:auto;display:flex;flex-direction:column;white-space:normal}.co-rte-bubble__font-search{padding:6px 6px 4px;flex-shrink:0}.co-rte-bubble__font-search-input{width:100%;padding:4px 8px;border:1px solid var(--co-semantic-border-default, #ccc);border-radius:4px;background:var(--co-semantic-surface-secondary, #fff);color:var(--co-semantic-text-default, #333);font-family:var(--co-font-family-primary);font-size:12px;outline:none;box-sizing:border-box}.co-rte-bubble__font-search-input:focus{border-color:var(--co-color-base-negro, #1a1a1a)}.co-rte-bubble__font-list{max-height:260px;overflow-y:auto;padding:0 var(--co-spacing-xxs, 2px) var(--co-spacing-xxs, 2px)}.co-rte-bubble__font-section-header{padding:6px 8px 2px;font-size:11px;font-weight:600;color:var(--co-semantic-text-muted, #888);text-transform:uppercase;letter-spacing:0.5px}.co-rte-bubble__font-empty{padding:12px 8px;text-align:center;color:var(--co-semantic-text-muted, #888);font-size:12px}.co-rte-bubble__color{position:relative}.co-rte-bubble__color-dropdown{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);z-index:120;width:224px;padding:var(--co-spacing-sm, 8px);background:var(--co-semantic-surface-secondary, #fff);border:1px solid var(--co-semantic-border-default, #e0e0e0);border-radius:var(--co-border-radius-xs, 8px);box-shadow:0 4px 16px rgba(0, 0, 0, 0.12);margin-bottom:4px;white-space:normal;max-width:calc(100vw - 16px)}.co-rte-bubble__color-dropdown[data-position="above"]{bottom:100%;top:auto;margin-bottom:4px;margin-top:0}.co-rte-bubble__color-dropdown[data-position="below"]{top:100%;bottom:auto;margin-top:4px;margin-bottom:0}.co-rte-bubble__color-grid{display:grid;grid-template-columns:repeat(10, 1fr);gap:2px}.co-rte-bubble__color-swatch{width:20px;height:20px;padding:0;border:none;border-radius:3px;cursor:pointer;transition:transform 0.1s, box-shadow 0.1s}.co-rte-bubble__color-swatch:hover{transform:scale(1.2);box-shadow:0 0 0 2px var(--co-color-base-negro, #1a1a1a)}.co-rte-bubble__color-hex{display:flex;align-items:center;gap:4px;margin-top:6px}.co-rte-bubble__color-hex-input{width:100%;padding:3px 6px;border:1px solid var(--co-semantic-border-default, #ccc);border-radius:3px;background:var(--co-semantic-surface-secondary, #fff);color:var(--co-semantic-text-default, #333);font-family:var(--co-font-family-mono, monospace);font-size:11px;outline:none}.co-rte-bubble__color-hex-input:focus{border-color:var(--co-color-base-negro, #1a1a1a)}.co-rte-bubble__color-clear{display:flex;align-items:center;gap:4px;width:100%;padding:3px 6px;margin-top:4px;border:none;background:transparent;color:var(--co-semantic-text-secondary, #666);font-family:var(--co-font-family-primary);font-size:11px;cursor:pointer;border-radius:3px}.co-rte-bubble__color-clear:hover{background:var(--co-semantic-surface-hover, #f5f5f5)}.co-rte-bubble__link-form{display:flex;align-items:center;gap:4px;margin-left:4px}.co-rte-bubble__link-input{width:160px;padding:3px 8px;border:1px solid var(--co-semantic-border-default, #ccc);border-radius:4px;background:var(--co-semantic-surface-secondary, #fff);color:var(--co-semantic-text-default, #333);font-family:var(--co-font-family-primary);font-size:12px;outline:none}.co-rte-bubble__link-input::placeholder{color:var(--co-semantic-text-muted, #999)}.co-rte-bubble__link-input:focus{border-color:var(--co-color-base-negro, #1a1a1a);box-shadow:0 0 0 2px rgba(0, 0, 0, 0.1)}.co-rte-bubble__link-btn{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;border:none;border-radius:4px;background:var(--co-color-base-negro, #1a1a1a);color:#fff;cursor:pointer}.co-rte-bubble__link-btn:hover{opacity:0.9}.co-rte-bubble__link-unlink{background:var(--co-semantic-surface-error, #ef4444)}.co-rte-bubble__panel{position:absolute;z-index:140;width:230px;background:var(--co-semantic-surface-secondary, #fff);border:1px solid var(--co-semantic-border-default, #e0e0e0);border-radius:var(--co-border-radius-xs, 8px);box-shadow:0 4px 16px rgba(0, 0, 0, 0.12);overflow:hidden;user-select:none}.co-rte-bubble__panel-header{display:flex;align-items:center;gap:4px;padding:6px 8px;border-bottom:1px solid var(--co-semantic-border-subtle, #eee)}.co-rte-bubble__panel-drag{cursor:grab;display:flex;align-items:center;justify-content:center;color:var(--co-semantic-text-muted, #999);flex-shrink:0}.co-rte-bubble__panel-drag:active{cursor:grabbing}.co-rte-bubble__panel-title{flex:1;font-size:12px;font-weight:600;color:var(--co-semantic-text-default, #333);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.co-rte-bubble__panel-close{display:flex;align-items:center;justify-content:center;width:22px;height:22px;border:none;border-radius:3px;background:transparent;color:var(--co-semantic-text-muted, #999);cursor:pointer;flex-shrink:0}.co-rte-bubble__panel-close:hover{background:var(--co-semantic-surface-hover, rgba(0, 0, 0, 0.06));color:var(--co-semantic-text-default, #333)}.co-rte-bubble__panel-input-wrap{padding:6px 8px}.co-rte-bubble__panel-input{width:100%;padding:4px 8px;border:1px solid var(--co-semantic-border-default, #e0e0e0);border-radius:4px;font-size:12px;font-family:inherit;outline:none;box-sizing:border-box;background:var(--co-semantic-surface-secondary, #fff);color:var(--co-semantic-text-default, #333)}.co-rte-bubble__panel-input:focus{border-color:var(--co-color-base-negro, #1a1a1a)}.co-rte-bubble__panel-options{max-height:280px;overflow-y:auto;padding:2px 4px 4px}.co-rte-bubble__panel-option{display:block;width:100%;padding:5px 8px;border:none;border-radius:3px;background:transparent;cursor:pointer;text-align:left;font-family:inherit;color:var(--co-semantic-text-default, #333)}.co-rte-bubble__panel-option:hover{background:var(--co-semantic-surface-hover, #f5f5f5)}.co-rte-bubble__panel-sep{height:1px;background:var(--co-semantic-border-subtle, #eee);margin:4px 8px}.co-rte-bubble__panel-opt-row{display:flex;justify-content:space-between;align-items:center;width:100%}.co-rte-bubble__panel-opt-value{color:var(--co-semantic-text-muted, #999);font-size:11px;font-weight:400 !important;min-width:28px;text-align:right}.co-rte-bubble__panel[data-position="above"]{bottom:100%;top:auto;margin-bottom:4px}.co-rte-bubble__panel[data-position="below"]{top:100%;bottom:auto;margin-top:4px}.co-rte-bubble__overflow{position:relative}.co-rte-bubble__overflow-menu{position:absolute;bottom:100%;right:0;z-index:130;min-width:230px;padding:4px;background:var(--co-semantic-surface-secondary, #fff);border:1px solid var(--co-semantic-border-default, #e0e0e0);border-radius:var(--co-border-radius-xs, 8px);box-shadow:0 4px 16px rgba(0, 0, 0, 0.12);margin-bottom:4px}.co-rte-bubble__overflow-menu[data-position="below"]{top:100%;bottom:auto;margin-top:4px;margin-bottom:0}.co-rte-bubble__overflow-item{display:flex;align-items:center;gap:8px;width:100%;padding:6px 8px;border:none;border-radius:4px;background:transparent;font-family:inherit;font-size:13px;color:var(--co-semantic-text-default, #333);cursor:pointer;text-align:left;white-space:nowrap}.co-rte-bubble__overflow-item:hover{background:var(--co-semantic-surface-hover, #f5f5f5)}.co-rte-bubble__overflow-item--active{background:var(--co-semantic-surface-hover, rgba(0, 0, 0, 0.06));color:var(--co-color-base-negro, #1a1a1a);font-weight:600}.co-rte-bubble__overflow-value{margin-left:auto;color:var(--co-semantic-text-muted, #999);font-size:11px}.co-rte-bubble__overflow-sep{height:1px;background:var(--co-semantic-border-subtle, #eee);margin:3px 8px}.co-rte-bubble__overflow-section-title{padding:6px 8px 2px;font-size:11px;font-weight:600;color:var(--co-semantic-text-muted, #888);letter-spacing:0.5px}.co-rte-bubble__overflow-item--danger{color:var(--co-color-status-error, #aa2e1b)}.co-rte-bubble__overflow-item--danger:hover{background:rgba(170, 46, 27, 0.06)}.co-rte-bubble__color-indicator{display:flex;flex-direction:column;align-items:center;gap:1px;line-height:1}.co-rte-bubble__color-letter{font-family:var(--co-font-family-primary);font-size:14px;font-weight:700;color:var(--co-semantic-text-default, #333);line-height:1}.co-rte-bubble__color-bar{width:14px;height:3px;border-radius:1px}.co-rte-content .callout{display:flex;gap:0.75rem;padding:1rem;border-radius:var(--co-border-radius-xs, 8px);border:2px solid;margin:1rem 0}.co-rte-content .callout--info{background:#eff6ff;border-color:#bfdbfe}.co-rte-content .callout--warning{background:#fffbeb;border-color:#fde68a}.co-rte-content .callout--success{background:#f0fdf4;border-color:#bbf7d0}.co-rte-content .callout--error{background:#fef2f2;border-color:#fecaca}.co-rte-content .callout__icon{flex-shrink:0;font-size:1.2em}.co-rte-content .callout__content{flex:1}.co-rte-content .callout__content p{margin:0}.co-rte-content table{border-collapse:collapse;table-layout:auto;width:100%;margin:1rem 0;overflow:hidden}.co-rte-content .tableWrapper{overflow-x:auto;max-width:100%}.co-rte-content td,.co-rte-content th{min-width:1em;border:1px solid var(--co-semantic-border-default, #e0e0e0);padding:0.5rem;vertical-align:top;box-sizing:border-box;position:relative}.co-rte-content th{font-weight:600;text-align:left;background-color:#e3e3e3;color:var(--co-semantic-text-default, #333)}.co-rte-content .ProseMirror table th{background-color:#e3e3e3}.co-rte-content .selectedCell{background:rgba(0, 0, 0, 0.06)}.co-rte-content .column-resize-handle{position:absolute;right:-2px;top:0;bottom:0;width:4px;background-color:var(--co-color-base-negro, #1a1a1a);pointer-events:none}.co-rte-content .ProseMirror.resize-cursor,.co-rte-content .ProseMirror.resize-cursor *{cursor:col-resize}.co-rte-content iframe{border-radius:var(--co-border-radius-xs, 8px);max-width:100%;aspect-ratio:16 / 9;width:100%;height:auto;display:block;margin:0}.co-rte-content .co-rte-embed{position:relative;display:block;max-width:100%;margin:1rem 0;line-height:0}.co-rte-content .co-rte-embed::before{content:'';position:absolute;inset:0;z-index:1}.co-rte-content .co-rte-embed.ProseMirror-selectednode,.co-rte-content .co-rte-embed--selected{outline:2px solid var(--co-color-base-negro, #1a1a1a);outline-offset:2px;border-radius:var(--co-border-radius-xs, 8px)}.co-rte-content .co-rte-embed__handle{position:absolute;width:12px;height:12px;background:var(--co-color-base-negro, #1a1a1a);border:1.5px solid #fff;border-radius:50%;box-shadow:0 0 2px rgba(0, 0, 0, 0.3);z-index:3;opacity:0;pointer-events:none}.co-rte-content .co-rte-embed.ProseMirror-selectednode .co-rte-embed__handle,.co-rte-content .co-rte-embed--selected .co-rte-embed__handle{opacity:1;pointer-events:auto}.co-rte-content .co-rte-embed__handle--bottom-right{right:-6px;bottom:-6px;cursor:nwse-resize}.co-rte-content .co-rte-embed__handle--bottom-left{left:-6px;bottom:-6px;cursor:nesw-resize}.co-rte-content .co-rte-embed--resizing{outline:2px dashed var(--co-color-base-negro, #1a1a1a);outline-offset:2px}.co-rich-text-editor--readonly .co-rte-embed::before,.co-rich-text-editor--disabled .co-rte-embed::before{display:none}.co-rich-text-editor--readonly .co-rte-embed.ProseMirror-selectednode,.co-rich-text-editor--readonly .co-rte-embed--selected,.co-rich-text-editor--disabled .co-rte-embed.ProseMirror-selectednode,.co-rich-text-editor--disabled .co-rte-embed--selected{outline:none !important}.co-rte-img-layout{position:absolute;z-index:50;display:flex;align-items:center;gap:2px;padding:4px;background:var(--co-semantic-surface-secondary, #fff);border:1px solid var(--co-semantic-border-default, #e0e0e0);border-radius:var(--co-border-radius-xs, 8px);box-shadow:0 2px 12px rgba(0, 0, 0, 0.12);pointer-events:auto}.co-rte-img-layout__btn{display:inline-flex;align-items:center;justify-content:center;width:34px;height:34px;padding:0;border:1px solid transparent;border-radius:var(--co-border-radius-xxs, 4px);background:transparent;color:var(--co-semantic-text-default, #333);cursor:pointer;transition:background 0.12s, border-color 0.12s}.co-rte-img-layout__btn:hover{background:var(--co-semantic-surface-hover, rgba(0, 0, 0, 0.06))}.co-rte-img-layout__btn--active{background:var(--co-color-base-negro, #1a1a1a);color:var(--co-color-base-blanco, #fff)}.co-rte-img-layout__btn--active:hover{background:var(--co-color-base-negro, #333)}.co-rte-img-layout__btn[data-tooltip]{position:relative}.co-rte-img-layout__btn[data-tooltip]::after{content:attr(data-tooltip);position:absolute;bottom:calc(100% + 6px);left:50%;transform:translateX(-50%);padding:4px 8px;background:var(--co-color-base-negro, #1a1a1a);color:var(--co-color-base-blanco, #fff);font-family:var(--co-font-family-primary);font-size:11px;font-weight:500;line-height:1.3;white-space:nowrap;border-radius:4px;pointer-events:none;opacity:0;transition:opacity 0.12s ease;z-index:100}.co-rte-img-layout__btn[data-tooltip]:hover::after{opacity:1;transition-delay:0.3s}.co-rte-content [data-resize-container][data-image-layout="wrap-left"]{float:left;max-width:50%;margin:4px 16px 8px 0}.co-rte-content [data-resize-container][data-image-layout="wrap-right"]{float:right;max-width:50%;margin:4px 0 8px 16px}.co-rte-content [data-resize-container][data-image-layout="center"]{display:block;margin:12px auto}.co-rte-content [data-resize-container][data-image-layout="full-width"]{display:block;width:100%;margin:12px 0}.co-rte-content [data-resize-container][data-image-layout="full-width"] [data-resize-wrapper],.co-rte-content [data-resize-container][data-image-layout="full-width"] img{width:100%}@media (max-width: 768px){.co-rte-content [data-resize-container][data-image-layout="wrap-left"],.co-rte-content [data-resize-container][data-image-layout="wrap-right"]{float:none;max-width:100%;display:block;margin:12px 0}}.co-rte-content--site .ProseMirror{width:var(--co-rte-content-width, 80%);max-width:100%;margin:0 auto}@media (max-width: 768px){.co-rte-content--site .ProseMirror{width:100%}}.co-rich-text-editor--readonly [data-resize-handle],.co-rich-text-editor--disabled [data-resize-handle]{display:none !important}.co-rich-text-editor--readonly [data-resize-container].ProseMirror-selectednode,.co-rich-text-editor--disabled [data-resize-container].ProseMirror-selectednode,.co-rich-text-editor--readonly img.ProseMirror-selectednode,.co-rich-text-editor--disabled img.ProseMirror-selectednode{outline:none !important}`;
5
8
 
6
9
  const CoRichTextEditor = class {
7
10
  constructor(hostRef) {
@@ -12,13 +15,13 @@ const CoRichTextEditor = class {
12
15
  this.coBlur = createEvent(this, "coBlur", 7);
13
16
  this.coClear = createEvent(this, "coClear", 7);
14
17
  this.coReady = createEvent(this, "coReady", 7);
18
+ this.coFontPopupShow = createEvent(this, "coFontPopupShow", 7);
19
+ this.coFontPopupHide = createEvent(this, "coFontPopupHide", 7);
15
20
  /** ProseMirror document as a JSON string. `null`/empty = empty editor. */
16
21
  this.value = null;
17
22
  /** Preset controlling allowed nodes/marks, toolbar and sanitization. */
18
23
  this.preset = 'task';
19
24
  this.placeholder = '';
20
- /** Label layout: vertical (label above) or horizontal (label beside) */
21
- this.layout = 'vertical';
22
25
  this.status = 'default';
23
26
  this.disabled = false;
24
27
  this.readonly = false;
@@ -27,42 +30,80 @@ const CoRichTextEditor = class {
27
30
  this.autofocus = false;
28
31
  /** Toolbar layout. `auto` uses the preset default. */
29
32
  this.toolbar = 'auto';
33
+ /** BCP-47 locale for UI strings (e.g. 'en', 'es-CO', 'pt-BR'). Default English. */
34
+ this.locale = 'en';
30
35
  this.ready = false;
31
36
  this.hasFocus = false;
37
+ /** Character count — updated imperatively to avoid re-renders on every keystroke. */
32
38
  this.charCount = 0;
33
- /** Last value we emitted — guards the value Watch against feedback loops. */
34
- this.lastEmitted = null;
39
+ this.bubbleDragged = false;
40
+ this.bubbleDragOffset = { x: 0, y: 0 };
41
+ this.bubbleDragPos = { x: 0, y: 0 };
42
+ /** Position lock — prevents floating-ui from repositioning the bubble during toolbar interactions. */
43
+ this.bubblePositionLocked = false;
44
+ this.bubbleLockPos = { x: 0, y: 0 };
45
+ this.applyingBubbleLock = false;
46
+ /** Account fonts loaded via fontLoader callback. */
47
+ this._loadedAccountFonts = [];
48
+ this._fontLoaderCalled = false;
49
+ this._fontLoaderLoading = false;
50
+ /** Last emitted JSON string — guards the value Watch against feedback loops. */
51
+ this.lastEmittedJson = null;
52
+ /** Last emitted HTML string — parents often send HTML back via value prop. */
53
+ this.lastEmittedHtml = '';
35
54
  /** True while applying an external value (suppresses emit). */
36
55
  this.applyingExternal = false;
37
- /** Set by disconnectedCallback — aborts editor creation if the element was
38
- * removed while the lazy import was still in flight (ProseMirror leak). */
39
- this.destroyed = false;
56
+ this.rt = RichText;
57
+ this.imgLayoutVisible = false;
40
58
  this.handleUpdate = (editor) => {
41
59
  this.refreshCharCount();
42
60
  if (this.applyingExternal)
43
61
  return;
44
62
  const out = this.buildOutput(editor);
45
- const next = out.json ? JSON.stringify(out.json) : null;
46
- this.lastEmitted = next;
47
- this.value = next;
63
+ // Track both JSON and HTML forms to prevent feedback loops.
64
+ // The parent may send back either format via the value prop.
65
+ this.lastEmittedJson = out.json ? JSON.stringify(out.json) : null;
66
+ this.lastEmittedHtml = out.html;
67
+ // Do NOT set this.value here — it triggers unnecessary Stencil re-renders
68
+ // and the Watch cycle. The parent is the source of truth for the value prop.
48
69
  this.coInput.emit(out);
70
+ // In readonly mode there's no blur cycle, so commit immediately
71
+ // (e.g. task-list checkbox toggled by onReadOnlyChecked).
72
+ if (this.readonly)
73
+ this.coChange.emit(out);
49
74
  };
50
75
  this.handleFocus = () => {
51
76
  this.hasFocus = true;
52
77
  this.coFocus.emit();
53
78
  };
54
79
  this.handleBlur = () => {
55
- this.hasFocus = false;
56
- if (this.editor)
57
- this.coChange.emit(this.buildOutput(this.editor));
58
- this.coBlur.emit();
80
+ // Delay blur processing — if the user clicked a toolbar button,
81
+ // chain().focus() will re-focus the editor before this timeout fires.
82
+ clearTimeout(this.blurTimeout);
83
+ this.blurTimeout = setTimeout(() => {
84
+ var _a, _b;
85
+ if ((_a = this.editor) === null || _a === void 0 ? void 0 : _a.isFocused)
86
+ return; // Focus was restored (toolbar click)
87
+ // Don't blur if focus moved to an element inside the bubble (e.g. hex input)
88
+ if ((_b = this.bubbleEl) === null || _b === void 0 ? void 0 : _b.contains(document.activeElement))
89
+ return;
90
+ this.hasFocus = false;
91
+ if (this.editor)
92
+ this.coChange.emit(this.buildOutput(this.editor));
93
+ this.coBlur.emit();
94
+ }, 100);
59
95
  };
60
96
  }
61
97
  async componentDidLoad() {
62
98
  var _a, _b;
63
- this.rt = await import('./index-BjAqSidM.js');
64
- if (this.destroyed || !this.contentEl)
99
+ if (!this.contentEl)
65
100
  return;
101
+ // Create bubble element imperatively so Stencil VDOM cannot interfere
102
+ // with BubbleMenu's DOM management (it calls element.remove/appendChild).
103
+ const showToolbar = this.resolvedToolbar !== 'none' && !this.readonly && !this.disabled;
104
+ if (showToolbar) {
105
+ this.bubbleEl = this.createBubbleElement();
106
+ }
66
107
  this.editor = this.rt.createEditor({
67
108
  preset: this.preset,
68
109
  element: this.contentEl,
@@ -72,40 +113,113 @@ const CoRichTextEditor = class {
72
113
  maxLength: this.maxLength,
73
114
  features: this.parsedFeatures,
74
115
  customExtensions: (_a = this.customExtensions) !== null && _a !== void 0 ? _a : [],
116
+ bubbleMenuElement: this.bubbleEl,
75
117
  imageUpload: this.imageUpload,
76
118
  onUpdate: (editor) => this.handleUpdate(editor),
77
119
  onFocus: () => this.handleFocus(),
78
120
  onBlur: () => this.handleBlur(),
79
121
  });
80
- this.lastEmitted = (_b = this.value) !== null && _b !== void 0 ? _b : null;
122
+ // Document / "site" preset: fluid ~80% content width (see editor.css). Marks
123
+ // both editable and readonly so the reader matches the author's measure.
124
+ if (this.preset === 'document') {
125
+ this.contentEl.classList.add('co-rte-content--site');
126
+ }
127
+ // Image layout toolbar — only when actually editable. The layout itself is
128
+ // CSS-driven (keyed on `data-image-layout`); the bar just lets the author
129
+ // pick a reflow mode (inline / wrap-left / wrap-right / center / full-width).
130
+ if (showToolbar && this.imagesEnabled) {
131
+ this.contentEl.style.position = 'relative'; // offset parent for the bar
132
+ this.imgLayoutEl = this.createImageLayoutBar();
133
+ this.contentEl.appendChild(this.imgLayoutEl);
134
+ }
135
+ // Update bubble active states on every transaction
136
+ this.editor.on('transaction', ({ transaction }) => {
137
+ if (this.bubbleEl) {
138
+ this.updateBubbleActiveStates();
139
+ if ((this.bubbleDragged || this.bubblePositionLocked) && this.bubbleEl) {
140
+ this.applyBubbleFixedPosition();
141
+ }
142
+ }
143
+ // Reapply floating-image positions only when the doc changed (skip pure
144
+ // selection/cursor moves to avoid a full descendants walk on every keystroke).
145
+ if (this.imagesEnabled && transaction.docChanged)
146
+ this.syncImageLayouts();
147
+ this.updateImageLayoutBar();
148
+ });
149
+ // Clicking the toolbar closes bubble popups (link form, panels, etc.)
150
+ if (this.bubbleEl && this.toolbarEl) {
151
+ this.toolbarEl.addEventListener('mousedown', () => {
152
+ this.closeBubbleDropdowns();
153
+ });
154
+ // Hide the selection bubble while a toolbar dropdown/popover is open so
155
+ // the two never overlap in the same space (the bubble lives inside the
156
+ // content area, right where toolbar dropdowns expand into).
157
+ this.toolbarEl.addEventListener('coPopoverChange', (e) => {
158
+ var _a;
159
+ const open = (_a = e.detail) === null || _a === void 0 ? void 0 : _a.open;
160
+ this.suppressBubble(!!open);
161
+ });
162
+ }
163
+ this.lastEmittedJson = (_b = this.value) !== null && _b !== void 0 ? _b : null;
81
164
  this.ready = true;
82
165
  this.refreshCharCount();
83
166
  this.syncToolbar();
84
167
  this.coReady.emit();
85
168
  if (this.autofocus)
86
169
  this.editor.commands.focus();
170
+ // Tag every image container with its layout mode so the CSS rules apply.
171
+ // Runs even without the layout toolbar (readonly/disabled viewers).
172
+ requestAnimationFrame(() => this.syncImageLayouts());
87
173
  }
88
174
  disconnectedCallback() {
89
- var _a;
90
- this.destroyed = true;
91
- (_a = this.editor) === null || _a === void 0 ? void 0 : _a.destroy();
175
+ var _a, _b, _c, _d;
176
+ clearTimeout(this.blurTimeout);
177
+ clearTimeout(this.bubbleLockTimer);
178
+ (_a = this.bubbleStyleObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
179
+ if (this.bubbleDragMoveHandler)
180
+ document.removeEventListener('mousemove', this.bubbleDragMoveHandler);
181
+ if (this.bubbleDragEndHandler)
182
+ document.removeEventListener('mouseup', this.bubbleDragEndHandler);
183
+ if (this.bubbleOutsideClickHandler)
184
+ document.removeEventListener('click', this.bubbleOutsideClickHandler, true);
185
+ (_b = this.editor) === null || _b === void 0 ? void 0 : _b.destroy();
92
186
  this.editor = undefined;
187
+ (_c = this.bubbleEl) === null || _c === void 0 ? void 0 : _c.remove();
188
+ (_d = this.imgLayoutEl) === null || _d === void 0 ? void 0 : _d.remove();
93
189
  }
94
190
  componentDidRender() {
95
191
  this.syncToolbar();
96
192
  }
193
+ onAccountFontsChange() {
194
+ var _a;
195
+ // Re-render the font dropdown list if it's open
196
+ if (this._fontDropdownRenderFn) {
197
+ const filter = ((_a = this._fontDropdownSearchInput) === null || _a === void 0 ? void 0 : _a.value) || '';
198
+ this._fontDropdownRenderFn(filter);
199
+ }
200
+ }
97
201
  onValueChange(next) {
98
202
  if (!this.editor || this.applyingExternal)
99
203
  return;
100
- if ((next !== null && next !== void 0 ? next : null) === this.lastEmitted)
204
+ const incoming = next !== null && next !== void 0 ? next : null;
205
+ // Skip if this value matches what we last emitted (JSON or HTML form).
206
+ // This prevents the destructive feedback loop where the parent sends
207
+ // back our own output and setContent resets the editor on every keystroke.
208
+ if (incoming === this.lastEmittedJson || incoming === this.lastEmittedHtml)
101
209
  return;
102
210
  this.applyingExternal = true;
103
211
  try {
104
- this.editor.commands.setContent(this.parseValue(next), { emitUpdate: false });
212
+ if (incoming === '' || incoming === null) {
213
+ this.editor.commands.clearContent(false);
214
+ }
215
+ else {
216
+ this.editor.commands.setContent(this.parseValue(next), { emitUpdate: false });
217
+ }
105
218
  }
106
219
  finally {
107
220
  this.applyingExternal = false;
108
- this.lastEmitted = next !== null && next !== void 0 ? next : null;
221
+ this.lastEmittedJson = incoming;
222
+ this.lastEmittedHtml = '';
109
223
  this.refreshCharCount();
110
224
  }
111
225
  }
@@ -143,6 +257,12 @@ const CoRichTextEditor = class {
143
257
  return (_a = this.editor) !== null && _a !== void 0 ? _a : null;
144
258
  }
145
259
  /* ── internals ── */
260
+ /** Whether the image node is enabled (mirrors presets.ts `wantImage` logic). */
261
+ get imagesEnabled() {
262
+ var _a;
263
+ const f = this.parsedFeatures;
264
+ return (_a = f === null || f === void 0 ? void 0 : f.image) !== null && _a !== void 0 ? _a : this.preset === 'document';
265
+ }
146
266
  get parsedFeatures() {
147
267
  if (!this.features)
148
268
  return undefined;
@@ -167,9 +287,7 @@ const CoRichTextEditor = class {
167
287
  }
168
288
  }
169
289
  sanitizeHtml(html) {
170
- // Same features as the schema — otherwise feature-enabled nodes (images,
171
- // variables) would survive in `json` but be stripped from `html`.
172
- return this.rt ? this.rt.sanitize(html, this.preset, this.parsedFeatures) : html;
290
+ return this.rt.sanitize(html, this.preset);
173
291
  }
174
292
  buildOutput(editor) {
175
293
  const empty = editor.isEmpty;
@@ -179,21 +297,191 @@ const CoRichTextEditor = class {
179
297
  text: editor.getText(),
180
298
  };
181
299
  }
300
+ /** Lock the bubble position so floating-ui doesn't reposition it. */
301
+ lockBubblePosition(durationMs = 1000) {
302
+ if (!this.bubbleEl)
303
+ return;
304
+ const rect = this.bubbleEl.getBoundingClientRect();
305
+ if (rect.width === 0)
306
+ return; // bubble not visible
307
+ this.bubbleLockPos = { x: rect.left, y: rect.top };
308
+ this.bubblePositionLocked = true;
309
+ clearTimeout(this.bubbleLockTimer);
310
+ this.bubbleLockTimer = setTimeout(() => {
311
+ this.bubblePositionLocked = false;
312
+ }, durationMs);
313
+ }
314
+ /** Apply fixed position to the bubble, overriding floating-ui. */
315
+ applyBubbleFixedPosition() {
316
+ if (!this.bubbleEl)
317
+ return;
318
+ const pos = this.bubbleDragged ? this.bubbleDragPos : this.bubbleLockPos;
319
+ this.applyingBubbleLock = true;
320
+ this.bubbleEl.style.position = 'fixed';
321
+ this.bubbleEl.style.top = `${pos.y}px`;
322
+ this.bubbleEl.style.left = `${pos.x}px`;
323
+ this.bubbleEl.style.transform = 'none';
324
+ this.bubbleEl.style.visibility = 'visible';
325
+ requestAnimationFrame(() => { this.applyingBubbleLock = false; });
326
+ }
327
+ /** Watch for floating-ui style changes and override them when locked/dragged. */
328
+ setupBubbleStyleObserver(bubble) {
329
+ // Use BubbleMenu plugin's onHide/onShow callbacks (dispatched as custom
330
+ // events from create-editor) for reliable drag state management.
331
+ // These fire synchronously inside hide()/show(), avoiding microtask races.
332
+ bubble.addEventListener('co-bubble-hide', () => {
333
+ this.bubbleDragged = false;
334
+ this.bubblePositionLocked = false;
335
+ clearTimeout(this.bubbleLockTimer);
336
+ this.closeBubbleDropdowns();
337
+ bubble.style.position = '';
338
+ bubble.style.top = '';
339
+ bubble.style.left = '';
340
+ bubble.style.transform = '';
341
+ });
342
+ bubble.addEventListener('co-bubble-show', () => {
343
+ this.bubbleDragged = false;
344
+ this.bubblePositionLocked = false;
345
+ });
346
+ // MutationObserver only handles overriding floating-ui position
347
+ // while the bubble is actively dragged or position-locked.
348
+ this.bubbleStyleObserver = new MutationObserver(() => {
349
+ if (this.applyingBubbleLock)
350
+ return;
351
+ if (!this.bubblePositionLocked && !this.bubbleDragged)
352
+ return;
353
+ this.applyBubbleFixedPosition();
354
+ });
355
+ this.bubbleStyleObserver.observe(bubble, {
356
+ attributes: true,
357
+ attributeFilter: ['style'],
358
+ });
359
+ }
360
+ /**
361
+ * Hide/show the selection bubble while a toolbar dropdown is open. Uses a
362
+ * class with `!important` so it wins over the BubbleMenu plugin's inline
363
+ * display/visibility writes. When unsuppressed, the plugin's own state
364
+ * (selection still active) reveals it again on the next update.
365
+ */
366
+ suppressBubble(on) {
367
+ if (!this.bubbleEl)
368
+ return;
369
+ this.bubbleEl.classList.toggle('co-rte-bubble--suppressed', on);
370
+ if (on)
371
+ this.closeBubbleDropdowns();
372
+ }
373
+ /** Close all open sub-dropdowns inside the bubble. */
374
+ closeBubbleDropdowns() {
375
+ if (!this.bubbleEl)
376
+ return;
377
+ this.bubbleEl.querySelectorAll('.co-rte-bubble__select-dropdown').forEach(d => {
378
+ d.style.display = 'none';
379
+ });
380
+ this.bubbleEl.querySelectorAll('.co-rte-bubble__color-dropdown').forEach(d => {
381
+ d.style.display = 'none';
382
+ });
383
+ this.bubbleEl.querySelectorAll('.co-rte-bubble__panel').forEach(d => {
384
+ d.style.display = 'none';
385
+ });
386
+ this.bubbleEl.querySelectorAll('.co-rte-bubble__overflow-menu').forEach(d => {
387
+ d.style.display = 'none';
388
+ });
389
+ if (this.bubbleLinkFormEl) {
390
+ this.bubbleLinkFormEl.style.display = 'none';
391
+ }
392
+ }
182
393
  refreshCharCount() {
183
394
  var _a;
184
395
  const storage = (_a = this.editor) === null || _a === void 0 ? void 0 : _a.storage;
185
- if (storage === null || storage === void 0 ? void 0 : storage.characterCount)
396
+ if (storage === null || storage === void 0 ? void 0 : storage.characterCount) {
186
397
  this.charCount = storage.characterCount.characters();
398
+ // Update DOM directly to avoid Stencil re-renders on every keystroke
399
+ if (this.charCountEl) {
400
+ this.charCountEl.textContent = this.maxLength != null
401
+ ? `${this.charCount} / ${this.maxLength}`
402
+ : `${this.charCount}`;
403
+ }
404
+ }
187
405
  }
188
406
  syncToolbar() {
189
407
  if (this.toolbarEl && this.editor && this.toolbarEl.editor !== this.editor) {
190
408
  this.toolbarEl.editor = this.editor;
191
409
  }
410
+ if (this.toolbarEl) {
411
+ this.toolbarEl.imageUpload = this.imageUpload;
412
+ }
192
413
  }
193
414
  get resolvedToolbar() {
194
415
  if (this.toolbar !== 'auto')
195
416
  return this.toolbar;
196
- return this.rt ? this.rt.defaultToolbarForPreset(this.preset) : 'basic';
417
+ return this.rt.defaultToolbarForPreset(this.preset);
418
+ }
419
+ get resolvedFontFamilies() {
420
+ if (!this.fontFamilies)
421
+ return CoRichTextEditor.DEFAULT_FONTS;
422
+ if (typeof this.fontFamilies === 'string') {
423
+ try {
424
+ return JSON.parse(this.fontFamilies);
425
+ }
426
+ catch (_a) {
427
+ return CoRichTextEditor.DEFAULT_FONTS;
428
+ }
429
+ }
430
+ return this.fontFamilies;
431
+ }
432
+ get resolvedAccountFonts() {
433
+ // Prefer prop over loaded fonts
434
+ if (this.accountFonts) {
435
+ if (typeof this.accountFonts === 'string') {
436
+ try {
437
+ return JSON.parse(this.accountFonts);
438
+ }
439
+ catch (_a) {
440
+ return [];
441
+ }
442
+ }
443
+ return this.accountFonts;
444
+ }
445
+ return this._loadedAccountFonts;
446
+ }
447
+ registerFontFace(name, url) {
448
+ if (!url || !name || CoRichTextEditor._registeredFonts.has(name))
449
+ return;
450
+ CoRichTextEditor._registeredFonts.add(name);
451
+ try {
452
+ const face = new FontFace(name, `url("${url}")`);
453
+ face.load().then(() => document.fonts.add(face)).catch(() => { });
454
+ }
455
+ catch ( /* ignore */_a) { /* ignore */ }
456
+ }
457
+ /** Load account fonts via the fontLoader callback (called once). */
458
+ async loadFontsViaCallback() {
459
+ var _a, _b, _c;
460
+ if (this._fontLoaderCalled || !this.fontLoader)
461
+ return;
462
+ this._fontLoaderCalled = true;
463
+ this._fontLoaderLoading = true;
464
+ // Re-render to show loading state
465
+ (_a = this._fontDropdownRenderFn) === null || _a === void 0 ? void 0 : _a.call(this, '');
466
+ try {
467
+ const fonts = await this.fontLoader();
468
+ if (Array.isArray(fonts)) {
469
+ this._loadedAccountFonts = fonts.map(f => {
470
+ if (f.url)
471
+ this.registerFontFace(f.label, f.url);
472
+ return { label: f.label, value: f.value };
473
+ });
474
+ }
475
+ }
476
+ catch (e) {
477
+ console.error('[co-rich-text-editor] fontLoader error', e);
478
+ }
479
+ finally {
480
+ this._fontLoaderLoading = false;
481
+ // Re-render with loaded fonts
482
+ const filter = ((_b = this._fontDropdownSearchInput) === null || _b === void 0 ? void 0 : _b.value) || '';
483
+ (_c = this._fontDropdownRenderFn) === null || _c === void 0 ? void 0 : _c.call(this, filter);
484
+ }
197
485
  }
198
486
  get helperIcon() {
199
487
  switch (this.status) {
@@ -203,20 +491,1546 @@ const CoRichTextEditor = class {
203
491
  default: return 'info';
204
492
  }
205
493
  }
494
+ /* ── Bubble menu (imperative — outside Stencil VDOM) ── */
495
+ /**
496
+ * Create the bubble menu element imperatively. BubbleMenu v3 manages
497
+ * the element via remove()/appendChild(), which conflicts with Stencil's
498
+ * virtual DOM reconciliation. By creating it outside the VDOM, Stencil
499
+ * won't recreate or interfere with the element.
500
+ */
501
+ createBubbleElement() {
502
+ const bubble = document.createElement('div');
503
+ bubble.className = 'co-rte-bubble';
504
+ // Start hidden and absolutely positioned so it never takes document flow space.
505
+ // BubbleMenu's floating-ui will manage position via inline styles when shown.
506
+ bubble.style.visibility = 'hidden';
507
+ bubble.style.position = 'absolute';
508
+ bubble.style.top = '0';
509
+ bubble.style.left = '0';
510
+ // Prevent any bubble click from stealing editor focus
511
+ // and lock bubble position during any toolbar interaction.
512
+ bubble.addEventListener('mousedown', (e) => {
513
+ if (e.target.tagName !== 'INPUT')
514
+ e.preventDefault();
515
+ this.lockBubblePosition();
516
+ });
517
+ // Close dropdowns/panels when clicking outside the bubble
518
+ this.bubbleOutsideClickHandler = (e) => {
519
+ if (!bubble.contains(e.target)) {
520
+ this.closeBubbleDropdowns();
521
+ }
522
+ };
523
+ document.addEventListener('click', this.bubbleOutsideClickHandler, true);
524
+ // Watch for floating-ui style overrides and restore locked position
525
+ this.setupBubbleStyleObserver(bubble);
526
+ const isDocument = this.preset === 'document';
527
+ /* ── Drag handle (document only) ── */
528
+ if (isDocument) {
529
+ const dragHandle = document.createElement('div');
530
+ dragHandle.className = 'co-rte-bubble__drag-handle';
531
+ dragHandle.innerHTML = `<co-icon name="dots-six-vertical" size="14"></co-icon>`;
532
+ dragHandle.addEventListener('mousedown', (e) => {
533
+ e.preventDefault();
534
+ e.stopPropagation();
535
+ const rect = bubble.getBoundingClientRect();
536
+ this.bubbleDragOffset = { x: e.clientX - rect.left, y: e.clientY - rect.top };
537
+ if (!this.bubbleDragged) {
538
+ this.bubbleDragPos = { x: rect.left, y: rect.top };
539
+ }
540
+ this.bubbleDragged = true;
541
+ this.bubbleDragMoveHandler = (ev) => {
542
+ this.bubbleDragPos.x = ev.clientX - this.bubbleDragOffset.x;
543
+ this.bubbleDragPos.y = ev.clientY - this.bubbleDragOffset.y;
544
+ bubble.style.position = 'fixed';
545
+ bubble.style.top = `${this.bubbleDragPos.y}px`;
546
+ bubble.style.left = `${this.bubbleDragPos.x}px`;
547
+ bubble.style.transform = 'none';
548
+ bubble.style.visibility = 'visible';
549
+ };
550
+ this.bubbleDragEndHandler = () => {
551
+ document.removeEventListener('mousemove', this.bubbleDragMoveHandler);
552
+ document.removeEventListener('mouseup', this.bubbleDragEndHandler);
553
+ };
554
+ document.addEventListener('mousemove', this.bubbleDragMoveHandler);
555
+ document.addEventListener('mouseup', this.bubbleDragEndHandler);
556
+ });
557
+ bubble.appendChild(dragHandle);
558
+ } // end isDocument drag handle
559
+ /* ── Single row: all controls ── */
560
+ const row = document.createElement('div');
561
+ row.className = 'co-rte-bubble__row';
562
+ // --- Advanced controls (document preset only) ---
563
+ // Panels will be appended to bubble root (not inside the row) at the end.
564
+ let fontSizePanel = null;
565
+ let fontWeightPanel = null;
566
+ let lineHeightPanelEl = null;
567
+ let letterSpacingPanelEl = null;
568
+ let bgColorPanelEl = null;
569
+ let overflowResult = null;
570
+ if (isDocument) {
571
+ // --- Font Family select (with search) ---
572
+ const fontFamilyWrap = this.createBubbleFontFamilySelect();
573
+ row.appendChild(fontFamilyWrap);
574
+ // --- Font Size panel (draggable with custom input) ---
575
+ fontSizePanel = this.createBubbleFontSizePanel();
576
+ row.appendChild(fontSizePanel.wrap);
577
+ // --- Font Weight panel (draggable, two-column) ---
578
+ fontWeightPanel = this.createBubbleFontWeightPanel();
579
+ row.appendChild(fontWeightPanel.wrap);
580
+ row.appendChild(this.createSep());
581
+ // --- Text color picker ---
582
+ const colorWrap = this.createBubbleColorPicker('textColor', (color) => {
583
+ if (!this.editor)
584
+ return;
585
+ this.editor.chain().focus().setColor(color).run();
586
+ });
587
+ row.appendChild(colorWrap);
588
+ row.appendChild(this.createSep());
589
+ } // end isDocument advanced controls
590
+ // --- B I U (all presets except comment which disables underline) ---
591
+ const _s = getRichTextStrings(this.locale);
592
+ const formatBtns = [
593
+ { action: 'bold', icon: 'text-b', label: _s.bold, check: 'bold' },
594
+ { action: 'italic', icon: 'text-italic', label: _s.italic, check: 'italic' },
595
+ ];
596
+ // Underline is available on task, email, document (not comment)
597
+ if (this.preset !== 'comment') {
598
+ formatBtns.push({ action: 'underline', icon: 'text-underline', label: _s.underline, check: 'underline' });
599
+ }
600
+ formatBtns.forEach(({ action, icon, label, check }) => {
601
+ const btn = this.createBubbleBtn(icon, label, action, check, () => {
602
+ if (!this.editor)
603
+ return;
604
+ const chain = this.editor.chain().focus();
605
+ switch (action) {
606
+ case 'bold':
607
+ chain.toggleBold().run();
608
+ break;
609
+ case 'italic':
610
+ chain.toggleItalic().run();
611
+ break;
612
+ case 'underline':
613
+ chain.toggleUnderline().run();
614
+ break;
615
+ }
616
+ });
617
+ row.appendChild(btn);
618
+ });
619
+ row.appendChild(this.createSep());
620
+ // --- Alignment buttons (document and email only) ---
621
+ if (isDocument || this.preset === 'email') {
622
+ const alignments = [
623
+ { align: 'left', icon: 'text-align-left', label: _s.alignLeft },
624
+ { align: 'center', icon: 'text-align-center', label: _s.center },
625
+ { align: 'right', icon: 'text-align-right', label: _s.alignRight },
626
+ { align: 'justify', icon: 'text-align-justify', label: _s.justify },
627
+ ];
628
+ alignments.forEach(({ align, icon, label }) => {
629
+ const btn = document.createElement('button');
630
+ btn.type = 'button';
631
+ btn.className = 'co-rte-bubble__btn';
632
+ btn.title = label;
633
+ btn.setAttribute('aria-label', label);
634
+ btn.setAttribute('data-action', 'textAlign');
635
+ btn.setAttribute('data-align', align);
636
+ btn.innerHTML = `<co-icon name="${icon}" size="16"></co-icon>`;
637
+ btn.addEventListener('click', () => {
638
+ if (!this.editor)
639
+ return;
640
+ this.editor.chain().focus().setTextAlign(align).run();
641
+ });
642
+ row.appendChild(btn);
643
+ });
644
+ row.appendChild(this.createSep());
645
+ } // end alignment
646
+ // --- Bullet / Ordered list (task, email — not comment, not document) ---
647
+ // For document preset, lists are moved to the overflow menu.
648
+ if (this.preset !== 'comment' && !isDocument) {
649
+ row.appendChild(this.createBubbleBtn('list-bullets', _s.bulletList, 'bulletList', 'bulletList', () => {
650
+ if (!this.editor)
651
+ return;
652
+ this.editor.chain().focus().toggleBulletList().run();
653
+ }));
654
+ row.appendChild(this.createBubbleBtn('list-numbers', _s.orderedList, 'orderedList', 'orderedList', () => {
655
+ if (!this.editor)
656
+ return;
657
+ this.editor.chain().focus().toggleOrderedList().run();
658
+ }));
659
+ row.appendChild(this.createSep());
660
+ } // end lists (non-document)
661
+ // --- Link (all presets) ---
662
+ const linkBtn = this.createBubbleBtn('link', _s.link, 'link', 'link', () => {
663
+ if (!this.editor)
664
+ return;
665
+ this.toggleBubbleLinkForm(true);
666
+ });
667
+ row.appendChild(linkBtn);
668
+ // --- Overflow menu (document only) ---
669
+ // Superscript, subscript, lists, strikethrough, bg color, line height,
670
+ // letter spacing, horizontal rule, clear formatting — all in overflow.
671
+ if (isDocument) {
672
+ row.appendChild(this.createSep());
673
+ lineHeightPanelEl = this.createBubbleLineHeightPanel();
674
+ letterSpacingPanelEl = this.createBubbleLetterSpacingPanel();
675
+ bgColorPanelEl = this.createBubbleBgColorPanel();
676
+ overflowResult = this.createBubbleOverflowMenu({
677
+ lineHeight: lineHeightPanelEl,
678
+ letterSpacing: letterSpacingPanelEl,
679
+ bgColor: bgColorPanelEl,
680
+ });
681
+ row.appendChild(overflowResult.overflowWrap);
682
+ } // end isDocument overflow
683
+ bubble.appendChild(row);
684
+ // Append floating panels to bubble root (outside the row, so they float freely)
685
+ if (isDocument) {
686
+ if (fontSizePanel)
687
+ bubble.appendChild(fontSizePanel.panelEl);
688
+ if (fontWeightPanel)
689
+ bubble.appendChild(fontWeightPanel.panelEl);
690
+ if (lineHeightPanelEl)
691
+ bubble.appendChild(lineHeightPanelEl);
692
+ if (letterSpacingPanelEl)
693
+ bubble.appendChild(letterSpacingPanelEl);
694
+ if (bgColorPanelEl)
695
+ bubble.appendChild(bgColorPanelEl);
696
+ }
697
+ // Link form (hidden by default)
698
+ const linkForm = document.createElement('div');
699
+ linkForm.className = 'co-rte-bubble__link-form';
700
+ linkForm.style.display = 'none';
701
+ this.bubbleLinkFormEl = linkForm;
702
+ const linkInput = document.createElement('input');
703
+ linkInput.type = 'url';
704
+ linkInput.className = 'co-rte-bubble__link-input';
705
+ linkInput.placeholder = 'https://...';
706
+ this.bubbleLinkInputEl = linkInput;
707
+ linkInput.addEventListener('keydown', (e) => {
708
+ if (e.key === 'Enter')
709
+ this.submitBubbleLinkImperative();
710
+ if (e.key === 'Escape')
711
+ this.toggleBubbleLinkForm(false);
712
+ });
713
+ const linkSubmit = document.createElement('button');
714
+ linkSubmit.type = 'button';
715
+ linkSubmit.className = 'co-rte-bubble__link-btn';
716
+ linkSubmit.innerHTML = `<co-icon name="check" size="14"></co-icon>`;
717
+ linkSubmit.addEventListener('click', () => this.submitBubbleLinkImperative());
718
+ const linkUnlink = document.createElement('button');
719
+ linkUnlink.type = 'button';
720
+ linkUnlink.className = 'co-rte-bubble__link-btn co-rte-bubble__link-unlink';
721
+ linkUnlink.title = _s.unlinkLink;
722
+ linkUnlink.innerHTML = `<co-icon name="link-break" size="14"></co-icon>`;
723
+ linkUnlink.addEventListener('click', () => {
724
+ if (!this.editor)
725
+ return;
726
+ this.editor.chain().focus().unsetLink().run();
727
+ this.toggleBubbleLinkForm(false);
728
+ });
729
+ this.bubbleLinkUnlinkEl = linkUnlink;
730
+ linkForm.appendChild(linkInput);
731
+ linkForm.appendChild(linkSubmit);
732
+ linkForm.appendChild(linkUnlink);
733
+ bubble.appendChild(linkForm);
734
+ return bubble;
735
+ }
736
+ /** Helper: create a separator span */
737
+ createSep() {
738
+ const sep = document.createElement('span');
739
+ sep.className = 'co-rte-bubble__sep';
740
+ return sep;
741
+ }
742
+ /**
743
+ * Position a dropdown above or below the trigger depending on available
744
+ * viewport space. Sets `data-position="above"|"below"` so CSS can flip.
745
+ */
746
+ positionDropdown(trigger, dropdown) {
747
+ const triggerRect = trigger.getBoundingClientRect();
748
+ // The dropdown is already display:block when this is called.
749
+ // Remove any previous position so it can be measured at its natural height.
750
+ dropdown.removeAttribute('data-position');
751
+ dropdown.style.removeProperty('left');
752
+ dropdown.style.removeProperty('transform');
753
+ const dropH = dropdown.offsetHeight || 320;
754
+ const dropW = dropdown.offsetWidth || 224;
755
+ const spaceAbove = triggerRect.top;
756
+ const spaceBelow = window.innerHeight - triggerRect.bottom;
757
+ if (spaceBelow >= dropH || spaceBelow > spaceAbove) {
758
+ dropdown.setAttribute('data-position', 'below');
759
+ }
760
+ else {
761
+ dropdown.setAttribute('data-position', 'above');
762
+ }
763
+ // Clamp horizontal position so the dropdown stays within the viewport.
764
+ // The dropdown is positioned relative to its parent (trigger wrapper).
765
+ // Default CSS uses left:50% + translateX(-50%) to center; we override
766
+ // when centering would push the dropdown outside the viewport.
767
+ const isColorDropdown = dropdown.classList.contains('co-rte-bubble__color-dropdown');
768
+ if (isColorDropdown) {
769
+ const parentRect = (trigger.parentElement || trigger).getBoundingClientRect();
770
+ // Desired center-aligned left edge in viewport coords
771
+ const idealLeft = parentRect.left + parentRect.width / 2 - dropW / 2;
772
+ const idealRight = idealLeft + dropW;
773
+ const viewportPad = 8;
774
+ if (idealLeft < viewportPad) {
775
+ // Would overflow left — align to left edge of trigger
776
+ dropdown.style.left = '0';
777
+ dropdown.style.transform = 'none';
778
+ }
779
+ else if (idealRight > window.innerWidth - viewportPad) {
780
+ // Would overflow right — align to right edge of trigger
781
+ dropdown.style.left = 'auto';
782
+ dropdown.style.right = '0';
783
+ dropdown.style.transform = 'none';
784
+ }
785
+ // else: default centering from CSS is fine
786
+ }
787
+ }
788
+ positionPanelNearBubble(panel) {
789
+ if (!this.bubbleEl)
790
+ return;
791
+ const overflowMenu = this.bubbleEl.querySelector('.co-rte-bubble__overflow-menu');
792
+ const anchorRect = overflowMenu && overflowMenu.style.display !== 'none'
793
+ ? overflowMenu.getBoundingClientRect()
794
+ : this.bubbleEl.getBoundingClientRect();
795
+ const panelH = panel.offsetHeight || 320;
796
+ const panelW = panel.offsetWidth || 230;
797
+ const gap = 4;
798
+ const pad = 8;
799
+ let top = anchorRect.top;
800
+ if (top + panelH > window.innerHeight - pad)
801
+ top = window.innerHeight - pad - panelH;
802
+ if (top < pad)
803
+ top = pad;
804
+ let left = anchorRect.left - panelW - gap;
805
+ if (left < pad)
806
+ left = anchorRect.right + gap;
807
+ if (left + panelW > window.innerWidth - pad)
808
+ left = window.innerWidth - pad - panelW;
809
+ panel.style.position = 'fixed';
810
+ panel.style.top = `${top}px`;
811
+ panel.style.left = `${left}px`;
812
+ panel.style.bottom = 'auto';
813
+ panel.style.right = 'auto';
814
+ panel.style.transform = 'none';
815
+ panel.removeAttribute('data-position');
816
+ }
817
+ /** Helper: create a toggle button for the bubble */
818
+ createBubbleBtn(icon, label, action, check, onClick) {
819
+ const btn = document.createElement('button');
820
+ btn.type = 'button';
821
+ btn.className = 'co-rte-bubble__btn';
822
+ btn.title = label;
823
+ btn.setAttribute('aria-label', label);
824
+ btn.setAttribute('data-action', action);
825
+ btn.setAttribute('data-check', check);
826
+ btn.innerHTML = `<co-icon name="${icon}" size="16"></co-icon>`;
827
+ btn.addEventListener('click', onClick);
828
+ return btn;
829
+ }
830
+ /** Creates the font family dropdown with search for the bubble menu. */
831
+ createBubbleFontFamilySelect() {
832
+ const wrap = document.createElement('div');
833
+ wrap.className = 'co-rte-bubble__select co-rte-bubble__select--font';
834
+ wrap.setAttribute('data-select', 'fontFamily');
835
+ const trigger = document.createElement('button');
836
+ trigger.type = 'button';
837
+ trigger.className = 'co-rte-bubble__select-trigger';
838
+ trigger.innerHTML = `<span class="co-rte-bubble__select-label">Sans-serif</span><co-icon name="caret-down" size="12"></co-icon>`;
839
+ const dropdown = document.createElement('div');
840
+ dropdown.className = 'co-rte-bubble__select-dropdown co-rte-bubble__select-dropdown--font';
841
+ dropdown.style.display = 'none';
842
+ // Search input
843
+ const searchWrap = document.createElement('div');
844
+ searchWrap.className = 'co-rte-bubble__font-search';
845
+ const searchInput = document.createElement('input');
846
+ searchInput.type = 'text';
847
+ searchInput.className = 'co-rte-bubble__font-search-input';
848
+ searchInput.placeholder = getRichTextStrings(this.locale).searchFont;
849
+ searchWrap.appendChild(searchInput);
850
+ dropdown.appendChild(searchWrap);
851
+ // Font list container
852
+ const listEl = document.createElement('div');
853
+ listEl.className = 'co-rte-bubble__font-list';
854
+ dropdown.appendChild(listEl);
855
+ const createFontOption = (label, value) => {
856
+ const opt = document.createElement('button');
857
+ opt.type = 'button';
858
+ opt.className = 'co-rte-bubble__select-option';
859
+ opt.setAttribute('data-value', value);
860
+ opt.textContent = label;
861
+ opt.style.fontFamily = value.includes(',') ? value : `"${value}", sans-serif`;
862
+ opt.addEventListener('click', () => {
863
+ if (!this.editor)
864
+ return;
865
+ this.editor.chain().focus().setFontFamily(value).run();
866
+ dropdown.style.display = 'none';
867
+ const labelEl = trigger.querySelector('.co-rte-bubble__select-label');
868
+ if (labelEl)
869
+ labelEl.textContent = label;
870
+ searchInput.value = '';
871
+ this.coFontPopupHide.emit();
872
+ });
873
+ return opt;
874
+ };
875
+ const renderFonts = (filter) => {
876
+ listEl.innerHTML = '';
877
+ const term = filter.toLowerCase();
878
+ const accountFonts = this.resolvedAccountFonts;
879
+ const systemFonts = this.resolvedFontFamilies;
880
+ const filteredAccount = term ? accountFonts.filter(f => f.label.toLowerCase().includes(term)) : accountFonts;
881
+ const filteredSystem = term ? systemFonts.filter(f => f.label.toLowerCase().includes(term)) : systemFonts;
882
+ if (!filteredAccount.length && !filteredSystem.length) {
883
+ const empty = document.createElement('div');
884
+ empty.className = 'co-rte-bubble__font-empty';
885
+ empty.textContent = getRichTextStrings(this.locale).noResults;
886
+ listEl.appendChild(empty);
887
+ return;
888
+ }
889
+ // Loading indicator
890
+ if ((this.fontsLoading || this._fontLoaderLoading) && !filteredAccount.length) {
891
+ const loading = document.createElement('div');
892
+ loading.className = 'co-rte-bubble__font-empty';
893
+ loading.textContent = getRichTextStrings(this.locale).loadingFonts;
894
+ listEl.appendChild(loading);
895
+ }
896
+ // Imported fonts section
897
+ if (filteredAccount.length) {
898
+ const header = document.createElement('div');
899
+ header.className = 'co-rte-bubble__font-section-header';
900
+ header.textContent = getRichTextStrings(this.locale).importedFonts;
901
+ listEl.appendChild(header);
902
+ filteredAccount.forEach(({ label, value }) => listEl.appendChild(createFontOption(label, value)));
903
+ }
904
+ // System fonts section
905
+ if (filteredSystem.length) {
906
+ const header = document.createElement('div');
907
+ header.className = 'co-rte-bubble__font-section-header';
908
+ header.textContent = getRichTextStrings(this.locale).systemFonts;
909
+ listEl.appendChild(header);
910
+ filteredSystem.forEach(({ label, value }) => listEl.appendChild(createFontOption(label, value)));
911
+ }
912
+ };
913
+ searchInput.addEventListener('input', () => renderFonts(searchInput.value));
914
+ // Re-render fonts when accountFonts prop changes (MutationObserver on the host)
915
+ this._fontDropdownRenderFn = renderFonts;
916
+ this._fontDropdownSearchInput = searchInput;
917
+ trigger.addEventListener('click', () => {
918
+ const parent = wrap.closest('.co-rte-bubble');
919
+ if (parent) {
920
+ parent.querySelectorAll('.co-rte-bubble__select-dropdown').forEach(d => {
921
+ if (d !== dropdown)
922
+ d.style.display = 'none';
923
+ });
924
+ parent.querySelectorAll('.co-rte-bubble__color-dropdown').forEach(d => {
925
+ d.style.display = 'none';
926
+ });
927
+ }
928
+ const isOpen = dropdown.style.display !== 'none';
929
+ dropdown.style.display = isOpen ? 'none' : 'block';
930
+ if (!isOpen) {
931
+ this.coFontPopupShow.emit();
932
+ this.loadFontsViaCallback();
933
+ this.positionDropdown(trigger, dropdown);
934
+ renderFonts('');
935
+ setTimeout(() => searchInput.focus(), 0);
936
+ }
937
+ else {
938
+ this.coFontPopupHide.emit();
939
+ }
940
+ });
941
+ wrap.appendChild(trigger);
942
+ wrap.appendChild(dropdown);
943
+ return wrap;
944
+ }
945
+ /** Creates a compact dropdown-select for the bubble menu. */
946
+ createBubbleSelect(name, options, defaultLabel, onChange) {
947
+ const wrap = document.createElement('div');
948
+ wrap.className = 'co-rte-bubble__select';
949
+ wrap.setAttribute('data-select', name);
950
+ const trigger = document.createElement('button');
951
+ trigger.type = 'button';
952
+ trigger.className = 'co-rte-bubble__select-trigger';
953
+ trigger.innerHTML = `<span class="co-rte-bubble__select-label">${defaultLabel}</span><co-icon name="caret-down" size="12"></co-icon>`;
954
+ const dropdown = document.createElement('div');
955
+ dropdown.className = 'co-rte-bubble__select-dropdown';
956
+ dropdown.style.display = 'none';
957
+ options.forEach(({ label, value }) => {
958
+ const opt = document.createElement('button');
959
+ opt.type = 'button';
960
+ opt.className = 'co-rte-bubble__select-option';
961
+ opt.setAttribute('data-value', value);
962
+ opt.textContent = label;
963
+ // Preview font weight in the option
964
+ if (name === 'fontWeight') {
965
+ opt.style.fontWeight = value;
966
+ }
967
+ opt.addEventListener('click', () => {
968
+ onChange(value);
969
+ dropdown.style.display = 'none';
970
+ const labelEl = trigger.querySelector('.co-rte-bubble__select-label');
971
+ if (labelEl)
972
+ labelEl.textContent = label;
973
+ });
974
+ dropdown.appendChild(opt);
975
+ });
976
+ trigger.addEventListener('click', () => {
977
+ // Close other open dropdowns in the bubble
978
+ const parent = wrap.closest('.co-rte-bubble');
979
+ if (parent) {
980
+ parent.querySelectorAll('.co-rte-bubble__select-dropdown').forEach(d => {
981
+ if (d !== dropdown)
982
+ d.style.display = 'none';
983
+ });
984
+ parent.querySelectorAll('.co-rte-bubble__color-dropdown').forEach(d => {
985
+ d.style.display = 'none';
986
+ });
987
+ }
988
+ const isOpen = dropdown.style.display !== 'none';
989
+ dropdown.style.display = isOpen ? 'none' : 'block';
990
+ if (!isOpen)
991
+ this.positionDropdown(trigger, dropdown);
992
+ });
993
+ wrap.appendChild(trigger);
994
+ wrap.appendChild(dropdown);
995
+ return wrap;
996
+ }
997
+ /** Creates a compact color picker button for the bubble menu. */
998
+ createBubbleColorPicker(name, onChange) {
999
+ const colors = [
1000
+ '#000000', '#434343', '#666666', '#999999', '#b7b7b7', '#cccccc',
1001
+ '#d9d9d9', '#efefef', '#f3f3f3', '#ffffff',
1002
+ '#980000', '#ff0000', '#ff9900', '#ffff00', '#00ff00', '#00ffff',
1003
+ '#4a86e8', '#0000ff', '#9900ff', '#ff00ff',
1004
+ '#e6b8af', '#f4cccc', '#fce5cd', '#fff2cc', '#d9ead3', '#d0e0e3',
1005
+ '#c9daf8', '#cfe2f3', '#d9d2e9', '#ead1dc',
1006
+ ];
1007
+ const wrap = document.createElement('div');
1008
+ wrap.className = 'co-rte-bubble__color';
1009
+ wrap.setAttribute('data-color', name);
1010
+ const iconName = name === 'textColor' ? '' : 'highlighter';
1011
+ const trigger = document.createElement('button');
1012
+ trigger.type = 'button';
1013
+ trigger.className = 'co-rte-bubble__btn';
1014
+ const _cs = getRichTextStrings(this.locale);
1015
+ trigger.title = name === 'textColor' ? _cs.textColor : _cs.backgroundColor;
1016
+ if (name === 'textColor') {
1017
+ trigger.innerHTML = `<span class="co-rte-bubble__color-indicator"><span class="co-rte-bubble__color-letter">A</span><span class="co-rte-bubble__color-bar" style="background:#000000"></span></span>`;
1018
+ }
1019
+ else {
1020
+ trigger.innerHTML = `<co-icon name="${iconName}" size="16"></co-icon>`;
1021
+ }
1022
+ const dropdown = document.createElement('div');
1023
+ dropdown.className = 'co-rte-bubble__color-dropdown';
1024
+ dropdown.style.display = 'none';
1025
+ const colorTitle = name === 'textColor' ? _cs.textColor : _cs.backgroundColor;
1026
+ const { resetDrag: resetColorDrag } = this.addDragHeader(dropdown, colorTitle);
1027
+ // Prevent focus loss
1028
+ dropdown.addEventListener('mousedown', (e) => {
1029
+ if (e.target.tagName !== 'INPUT')
1030
+ e.preventDefault();
1031
+ this.lockBubblePosition();
1032
+ });
1033
+ const grid = document.createElement('div');
1034
+ grid.className = 'co-rte-bubble__color-grid';
1035
+ colors.forEach(color => {
1036
+ const swatch = document.createElement('button');
1037
+ swatch.type = 'button';
1038
+ swatch.className = 'co-rte-bubble__color-swatch';
1039
+ swatch.style.background = color;
1040
+ if (color === '#ffffff') {
1041
+ swatch.style.border = '1px solid #e0e0e0';
1042
+ }
1043
+ swatch.addEventListener('click', () => {
1044
+ onChange(color);
1045
+ dropdown.style.display = 'none';
1046
+ });
1047
+ grid.appendChild(swatch);
1048
+ });
1049
+ // Hex input
1050
+ const hexRow = document.createElement('div');
1051
+ hexRow.className = 'co-rte-bubble__color-hex';
1052
+ const hexInput = document.createElement('input');
1053
+ hexInput.type = 'text';
1054
+ hexInput.className = 'co-rte-bubble__color-hex-input';
1055
+ hexInput.placeholder = '#hex';
1056
+ hexInput.maxLength = 7;
1057
+ hexInput.addEventListener('keydown', (e) => {
1058
+ if (e.key === 'Enter') {
1059
+ const val = hexInput.value.trim();
1060
+ if (/^#[0-9a-fA-F]{3,6}$/.test(val)) {
1061
+ onChange(val);
1062
+ dropdown.style.display = 'none';
1063
+ hexInput.value = '';
1064
+ }
1065
+ }
1066
+ });
1067
+ // Clear color button
1068
+ const clearBtn = document.createElement('button');
1069
+ clearBtn.type = 'button';
1070
+ clearBtn.className = 'co-rte-bubble__color-clear';
1071
+ clearBtn.innerHTML = `<co-icon name="x" size="12"></co-icon> ${_cs.noColor}`;
1072
+ clearBtn.addEventListener('click', () => {
1073
+ if (!this.editor)
1074
+ return;
1075
+ if (name === 'textColor')
1076
+ this.editor.chain().focus().unsetColor().run();
1077
+ else
1078
+ this.editor.chain().focus().unsetHighlight().run();
1079
+ dropdown.style.display = 'none';
1080
+ });
1081
+ dropdown.appendChild(grid);
1082
+ hexRow.appendChild(hexInput);
1083
+ dropdown.appendChild(hexRow);
1084
+ dropdown.appendChild(clearBtn);
1085
+ trigger.addEventListener('click', () => {
1086
+ const parent = wrap.closest('.co-rte-bubble');
1087
+ if (parent) {
1088
+ parent.querySelectorAll('.co-rte-bubble__select-dropdown').forEach(d => {
1089
+ d.style.display = 'none';
1090
+ });
1091
+ parent.querySelectorAll('.co-rte-bubble__color-dropdown').forEach(d => {
1092
+ if (d !== dropdown)
1093
+ d.style.display = 'none';
1094
+ });
1095
+ }
1096
+ const isOpen = dropdown.style.display !== 'none';
1097
+ if (isOpen) {
1098
+ dropdown.style.display = 'none';
1099
+ }
1100
+ else {
1101
+ resetColorDrag();
1102
+ dropdown.style.position = '';
1103
+ dropdown.style.top = '';
1104
+ dropdown.style.left = '';
1105
+ dropdown.style.bottom = '';
1106
+ dropdown.style.right = '';
1107
+ dropdown.style.transform = '';
1108
+ dropdown.style.display = 'block';
1109
+ this.positionDropdown(trigger, dropdown);
1110
+ }
1111
+ });
1112
+ wrap.appendChild(trigger);
1113
+ wrap.appendChild(dropdown);
1114
+ return wrap;
1115
+ }
1116
+ /** Close all bubble popups EXCEPT the given element. */
1117
+ closeAllBubblePopups(...except) {
1118
+ if (!this.bubbleEl)
1119
+ return;
1120
+ const keep = except.filter(Boolean);
1121
+ this.bubbleEl.querySelectorAll('.co-rte-bubble__select-dropdown').forEach(d => {
1122
+ if (!keep.includes(d))
1123
+ d.style.display = 'none';
1124
+ });
1125
+ this.bubbleEl.querySelectorAll('.co-rte-bubble__color-dropdown').forEach(d => {
1126
+ if (!keep.includes(d))
1127
+ d.style.display = 'none';
1128
+ });
1129
+ this.bubbleEl.querySelectorAll('.co-rte-bubble__panel').forEach(d => {
1130
+ if (!keep.includes(d))
1131
+ d.style.display = 'none';
1132
+ });
1133
+ this.bubbleEl.querySelectorAll('.co-rte-bubble__overflow-menu').forEach(d => {
1134
+ if (!keep.includes(d))
1135
+ d.style.display = 'none';
1136
+ });
1137
+ if (this.bubbleLinkFormEl && !keep.includes(this.bubbleLinkFormEl)) {
1138
+ this.bubbleLinkFormEl.style.display = 'none';
1139
+ }
1140
+ }
1141
+ addDragHeader(panel, title) {
1142
+ let dragged = false;
1143
+ let dragPos = { x: 0, y: 0 };
1144
+ let dragOffset = { x: 0, y: 0 };
1145
+ const header = document.createElement('div');
1146
+ header.className = 'co-rte-bubble__panel-header';
1147
+ const dragHandle = document.createElement('div');
1148
+ dragHandle.className = 'co-rte-bubble__panel-drag';
1149
+ dragHandle.innerHTML = `<co-icon name="dots-six" size="14"></co-icon>`;
1150
+ const titleEl = document.createElement('span');
1151
+ titleEl.className = 'co-rte-bubble__panel-title';
1152
+ titleEl.textContent = title;
1153
+ const closeBtn = document.createElement('button');
1154
+ closeBtn.type = 'button';
1155
+ closeBtn.className = 'co-rte-bubble__panel-close';
1156
+ closeBtn.innerHTML = `<co-icon name="x" size="14"></co-icon>`;
1157
+ closeBtn.addEventListener('click', () => { panel.style.display = 'none'; });
1158
+ header.appendChild(dragHandle);
1159
+ header.appendChild(titleEl);
1160
+ header.appendChild(closeBtn);
1161
+ dragHandle.addEventListener('mousedown', (e) => {
1162
+ e.preventDefault();
1163
+ e.stopPropagation();
1164
+ const rect = panel.getBoundingClientRect();
1165
+ dragOffset = { x: e.clientX - rect.left, y: e.clientY - rect.top };
1166
+ if (!dragged)
1167
+ dragPos = { x: rect.left, y: rect.top };
1168
+ dragged = true;
1169
+ const onMove = (ev) => {
1170
+ dragPos.x = ev.clientX - dragOffset.x;
1171
+ dragPos.y = ev.clientY - dragOffset.y;
1172
+ panel.style.position = 'fixed';
1173
+ panel.style.top = `${dragPos.y}px`;
1174
+ panel.style.left = `${dragPos.x}px`;
1175
+ panel.style.bottom = 'auto';
1176
+ panel.style.right = 'auto';
1177
+ panel.style.transform = 'none';
1178
+ panel.removeAttribute('data-position');
1179
+ };
1180
+ const onUp = () => {
1181
+ document.removeEventListener('mousemove', onMove);
1182
+ document.removeEventListener('mouseup', onUp);
1183
+ };
1184
+ document.addEventListener('mousemove', onMove);
1185
+ document.addEventListener('mouseup', onUp);
1186
+ });
1187
+ const resetDrag = () => { dragged = false; };
1188
+ panel.insertBefore(header, panel.firstChild);
1189
+ return { header, resetDrag };
1190
+ }
1191
+ /** Generic draggable panel factory. */
1192
+ createBubblePanel(config) {
1193
+ const wrap = document.createElement('div');
1194
+ wrap.className = 'co-rte-bubble__select';
1195
+ wrap.setAttribute('data-select', config.name);
1196
+ const trigger = document.createElement('button');
1197
+ trigger.type = 'button';
1198
+ trigger.className = 'co-rte-bubble__select-trigger';
1199
+ trigger.innerHTML = `<span class="co-rte-bubble__select-label">${config.triggerLabel}</span><co-icon name="caret-down" size="12"></co-icon>`;
1200
+ const panel = document.createElement('div');
1201
+ panel.className = 'co-rte-bubble__panel';
1202
+ panel.setAttribute('data-panel', config.name);
1203
+ panel.style.display = 'none';
1204
+ // Header
1205
+ const header = document.createElement('div');
1206
+ header.className = 'co-rte-bubble__panel-header';
1207
+ const dragHandle = document.createElement('div');
1208
+ dragHandle.className = 'co-rte-bubble__panel-drag';
1209
+ dragHandle.innerHTML = `<co-icon name="dots-six" size="14"></co-icon>`;
1210
+ const titleEl = document.createElement('span');
1211
+ titleEl.className = 'co-rte-bubble__panel-title';
1212
+ titleEl.textContent = config.title;
1213
+ const closeBtn = document.createElement('button');
1214
+ closeBtn.type = 'button';
1215
+ closeBtn.className = 'co-rte-bubble__panel-close';
1216
+ closeBtn.innerHTML = `<co-icon name="x" size="14"></co-icon>`;
1217
+ closeBtn.addEventListener('click', () => { panel.style.display = 'none'; });
1218
+ header.appendChild(dragHandle);
1219
+ header.appendChild(titleEl);
1220
+ header.appendChild(closeBtn);
1221
+ panel.appendChild(header);
1222
+ // Panel drag
1223
+ let panelDragged = false;
1224
+ let panelDragPos = { x: 0, y: 0 };
1225
+ let panelDragOffset = { x: 0, y: 0 };
1226
+ dragHandle.addEventListener('mousedown', (e) => {
1227
+ e.preventDefault();
1228
+ e.stopPropagation();
1229
+ const rect = panel.getBoundingClientRect();
1230
+ panelDragOffset = { x: e.clientX - rect.left, y: e.clientY - rect.top };
1231
+ if (!panelDragged)
1232
+ panelDragPos = { x: rect.left, y: rect.top };
1233
+ panelDragged = true;
1234
+ const onMove = (ev) => {
1235
+ panelDragPos.x = ev.clientX - panelDragOffset.x;
1236
+ panelDragPos.y = ev.clientY - panelDragOffset.y;
1237
+ panel.style.position = 'fixed';
1238
+ panel.style.top = `${panelDragPos.y}px`;
1239
+ panel.style.left = `${panelDragPos.x}px`;
1240
+ panel.style.bottom = 'auto';
1241
+ panel.style.right = 'auto';
1242
+ panel.style.transform = 'none';
1243
+ panel.removeAttribute('data-position');
1244
+ };
1245
+ const onUp = () => {
1246
+ document.removeEventListener('mousemove', onMove);
1247
+ document.removeEventListener('mouseup', onUp);
1248
+ };
1249
+ document.addEventListener('mousemove', onMove);
1250
+ document.addEventListener('mouseup', onUp);
1251
+ });
1252
+ // Custom input
1253
+ if (config.hasCustomInput) {
1254
+ const inputWrap = document.createElement('div');
1255
+ inputWrap.className = 'co-rte-bubble__panel-input-wrap';
1256
+ const input = document.createElement('input');
1257
+ input.type = config.inputType || 'text';
1258
+ input.className = 'co-rte-bubble__panel-input';
1259
+ input.placeholder = config.inputPlaceholder || '';
1260
+ input.addEventListener('mousedown', (e) => e.stopPropagation());
1261
+ input.addEventListener('keydown', (e) => {
1262
+ if (e.key === 'Enter') {
1263
+ const val = input.value.trim();
1264
+ if (val && config.onCustomInput) {
1265
+ config.onCustomInput(val);
1266
+ input.value = '';
1267
+ }
1268
+ }
1269
+ if (e.key === 'Escape') {
1270
+ panel.style.display = 'none';
1271
+ }
1272
+ });
1273
+ inputWrap.appendChild(input);
1274
+ panel.appendChild(inputWrap);
1275
+ }
1276
+ // Options
1277
+ const optionsWrap = document.createElement('div');
1278
+ optionsWrap.className = 'co-rte-bubble__panel-options';
1279
+ config.options.forEach(opt => {
1280
+ const btn = document.createElement('button');
1281
+ btn.type = 'button';
1282
+ btn.className = 'co-rte-bubble__panel-option';
1283
+ btn.setAttribute('data-value', opt.value);
1284
+ if (config.renderOption) {
1285
+ config.renderOption(opt, btn);
1286
+ }
1287
+ else {
1288
+ btn.textContent = opt.label;
1289
+ }
1290
+ btn.addEventListener('click', () => {
1291
+ config.onSelect(opt.value);
1292
+ panel.style.display = 'none';
1293
+ panelDragged = false;
1294
+ });
1295
+ optionsWrap.appendChild(btn);
1296
+ });
1297
+ panel.appendChild(optionsWrap);
1298
+ // Prevent bubble from losing focus
1299
+ panel.addEventListener('mousedown', (e) => {
1300
+ if (e.target.tagName !== 'INPUT')
1301
+ e.preventDefault();
1302
+ this.lockBubblePosition();
1303
+ });
1304
+ // Toggle logic
1305
+ const togglePanel = () => {
1306
+ this.closeAllBubblePopups(panel);
1307
+ const isOpen = panel.style.display !== 'none';
1308
+ if (isOpen) {
1309
+ panel.style.display = 'none';
1310
+ }
1311
+ else {
1312
+ panelDragged = false;
1313
+ panel.style.position = '';
1314
+ panel.style.top = '';
1315
+ panel.style.left = '';
1316
+ panel.style.bottom = '';
1317
+ panel.style.right = '';
1318
+ panel.style.transform = '';
1319
+ panel.style.display = 'block';
1320
+ this.positionDropdown(trigger, panel);
1321
+ }
1322
+ };
1323
+ trigger.addEventListener('click', togglePanel);
1324
+ wrap.appendChild(trigger);
1325
+ const updateLabel = (text) => {
1326
+ const labelEl = trigger.querySelector('.co-rte-bubble__select-label');
1327
+ if (labelEl)
1328
+ labelEl.textContent = text;
1329
+ };
1330
+ return { wrap, panelEl: panel, updateLabel };
1331
+ }
1332
+ /** Font size panel with visual preview and custom input. */
1333
+ createBubbleFontSizePanel() {
1334
+ const _fs = getRichTextStrings(this.locale);
1335
+ const headings = [
1336
+ { label: _fs.title, value: 'h1' },
1337
+ { label: _fs.heading1, value: 'h2' },
1338
+ { label: _fs.heading2, value: 'h3' },
1339
+ ];
1340
+ const sizes = ['8px', '10px', '12px', '14px', '16px', '18px', '20px', '24px', '28px', '32px', '36px', '48px', '64px', '72px'];
1341
+ const allOptions = [
1342
+ ...headings,
1343
+ { label: '---', value: '---' },
1344
+ ...sizes.map(s => ({ label: s, value: s })),
1345
+ ];
1346
+ return this.createBubblePanel({
1347
+ name: 'fontSize',
1348
+ title: _fs.fontSize,
1349
+ triggerLabel: '16px',
1350
+ hasCustomInput: true,
1351
+ inputType: 'number',
1352
+ inputPlaceholder: _fs.writeSize,
1353
+ options: allOptions,
1354
+ renderOption: (opt, btn) => {
1355
+ if (opt.value === '---') {
1356
+ btn.className = 'co-rte-bubble__panel-sep';
1357
+ btn.disabled = true;
1358
+ btn.style.pointerEvents = 'none';
1359
+ return;
1360
+ }
1361
+ if (opt.value === 'h1') {
1362
+ btn.textContent = opt.label;
1363
+ btn.style.fontSize = '24px';
1364
+ btn.style.fontWeight = '700';
1365
+ btn.style.padding = '6px 8px';
1366
+ }
1367
+ else if (opt.value === 'h2') {
1368
+ btn.textContent = opt.label;
1369
+ btn.style.fontSize = '18px';
1370
+ btn.style.fontWeight = '700';
1371
+ btn.style.padding = '5px 8px';
1372
+ }
1373
+ else if (opt.value === 'h3') {
1374
+ btn.textContent = opt.label;
1375
+ btn.style.fontSize = '15px';
1376
+ btn.style.fontWeight = '700';
1377
+ btn.style.padding = '4px 8px';
1378
+ }
1379
+ else {
1380
+ btn.textContent = opt.label;
1381
+ const px = parseInt(opt.value);
1382
+ btn.style.fontSize = `${Math.min(px, 36)}px`;
1383
+ btn.style.lineHeight = '1.3';
1384
+ }
1385
+ },
1386
+ onSelect: (val) => {
1387
+ if (!this.editor || val === '---')
1388
+ return;
1389
+ const chain = this.editor.chain().focus();
1390
+ if (val === 'h1')
1391
+ chain.toggleHeading({ level: 1 }).run();
1392
+ else if (val === 'h2')
1393
+ chain.toggleHeading({ level: 2 }).run();
1394
+ else if (val === 'h3')
1395
+ chain.toggleHeading({ level: 3 }).run();
1396
+ else
1397
+ chain.setFontSize(val).run();
1398
+ },
1399
+ onCustomInput: (val) => {
1400
+ if (!this.editor)
1401
+ return;
1402
+ const num = parseInt(val);
1403
+ if (num > 0)
1404
+ this.editor.chain().focus().setFontSize(`${num}px`).run();
1405
+ },
1406
+ });
1407
+ }
1408
+ /** Font weight panel with two-column layout and visual preview. */
1409
+ createBubbleFontWeightPanel() {
1410
+ const weights = [
1411
+ { label: 'Thin', value: '100' },
1412
+ { label: 'Extra Light', value: '200' },
1413
+ { label: 'Light', value: '300' },
1414
+ { label: 'Regular', value: '400' },
1415
+ { label: 'Medium', value: '500' },
1416
+ { label: 'Semi Bold', value: '600' },
1417
+ { label: 'Bold', value: '700' },
1418
+ { label: 'Extra Bold', value: '800' },
1419
+ { label: 'Black', value: '900' },
1420
+ ];
1421
+ return this.createBubblePanel({
1422
+ name: 'fontWeight',
1423
+ title: getRichTextStrings(this.locale).fontWeight,
1424
+ triggerLabel: 'Regular',
1425
+ hasCustomInput: false,
1426
+ options: weights,
1427
+ renderOption: (opt, btn) => {
1428
+ btn.style.fontWeight = opt.value;
1429
+ btn.innerHTML = `<span class="co-rte-bubble__panel-opt-row"><span>${opt.label}</span><span class="co-rte-bubble__panel-opt-value">${opt.value}</span></span>`;
1430
+ },
1431
+ onSelect: (val) => {
1432
+ if (!this.editor)
1433
+ return;
1434
+ this.editor.chain().focus().setFontWeight(val).run();
1435
+ },
1436
+ });
1437
+ }
1438
+ /** Line height panel with custom input. */
1439
+ createBubbleLineHeightPanel() {
1440
+ const options = [
1441
+ { label: '0.5', value: '0.5' },
1442
+ { label: '1', value: '1' },
1443
+ { label: '1.15', value: '1.15' },
1444
+ { label: '1.5', value: '1.5' },
1445
+ { label: '1.75', value: '1.75' },
1446
+ { label: '2', value: '2' },
1447
+ { label: '2.5', value: '2.5' },
1448
+ { label: '3', value: '3' },
1449
+ { label: '---', value: '---' },
1450
+ { label: '16px', value: '16px' },
1451
+ { label: '20px', value: '20px' },
1452
+ { label: '24px', value: '24px' },
1453
+ { label: '32px', value: '32px' },
1454
+ { label: '---', value: '---2' },
1455
+ { label: '100%', value: '100%' },
1456
+ { label: '150%', value: '150%' },
1457
+ { label: '200%', value: '200%' },
1458
+ ];
1459
+ const { panelEl } = this.createBubblePanel({
1460
+ name: 'lineHeight',
1461
+ title: getRichTextStrings(this.locale).lineSpacing,
1462
+ triggerLabel: '1.5',
1463
+ hasCustomInput: true,
1464
+ inputPlaceholder: '1.5, 20px, 150%...',
1465
+ options,
1466
+ renderOption: (opt, btn) => {
1467
+ if (opt.value.startsWith('---')) {
1468
+ btn.className = 'co-rte-bubble__panel-sep';
1469
+ btn.disabled = true;
1470
+ btn.style.pointerEvents = 'none';
1471
+ return;
1472
+ }
1473
+ btn.textContent = opt.label;
1474
+ },
1475
+ onSelect: (val) => {
1476
+ if (!this.editor || val.startsWith('---'))
1477
+ return;
1478
+ this.editor.chain().focus().setLineHeight(val).run();
1479
+ },
1480
+ onCustomInput: (val) => {
1481
+ if (!this.editor)
1482
+ return;
1483
+ this.editor.chain().focus().setLineHeight(val).run();
1484
+ },
1485
+ });
1486
+ return panelEl;
1487
+ }
1488
+ /** Letter spacing panel with custom input. */
1489
+ createBubbleLetterSpacingPanel() {
1490
+ const options = [
1491
+ { label: '-0.05em', value: '-0.05em' },
1492
+ { label: 'Normal', value: 'normal' },
1493
+ { label: '0.05em', value: '0.05em' },
1494
+ { label: '0.1em', value: '0.1em' },
1495
+ { label: '0.2em', value: '0.2em' },
1496
+ ];
1497
+ const { panelEl } = this.createBubblePanel({
1498
+ name: 'letterSpacing',
1499
+ title: getRichTextStrings(this.locale).letterSpacing,
1500
+ triggerLabel: getRichTextStrings(this.locale).normal,
1501
+ hasCustomInput: true,
1502
+ inputPlaceholder: 'Custom (em)...',
1503
+ options,
1504
+ onSelect: (val) => {
1505
+ if (!this.editor)
1506
+ return;
1507
+ if (val === 'normal')
1508
+ this.editor.chain().focus().unsetLetterSpacing().run();
1509
+ else
1510
+ this.editor.chain().focus().setLetterSpacing(val).run();
1511
+ },
1512
+ onCustomInput: (val) => {
1513
+ if (!this.editor)
1514
+ return;
1515
+ const v = val.includes('em') || val.includes('px') ? val : `${val}em`;
1516
+ this.editor.chain().focus().setLetterSpacing(v).run();
1517
+ },
1518
+ });
1519
+ return panelEl;
1520
+ }
1521
+ /** Background color panel for overflow menu. */
1522
+ createBubbleBgColorPanel() {
1523
+ const bgColorWrap = this.createBubbleColorPicker('bgColor', (color) => {
1524
+ if (!this.editor)
1525
+ return;
1526
+ this.editor.chain().focus().toggleHighlight({ color }).run();
1527
+ });
1528
+ // Hide the trigger button — bg color is only opened from the overflow menu.
1529
+ const triggerBtn = bgColorWrap.querySelector('.co-rte-bubble__btn');
1530
+ if (triggerBtn)
1531
+ triggerBtn.style.display = 'none';
1532
+ return bgColorWrap;
1533
+ }
1534
+ /** Overflow menu (three-dots ⋮) with dynamic table context section. */
1535
+ createBubbleOverflowMenu(panels) {
1536
+ const wrap = document.createElement('div');
1537
+ wrap.className = 'co-rte-bubble__overflow';
1538
+ const btn = document.createElement('button');
1539
+ btn.type = 'button';
1540
+ btn.className = 'co-rte-bubble__btn';
1541
+ const _os = getRichTextStrings(this.locale);
1542
+ btn.title = _os.moreOptions;
1543
+ btn.setAttribute('aria-label', _os.moreOptions);
1544
+ btn.innerHTML = `<co-icon name="dots-three" size="16"></co-icon>`;
1545
+ const menu = document.createElement('div');
1546
+ menu.className = 'co-rte-bubble__overflow-menu';
1547
+ menu.style.display = 'none';
1548
+ const { resetDrag: resetOverflowDrag } = this.addDragHeader(menu, _os.moreOptions);
1549
+ // Prevent focus loss
1550
+ menu.addEventListener('mousedown', (e) => {
1551
+ if (e.target.tagName !== 'INPUT')
1552
+ e.preventDefault();
1553
+ this.lockBubblePosition();
1554
+ });
1555
+ const items = [
1556
+ { icon: 'text-strikethrough', label: _os.strikethrough, action: 'strike', check: 'strike', type: 'toggle' },
1557
+ { icon: 'highlighter', label: _os.backgroundColor, action: 'bgColor', type: 'panel', panel: panels.bgColor },
1558
+ { icon: 'list-bullets', label: _os.bulletList, action: 'bulletList', check: 'bulletList', type: 'toggle' },
1559
+ { icon: 'list-numbers', label: _os.orderedList, action: 'orderedList', check: 'orderedList', type: 'toggle' },
1560
+ { icon: 'text-superscript', label: _os.superscript, action: 'superscript', check: 'superscript', type: 'toggle' },
1561
+ { icon: 'text-subscript', label: _os.subscript, action: 'subscript', check: 'subscript', type: 'toggle' },
1562
+ { icon: 'line-segments', label: _os.lineSpacing, action: 'lineHeight', type: 'panel', panel: panels.lineHeight, valueAttr: 'lineHeight' },
1563
+ { icon: 'text-aa', label: _os.letterSpacing, action: 'letterSpacing', type: 'panel', panel: panels.letterSpacing, valueAttr: 'letterSpacing' },
1564
+ { icon: 'minus', label: _os.horizontalRule, action: 'horizontalRule', type: 'toggle' },
1565
+ { icon: 'eraser', label: _os.clearFormat, action: 'clearFormat', type: 'toggle' },
1566
+ ];
1567
+ items.forEach((item) => {
1568
+ if (item.action === 'lineHeight' || item.action === 'horizontalRule') {
1569
+ const sep = document.createElement('div');
1570
+ sep.className = 'co-rte-bubble__overflow-sep';
1571
+ menu.appendChild(sep);
1572
+ }
1573
+ const itemBtn = document.createElement('button');
1574
+ itemBtn.type = 'button';
1575
+ itemBtn.className = 'co-rte-bubble__overflow-item';
1576
+ itemBtn.setAttribute('data-overflow-item', item.action);
1577
+ if (item.check)
1578
+ itemBtn.setAttribute('data-check', item.check);
1579
+ let valueSpan = '';
1580
+ if (item.valueAttr) {
1581
+ valueSpan = `<span class="co-rte-bubble__overflow-value" data-overflow-value="${item.valueAttr}"></span>`;
1582
+ }
1583
+ itemBtn.innerHTML = `<co-icon name="${item.icon}" size="16"></co-icon><span>${item.label}</span>${valueSpan}`;
1584
+ itemBtn.addEventListener('click', () => {
1585
+ if (!this.editor)
1586
+ return;
1587
+ if (item.type === 'panel' && item.panel) {
1588
+ if (item.action === 'bgColor') {
1589
+ const dd = item.panel.querySelector('.co-rte-bubble__color-dropdown');
1590
+ if (dd) {
1591
+ const isOpen = dd.style.display !== 'none';
1592
+ this.closeAllBubblePopups(menu, isOpen ? undefined : dd);
1593
+ dd.style.display = isOpen ? 'none' : 'block';
1594
+ if (!isOpen)
1595
+ this.positionPanelNearBubble(dd);
1596
+ }
1597
+ }
1598
+ else {
1599
+ const isOpen = item.panel.style.display !== 'none';
1600
+ this.closeAllBubblePopups(menu, isOpen ? undefined : item.panel);
1601
+ item.panel.style.display = isOpen ? 'none' : 'block';
1602
+ if (!isOpen)
1603
+ this.positionPanelNearBubble(item.panel);
1604
+ }
1605
+ return;
1606
+ }
1607
+ const chain = this.editor.chain().focus();
1608
+ switch (item.action) {
1609
+ case 'strike':
1610
+ chain.toggleStrike().run();
1611
+ break;
1612
+ case 'bulletList':
1613
+ chain.toggleBulletList().run();
1614
+ break;
1615
+ case 'orderedList':
1616
+ chain.toggleOrderedList().run();
1617
+ break;
1618
+ case 'superscript':
1619
+ chain.toggleSuperscript().run();
1620
+ break;
1621
+ case 'subscript':
1622
+ chain.toggleSubscript().run();
1623
+ break;
1624
+ case 'horizontalRule':
1625
+ chain.setHorizontalRule().run();
1626
+ menu.style.display = 'none';
1627
+ break;
1628
+ case 'clearFormat':
1629
+ chain.unsetAllMarks().clearNodes().run();
1630
+ menu.style.display = 'none';
1631
+ break;
1632
+ }
1633
+ });
1634
+ menu.appendChild(itemBtn);
1635
+ });
1636
+ // ── Table context section (hidden by default, shown when cursor is in a table) ──
1637
+ const tableSection = document.createElement('div');
1638
+ tableSection.className = 'co-rte-bubble__overflow-table-section';
1639
+ tableSection.style.display = 'none';
1640
+ const tableSep = document.createElement('div');
1641
+ tableSep.className = 'co-rte-bubble__overflow-sep';
1642
+ tableSection.appendChild(tableSep);
1643
+ const tableHeader = document.createElement('div');
1644
+ tableHeader.className = 'co-rte-bubble__overflow-section-title';
1645
+ tableHeader.textContent = _os.tableOptions;
1646
+ tableSection.appendChild(tableHeader);
1647
+ const tableItems = [
1648
+ { action: 'addColumnBefore', icon: 'columns-plus-left', label: _os.addColumnBefore },
1649
+ { action: 'addColumnAfter', icon: 'columns-plus-right', label: _os.addColumnAfter },
1650
+ { action: 'addRowBefore', icon: 'rows-plus-top', label: _os.addRowAbove },
1651
+ { action: 'addRowAfter', icon: 'rows-plus-bottom', label: _os.addRowBelow },
1652
+ { action: 'mergeCells', icon: 'arrows-merge', label: _os.mergeCells },
1653
+ { action: 'splitCell', icon: 'arrows-split', label: _os.splitCell },
1654
+ { action: 'toggleHeaderRow', icon: 'rows', label: _os.headerRow },
1655
+ ];
1656
+ tableItems.forEach(({ action, icon, label }) => {
1657
+ const tBtn = document.createElement('button');
1658
+ tBtn.type = 'button';
1659
+ tBtn.className = 'co-rte-bubble__overflow-item';
1660
+ tBtn.setAttribute('data-overflow-item', action);
1661
+ if (action === 'toggleHeaderRow')
1662
+ tBtn.setAttribute('data-check', 'toggleHeaderRow');
1663
+ tBtn.innerHTML = `<co-icon name="${icon}" size="16"></co-icon><span>${label}</span>`;
1664
+ tBtn.addEventListener('click', () => {
1665
+ if (!this.editor)
1666
+ return;
1667
+ const chain = this.editor.chain().focus();
1668
+ switch (action) {
1669
+ case 'addColumnAfter':
1670
+ chain.addColumnAfter().run();
1671
+ break;
1672
+ case 'addColumnBefore':
1673
+ chain.addColumnBefore().run();
1674
+ break;
1675
+ case 'addRowAfter':
1676
+ chain.addRowAfter().run();
1677
+ break;
1678
+ case 'addRowBefore':
1679
+ chain.addRowBefore().run();
1680
+ break;
1681
+ case 'mergeCells':
1682
+ chain.mergeCells().run();
1683
+ break;
1684
+ case 'splitCell':
1685
+ chain.splitCell().run();
1686
+ break;
1687
+ case 'toggleHeaderRow':
1688
+ chain.toggleHeaderRow().run();
1689
+ break;
1690
+ }
1691
+ });
1692
+ tableSection.appendChild(tBtn);
1693
+ });
1694
+ // Danger items (delete column, row, table)
1695
+ const dangerSep = document.createElement('div');
1696
+ dangerSep.className = 'co-rte-bubble__overflow-sep';
1697
+ tableSection.appendChild(dangerSep);
1698
+ const dangerItems = [
1699
+ { action: 'deleteColumn', icon: 'minus-square', label: _os.deleteColumn },
1700
+ { action: 'deleteRow', icon: 'x-square', label: _os.deleteRow },
1701
+ { action: 'deleteTable', icon: 'trash', label: _os.deleteTable },
1702
+ ];
1703
+ dangerItems.forEach(({ action, icon, label }) => {
1704
+ const dBtn = document.createElement('button');
1705
+ dBtn.type = 'button';
1706
+ dBtn.className = 'co-rte-bubble__overflow-item co-rte-bubble__overflow-item--danger';
1707
+ dBtn.setAttribute('data-overflow-item', action);
1708
+ dBtn.innerHTML = `<co-icon name="${icon}" size="16"></co-icon><span>${label}</span>`;
1709
+ dBtn.addEventListener('click', () => {
1710
+ if (!this.editor)
1711
+ return;
1712
+ const chain = this.editor.chain().focus();
1713
+ switch (action) {
1714
+ case 'deleteColumn':
1715
+ chain.deleteColumn().run();
1716
+ break;
1717
+ case 'deleteRow':
1718
+ chain.deleteRow().run();
1719
+ break;
1720
+ case 'deleteTable':
1721
+ chain.deleteTable().run();
1722
+ menu.style.display = 'none';
1723
+ break;
1724
+ }
1725
+ });
1726
+ tableSection.appendChild(dBtn);
1727
+ });
1728
+ menu.appendChild(tableSection);
1729
+ btn.addEventListener('click', () => {
1730
+ this.closeAllBubblePopups(menu);
1731
+ const isOpen = menu.style.display !== 'none';
1732
+ if (isOpen) {
1733
+ menu.style.display = 'none';
1734
+ }
1735
+ else {
1736
+ resetOverflowDrag();
1737
+ menu.style.position = '';
1738
+ menu.style.top = '';
1739
+ menu.style.left = '';
1740
+ menu.style.bottom = '';
1741
+ menu.style.right = '';
1742
+ menu.style.transform = '';
1743
+ menu.style.display = 'block';
1744
+ this.positionDropdown(btn, menu);
1745
+ }
1746
+ });
1747
+ wrap.appendChild(btn);
1748
+ wrap.appendChild(menu);
1749
+ return { overflowWrap: wrap, overflowMenu: menu };
1750
+ }
1751
+ toggleBubbleLinkForm(show) {
1752
+ var _a, _b;
1753
+ if (!this.bubbleLinkFormEl || !this.bubbleLinkInputEl)
1754
+ return;
1755
+ this.bubbleLinkFormEl.style.display = show ? 'flex' : 'none';
1756
+ if (show) {
1757
+ const existing = ((_a = this.editor) === null || _a === void 0 ? void 0 : _a.isActive('link'))
1758
+ ? ((_b = this.editor.getAttributes('link')) === null || _b === void 0 ? void 0 : _b.href) || ''
1759
+ : '';
1760
+ this.bubbleLinkInputEl.value = existing;
1761
+ if (this.bubbleLinkUnlinkEl) {
1762
+ this.bubbleLinkUnlinkEl.style.display = existing ? 'flex' : 'none';
1763
+ }
1764
+ setTimeout(() => { var _a; return (_a = this.bubbleLinkInputEl) === null || _a === void 0 ? void 0 : _a.focus(); }, 0);
1765
+ }
1766
+ }
1767
+ submitBubbleLinkImperative() {
1768
+ if (!this.editor || !this.bubbleLinkInputEl)
1769
+ return;
1770
+ const url = this.bubbleLinkInputEl.value.trim();
1771
+ if (!url) {
1772
+ this.toggleBubbleLinkForm(false);
1773
+ return;
1774
+ }
1775
+ this.editor.chain().focus().setLink({ href: url }).run();
1776
+ this.toggleBubbleLinkForm(false);
1777
+ }
1778
+ updateBubbleActiveStates() {
1779
+ if (!this.editor || !this.bubbleEl)
1780
+ return;
1781
+ // Toggle buttons (bold, italic, etc.)
1782
+ const btns = this.bubbleEl.querySelectorAll('.co-rte-bubble__btn[data-check]');
1783
+ btns.forEach(btn => {
1784
+ const check = btn.getAttribute('data-check');
1785
+ if (check) {
1786
+ btn.classList.toggle('co-rte-bubble__btn--active', this.editor.isActive(check));
1787
+ }
1788
+ });
1789
+ // Alignment buttons
1790
+ const alignBtns = this.bubbleEl.querySelectorAll('.co-rte-bubble__btn[data-align]');
1791
+ alignBtns.forEach(btn => {
1792
+ const align = btn.getAttribute('data-align');
1793
+ if (align) {
1794
+ btn.classList.toggle('co-rte-bubble__btn--active', this.editor.isActive({ textAlign: align }));
1795
+ }
1796
+ });
1797
+ // Font family label
1798
+ const ffLabel = this.bubbleEl.querySelector('[data-select="fontFamily"] .co-rte-bubble__select-label');
1799
+ if (ffLabel) {
1800
+ const attrs = this.editor.getAttributes('textStyle');
1801
+ const family = (attrs === null || attrs === void 0 ? void 0 : attrs.fontFamily) || '';
1802
+ ffLabel.textContent = family ? family.split(',')[0].replace(/['"]/g, '').trim() : 'Sans-serif';
1803
+ }
1804
+ // Font size label (panel trigger)
1805
+ const fsTrigger = this.bubbleEl.querySelector('[data-select="fontSize"] .co-rte-bubble__select-label');
1806
+ if (fsTrigger) {
1807
+ const attrs = this.editor.getAttributes('textStyle');
1808
+ const _us = getRichTextStrings(this.locale);
1809
+ if (this.editor.isActive('heading', { level: 1 }))
1810
+ fsTrigger.textContent = _us.title;
1811
+ else if (this.editor.isActive('heading', { level: 2 }))
1812
+ fsTrigger.textContent = _us.headingAbbr1;
1813
+ else if (this.editor.isActive('heading', { level: 3 }))
1814
+ fsTrigger.textContent = _us.headingAbbr2;
1815
+ else
1816
+ fsTrigger.textContent = (attrs === null || attrs === void 0 ? void 0 : attrs.fontSize) || '16px';
1817
+ }
1818
+ // Font weight label (panel trigger)
1819
+ const fwTrigger = this.bubbleEl.querySelector('[data-select="fontWeight"] .co-rte-bubble__select-label');
1820
+ if (fwTrigger) {
1821
+ const attrs = this.editor.getAttributes('textStyle');
1822
+ const w = (attrs === null || attrs === void 0 ? void 0 : attrs.fontWeight) || '400';
1823
+ const wMap = { '100': 'Thin', '200': 'Extra Light', '300': 'Light', '400': 'Regular', '500': 'Medium', '600': 'Semi-bold', '700': 'Bold', '800': 'Extra-bold', '900': 'Black' };
1824
+ fwTrigger.textContent = wMap[w] || 'Regular';
1825
+ }
1826
+ // Overflow menu items active states
1827
+ const overflowItems = this.bubbleEl.querySelectorAll('.co-rte-bubble__overflow-item[data-check]');
1828
+ overflowItems.forEach(item => {
1829
+ const check = item.getAttribute('data-check');
1830
+ if (check) {
1831
+ item.classList.toggle('co-rte-bubble__overflow-item--active', this.editor.isActive(check));
1832
+ }
1833
+ });
1834
+ // Line height value in overflow (lineHeight is a block-level attribute on paragraph/heading)
1835
+ const lhValue = this.bubbleEl.querySelector('[data-overflow-value="lineHeight"]');
1836
+ if (lhValue) {
1837
+ const pAttrs = this.editor.getAttributes('paragraph');
1838
+ const hAttrs = this.editor.getAttributes('heading');
1839
+ lhValue.textContent = (pAttrs === null || pAttrs === void 0 ? void 0 : pAttrs.lineHeight) || (hAttrs === null || hAttrs === void 0 ? void 0 : hAttrs.lineHeight) || '';
1840
+ }
1841
+ // Letter spacing value in overflow
1842
+ const lsValue = this.bubbleEl.querySelector('[data-overflow-value="letterSpacing"]');
1843
+ if (lsValue) {
1844
+ const attrs = this.editor.getAttributes('textStyle');
1845
+ lsValue.textContent = (attrs === null || attrs === void 0 ? void 0 : attrs.letterSpacing) || '';
1846
+ }
1847
+ // Text color indicator bar
1848
+ const colorBar = this.bubbleEl.querySelector('.co-rte-bubble__color-bar');
1849
+ if (colorBar) {
1850
+ const attrs = this.editor.getAttributes('textStyle');
1851
+ colorBar.style.background = (attrs === null || attrs === void 0 ? void 0 : attrs.color) || '#000000';
1852
+ }
1853
+ // Table context section — show/hide based on cursor position
1854
+ const tableSection = this.bubbleEl.querySelector('.co-rte-bubble__overflow-table-section');
1855
+ if (tableSection) {
1856
+ const inTable = this.editor.isActive('table');
1857
+ tableSection.style.display = inTable ? 'block' : 'none';
1858
+ // Toggle header row active state
1859
+ if (inTable) {
1860
+ const headerBtn = tableSection.querySelector('[data-overflow-item="toggleHeaderRow"]');
1861
+ if (headerBtn) {
1862
+ const view = this.editor.view;
1863
+ const { $anchor } = this.editor.state.selection;
1864
+ let d = $anchor.depth;
1865
+ let hasHeader = false;
1866
+ while (d > 0) {
1867
+ if ($anchor.node(d).type.name === 'table') {
1868
+ const domEl = view.nodeDOM($anchor.start(d) - 1);
1869
+ if (domEl) {
1870
+ const tbl = domEl.querySelector('table') || domEl;
1871
+ const firstRow = tbl.querySelector('tr');
1872
+ hasHeader = firstRow ? firstRow.querySelector('th') !== null : false;
1873
+ }
1874
+ break;
1875
+ }
1876
+ d--;
1877
+ }
1878
+ headerBtn.classList.toggle('co-rte-bubble__overflow-item--active', hasHeader);
1879
+ }
1880
+ }
1881
+ }
1882
+ }
1883
+ createImageLayoutBar() {
1884
+ const bar = document.createElement('div');
1885
+ bar.className = 'co-rte-img-layout';
1886
+ bar.style.display = 'none';
1887
+ bar.addEventListener('mousedown', (e) => {
1888
+ e.preventDefault();
1889
+ e.stopPropagation();
1890
+ });
1891
+ const s = getRichTextStrings(this.locale);
1892
+ const labels = {
1893
+ 'inline': s.imageLayoutInline,
1894
+ 'wrap-left': s.imageLayoutWrapLeft,
1895
+ 'wrap-right': s.imageLayoutWrapRight,
1896
+ 'center': s.imageLayoutCenter,
1897
+ 'full-width': s.imageLayoutFullWidth,
1898
+ };
1899
+ const keys = ['inline', 'wrap-left', 'wrap-right', 'center', 'full-width'];
1900
+ keys.forEach(key => {
1901
+ const btn = document.createElement('button');
1902
+ btn.type = 'button';
1903
+ btn.className = 'co-rte-img-layout__btn';
1904
+ btn.setAttribute('data-layout', key);
1905
+ // Fast CSS tooltip (avoids the slow native `title` delay).
1906
+ btn.setAttribute('data-tooltip', labels[key] || key);
1907
+ btn.setAttribute('aria-label', labels[key] || key);
1908
+ btn.innerHTML = `<co-icon name="${CoRichTextEditor.IMG_LAYOUT_ICONS[key]}" size="18"></co-icon>`;
1909
+ btn.addEventListener('click', () => this.setImageLayout(key));
1910
+ bar.appendChild(btn);
1911
+ });
1912
+ return bar;
1913
+ }
1914
+ setImageLayout(layout) {
1915
+ if (!this.editor || !this.contentEl)
1916
+ return;
1917
+ const { state } = this.editor;
1918
+ const sel = state.selection;
1919
+ if (sel.constructor.name !== 'NodeSelection')
1920
+ return;
1921
+ const node = sel.node;
1922
+ if ((node === null || node === void 0 ? void 0 : node.type.name) !== 'image')
1923
+ return;
1924
+ const pos = sel.from;
1925
+ const tr = state.tr.setNodeMarkup(pos, undefined, Object.assign(Object.assign({}, node.attrs), { imageLayout: layout }));
1926
+ this.editor.view.dispatch(tr);
1927
+ this.editor.commands.setNodeSelection(pos);
1928
+ requestAnimationFrame(() => {
1929
+ this.syncImageLayouts();
1930
+ this.updateImageLayoutBar();
1931
+ });
1932
+ }
1933
+ getSelectedImageInfo() {
1934
+ var _a;
1935
+ if (!this.editor)
1936
+ return null;
1937
+ const { state } = this.editor;
1938
+ const sel = state.selection;
1939
+ if (sel.constructor.name !== 'NodeSelection')
1940
+ return null;
1941
+ const node = sel.node;
1942
+ if ((node === null || node === void 0 ? void 0 : node.type.name) !== 'image')
1943
+ return null;
1944
+ const pos = sel.from;
1945
+ const domNode = this.editor.view.nodeDOM(pos);
1946
+ if (!domNode)
1947
+ return null;
1948
+ const container = (((_a = domNode.closest) === null || _a === void 0 ? void 0 : _a.call(domNode, '[data-resize-container]')) || domNode);
1949
+ return { node, pos, container };
1950
+ }
1951
+ /**
1952
+ * Tag every image container with its layout mode (`data-image-layout`) so the
1953
+ * stylesheet's responsive rules apply, and clear any stray inline positioning
1954
+ * left over from legacy absolute-positioned content. Layout is CSS-only now
1955
+ * (it reflows and collapses on mobile); we only set the attribute here.
1956
+ *
1957
+ * Runs on every transaction. The resize NodeView's `onUpdate` returns `true`,
1958
+ * so ProseMirror never reflects attribute changes to the DOM — we must read
1959
+ * from state and write the attribute imperatively to the container.
1960
+ */
1961
+ syncImageLayouts() {
1962
+ if (!this.editor)
1963
+ return;
1964
+ const view = this.editor.view;
1965
+ this.editor.state.doc.descendants((node, pos) => {
1966
+ var _a;
1967
+ if (node.type.name !== 'image')
1968
+ return true;
1969
+ const dom = view.nodeDOM(pos);
1970
+ const c = (((_a = dom === null || dom === void 0 ? void 0 : dom.closest) === null || _a === void 0 ? void 0 : _a.call(dom, '[data-resize-container]')) || dom);
1971
+ if (!c)
1972
+ return true;
1973
+ c.dataset.imageLayout = node.attrs.imageLayout || 'inline';
1974
+ // Neutralise any absolute positioning baked by the old fixed-page model.
1975
+ c.style.position = '';
1976
+ c.style.left = '';
1977
+ c.style.top = '';
1978
+ c.style.zIndex = '';
1979
+ return true;
1980
+ });
1981
+ }
1982
+ /** Reposition only the layout bar (used during drag for performance). */
1983
+ updateImageLayoutBarPosition() {
1984
+ if (!this.imgLayoutEl || !this.contentEl)
1985
+ return;
1986
+ const info = this.getSelectedImageInfo();
1987
+ if (!info)
1988
+ return;
1989
+ const containerRect = info.container.getBoundingClientRect();
1990
+ const contentRect = this.contentEl.getBoundingClientRect();
1991
+ const barWidth = this.imgLayoutEl.offsetWidth || 194;
1992
+ let leftPos = (containerRect.left + containerRect.width / 2) - contentRect.left + this.contentEl.scrollLeft - barWidth / 2;
1993
+ leftPos = Math.max(4, Math.min(leftPos, contentRect.width - barWidth - 4));
1994
+ const topPos = containerRect.bottom - contentRect.top + this.contentEl.scrollTop + 8;
1995
+ this.imgLayoutEl.style.left = `${leftPos}px`;
1996
+ this.imgLayoutEl.style.top = `${topPos}px`;
1997
+ }
1998
+ updateImageLayoutBar() {
1999
+ if (!this.imgLayoutEl || !this.editor)
2000
+ return;
2001
+ const info = this.getSelectedImageInfo();
2002
+ if (!info) {
2003
+ if (this.imgLayoutVisible) {
2004
+ this.imgLayoutEl.style.display = 'none';
2005
+ this.imgLayoutVisible = false;
2006
+ }
2007
+ return;
2008
+ }
2009
+ this.imgLayoutEl.style.display = 'flex';
2010
+ this.imgLayoutVisible = true;
2011
+ this.updateImageLayoutBarPosition();
2012
+ const currentLayout = info.node.attrs.imageLayout || 'inline';
2013
+ this.imgLayoutEl.querySelectorAll('.co-rte-img-layout__btn').forEach(btn => {
2014
+ btn.classList.toggle('co-rte-img-layout__btn--active', btn.getAttribute('data-layout') === currentLayout);
2015
+ });
2016
+ }
206
2017
  render() {
207
2018
  const showToolbar = this.resolvedToolbar !== 'none' && !this.readonly && !this.disabled;
208
2019
  const showCount = this.showCharacterCount || this.maxLength != null;
209
- return (h("div", { key: 'c853d865716114025949e33e011394d824e4a961', class: {
2020
+ return (h("div", { key: 'd24b8e5db1151bcd983790ea15f68aaf4838ff43', class: {
210
2021
  'co-rich-text-editor': true,
211
2022
  'co-rich-text-editor--focused': this.hasFocus,
212
2023
  'co-rich-text-editor--disabled': this.disabled,
213
2024
  'co-rich-text-editor--readonly': this.readonly,
214
2025
  'co-rich-text-editor--loading': !this.ready,
215
2026
  [`co-rich-text-editor--${this.status}`]: this.status !== 'default',
216
- }, part: "wrapper" }, (this.label || this.secondaryLabel) && (h("div", { key: '049a14875b801e745c91f28410474d8139a366e6', class: "co-rich-text-editor__labels" }, this.label && h("label", { key: '4221652dd84a86192d84ba8889eafbd311ac27dd', class: "co-rich-text-editor__label", part: "label" }, this.label, h(RequiredMark, { key: '6576f8bdd8c744f6f4fd2990e3c3b58806a03bd4', required: this.required })), this.secondaryLabel && (h("span", { key: '5c28820cf466f06900ae3981b780f6664a14ca08', class: "co-rich-text-editor__secondary-label" }, this.secondaryLabel)))), h("div", { key: '94557b815f4dd9bfd33f2d4ae613554a54a391ad', class: "co-rich-text-editor__box" }, showToolbar && (h("co-rich-text-toolbar", { key: '7727dc54776263c3ef56f274e09d7d851df245d8', class: "co-rich-text-editor__toolbar", part: "toolbar", variant: this.resolvedToolbar, disabled: this.disabled || this.readonly, ref: (el) => (this.toolbarEl = el) })), h("div", { key: 'd81af8d3887e1f77062eb64efe02cda157f77216', class: "co-rte-content", part: "content", role: "textbox", "aria-multiline": "true", "aria-label": this.label, "aria-required": this.required ? 'true' : undefined, "aria-invalid": this.status === 'error' ? 'true' : undefined, ref: (el) => (this.contentEl = el) })), h("div", { key: 'f747db5469b5a805e88101cb7670432dc114c30f', class: "co-rich-text-editor__footer" }, this.helperText && (h("div", { key: '80c703179448310e86a16e908cc29edfc73260ba', class: `co-rich-text-editor__helper co-rich-text-editor__helper--${this.status}`, part: "helper" }, h("co-icon", { key: '7411c41c32e7c1845983df2608f604f764585230', name: this.helperIcon, size: 14 }), h("span", { key: 'be108ca9544684e2d6d0dbf68eca65d11f3c841b' }, this.helperText))), showCount && (h("span", { key: '5c88aeb55460778024664510a58ca9d331ef10c7', class: "co-rich-text-editor__count" }, this.charCount, this.maxLength != null ? ` / ${this.maxLength}` : '')))));
2027
+ }, part: "wrapper" }, (this.label || this.secondaryLabel) && (h("div", { key: '1622079a94d8ebb190642f91463b715f3456fcf4', class: "co-rich-text-editor__labels" }, this.label && h("label", { key: 'bb5c0754a63d46d45ce8f211ae0f0e8c4ddbc478', class: "co-rich-text-editor__label", part: "label" }, this.label), this.secondaryLabel && (h("span", { key: '1af0a217a38746c3a78693c552be44df6d03b276', class: "co-rich-text-editor__secondary-label" }, this.secondaryLabel)))), h("div", { key: 'e5ad90dd90061be3e40136eece0f485e5cfb89a1', class: "co-rich-text-editor__frame" }, showToolbar && (h("co-rich-text-toolbar", { key: '56f3da29e9259cd37fdf6e7511dc54efb30085ca', class: "co-rich-text-editor__toolbar", part: "toolbar", variant: this.resolvedToolbar, disabled: this.disabled || this.readonly, locale: this.locale, ref: (el) => (this.toolbarEl = el) })), h("div", { key: 'bb0dc27e8625171284cae02b5cae28dcbe638991', class: "co-rich-text-editor__box" }, h("div", { key: '647563e73112023ec546418787dbf61acb58853d', class: "co-rte-content", part: "content", role: "textbox", "aria-multiline": "true", "aria-label": this.label, "aria-required": this.required ? 'true' : undefined, "aria-invalid": this.status === 'error' ? 'true' : undefined, ref: (el) => (this.contentEl = el) }))), h("div", { key: '460dad69fd1781f11d751565d0ca09015013e8ce', class: "co-rich-text-editor__footer" }, this.helperText && (h("div", { key: '69d8fb55797eb8f35885fa10e86cf08e4d0e45ec', class: `co-rich-text-editor__helper co-rich-text-editor__helper--${this.status}`, part: "helper" }, h("co-icon", { key: 'd1c3cc4f06284b865c889dac7492305a4b7d8dfd', name: this.helperIcon, size: 14 }), h("span", { key: '361940f354fcee5a309cd2ef5cff84b73689650e' }, this.helperText))), showCount && (h("span", { key: '2b5a1b6e04ba3d428346034d092bf83978de0124', class: "co-rich-text-editor__count", ref: (el) => (this.charCountEl = el) }, this.charCount, this.maxLength != null ? ` / ${this.maxLength}` : '')))));
217
2028
  }
218
2029
  get el() { return getElement(this); }
219
2030
  static get watchers() { return {
2031
+ "accountFonts": [{
2032
+ "onAccountFontsChange": 0
2033
+ }],
220
2034
  "value": [{
221
2035
  "onValueChange": 0
222
2036
  }],
@@ -228,6 +2042,38 @@ const CoRichTextEditor = class {
228
2042
  }]
229
2043
  }; }
230
2044
  };
2045
+ CoRichTextEditor.DEFAULT_FONTS = [
2046
+ { label: 'Arial', value: 'Arial, sans-serif' },
2047
+ { label: 'Calibri', value: 'Calibri, sans-serif' },
2048
+ { label: 'Cambria', value: 'Cambria, serif' },
2049
+ { label: 'Comic Sans MS', value: "'Comic Sans MS', cursive" },
2050
+ { label: 'Courier New', value: "'Courier New', monospace" },
2051
+ { label: 'Georgia', value: 'Georgia, serif' },
2052
+ { label: 'Geist', value: "'Geist', sans-serif" },
2053
+ { label: 'Helvetica', value: 'Helvetica, Arial, sans-serif' },
2054
+ { label: 'Impact', value: 'Impact, sans-serif' },
2055
+ { label: 'Inter', value: "'Inter', sans-serif" },
2056
+ { label: 'Lato', value: "'Lato', sans-serif" },
2057
+ { label: 'Montserrat', value: "'Montserrat', sans-serif" },
2058
+ { label: 'Open Sans', value: "'Open Sans', sans-serif" },
2059
+ { label: 'Poppins', value: "'Poppins', sans-serif" },
2060
+ { label: 'Roboto', value: "'Roboto', sans-serif" },
2061
+ { label: 'Segoe UI', value: "'Segoe UI', sans-serif" },
2062
+ { label: 'Tahoma', value: 'Tahoma, sans-serif' },
2063
+ { label: 'Times New Roman', value: "'Times New Roman', serif" },
2064
+ { label: 'Trebuchet MS', value: "'Trebuchet MS', sans-serif" },
2065
+ { label: 'Verdana', value: 'Verdana, sans-serif' },
2066
+ ];
2067
+ /** Register a font via FontFace API so it can be previewed. */
2068
+ CoRichTextEditor._registeredFonts = new Set();
2069
+ /* ── Image layout bar (Google-Docs-style toolbar below selected image) ── */
2070
+ CoRichTextEditor.IMG_LAYOUT_ICONS = {
2071
+ 'inline': 'image-square',
2072
+ 'wrap-left': 'text-align-left',
2073
+ 'wrap-right': 'text-align-right',
2074
+ 'center': 'text-align-center',
2075
+ 'full-width': 'arrows-horizontal',
2076
+ };
231
2077
  CoRichTextEditor.style = coRichTextEditorCss();
232
2078
 
233
2079
  export { CoRichTextEditor as co_rich_text_editor };