@prolibu-suite/cobalt-core 0.10.4 → 0.11.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 (736) hide show
  1. package/custom-elements.json +4362 -388
  2. package/dist/cjs/co-accordion.cjs.entry.js +3 -3
  3. package/dist/cjs/co-action-bar.cjs.entry.js +3 -3
  4. package/dist/cjs/co-app-shell.cjs.entry.js +3 -3
  5. package/dist/cjs/co-audio-player.cjs.entry.js +4 -4
  6. package/dist/cjs/co-autocomplete.cjs.entry.js +2 -2
  7. package/dist/cjs/co-avatar-group.cjs.entry.js +1 -1
  8. package/dist/cjs/co-avatar.cjs.entry.js +7 -4
  9. package/dist/cjs/co-badge.cjs.entry.js +2 -2
  10. package/dist/cjs/co-bottom-sheet.cjs.entry.js +5 -5
  11. package/dist/cjs/co-breadcrumb-item.cjs.entry.js +3 -3
  12. package/dist/cjs/co-breadcrumb.cjs.entry.js +2 -2
  13. package/dist/cjs/co-button-group.cjs.entry.js +3 -3
  14. package/dist/cjs/co-button.cjs.entry.js +9 -7
  15. package/dist/cjs/co-calendar-month_2.cjs.entry.js +4 -4
  16. package/dist/cjs/co-calendar_3.cjs.entry.js +72 -27
  17. package/dist/cjs/co-card.cjs.entry.js +3 -3
  18. package/dist/cjs/co-carousel-item.cjs.entry.js +2 -2
  19. package/dist/cjs/co-carousel.cjs.entry.js +3 -3
  20. package/dist/cjs/co-checkbox-group.cjs.entry.js +1 -1
  21. package/dist/cjs/co-checkbox.cjs.entry.js +13 -5
  22. package/dist/cjs/co-chip_2.cjs.entry.js +9 -6
  23. package/dist/cjs/co-color-area.cjs.entry.js +169 -0
  24. package/dist/cjs/co-color-picker.cjs.entry.js +5 -5
  25. package/dist/cjs/co-color-slider.cjs.entry.js +189 -0
  26. package/dist/cjs/co-column-picker.cjs.entry.js +3 -3
  27. package/dist/cjs/co-combobox.cjs.entry.js +5 -5
  28. package/dist/cjs/co-command-search.cjs.entry.js +5 -5
  29. package/dist/cjs/co-data-table-pagination.cjs.entry.js +5 -5
  30. package/dist/cjs/co-data-table.cjs.entry.js +3 -3
  31. package/dist/cjs/co-date-picker.cjs.entry.js +2 -2
  32. package/dist/cjs/co-date-range-picker.cjs.entry.js +2 -2
  33. package/dist/cjs/co-date-range.cjs.entry.js +2 -2
  34. package/dist/cjs/co-date-time-picker.cjs.entry.js +4 -4
  35. package/dist/cjs/co-document-editor.cjs.entry.js +1161 -0
  36. package/dist/cjs/co-drive-card.cjs.entry.js +2 -2
  37. package/dist/cjs/co-drop-zone.cjs.entry.js +2 -2
  38. package/dist/cjs/co-emoji-picker.cjs.entry.js +3 -3
  39. package/dist/cjs/co-empty-state.cjs.entry.js +3 -3
  40. package/dist/cjs/co-event-calendar.cjs.entry.js +3 -3
  41. package/dist/cjs/co-event-popover.cjs.entry.js +3 -3
  42. package/dist/cjs/co-fab.cjs.entry.js +3 -3
  43. package/dist/cjs/co-file-field.cjs.entry.js +8 -8
  44. package/dist/cjs/co-file-type-tile.cjs.entry.js +3 -3
  45. package/dist/cjs/co-gradient-bar.cjs.entry.js +220 -0
  46. package/dist/cjs/co-helper-text.cjs.entry.js +3 -3
  47. package/dist/cjs/co-icon-button.cjs.entry.js +49 -9
  48. package/dist/cjs/co-icon.cjs.entry.js +3 -3
  49. package/dist/cjs/co-input.cjs.entry.js +14 -8
  50. package/dist/cjs/co-json-field.cjs.entry.js +5 -5
  51. package/dist/cjs/{co-tooltip.cjs.entry.js → co-kbd_2.cjs.entry.js} +194 -6
  52. package/dist/cjs/co-lightbox.cjs.entry.js +5 -5
  53. package/dist/cjs/co-list-footer.cjs.entry.js +2 -2
  54. package/dist/cjs/co-list-item.cjs.entry.js +5 -5
  55. package/dist/cjs/co-loader.cjs.entry.js +1 -1
  56. package/dist/cjs/co-media-thumb.cjs.entry.js +3 -3
  57. package/dist/cjs/co-menu-divider.cjs.entry.js +3 -3
  58. package/dist/cjs/co-menu-item.cjs.entry.js +41 -43
  59. package/dist/cjs/co-menu.cjs.entry.js +81 -5
  60. package/dist/cjs/co-modal.cjs.entry.js +350 -7
  61. package/dist/cjs/co-navbar.cjs.entry.js +3 -3
  62. package/dist/cjs/co-number-field.cjs.entry.js +5 -5
  63. package/dist/cjs/co-overlay.cjs.entry.js +8 -4
  64. package/dist/cjs/co-page-header.cjs.entry.js +2 -2
  65. package/dist/cjs/co-phone-field.cjs.entry.js +3 -3
  66. package/dist/cjs/co-popover.cjs.entry.js +67 -6
  67. package/dist/cjs/co-progress-bar.cjs.entry.js +3 -3
  68. package/dist/cjs/co-progress-circle.cjs.entry.js +3 -3
  69. package/dist/cjs/co-provider-logo_2.cjs.entry.js +2 -2
  70. package/dist/cjs/co-radio-group.cjs.entry.js +4 -4
  71. package/dist/cjs/co-radio.cjs.entry.js +4 -4
  72. package/dist/cjs/co-rating.cjs.entry.js +4 -4
  73. package/dist/cjs/co-ref-field.cjs.entry.js +5 -5
  74. package/dist/cjs/co-rich-text-editor.cjs.entry.js +26 -92
  75. package/dist/cjs/co-rich-text-toolbar.cjs.entry.js +79 -20
  76. package/dist/cjs/co-rich-text-viewer.cjs.entry.js +9 -2
  77. package/dist/cjs/co-row.cjs.entry.js +3 -3
  78. package/dist/cjs/co-segmented-bar.cjs.entry.js +3 -3
  79. package/dist/cjs/co-select.cjs.entry.js +158 -29
  80. package/dist/cjs/co-separator.cjs.entry.js +2 -2
  81. package/dist/cjs/co-sidebar-nav.cjs.entry.js +20 -5
  82. package/dist/cjs/co-sidebar.cjs.entry.js +3 -3
  83. package/dist/cjs/co-slider.cjs.entry.js +203 -23
  84. package/dist/cjs/co-swatch-grid.cjs.entry.js +121 -0
  85. package/dist/cjs/co-switch.cjs.entry.js +5 -5
  86. package/dist/cjs/co-tab-group.cjs.entry.js +113 -4
  87. package/dist/cjs/co-tab.cjs.entry.js +15 -5
  88. package/dist/cjs/co-tags-field.cjs.entry.js +8 -8
  89. package/dist/cjs/co-textarea.cjs.entry.js +6 -6
  90. package/dist/cjs/co-tile.cjs.entry.js +61 -0
  91. package/dist/cjs/co-time-field.cjs.entry.js +2 -2
  92. package/dist/cjs/co-toast.cjs.entry.js +3 -3
  93. package/dist/cjs/co-toggle-button-group.cjs.entry.js +26 -5
  94. package/dist/cjs/co-toggle-button.cjs.entry.js +67 -6
  95. package/dist/cjs/co-transfer-list.cjs.entry.js +3 -3
  96. package/dist/cjs/co-tree-item.cjs.entry.js +110 -0
  97. package/dist/cjs/co-video.cjs.entry.js +3 -3
  98. package/dist/cjs/cobalt.cjs.js +2 -2
  99. package/dist/cjs/{color-CML2Cfdh.js → color-DQVrQGi0.js} +10 -5
  100. package/dist/cjs/{fieldChip-B6YIGU1V.js → fieldChip-C7MxxBVO.js} +1 -1
  101. package/dist/cjs/gradientStops-CMpH4fB_.js +153 -0
  102. package/dist/cjs/hsv-DpfSF3M2.js +95 -0
  103. package/dist/cjs/{index-MDAnKsze.js → index-bHoidDwv.js} +67 -27
  104. package/dist/cjs/index-oMHzCXm6.js +144 -0
  105. package/dist/cjs/loader.cjs.js +2 -2
  106. package/dist/cjs/{index-2kMmd5-a.js → pagination-DV43TRj9.js} +1780 -297
  107. package/dist/cjs/{positioning-CyatXeT_.js → positioning-CILo5esi.js} +45 -18
  108. package/dist/cjs/{requiredMark-D-t-IPN0.js → requiredMark-21yHvvZS.js} +1 -1
  109. package/dist/cjs/rich-text-host-ueFSfW-6.js +119 -0
  110. package/dist/cjs/{richTextI18n-B28uAhh4.js → richTextI18n-DXGIv5w1.js} +45 -0
  111. package/dist/cjs/submenu-RlaX6irw.js +65 -0
  112. package/dist/cjs/{toolbar-config-CYACt9hh.js → toolbar-config-DczL6C4W.js} +32 -0
  113. package/dist/cobalt/cobalt.css +1 -1
  114. package/dist/cobalt/cobalt.esm.js +1 -1
  115. package/dist/cobalt/{p-ee149fd2.entry.js → p-05000ef3.entry.js} +1 -1
  116. package/dist/cobalt/p-06689166.entry.js +1 -0
  117. package/dist/cobalt/{p-1dc55e43.entry.js → p-0a5cfed0.entry.js} +1 -1
  118. package/dist/cobalt/p-1289131f.entry.js +1 -0
  119. package/dist/cobalt/{p-c7d7d7f7.entry.js → p-136beb2c.entry.js} +1 -1
  120. package/dist/cobalt/{p-b437eff6.entry.js → p-1693b614.entry.js} +1 -1
  121. package/dist/cobalt/p-1bfb69ae.entry.js +1 -0
  122. package/dist/cobalt/{p-2c9dba2f.entry.js → p-1f3d5313.entry.js} +1 -1
  123. package/dist/cobalt/{p-b821d9de.entry.js → p-22233b31.entry.js} +1 -1
  124. package/dist/cobalt/{p-c30b4cb5.entry.js → p-26fa36f8.entry.js} +1 -1
  125. package/dist/cobalt/p-2794c500.entry.js +1 -0
  126. package/dist/cobalt/p-297b55cd.entry.js +1 -0
  127. package/dist/cobalt/{p-17244412.entry.js → p-2a2b0c7a.entry.js} +1 -1
  128. package/dist/cobalt/{p-2636b7eb.entry.js → p-2e5702a0.entry.js} +1 -1
  129. package/dist/cobalt/p-3011c84f.entry.js +1 -0
  130. package/dist/cobalt/{p-4d65e713.entry.js → p-30760f77.entry.js} +1 -1
  131. package/dist/cobalt/{p-6dd220e0.entry.js → p-3b9a8e86.entry.js} +1 -1
  132. package/dist/cobalt/p-4111fefa.entry.js +1 -0
  133. package/dist/cobalt/{p-a32b20eb.entry.js → p-44edde81.entry.js} +1 -1
  134. package/dist/cobalt/{p-292b0389.entry.js → p-45007758.entry.js} +1 -1
  135. package/dist/cobalt/p-48c23310.entry.js +1 -0
  136. package/dist/cobalt/p-4b327483.entry.js +1 -0
  137. package/dist/cobalt/p-4c6caa41.entry.js +1 -0
  138. package/dist/cobalt/{p-000a15b8.entry.js → p-5534a64f.entry.js} +1 -1
  139. package/dist/cobalt/p-5573985a.entry.js +1 -0
  140. package/dist/cobalt/p-57d250ad.entry.js +1 -0
  141. package/dist/cobalt/{p-826ee074.entry.js → p-59d3e8fc.entry.js} +1 -1
  142. package/dist/cobalt/{p-4592ca00.entry.js → p-5a32b9a2.entry.js} +1 -1
  143. package/dist/cobalt/p-5b2aa70e.entry.js +1 -0
  144. package/dist/cobalt/{p-d29bb0fa.entry.js → p-5d6e02dd.entry.js} +1 -1
  145. package/dist/cobalt/{p-623cc195.entry.js → p-608d251d.entry.js} +1 -1
  146. package/dist/cobalt/{p-011dc80b.entry.js → p-66fc1528.entry.js} +1 -1
  147. package/dist/cobalt/{p-11c5ce78.entry.js → p-67ad9544.entry.js} +1 -1
  148. package/dist/cobalt/{p-290066ef.entry.js → p-6c157ea2.entry.js} +1 -1
  149. package/dist/cobalt/{p-a2462d7a.entry.js → p-6d541199.entry.js} +1 -1
  150. package/dist/cobalt/{p-58d9b650.entry.js → p-7376f4ed.entry.js} +1 -1
  151. package/dist/cobalt/{p-39a50e7f.entry.js → p-7569375a.entry.js} +1 -1
  152. package/dist/cobalt/{p-7b5c555c.entry.js → p-763698b3.entry.js} +1 -1
  153. package/dist/cobalt/{p-f57dffca.entry.js → p-7675cebe.entry.js} +1 -1
  154. package/dist/cobalt/p-78a20284.entry.js +1 -0
  155. package/dist/cobalt/{p-aa9400bf.entry.js → p-7f3523ce.entry.js} +1 -1
  156. package/dist/cobalt/{p-24196410.entry.js → p-86b6fd81.entry.js} +1 -1
  157. package/dist/cobalt/{p-996f4e38.entry.js → p-889563d5.entry.js} +1 -1
  158. package/dist/cobalt/{p-eadfd661.entry.js → p-8ab5b396.entry.js} +1 -1
  159. package/dist/cobalt/{p-c91d4fc6.entry.js → p-8b2e4579.entry.js} +1 -1
  160. package/dist/cobalt/p-8cd3acaa.entry.js +1 -0
  161. package/dist/cobalt/{p-23ab0cc5.entry.js → p-8f701eac.entry.js} +1 -1
  162. package/dist/cobalt/p-90fad0f9.entry.js +1 -0
  163. package/dist/cobalt/{p-76249983.entry.js → p-97a4fbba.entry.js} +1 -1
  164. package/dist/cobalt/p-9b46a8fe.entry.js +1 -0
  165. package/dist/cobalt/{p-ee2023da.entry.js → p-9bee9dc8.entry.js} +1 -1
  166. package/dist/cobalt/{p-2f9cbbd5.entry.js → p-9cf10331.entry.js} +1 -1
  167. package/dist/cobalt/p-9dc01092.entry.js +1 -0
  168. package/dist/cobalt/p-9e406172.entry.js +1 -0
  169. package/dist/cobalt/p-B1JT7us1.js +1 -0
  170. package/dist/cobalt/{p-BRbgGqLw.js → p-BVGGRfNG.js} +1 -1
  171. package/dist/cobalt/p-BmdKHBZP.js +1 -0
  172. package/dist/cobalt/p-BtliEQAT.js +1 -0
  173. package/dist/cobalt/p-COJdaKBU.js +1 -0
  174. package/dist/cobalt/{p-BAYo-RBt.js → p-CRxTFT_z.js} +1 -1
  175. package/dist/cobalt/p-CYN5B3IQ.js +1 -0
  176. package/dist/cobalt/p-DJkaRtbb.js +2 -0
  177. package/dist/cobalt/p-DU-KOQ8L.js +1 -0
  178. package/dist/cobalt/p-DXLeDZvr.js +1 -0
  179. package/dist/cobalt/{p-D_zA1Pv4.js → p-DgJovDdy.js} +1 -1
  180. package/dist/cobalt/p-RVQJEYxa.js +1 -0
  181. package/dist/cobalt/{p-1861fe41.entry.js → p-a07dedd1.entry.js} +1 -1
  182. package/dist/cobalt/{p-08e42e00.entry.js → p-a336178b.entry.js} +1 -1
  183. package/dist/cobalt/{p-f9a7b7c6.entry.js → p-a52ed6ff.entry.js} +1 -1
  184. package/dist/cobalt/{p-aaca6dab.entry.js → p-a930cdd7.entry.js} +1 -1
  185. package/dist/cobalt/{p-eb82358d.entry.js → p-b1994bb4.entry.js} +1 -1
  186. package/dist/cobalt/p-b2b13da8.entry.js +1 -0
  187. package/dist/cobalt/{p-c2ebf0ec.entry.js → p-b5ec4286.entry.js} +1 -1
  188. package/dist/cobalt/p-b9401dd7.entry.js +1 -0
  189. package/dist/cobalt/p-b9dfb333.entry.js +1 -0
  190. package/dist/cobalt/p-bc3ba0cd.entry.js +1 -0
  191. package/dist/cobalt/{p-d375014b.entry.js → p-bc4fbfa6.entry.js} +1 -1
  192. package/dist/cobalt/{p-d0b2c418.entry.js → p-c109a1e1.entry.js} +1 -1
  193. package/dist/cobalt/{p-ee9a623d.entry.js → p-c1caa112.entry.js} +1 -1
  194. package/dist/cobalt/p-c9990662.entry.js +1 -0
  195. package/dist/cobalt/p-cc4b51fa.entry.js +1 -0
  196. package/dist/cobalt/p-cc5989e9.entry.js +1 -0
  197. package/dist/cobalt/{p-e4264532.entry.js → p-ce2b2048.entry.js} +1 -1
  198. package/dist/cobalt/p-d1c378ff.entry.js +1 -0
  199. package/dist/cobalt/p-d1e83525.entry.js +1 -0
  200. package/dist/cobalt/{p-59963937.entry.js → p-d1f47915.entry.js} +1 -1
  201. package/dist/cobalt/{p-28764b8e.entry.js → p-d4979025.entry.js} +1 -1
  202. package/dist/cobalt/p-d6e7c258.entry.js +1 -0
  203. package/dist/cobalt/p-d75d2f3d.entry.js +1 -0
  204. package/dist/cobalt/p-db42c4ab.entry.js +1 -0
  205. package/dist/cobalt/{p-44c4e4a3.entry.js → p-e4ff2fcb.entry.js} +1 -1
  206. package/dist/cobalt/p-e6116149.entry.js +1 -0
  207. package/dist/cobalt/{p-0c004735.entry.js → p-e99ddf9c.entry.js} +1 -1
  208. package/dist/cobalt/{p-1cc818ca.entry.js → p-ea24eea8.entry.js} +1 -1
  209. package/dist/cobalt/{p-07416e31.entry.js → p-ea564148.entry.js} +1 -1
  210. package/dist/cobalt/{p-8471abe2.entry.js → p-ec7a6bf2.entry.js} +1 -1
  211. package/dist/cobalt/{p-fb2d1144.entry.js → p-ee42dca6.entry.js} +1 -1
  212. package/dist/cobalt/{p-49834b8e.entry.js → p-ee88ec40.entry.js} +1 -1
  213. package/dist/cobalt/p-eeb114da.entry.js +1 -0
  214. package/dist/cobalt/{p-f6691108.entry.js → p-f0898e21.entry.js} +1 -1
  215. package/dist/cobalt/p-f246946a.entry.js +1 -0
  216. package/dist/cobalt/{p-b90d41e4.entry.js → p-f5934cd9.entry.js} +1 -1
  217. package/dist/cobalt/p-f5e1873d.entry.js +1 -0
  218. package/dist/cobalt/p-f60bd4d6.entry.js +1 -0
  219. package/dist/cobalt/p-f813569c.entry.js +1 -0
  220. package/dist/cobalt/{p-f7eb1a40.entry.js → p-f8c7941f.entry.js} +1 -1
  221. package/dist/cobalt/{p-44ea675f.entry.js → p-f8d3c71e.entry.js} +1 -1
  222. package/dist/cobalt/{p-91e73a92.entry.js → p-ffbe955a.entry.js} +1 -1
  223. package/dist/cobalt/p-xnrKkNWQ.js +1 -0
  224. package/dist/collection/collection-manifest.json +8 -0
  225. package/dist/collection/components/co-accordion/co-accordion.js +2 -2
  226. package/dist/collection/components/co-action-bar/co-action-bar.js +2 -2
  227. package/dist/collection/components/co-app-shell/co-app-shell.js +2 -2
  228. package/dist/collection/components/co-audio-player/co-audio-player.js +3 -3
  229. package/dist/collection/components/co-autocomplete/co-autocomplete.js +1 -1
  230. package/dist/collection/components/co-avatar/co-avatar.css +11 -2
  231. package/dist/collection/components/co-avatar/co-avatar.js +7 -4
  232. package/dist/collection/components/co-avatar-group/co-avatar-group.js +1 -1
  233. package/dist/collection/components/co-badge/co-badge.js +1 -1
  234. package/dist/collection/components/co-bottom-sheet/co-bottom-sheet.js +4 -4
  235. package/dist/collection/components/co-breadcrumb/co-breadcrumb.js +1 -1
  236. package/dist/collection/components/co-breadcrumb-item/co-breadcrumb-item.js +2 -2
  237. package/dist/collection/components/co-button/co-button.css +73 -6
  238. package/dist/collection/components/co-button/co-button.js +33 -11
  239. package/dist/collection/components/co-button-group/co-button-group.js +2 -2
  240. package/dist/collection/components/co-calendar/calendarMarks.js +40 -0
  241. package/dist/collection/components/co-calendar/co-calendar.css +11 -1
  242. package/dist/collection/components/co-calendar/co-calendar.js +82 -20
  243. package/dist/collection/components/co-calendar-month/co-calendar-month.js +1 -1
  244. package/dist/collection/components/co-calendar-timegrid/co-calendar-timegrid.js +2 -2
  245. package/dist/collection/components/co-card/co-card.js +2 -2
  246. package/dist/collection/components/co-carousel/co-carousel.js +2 -2
  247. package/dist/collection/components/co-carousel-item/co-carousel-item.js +1 -1
  248. package/dist/collection/components/co-checkbox/co-checkbox.css +43 -1
  249. package/dist/collection/components/co-checkbox/co-checkbox.js +31 -3
  250. package/dist/collection/components/co-checkbox-group/co-checkbox-group.js +1 -1
  251. package/dist/collection/components/co-chip/co-chip.js +2 -2
  252. package/dist/collection/components/co-color-area/co-color-area.css +83 -0
  253. package/dist/collection/components/co-color-area/co-color-area.js +341 -0
  254. package/dist/collection/components/co-color-picker/co-color-picker.js +2 -2
  255. package/dist/collection/components/co-color-slider/co-color-slider.css +115 -0
  256. package/dist/collection/components/co-color-slider/co-color-slider.js +353 -0
  257. package/dist/collection/components/co-column-picker/co-column-picker.js +2 -2
  258. package/dist/collection/components/co-combobox/co-combobox.js +4 -4
  259. package/dist/collection/components/co-command-search/co-command-search.js +5 -5
  260. package/dist/collection/components/co-data-table/co-data-table.js +3 -3
  261. package/dist/collection/components/co-data-table-pagination/co-data-table-pagination.js +4 -4
  262. package/dist/collection/components/co-date-field/co-date-field.js +4 -4
  263. package/dist/collection/components/co-date-range/co-date-range.js +1 -1
  264. package/dist/collection/components/co-date-range-picker/co-date-range-picker.js +2 -2
  265. package/dist/collection/components/co-date-time-picker/co-date-time-picker.js +3 -3
  266. package/dist/collection/components/co-document-editor/change-throttle.js +30 -0
  267. package/dist/collection/components/co-document-editor/co-document-editor.css +438 -0
  268. package/dist/collection/components/co-document-editor/co-document-editor.js +1542 -0
  269. package/dist/collection/components/co-document-editor/document-props.js +40 -0
  270. package/dist/collection/components/co-document-editor/header-tools.js +11 -0
  271. package/dist/collection/components/co-document-editor/image-bar.js +66 -0
  272. package/dist/collection/components/co-document-editor/page-styles.js +90 -0
  273. package/dist/collection/components/co-document-editor/zoom.js +45 -0
  274. package/dist/collection/components/co-drive-card/co-drive-card.js +1 -1
  275. package/dist/collection/components/co-drop-zone/co-drop-zone.js +1 -1
  276. package/dist/collection/components/co-emoji-picker/co-emoji-picker.js +2 -2
  277. package/dist/collection/components/co-empty-state/co-empty-state.js +2 -2
  278. package/dist/collection/components/co-event-calendar/co-event-calendar.js +2 -2
  279. package/dist/collection/components/co-event-popover/co-event-popover.js +1 -1
  280. package/dist/collection/components/co-fab/co-fab.js +2 -2
  281. package/dist/collection/components/co-file-field/co-file-field.js +6 -6
  282. package/dist/collection/components/co-file-type-tile/co-file-type-tile.js +2 -2
  283. package/dist/collection/components/co-gradient-bar/co-gradient-bar.css +138 -0
  284. package/dist/collection/components/co-gradient-bar/co-gradient-bar.js +407 -0
  285. package/dist/collection/components/co-helper-text/co-helper-text.js +2 -2
  286. package/dist/collection/components/co-icon/co-icon.js +2 -2
  287. package/dist/collection/components/co-icon-button/co-icon-button.css +95 -19
  288. package/dist/collection/components/co-icon-button/co-icon-button.js +120 -10
  289. package/dist/collection/components/co-input/co-input.css +122 -0
  290. package/dist/collection/components/co-input/co-input.js +37 -11
  291. package/dist/collection/components/co-json-field/co-json-field.js +3 -3
  292. package/dist/collection/components/co-kbd/co-kbd.css +99 -0
  293. package/dist/collection/components/co-kbd/co-kbd.js +291 -0
  294. package/dist/collection/components/co-lightbox/co-lightbox.js +4 -4
  295. package/dist/collection/components/co-list-footer/co-list-footer.js +1 -1
  296. package/dist/collection/components/co-list-item/co-list-item.js +4 -4
  297. package/dist/collection/components/co-media-thumb/co-media-thumb.js +2 -2
  298. package/dist/collection/components/co-menu/co-menu.css +60 -0
  299. package/dist/collection/components/co-menu/co-menu.js +143 -3
  300. package/dist/collection/components/co-menu-divider/co-menu-divider.css +17 -0
  301. package/dist/collection/components/co-menu-divider/co-menu-divider.js +1 -1
  302. package/dist/collection/components/co-menu-item/co-menu-item.css +42 -6
  303. package/dist/collection/components/co-menu-item/co-menu-item.js +58 -4
  304. package/dist/collection/components/co-modal/co-modal.css +212 -1
  305. package/dist/collection/components/co-modal/co-modal.js +339 -9
  306. package/dist/collection/components/co-navbar/co-navbar.js +2 -2
  307. package/dist/collection/components/co-number-field/co-number-field.js +3 -3
  308. package/dist/collection/components/co-option-list/co-option-list.css +64 -21
  309. package/dist/collection/components/co-option-list/co-option-list.js +6 -2
  310. package/dist/collection/components/co-overlay/co-overlay.js +7 -3
  311. package/dist/collection/components/co-page-header/co-page-header.js +1 -1
  312. package/dist/collection/components/co-phone-field/co-phone-field.js +1 -1
  313. package/dist/collection/components/co-popover/co-popover.css +15 -2
  314. package/dist/collection/components/co-popover/co-popover.js +130 -5
  315. package/dist/collection/components/co-progress-bar/co-progress-bar.js +2 -2
  316. package/dist/collection/components/co-progress-circle/co-progress-circle.js +2 -2
  317. package/dist/collection/components/co-radio/co-radio.js +3 -3
  318. package/dist/collection/components/co-radio-group/co-radio-group.js +4 -4
  319. package/dist/collection/components/co-rating/co-rating.js +3 -3
  320. package/dist/collection/components/co-ref-field/co-ref-field.js +5 -5
  321. package/dist/collection/components/co-rich-text-editor/co-rich-text-editor.js +23 -90
  322. package/dist/collection/components/co-rich-text-toolbar/co-rich-text-toolbar.css +12 -0
  323. package/dist/collection/components/co-rich-text-toolbar/co-rich-text-toolbar.js +123 -18
  324. package/dist/collection/components/co-rich-text-viewer/co-rich-text-viewer.js +8 -1
  325. package/dist/collection/components/co-row/co-row.js +2 -2
  326. package/dist/collection/components/co-segmented-bar/co-segmented-bar.js +3 -3
  327. package/dist/collection/components/co-select/co-select.css +194 -10
  328. package/dist/collection/components/co-select/co-select.js +163 -32
  329. package/dist/collection/components/co-select/virtualRows.js +57 -0
  330. package/dist/collection/components/co-separator/co-separator.js +1 -1
  331. package/dist/collection/components/co-sidebar/co-sidebar.js +2 -2
  332. package/dist/collection/components/co-sidebar-nav/co-sidebar-nav.css +10 -0
  333. package/dist/collection/components/co-sidebar-nav/co-sidebar-nav.js +19 -4
  334. package/dist/collection/components/co-skeleton/co-skeleton.js +1 -1
  335. package/dist/collection/components/co-slider/co-slider.css +148 -5
  336. package/dist/collection/components/co-slider/co-slider.js +240 -21
  337. package/dist/collection/components/co-swatch-grid/co-swatch-grid.css +56 -0
  338. package/dist/collection/components/co-swatch-grid/co-swatch-grid.js +292 -0
  339. package/dist/collection/components/co-switch/co-switch.js +3 -3
  340. package/dist/collection/components/co-tab/co-tab.css +60 -0
  341. package/dist/collection/components/co-tab/co-tab.js +36 -6
  342. package/dist/collection/components/co-tab-group/co-tab-group.css +24 -0
  343. package/dist/collection/components/co-tab-group/co-tab-group.js +124 -2
  344. package/dist/collection/components/co-tab-group/revealTab.js +26 -0
  345. package/dist/collection/components/co-tags-field/co-tags-field.js +5 -5
  346. package/dist/collection/components/co-textarea/co-textarea.js +4 -4
  347. package/dist/collection/components/co-tile/co-tile.css +63 -0
  348. package/dist/collection/components/co-tile/co-tile.js +162 -0
  349. package/dist/collection/components/co-time-field/co-time-field.js +1 -1
  350. package/dist/collection/components/co-toast/co-toast.js +4 -4
  351. package/dist/collection/components/co-toggle-button/co-toggle-button.css +101 -0
  352. package/dist/collection/components/co-toggle-button/co-toggle-button.js +80 -8
  353. package/dist/collection/components/co-toggle-button-group/co-toggle-button-group.css +21 -0
  354. package/dist/collection/components/co-toggle-button-group/co-toggle-button-group.js +28 -7
  355. package/dist/collection/components/co-tooltip/co-tooltip.css +36 -0
  356. package/dist/collection/components/co-tooltip/co-tooltip.js +51 -3
  357. package/dist/collection/components/co-transfer-list/co-transfer-list.js +3 -3
  358. package/dist/collection/components/co-tree-item/co-tree-item.css +226 -0
  359. package/dist/collection/components/co-tree-item/co-tree-item.js +353 -0
  360. package/dist/collection/components/co-tree-item/treeItemI18n.js +16 -0
  361. package/dist/collection/components/co-video/co-video.js +2 -2
  362. package/dist/collection/utils/color.js +9 -5
  363. package/dist/collection/utils/dragMove.js +95 -0
  364. package/dist/collection/utils/gradientBarI18n.js +24 -0
  365. package/dist/collection/utils/gradientStops.js +142 -0
  366. package/dist/collection/utils/hsv.js +114 -0
  367. package/dist/collection/utils/kbdI18n.js +29 -0
  368. package/dist/collection/utils/positioning.js +44 -18
  369. package/dist/collection/utils/rich-text-host.js +109 -0
  370. package/dist/collection/utils/richTextI18n.js +45 -0
  371. package/dist/collection/utils/submenu.js +23 -3
  372. package/dist/collection/utils/swatchGridI18n.js +14 -0
  373. package/dist/collection/utils/test/fake-block-layout.js +41 -0
  374. package/dist/collection/utils/test/prosemirror-dom-shim.js +17 -0
  375. package/dist/collection/utils/test/shared-contract-css.js +9 -0
  376. package/dist/components/co-accordion.js +1 -1
  377. package/dist/components/co-action-bar.js +1 -1
  378. package/dist/components/co-app-shell.js +1 -1
  379. package/dist/components/co-audio-player.js +1 -1
  380. package/dist/components/co-autocomplete.js +1 -1
  381. package/dist/components/co-avatar-group.js +1 -1
  382. package/dist/components/co-avatar.js +1 -1
  383. package/dist/components/co-badge.js +1 -1
  384. package/dist/components/co-bottom-sheet.js +1 -1
  385. package/dist/components/co-breadcrumb-item.js +1 -1
  386. package/dist/components/co-breadcrumb.js +1 -1
  387. package/dist/components/co-button-group.js +1 -1
  388. package/dist/components/co-button.js +1 -1
  389. package/dist/components/co-calendar-month.js +1 -1
  390. package/dist/components/co-calendar-timegrid.js +1 -1
  391. package/dist/components/co-calendar.js +1 -1
  392. package/dist/components/co-card.js +1 -1
  393. package/dist/components/co-carousel-item.js +1 -1
  394. package/dist/components/co-carousel.js +1 -1
  395. package/dist/components/co-checkbox-group.js +1 -1
  396. package/dist/components/co-checkbox.js +1 -1
  397. package/dist/components/co-chip.js +1 -1
  398. package/dist/components/co-color-area.d.ts +11 -0
  399. package/dist/components/co-color-area.js +1 -0
  400. package/dist/components/co-color-picker.js +1 -1
  401. package/dist/components/co-color-slider.d.ts +11 -0
  402. package/dist/components/co-color-slider.js +1 -0
  403. package/dist/components/co-column-picker.js +1 -1
  404. package/dist/components/co-combobox.js +1 -1
  405. package/dist/components/co-command-search.js +1 -1
  406. package/dist/components/co-data-table-pagination.js +1 -1
  407. package/dist/components/co-data-table.js +1 -1
  408. package/dist/components/co-date-field.js +1 -1
  409. package/dist/components/co-date-picker.js +1 -1
  410. package/dist/components/co-date-range-picker.js +1 -1
  411. package/dist/components/co-date-range.js +1 -1
  412. package/dist/components/co-date-time-picker.js +1 -1
  413. package/dist/components/co-document-editor.d.ts +11 -0
  414. package/dist/components/co-document-editor.js +1 -0
  415. package/dist/components/co-drawer.js +1 -1
  416. package/dist/components/co-drive-card.js +1 -1
  417. package/dist/components/co-drop-zone.js +1 -1
  418. package/dist/components/co-emoji-picker.js +1 -1
  419. package/dist/components/co-empty-state.js +1 -1
  420. package/dist/components/co-event-calendar.js +1 -1
  421. package/dist/components/co-event-popover.js +1 -1
  422. package/dist/components/co-fab.js +1 -1
  423. package/dist/components/co-file-field.js +1 -1
  424. package/dist/components/co-file-type-tile.js +1 -1
  425. package/dist/components/co-gradient-bar.d.ts +11 -0
  426. package/dist/components/co-gradient-bar.js +1 -0
  427. package/dist/components/co-helper-text.js +1 -1
  428. package/dist/components/co-icon-button.js +1 -1
  429. package/dist/components/co-icon.js +1 -1
  430. package/dist/components/co-input.js +1 -1
  431. package/dist/components/co-json-field.js +1 -1
  432. package/dist/components/co-kbd.d.ts +11 -0
  433. package/dist/components/co-kbd.js +1 -0
  434. package/dist/components/co-lightbox.js +1 -1
  435. package/dist/components/co-list-footer.js +1 -1
  436. package/dist/components/co-list-item.js +1 -1
  437. package/dist/components/co-media-thumb.js +1 -1
  438. package/dist/components/co-menu-divider.js +1 -1
  439. package/dist/components/co-menu-item.js +1 -1
  440. package/dist/components/co-menu.js +1 -1
  441. package/dist/components/co-modal.js +1 -1
  442. package/dist/components/co-navbar.js +1 -1
  443. package/dist/components/co-number-field.js +1 -1
  444. package/dist/components/co-option-list.js +1 -1
  445. package/dist/components/co-overlay.js +1 -1
  446. package/dist/components/co-page-header.js +1 -1
  447. package/dist/components/co-phone-field.js +1 -1
  448. package/dist/components/co-popover.js +1 -1
  449. package/dist/components/co-progress-bar.js +1 -1
  450. package/dist/components/co-progress-circle.js +1 -1
  451. package/dist/components/co-radio-group.js +1 -1
  452. package/dist/components/co-radio.js +1 -1
  453. package/dist/components/co-rating.js +1 -1
  454. package/dist/components/co-ref-field.js +1 -1
  455. package/dist/components/co-rich-text-editor.js +1 -1
  456. package/dist/components/co-rich-text-toolbar.js +1 -1
  457. package/dist/components/co-rich-text-viewer.js +1 -1
  458. package/dist/components/co-row.js +1 -1
  459. package/dist/components/co-segmented-bar.js +1 -1
  460. package/dist/components/co-select.js +1 -1
  461. package/dist/components/co-separator.js +1 -1
  462. package/dist/components/co-sidebar-nav.js +1 -1
  463. package/dist/components/co-sidebar.js +1 -1
  464. package/dist/components/co-skeleton.js +1 -1
  465. package/dist/components/co-slider.js +1 -1
  466. package/dist/components/co-swatch-grid.d.ts +11 -0
  467. package/dist/components/co-swatch-grid.js +1 -0
  468. package/dist/components/co-switch.js +1 -1
  469. package/dist/components/co-tab-group.js +1 -1
  470. package/dist/components/co-tab.js +1 -1
  471. package/dist/components/co-tags-field.js +1 -1
  472. package/dist/components/co-textarea.js +1 -1
  473. package/dist/components/co-tile.d.ts +11 -0
  474. package/dist/components/co-tile.js +1 -0
  475. package/dist/components/co-time-field.js +1 -1
  476. package/dist/components/co-toast.js +1 -1
  477. package/dist/components/co-toggle-button-group.js +1 -1
  478. package/dist/components/co-toggle-button.js +1 -1
  479. package/dist/components/co-tooltip.js +1 -1
  480. package/dist/components/co-transfer-list.js +1 -1
  481. package/dist/components/co-tree-item.d.ts +11 -0
  482. package/dist/components/co-tree-item.js +1 -0
  483. package/dist/components/co-video.js +1 -1
  484. package/dist/components/index.js +1 -1
  485. package/dist/components/p-B1JT7us1.js +1 -0
  486. package/dist/components/{p-Nt4JJxbL.js → p-B20o5exO.js} +1 -1
  487. package/dist/components/{p-DNJAIVfI.js → p-B3kKOgsA.js} +1 -1
  488. package/dist/components/{p-P4HlMBlL.js → p-BIDSDP05.js} +1 -1
  489. package/dist/components/p-BOqtnWTJ.js +1 -0
  490. package/dist/components/p-BQltjDw5.js +1 -0
  491. package/dist/components/p-BR0LYW9v.js +1 -0
  492. package/dist/components/{p-BRbgGqLw.js → p-BVGGRfNG.js} +1 -1
  493. package/dist/components/p-BZDl9aFl.js +1 -0
  494. package/dist/components/p-BcXdId8y.js +1 -0
  495. package/dist/components/p-BmdKHBZP.js +1 -0
  496. package/dist/components/{p-NNxjElcX.js → p-BraiMwgs.js} +1 -1
  497. package/dist/components/p-BtliEQAT.js +1 -0
  498. package/dist/components/p-Bymi-A7C.js +1 -0
  499. package/dist/components/p-C-f8wTqe.js +1 -0
  500. package/dist/components/{p-BhCVadcA.js → p-C1jZYtUS.js} +1 -1
  501. package/dist/components/{p-CT2enQ6h.js → p-C3G8oPgU.js} +1 -1
  502. package/dist/components/{p-B56LX2SH.js → p-CGH3E8uK.js} +1 -1
  503. package/dist/components/p-COJdaKBU.js +1 -0
  504. package/dist/components/{p-BAYo-RBt.js → p-CRxTFT_z.js} +1 -1
  505. package/dist/components/{p-Du_CgT5E.js → p-CfJgypOl.js} +1 -1
  506. package/dist/components/{p-uxdXViMV.js → p-ChwSnCFf.js} +1 -1
  507. package/dist/components/{p-Dc_Kbari.js → p-CpGEV0iM.js} +1 -1
  508. package/dist/components/{p-DvR45CLa.js → p-D9or2g4j.js} +1 -1
  509. package/dist/components/{p-e5KibEs8.js → p-DJ468fPu.js} +1 -1
  510. package/dist/components/{p-DFlJMEJ-.js → p-DKXCr-hE.js} +1 -1
  511. package/dist/components/p-DU-KOQ8L.js +1 -0
  512. package/dist/components/p-DXLeDZvr.js +1 -0
  513. package/dist/components/{p-BGDqldEg.js → p-DfcPGitr.js} +1 -1
  514. package/dist/components/p-Dg-Ti_Bf.js +1 -0
  515. package/dist/components/p-Dh_eRYKu.js +1 -0
  516. package/dist/components/p-Dp650Gpp.js +1 -0
  517. package/dist/components/p-FA1kBmZ-.js +1 -0
  518. package/dist/components/p-RVQJEYxa.js +1 -0
  519. package/dist/components/p-d4rf3H8p.js +1 -0
  520. package/dist/components/{p-Dxa7c4Ap.js → p-dnaee7fS.js} +1 -1
  521. package/dist/components/p-f2xwcrXa.js +1 -0
  522. package/dist/esm/co-accordion.entry.js +3 -3
  523. package/dist/esm/co-action-bar.entry.js +3 -3
  524. package/dist/esm/co-app-shell.entry.js +3 -3
  525. package/dist/esm/co-audio-player.entry.js +4 -4
  526. package/dist/esm/co-autocomplete.entry.js +2 -2
  527. package/dist/esm/co-avatar-group.entry.js +1 -1
  528. package/dist/esm/co-avatar.entry.js +7 -4
  529. package/dist/esm/co-badge.entry.js +2 -2
  530. package/dist/esm/co-bottom-sheet.entry.js +5 -5
  531. package/dist/esm/co-breadcrumb-item.entry.js +3 -3
  532. package/dist/esm/co-breadcrumb.entry.js +2 -2
  533. package/dist/esm/co-button-group.entry.js +3 -3
  534. package/dist/esm/co-button.entry.js +9 -7
  535. package/dist/esm/co-calendar-month_2.entry.js +4 -4
  536. package/dist/esm/co-calendar_3.entry.js +72 -27
  537. package/dist/esm/co-card.entry.js +3 -3
  538. package/dist/esm/co-carousel-item.entry.js +2 -2
  539. package/dist/esm/co-carousel.entry.js +3 -3
  540. package/dist/esm/co-checkbox-group.entry.js +1 -1
  541. package/dist/esm/co-checkbox.entry.js +13 -5
  542. package/dist/esm/co-chip_2.entry.js +9 -6
  543. package/dist/esm/co-color-area.entry.js +167 -0
  544. package/dist/esm/co-color-picker.entry.js +5 -5
  545. package/dist/esm/co-color-slider.entry.js +187 -0
  546. package/dist/esm/co-column-picker.entry.js +3 -3
  547. package/dist/esm/co-combobox.entry.js +5 -5
  548. package/dist/esm/co-command-search.entry.js +5 -5
  549. package/dist/esm/co-data-table-pagination.entry.js +5 -5
  550. package/dist/esm/co-data-table.entry.js +3 -3
  551. package/dist/esm/co-date-picker.entry.js +2 -2
  552. package/dist/esm/co-date-range-picker.entry.js +2 -2
  553. package/dist/esm/co-date-range.entry.js +2 -2
  554. package/dist/esm/co-date-time-picker.entry.js +4 -4
  555. package/dist/esm/co-document-editor.entry.js +1159 -0
  556. package/dist/esm/co-drive-card.entry.js +2 -2
  557. package/dist/esm/co-drop-zone.entry.js +2 -2
  558. package/dist/esm/co-emoji-picker.entry.js +3 -3
  559. package/dist/esm/co-empty-state.entry.js +3 -3
  560. package/dist/esm/co-event-calendar.entry.js +3 -3
  561. package/dist/esm/co-event-popover.entry.js +3 -3
  562. package/dist/esm/co-fab.entry.js +3 -3
  563. package/dist/esm/co-file-field.entry.js +8 -8
  564. package/dist/esm/co-file-type-tile.entry.js +3 -3
  565. package/dist/esm/co-gradient-bar.entry.js +218 -0
  566. package/dist/esm/co-helper-text.entry.js +3 -3
  567. package/dist/esm/co-icon-button.entry.js +49 -9
  568. package/dist/esm/co-icon.entry.js +3 -3
  569. package/dist/esm/co-input.entry.js +14 -8
  570. package/dist/esm/co-json-field.entry.js +5 -5
  571. package/dist/esm/{co-tooltip.entry.js → co-kbd_2.entry.js} +194 -7
  572. package/dist/esm/co-lightbox.entry.js +5 -5
  573. package/dist/esm/co-list-footer.entry.js +2 -2
  574. package/dist/esm/co-list-item.entry.js +5 -5
  575. package/dist/esm/co-loader.entry.js +1 -1
  576. package/dist/esm/co-media-thumb.entry.js +3 -3
  577. package/dist/esm/co-menu-divider.entry.js +3 -3
  578. package/dist/esm/co-menu-item.entry.js +39 -41
  579. package/dist/esm/co-menu.entry.js +81 -5
  580. package/dist/esm/co-modal.entry.js +350 -7
  581. package/dist/esm/co-navbar.entry.js +3 -3
  582. package/dist/esm/co-number-field.entry.js +5 -5
  583. package/dist/esm/co-overlay.entry.js +8 -4
  584. package/dist/esm/co-page-header.entry.js +2 -2
  585. package/dist/esm/co-phone-field.entry.js +3 -3
  586. package/dist/esm/co-popover.entry.js +67 -6
  587. package/dist/esm/co-progress-bar.entry.js +3 -3
  588. package/dist/esm/co-progress-circle.entry.js +3 -3
  589. package/dist/esm/co-provider-logo_2.entry.js +2 -2
  590. package/dist/esm/co-radio-group.entry.js +4 -4
  591. package/dist/esm/co-radio.entry.js +4 -4
  592. package/dist/esm/co-rating.entry.js +4 -4
  593. package/dist/esm/co-ref-field.entry.js +5 -5
  594. package/dist/esm/co-rich-text-editor.entry.js +26 -92
  595. package/dist/esm/co-rich-text-toolbar.entry.js +79 -20
  596. package/dist/esm/co-rich-text-viewer.entry.js +9 -2
  597. package/dist/esm/co-row.entry.js +3 -3
  598. package/dist/esm/co-segmented-bar.entry.js +3 -3
  599. package/dist/esm/co-select.entry.js +158 -29
  600. package/dist/esm/co-separator.entry.js +2 -2
  601. package/dist/esm/co-sidebar-nav.entry.js +20 -5
  602. package/dist/esm/co-sidebar.entry.js +3 -3
  603. package/dist/esm/co-slider.entry.js +203 -23
  604. package/dist/esm/co-swatch-grid.entry.js +119 -0
  605. package/dist/esm/co-switch.entry.js +5 -5
  606. package/dist/esm/co-tab-group.entry.js +113 -4
  607. package/dist/esm/co-tab.entry.js +15 -5
  608. package/dist/esm/co-tags-field.entry.js +8 -8
  609. package/dist/esm/co-textarea.entry.js +6 -6
  610. package/dist/esm/co-tile.entry.js +59 -0
  611. package/dist/esm/co-time-field.entry.js +2 -2
  612. package/dist/esm/co-toast.entry.js +3 -3
  613. package/dist/esm/co-toggle-button-group.entry.js +26 -5
  614. package/dist/esm/co-toggle-button.entry.js +67 -6
  615. package/dist/esm/co-transfer-list.entry.js +3 -3
  616. package/dist/esm/co-tree-item.entry.js +108 -0
  617. package/dist/esm/co-video.entry.js +3 -3
  618. package/dist/esm/cobalt.js +3 -3
  619. package/dist/esm/{color-BRbgGqLw.js → color-BVGGRfNG.js} +10 -6
  620. package/dist/esm/{fieldChip-uyggU8VV.js → fieldChip-B2ctp2m6.js} +1 -1
  621. package/dist/esm/gradientStops-DDK0y8ra.js +145 -0
  622. package/dist/esm/hsv-COJdaKBU.js +90 -0
  623. package/dist/esm/index-Cpo8HTwr.js +142 -0
  624. package/dist/esm/{index-DH5lfRNj.js → index-DJkaRtbb.js} +67 -28
  625. package/dist/esm/loader.js +3 -3
  626. package/dist/esm/{index-BBIYyvq-.js → pagination-D9OfZUnY.js} +1728 -297
  627. package/dist/esm/{positioning-DFHRS9cJ.js → positioning-BtliEQAT.js} +45 -19
  628. package/dist/esm/{requiredMark-BCJUuZvC.js → requiredMark-D5C5NzOE.js} +1 -1
  629. package/dist/esm/rich-text-host-BmdKHBZP.js +111 -0
  630. package/dist/esm/{richTextI18n-BYKAgwq3.js → richTextI18n-xnrKkNWQ.js} +45 -0
  631. package/dist/esm/submenu-DU-KOQ8L.js +57 -0
  632. package/dist/esm/{toolbar-config-BAYo-RBt.js → toolbar-config-CRxTFT_z.js} +32 -0
  633. package/dist/types/components/co-avatar/co-avatar.d.ts +4 -2
  634. package/dist/types/components/co-button/co-button.d.ts +6 -4
  635. package/dist/types/components/co-calendar/calendarMarks.d.ts +15 -0
  636. package/dist/types/components/co-calendar/co-calendar.d.ts +16 -0
  637. package/dist/types/components/co-checkbox/co-checkbox.d.ts +7 -0
  638. package/dist/types/components/co-color-area/co-color-area.d.ts +64 -0
  639. package/dist/types/components/co-color-slider/co-color-slider.d.ts +61 -0
  640. package/dist/types/components/co-date-time-picker/co-date-time-picker.d.ts +1 -1
  641. package/dist/types/components/co-document-editor/change-throttle.d.ts +9 -0
  642. package/dist/types/components/co-document-editor/co-document-editor.d.ts +276 -0
  643. package/dist/types/components/co-document-editor/document-props.d.ts +6 -0
  644. package/dist/types/components/co-document-editor/header-tools.d.ts +11 -0
  645. package/dist/types/components/co-document-editor/image-bar.d.ts +50 -0
  646. package/dist/types/components/co-document-editor/page-styles.d.ts +1 -0
  647. package/dist/types/components/co-document-editor/zoom.d.ts +26 -0
  648. package/dist/types/components/co-gradient-bar/co-gradient-bar.d.ts +72 -0
  649. package/dist/types/components/co-icon-button/co-icon-button.d.ts +34 -2
  650. package/dist/types/components/co-input/co-input.d.ts +14 -5
  651. package/dist/types/components/co-kbd/co-kbd.d.ts +43 -0
  652. package/dist/types/components/co-menu/co-menu.d.ts +40 -1
  653. package/dist/types/components/co-menu-item/co-menu-item.d.ts +17 -0
  654. package/dist/types/components/co-modal/co-modal.d.ts +111 -2
  655. package/dist/types/components/co-option-list/co-option-list.d.ts +1 -0
  656. package/dist/types/components/co-option-list/optionListLogic.d.ts +3 -0
  657. package/dist/types/components/co-popover/co-popover.d.ts +36 -0
  658. package/dist/types/components/co-rich-text-editor/co-rich-text-editor.d.ts +2 -5
  659. package/dist/types/components/co-rich-text-toolbar/co-rich-text-toolbar.d.ts +17 -2
  660. package/dist/types/components/co-select/co-select.d.ts +47 -5
  661. package/dist/types/components/co-select/virtualRows.d.ts +44 -0
  662. package/dist/types/components/co-slider/co-slider.d.ts +143 -1
  663. package/dist/types/components/co-swatch-grid/co-swatch-grid.d.ts +37 -0
  664. package/dist/types/components/co-tab/co-tab.d.ts +12 -2
  665. package/dist/types/components/co-tab-group/co-tab-group.d.ts +37 -0
  666. package/dist/types/components/co-tab-group/revealTab.d.ts +29 -0
  667. package/dist/types/components/co-tile/co-tile.d.ts +40 -0
  668. package/dist/types/components/co-toggle-button/co-toggle-button.d.ts +37 -2
  669. package/dist/types/components/co-toggle-button-group/co-toggle-button-group.d.ts +20 -2
  670. package/dist/types/components/co-tooltip/co-tooltip.d.ts +12 -0
  671. package/dist/types/components/co-tree-item/co-tree-item.d.ts +73 -0
  672. package/dist/types/components/co-tree-item/treeItemI18n.d.ts +6 -0
  673. package/dist/types/components.d.ts +1744 -88
  674. package/dist/types/utils/color.d.ts +9 -1
  675. package/dist/types/utils/dragMove.d.ts +63 -0
  676. package/dist/types/utils/gradientBarI18n.d.ts +8 -0
  677. package/dist/types/utils/gradientStops.d.ts +63 -0
  678. package/dist/types/utils/hsv.d.ts +44 -0
  679. package/dist/types/utils/kbdI18n.d.ts +25 -0
  680. package/dist/types/utils/positioning.d.ts +24 -0
  681. package/dist/types/utils/rich-text-host.d.ts +41 -0
  682. package/dist/types/utils/richTextI18n.d.ts +15 -0
  683. package/dist/types/utils/submenu.d.ts +16 -2
  684. package/dist/types/utils/swatchGridI18n.d.ts +6 -0
  685. package/dist/types/utils/test/fake-block-layout.d.ts +7 -0
  686. package/dist/types/utils/test/prosemirror-dom-shim.d.ts +1 -0
  687. package/dist/types/utils/test/shared-contract-css.d.ts +9 -0
  688. package/package.json +5 -5
  689. package/dist/cobalt/p-0678c797.entry.js +0 -1
  690. package/dist/cobalt/p-1d3a79af.entry.js +0 -1
  691. package/dist/cobalt/p-216a63ee.entry.js +0 -1
  692. package/dist/cobalt/p-3d31c575.entry.js +0 -1
  693. package/dist/cobalt/p-416795f5.entry.js +0 -1
  694. package/dist/cobalt/p-56551580.entry.js +0 -1
  695. package/dist/cobalt/p-58137c9e.entry.js +0 -1
  696. package/dist/cobalt/p-5a3e4c81.entry.js +0 -1
  697. package/dist/cobalt/p-5c756787.entry.js +0 -1
  698. package/dist/cobalt/p-67f3b9d6.entry.js +0 -1
  699. package/dist/cobalt/p-6a4f3179.entry.js +0 -1
  700. package/dist/cobalt/p-71cbc53c.entry.js +0 -1
  701. package/dist/cobalt/p-72e52af7.entry.js +0 -1
  702. package/dist/cobalt/p-8530ad16.entry.js +0 -1
  703. package/dist/cobalt/p-8a74bf7d.entry.js +0 -1
  704. package/dist/cobalt/p-8e05b979.entry.js +0 -1
  705. package/dist/cobalt/p-8ebc0c12.entry.js +0 -1
  706. package/dist/cobalt/p-8f2199ff.entry.js +0 -1
  707. package/dist/cobalt/p-9246e09c.entry.js +0 -1
  708. package/dist/cobalt/p-99a655f6.entry.js +0 -1
  709. package/dist/cobalt/p-BYKAgwq3.js +0 -1
  710. package/dist/cobalt/p-CJW9H3Gi.js +0 -1
  711. package/dist/cobalt/p-DFHRS9cJ.js +0 -1
  712. package/dist/cobalt/p-DH5lfRNj.js +0 -2
  713. package/dist/cobalt/p-a1b422ca.entry.js +0 -1
  714. package/dist/cobalt/p-ade07307.entry.js +0 -1
  715. package/dist/cobalt/p-b0762fd8.entry.js +0 -1
  716. package/dist/cobalt/p-b698188c.entry.js +0 -1
  717. package/dist/cobalt/p-bde32f8b.entry.js +0 -1
  718. package/dist/cobalt/p-db805569.entry.js +0 -1
  719. package/dist/cobalt/p-e3aae282.entry.js +0 -1
  720. package/dist/cobalt/p-e49a564c.entry.js +0 -1
  721. package/dist/cobalt/p-ef301976.entry.js +0 -1
  722. package/dist/cobalt/p-f4e1c3c3.entry.js +0 -1
  723. package/dist/cobalt/p-fMqVDypp.js +0 -1
  724. package/dist/components/p-2EOI1nrz.js +0 -1
  725. package/dist/components/p-7TncUlLN.js +0 -1
  726. package/dist/components/p-B4NCaKrR.js +0 -1
  727. package/dist/components/p-BJh68Jqe.js +0 -1
  728. package/dist/components/p-BrAFTkAn.js +0 -1
  729. package/dist/components/p-Bsh0JMGf.js +0 -1
  730. package/dist/components/p-CJW9H3Gi.js +0 -1
  731. package/dist/components/p-CWCYYQrF.js +0 -1
  732. package/dist/components/p-D9T7zKeL.js +0 -1
  733. package/dist/components/p-DFHRS9cJ.js +0 -1
  734. package/dist/components/p-DTPYZwaZ.js +0 -1
  735. package/dist/components/p-Dcg4krSX.js +0 -1
  736. package/dist/components/p-Dh8ffSjK.js +0 -1
