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