@@ -1,5 +1,4 @@
1
1
  import { p as purify } from './purify.es-B2QLgWrz.js';
2
- import { C as COLOR_PALETTE, T as TABLE_CONTEXT_ITEMS, t as toolbarItems } from './toolbar-config-BAYo-RBt.js';
3
2
 
4
3
  // ::- Persistent data structure representing an ordered mapping from
5
4
  // strings to values, with some convenient update methods.
@@ -2655,7 +2654,7 @@ A DOM parser represents a strategy for parsing DOM content into a
2655
2654
  ProseMirror document conforming to a given schema. Its behavior is
2656
2655
  defined by an array of [rules](https://prosemirror.net/docs/ref/#model.ParseRule).
2657
2656
  */
2658
- class DOMParser {
2657
+ let DOMParser$1 = class DOMParser {
2659
2658
  /**
2660
2659
  Create a parser that targets the given schema, using the given
2661
2660
  parsing rules.
@@ -2806,7 +2805,7 @@ class DOMParser {
2806
2805
  return schema.cached.domParser ||
2807
2806
  (schema.cached.domParser = new DOMParser(schema, DOMParser.schemaRules(schema)));
2808
2807
  }
2809
- }
2808
+ };
2810
2809
  const blockTags = {
2811
2810
  address: true, article: true, aside: true, blockquote: true, canvas: true,
2812
2811
  dd: true, div: true, dl: true, fieldset: true, figcaption: true, figure: true,
@@ -10005,7 +10004,7 @@ function skipIgnoredNodesBefore(view) {
10005
10004
  break;
10006
10005
  }
10007
10006
  }
10008
- else if (isBlockNode(node)) {
10007
+ else if (isBlockNode$1(node)) {
10009
10008
  break;
10010
10009
  }
10011
10010
  else {
@@ -10053,7 +10052,7 @@ function skipIgnoredNodesAfter(view) {
10053
10052
  else
10054
10053
  break;
10055
10054
  }
10056
- else if (isBlockNode(node)) {
10055
+ else if (isBlockNode$1(node)) {
10057
10056
  break;
10058
10057
  }
10059
10058
  else {
@@ -10079,7 +10078,7 @@ function skipIgnoredNodesAfter(view) {
10079
10078
  if (moveNode)
10080
10079
  setSelFocus(view, moveNode, moveOffset);
10081
10080
  }
10082
- function isBlockNode(dom) {
10081
+ function isBlockNode$1(dom) {
10083
10082
  let desc = dom.pmViewDesc;
10084
10083
  return desc && desc.node && desc.node.isBlock;
10085
10084
  }
@@ -10359,7 +10358,7 @@ function parseFromClipboard(view, text, html, plainText, $context) {
10359
10358
  dom = child;
10360
10359
  }
10361
10360
  if (!slice) {
10362
- let parser = view.someProp("clipboardParser") || view.someProp("domParser") || DOMParser.fromSchema(view.state.schema);
10361
+ let parser = view.someProp("clipboardParser") || view.someProp("domParser") || DOMParser$1.fromSchema(view.state.schema);
10363
10362
  slice = parser.parseSlice(dom, {
10364
10363
  preserveWhitespace: !!(asText || sliceData),
10365
10364
  context: $context,
@@ -12460,7 +12459,7 @@ function parseBetween(view, from_, to_) {
12460
12459
  }
12461
12460
  }
12462
12461
  let startDoc = view.state.doc;
12463
- let parser = view.someProp("domParser") || DOMParser.fromSchema(view.state.schema);
12462
+ let parser = view.someProp("domParser") || DOMParser$1.fromSchema(view.state.schema);
12464
12463
  let $from = startDoc.resolve(from);
12465
12464
  let sel = null, doc = parser.parse(parent, {
12466
12465
  topNode: $from.parent,
@@ -14322,12 +14321,12 @@ function createNodeFromContent(content, schema, options) {
14322
14321
  })
14323
14322
  });
14324
14323
  if (options.slice) {
14325
- DOMParser.fromSchema(contentCheckSchema).parseSlice(
14324
+ DOMParser$1.fromSchema(contentCheckSchema).parseSlice(
14326
14325
  elementFromString(content),
14327
14326
  options.parseOptions
14328
14327
  );
14329
14328
  } else {
14330
- DOMParser.fromSchema(contentCheckSchema).parse(
14329
+ DOMParser$1.fromSchema(contentCheckSchema).parse(
14331
14330
  elementFromString(content),
14332
14331
  options.parseOptions
14333
14332
  );
@@ -14338,7 +14337,7 @@ function createNodeFromContent(content, schema, options) {
14338
14337
  });
14339
14338
  }
14340
14339
  }
14341
- const parser = DOMParser.fromSchema(schema);
14340
+ const parser = DOMParser$1.fromSchema(schema);
14342
14341
  if (options.slice) {
14343
14342
  return parser.parseSlice(elementFromString(content), options.parseOptions).content;
14344
14343
  }
@@ -34994,6 +34993,799 @@ var Subscript = Mark.create({
34994
34993
  }
34995
34994
  });
34996
34995
 
34996
+ function sanitizeFieldName(raw) {
34997
+ return String(raw ?? '')
34998
+ .trim()
34999
+ .replace(/\s+/g, '_')
35000
+ .replace(/[^\p{L}\p{N}_.]/gu, '_');
35001
+ }
35002
+ /** Admite un grupo `[…]` al final del contenido (enum en JSON). Nueva instancia por llamada (flag g). */
35003
+ function fieldTokenRegex() {
35004
+ return /\[\[\s*([^[\]]+?(?:\[[^[\]]*\])?)\s*\]\]/g;
35005
+ }
35006
+ function parseFieldToken(inner) {
35007
+ const parts = String(inner ?? '').split('|').map((p) => p.trim());
35008
+ let raw = parts[0] ?? '';
35009
+ const required = raw.endsWith('*');
35010
+ if (required)
35011
+ raw = raw.slice(0, -1);
35012
+ const name = sanitizeFieldName(raw);
35013
+ if (!name)
35014
+ return null;
35015
+ const type = parts[1] || 'string';
35016
+ let values = null;
35017
+ if (parts[2]?.startsWith('enum:')) {
35018
+ const rawEnum = parts[2].slice(5).trim();
35019
+ try {
35020
+ const parsed = JSON.parse(rawEnum);
35021
+ values = Array.isArray(parsed) ? parsed.map(String) : null;
35022
+ }
35023
+ catch {
35024
+ values = rawEnum.split(',').map((v) => v.trim()).filter(Boolean);
35025
+ }
35026
+ }
35027
+ return { name, required, type, enum: values };
35028
+ }
35029
+
35030
+ /** Meta de las transacciones que escribe el HOST (valores): no son edición del usuario. */
35031
+ const FIELD_SYNC_META = 'coFieldSync';
35032
+ function parseEnumAttr(raw) {
35033
+ if (!raw)
35034
+ return null;
35035
+ try {
35036
+ const v = JSON.parse(raw);
35037
+ return Array.isArray(v) ? v.map(String) : null;
35038
+ }
35039
+ catch {
35040
+ return null;
35041
+ }
35042
+ }
35043
+ /** Lista de campos en orden de primera aparición (sin repetidos). Acepta un doc de ProseMirror o su JSON. */
35044
+ function collectFields(doc, into = []) {
35045
+ const index = new Map(into.map((f, i) => [f.name, i]));
35046
+ const visit = (attrs) => {
35047
+ const name = attrs?.name;
35048
+ if (!name)
35049
+ return;
35050
+ const at = index.get(name);
35051
+ if (at === undefined) {
35052
+ index.set(name, into.length);
35053
+ into.push({ name, required: !!attrs.required, type: attrs.type || 'string', enum: attrs.enum ?? null });
35054
+ }
35055
+ else if (attrs.required) {
35056
+ into[at].required = true;
35057
+ }
35058
+ };
35059
+ if (typeof doc.descendants === 'function') {
35060
+ doc.descendants((node) => {
35061
+ if (node.type.name === 'mergeField') {
35062
+ visit(node.attrs);
35063
+ return false;
35064
+ }
35065
+ return true;
35066
+ });
35067
+ }
35068
+ else {
35069
+ const walk = (node) => {
35070
+ if (!node)
35071
+ return;
35072
+ if (node.type === 'mergeField')
35073
+ visit(node.attrs ?? {});
35074
+ node.content?.forEach(walk);
35075
+ };
35076
+ walk(doc);
35077
+ }
35078
+ return into;
35079
+ }
35080
+ /** Textblocks tocados por las transacciones (para no recorrer todo el doc por tecla). */
35081
+ function touchedTextblocks(transactions, state) {
35082
+ let ranges = [];
35083
+ transactions.forEach((tr) => {
35084
+ // Lo tocado por transacciones anteriores se lleva a las posiciones de ésta.
35085
+ ranges = ranges.map(([a, b]) => [tr.mapping.map(a, -1), tr.mapping.map(b, 1)]);
35086
+ if (!tr.docChanged)
35087
+ return;
35088
+ tr.mapping.maps.forEach((map, i) => {
35089
+ map.forEach((_oldStart, _oldEnd, newStart, newEnd) => {
35090
+ const rest = tr.mapping.slice(i + 1);
35091
+ ranges.push([rest.map(newStart, -1), rest.map(newEnd, 1)]);
35092
+ });
35093
+ });
35094
+ });
35095
+ const out = new Set();
35096
+ const size = state.doc.content.size;
35097
+ ranges.forEach(([from, to]) => {
35098
+ state.doc.nodesBetween(Math.max(0, from), Math.min(size, to), (node, pos) => {
35099
+ if (node.isTextblock) {
35100
+ out.add(pos);
35101
+ return false;
35102
+ }
35103
+ return true;
35104
+ });
35105
+ });
35106
+ return Array.from(out);
35107
+ }
35108
+ const MergeField = Node3.create({
35109
+ name: 'mergeField',
35110
+ group: 'inline',
35111
+ inline: true,
35112
+ atom: true,
35113
+ selectable: true,
35114
+ addOptions() {
35115
+ return { renameLabel: 'Field name' };
35116
+ },
35117
+ addAttributes() {
35118
+ return {
35119
+ name: { default: '', parseHTML: (el) => el.getAttribute('data-variable') || '', rendered: false },
35120
+ value: { default: '', parseHTML: (el) => el.getAttribute('data-value') ?? '', rendered: false },
35121
+ required: { default: false, parseHTML: (el) => el.getAttribute('data-required') === 'true', rendered: false },
35122
+ type: { default: 'string', parseHTML: (el) => el.getAttribute('data-type') || 'string', rendered: false },
35123
+ enum: { default: null, parseHTML: (el) => parseEnumAttr(el.getAttribute('data-enum')), rendered: false },
35124
+ };
35125
+ },
35126
+ // Prioridad 100: gana a las marcas `span[style]` (color/tamaño), como en V1.
35127
+ parseHTML() {
35128
+ return [{ tag: 'span[data-variable]', priority: 100 }];
35129
+ },
35130
+ // Forma canónica (spec §3.4): SIN estilos (D9), atributos en orden fijo.
35131
+ renderHTML({ node }) {
35132
+ const { name, value, type, required } = node.attrs;
35133
+ const attrs = {
35134
+ class: 'variable-node',
35135
+ 'data-variable': name,
35136
+ 'data-value': value ?? '',
35137
+ 'data-type': type || 'string',
35138
+ 'data-required': required ? 'true' : 'false',
35139
+ };
35140
+ if (node.attrs.enum)
35141
+ attrs['data-enum'] = JSON.stringify(node.attrs.enum);
35142
+ attrs.contenteditable = 'false';
35143
+ return ['span', attrs, value || `[[${name}]]`];
35144
+ },
35145
+ renderText({ node }) {
35146
+ return node.attrs.value || `[[${node.attrs.name}]]`;
35147
+ },
35148
+ addNodeView() {
35149
+ const renameLabel = this.options.renameLabel;
35150
+ return ({ node, getPos, editor }) => {
35151
+ const dom = document.createElement('span');
35152
+ dom.className = 'co-doc-field';
35153
+ dom.contentEditable = 'false';
35154
+ let current = node;
35155
+ let editing = false;
35156
+ const paint = (n) => {
35157
+ dom.textContent = n.attrs.value || `[[${n.attrs.name}]]`;
35158
+ dom.classList.toggle('co-doc-field--empty', !n.attrs.value);
35159
+ dom.classList.toggle('co-doc-field--required', !!n.attrs.required);
35160
+ dom.setAttribute('data-variable', n.attrs.name);
35161
+ };
35162
+ const startRename = () => {
35163
+ if (editing || !editor.isEditable)
35164
+ return;
35165
+ editing = true;
35166
+ const input = document.createElement('input');
35167
+ input.className = 'co-doc-field__input';
35168
+ input.value = current.attrs.name;
35169
+ input.setAttribute('aria-label', renameLabel);
35170
+ dom.textContent = '';
35171
+ dom.appendChild(input);
35172
+ input.focus();
35173
+ input.select();
35174
+ let done = false;
35175
+ const finish = (commit) => {
35176
+ if (done)
35177
+ return;
35178
+ done = true;
35179
+ editing = false;
35180
+ const next = sanitizeFieldName(input.value);
35181
+ const pos = typeof getPos === 'function' ? getPos() : undefined;
35182
+ if (commit && next && next !== current.attrs.name && typeof pos === 'number') {
35183
+ // Como V1: el campo renombrado arranca vacío (solo ESTE nodo).
35184
+ editor.view.dispatch(editor.state.tr.setNodeMarkup(pos, undefined, { ...current.attrs, name: next, value: '' }));
35185
+ }
35186
+ else {
35187
+ paint(current);
35188
+ }
35189
+ };
35190
+ input.addEventListener('keydown', (ev) => {
35191
+ ev.stopPropagation(); // Esc no debe cerrar el overlay del host
35192
+ if (ev.key === 'Enter') {
35193
+ ev.preventDefault();
35194
+ finish(true);
35195
+ }
35196
+ else if (ev.key === 'Escape') {
35197
+ ev.preventDefault();
35198
+ finish(false);
35199
+ }
35200
+ });
35201
+ input.addEventListener('blur', () => finish(false));
35202
+ };
35203
+ dom.addEventListener('dblclick', (ev) => {
35204
+ ev.preventDefault();
35205
+ startRename();
35206
+ });
35207
+ paint(node);
35208
+ return {
35209
+ dom,
35210
+ update(next) {
35211
+ if (next.type.name !== 'mergeField')
35212
+ return false;
35213
+ current = next;
35214
+ if (!editing)
35215
+ paint(next);
35216
+ return true;
35217
+ },
35218
+ stopEvent: (ev) => ev.target instanceof HTMLInputElement,
35219
+ ignoreMutation: () => true,
35220
+ };
35221
+ };
35222
+ },
35223
+ addCommands() {
35224
+ return {
35225
+ insertField: (name, opts = {}) => ({ commands }) => {
35226
+ const clean = sanitizeFieldName(name);
35227
+ if (!clean)
35228
+ return false;
35229
+ return commands.insertContent({
35230
+ type: this.name,
35231
+ attrs: {
35232
+ name: clean,
35233
+ value: opts.value ?? '',
35234
+ required: !!opts.required,
35235
+ type: opts.type || 'string',
35236
+ enum: opts.enum ?? null,
35237
+ },
35238
+ });
35239
+ },
35240
+ setFieldValues: (values) => ({ tr, state, dispatch }) => {
35241
+ let changed = false;
35242
+ state.doc.descendants((node, pos) => {
35243
+ if (node.type.name !== this.name)
35244
+ return true;
35245
+ if (!Object.prototype.hasOwnProperty.call(values, node.attrs.name))
35246
+ return false;
35247
+ const next = String(values[node.attrs.name] ?? '');
35248
+ if (next !== node.attrs.value) {
35249
+ changed = true;
35250
+ if (dispatch)
35251
+ tr.setNodeMarkup(pos, undefined, { ...node.attrs, value: next });
35252
+ }
35253
+ return false;
35254
+ });
35255
+ if (!changed)
35256
+ return false;
35257
+ if (dispatch) {
35258
+ tr.setMeta(FIELD_SYNC_META, true);
35259
+ tr.setMeta('addToHistory', false);
35260
+ }
35261
+ return true;
35262
+ },
35263
+ renameField: (from, to) => ({ tr, state, dispatch }) => {
35264
+ const clean = sanitizeFieldName(to);
35265
+ if (!clean || clean === from)
35266
+ return false; // renombrar a sí mismo borraría los valores
35267
+ let changed = false;
35268
+ state.doc.descendants((node, pos) => {
35269
+ if (node.type.name !== this.name)
35270
+ return true;
35271
+ if (node.attrs.name === from) {
35272
+ changed = true;
35273
+ if (dispatch)
35274
+ tr.setNodeMarkup(pos, undefined, { ...node.attrs, name: clean, value: '' });
35275
+ }
35276
+ return false;
35277
+ });
35278
+ return changed;
35279
+ },
35280
+ };
35281
+ },
35282
+ addProseMirrorPlugins() {
35283
+ const type = this.type;
35284
+ return [
35285
+ new Plugin({
35286
+ key: new PluginKey('coMergeFieldTokens'),
35287
+ // Convierte `[[…]]` escritos o pegados en campos, solo en los textblocks tocados.
35288
+ appendTransaction: (transactions, _old, state) => {
35289
+ if (!transactions.some((t) => t.docChanged && !t.getMeta(FIELD_SYNC_META)))
35290
+ return null;
35291
+ const blocks = touchedTextblocks(transactions, state);
35292
+ if (!blocks.length)
35293
+ return null;
35294
+ const hits = [];
35295
+ blocks.forEach((blockPos) => {
35296
+ const block = state.doc.nodeAt(blockPos);
35297
+ if (!block || block.type.spec.code)
35298
+ return;
35299
+ block.forEach((child, offset) => {
35300
+ if (!child.isText || !child.text || !child.text.includes('[['))
35301
+ return;
35302
+ const re = fieldTokenRegex();
35303
+ let m;
35304
+ while ((m = re.exec(child.text)) !== null) {
35305
+ const def = parseFieldToken(m[1]);
35306
+ if (!def)
35307
+ continue;
35308
+ const from = blockPos + 1 + offset + m.index;
35309
+ hits.push({ from, to: from + m[0].length, def });
35310
+ }
35311
+ });
35312
+ });
35313
+ if (!hits.length)
35314
+ return null;
35315
+ const tr = state.tr;
35316
+ hits
35317
+ .sort((a, b) => b.from - a.from)
35318
+ .forEach(({ from, to, def }) => {
35319
+ tr.replaceWith(from, to, type.create({ ...def, value: '' }));
35320
+ });
35321
+ return tr;
35322
+ },
35323
+ }),
35324
+ ];
35325
+ },
35326
+ });
35327
+
35328
+ /**
35329
+ * Marcador de firma `⟦sig:N⟧`. La forma canónica es la de V1
35330
+ * (tiptap-editor-html/utils/normalizeSignatureSlots.js) byte a byte: pdf.js lee
35331
+ * el token transparente de la capa de texto del PDF y deriva la posición.
35332
+ * Con font-size:1px Chromium colapsaba glifos: el token va a 8px y transparente.
35333
+ *
35334
+ * ⚠️ `editor.getHTML()` NO es la forma canónica: el DOMSerializer de ProseMirror
35335
+ * escribe `style` por CSSOM (`top:0` → `top: 0px;`). La forma exacta sale de
35336
+ * `signatureSlotHtml()` o de un serializador que escriba `style` con `setAttribute`
35337
+ * (`serializePrintHtml`).
35338
+ */
35339
+ const signatureToken = (n) => `⟦sig:${n}⟧`;
35340
+ const SIGNATURE_TOKEN_STYLE = 'position:absolute;top:0;left:0;color:transparent;font-size:8px;line-height:1;white-space:nowrap;pointer-events:none;user-select:none';
35341
+ const signatureBoxStyle = (w, h) => `display:inline-block;position:relative;width:${w}px;height:${h}px;vertical-align:top`;
35342
+ const SIGNATURE_DEFAULT_W = 150;
35343
+ const SIGNATURE_DEFAULT_H = 50;
35344
+ function nextFreeSlot(used = []) {
35345
+ const taken = new Set(used);
35346
+ let n = 1;
35347
+ while (taken.has(n))
35348
+ n += 1;
35349
+ return n;
35350
+ }
35351
+ /** Spec de la forma canónica (orden de atributos = el de V1). Lo usa `renderHTML`. */
35352
+ function signatureSlotSpec({ slot, w, h }) {
35353
+ return [
35354
+ 'span',
35355
+ {
35356
+ 'data-sig-slot': String(slot),
35357
+ 'data-w': String(w),
35358
+ 'data-h': String(h),
35359
+ contenteditable: 'false',
35360
+ style: signatureBoxStyle(w, h),
35361
+ },
35362
+ ['span', { style: SIGNATURE_TOKEN_STYLE }, signatureToken(slot)],
35363
+ ];
35364
+ }
35365
+ /**
35366
+ * La forma canónica como string, armada del MISMO spec que `renderHTML` y sin pasar
35367
+ * por CSSOM. Los valores son números y constantes propias: no hay nada que escapar.
35368
+ */
35369
+ function signatureSlotHtml(attrs) {
35370
+ const [tag, boxAttrs, [innerTag, innerAttrs, text]] = signatureSlotSpec(attrs);
35371
+ const attrsOf = (a) => Object.entries(a)
35372
+ .map(([k, v]) => ` ${k}="${v}"`)
35373
+ .join('');
35374
+ return `<${tag}${attrsOf(boxAttrs)}><${innerTag}${attrsOf(innerAttrs)}>${text}</${innerTag}></${tag}>`;
35375
+ }
35376
+ const toInt = (v, fallback) => {
35377
+ const n = parseInt(v ?? '', 10);
35378
+ return Number.isFinite(n) && n > 0 ? n : fallback;
35379
+ };
35380
+ const SignatureSlot = Node3.create({
35381
+ name: 'signatureSlot',
35382
+ group: 'inline',
35383
+ inline: true,
35384
+ atom: true,
35385
+ selectable: true,
35386
+ addOptions() {
35387
+ return { label: (slot) => `Signature ${slot}` };
35388
+ },
35389
+ addAttributes() {
35390
+ return {
35391
+ slot: { default: 1, parseHTML: (el) => toInt(el.getAttribute('data-sig-slot'), 1), rendered: false },
35392
+ w: { default: SIGNATURE_DEFAULT_W, parseHTML: (el) => toInt(el.getAttribute('data-w'), SIGNATURE_DEFAULT_W), rendered: false },
35393
+ h: { default: SIGNATURE_DEFAULT_H, parseHTML: (el) => toInt(el.getAttribute('data-h'), SIGNATURE_DEFAULT_H), rendered: false },
35394
+ };
35395
+ },
35396
+ parseHTML() {
35397
+ return [{ tag: 'span[data-sig-slot]', priority: 100 }];
35398
+ },
35399
+ renderHTML({ node }) {
35400
+ return signatureSlotSpec(node.attrs);
35401
+ },
35402
+ renderText({ node }) {
35403
+ return signatureToken(node.attrs.slot);
35404
+ },
35405
+ addNodeView() {
35406
+ const label = this.options.label;
35407
+ return ({ node }) => {
35408
+ const dom = document.createElement('span');
35409
+ dom.className = 'co-doc-signature';
35410
+ dom.contentEditable = 'false';
35411
+ const paint = (n) => {
35412
+ dom.style.width = `${n.attrs.w}px`;
35413
+ dom.style.height = `${n.attrs.h}px`;
35414
+ dom.textContent = label(n.attrs.slot);
35415
+ dom.setAttribute('data-sig-slot', String(n.attrs.slot));
35416
+ };
35417
+ paint(node);
35418
+ return {
35419
+ dom,
35420
+ update(next) {
35421
+ if (next.type.name !== 'signatureSlot')
35422
+ return false;
35423
+ paint(next);
35424
+ return true;
35425
+ },
35426
+ ignoreMutation: () => true,
35427
+ };
35428
+ };
35429
+ },
35430
+ addCommands() {
35431
+ return {
35432
+ insertSignatureSlot: (size = {}) => ({ state, commands }) => {
35433
+ const used = [];
35434
+ state.doc.descendants((n) => {
35435
+ if (n.type.name === this.name)
35436
+ used.push(n.attrs.slot);
35437
+ });
35438
+ return commands.insertContent({
35439
+ type: this.name,
35440
+ attrs: { slot: nextFreeSlot(used), w: size.w ?? SIGNATURE_DEFAULT_W, h: size.h ?? SIGNATURE_DEFAULT_H },
35441
+ });
35442
+ },
35443
+ };
35444
+ },
35445
+ });
35446
+
35447
+ /** Tamaño base del cuerpo de impresión (SharedContractUtils: 14px/1.5). */
35448
+ const BASE_FONT_PX = 14;
35449
+ /** Valor crudo de una propiedad del atributo style (conserva `#hex`; `el.style.color` lo pasaría a rgb). */
35450
+ function rawStyleValue(el, prop) {
35451
+ const style = el.getAttribute('style') || '';
35452
+ for (const decl of style.split(';')) {
35453
+ const i = decl.indexOf(':');
35454
+ if (i <= 0)
35455
+ continue;
35456
+ if (decl.slice(0, i).trim().toLowerCase() === prop) {
35457
+ const v = decl.slice(i + 1).trim();
35458
+ return v || null;
35459
+ }
35460
+ }
35461
+ return null;
35462
+ }
35463
+ /** V1 pasaba mal las unidades (12pt → 12px, 1.5em → 1px). Acá se convierten a px de verdad. */
35464
+ function normalizeFontSizePx(v) {
35465
+ if (v == null)
35466
+ return null;
35467
+ const m = /^\s*(\d+(?:\.\d+)?)\s*(px|pt|em|rem|%)?\s*$/i.exec(String(v));
35468
+ if (!m)
35469
+ return null;
35470
+ const n = parseFloat(m[1]);
35471
+ const unit = (m[2] || 'px').toLowerCase();
35472
+ const px = unit === 'px' ? n : unit === 'pt' ? (n * 4) / 3 : unit === '%' ? (n / 100) * BASE_FONT_PX : n * BASE_FONT_PX;
35473
+ const r = Math.round(px);
35474
+ return r >= 1 && r <= 400 ? `${r}px` : null;
35475
+ }
35476
+ /**
35477
+ * Color de texto en la forma de V1: `<span class="editor-text-style" style="color: X">`,
35478
+ * SIEMPRE por fuera del tamaño (un span con color + tamaño pierde el color en V1).
35479
+ * Se llama `textStyle` para que la barra lea `getAttributes('textStyle').color`.
35480
+ * Prioridad alta = marca más externa (link 1003 > color 1002 > tamaño 1001 > resto 100).
35481
+ *
35482
+ * La regla de parse queda con la prioridad por defecto (50): la firma
35483
+ * (`span[data-sig-slot]`) y el campo (`span[data-variable]`) van a 100 y le ganan
35484
+ * aunque lleven `style` inline.
35485
+ */
35486
+ const PrintTextColor = Mark.create({
35487
+ name: 'textStyle',
35488
+ priority: 1002,
35489
+ addAttributes() {
35490
+ return {
35491
+ color: { default: null, parseHTML: (el) => rawStyleValue(el, 'color'), rendered: false },
35492
+ };
35493
+ },
35494
+ parseHTML() {
35495
+ return [{ tag: 'span', consuming: false, getAttrs: (el) => (rawStyleValue(el, 'color') ? {} : false) }];
35496
+ },
35497
+ renderHTML({ mark }) {
35498
+ return ['span', { class: 'editor-text-style', style: `color: ${mark.attrs.color}` }, 0];
35499
+ },
35500
+ addCommands() {
35501
+ return {
35502
+ setColor: (color) => ({ commands }) => commands.setMark(this.name, { color }),
35503
+ unsetColor: () => ({ commands }) => commands.unsetMark(this.name),
35504
+ };
35505
+ },
35506
+ });
35507
+ /** Tamaño en px como marca APARTE, anidada dentro del color: `<span style="font-size: Npx">`. */
35508
+ const PrintFontSize = Mark.create({
35509
+ name: 'printFontSize',
35510
+ priority: 1001,
35511
+ addAttributes() {
35512
+ return {
35513
+ size: { default: null, parseHTML: (el) => normalizeFontSizePx(rawStyleValue(el, 'font-size')), rendered: false },
35514
+ };
35515
+ },
35516
+ parseHTML() {
35517
+ return [{ tag: 'span', consuming: false, getAttrs: (el) => (normalizeFontSizePx(rawStyleValue(el, 'font-size')) ? {} : false) }];
35518
+ },
35519
+ renderHTML({ mark }) {
35520
+ return ['span', { style: `font-size: ${mark.attrs.size}` }, 0];
35521
+ },
35522
+ addCommands() {
35523
+ return {
35524
+ setFontSize: (size) => ({ commands }) => {
35525
+ const px = normalizeFontSizePx(size);
35526
+ return px ? commands.setMark(this.name, { size: px }) : false;
35527
+ },
35528
+ unsetFontSize: () => ({ commands }) => commands.unsetMark(this.name),
35529
+ };
35530
+ },
35531
+ });
35532
+
35533
+ const IMAGE_LAYOUT_MODES = ['inline', 'wrap-left', 'wrap-right', 'break'];
35534
+ const MODE_PROPS = new Set(['float', 'clear', 'display', 'padding-left', 'padding-right']);
35535
+ const MODE_STYLES = {
35536
+ inline: { wrapper: ['display: inline-block'], container: ['display: inline-block'] },
35537
+ 'wrap-left': { wrapper: ['display: inline-block', 'float: left'], container: ['display: inline-block', 'float: left', 'padding-right: 8px'] },
35538
+ 'wrap-right': { wrapper: ['display: inline-block', 'float: right'], container: ['display: inline-block', 'float: right', 'padding-left: 8px'] },
35539
+ break: { wrapper: ['display: block'], container: ['display: block'] },
35540
+ };
35541
+ /** Una imagen nueva nace en línea (ruling del ledger); al leer una de V1 manda su wrapperstyle. */
35542
+ const DEFAULT_WRAPPER_STYLE = 'display: inline-block;';
35543
+ const DEFAULT_CONTAINER_STYLE = 'height: auto; cursor: pointer; display: inline-block;';
35544
+ function stripModeProps(style) {
35545
+ return String(style || '')
35546
+ .split(';')
35547
+ .map((d) => d.trim())
35548
+ .filter((d) => d.includes(':'))
35549
+ .filter((d) => !MODE_PROPS.has(d.slice(0, d.indexOf(':')).trim().toLowerCase()));
35550
+ }
35551
+ function applyImageLayoutMode(mode, { wrapperStyle = '', containerStyle = '' } = {}) {
35552
+ const preset = MODE_STYLES[mode];
35553
+ if (!preset)
35554
+ return { wrapperStyle: wrapperStyle || '', containerStyle: containerStyle || '' };
35555
+ const join = (mods, rest) => [...mods, ...rest].join('; ').replace(/;?\s*$/, ';');
35556
+ return {
35557
+ wrapperStyle: join(preset.wrapper, stripModeProps(wrapperStyle || '')),
35558
+ containerStyle: join(preset.container, stripModeProps(containerStyle || '')),
35559
+ };
35560
+ }
35561
+ function getImageLayoutMode({ wrapperStyle = '', containerStyle = '' } = {}) {
35562
+ const style = `${containerStyle || ''};${wrapperStyle || ''}`.toLowerCase();
35563
+ if (/float:\s*left/.test(style))
35564
+ return 'wrap-left';
35565
+ if (/float:\s*right/.test(style))
35566
+ return 'wrap-right';
35567
+ if (/display:\s*block\b/.test(style))
35568
+ return 'break';
35569
+ return 'inline';
35570
+ }
35571
+ const HEADER_IMG_MAX = { w: 400, h: 40 };
35572
+ /** Ancho que entra en la banda del encabezado (port de headerContainerStyle de V1). */
35573
+ function headerImageWidth(dims, max = HEADER_IMG_MAX) {
35574
+ if (!dims || !dims.w || !dims.h)
35575
+ return null;
35576
+ const scale = Math.min(1, max.h / dims.h, max.w / dims.w);
35577
+ return Math.max(1, Math.round(dims.w * scale));
35578
+ }
35579
+ /**
35580
+ * `width:` anclado a inicio de declaración: sin el ancla, `min-width`/`max-width` también
35581
+ * matchean y se leía (y se pisaba) el ancho equivocado de un `containerstyle` de V1.
35582
+ */
35583
+ const WIDTH_DECL = /(^|;)(\s*)width:\s*([0-9.]+)px/i;
35584
+ function withWidth(style, width) {
35585
+ if (!width)
35586
+ return style;
35587
+ const decl = `width: ${width}px`;
35588
+ return WIDTH_DECL.test(style)
35589
+ ? style.replace(WIDTH_DECL, (_m, sep, ws) => `${sep}${ws}${decl}`)
35590
+ : `${decl}; ${style}`.trim();
35591
+ }
35592
+ function parseWidth(el) {
35593
+ const attr = parseInt(el.getAttribute('width') || '', 10);
35594
+ if (attr > 0)
35595
+ return attr;
35596
+ const m = WIDTH_DECL.exec(el.getAttribute('containerstyle') || el.getAttribute('style') || '');
35597
+ return m ? Math.round(parseFloat(m[3])) : null;
35598
+ }
35599
+ /**
35600
+ * H10: el node view de resize de Tiptap solo copia los atributos RENDERIZADOS, y
35601
+ * `wrapperStyle`/`containerStyle` no lo son → en el editor toda imagen se veía en línea.
35602
+ * Se lleva el modo al contenedor (`[data-resize-container]`) para que la hoja pagine
35603
+ * como el PDF. `inline-flex`/`flex` (no `inline-block`/`block`): el contenedor de
35604
+ * resize los necesita para ubicar las manijas.
35605
+ */
35606
+ function syncImageModeToContainer(container, node) {
35607
+ const mode = getImageLayoutMode(node.attrs);
35608
+ container.dataset.imageLayout = mode;
35609
+ container.style.float = mode === 'wrap-left' ? 'left' : mode === 'wrap-right' ? 'right' : '';
35610
+ container.style.paddingLeft = mode === 'wrap-right' ? '8px' : '';
35611
+ container.style.paddingRight = mode === 'wrap-left' ? '8px' : '';
35612
+ container.style.display = mode === 'break' ? 'flex' : 'inline-flex';
35613
+ }
35614
+ const PrintImage = Image.extend({
35615
+ name: 'image',
35616
+ addOptions() {
35617
+ return { ...this.parent?.(), header: false };
35618
+ },
35619
+ addAttributes() {
35620
+ return {
35621
+ ...this.parent?.(),
35622
+ width: { default: null, parseHTML: (el) => parseWidth(el), rendered: false },
35623
+ dataFileId: { default: null, parseHTML: (el) => el.getAttribute('data-file-id'), rendered: false },
35624
+ containerStyle: { default: null, parseHTML: (el) => el.getAttribute('containerstyle'), rendered: false },
35625
+ wrapperStyle: { default: null, parseHTML: (el) => el.getAttribute('wrapperstyle'), rendered: false },
35626
+ };
35627
+ },
35628
+ parseHTML() {
35629
+ return [{ tag: this.options.allowBase64 ? 'img[src]' : 'img[src]:not([src^="data:"])', priority: 100 }];
35630
+ },
35631
+ renderHTML({ node }) {
35632
+ const a = node.attrs;
35633
+ const width = a.width ? Math.round(Number(a.width)) : null;
35634
+ const wrapper = a.wrapperStyle || DEFAULT_WRAPPER_STYLE;
35635
+ const container = withWidth(a.containerStyle || DEFAULT_CONTAINER_STYLE, width);
35636
+ const img = { src: a.src };
35637
+ if (a.alt)
35638
+ img.alt = a.alt;
35639
+ if (a.title)
35640
+ img.title = a.title;
35641
+ if (a.dataFileId)
35642
+ img['data-file-id'] = String(a.dataFileId);
35643
+ if (width) {
35644
+ img.width = String(width);
35645
+ img.style = this.options.header ? `width: ${width}px; height: auto;` : `width: ${width}px;`;
35646
+ }
35647
+ img.containerstyle = container;
35648
+ img.wrapperstyle = wrapper;
35649
+ return ['span', { style: wrapper }, ['img', img]];
35650
+ },
35651
+ addNodeView() {
35652
+ const parent = this.parent?.();
35653
+ if (!parent)
35654
+ return null;
35655
+ return (props) => {
35656
+ const view = parent(props);
35657
+ const container = view.dom;
35658
+ syncImageModeToContainer(container, props.node);
35659
+ const update = view.update?.bind(view);
35660
+ view.update = (node, decorations, inner) => {
35661
+ const ok = update ? update(node, decorations, inner) : node.type === props.node.type;
35662
+ if (ok)
35663
+ syncImageModeToContainer(container, node);
35664
+ return ok;
35665
+ };
35666
+ return view;
35667
+ };
35668
+ },
35669
+ addCommands() {
35670
+ return {
35671
+ ...this.parent?.(),
35672
+ setImageLayoutMode: (mode) => ({ state, tr, dispatch }) => {
35673
+ const sel = state.selection;
35674
+ if (!(sel instanceof NodeSelection) || sel.node.type.name !== this.name)
35675
+ return false;
35676
+ if (dispatch) {
35677
+ const next = applyImageLayoutMode(mode, {
35678
+ wrapperStyle: sel.node.attrs.wrapperStyle || DEFAULT_WRAPPER_STYLE,
35679
+ containerStyle: withWidth(sel.node.attrs.containerStyle || DEFAULT_CONTAINER_STYLE, sel.node.attrs.width),
35680
+ });
35681
+ tr.setNodeMarkup(sel.from, undefined, { ...sel.node.attrs, ...next });
35682
+ // H7: la NodeSelection no sobrevive al reemplazo de la hoja; sin esto la barra de imagen se cierra.
35683
+ tr.setSelection(NodeSelection.create(tr.doc, sel.from));
35684
+ }
35685
+ return true;
35686
+ },
35687
+ };
35688
+ },
35689
+ });
35690
+
35691
+ /** Validación de V1 (tiptap-editor-html/extensions/index.js): exige un `.`, rechaza `/` y `./`. */
35692
+ const printLinkAllowed = (url, ctx) => ctx.defaultValidate(url) && !url.startsWith('./') && !url.startsWith('/') && url.includes('.');
35693
+ /** Autolink APAGADO: generaba `<a>` dentro de `{{ }}` y rompía Handlebars. Prioridad 1003 = marca más externa. */
35694
+ const PrintLink = Link.extend({ inclusive: () => false, priority: 1003 }).configure({
35695
+ autolink: false,
35696
+ openOnClick: false,
35697
+ defaultProtocol: 'https',
35698
+ protocols: ['mailto', { scheme: 'tel', optionalSlashes: true }],
35699
+ HTMLAttributes: { target: '_blank', rel: 'noopener noreferrer', class: 'editor-link' },
35700
+ isAllowedUri: printLinkAllowed,
35701
+ });
35702
+
35703
+ /** Resalta `{{ … }}` con una DECORACIÓN: no toca el documento ni se serializa. */
35704
+ const HB_RE = /\{\{[^}]*\}\}/g;
35705
+ function build(doc) {
35706
+ const decos = [];
35707
+ doc.descendants((node, pos) => {
35708
+ if (!node.isText || !node.text)
35709
+ return true;
35710
+ HB_RE.lastIndex = 0;
35711
+ let m;
35712
+ while ((m = HB_RE.exec(node.text)) !== null) {
35713
+ decos.push(Decoration.inline(pos + m.index, pos + m.index + m[0].length, { class: 'co-doc-hb' }));
35714
+ }
35715
+ return true;
35716
+ });
35717
+ return DecorationSet.create(doc, decos);
35718
+ }
35719
+ const HandlebarsHighlight = Extension.create({
35720
+ name: 'handlebarsHighlight',
35721
+ addProseMirrorPlugins() {
35722
+ const key = new PluginKey('coHandlebarsHighlight');
35723
+ return [
35724
+ new Plugin({
35725
+ key,
35726
+ state: {
35727
+ init: (_config, { doc }) => build(doc),
35728
+ apply: (tr, old) => (tr.docChanged ? build(tr.doc) : old),
35729
+ },
35730
+ props: {
35731
+ decorations(state) {
35732
+ return key.getState(state);
35733
+ },
35734
+ },
35735
+ }),
35736
+ ];
35737
+ },
35738
+ });
35739
+
35740
+ /**
35741
+ * Presets `print` (cuerpo) y `print-header` (banda). Paridad ESTRICTA de
35742
+ * funciones de V1 (spec §3.5/§3.6, D7): sin subrayado, familia, peso,
35743
+ * interlineado, espaciado ni sangría; autolink apagado; sin nodo `variable`
35744
+ * (comparte selector `span[data-variable]` con el campo). `trailingNode` apagado:
35745
+ * V1 no lo tenía y una tabla al final sumaría una línea vacía al PDF.
35746
+ * Las etiquetas (`labels`) las localiza el host; sin ellas quedan en inglés.
35747
+ */
35748
+ function getPrintExtensions(preset, opts = {}) {
35749
+ const header = preset === 'print-header';
35750
+ const { features = {}, labels = {} } = opts;
35751
+ const starter = { underline: false, link: false, trailingNode: false };
35752
+ if (header) {
35753
+ Object.assign(starter, {
35754
+ heading: false, bulletList: false, orderedList: false, listItem: false, listKeymap: false,
35755
+ blockquote: false, codeBlock: false, horizontalRule: false,
35756
+ });
35757
+ }
35758
+ else {
35759
+ starter.heading = { levels: [1, 2, 3, 4] };
35760
+ }
35761
+ const exts = [
35762
+ StarterKit.configure(starter),
35763
+ PrintTextColor,
35764
+ PrintFontSize,
35765
+ Highlight.configure({ multicolor: true }),
35766
+ TextAlign.configure({ types: header ? ['paragraph'] : ['heading', 'paragraph'] }),
35767
+ HandlebarsHighlight,
35768
+ ];
35769
+ if (!header) {
35770
+ exts.push(PrintLink, Table.configure({ resizable: true, renderWrapper: true }), TableRow, TableHeader, TableCell);
35771
+ }
35772
+ exts.push(PrintImage.configure({
35773
+ inline: true,
35774
+ allowBase64: true,
35775
+ header,
35776
+ resize: header
35777
+ ? false
35778
+ : { enabled: true, directions: ['left', 'right', 'bottom-left', 'bottom-right'], minWidth: 50, minHeight: 20, alwaysPreserveAspectRatio: true },
35779
+ }));
35780
+ if (features.fields !== false) {
35781
+ exts.push(MergeField.configure({ renameLabel: labels.fieldName ?? 'Field name' }));
35782
+ }
35783
+ if (!header && features.signatureSlots !== false) {
35784
+ exts.push(labels.signature ? SignatureSlot.configure({ label: labels.signature }) : SignatureSlot);
35785
+ }
35786
+ return exts;
35787
+ }
35788
+
34997
35789
  /** Shared link configuration — never auto-opens inside the editor, safe rel. */
34998
35790
  const LINK_CONFIG = {
34999
35791
  openOnClick: false,
@@ -35072,6 +35864,8 @@ const PRESET_TOOLBAR = {
35072
35864
  email: 'full',
35073
35865
  document: 'full',
35074
35866
  'block-email': 'basic',
35867
+ print: 'document',
35868
+ 'print-header': 'document',
35075
35869
  };
35076
35870
  /** Suggested max length per preset (null = no limit). */
35077
35871
  const PRESET_MAXLENGTH = {
@@ -35081,10 +35875,22 @@ const PRESET_MAXLENGTH = {
35081
35875
  email: null,
35082
35876
  document: null,
35083
35877
  'block-email': null,
35878
+ print: null,
35879
+ 'print-header': null,
35084
35880
  };
35085
35881
  /** Build the ordered extension array for a preset. */
35086
35882
  function getExtensions(preset = 'task', options = {}) {
35087
- const { placeholder, maxLength, features = {}, includeUiExtensions = true } = options;
35883
+ const { placeholder, maxLength, features = {}, includeUiExtensions = true, labels } = options;
35884
+ // Presets de impresión: schema propio (spec contracts-v2-contract-editor §3.5/§3.6).
35885
+ if (preset === 'print' || preset === 'print-header') {
35886
+ const exts = getPrintExtensions(preset, {
35887
+ features: { fields: features.fields, signatureSlots: features.signatureSlots },
35888
+ labels,
35889
+ });
35890
+ if (includeUiExtensions && placeholder)
35891
+ exts.push(Placeholder.configure({ placeholder }));
35892
+ return exts;
35893
+ }
35088
35894
  const config = STARTERKIT_CONFIG[preset] ?? STARTERKIT_CONFIG.task;
35089
35895
  const exts = [StarterKit.configure(config), CobaltLink];
35090
35896
  // Color requires TextStyle to be registered first. Only presets that keep
@@ -35182,7 +35988,573 @@ function defaultToolbarForPreset(preset = 'task') {
35182
35988
  function maxLengthForPreset(preset = 'task') {
35183
35989
  return PRESET_MAXLENGTH[preset] ?? null;
35184
35990
  }
35185
- const PRESETS = ['comment', 'task', 'notes', 'email', 'document', 'block-email'];
35991
+ const PRESETS = ['comment', 'task', 'notes', 'email', 'document', 'block-email', 'print', 'print-header'];
35992
+
35993
+ // src/generateHTML.ts
35994
+ function getHTMLFromFragment(doc, schema, options) {
35995
+ if (typeof window === "undefined") {
35996
+ throw new Error(
35997
+ "getHTMLFromFragment can only be used in a browser environment\nIf you want to use this in a Node environment, use the `@tiptap/html/server` import instead."
35998
+ );
35999
+ }
36000
+ const wrap = window.document.createElement("div");
36001
+ DOMSerializer.fromSchema(schema).serializeFragment(
36002
+ doc.content,
36003
+ {
36004
+ document: window.document
36005
+ },
36006
+ wrap
36007
+ );
36008
+ return wrap.innerHTML;
36009
+ }
36010
+
36011
+ // src/generateHTML.ts
36012
+ function generateHTML(doc, extensions) {
36013
+ if (typeof window === "undefined") {
36014
+ throw new Error(
36015
+ "generateHTML can only be used in a browser environment\nIf you want to use this in a Node environment, use the `@tiptap/html/server` import instead."
36016
+ );
36017
+ }
36018
+ const schema = getSchema(extensions);
36019
+ const contentNode = Node$1.fromJSON(schema, doc);
36020
+ return getHTMLFromFragment(contentNode, schema);
36021
+ }
36022
+ function generateJSON(html, extensions, options) {
36023
+ if (typeof window === "undefined") {
36024
+ throw new Error(
36025
+ "generateJSON can only be used in a browser environment\nIf you want to use this in a Node environment, use the `@tiptap/html/server` import instead."
36026
+ );
36027
+ }
36028
+ const schema = getSchema(extensions);
36029
+ const doc = new window.DOMParser().parseFromString(html, "text/html");
36030
+ if (!doc) {
36031
+ throw new Error("Failed to parse HTML string");
36032
+ }
36033
+ return DOMParser$1.fromSchema(schema).parse(doc.body, options).toJSON();
36034
+ }
36035
+
36036
+ const BASE_INLINE = ['p', 'br', 'strong', 'em', 'a', 'span'];
36037
+ const BASE_ATTR = ['href', 'target', 'rel', 'data-mention-id', 'data-mention-label'];
36038
+ const SANITIZE_CONFIGS = {
36039
+ // Más ancho que su schema A PROPÓSITO (única excepción al lock-step): el
36040
+ // editor `comment` no puede autorar listas ni headings (STARTERKIT_CONFIG los
36041
+ // apaga y ProseMirror descarta esos nodos al parsear el paste), pero el
36042
+ // VIEWER tiene que pintarlos cuando el HTML entra por API — una nota de
36043
+ // enriquecimiento (Apollo.io) trae <ul>/<li>/<h4> y con KEEP_CONTENT el
36044
+ // texto se hoisteaba al padre: lista corrida, heading fundido en el cuerpo.
36045
+ // Espejo inline en core/co-rich-text-viewer.tsx (ALLOWED_TAGS.comment).
36046
+ comment: {
36047
+ ALLOWED_TAGS: [...BASE_INLINE, 'ul', 'ol', 'li', 'h1', 'h2', 'h3', 'h4'],
36048
+ ALLOWED_ATTR: [...BASE_ATTR],
36049
+ ALLOW_DATA_ATTR: false,
36050
+ },
36051
+ task: {
36052
+ ALLOWED_TAGS: [...BASE_INLINE, 'u', 's', 'code', 'ul', 'ol', 'li', 'blockquote', 'input', 'label'],
36053
+ ALLOWED_ATTR: [...BASE_ATTR, 'type', 'checked', 'disabled', 'data-type', 'data-checked', 'data-variant'],
36054
+ ALLOW_DATA_ATTR: false,
36055
+ },
36056
+ // Lock-step con getExtensions('notes'): task sin checklists + TextStyle/Color
36057
+ // (`style` capado a STYLE_ALLOWED_PROPS) + Highlight multicolor (`mark` con
36058
+ // `data-color`).
36059
+ notes: {
36060
+ ALLOWED_TAGS: [...BASE_INLINE, 'u', 's', 'code', 'ul', 'ol', 'li', 'blockquote', 'mark'],
36061
+ ALLOWED_ATTR: [...BASE_ATTR, 'style', 'data-color'],
36062
+ ALLOW_DATA_ATTR: false,
36063
+ },
36064
+ email: {
36065
+ ALLOWED_TAGS: [
36066
+ ...BASE_INLINE, 'u', 's', 'code', 'ul', 'ol', 'li', 'blockquote',
36067
+ 'h2', 'h3', 'div', 'img',
36068
+ ],
36069
+ ALLOWED_ATTR: [...BASE_ATTR, 'style', 'data-variable', 'data-transform', 'data-fallback', 'src', 'alt', 'width', 'height', 'data-file-id', 'data-image-layout'],
36070
+ ALLOW_DATA_ATTR: false,
36071
+ },
36072
+ document: {
36073
+ ALLOWED_TAGS: [
36074
+ ...BASE_INLINE, 'u', 's', 'code', 'ul', 'ol', 'li', 'blockquote',
36075
+ 'h1', 'h2', 'h3', 'h4', 'hr', 'div', 'mark', 'img',
36076
+ 'table', 'thead', 'tbody', 'tr', 'th', 'td',
36077
+ 'input', 'label', 'iframe',
36078
+ ],
36079
+ ALLOWED_ATTR: [...BASE_ATTR, 'style', 'data-variable', 'colspan', 'rowspan', 'src', 'alt', 'width', 'height', 'type', 'checked', 'disabled', 'allowfullscreen', 'frameborder', 'allow', 'loading'],
36080
+ ALLOW_DATA_ATTR: true,
36081
+ },
36082
+ 'block-email': {
36083
+ ALLOWED_TAGS: [...BASE_INLINE, 'u', 's', 'code', 'ul', 'ol', 'li', 'blockquote', 'h2', 'h3', 'div', 'img'],
36084
+ ALLOWED_ATTR: [...BASE_ATTR, 'style', 'data-variable', 'data-transform', 'data-fallback', 'src', 'alt', 'width', 'height', 'data-file-id', 'data-image-layout', 'data-type', 'data-label', 'data-href', 'data-bg', 'data-color', 'data-height'],
36085
+ ALLOW_DATA_ATTR: false,
36086
+ },
36087
+ // Espejo de getPrintExtensions('print'): cuerpo del documento de impresión.
36088
+ // `class` y data-* son parte de la forma que V1 re-parsea (editor-text-style,
36089
+ // variable-node, editor-link, tableWrapper, trailingBreak, data-variable…).
36090
+ print: {
36091
+ ALLOWED_TAGS: [
36092
+ 'p', 'br', 'strong', 'em', 's', 'code', 'a', 'span', 'mark',
36093
+ 'h1', 'h2', 'h3', 'h4', 'ul', 'ol', 'li', 'blockquote', 'pre', 'hr', 'img', 'div',
36094
+ 'table', 'colgroup', 'col', 'thead', 'tbody', 'tr', 'th', 'td',
36095
+ ],
36096
+ ALLOWED_ATTR: [
36097
+ 'href', 'target', 'rel', 'class', 'style', 'src', 'alt', 'title', 'width', 'height',
36098
+ 'colspan', 'rowspan', 'colwidth', 'start', 'contenteditable', 'containerstyle', 'wrapperstyle',
36099
+ ],
36100
+ ALLOW_DATA_ATTR: true,
36101
+ ADD_URI_SAFE_ATTR: ['containerstyle', 'wrapperstyle'],
36102
+ },
36103
+ // Espejo de getPrintExtensions('print-header'): la banda del encabezado.
36104
+ 'print-header': {
36105
+ ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 's', 'code', 'span', 'mark', 'img'],
36106
+ ALLOWED_ATTR: ['class', 'style', 'src', 'alt', 'title', 'width', 'height', 'contenteditable', 'containerstyle', 'wrapperstyle'],
36107
+ ALLOW_DATA_ATTR: true,
36108
+ ADD_URI_SAFE_ATTR: ['containerstyle', 'wrapperstyle'],
36109
+ },
36110
+ };
36111
+ /**
36112
+ * `<iframe>`s are permitted only with an `https:` source (blocks javascript:,
36113
+ * data:, and plain http: embeds). This is what makes allowing iframes safe-ish
36114
+ * for a trusted-author document; YouTube embeds satisfy it too.
36115
+ */
36116
+ const SAFE_IFRAME_SRC_RE = /^https:\/\/[^\s"'<>]+$/i;
36117
+ /** Tags forbidden in every preset, regardless of the allow-list. */
36118
+ const FORBID_TAGS = ['script', 'object', 'embed', 'form', 'textarea', 'style'];
36119
+ /** Attributes forbidden in every preset (event handlers handled by DOMPurify itself). */
36120
+ const FORBID_ATTR = ['onerror', 'onload', 'onclick'];
36121
+ /**
36122
+ * Resolve the effective config for a preset + feature overrides. Features can
36123
+ * only ADD capabilities (mirroring `getExtensions`, where they register extra
36124
+ * nodes); they never narrow a preset's base whitelist.
36125
+ */
36126
+ function configFor(preset, features) {
36127
+ const cfg = SANITIZE_CONFIGS[preset] ?? SANITIZE_CONFIGS.task;
36128
+ if (!features)
36129
+ return cfg;
36130
+ const tags = new Set(cfg.ALLOWED_TAGS);
36131
+ const attr = new Set(cfg.ALLOWED_ATTR);
36132
+ if (features.image) {
36133
+ tags.add('img');
36134
+ ['src', 'alt', 'width', 'height'].forEach((a) => attr.add(a));
36135
+ }
36136
+ if (features.variables)
36137
+ attr.add('data-variable');
36138
+ if (features.mentions) {
36139
+ // data-mention-id/label ya están en BASE_ATTR. Los attrs del markup V1
36140
+ // (quill-mention) se suman porque el BACKEND los parsea para notificar —
36141
+ // re-editar una nota no debe destruirlos.
36142
+ // Espejo inline en core/co-rich-text-viewer.tsx (el viewer no importa este módulo para no cargar el engine) — si cambias esta lista, cambia la del viewer.
36143
+ ['data-id', 'data-value', 'data-denotation-char', 'data-index'].forEach((a) => attr.add(a));
36144
+ }
36145
+ return { ...cfg, ALLOWED_TAGS: [...tags], ALLOWED_ATTR: [...attr] };
36146
+ }
36147
+ /**
36148
+ * `style` is only allowed in notes/email/document, and even there we cap it to
36149
+ * the properties our extensions actually emit (TextStyle/Color/TextAlign,
36150
+ * ListStyleExtension's `list-style-type`). Everything else — position,
36151
+ * background-image url(), etc. — is UI-redressing/tracking surface.
36152
+ */
36153
+ const STYLE_ALLOWED_PROPS = new Set(['color', 'background-color', 'text-align', 'list-style-type']);
36154
+ const UNSAFE_STYLE_VALUE = /url\s*\(|expression\s*\(/i;
36155
+ const DEFAULT_STYLE_POLICY = {
36156
+ attrs: new Set(['style']),
36157
+ allows: (prop) => STYLE_ALLOWED_PROPS.has(prop),
36158
+ keepOriginalWhenClean: false,
36159
+ };
36160
+ const COLOR_VALUE = /^(#[0-9a-f]{3,8}|rgba?\([\d.\s,%]+\)|hsla?\([\d.\s,%deg]+\)|[a-z]+)$/i;
36161
+ const LENGTH_TOKEN = /^(-?\d+(\.\d+)?(px|pt|em|rem|%|mm|cm|in)?|auto)$/i;
36162
+ const lengths = (v) => v.split(/\s+/).every((t) => LENGTH_TOKEN.test(t));
36163
+ const oneOf = (re) => (v) => re.test(v);
36164
+ /** Lo que emiten las extensiones del preset print y la firma canónica (spec §3.4, §4.1). */
36165
+ const PRINT_STYLE_RULES = {
36166
+ color: oneOf(COLOR_VALUE),
36167
+ 'background-color': oneOf(COLOR_VALUE),
36168
+ 'text-align': oneOf(/^(left|center|right|justify)$/i),
36169
+ 'font-size': oneOf(/^\d+(\.\d+)?(px|pt|em|rem|%)$/i),
36170
+ width: lengths,
36171
+ height: lengths,
36172
+ 'min-width': lengths,
36173
+ 'max-width': lengths,
36174
+ display: oneOf(/^(inline-block|inline|block|flex|inline-flex)$/i),
36175
+ float: oneOf(/^(left|right|none)$/i),
36176
+ margin: lengths,
36177
+ 'margin-top': lengths,
36178
+ 'margin-right': lengths,
36179
+ 'margin-bottom': lengths,
36180
+ 'margin-left': lengths,
36181
+ padding: lengths,
36182
+ 'padding-top': lengths,
36183
+ 'padding-right': lengths,
36184
+ 'padding-bottom': lengths,
36185
+ 'padding-left': lengths,
36186
+ 'vertical-align': oneOf(/^(top|middle|bottom|baseline|text-top|text-bottom)$/i),
36187
+ position: oneOf(/^(relative|absolute)$/i),
36188
+ top: lengths,
36189
+ left: lengths,
36190
+ 'line-height': oneOf(/^\d+(\.\d+)?(px)?$/i),
36191
+ 'white-space': oneOf(/^(nowrap|normal|pre-wrap)$/i),
36192
+ 'pointer-events': oneOf(/^none$/i),
36193
+ 'user-select': oneOf(/^none$/i),
36194
+ cursor: oneOf(/^(pointer|default)$/i),
36195
+ };
36196
+ const PRINT_STYLE_POLICY = {
36197
+ // containerstyle/wrapperstyle son CSS que V1 aplica inline a la imagen (H2).
36198
+ attrs: new Set(['style', 'containerstyle', 'wrapperstyle']),
36199
+ allows: (prop, value) => Object.prototype.hasOwnProperty.call(PRINT_STYLE_RULES, prop) && PRINT_STYLE_RULES[prop](value),
36200
+ keepOriginalWhenClean: true,
36201
+ };
36202
+ const STYLE_POLICIES = {
36203
+ print: PRINT_STYLE_POLICY,
36204
+ 'print-header': PRINT_STYLE_POLICY,
36205
+ };
36206
+ /**
36207
+ * Sanitize an HTML string for the given preset (+ feature overrides — pass the
36208
+ * same `features` you gave `getExtensions`/`createEditor` so the whitelist
36209
+ * stays in lock-step with the schema). Always strips script/object/embed/style/
36210
+ * form/event-handlers and `javascript:` URLs (DOMPurify default). `<iframe>` is
36211
+ * allowed ONLY for the document preset and ONLY with an `https:` source
36212
+ * (YouTube, Vimeo, Loom, Slides, … survive save/render; unsafe embeds are
36213
+ * dropped). `style` is capped to color/background-color/text-align.
36214
+ */
36215
+ function sanitize(html, preset = 'task', features) {
36216
+ if (!html)
36217
+ return '';
36218
+ const cfg = configFor(preset, features);
36219
+ purify.addHook('uponSanitizeElement', (node, data) => {
36220
+ // Only allow <input type="checkbox"> (task list checkboxes); strip others.
36221
+ if (data.tagName === 'input' && node.type !== 'checkbox') {
36222
+ node.parentNode?.removeChild(node);
36223
+ }
36224
+ // Allow only https iframes (YouTube and other embeds); drop anything else.
36225
+ if (data.tagName === 'iframe') {
36226
+ const src = node.getAttribute('src') || '';
36227
+ if (!SAFE_IFRAME_SRC_RE.test(src))
36228
+ node.parentNode?.removeChild(node);
36229
+ }
36230
+ });
36231
+ // Cap `style` (and, in print, the image's containerstyle/wrapperstyle) to
36232
+ // the properties the preset's extensions actually emit; strip the rest
36233
+ // (position:fixed, background-image url(), expression(), …). Drop the attr
36234
+ // entirely when nothing survives. The default policy is the pre-print rule
36235
+ // verbatim (guarded by sanitizer.presets.snapshot.test.ts).
36236
+ const policy = STYLE_POLICIES[preset] ?? DEFAULT_STYLE_POLICY;
36237
+ purify.addHook('uponSanitizeAttribute', (_node, data) => {
36238
+ if (!policy.attrs.has(data.attrName))
36239
+ return;
36240
+ const decls = data.attrValue.split(';').map((d) => d.trim()).filter(Boolean);
36241
+ const safe = decls.filter((d) => {
36242
+ const colon = d.indexOf(':');
36243
+ if (colon <= 0)
36244
+ return false;
36245
+ const prop = d.slice(0, colon).trim().toLowerCase();
36246
+ const value = d.slice(colon + 1).trim();
36247
+ return !UNSAFE_STYLE_VALUE.test(d) && policy.allows(prop, value);
36248
+ });
36249
+ if (policy.keepOriginalWhenClean && safe.length === decls.length && safe.length > 0)
36250
+ return;
36251
+ data.attrValue = safe.join('; ');
36252
+ if (!data.attrValue)
36253
+ data.keepAttr = false;
36254
+ });
36255
+ try {
36256
+ const clean = purify.sanitize(html, {
36257
+ ALLOWED_TAGS: cfg.ALLOWED_TAGS,
36258
+ ALLOWED_ATTR: cfg.ALLOWED_ATTR,
36259
+ ALLOW_DATA_ATTR: cfg.ALLOW_DATA_ATTR ?? false,
36260
+ FORBID_TAGS,
36261
+ FORBID_ATTR,
36262
+ ADD_ATTR: ['target', 'allowfullscreen', 'frameborder', 'allow'],
36263
+ ...(cfg.ADD_URI_SAFE_ATTR ? { ADD_URI_SAFE_ATTR: cfg.ADD_URI_SAFE_ATTR } : {}),
36264
+ });
36265
+ return clean;
36266
+ }
36267
+ finally {
36268
+ purify.removeHook('uponSanitizeElement');
36269
+ purify.removeHook('uponSanitizeAttribute');
36270
+ }
36271
+ }
36272
+
36273
+ /**
36274
+ * Lector tolerante del HTML de impresión (spec contracts-v2-contract-editor §3.3).
36275
+ * Entrada: lo que guardó V1 (documento completo con CSS, fragmento que dejó
36276
+ * cheerio en el backend, cuerpo compilado de generateFromDeal) o lo que escribe
36277
+ * el serializador canónico. Salida: SOLO el cuerpo, sin restos de edición.
36278
+ * No usa schema: el parse lo hace readPrintHtml (print/io.ts).
36279
+ */
36280
+ const EDITING_CLASSES = ['ProseMirror-selectednode', 'variable-node--editing', 'selectedCell'];
36281
+ const BLOCK_TAGS = new Set(['P', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'UL', 'OL', 'LI', 'TABLE', 'BLOCKQUOTE', 'PRE', 'HR']);
36282
+ const INLINE_CONTENT_TAGS = new Set(['P', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6']);
36283
+ const HEAD_ONLY = 'style, script, meta, title, link, base';
36284
+ function normalizePrintHtml(html) {
36285
+ if (!html || !html.trim())
36286
+ return '';
36287
+ const doc = new DOMParser().parseFromString(html, 'text/html');
36288
+ const root = doc.querySelector('.tiptap.ProseMirror, .ProseMirror') ?? doc.body;
36289
+ root.querySelectorAll('#document-metadata').forEach((el) => el.remove());
36290
+ root.querySelectorAll(HEAD_ONLY).forEach((el) => el.remove());
36291
+ // prosemirror-model convierte estos br en saltos REALES al re-parsear: fuera todos.
36292
+ root.querySelectorAll('br.ProseMirror-trailingBreak, img.ProseMirror-separator').forEach((el) => el.remove());
36293
+ // V1 serializa por error la decoración de {{ }}.
36294
+ root.querySelectorAll('span.hb-token').forEach(unwrap);
36295
+ Array.from(root.querySelectorAll('*')).forEach(cleanEditingResidue);
36296
+ cleanCellStyles(root);
36297
+ rebuildSplitImages(root);
36298
+ // Tras desenvolver hb-token y quitar breaks quedan textos adyacentes: un token repartido entre ellos no matchearía.
36299
+ root.normalize();
36300
+ tokensToFieldSpans(root);
36301
+ return root.innerHTML;
36302
+ }
36303
+ function unwrap(el) {
36304
+ el.replaceWith(...Array.from(el.childNodes));
36305
+ }
36306
+ function cleanEditingResidue(el) {
36307
+ Array.from(el.attributes).forEach((a) => {
36308
+ if (a.name.startsWith('data-v-') || a.name === 'data-node-view-wrapper')
36309
+ el.removeAttribute(a.name);
36310
+ });
36311
+ EDITING_CLASSES.forEach((c) => el.classList.remove(c));
36312
+ if (el.getAttribute('class') === '')
36313
+ el.removeAttribute('class');
36314
+ }
36315
+ function cleanCellStyles(root) {
36316
+ root.querySelectorAll('td[style], th[style]').forEach((cell) => {
36317
+ const kept = (cell.getAttribute('style') || '')
36318
+ .split(';')
36319
+ .map((d) => d.trim())
36320
+ .filter((d) => {
36321
+ const i = d.indexOf(':');
36322
+ if (i <= 0)
36323
+ return false;
36324
+ const v = d.slice(i + 1).trim().toLowerCase();
36325
+ return v !== '' && v !== 'null' && v !== 'undefined';
36326
+ });
36327
+ if (kept.length)
36328
+ cell.setAttribute('style', kept.join('; '));
36329
+ else
36330
+ cell.removeAttribute('style');
36331
+ });
36332
+ }
36333
+ const isBlockNode = (n) => n.nodeType === 1 && BLOCK_TAGS.has(n.tagName);
36334
+ const isBlankText = (n) => n.nodeType === 3 && !(n.textContent ?? '').trim();
36335
+ /**
36336
+ * V1 guarda la imagen como `<div wrapper><div container><img></div></div>`
36337
+ * DENTRO del `<p>`; el parser HTML5 parte el párrafo en `<p>antes</p><div>…</div>después<p></p>`.
36338
+ * Se vuelve a juntar en un solo párrafo, con los estilos del wrapper y del
36339
+ * container copiados al `<img>` (así los lee el nodo image del preset print).
36340
+ */
36341
+ function rebuildSplitImages(root) {
36342
+ const doc = root.ownerDocument;
36343
+ Array.from(root.querySelectorAll('img')).forEach((img) => {
36344
+ const container = img.parentElement;
36345
+ // `container !== root`: un <img> suelto al tope del cuerpo no es una imagen partida.
36346
+ if (!container || container === root || container.tagName !== 'DIV' || container.firstElementChild !== img)
36347
+ return;
36348
+ const parent = container.parentElement;
36349
+ const wrapper = parent && parent.tagName === 'DIV' && parent.firstElementChild === container && parent !== root ? parent : null;
36350
+ const containerCss = container.getAttribute('style');
36351
+ if (containerCss && !img.hasAttribute('containerstyle'))
36352
+ img.setAttribute('containerstyle', containerCss);
36353
+ const wrapperCss = wrapper?.getAttribute('style');
36354
+ if (wrapperCss && !img.hasAttribute('wrapperstyle'))
36355
+ img.setAttribute('wrapperstyle', wrapperCss);
36356
+ const outer = wrapper ?? container;
36357
+ // El parser HTML5 solo parte <p>: dentro de un título (o de un <p> que no se
36358
+ // partió) la imagen queda en su lugar, sin recomponer hermanos ni crear <p>.
36359
+ if (outer.parentElement && INLINE_CONTENT_TAGS.has(outer.parentElement.tagName)) {
36360
+ outer.replaceWith(img);
36361
+ return;
36362
+ }
36363
+ const before = [];
36364
+ let prev = outer.previousSibling;
36365
+ while (prev && !isBlockNode(prev)) {
36366
+ before.unshift(prev);
36367
+ prev = prev.previousSibling;
36368
+ }
36369
+ const after = [];
36370
+ let next = outer.nextSibling;
36371
+ while (next && !isBlockNode(next)) {
36372
+ after.push(next);
36373
+ next = next.nextSibling;
36374
+ }
36375
+ // El `</p>` original quedó huérfano: el parser lo convierte en un <p></p> vacío.
36376
+ if (next && next.nodeName === 'P' && !next.hasChildNodes())
36377
+ next.remove();
36378
+ let target;
36379
+ if (before.every(isBlankText) && prev && prev.nodeName === 'P') {
36380
+ before.forEach((n) => n.parentNode?.removeChild(n));
36381
+ target = prev;
36382
+ }
36383
+ else {
36384
+ target = doc.createElement('p');
36385
+ outer.before(target);
36386
+ before.forEach((n) => target.appendChild(n));
36387
+ }
36388
+ target.appendChild(img);
36389
+ after.forEach((n) => target.appendChild(n));
36390
+ outer.remove();
36391
+ });
36392
+ }
36393
+ function tokensToFieldSpans(root) {
36394
+ const doc = root.ownerDocument;
36395
+ const walker = doc.createTreeWalker(root, NodeFilter.SHOW_TEXT);
36396
+ const targets = [];
36397
+ let n;
36398
+ while ((n = walker.nextNode())) {
36399
+ const t = n;
36400
+ if (!t.data.includes('[['))
36401
+ continue;
36402
+ if (t.parentElement?.closest('[data-variable], [data-sig-slot], pre, code'))
36403
+ continue;
36404
+ targets.push(t);
36405
+ }
36406
+ targets.forEach((t) => {
36407
+ const text = t.data;
36408
+ const re = fieldTokenRegex();
36409
+ const frag = doc.createDocumentFragment();
36410
+ let last = 0;
36411
+ let any = false;
36412
+ let m;
36413
+ while ((m = re.exec(text)) !== null) {
36414
+ const def = parseFieldToken(m[1]);
36415
+ if (!def)
36416
+ continue;
36417
+ any = true;
36418
+ if (m.index > last)
36419
+ frag.appendChild(doc.createTextNode(text.slice(last, m.index)));
36420
+ const span = doc.createElement('span');
36421
+ span.setAttribute('data-variable', def.name);
36422
+ span.setAttribute('data-value', '');
36423
+ span.setAttribute('data-type', def.type);
36424
+ span.setAttribute('data-required', def.required ? 'true' : 'false');
36425
+ if (def.enum)
36426
+ span.setAttribute('data-enum', JSON.stringify(def.enum));
36427
+ span.textContent = `[[${def.name}]]`;
36428
+ frag.appendChild(span);
36429
+ last = m.index + m[0].length;
36430
+ }
36431
+ if (!any)
36432
+ return;
36433
+ if (last < text.length)
36434
+ frag.appendChild(doc.createTextNode(text.slice(last)));
36435
+ t.replaceWith(frag);
36436
+ });
36437
+ }
36438
+
36439
+ /**
36440
+ * Serializador canónico del preset print (spec contracts-v2-contract-editor §3.4).
36441
+ * Escribe desde el DOCUMENTO (renderHTML del schema), nunca desde el DOM de
36442
+ * pantalla: así no se cuelan NodeViews, decoraciones ni los hacks de
36443
+ * prosemirror-view que V1 guardaba con innerHTML.
36444
+ *
36445
+ * H1: `DOMSerializer` escribe `style` por CSSOM (`dom.style.cssText = …`), que
36446
+ * normaliza el string (`#ff0000` → `rgb(255, 0, 0)`, `top:0` → `top: 0px;`) y
36447
+ * rompe la forma byte a byte de V1 (firma, color, tamaño, imagen). Por eso se
36448
+ * serializa con un `document` sustituto cuyos elementos no exponen `style`:
36449
+ * ProseMirror cae a `setAttribute` y conserva el string crudo. `editor.getHTML()`
36450
+ * NO es la forma canónica.
36451
+ */
36452
+ const TRAILING_BREAK_CLASS = 'ProseMirror-trailingBreak';
36453
+ const TRAILING_MARKER = 'data-co-trailing-break';
36454
+ /**
36455
+ * Como prosemirror-view, el trailingBreak se decide por el NODO: textblock vacío o
36456
+ * cuyo último hijo es un hardBreak (aunque el <br> quede dentro de un mark).
36457
+ */
36458
+ function needsTrailingBreak(node) {
36459
+ if (!node.isTextblock)
36460
+ return false;
36461
+ return node.childCount === 0 || node.lastChild.type.name === 'hardBreak';
36462
+ }
36463
+ /**
36464
+ * Marca el elemento de bloque (spec `[tag, attrs?, 0]`, hueco directo en el
36465
+ * elemento: p/h*) para que el <br> vaya como su ÚLTIMO hijo, fuera de los marks.
36466
+ */
36467
+ function withTrailingMarker(spec) {
36468
+ if (!Array.isArray(spec) || spec[spec.length - 1] !== 0)
36469
+ return spec;
36470
+ const attrs = spec[1];
36471
+ if (attrs && typeof attrs === 'object' && !Array.isArray(attrs) && !('nodeType' in attrs)) {
36472
+ return [spec[0], { ...attrs, [TRAILING_MARKER]: '' }, ...spec.slice(2)];
36473
+ }
36474
+ return [spec[0], { [TRAILING_MARKER]: '' }, ...spec.slice(1)];
36475
+ }
36476
+ function rawStyleDocument(real) {
36477
+ return {
36478
+ createElement: (tag) => {
36479
+ const el = real.createElement(tag);
36480
+ Object.defineProperty(el, 'style', { value: null });
36481
+ return el;
36482
+ },
36483
+ createElementNS: (ns, tag) => {
36484
+ const el = real.createElementNS(ns, tag);
36485
+ Object.defineProperty(el, 'style', { value: null });
36486
+ return el;
36487
+ },
36488
+ createTextNode: real.createTextNode.bind(real),
36489
+ createDocumentFragment: real.createDocumentFragment.bind(real),
36490
+ };
36491
+ }
36492
+ function printSerializer(schema) {
36493
+ const base = DOMSerializer.fromSchema(schema);
36494
+ const nodes = {};
36495
+ Object.entries(base.nodes).forEach(([name, render]) => {
36496
+ nodes[name] = (node) => {
36497
+ const spec = render(node);
36498
+ return needsTrailingBreak(node) ? withTrailingMarker(spec) : spec;
36499
+ };
36500
+ });
36501
+ return new DOMSerializer(nodes, base.marks);
36502
+ }
36503
+ function serializePrintHtml(doc) {
36504
+ const container = document.createElement('div');
36505
+ const fragment = printSerializer(doc.type.schema).serializeFragment(doc.content, {
36506
+ document: rawStyleDocument(document),
36507
+ });
36508
+ container.appendChild(fragment);
36509
+ // Sin el trailingBreak la línea vacía o final no ocupa alto en el PDF
36510
+ // (.tiptap p{margin:0}). El lector lo quita al volver.
36511
+ container.querySelectorAll(`[${TRAILING_MARKER}]`).forEach((el) => {
36512
+ el.removeAttribute(TRAILING_MARKER);
36513
+ const br = document.createElement('br');
36514
+ br.className = TRAILING_BREAK_CLASS;
36515
+ el.appendChild(br);
36516
+ });
36517
+ return container.innerHTML;
36518
+ }
36519
+
36520
+ function isPrintPreset(p) {
36521
+ return p === 'print' || p === 'print-header';
36522
+ }
36523
+ function schemaExtensions(preset, features) {
36524
+ return getExtensions(preset, { includeUiExtensions: false, features });
36525
+ }
36526
+ /** HTML de impresión (el de V1 incluido) → JSON: lector tolerante → limpieza del preset → parse. */
36527
+ function readPrintHtml(html, preset = 'print', features) {
36528
+ const clean = sanitize(normalizePrintHtml(html ?? ''), preset, features);
36529
+ return generateJSON(clean, schemaExtensions(preset, features));
36530
+ }
36531
+ /**
36532
+ * Documento → forma canónica (spec §3.4), pasada por la limpieza del preset.
36533
+ * Es la ÚNICA forma canónica: `editor.getHTML()` de Tiptap normaliza los `style`
36534
+ * (H1) y no sirve para guardar.
36535
+ */
36536
+ function writePrintHtml(doc, preset = 'print', features) {
36537
+ if (!doc)
36538
+ return '';
36539
+ const node = doc instanceof Node$1
36540
+ ? doc
36541
+ : Node$1.fromJSON(getSchema(schemaExtensions(preset, features)), doc);
36542
+ return sanitize(serializePrintHtml(node), preset, features);
36543
+ }
36544
+ /** Aplica valores a los campos de un HTML sin montar un editor (encabezado fuera de edición). */
36545
+ function setFieldValuesInHtml(html, values, preset = 'print-header', features) {
36546
+ if (!html)
36547
+ return '';
36548
+ const json = readPrintHtml(html, preset, features);
36549
+ const apply = (n) => {
36550
+ if (n.type === 'mergeField' && n.attrs && Object.prototype.hasOwnProperty.call(values, n.attrs.name)) {
36551
+ n.attrs = { ...n.attrs, value: String(values[n.attrs.name] ?? '') };
36552
+ }
36553
+ n.content?.forEach(apply);
36554
+ };
36555
+ apply(json);
36556
+ return writePrintHtml(json, preset, features);
36557
+ }
35186
36558
 
35187
36559
  /**
35188
36560
  * ProseMirror editorProps that insert pasted/dropped images optimistically
@@ -35308,6 +36680,11 @@ function autolinkTrailing(editor) {
35308
36680
  editor.view.dispatch(tr);
35309
36681
  return changed;
35310
36682
  }
36683
+ /** El autolink al perder foco solo corre si el link del schema lo tiene activo (print lo apaga). */
36684
+ function autolinkEnabled(editor) {
36685
+ const link = editor.extensionManager.extensions.find((ext) => ext.name === 'link');
36686
+ return !!(link && link.options.autolink);
36687
+ }
35311
36688
  /**
35312
36689
  * Create a configured Tiptap v3 editor for a Cobalt preset.
35313
36690
  *
@@ -35316,9 +36693,9 @@ function autolinkTrailing(editor) {
35316
36693
  * always false — Cobalt owns every style.
35317
36694
  */
35318
36695
  function createEditor(options = {}) {
35319
- const { preset = 'task', element = null, content = null, editable = true, placeholder, maxLength, features, customExtensions = [], bubbleMenuElement, imageUpload, onUpdate, onSelectionUpdate, onFocus, onBlur, onCreate, onDestroy, onContentError, } = options;
36696
+ const { preset = 'task', element = null, content = null, editable = true, placeholder, maxLength, features, labels, customExtensions = [], bubbleMenuElement, imageUpload, onUpdate, onSelectionUpdate, onFocus, onBlur, onCreate, onDestroy, onContentError, } = options;
35320
36697
  const extensions = [
35321
- ...getExtensions(preset, { placeholder, maxLength, features }),
36698
+ ...getExtensions(preset, { placeholder, maxLength, features, labels }),
35322
36699
  ...customExtensions,
35323
36700
  ];
35324
36701
  let editor;
@@ -35375,11 +36752,13 @@ function createEditor(options = {}) {
35375
36752
  },
35376
36753
  }));
35377
36754
  }
36755
+ // En print, un string es HTML de impresión (quizá de V1): pasa por el lector tolerante.
36756
+ const initialContent = isPrintPreset(preset) && typeof content === 'string' ? readPrintHtml(content, preset, features) : content;
35378
36757
  editor = new Editor({
35379
36758
  ...(element ? { element } : {}),
35380
36759
  ...(imageUpload ? { editorProps: imageDropPaste(imageUpload) } : {}),
35381
36760
  extensions,
35382
- content: content ?? '',
36761
+ content: initialContent ?? '',
35383
36762
  editable,
35384
36763
  injectCSS: false,
35385
36764
  // `enableContentCheck: true` makes tiptap THROW on invalid content from
@@ -35394,304 +36773,356 @@ function createEditor(options = {}) {
35394
36773
  onUpdate: ({ editor: e }) => onUpdate?.(e),
35395
36774
  onSelectionUpdate: ({ editor: e }) => onSelectionUpdate?.(e),
35396
36775
  onFocus: ({ editor: e }) => onFocus?.(e),
35397
- onBlur: ({ editor: e }) => { autolinkTrailing(e); onBlur?.(e); },
36776
+ onBlur: ({ editor: e }) => { if (autolinkEnabled(e))
36777
+ autolinkTrailing(e); onBlur?.(e); },
35398
36778
  onDestroy: () => onDestroy?.(),
35399
36779
  });
35400
36780
  return editor;
35401
36781
  }
35402
36782
 
35403
- // src/generateHTML.ts
35404
- function getHTMLFromFragment(doc, schema, options) {
35405
- if (typeof window === "undefined") {
35406
- throw new Error(
35407
- "getHTMLFromFragment can only be used in a browser environment\nIf you want to use this in a Node environment, use the `@tiptap/html/server` import instead."
35408
- );
35409
- }
35410
- const wrap = window.document.createElement("div");
35411
- DOMSerializer.fromSchema(schema).serializeFragment(
35412
- doc.content,
35413
- {
35414
- document: window.document
35415
- },
35416
- wrap
35417
- );
35418
- return wrap.innerHTML;
35419
- }
35420
-
35421
- // src/generateHTML.ts
35422
- function generateHTML(doc, extensions) {
35423
- if (typeof window === "undefined") {
35424
- throw new Error(
35425
- "generateHTML can only be used in a browser environment\nIf you want to use this in a Node environment, use the `@tiptap/html/server` import instead."
35426
- );
35427
- }
35428
- const schema = getSchema(extensions);
35429
- const contentNode = Node$1.fromJSON(schema, doc);
35430
- return getHTMLFromFragment(contentNode, schema);
35431
- }
35432
- function generateJSON(html, extensions, options) {
35433
- if (typeof window === "undefined") {
35434
- throw new Error(
35435
- "generateJSON can only be used in a browser environment\nIf you want to use this in a Node environment, use the `@tiptap/html/server` import instead."
35436
- );
35437
- }
35438
- const schema = getSchema(extensions);
35439
- const doc = new window.DOMParser().parseFromString(html, "text/html");
35440
- if (!doc) {
35441
- throw new Error("Failed to parse HTML string");
35442
- }
35443
- return DOMParser.fromSchema(schema).parse(doc.body, options).toJSON();
35444
- }
35445
-
35446
- const BASE_INLINE = ['p', 'br', 'strong', 'em', 'a', 'span'];
35447
- const BASE_ATTR = ['href', 'target', 'rel', 'data-mention-id', 'data-mention-label'];
35448
- const SANITIZE_CONFIGS = {
35449
- // Más ancho que su schema A PROPÓSITO (única excepción al lock-step): el
35450
- // editor `comment` no puede autorar listas ni headings (STARTERKIT_CONFIG los
35451
- // apaga y ProseMirror descarta esos nodos al parsear el paste), pero el
35452
- // VIEWER tiene que pintarlos cuando el HTML entra por API — una nota de
35453
- // enriquecimiento (Apollo.io) trae <ul>/<li>/<h4> y con KEEP_CONTENT el
35454
- // texto se hoisteaba al padre: lista corrida, heading fundido en el cuerpo.
35455
- // Espejo inline en core/co-rich-text-viewer.tsx (ALLOWED_TAGS.comment).
35456
- comment: {
35457
- ALLOWED_TAGS: [...BASE_INLINE, 'ul', 'ol', 'li', 'h1', 'h2', 'h3', 'h4'],
35458
- ALLOWED_ATTR: [...BASE_ATTR],
35459
- ALLOW_DATA_ATTR: false,
35460
- },
35461
- task: {
35462
- ALLOWED_TAGS: [...BASE_INLINE, 'u', 's', 'code', 'ul', 'ol', 'li', 'blockquote', 'input', 'label'],
35463
- ALLOWED_ATTR: [...BASE_ATTR, 'type', 'checked', 'disabled', 'data-type', 'data-checked', 'data-variant'],
35464
- ALLOW_DATA_ATTR: false,
35465
- },
35466
- // Lock-step con getExtensions('notes'): task sin checklists + TextStyle/Color
35467
- // (`style` capado a STYLE_ALLOWED_PROPS) + Highlight multicolor (`mark` con
35468
- // `data-color`).
35469
- notes: {
35470
- ALLOWED_TAGS: [...BASE_INLINE, 'u', 's', 'code', 'ul', 'ol', 'li', 'blockquote', 'mark'],
35471
- ALLOWED_ATTR: [...BASE_ATTR, 'style', 'data-color'],
35472
- ALLOW_DATA_ATTR: false,
35473
- },
35474
- email: {
35475
- ALLOWED_TAGS: [
35476
- ...BASE_INLINE, 'u', 's', 'code', 'ul', 'ol', 'li', 'blockquote',
35477
- 'h2', 'h3', 'div', 'img',
35478
- ],
35479
- ALLOWED_ATTR: [...BASE_ATTR, 'style', 'data-variable', 'data-transform', 'data-fallback', 'src', 'alt', 'width', 'height', 'data-file-id', 'data-image-layout'],
35480
- ALLOW_DATA_ATTR: false,
35481
- },
35482
- document: {
35483
- ALLOWED_TAGS: [
35484
- ...BASE_INLINE, 'u', 's', 'code', 'ul', 'ol', 'li', 'blockquote',
35485
- 'h1', 'h2', 'h3', 'h4', 'hr', 'div', 'mark', 'img',
35486
- 'table', 'thead', 'tbody', 'tr', 'th', 'td',
35487
- 'input', 'label', 'iframe',
35488
- ],
35489
- ALLOWED_ATTR: [...BASE_ATTR, 'style', 'data-variable', 'colspan', 'rowspan', 'src', 'alt', 'width', 'height', 'type', 'checked', 'disabled', 'allowfullscreen', 'frameborder', 'allow', 'loading'],
35490
- ALLOW_DATA_ATTR: true,
35491
- },
35492
- 'block-email': {
35493
- ALLOWED_TAGS: [...BASE_INLINE, 'u', 's', 'code', 'ul', 'ol', 'li', 'blockquote', 'h2', 'h3', 'div', 'img'],
35494
- ALLOWED_ATTR: [...BASE_ATTR, 'style', 'data-variable', 'data-transform', 'data-fallback', 'src', 'alt', 'width', 'height', 'data-file-id', 'data-image-layout', 'data-type', 'data-label', 'data-href', 'data-bg', 'data-color', 'data-height'],
35495
- ALLOW_DATA_ATTR: false,
35496
- },
35497
- };
35498
- /**
35499
- * `<iframe>`s are permitted only with an `https:` source (blocks javascript:,
35500
- * data:, and plain http: embeds). This is what makes allowing iframes safe-ish
35501
- * for a trusted-author document; YouTube embeds satisfy it too.
35502
- */
35503
- const SAFE_IFRAME_SRC_RE = /^https:\/\/[^\s"'<>]+$/i;
35504
- /** Tags forbidden in every preset, regardless of the allow-list. */
35505
- const FORBID_TAGS = ['script', 'object', 'embed', 'form', 'textarea', 'style'];
35506
- /** Attributes forbidden in every preset (event handlers handled by DOMPurify itself). */
35507
- const FORBID_ATTR = ['onerror', 'onload', 'onclick'];
35508
- /**
35509
- * Resolve the effective config for a preset + feature overrides. Features can
35510
- * only ADD capabilities (mirroring `getExtensions`, where they register extra
35511
- * nodes); they never narrow a preset's base whitelist.
35512
- */
35513
- function configFor(preset, features) {
35514
- const cfg = SANITIZE_CONFIGS[preset] ?? SANITIZE_CONFIGS.task;
35515
- if (!features)
35516
- return cfg;
35517
- const tags = new Set(cfg.ALLOWED_TAGS);
35518
- const attr = new Set(cfg.ALLOWED_ATTR);
35519
- if (features.image) {
35520
- tags.add('img');
35521
- ['src', 'alt', 'width', 'height'].forEach((a) => attr.add(a));
35522
- }
35523
- if (features.variables)
35524
- attr.add('data-variable');
35525
- if (features.mentions) {
35526
- // data-mention-id/label ya están en BASE_ATTR. Los attrs del markup V1
35527
- // (quill-mention) se suman porque el BACKEND los parsea para notificar —
35528
- // re-editar una nota no debe destruirlos.
35529
- // Espejo inline en core/co-rich-text-viewer.tsx (el viewer no importa este módulo para no cargar el engine) — si cambias esta lista, cambia la del viewer.
35530
- ['data-id', 'data-value', 'data-denotation-char', 'data-index'].forEach((a) => attr.add(a));
36783
+ function computePageBreaks(atoms, pageContentHeight) {
36784
+ const breaks = [];
36785
+ if (!atoms.length || !(pageContentHeight > 0))
36786
+ return { breaks, pageCount: 1 };
36787
+ let page = 1;
36788
+ let start = 0;
36789
+ let pageTop = atoms[0].top;
36790
+ let i = 0;
36791
+ while (i < atoms.length) {
36792
+ const atom = atoms[i];
36793
+ const bottom = atom.top + atom.height;
36794
+ if (bottom - pageTop <= pageContentHeight) {
36795
+ i += 1;
36796
+ continue;
36797
+ }
36798
+ if (i === start) {
36799
+ // Más alto que una hoja: ocupa las que necesite; no hay frontera adentro.
36800
+ const extra = Math.ceil((bottom - pageTop) / pageContentHeight) - 1;
36801
+ page += extra;
36802
+ pageTop += extra * pageContentHeight;
36803
+ i += 1;
36804
+ continue;
36805
+ }
36806
+ let b = i;
36807
+ while (b - 1 > start && atoms[b - 1].keepWithNext)
36808
+ b -= 1;
36809
+ page += 1;
36810
+ breaks.push({ pos: atoms[b].pos, page });
36811
+ start = b;
36812
+ pageTop = atoms[b].top;
36813
+ i = b;
35531
36814
  }
35532
- return { ...cfg, ALLOWED_TAGS: [...tags], ALLOWED_ATTR: [...attr] };
36815
+ return { breaks, pageCount: page };
35533
36816
  }
35534
36817
  /**
35535
- * `style` is only allowed in notes/email/document, and even there we cap it to
35536
- * the properties our extensions actually emit (TextStyle/Color/TextAlign,
35537
- * ListStyleExtension's `list-style-type`). Everything else — position,
35538
- * background-image url(), etc. — is UI-redressing/tracking surface.
36818
+ * Resta a cada átomo la altura de las bandas de salto que ya están dibujadas
36819
+ * por encima (V1 medía con las bandas viejas en el flujo y cortaba antes).
35539
36820
  */
35540
- const STYLE_ALLOWED_PROPS = new Set(['color', 'background-color', 'text-align', 'list-style-type']);
35541
- /**
35542
- * Sanitize an HTML string for the given preset (+ feature overrides — pass the
35543
- * same `features` you gave `getExtensions`/`createEditor` so the whitelist
35544
- * stays in lock-step with the schema). Always strips script/object/embed/style/
35545
- * form/event-handlers and `javascript:` URLs (DOMPurify default). `<iframe>` is
35546
- * allowed ONLY for the document preset and ONLY with an `https:` source
35547
- * (YouTube, Vimeo, Loom, Slides, … survive save/render; unsafe embeds are
35548
- * dropped). `style` is capped to color/background-color/text-align.
35549
- */
35550
- function sanitize(html, preset = 'task', features) {
35551
- if (!html)
35552
- return '';
35553
- const cfg = configFor(preset, features);
35554
- purify.addHook('uponSanitizeElement', (node, data) => {
35555
- // Only allow <input type="checkbox"> (task list checkboxes); strip others.
35556
- if (data.tagName === 'input' && node.type !== 'checkbox') {
35557
- node.parentNode?.removeChild(node);
35558
- }
35559
- // Allow only https iframes (YouTube and other embeds); drop anything else.
35560
- if (data.tagName === 'iframe') {
35561
- const src = node.getAttribute('src') || '';
35562
- if (!SAFE_IFRAME_SRC_RE.test(src))
35563
- node.parentNode?.removeChild(node);
36821
+ function stripBandOffsets(atoms, bands) {
36822
+ if (!bands.length)
36823
+ return atoms;
36824
+ const sorted = [...bands].sort((a, b) => a.top - b.top);
36825
+ return atoms.map((atom) => {
36826
+ let shift = 0;
36827
+ for (const band of sorted) {
36828
+ if (band.top < atom.top)
36829
+ shift += band.height;
36830
+ else
36831
+ break;
35564
36832
  }
36833
+ return shift ? { ...atom, top: atom.top - shift } : atom;
35565
36834
  });
35566
- // Cap `style` to the properties our extensions actually emit; strip the rest
35567
- // (position, background-image url(), expression(), …). Drop the attr entirely
35568
- // when nothing survives.
35569
- purify.addHook('uponSanitizeAttribute', (_node, data) => {
35570
- if (data.attrName !== 'style')
35571
- return;
35572
- const safe = data.attrValue
35573
- .split(';')
35574
- .map((d) => d.trim())
35575
- .filter((d) => {
35576
- const colon = d.indexOf(':');
35577
- if (colon <= 0)
35578
- return false;
35579
- const prop = d.slice(0, colon).trim().toLowerCase();
35580
- return STYLE_ALLOWED_PROPS.has(prop) && !/url\s*\(|expression\s*\(/i.test(d);
35581
- });
35582
- data.attrValue = safe.join('; ');
35583
- if (!data.attrValue)
35584
- data.keepAttr = false;
36835
+ }
36836
+ const ATOM_TYPES = new Set(['listItem', 'tableRow']);
36837
+ const CONTAINER_TYPES = new Set(['bulletList', 'orderedList', 'table']);
36838
+ function classifyPaginationNode(node) {
36839
+ const name = node?.type?.name;
36840
+ if (!name || name === 'doc')
36841
+ return 'skip';
36842
+ if (CONTAINER_TYPES.has(name))
36843
+ return 'container';
36844
+ if (ATOM_TYPES.has(name))
36845
+ return 'atom';
36846
+ if (node?.isBlock)
36847
+ return 'atom';
36848
+ return 'skip';
36849
+ }
36850
+ function isKeepWithNext(node) {
36851
+ return node.type.name === 'heading' && Number(node.attrs?.level) >= 2;
36852
+ }
36853
+ /** Columnas de una tabla = suma de colspan de su primera fila (banda-fila que cruza la tabla). */
36854
+ function tableColumnCount(tableNode) {
36855
+ const firstRow = tableNode && typeof tableNode.child === 'function' ? tableNode.child(0) : null;
36856
+ if (!firstRow || typeof firstRow.forEach !== 'function')
36857
+ return 1;
36858
+ let cols = 0;
36859
+ firstRow.forEach((cell) => {
36860
+ cols += cell?.attrs?.colspan || 1;
35585
36861
  });
35586
- try {
35587
- const clean = purify.sanitize(html, {
35588
- ALLOWED_TAGS: cfg.ALLOWED_TAGS,
35589
- ALLOWED_ATTR: cfg.ALLOWED_ATTR,
35590
- ALLOW_DATA_ATTR: cfg.ALLOW_DATA_ATTR ?? false,
35591
- FORBID_TAGS,
35592
- FORBID_ATTR,
35593
- ADD_ATTR: ['target', 'allowfullscreen', 'frameborder', 'allow'],
35594
- });
35595
- return clean;
35596
- }
35597
- finally {
35598
- purify.removeHook('uponSanitizeElement');
35599
- purify.removeHook('uponSanitizeAttribute');
35600
- }
36862
+ return cols || 1;
35601
36863
  }
35602
36864
 
35603
- /** Schema-affecting extensions only (no Placeholder/CharacterCount). */
35604
- function schemaExtensions(preset, features) {
35605
- return getExtensions(preset, { includeUiExtensions: false, features });
35606
- }
35607
- function isEmptyDoc(doc) {
35608
- if (!doc)
35609
- return true;
35610
- const content = doc.content;
35611
- if (!Array.isArray(content) || content.length === 0)
35612
- return true;
35613
- // A single empty paragraph counts as empty.
35614
- return content.every((n) => n?.type === 'paragraph' && (!n.content || n.content.length === 0));
35615
- }
35616
- /** ProseMirror JSON → sanitized HTML for the given preset (+ feature overrides). */
35617
- function jsonToHtml(doc, preset = 'task', features) {
35618
- if (isEmptyDoc(doc))
35619
- return '';
35620
- const html = generateHTML(doc, schemaExtensions(preset, features));
35621
- return sanitize(html, preset, features);
35622
- }
35623
- /** HTML string → ProseMirror JSON (tolerant; unknown nodes are dropped by the schema). */
35624
- function htmlToJson(html, preset = 'task', features) {
35625
- const safe = sanitize(html ?? '', preset, features);
35626
- return generateJSON(safe, schemaExtensions(preset, features));
36865
+ /** px a 96 dpi. */
36866
+ const PAGE_SIZES = {
36867
+ letter: { width: 816, height: 1056 },
36868
+ a4: { width: 794, height: 1123 },
36869
+ legal: { width: 816, height: 1344 },
36870
+ };
36871
+ /** Separación visual entre hojas (no existe en el PDF). */
36872
+ const PAGE_GAP_PX = 24;
36873
+ const PAGINATION_META = 'coPagination';
36874
+ function resolvePageSize(page) {
36875
+ if (!page)
36876
+ return PAGE_SIZES.letter;
36877
+ if (typeof page === 'string')
36878
+ return PAGE_SIZES[page] ?? PAGE_SIZES.letter;
36879
+ return { width: Number(page.width), height: Number(page.height) };
36880
+ }
36881
+ function pageContentHeight(o) {
36882
+ return o.page.height - o.margins.top - o.margins.bottom - o.header.height - o.footer.height;
35627
36883
  }
35628
36884
  /**
35629
- * ProseMirror JSON → plain text. Walks the document directly (no engine), so
35630
- * it stays cheap and dependency-light. Block nodes are separated by newlines.
36885
+ * Top relativo a `root` sumando `offsetTop` por la cadena de offsetParent.
36886
+ * `root` tiene que ser posicionado (la extensión le pone `position: relative`).
36887
+ * Son px de LAYOUT: un `transform: scale()` de zoom no los altera.
35631
36888
  */
35632
- function jsonToText(doc) {
35633
- if (!doc)
35634
- return '';
35635
- const BLOCK = new Set([
35636
- 'paragraph', 'heading', 'blockquote', 'listItem', 'bulletList',
35637
- 'orderedList', 'codeBlock', 'horizontalRule',
35638
- ]);
35639
- const out = [];
35640
- const walk = (node) => {
35641
- if (!node)
35642
- return;
35643
- if (node.type === 'text' && typeof node.text === 'string') {
35644
- out.push(node.text);
35645
- return;
35646
- }
35647
- if (node.type === 'variable') {
35648
- out.push(`{{${node.attrs?.name ?? ''}}}`);
35649
- return;
35650
- }
35651
- if (node.type === 'mention') {
35652
- out.push(`@${node.attrs?.label ?? ''}`);
35653
- return;
35654
- }
35655
- if (node.type === 'hardBreak') {
35656
- out.push('\n');
35657
- return;
35658
- }
35659
- if (Array.isArray(node.content))
35660
- node.content.forEach(walk);
35661
- if (BLOCK.has(node.type))
35662
- out.push('\n');
36889
+ function layoutBox(el, root) {
36890
+ let top = 0;
36891
+ let node = el;
36892
+ while (node && node !== root) {
36893
+ top += node.offsetTop;
36894
+ node = node.offsetParent;
36895
+ }
36896
+ return { top, height: el.offsetHeight };
36897
+ }
36898
+ const defaultSchedule = (cb) => {
36899
+ if (typeof requestAnimationFrame === 'function')
36900
+ requestAnimationFrame(() => cb());
36901
+ else
36902
+ setTimeout(cb, 16);
36903
+ };
36904
+ function toLayoutOptions(o) {
36905
+ return {
36906
+ page: resolvePageSize(o.page),
36907
+ margins: { ...o.margins },
36908
+ header: { height: o.header?.height ?? 0 },
36909
+ footer: { height: o.footer?.height ?? 0 },
36910
+ gap: o.gap ?? PAGE_GAP_PX,
35663
36911
  };
35664
- walk(doc);
35665
- return out.join('').replace(/\n{3,}/g, '\n\n').trim();
35666
- }
35667
-
35668
- var RichText = /*#__PURE__*/Object.freeze({
35669
- __proto__: null,
35670
- COLOR_PALETTE: COLOR_PALETTE,
35671
- CalloutNode: CalloutNode,
35672
- CobaltTaskItem: CobaltTaskItem,
35673
- CobaltTaskList: CobaltTaskList,
35674
- FontFamilyExtension: FontFamilyExtension,
35675
- FontSizeExtension: FontSizeExtension,
35676
- FontWeightExtension: FontWeightExtension,
35677
- IndentExtension: IndentExtension,
35678
- LetterSpacingExtension: LetterSpacingExtension,
35679
- LineHeightExtension: LineHeightExtension,
35680
- ListStyleExtension: ListStyleExtension,
35681
- MentionNode: MentionNode,
35682
- PRESETS: PRESETS,
35683
- SANITIZE_CONFIGS: SANITIZE_CONFIGS,
35684
- TABLE_CONTEXT_ITEMS: TABLE_CONTEXT_ITEMS,
35685
- VariableNode: VariableNode,
35686
- createEditor: createEditor,
35687
- defaultToolbarForPreset: defaultToolbarForPreset,
35688
- getExtensions: getExtensions,
35689
- htmlToJson: htmlToJson,
35690
- jsonToHtml: jsonToHtml,
35691
- jsonToText: jsonToText,
35692
- maxLengthForPreset: maxLengthForPreset,
35693
- sanitize: sanitize,
35694
- toolbarItems: toolbarItems
36912
+ }
36913
+ /**
36914
+ * Banda de salto: margen inferior (+ pie) de la hoja que termina, separación
36915
+ * entre hojas y margen superior (+ encabezado) de la que empieza. Dentro de una
36916
+ * tabla va envuelta en una fila con el colspan de la tabla (un div entre `tr`
36917
+ * lo expulsaría el navegador).
36918
+ */
36919
+ function buildPageGap(page, pageCount, o, header, cols = 0) {
36920
+ const foot = o.margins.bottom + o.footer.height;
36921
+ const head = o.margins.top + o.header.height;
36922
+ const band = document.createElement('div');
36923
+ band.className = 'co-doc-page-gap';
36924
+ band.setAttribute('contenteditable', 'false');
36925
+ band.style.height = `${foot + o.gap + head}px`;
36926
+ const bottom = document.createElement('div');
36927
+ bottom.className = 'co-doc-page-gap__foot';
36928
+ bottom.style.height = `${foot}px`;
36929
+ const between = document.createElement('div');
36930
+ between.className = 'co-doc-page-gap__between';
36931
+ between.style.height = `${o.gap}px`;
36932
+ const top = document.createElement('div');
36933
+ top.className = 'co-doc-page-gap__head';
36934
+ top.style.height = `${head}px`;
36935
+ top.style.paddingTop = `${o.margins.top}px`;
36936
+ top.style.boxSizing = 'border-box';
36937
+ if (header)
36938
+ top.appendChild(header);
36939
+ band.append(bottom, between, top);
36940
+ band.setAttribute('data-page', String(page));
36941
+ band.setAttribute('data-page-count', String(pageCount));
36942
+ if (!cols) {
36943
+ band.setAttribute('data-co-page-gap', String(page));
36944
+ return band;
36945
+ }
36946
+ const tr = document.createElement('tr');
36947
+ tr.className = 'co-doc-page-gap-row';
36948
+ tr.setAttribute('contenteditable', 'false');
36949
+ tr.setAttribute('data-co-page-gap', String(page));
36950
+ const td = document.createElement('td');
36951
+ td.setAttribute('colspan', String(cols));
36952
+ td.appendChild(band);
36953
+ tr.appendChild(td);
36954
+ return tr;
36955
+ }
36956
+ function measureLayout(view, opts, measure) {
36957
+ const root = view.dom;
36958
+ const atoms = [];
36959
+ view.state.doc.descendants((node, pos) => {
36960
+ const kind = classifyPaginationNode(node);
36961
+ if (kind === 'container')
36962
+ return true;
36963
+ if (kind === 'skip')
36964
+ return false;
36965
+ const dom = view.nodeDOM(pos);
36966
+ if (!(dom instanceof HTMLElement))
36967
+ return false;
36968
+ const box = measure(dom, root);
36969
+ if (box.height > 0)
36970
+ atoms.push({ pos, top: box.top, height: box.height, keepWithNext: isKeepWithNext(node) });
36971
+ return false;
36972
+ });
36973
+ const bands = Array.from(root.querySelectorAll('[data-co-page-gap]')).map((el) => measure(el, root));
36974
+ return computePageBreaks(stripBandOffsets(atoms, bands), pageContentHeight(opts));
36975
+ }
36976
+ const paginationKey = new PluginKey('coPagination');
36977
+ const Pagination = Extension.create({
36978
+ name: 'pagination',
36979
+ addOptions() {
36980
+ return {
36981
+ page: 'letter',
36982
+ margins: { top: 38, right: 38, bottom: 38, left: 38 },
36983
+ header: { height: 0 },
36984
+ footer: { height: 0 },
36985
+ gap: PAGE_GAP_PX,
36986
+ renderHeader: null,
36987
+ onPagesChange: null,
36988
+ measure: layoutBox,
36989
+ schedule: defaultSchedule,
36990
+ };
36991
+ },
36992
+ addStorage() {
36993
+ return { pageCount: 1 };
36994
+ },
36995
+ addCommands() {
36996
+ return {
36997
+ setPaginationOptions: (patch) => ({ tr, dispatch }) => {
36998
+ if (dispatch)
36999
+ tr.setMeta(PAGINATION_META, { patch });
37000
+ return true;
37001
+ },
37002
+ remeasurePages: () => ({ tr, dispatch }) => {
37003
+ if (dispatch)
37004
+ tr.setMeta(PAGINATION_META, { remeasure: true });
37005
+ return true;
37006
+ },
37007
+ };
37008
+ },
37009
+ addProseMirrorPlugins() {
37010
+ const options = this.options;
37011
+ const storage = this.storage;
37012
+ let lastEmitted = 0;
37013
+ const decorationsFor = (state, st) => {
37014
+ const decos = [];
37015
+ for (const br of st.layout.breaks) {
37016
+ if (br.pos < 0 || br.pos > state.doc.content.size)
37017
+ continue;
37018
+ // Nunca un widget de bloque dentro de contenido inline.
37019
+ if (state.doc.resolve(br.pos).parent.inlineContent)
37020
+ continue;
37021
+ const node = state.doc.nodeAt(br.pos);
37022
+ const cols = node?.type.name === 'tableRow' ? tableColumnCount(state.doc.resolve(br.pos).parent) : 0;
37023
+ decos.push(Decoration.widget(br.pos, () => buildPageGap(br.page, st.layout.pageCount, st.opts, options.renderHeader?.(br.page, st.layout.pageCount) ?? null, cols), { side: -1, key: `co-pg-${br.page}-${st.layout.pageCount}-v${st.version}-c${cols}` }));
37024
+ }
37025
+ return DecorationSet.create(state.doc, decos);
37026
+ };
37027
+ return [
37028
+ new Plugin({
37029
+ key: paginationKey,
37030
+ state: {
37031
+ init: () => ({ layout: { breaks: [], pageCount: 1 }, opts: toLayoutOptions(options), version: 0, dirty: true }),
37032
+ apply(tr, prev) {
37033
+ const meta = tr.getMeta(PAGINATION_META);
37034
+ let next = prev;
37035
+ if (tr.docChanged) {
37036
+ next = {
37037
+ ...next,
37038
+ dirty: true,
37039
+ // Un salto cuya frontera se borró (p. ej. unir párrafos en el borde de una hoja)
37040
+ // se descarta: mapearlo lo dejaría dentro de un textblock. La medición siguiente
37041
+ // lo recalcula.
37042
+ layout: {
37043
+ ...next.layout,
37044
+ breaks: next.layout.breaks.flatMap((b) => {
37045
+ const r = tr.mapping.mapResult(b.pos);
37046
+ return r.deleted ? [] : [{ ...b, pos: r.pos }];
37047
+ }),
37048
+ },
37049
+ };
37050
+ }
37051
+ if (meta?.patch) {
37052
+ const merged = toLayoutOptions({ ...next.opts, ...meta.patch, page: meta.patch.page ?? next.opts.page });
37053
+ next = { ...next, opts: merged, version: next.version + 1, dirty: true };
37054
+ }
37055
+ if (meta?.remeasure)
37056
+ next = { ...next, dirty: true };
37057
+ if (meta?.layout)
37058
+ next = { ...next, layout: meta.layout, dirty: false };
37059
+ return next;
37060
+ },
37061
+ },
37062
+ props: {
37063
+ decorations(state) {
37064
+ const st = paginationKey.getState(state);
37065
+ return st ? decorationsFor(state, st) : DecorationSet.empty;
37066
+ },
37067
+ },
37068
+ view(view) {
37069
+ const root = view.dom;
37070
+ if (!root.style.position)
37071
+ root.style.position = 'relative';
37072
+ let scheduled = false;
37073
+ let alive = true;
37074
+ const run = () => {
37075
+ scheduled = false;
37076
+ if (!alive || view.isDestroyed)
37077
+ return;
37078
+ const st = paginationKey.getState(view.state);
37079
+ if (!st)
37080
+ return;
37081
+ const layout = measureLayout(view, st.opts, options.measure);
37082
+ storage.pageCount = layout.pageCount;
37083
+ view.dispatch(view.state.tr.setMeta(PAGINATION_META, { layout }));
37084
+ if (layout.pageCount !== lastEmitted) {
37085
+ lastEmitted = layout.pageCount;
37086
+ options.onPagesChange?.(layout.pageCount);
37087
+ }
37088
+ };
37089
+ const maybeSchedule = () => {
37090
+ const st = paginationKey.getState(view.state);
37091
+ if (!st?.dirty || scheduled)
37092
+ return;
37093
+ scheduled = true;
37094
+ options.schedule(run);
37095
+ };
37096
+ const remeasure = () => {
37097
+ if (alive && !view.isDestroyed) {
37098
+ view.dispatch(view.state.tr.setMeta(PAGINATION_META, { remeasure: true }));
37099
+ }
37100
+ };
37101
+ // Imágenes que cargan tarde cambian alturas (las de las bandas no: tienen alto fijo).
37102
+ const onLoad = (e) => {
37103
+ const t = e.target;
37104
+ if (!t || t.tagName !== 'IMG' || t.closest('[data-co-page-gap]'))
37105
+ return;
37106
+ remeasure();
37107
+ };
37108
+ root.addEventListener('load', onLoad, true);
37109
+ const fonts = document.fonts;
37110
+ fonts?.ready?.then(remeasure).catch(() => { });
37111
+ // Fuentes que cargan después (un peso o familia aplicado por primera vez).
37112
+ fonts?.addEventListener?.('loadingdone', remeasure);
37113
+ maybeSchedule();
37114
+ return {
37115
+ update: () => maybeSchedule(),
37116
+ destroy: () => {
37117
+ alive = false;
37118
+ root.removeEventListener('load', onLoad, true);
37119
+ fonts?.removeEventListener?.('loadingdone', remeasure);
37120
+ },
37121
+ };
37122
+ },
37123
+ }),
37124
+ ];
37125
+ },
35695
37126
  });
35696
37127
 
35697
- export { RichText as R };
37128
+ export { defaultToolbarForPreset as A, getImageLayoutMode as B, CalloutNode as C, getPrintExtensions as D, headerImageWidth as E, FIELD_SYNC_META as F, layoutBox as G, maxLengthForPreset as H, IMAGE_LAYOUT_MODES as I, nextFreeSlot as J, normalizePrintHtml as K, LetterSpacingExtension as L, MentionNode as M, pageContentHeight as N, parseFieldToken as O, PAGE_GAP_PX as P, resolvePageSize as Q, sanitizeFieldName as R, SANITIZE_CONFIGS as S, TRAILING_BREAK_CLASS as T, serializePrintHtml as U, VariableNode as V, setFieldValuesInHtml as W, signatureBoxStyle as X, signatureSlotHtml as Y, signatureToken as Z, stripBandOffsets as _, generateJSON as a, getExtensions as b, CobaltTaskItem as c, CobaltTaskList as d, FontFamilyExtension as e, FontSizeExtension as f, generateHTML as g, FontWeightExtension as h, isPrintPreset as i, IndentExtension as j, LineHeightExtension as k, ListStyleExtension as l, MergeField as m, PAGE_SIZES as n, PAGINATION_META as o, PRESETS as p, Pagination as q, readPrintHtml as r, sanitize as s, SIGNATURE_TOKEN_STYLE as t, SignatureSlot as u, applyImageLayoutMode as v, writePrintHtml as w, collectFields as x, computePageBreaks as y, createEditor as z };