@heartlandone/vega 2.102.0 → 2.103.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 (387) hide show
  1. package/dist/cjs/{app-globals-49c2a999.js → app-globals-85986306.js} +10 -10
  2. package/dist/cjs/{code-block-06e6591f.js → code-block-72de6c4d.js} +80 -1
  3. package/dist/cjs/{component-value-history-controller-slimmer.abstract-f29908f8.js → component-value-history-controller-slimmer.abstract-23d2b3d8.js} +3 -3
  4. package/dist/cjs/{content-state-8c862e5e.js → content-state-ff40bdc6.js} +38 -5
  5. package/dist/cjs/{date-required-rule-b672c432.js → date-required-rule-608e704b.js} +1 -1
  6. package/dist/cjs/{design-token-351ffd2c.js → design-token-a101a8d0.js} +3 -3
  7. package/dist/cjs/{element-appender-slimmer-f932b166.js → element-appender-slimmer-b93cc564.js} +2 -2
  8. package/dist/cjs/{form-field-controller-slimmer-5adb86ae.js → form-field-controller-slimmer-124d54ea.js} +1 -1
  9. package/dist/cjs/{image-annotation-action-25907d6b.js → image-annotation-action-1ee41bc7.js} +2 -2
  10. package/dist/cjs/{image-extension-1cf84f27.js → image-extension-6a92c524.js} +247 -5
  11. package/dist/cjs/index.cjs.js +17 -17
  12. package/dist/cjs/{inject-keyboard-manager-84d33920.js → inject-keyboard-manager-32d7dd0e.js} +1 -1
  13. package/dist/cjs/{internal-calendar-period-factory-3c5236be.js → internal-calendar-period-factory-c3198ea7.js} +1 -1
  14. package/dist/cjs/{internal-translation-controller-eae8a8de.js → internal-translation-controller-0d67ca4d.js} +1 -0
  15. package/dist/cjs/{keyboard-manager-baa83a61.js → keyboard-manager-332eec89.js} +1 -1
  16. package/dist/cjs/{keyboard-manager-slimmer-d1974b28.js → keyboard-manager-slimmer-a2872981.js} +1 -1
  17. package/dist/cjs/{link-extension-2a6133b7.js → link-extension-1b4ed437.js} +3 -3
  18. package/dist/cjs/loader.cjs.js +12 -12
  19. package/dist/cjs/{month-view-generator-a6827548.js → month-view-generator-b6a2b8be.js} +1 -1
  20. package/dist/cjs/{public-rules-7f26e0ae.js → public-rules-2066613c.js} +7 -7
  21. package/dist/cjs/{range-518b95a2.js → range-712fe703.js} +1 -1
  22. package/dist/cjs/{responsive-format-facade-95c54444.js → responsive-format-facade-44d33457.js} +1 -1
  23. package/dist/cjs/{rich-text-editor-required-rule-5d0c76ec.js → rich-text-editor-required-rule-1aa75d22.js} +1 -1
  24. package/dist/cjs/{split-cell-operation-28f6f8d9.js → split-cell-operation-afc82323.js} +3 -3
  25. package/dist/cjs/{state-border-formatter-6c284859.js → state-border-formatter-49984fd6.js} +1 -1
  26. package/dist/cjs/{string-format-strategy.abstract-f15b6196.js → string-format-strategy.abstract-bd563c01.js} +1 -1
  27. package/dist/cjs/{string-input-formatter-slimmer-5a3f1b55.js → string-input-formatter-slimmer-4faebac9.js} +1 -1
  28. package/dist/cjs/{string-mask-strategy-af6f3ba0.js → string-mask-strategy-624c4398.js} +2 -2
  29. package/dist/cjs/{style-formatter-324211fd.js → style-formatter-151d89a3.js} +2 -2
  30. package/dist/cjs/{time-required-rule-9e714442.js → time-required-rule-8cd8f9b9.js} +1 -1
  31. package/dist/cjs/{token-extension-86723cad.js → token-extension-72d0cb08.js} +1011 -767
  32. package/dist/cjs/{translation-slimmer-0227ee24.js → translation-slimmer-1771d01f.js} +1 -1
  33. package/dist/cjs/{type-guard-29e01bd4.js → type-guard-cce6fe1f.js} +1 -1
  34. package/dist/cjs/{valid-credit-card-number-rule-4ec364af.js → valid-credit-card-number-rule-b13c2fc4.js} +1 -1
  35. package/dist/cjs/vega-accordion.cjs.entry.js +6 -6
  36. package/dist/cjs/vega-app-header-button.cjs.entry.js +5 -5
  37. package/dist/cjs/vega-box.cjs.entry.js +6 -6
  38. package/dist/cjs/vega-button-circle.cjs.entry.js +5 -5
  39. package/dist/cjs/vega-button.cjs.entry.js +3 -3
  40. package/dist/cjs/vega-calendar_5.cjs.entry.js +7 -7
  41. package/dist/cjs/vega-card.cjs.entry.js +5 -5
  42. package/dist/cjs/vega-carousel.cjs.entry.js +3 -3
  43. package/dist/cjs/vega-checkbox_2.cjs.entry.js +2 -2
  44. package/dist/cjs/vega-chip.cjs.entry.js +5 -5
  45. package/dist/cjs/vega-code-block.cjs.entry.js +8 -8
  46. package/dist/cjs/vega-color-picker.cjs.entry.js +2 -2
  47. package/dist/cjs/vega-color-swatch-picker.cjs.entry.js +3 -3
  48. package/dist/cjs/vega-color-swatch.cjs.entry.js +2 -2
  49. package/dist/cjs/vega-combo-box.cjs.entry.js +8 -8
  50. package/dist/cjs/vega-date-picker_2.cjs.entry.js +13 -13
  51. package/dist/cjs/vega-dialog_2.cjs.entry.js +3 -3
  52. package/dist/cjs/vega-divider.cjs.entry.js +5 -5
  53. package/dist/cjs/vega-dropdown_5.cjs.entry.js +7 -7
  54. package/dist/cjs/vega-env-manager-23b8b23c.js +2 -2
  55. package/dist/cjs/vega-field-label.cjs.entry.js +2 -2
  56. package/dist/cjs/vega-file-uploader.cjs.entry.js +3 -3
  57. package/dist/cjs/vega-flag-icon.cjs.entry.js +5 -5
  58. package/dist/cjs/vega-flex.cjs.entry.js +6 -6
  59. package/dist/cjs/vega-font.cjs.entry.js +5 -5
  60. package/dist/cjs/vega-form.cjs.entry.js +2 -2
  61. package/dist/cjs/vega-grid.cjs.entry.js +5 -5
  62. package/dist/cjs/vega-icon.cjs.entry.js +5 -5
  63. package/dist/cjs/vega-image-uploader.cjs.entry.js +5 -5
  64. package/dist/cjs/vega-input-credit-card.cjs.entry.js +6 -6
  65. package/dist/cjs/vega-input-numeric.cjs.entry.js +12 -14
  66. package/dist/cjs/vega-input-passcode.cjs.entry.js +5 -5
  67. package/dist/cjs/vega-input-phone-number.cjs.entry.js +4 -4
  68. package/dist/cjs/vega-input-range.cjs.entry.js +3 -3
  69. package/dist/cjs/vega-input-select.cjs.entry.js +5 -5
  70. package/dist/cjs/vega-input.cjs.entry.js +31 -27
  71. package/dist/cjs/vega-left-nav_5.cjs.entry.js +7 -7
  72. package/dist/cjs/vega-loader-wrapper_2.cjs.entry.js +3 -3
  73. package/dist/cjs/vega-pagination-page-size-selector-mobile.cjs.entry.js +2 -2
  74. package/dist/cjs/vega-pagination.cjs.entry.js +4 -4
  75. package/dist/cjs/vega-popover_2.cjs.entry.js +8 -8
  76. package/dist/cjs/vega-progress-tracker_2.cjs.entry.js +3 -3
  77. package/dist/cjs/vega-radio_2.cjs.entry.js +5 -5
  78. package/dist/cjs/vega-rich-text-bookmark-editor.cjs.entry.js +2 -2
  79. package/dist/cjs/vega-rich-text-content.cjs.entry.js +6 -6
  80. package/dist/cjs/vega-rich-text-editor_4.cjs.entry.js +474 -207
  81. package/dist/cjs/vega-rich-text-find-replace-panel.cjs.entry.js +1 -1
  82. package/dist/cjs/vega-rich-text-special-characters-panel.cjs.entry.js +5 -5
  83. package/dist/cjs/vega-rich-text-table-properties_3.cjs.entry.js +8 -8
  84. package/dist/cjs/vega-selection-chip_2.cjs.entry.js +4 -4
  85. package/dist/cjs/vega-selection-tile_2.cjs.entry.js +2 -2
  86. package/dist/cjs/vega-sidenav_3.cjs.entry.js +3 -3
  87. package/dist/cjs/vega-signature-capture.cjs.entry.js +7 -7
  88. package/dist/cjs/vega-stepper.cjs.entry.js +2 -2
  89. package/dist/cjs/vega-tab-group_2.cjs.entry.js +6 -6
  90. package/dist/cjs/vega-table_11.cjs.entry.js +4 -4
  91. package/dist/cjs/vega-textarea.cjs.entry.js +2 -2
  92. package/dist/cjs/vega-time-picker_2.cjs.entry.js +9 -9
  93. package/dist/cjs/vega-toggle-switch.cjs.entry.js +2 -2
  94. package/dist/cjs/vega-tooltip_2.cjs.entry.js +6 -6
  95. package/dist/cjs/vega.cjs.js +12 -12
  96. package/dist/collection/components/vega-input/slimmers/controllers/vega-input-state-controller.js +0 -14
  97. package/dist/collection/components/vega-input/slimmers/renderers/vega-input-input-container-renderer.js +11 -2
  98. package/dist/collection/components/vega-input/slimmers/renderers/vega-input-input-renderer.js +11 -1
  99. package/dist/collection/components/vega-input/vega-input.js +52 -8
  100. package/dist/collection/components/vega-input-numeric/slimmers/renderers/vega-input-numeric-renderer.js +7 -1
  101. package/dist/collection/components/vega-input-numeric/vega-input-numeric.js +0 -8
  102. package/dist/collection/components/vega-rich-text-editor/constants/constant.js +4 -0
  103. package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/sequential-composition-strategy.js +31 -0
  104. package/dist/collection/components/vega-rich-text-editor/dto/actions/modify-content-action.abstract.js +1 -0
  105. package/dist/collection/components/vega-rich-text-editor/dto/actions/sequential-composition-action.js +14 -0
  106. package/dist/collection/components/vega-rich-text-editor/dto/content-state.js +4 -1
  107. package/dist/collection/components/vega-rich-text-editor/dto/flush-changes-payload.js +1 -0
  108. package/dist/collection/components/vega-rich-text-editor/dto/nodes/image-node.js +3 -2
  109. package/dist/collection/components/vega-rich-text-editor/extensions/functions/dto/function-block.js +30 -0
  110. package/dist/collection/components/vega-rich-text-editor/extensions/functions/element-to-dto-strategies/div-to-function-block-strategy.js +1 -0
  111. package/dist/collection/components/vega-rich-text-editor/extensions/paste/controllers/chooser-positioner.js +107 -0
  112. package/dist/collection/components/vega-rich-text-editor/extensions/paste/controllers/paste-chooser-controller.js +91 -0
  113. package/dist/collection/components/vega-rich-text-editor/extensions/paste/controllers/paste-event-interceptor.js +47 -0
  114. package/dist/collection/components/vega-rich-text-editor/extensions/paste/controllers/selection-snapshot-service.js +54 -0
  115. package/dist/collection/components/vega-rich-text-editor/extensions/paste/parse-local-images-helper/image-extractor.js +17 -0
  116. package/dist/collection/components/vega-rich-text-editor/extensions/paste/paste-chooser-ui.js +3 -1
  117. package/dist/collection/components/vega-rich-text-editor/extensions/paste/paste-extension.js +41 -354
  118. package/dist/collection/components/vega-rich-text-editor/extensions/paste/pipeline/data-transfer-builder.js +36 -0
  119. package/dist/collection/components/vega-rich-text-editor/extensions/paste/pipeline/paste-dispatcher.js +23 -0
  120. package/dist/collection/components/vega-rich-text-editor/extensions/paste/pipeline/paste-processing-pipeline.js +30 -0
  121. package/dist/collection/components/vega-rich-text-editor/extensions/paste/strategies/paste-processing-strategy.abstract.js +34 -0
  122. package/dist/collection/components/vega-rich-text-editor/extensions/paste/strategies/paste-strategy-selector.js +19 -0
  123. package/dist/collection/components/vega-rich-text-editor/extensions/paste/strategies/plain-paste-strategy.js +74 -0
  124. package/dist/collection/components/vega-rich-text-editor/extensions/paste/type.js +1 -0
  125. package/dist/collection/components/vega-rich-text-editor/helpers/utils.js +67 -0
  126. package/dist/collection/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/abstract-delete-content-handler.js +67 -11
  127. package/dist/collection/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/backward-delete-content-handler.js +4 -17
  128. package/dist/collection/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/base-handler.js +34 -1
  129. package/dist/collection/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/forward-delete-content-handler.js +13 -32
  130. package/dist/collection/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/insert-line-break-handler.js +60 -25
  131. package/dist/collection/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/insert-paragraph-handler.js +55 -19
  132. package/dist/collection/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/insert-paste-handler.js +165 -59
  133. package/dist/collection/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/insert-text-handler.js +55 -21
  134. package/dist/collection/components/vega-rich-text-editor/slimmers/controllers/user-input-controller.js +2 -16
  135. package/dist/collection/components/vega-rich-text-editor/slimmers/controllers/value-controller.js +11 -1
  136. package/dist/collection/components/vega-rich-text-editor/utils/html-to-plain-text-utils.js +240 -0
  137. package/dist/collection/helpers/translation/locales/en.js +1 -0
  138. package/dist/esm/{app-globals-da5c83c2.js → app-globals-8cdfc5c9.js} +10 -10
  139. package/dist/esm/{code-block-d8f83d85.js → code-block-9360c331.js} +74 -2
  140. package/dist/esm/{component-value-history-controller-slimmer.abstract-642e7147.js → component-value-history-controller-slimmer.abstract-9ea58806.js} +3 -3
  141. package/dist/esm/{content-state-486eae1d.js → content-state-67a12e74.js} +38 -5
  142. package/dist/esm/{date-required-rule-08695d25.js → date-required-rule-66b5bf02.js} +1 -1
  143. package/dist/esm/{design-token-df3331d9.js → design-token-acd1efeb.js} +3 -3
  144. package/dist/esm/{element-appender-slimmer-f02a227f.js → element-appender-slimmer-7e5bc1e9.js} +2 -2
  145. package/dist/esm/{form-field-controller-slimmer-a7c0a0f8.js → form-field-controller-slimmer-d653c494.js} +1 -1
  146. package/dist/esm/{image-annotation-action-df744ba5.js → image-annotation-action-9525be48.js} +2 -2
  147. package/dist/esm/{image-extension-20b39140.js → image-extension-aea75132.js} +246 -6
  148. package/dist/esm/index.js +17 -17
  149. package/dist/esm/{inject-keyboard-manager-399ed867.js → inject-keyboard-manager-f6522d2f.js} +1 -1
  150. package/dist/esm/{internal-calendar-period-factory-7b866c3b.js → internal-calendar-period-factory-261df2f2.js} +1 -1
  151. package/dist/esm/{internal-translation-controller-4a7ee4d5.js → internal-translation-controller-3637e47e.js} +1 -0
  152. package/dist/esm/{keyboard-manager-f5d13a34.js → keyboard-manager-53e8d8d0.js} +1 -1
  153. package/dist/esm/{keyboard-manager-slimmer-f40dcb54.js → keyboard-manager-slimmer-b3de042d.js} +1 -1
  154. package/dist/esm/{link-extension-3f93d70d.js → link-extension-57ba9520.js} +3 -3
  155. package/dist/esm/loader.js +12 -12
  156. package/dist/esm/{month-view-generator-0c665987.js → month-view-generator-15215a09.js} +1 -1
  157. package/dist/esm/{public-rules-470a1dac.js → public-rules-c77a1550.js} +7 -7
  158. package/dist/esm/{range-8e89fb54.js → range-3c74e1c8.js} +1 -1
  159. package/dist/esm/{responsive-format-facade-55131a33.js → responsive-format-facade-1b325d06.js} +1 -1
  160. package/dist/esm/{rich-text-editor-required-rule-06caf383.js → rich-text-editor-required-rule-cfd32ba2.js} +1 -1
  161. package/dist/esm/{split-cell-operation-e158366a.js → split-cell-operation-85a036f9.js} +3 -3
  162. package/dist/esm/{state-border-formatter-2b73fa08.js → state-border-formatter-ce3495b0.js} +1 -1
  163. package/dist/esm/{string-format-strategy.abstract-8c7937e3.js → string-format-strategy.abstract-8ce04558.js} +1 -1
  164. package/dist/esm/{string-input-formatter-slimmer-681c6b71.js → string-input-formatter-slimmer-0d60ba7d.js} +1 -1
  165. package/dist/esm/{string-mask-strategy-b8cceee6.js → string-mask-strategy-cabc1d50.js} +2 -2
  166. package/dist/esm/{style-formatter-fcd70869.js → style-formatter-00fe4f1c.js} +2 -2
  167. package/dist/esm/{time-required-rule-ce50859b.js → time-required-rule-57ceeae9.js} +1 -1
  168. package/dist/esm/{token-extension-2401e753.js → token-extension-645a9520.js} +1011 -767
  169. package/dist/esm/{translation-slimmer-b3f3cf65.js → translation-slimmer-b69057eb.js} +1 -1
  170. package/dist/esm/{type-guard-08c82e08.js → type-guard-204094c6.js} +1 -1
  171. package/dist/esm/{valid-credit-card-number-rule-66bad519.js → valid-credit-card-number-rule-0874e19f.js} +1 -1
  172. package/dist/esm/vega-accordion.entry.js +6 -6
  173. package/dist/esm/vega-app-header-button.entry.js +5 -5
  174. package/dist/esm/vega-box.entry.js +6 -6
  175. package/dist/esm/vega-button-circle.entry.js +5 -5
  176. package/dist/esm/vega-button.entry.js +3 -3
  177. package/dist/esm/vega-calendar_5.entry.js +7 -7
  178. package/dist/esm/vega-card.entry.js +5 -5
  179. package/dist/esm/vega-carousel.entry.js +3 -3
  180. package/dist/esm/vega-checkbox_2.entry.js +2 -2
  181. package/dist/esm/vega-chip.entry.js +5 -5
  182. package/dist/esm/vega-code-block.entry.js +8 -8
  183. package/dist/esm/vega-color-picker.entry.js +2 -2
  184. package/dist/esm/vega-color-swatch-picker.entry.js +3 -3
  185. package/dist/esm/vega-color-swatch.entry.js +2 -2
  186. package/dist/esm/vega-combo-box.entry.js +8 -8
  187. package/dist/esm/vega-date-picker_2.entry.js +13 -13
  188. package/dist/esm/vega-dialog_2.entry.js +3 -3
  189. package/dist/esm/vega-divider.entry.js +5 -5
  190. package/dist/esm/vega-dropdown_5.entry.js +7 -7
  191. package/dist/esm/vega-env-manager-8f8dc473.js +2 -2
  192. package/dist/esm/vega-field-label.entry.js +2 -2
  193. package/dist/esm/vega-file-uploader.entry.js +3 -3
  194. package/dist/esm/vega-flag-icon.entry.js +5 -5
  195. package/dist/esm/vega-flex.entry.js +6 -6
  196. package/dist/esm/vega-font.entry.js +5 -5
  197. package/dist/esm/vega-form.entry.js +2 -2
  198. package/dist/esm/vega-grid.entry.js +5 -5
  199. package/dist/esm/vega-icon.entry.js +5 -5
  200. package/dist/esm/vega-image-uploader.entry.js +5 -5
  201. package/dist/esm/vega-input-credit-card.entry.js +6 -6
  202. package/dist/esm/vega-input-numeric.entry.js +12 -14
  203. package/dist/esm/vega-input-passcode.entry.js +5 -5
  204. package/dist/esm/vega-input-phone-number.entry.js +4 -4
  205. package/dist/esm/vega-input-range.entry.js +3 -3
  206. package/dist/esm/vega-input-select.entry.js +5 -5
  207. package/dist/esm/vega-input.entry.js +31 -27
  208. package/dist/esm/vega-left-nav_5.entry.js +7 -7
  209. package/dist/esm/vega-loader-wrapper_2.entry.js +3 -3
  210. package/dist/esm/vega-pagination-page-size-selector-mobile.entry.js +2 -2
  211. package/dist/esm/vega-pagination.entry.js +4 -4
  212. package/dist/esm/vega-popover_2.entry.js +8 -8
  213. package/dist/esm/vega-progress-tracker_2.entry.js +3 -3
  214. package/dist/esm/vega-radio_2.entry.js +5 -5
  215. package/dist/esm/vega-rich-text-bookmark-editor.entry.js +2 -2
  216. package/dist/esm/vega-rich-text-content.entry.js +6 -6
  217. package/dist/esm/vega-rich-text-editor_4.entry.js +474 -207
  218. package/dist/esm/vega-rich-text-find-replace-panel.entry.js +1 -1
  219. package/dist/esm/vega-rich-text-special-characters-panel.entry.js +5 -5
  220. package/dist/esm/vega-rich-text-table-properties_3.entry.js +8 -8
  221. package/dist/esm/vega-selection-chip_2.entry.js +4 -4
  222. package/dist/esm/vega-selection-tile_2.entry.js +2 -2
  223. package/dist/esm/vega-sidenav_3.entry.js +3 -3
  224. package/dist/esm/vega-signature-capture.entry.js +7 -7
  225. package/dist/esm/vega-stepper.entry.js +2 -2
  226. package/dist/esm/vega-tab-group_2.entry.js +6 -6
  227. package/dist/esm/vega-table_11.entry.js +4 -4
  228. package/dist/esm/vega-textarea.entry.js +2 -2
  229. package/dist/esm/vega-time-picker_2.entry.js +9 -9
  230. package/dist/esm/vega-toggle-switch.entry.js +2 -2
  231. package/dist/esm/vega-tooltip_2.entry.js +6 -6
  232. package/dist/esm/vega.js +12 -12
  233. package/dist/sri/vega-sri-manifest.json +321 -321
  234. package/dist/types/components/vega-input/slimmers/controllers/vega-input-state-controller.d.ts +0 -2
  235. package/dist/types/components/vega-input/slimmers/renderers/vega-input-input-container-renderer.d.ts +4 -0
  236. package/dist/types/components/vega-input/slimmers/renderers/vega-input-input-renderer.d.ts +2 -0
  237. package/dist/types/components/vega-input/vega-input.d.ts +15 -3
  238. package/dist/types/components/vega-input-numeric/slimmers/renderers/vega-input-numeric-renderer.d.ts +2 -0
  239. package/dist/types/components/vega-input-numeric/vega-input-numeric.d.ts +0 -2
  240. package/dist/types/components/vega-rich-text-editor/constants/constant.d.ts +4 -0
  241. package/dist/types/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/sequential-composition-strategy.d.ts +14 -0
  242. package/dist/types/components/vega-rich-text-editor/dto/actions/modify-content-action.abstract.d.ts +4 -1
  243. package/dist/types/components/vega-rich-text-editor/dto/actions/sequential-composition-action.d.ts +30 -0
  244. package/dist/types/components/vega-rich-text-editor/dto/flush-changes-payload.d.ts +16 -0
  245. package/dist/types/components/vega-rich-text-editor/extensions/functions/dto/function-block.d.ts +7 -0
  246. package/dist/types/components/vega-rich-text-editor/extensions/paste/controllers/chooser-positioner.d.ts +33 -0
  247. package/dist/types/components/vega-rich-text-editor/extensions/paste/controllers/paste-chooser-controller.d.ts +43 -0
  248. package/dist/types/components/vega-rich-text-editor/extensions/paste/controllers/paste-event-interceptor.d.ts +22 -0
  249. package/dist/types/components/vega-rich-text-editor/extensions/paste/controllers/selection-snapshot-service.d.ts +29 -0
  250. package/dist/types/components/vega-rich-text-editor/extensions/paste/parse-local-images-helper/image-extractor.d.ts +13 -0
  251. package/dist/types/components/vega-rich-text-editor/extensions/paste/parse-local-images-helper/paste-image-parser.d.ts +1 -1
  252. package/dist/types/components/vega-rich-text-editor/extensions/paste/parse-local-images-helper/pending-image-registry.d.ts +1 -1
  253. package/dist/types/components/vega-rich-text-editor/extensions/paste/paste-chooser-ui.d.ts +1 -0
  254. package/dist/types/components/vega-rich-text-editor/extensions/paste/paste-extension.d.ts +28 -93
  255. package/dist/types/components/vega-rich-text-editor/extensions/paste/pipeline/data-transfer-builder.d.ts +10 -0
  256. package/dist/types/components/vega-rich-text-editor/extensions/paste/pipeline/paste-dispatcher.d.ts +8 -0
  257. package/dist/types/components/vega-rich-text-editor/extensions/paste/pipeline/paste-processing-pipeline.d.ts +18 -0
  258. package/dist/types/components/vega-rich-text-editor/extensions/paste/strategies/paste-processing-strategy.abstract.d.ts +28 -6
  259. package/dist/types/components/vega-rich-text-editor/extensions/paste/strategies/paste-strategy-selector.d.ts +13 -0
  260. package/dist/types/components/vega-rich-text-editor/extensions/paste/strategies/plain-paste-strategy.d.ts +29 -0
  261. package/dist/types/components/vega-rich-text-editor/extensions/paste/type.d.ts +35 -0
  262. package/dist/types/components/vega-rich-text-editor/helpers/utils.d.ts +47 -0
  263. package/dist/types/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/abstract-delete-content-handler.d.ts +17 -6
  264. package/dist/types/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/backward-delete-content-handler.d.ts +5 -1
  265. package/dist/types/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/base-handler.d.ts +30 -1
  266. package/dist/types/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/forward-delete-content-handler.d.ts +5 -1
  267. package/dist/types/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/insert-line-break-handler.d.ts +21 -4
  268. package/dist/types/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/insert-paragraph-handler.d.ts +12 -4
  269. package/dist/types/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/insert-paste-handler.d.ts +38 -5
  270. package/dist/types/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/insert-text-handler.d.ts +7 -2
  271. package/dist/types/components/vega-rich-text-editor/slimmers/controllers/user-input-controller.d.ts +2 -0
  272. package/dist/types/components/vega-rich-text-editor/utils/html-to-plain-text-utils.d.ts +31 -0
  273. package/dist/types/components.d.ts +24 -0
  274. package/dist/types/helpers/translation/interface.d.ts +1 -0
  275. package/dist/types/types/public-api.d.ts +2 -1
  276. package/dist/vega/index.esm.js +1 -1
  277. package/dist/vega/{p-8a4cc7c2.entry.js → p-0169f71c.entry.js} +1 -1
  278. package/dist/vega/p-018bb83b.entry.js +1 -0
  279. package/dist/vega/{p-25e51acb.js → p-08bf08d2.js} +1 -1
  280. package/dist/vega/{p-85a940c0.entry.js → p-0b33753f.entry.js} +1 -1
  281. package/dist/vega/{p-a5fa260b.js → p-1537b1e4.js} +1 -1
  282. package/dist/vega/{p-7dfb1481.entry.js → p-17f6dc94.entry.js} +1 -1
  283. package/dist/vega/{p-dd673eb4.entry.js → p-1a4d1991.entry.js} +1 -1
  284. package/dist/vega/{p-557b64bd.js → p-1b2e5898.js} +1 -1
  285. package/dist/vega/{p-2256eb09.entry.js → p-1f1f93bf.entry.js} +1 -1
  286. package/dist/vega/{p-d86e0b01.js → p-1fb953f8.js} +1 -1
  287. package/dist/vega/{p-03efc67a.entry.js → p-2171b571.entry.js} +1 -1
  288. package/dist/vega/p-255fe20b.js +1 -0
  289. package/dist/vega/{p-cf5c5515.js → p-261cf764.js} +1 -1
  290. package/dist/vega/{p-f0b49ae4.entry.js → p-27e77ea1.entry.js} +1 -1
  291. package/dist/vega/{p-109f0e33.entry.js → p-28acbe42.entry.js} +1 -1
  292. package/dist/vega/{p-27c9c2a5.entry.js → p-2acc600a.entry.js} +1 -1
  293. package/dist/vega/p-2fc2299f.js +1 -0
  294. package/dist/vega/{p-b48caf90.entry.js → p-2ff659a1.entry.js} +1 -1
  295. package/dist/vega/{p-527c3211.entry.js → p-322da1eb.entry.js} +1 -1
  296. package/dist/vega/{p-dffe47db.js → p-3283fa2f.js} +1 -1
  297. package/dist/vega/p-3567dc55.entry.js +1 -0
  298. package/dist/vega/{p-c6419eb3.entry.js → p-36b795c6.entry.js} +1 -1
  299. package/dist/vega/p-37714a3a.js +1 -0
  300. package/dist/vega/{p-d7e59f31.js → p-3b4e2ba0.js} +1 -1
  301. package/dist/vega/{p-3d060d2f.entry.js → p-3b911043.entry.js} +1 -1
  302. package/dist/vega/{p-5c6d36ef.entry.js → p-3e270b65.entry.js} +1 -1
  303. package/dist/vega/{p-b68f55e2.js → p-4043508a.js} +1 -1
  304. package/dist/vega/p-4151d4a8.js +1 -0
  305. package/dist/vega/{p-c6b6987e.js → p-45af801f.js} +1 -1
  306. package/dist/vega/p-48c2150b.entry.js +1 -0
  307. package/dist/vega/p-4b253f74.entry.js +1 -0
  308. package/dist/vega/{p-75c7f8ea.entry.js → p-4cdc064d.entry.js} +1 -1
  309. package/dist/vega/{p-1d8a8507.entry.js → p-4e4b50f3.entry.js} +1 -1
  310. package/dist/vega/{p-d8fa2f19.entry.js → p-564110ba.entry.js} +1 -1
  311. package/dist/vega/p-5f377954.js +1 -1
  312. package/dist/vega/{p-bec31ffc.entry.js → p-608d3559.entry.js} +1 -1
  313. package/dist/vega/{p-3ce7521e.entry.js → p-64eb05d3.entry.js} +1 -1
  314. package/dist/vega/{p-2f5c4b61.entry.js → p-66bf209b.entry.js} +1 -1
  315. package/dist/vega/{p-83f5ef3a.entry.js → p-69eadbd8.entry.js} +1 -1
  316. package/dist/vega/{p-c66c6fd2.entry.js → p-6c4edee8.entry.js} +1 -1
  317. package/dist/vega/p-6e16bb3a.js +1 -0
  318. package/dist/vega/{p-7d748545.entry.js → p-76f4fdba.entry.js} +1 -1
  319. package/dist/vega/{p-4c6989ae.entry.js → p-7874055b.entry.js} +1 -1
  320. package/dist/vega/{p-ca60a74b.entry.js → p-7d3d24f6.entry.js} +1 -1
  321. package/dist/vega/{p-3bfb53e3.js → p-7f9ad7bc.js} +1 -1
  322. package/dist/vega/{p-18ddc6a4.entry.js → p-8193f4ef.entry.js} +1 -1
  323. package/dist/vega/{p-816064f2.entry.js → p-8197d172.entry.js} +1 -1
  324. package/dist/vega/{p-634b138c.entry.js → p-8ac0b1b2.entry.js} +1 -1
  325. package/dist/vega/{p-553510d8.entry.js → p-8c61db9d.entry.js} +1 -1
  326. package/dist/vega/{p-061a76c3.entry.js → p-8de29082.entry.js} +1 -1
  327. package/dist/vega/{p-325b804d.entry.js → p-8e59606f.entry.js} +1 -1
  328. package/dist/vega/p-8ea41806.js +1 -0
  329. package/dist/vega/{p-ff9090af.entry.js → p-9153c2f5.entry.js} +1 -1
  330. package/dist/vega/{p-a0c87e88.entry.js → p-92411f56.entry.js} +1 -1
  331. package/dist/vega/{p-049e64b1.entry.js → p-94d65dcf.entry.js} +1 -1
  332. package/dist/vega/{p-a261a675.entry.js → p-9a96fb05.entry.js} +1 -1
  333. package/dist/vega/{p-7044bb48.js → p-9fcfd738.js} +1 -1
  334. package/dist/vega/{p-b1e1c7d0.js → p-a2c7a3bc.js} +1 -1
  335. package/dist/vega/p-a2dcde12.js +1 -0
  336. package/dist/vega/{p-be0eb72f.js → p-a60d75d9.js} +1 -1
  337. package/dist/vega/{p-5a347a15.js → p-a9fc4043.js} +1 -1
  338. package/dist/vega/{p-efef0dfe.entry.js → p-abe5f7f0.entry.js} +1 -1
  339. package/dist/vega/{p-197388a5.entry.js → p-ac98c189.entry.js} +1 -1
  340. package/dist/vega/{p-dd273d89.entry.js → p-ade903b3.entry.js} +1 -1
  341. package/dist/vega/{p-c0eb8c58.js → p-affb40e8.js} +1 -1
  342. package/dist/vega/{p-277aab9b.js → p-b3a1cd22.js} +1 -1
  343. package/dist/vega/p-b63a90b3.entry.js +1 -0
  344. package/dist/vega/{p-f9f96030.entry.js → p-ba050d63.entry.js} +1 -1
  345. package/dist/vega/{p-bf0b46c1.js → p-ba67eb96.js} +1 -1
  346. package/dist/vega/{p-f0c6e9c5.entry.js → p-c08ac33f.entry.js} +1 -1
  347. package/dist/vega/{p-46be74fc.entry.js → p-c7ec97d1.entry.js} +1 -1
  348. package/dist/vega/{p-effbfc50.entry.js → p-ca1fe571.entry.js} +1 -1
  349. package/dist/vega/{p-408c3ad4.entry.js → p-cc9fc36a.entry.js} +1 -1
  350. package/dist/vega/{p-741e064e.entry.js → p-d044d54f.entry.js} +1 -1
  351. package/dist/vega/{p-0e0e66c9.entry.js → p-d3a9355c.entry.js} +1 -1
  352. package/dist/vega/p-d5a75228.js +1 -0
  353. package/dist/vega/{p-76135e80.entry.js → p-dc83fa6b.entry.js} +1 -1
  354. package/dist/vega/{p-92efdbf0.entry.js → p-dcfce26e.entry.js} +1 -1
  355. package/dist/vega/p-df9585f6.js +3 -0
  356. package/dist/vega/{p-f5f26b44.entry.js → p-e2c8a470.entry.js} +1 -1
  357. package/dist/vega/{p-23781e76.js → p-e33a954f.js} +1 -1
  358. package/dist/vega/{p-e577dda8.entry.js → p-e5fc6583.entry.js} +1 -1
  359. package/dist/vega/p-e668cf11.js +1 -0
  360. package/dist/vega/{p-0338f621.entry.js → p-e6b0a292.entry.js} +1 -1
  361. package/dist/vega/{p-381d8781.js → p-e84c2589.js} +1 -1
  362. package/dist/vega/{p-1b97e751.entry.js → p-eb945d34.entry.js} +1 -1
  363. package/dist/vega/{p-d8a0e3e0.entry.js → p-ebe1dd2b.entry.js} +1 -1
  364. package/dist/vega/{p-6beaf1c8.entry.js → p-f818bb20.entry.js} +1 -1
  365. package/dist/vega/p-f981cf2c.js +1 -0
  366. package/dist/vega/p-f9d09b0c.js +1 -0
  367. package/dist/vega/{p-4d20a56f.js → p-fdbdf12f.js} +1 -1
  368. package/dist/vega/{p-48100d38.entry.js → p-fee080b9.entry.js} +1 -1
  369. package/dist/vega/vega.esm.js +1 -1
  370. package/package.json +1 -1
  371. package/dist/vega/p-040bd9ca.js +0 -1
  372. package/dist/vega/p-087240db.js +0 -1
  373. package/dist/vega/p-15052b2e.entry.js +0 -1
  374. package/dist/vega/p-28c16885.js +0 -1
  375. package/dist/vega/p-30cc31dd.entry.js +0 -1
  376. package/dist/vega/p-3ec4d710.js +0 -1
  377. package/dist/vega/p-43ea1e86.js +0 -1
  378. package/dist/vega/p-7228088b.entry.js +0 -1
  379. package/dist/vega/p-7f711049.js +0 -1
  380. package/dist/vega/p-7fd15dd1.js +0 -1
  381. package/dist/vega/p-85695819.js +0 -1
  382. package/dist/vega/p-8e1f30ec.entry.js +0 -1
  383. package/dist/vega/p-9680dfe6.js +0 -1
  384. package/dist/vega/p-ae12cc3f.js +0 -3
  385. package/dist/vega/p-c0823f32.js +0 -1
  386. package/dist/vega/p-c5af2ecc.entry.js +0 -1
  387. package/dist/vega/p-fa43272c.js +0 -1
@@ -6,16 +6,16 @@ import { I as InternalVegaZIndexManager } from './internal-vega-z-index-manager-
6
6
  import { c as createDynamicSlimmer } from './dynamic-slimmer-90b8af32.js';
7
7
  import { P as PageResizeObserverSlimmer } from './page-resize-observer-slimmer-e24d36c5.js';
8
8
  import { i as internalVegaEventManager } from './internal-vega-event-manager-6eebe8f8.js';
9
- import { V as VegaInternalTranslation } from './internal-translation-controller-4a7ee4d5.js';
10
- import { I as InternalCalendarPeriodConverter } from './internal-calendar-period-factory-7b866c3b.js';
11
- import { M as ModifyContentAction, A as ActionHandleStrategyRegistry, R as RTETextNode, H as HTML_VOID_TAGS, a as RTEBlock, b as RTETextBlock, c as RTE_BLOCK_BOUNDARY_ATTRIBUTE, d as RTEAnnotationStyle, e as ActionHandleStrategy, I as InsertChildrenAfterAction, f as AppendChildrenAction, g as RTENode, s as stateEntityRenderingRegistry, h as InsertChildrenBeforeAction, i as InternalAnnotationTypeEnum, j as ModifyContentActionType, B as BlockAnnotation, k as AnnotationAction, l as RemoveChildrenAction, C as CommonAnnotationTypeEnum, m as CustomAttributeAnnotation, n as RTEDTOClassManager, o as RTEFilterStylesStrategy, p as RTEDecoratorNode, S as SplitBlockWithNodeAction, U as UpdateTextAction, q as RTECodeBlock, r as RTEListItemBlock, t as RTECodeBlockNode, N as NodeAnnotationTypeEnum, u as CustomStyleAnnotation, v as RTEFilterStylesStrategyRegistry, w as RTE_PASTE_MODE_DATA_TYPE, x as RTE_WORD_COUNT_KEY } from './code-block-d8f83d85.js';
12
- import { U as UpdateCursorPositionAction, V as VegaRTEContent, B as BlockToRTEBlockStrategyAbstract, E as ElementToDTOStrategy, h as htmlElementToAnnotationGenerator, H as HtmlBlockStrategy, I as InsertNewParagraphAction, R as RTEImageBlock, a as InsertChildrenBeforeStrategy, P as PasteContentStrategy, A as AnnotationGeneratorStrategyAbstract, S as StylePreservator, b as RTEImageNode, C as COMMIT_VALUE } from './content-state-486eae1d.js';
13
- import { a as VegaRTEExtensionRenderer, b as VegaRTEExtension, e as extensionContextManager } from './link-extension-3f93d70d.js';
9
+ import { V as VegaInternalTranslation } from './internal-translation-controller-3637e47e.js';
10
+ import { I as InternalCalendarPeriodConverter } from './internal-calendar-period-factory-261df2f2.js';
11
+ import { M as ModifyContentAction, A as ActionHandleStrategyRegistry, R as RTETextNode, H as HTML_VOID_TAGS, a as RTENode, s as stateEntityRenderingRegistry, b as RTEBlock, c as RTETextBlock, N as NodeAnnotationTypeEnum, d as RTE_BLOCK_BOUNDARY_ATTRIBUTE, e as RTEAnnotationStyle, f as ActionHandleStrategy, I as InsertChildrenAfterAction, g as AppendChildrenAction, h as InsertChildrenBeforeAction, i as InternalAnnotationTypeEnum, j as ModifyContentActionType, B as BlockAnnotation, k as AnnotationAction, l as RemoveChildrenAction, C as CommonAnnotationTypeEnum, m as CustomAttributeAnnotation, n as RTEDTOClassManager, o as RTEFilterStylesStrategy, p as RTEDecoratorNode, S as SplitBlockWithNodeAction, U as UpdateTextAction, q as RTECodeBlock, r as RTEListItemBlock, t as RTECodeBlockNode, u as CustomStyleAnnotation, v as RTEFilterStylesStrategyRegistry, w as plainPasteLinesToHtml, x as toPlainPasteLines, y as RTE_PRESERVED_WHITESPACE_DATA_TYPE, z as RTE_PASTE_MODE_DATA_TYPE, D as RTE_WORD_COUNT_KEY } from './code-block-9360c331.js';
12
+ import { U as UpdateCursorPositionAction, V as VegaRTEContent, B as BlockToRTEBlockStrategyAbstract, E as ElementToDTOStrategy, h as htmlElementToAnnotationGenerator, H as HtmlBlockStrategy, I as InsertNewParagraphAction, R as RTEImageBlock, a as InsertChildrenBeforeStrategy, P as PasteContentStrategy, A as AnnotationGeneratorStrategyAbstract, S as StylePreservator, b as RTEImageNode, C as COMMIT_VALUE } from './content-state-67a12e74.js';
13
+ import { a as VegaRTEExtensionRenderer, b as VegaRTEExtension, e as extensionContextManager } from './link-extension-57ba9520.js';
14
14
  import { V as VegaInternalIconManager } from './internal-icon-manager-d4d534d2.js';
15
- import { i as isNonNullable } from './type-guard-08c82e08.js';
15
+ import { i as isNonNullable } from './type-guard-204094c6.js';
16
16
  import { v as vegaNonceManager } from './vega-nonce-manager-497e5eb5.js';
17
- import { b as VegaRTEToolbarButtonRenderer, A as ActionHandlerInterceptor, R as ReplaceSelectedTextAction, I as InsertNodeToNearestRootAction } from './image-extension-20b39140.js';
18
- import { R as RTETableExtensionAnnotationTypeEnum, a as RTE_TABLE_HEAD_DEFAULT_BACKGROUND_COLOR, S as SettingEventHandler, T as TableSettingType, b as RTETableAnnotation, c as RTETableCellAnnotation, d as RTETableHeadCellBlock, e as RowOperationEventHandler, C as ColumnOperationEventHandler, M as MergeCellsOperationEventHandler, f as SplitCellOperationEventHandler, g as RTETableColorManager, h as RTETableBlock, i as generateTableBody, j as RTETableCellBlock, k as RTETableHeadBlock, l as RTETableBodyBlock, m as getParentBlockByType, n as RTETableHeadCellAnnotation, o as TableColumnStrategy, p as getAllTableRows, q as buildTableGrid, s as setSpanAttributes, r as findCellBlockById, t as getDefaultCellBlockTemplate, I as InsertTableColumnDirection, u as buildCellStartColumnMap, v as getTableColumnCount, w as getFirstNode, x as getCellSpan, y as createNewCell, z as MergeCellsOperationType, A as RTETableRowBlock, B as getActualColumnPosition, D as InsertTableRowDirection, E as RTE_TABLE_DEFAULT_COLORS, F as INSERT_TABLE_ROW_INTO_DIFFERENT_SECTION, G as INSERT_TABLE_ROW_INTO_SAME_SECTION, H as DELETE_TABLE_ROW, J as TOGGLE_HEADER_ROW, K as INSERT_TABLE_COLUMN, L as DELETE_TABLE_COLUMN, N as TOGGLE_HEADER_TABLE_COLUMN, O as ToggleHeaderTableColumnStrategy, P as SPLIT_TABLE_CELL, Q as REPLACE_TABLE_CELL, U as SPLIT_CELL_HORIZONTALLY, W as SPLIT_CELL_VERTICALLY, X as SELECT_TABLE_COLUMN, Y as MERGE_CELLS } from './split-cell-operation-e158366a.js';
17
+ import { b as VegaRTEToolbarButtonRenderer, A as ActionHandlerInterceptor, R as ReplaceSelectedTextAction, h as htmlContainsTable, c as htmlToPlainText, I as InsertNodeToNearestRootAction } from './image-extension-aea75132.js';
18
+ import { R as RTETableExtensionAnnotationTypeEnum, a as RTE_TABLE_HEAD_DEFAULT_BACKGROUND_COLOR, S as SettingEventHandler, T as TableSettingType, b as RTETableAnnotation, c as RTETableCellAnnotation, d as RTETableHeadCellBlock, e as RowOperationEventHandler, C as ColumnOperationEventHandler, M as MergeCellsOperationEventHandler, f as SplitCellOperationEventHandler, g as RTETableColorManager, h as RTETableBlock, i as generateTableBody, j as RTETableCellBlock, k as RTETableHeadBlock, l as RTETableBodyBlock, m as getParentBlockByType, n as RTETableHeadCellAnnotation, o as TableColumnStrategy, p as getAllTableRows, q as buildTableGrid, s as setSpanAttributes, r as findCellBlockById, t as getDefaultCellBlockTemplate, I as InsertTableColumnDirection, u as buildCellStartColumnMap, v as getTableColumnCount, w as getFirstNode, x as getCellSpan, y as createNewCell, z as MergeCellsOperationType, A as RTETableRowBlock, B as getActualColumnPosition, D as InsertTableRowDirection, E as RTE_TABLE_DEFAULT_COLORS, F as INSERT_TABLE_ROW_INTO_DIFFERENT_SECTION, G as INSERT_TABLE_ROW_INTO_SAME_SECTION, H as DELETE_TABLE_ROW, J as TOGGLE_HEADER_ROW, K as INSERT_TABLE_COLUMN, L as DELETE_TABLE_COLUMN, N as TOGGLE_HEADER_TABLE_COLUMN, O as ToggleHeaderTableColumnStrategy, P as SPLIT_TABLE_CELL, Q as REPLACE_TABLE_CELL, U as SPLIT_CELL_HORIZONTALLY, W as SPLIT_CELL_VERTICALLY, X as SELECT_TABLE_COLUMN, Y as MERGE_CELLS } from './split-cell-operation-85a036f9.js';
19
19
  import { C as ChangeManager } from './change-manager-6a7eb88c.js';
20
20
  import { D as DomNodeSubjectObserverFactory, d as domNodeSubjectFactory } from './dom-node-subject-observer-factory-bb7e68a0.js';
21
21
  import { V as VegaInternalRTEExtensionTableCellsSelectionAnchor, a as VegaInternalPopoverUpdateTarget, b as VegaInternalRTEExtensionTableCellSelectionChange } from './vega-internal-event-id-02093067.js';
@@ -1628,6 +1628,154 @@ const FUNCTION_ELEMENT_CLASSES = [
1628
1628
  FUNCTION_SYNTAX_CLASS,
1629
1629
  ];
1630
1630
 
1631
+ /**
1632
+ * Class representing a logic control node in the rich text editor.
1633
+ */
1634
+ class RTELogicControlNode extends RTENode {
1635
+ constructor(id, text, parent) {
1636
+ super(id);
1637
+ this.type = 'logic-control-node';
1638
+ this.text = '';
1639
+ this.text = text;
1640
+ this.parent = parent;
1641
+ }
1642
+ /**
1643
+ * Clone the current node instance.
1644
+ *
1645
+ * @returns {RTELogicControlNode} - A new instance of RTELogicControlNode.
1646
+ */
1647
+ clone() {
1648
+ return new RTELogicControlNode(this.id, this.text, this.parent);
1649
+ }
1650
+ /**
1651
+ * Convert the node to its HTML representation.
1652
+ *
1653
+ * @returns {string} - The HTML string of the logic control node.
1654
+ */
1655
+ toHtml() {
1656
+ return this.text;
1657
+ }
1658
+ /**
1659
+ * Convert the node to a JSON representation.
1660
+ *
1661
+ * @returns {unknown} - The JSON object of the statement syntax node.
1662
+ */
1663
+ toJSON() {
1664
+ return {
1665
+ id: this.id,
1666
+ type: this.type,
1667
+ text: this.text,
1668
+ };
1669
+ }
1670
+ /**
1671
+ * Get the end offset of the node's range.
1672
+ *
1673
+ * @returns {number} - The end offset of the node's range.
1674
+ */
1675
+ getRangeEndOffset() {
1676
+ return 1;
1677
+ }
1678
+ /**
1679
+ * Get the container element for the node's range.
1680
+ *
1681
+ * @returns {Nullable<Node>} - The container node for the range.
1682
+ */
1683
+ getRangeContainer() {
1684
+ const element = stateEntityRenderingRegistry.getDOMByEntity(this);
1685
+ if (element) {
1686
+ return element.parentElement;
1687
+ }
1688
+ }
1689
+ /**
1690
+ * Get the content editable state of the node.
1691
+ *
1692
+ * @returns {boolean} - The content editable state of the node.
1693
+ */
1694
+ isContentEditable() {
1695
+ return false;
1696
+ }
1697
+ /**
1698
+ * @inheritDoc
1699
+ */
1700
+ getPlainText() {
1701
+ return this.text;
1702
+ }
1703
+ }
1704
+ RTELogicControlNode.typeName = 'RTELogicControlNode';
1705
+
1706
+ /**
1707
+ * Class representing a logic control block in the rich text editor.
1708
+ */
1709
+ class RTELogicControlBlock extends RTEBlock {
1710
+ constructor(id, statementText, parent) {
1711
+ super(id);
1712
+ this.type = 'logic-control-block';
1713
+ this.children = [];
1714
+ this.statementText = '';
1715
+ this.statementText = statementText;
1716
+ this.children = [new RTELogicControlNode(`${id}-node-1`, statementText, this)];
1717
+ if (parent) {
1718
+ this.parent = parent;
1719
+ }
1720
+ }
1721
+ /**
1722
+ * Create a logic control block from a JSON representation.
1723
+ *
1724
+ * @param {VegaRTELogicControlBlock} json - The JSON object representing the logic control block.
1725
+ * @returns {RTELogicControlBlock} - The created logic control block.
1726
+ */
1727
+ static from(json) {
1728
+ const block = new RTELogicControlBlock(json.id, json.statementText);
1729
+ return block;
1730
+ }
1731
+ /**
1732
+ * Check the block is not empty.
1733
+ *
1734
+ * @returns {boolean} - Always true for logic control block.
1735
+ */
1736
+ isNotEmpty() {
1737
+ return true;
1738
+ }
1739
+ /**
1740
+ * Get the last node of the block.
1741
+ *
1742
+ * @returns {RTELogicControlNode} - The last node in the block.
1743
+ */
1744
+ getLastNode() {
1745
+ return this.children[this.children.length - 1];
1746
+ }
1747
+ /**
1748
+ * Convert the block to its HTML representation.
1749
+ *
1750
+ * @returns {string} - The HTML string of the logic control block.
1751
+ */
1752
+ toHtml() {
1753
+ return `<div class='${FUNCTION_SYNTAX_CLASS}' contenteditable='false'>${this.statementText}</div>`;
1754
+ }
1755
+ /**
1756
+ * Clone the current block instance.
1757
+ *
1758
+ * @param { RTEFunctionBlock } parent - The parent function block for the cloned instance.
1759
+ * @returns {RTELogicControlBlock} - A new instance of RTEStatementSyntaxBlock.
1760
+ */
1761
+ clone(parent) {
1762
+ return new RTELogicControlBlock(this.id, this.statementText, parent);
1763
+ }
1764
+ /**
1765
+ * Get the JSON representation of the block.
1766
+ *
1767
+ * @returns {VegaRTELogicControlBlock} - The JSON object of the logic control block.
1768
+ */
1769
+ toJSON() {
1770
+ return {
1771
+ id: this.id,
1772
+ type: this.type,
1773
+ statementText: this.statementText,
1774
+ };
1775
+ }
1776
+ }
1777
+ RTELogicControlBlock.typeName = 'RTELogicControlBlock';
1778
+
1631
1779
  /**
1632
1780
  * RTE Function Block
1633
1781
  */
@@ -1652,8 +1800,36 @@ class RTEFunctionBlock extends RTEBlock {
1652
1800
  ? Object.assign(Object.assign({}, annotations), defaultAnnotation) : defaultAnnotation;
1653
1801
  super.convertAnnotationsToMap(functionBlock.annotationMap, annotations);
1654
1802
  functionBlock.children = this.generateBlockChildren(block.children, options, functionBlock);
1803
+ this.unwrapForeachContent(functionBlock.children);
1655
1804
  return functionBlock;
1656
1805
  }
1806
+ /**
1807
+ * Removes a redundant div wrapper from FOREACH content so it is rendered inline
1808
+ * with the FOREACH control. SHOW content retains its wrapper to preserve line breaks.
1809
+ *
1810
+ * @param {RTEFunctionBlockChild[]} children - The function block children to normalize.
1811
+ */
1812
+ static unwrapForeachContent(children) {
1813
+ children.forEach((logicControlBlock, index) => {
1814
+ const contentBlock = children[index + 1];
1815
+ if (!(logicControlBlock instanceof RTELogicControlBlock) ||
1816
+ logicControlBlock.statementText !== 'FOREACH' ||
1817
+ !(contentBlock instanceof RTETextBlock)) {
1818
+ return;
1819
+ }
1820
+ contentBlock.children.forEach((node) => {
1821
+ const inlineHtml = node.getAnnotationByType(NodeAnnotationTypeEnum.INLINE_HTML);
1822
+ if ((inlineHtml === null || inlineHtml === void 0 ? void 0 : inlineHtml.htmlTag) !== 'div')
1823
+ return;
1824
+ if (inlineHtml.child) {
1825
+ node.annotationMap.set(NodeAnnotationTypeEnum.INLINE_HTML, inlineHtml.child);
1826
+ }
1827
+ else {
1828
+ node.annotationMap.delete(NodeAnnotationTypeEnum.INLINE_HTML);
1829
+ }
1830
+ });
1831
+ });
1832
+ }
1657
1833
  /**
1658
1834
  * Converts the RTEFunctionBlock and its children to an HTML string.
1659
1835
  *
@@ -1827,218 +2003,70 @@ class InsertFunctionBlockStrategy extends ActionHandleStrategy {
1827
2003
  }
1828
2004
 
1829
2005
  /**
1830
- * Class representing a logic control node in the rich text editor.
2006
+ * Function toolbar button renderer class.
1831
2007
  */
1832
- class RTELogicControlNode extends RTENode {
1833
- constructor(id, text, parent) {
1834
- super(id);
1835
- this.type = 'logic-control-node';
1836
- this.text = '';
1837
- this.text = text;
1838
- this.parent = parent;
1839
- }
1840
- /**
1841
- * Clone the current node instance.
1842
- *
1843
- * @returns {RTELogicControlNode} - A new instance of RTELogicControlNode.
1844
- */
1845
- clone() {
1846
- return new RTELogicControlNode(this.id, this.text, this.parent);
1847
- }
2008
+ class FunctionToolbarButtonRenderer extends VegaRTEToolbarButtonRenderer {
1848
2009
  /**
1849
- * Convert the node to its HTML representation.
1850
- *
1851
- * @returns {string} - The HTML string of the logic control node.
2010
+ * @inheritDoc
1852
2011
  */
1853
- toHtml() {
1854
- return this.text;
2012
+ render(h, editorContext) {
2013
+ return this.renderDropdown(h, editorContext, {}, [
2014
+ this.renderButton(h, editorContext, {
2015
+ label: 'Functions',
2016
+ ariaLabel: 'Functions',
2017
+ showArrowIcon: true,
2018
+ tooltip: { text: 'Insert function' },
2019
+ }),
2020
+ this.renderDropdownListTemplate(h, FunctionToolbarButtonRenderer.FUNCTION_LIST, editorContext),
2021
+ ]);
1855
2022
  }
1856
2023
  /**
1857
- * Convert the node to a JSON representation.
2024
+ * Overrides the isDisabled method to determine if the button should be disabled.
1858
2025
  *
1859
- * @returns {unknown} - The JSON object of the statement syntax node.
2026
+ * @param {VegaRTEToolbarRenderContext} editorContext The render context for the editor.
2027
+ * @returns {boolean} - true if the button should be disabled, false otherwise.
1860
2028
  */
1861
- toJSON() {
1862
- return {
1863
- id: this.id,
1864
- type: this.type,
1865
- text: this.text,
1866
- };
2029
+ isDisabled(editorContext) {
2030
+ const context = this.getExtensionContext(editorContext.host);
2031
+ if (context) {
2032
+ const { host, getSelectedNodes } = context;
2033
+ const focusNode = getSelectedNodes()[0];
2034
+ let enableInsert = true;
2035
+ if (focusNode) {
2036
+ enableInsert = ActionHandleStrategyRegistry.canHandle(INSERT_FUNCTION_BLOCK, focusNode.parent);
2037
+ }
2038
+ return host.disabled || !enableInsert;
2039
+ }
2040
+ return false;
1867
2041
  }
1868
- /**
1869
- * Get the end offset of the node's range.
1870
- *
1871
- * @returns {number} - The end offset of the node's range.
1872
- */
1873
- getRangeEndOffset() {
1874
- return 1;
2042
+ /* istanbul ignore next */
2043
+ // eslint-disable-next-line jsdoc/require-jsdoc
2044
+ handleButtonClick() {
2045
+ throw new Error('Method not implemented.');
1875
2046
  }
1876
2047
  /**
1877
- * Get the container element for the node's range.
2048
+ * Handles dropdown click event
1878
2049
  *
1879
- * @returns {Nullable<Node>} - The container node for the range.
2050
+ * @param {RTEExtensionFunctionType} itemKey - key of the clicked item
2051
+ * @param {VegaRTEToolbarRenderContext} editorContext The render context for the editor.
1880
2052
  */
1881
- getRangeContainer() {
1882
- const element = stateEntityRenderingRegistry.getDOMByEntity(this);
1883
- if (element) {
1884
- return element.parentElement;
1885
- }
1886
- }
1887
- /**
1888
- * Get the content editable state of the node.
1889
- *
1890
- * @returns {boolean} - The content editable state of the node.
1891
- */
1892
- isContentEditable() {
1893
- return false;
1894
- }
1895
- /**
1896
- * @inheritDoc
1897
- */
1898
- getPlainText() {
1899
- return this.text;
1900
- }
1901
- }
1902
- RTELogicControlNode.typeName = 'RTELogicControlNode';
1903
-
1904
- /**
1905
- * Class representing a logic control block in the rich text editor.
1906
- */
1907
- class RTELogicControlBlock extends RTEBlock {
1908
- constructor(id, statementText, parent) {
1909
- super(id);
1910
- this.type = 'logic-control-block';
1911
- this.children = [];
1912
- this.statementText = '';
1913
- this.statementText = statementText;
1914
- this.children = [new RTELogicControlNode(`${id}-node-1`, statementText, this)];
1915
- if (parent) {
1916
- this.parent = parent;
1917
- }
1918
- }
1919
- /**
1920
- * Create a logic control block from a JSON representation.
1921
- *
1922
- * @param {VegaRTELogicControlBlock} json - The JSON object representing the logic control block.
1923
- * @returns {RTELogicControlBlock} - The created logic control block.
1924
- */
1925
- static from(json) {
1926
- const block = new RTELogicControlBlock(json.id, json.statementText);
1927
- return block;
1928
- }
1929
- /**
1930
- * Check the block is not empty.
1931
- *
1932
- * @returns {boolean} - Always true for logic control block.
1933
- */
1934
- isNotEmpty() {
1935
- return true;
1936
- }
1937
- /**
1938
- * Get the last node of the block.
1939
- *
1940
- * @returns {RTELogicControlNode} - The last node in the block.
1941
- */
1942
- getLastNode() {
1943
- return this.children[this.children.length - 1];
1944
- }
1945
- /**
1946
- * Convert the block to its HTML representation.
1947
- *
1948
- * @returns {string} - The HTML string of the logic control block.
1949
- */
1950
- toHtml() {
1951
- return `<div class='${FUNCTION_SYNTAX_CLASS}' contenteditable='false'>${this.statementText}</div>`;
1952
- }
1953
- /**
1954
- * Clone the current block instance.
1955
- *
1956
- * @param { RTEFunctionBlock } parent - The parent function block for the cloned instance.
1957
- * @returns {RTELogicControlBlock} - A new instance of RTEStatementSyntaxBlock.
1958
- */
1959
- clone(parent) {
1960
- return new RTELogicControlBlock(this.id, this.statementText, parent);
1961
- }
1962
- /**
1963
- * Get the JSON representation of the block.
1964
- *
1965
- * @returns {VegaRTELogicControlBlock} - The JSON object of the logic control block.
1966
- */
1967
- toJSON() {
1968
- return {
1969
- id: this.id,
1970
- type: this.type,
1971
- statementText: this.statementText,
1972
- };
1973
- }
1974
- }
1975
- RTELogicControlBlock.typeName = 'RTELogicControlBlock';
1976
-
1977
- /**
1978
- * Function toolbar button renderer class.
1979
- */
1980
- class FunctionToolbarButtonRenderer extends VegaRTEToolbarButtonRenderer {
1981
- /**
1982
- * @inheritDoc
1983
- */
1984
- render(h, editorContext) {
1985
- return this.renderDropdown(h, editorContext, {}, [
1986
- this.renderButton(h, editorContext, {
1987
- label: 'Functions',
1988
- ariaLabel: 'Functions',
1989
- showArrowIcon: true,
1990
- tooltip: { text: 'Insert function' },
1991
- }),
1992
- this.renderDropdownListTemplate(h, FunctionToolbarButtonRenderer.FUNCTION_LIST, editorContext),
1993
- ]);
1994
- }
1995
- /**
1996
- * Overrides the isDisabled method to determine if the button should be disabled.
1997
- *
1998
- * @param {VegaRTEToolbarRenderContext} editorContext The render context for the editor.
1999
- * @returns {boolean} - true if the button should be disabled, false otherwise.
2000
- */
2001
- isDisabled(editorContext) {
2002
- const context = this.getExtensionContext(editorContext.host);
2003
- if (context) {
2004
- const { host, getSelectedNodes } = context;
2005
- const focusNode = getSelectedNodes()[0];
2006
- let enableInsert = true;
2007
- if (focusNode) {
2008
- enableInsert = ActionHandleStrategyRegistry.canHandle(INSERT_FUNCTION_BLOCK, focusNode.parent);
2009
- }
2010
- return host.disabled || !enableInsert;
2011
- }
2012
- return false;
2013
- }
2014
- /* istanbul ignore next */
2015
- // eslint-disable-next-line jsdoc/require-jsdoc
2016
- handleButtonClick() {
2017
- throw new Error('Method not implemented.');
2018
- }
2019
- /**
2020
- * Handles dropdown click event
2021
- *
2022
- * @param {RTEExtensionFunctionType} itemKey - key of the clicked item
2023
- * @param {VegaRTEToolbarRenderContext} editorContext The render context for the editor.
2024
- */
2025
- handleDropdownClick(itemKey, editorContext) {
2026
- if (editorContext) {
2027
- const context = this.getExtensionContext(editorContext.host);
2028
- if (context) {
2029
- const { host, getSelectedNodes } = context;
2030
- const focusNode = getSelectedNodes()[0];
2031
- const action = new InsertFunctionBlockAction(itemKey);
2032
- if (!focusNode) {
2033
- host.value.apply(action);
2034
- }
2035
- else if (focusNode.parent) {
2036
- focusNode.parent.apply(action);
2037
- }
2038
- if (action.nextFocusNode) {
2039
- host.value.apply(new UpdateCursorPositionAction(action.nextFocusNode, 1));
2040
- }
2041
- }
2053
+ handleDropdownClick(itemKey, editorContext) {
2054
+ if (editorContext) {
2055
+ const context = this.getExtensionContext(editorContext.host);
2056
+ if (context) {
2057
+ const { host, getSelectedNodes } = context;
2058
+ const focusNode = getSelectedNodes()[0];
2059
+ const action = new InsertFunctionBlockAction(itemKey);
2060
+ if (!focusNode) {
2061
+ host.value.apply(action);
2062
+ }
2063
+ else if (focusNode.parent) {
2064
+ focusNode.parent.apply(action);
2065
+ }
2066
+ if (action.nextFocusNode) {
2067
+ host.value.apply(new UpdateCursorPositionAction(action.nextFocusNode, 1));
2068
+ }
2069
+ }
2042
2070
  }
2043
2071
  }
2044
2072
  }
@@ -2192,6 +2220,7 @@ class DivToFunctionBlockStrategy extends ElementToDTOStrategy {
2192
2220
  * @inheritDoc
2193
2221
  */
2194
2222
  appendChildBlocks(currentBlock, childBlocks) {
2223
+ RTEFunctionBlock.unwrapForeachContent(childBlocks);
2195
2224
  currentBlock.children = childBlocks.map((block) => {
2196
2225
  block.parent = currentBlock;
2197
2226
  return block;
@@ -11492,6 +11521,7 @@ VegaRTEFullscreenExtension.controllerStore = VegaRTEFullscreenExtension.createSt
11492
11521
  var RTEPasteMode;
11493
11522
  (function (RTEPasteMode) {
11494
11523
  RTEPasteMode["RICH"] = "rich";
11524
+ RTEPasteMode["PLAIN"] = "plain";
11495
11525
  RTEPasteMode["WORD"] = "word";
11496
11526
  })(RTEPasteMode || (RTEPasteMode = {}));
11497
11527
  /**
@@ -11543,185 +11573,63 @@ class AbstractPasteProcessingStrategy {
11543
11573
  get supportsImageProcessing() {
11544
11574
  return false;
11545
11575
  }
11546
- }
11547
-
11548
- const paste = {
11549
- icon: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.3.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path fill="currentColor" d="M80 96v16c0 17.7 14.3 32 32 32h60.8c16.6-28.7 47.6-48 83.2-48h62c-7.1-27.6-32.2-48-62-48H215.4C211.6 20.9 188.2 0 160 0s-51.6 20.9-55.4 48H64C28.7 48 0 76.7 0 112V384c0 35.3 28.7 64 64 64h96V400H64c-8.8 0-16-7.2-16-16V112c0-8.8 7.2-16 16-16H80zm64-40a16 16 0 1 1 32 0 16 16 0 1 1 -32 0zM256 464c-8.8 0-16-7.2-16-16V192c0-8.8 7.2-16 16-16H384v48c0 17.7 14.3 32 32 32h48V448c0 8.8-7.2 16-16 16H256zm192 48c35.3 0 64-28.7 64-64V227.9c0-12.7-5.1-24.9-14.1-33.9l-51.9-51.9c-9-9-21.2-14.1-33.9-14.1H256c-35.3 0-64 28.7-64 64V448c0 35.3 28.7 64 64 64H448z"/></svg>`,
11550
- };
11551
-
11552
- /**
11553
- * Renders and manages the paste format chooser UI.
11554
- */
11555
- class RTEPasteChooserUI {
11556
- constructor(hostRoot, callbacks, options = {}) {
11557
- this.hostRoot = hostRoot;
11558
- this.callbacks = callbacks;
11559
- this.options = options;
11560
- this.chooserEl = null;
11561
- this.dropdownEl = null;
11562
- this.triggerButtonEl = null;
11576
+ /** @returns {boolean} Whether this strategy consumes `text/plain` instead of `text/html` (default: false). */
11577
+ get consumesPlainText() {
11578
+ return false;
11563
11579
  }
11564
11580
  /**
11565
- * Opens the paste-mode chooser at the given position.
11581
+ * Owns the complete content policy for this paste mode. Subclasses that
11582
+ * only need a different source string should override {@link getSourceContent}
11583
+ * instead of re-implementing this method.
11566
11584
  *
11567
- * @param {PasteChooserPosition} position Viewport position for the chooser.
11585
+ * @param {PasteInput} input Complete clipboard payload.
11586
+ * @returns {PasteOutput} Complete downstream paste contract.
11568
11587
  */
11569
- open(position) {
11570
- this.destroy();
11571
- const doc = this.hostRoot.ownerDocument;
11572
- const chooser = doc.createElement('div');
11573
- chooser.setAttribute(RTEPasteChooserUI.CHOOSER_ATTR, 'true');
11574
- chooser.style.position = 'fixed';
11575
- chooser.style.zIndex = '1000';
11576
- chooser.style.left = `${position.left}px`;
11577
- chooser.style.top = `${position.top}px`;
11578
- const dropdownEl = this.createPasteChooserDropdown(doc, position.placement);
11579
- dropdownEl.placement = position.placement;
11580
- chooser.append(dropdownEl);
11581
- this.hostRoot.appendChild(chooser);
11582
- this.chooserEl = chooser;
11583
- this.dropdownEl = dropdownEl;
11584
- dropdownEl.addEventListener('vegaShow', () => {
11585
- if (this.triggerButtonEl) {
11586
- this.triggerButtonEl.selected = true;
11587
- }
11588
- });
11589
- dropdownEl.addEventListener('vegaHide', () => {
11590
- if (this.triggerButtonEl) {
11591
- this.triggerButtonEl.selected = false;
11592
- }
11593
- });
11588
+ transform(input) {
11589
+ const content = this.getSourceContent(input);
11590
+ return {
11591
+ html: this.process(content),
11592
+ text: this.consumesPlainText ? content : input.text,
11593
+ mode: this.type,
11594
+ markers: {},
11595
+ extractImages: this.supportsImageProcessing,
11596
+ imagesToExtract: this.supportsImageProcessing ? input.files : [],
11597
+ };
11594
11598
  }
11595
11599
  /**
11596
- * Removes the chooser from the DOM.
11600
+ * Resolves the source string passed to {@link process}. Defaults to
11601
+ * `input.text` when {@link consumesPlainText} is true, otherwise `input.html`.
11602
+ *
11603
+ * @param {PasteInput} input Complete clipboard payload.
11604
+ * @returns {string} Content to feed into `process`.
11597
11605
  */
11598
- destroy() {
11599
- var _a;
11600
- if (this.dropdownEl && typeof this.dropdownEl.hide === 'function') {
11601
- void this.dropdownEl.hide();
11602
- }
11603
- if ((_a = this.chooserEl) === null || _a === void 0 ? void 0 : _a.parentNode) {
11604
- this.chooserEl.parentNode.removeChild(this.chooserEl);
11605
- }
11606
- if (this.triggerButtonEl) {
11607
- this.triggerButtonEl.selected = false;
11608
- }
11609
- this.dropdownEl = null;
11610
- this.chooserEl = null;
11611
- this.triggerButtonEl = null;
11606
+ getSourceContent(input) {
11607
+ return this.consumesPlainText ? input.text : input.html;
11612
11608
  }
11609
+ }
11610
+
11611
+ /**
11612
+ * Default paste processing strategy that acts as a fallback when no other
11613
+ * strategy matches. This strategy always accepts the content and passes it
11614
+ * through unchanged — the normal RTE paste pipeline (DOMParser +
11615
+ * ElementToDtoStrategyProcessor) handles the rest.
11616
+ */
11617
+ class DefaultPasteProcessingStrategy extends AbstractPasteProcessingStrategy {
11613
11618
  /**
11614
- * Determines whether the given event path targets the chooser.
11619
+ * Always matches as the terminal fallback strategy.
11615
11620
  *
11616
- * @param {EventTarget[]} eventPath Composed path of an event.
11617
- * @returns {boolean} `true` when the path includes the chooser.
11621
+ * @param {string} html Raw clipboard HTML.
11622
+ * @returns {boolean} Always `true`.
11618
11623
  */
11619
- includesEventPath(eventPath) {
11620
- if (!this.chooserEl) {
11621
- return false;
11622
- }
11623
- const isDropdownContentClick = eventPath.some((target) => {
11624
- return 'tagName' in target && target.tagName === 'VEGA-DROPDOWN-CONTENT-BOX';
11625
- });
11626
- return eventPath.includes(this.chooserEl) || isDropdownContentClick;
11624
+ canHandle(html) {
11625
+ // Default strategy is the fallback — always returns true.
11626
+ return html !== undefined;
11627
11627
  }
11628
11628
  /**
11629
- * Builds the dropdown element with the rich text paste option.
11629
+ * Returns the original HTML unchanged.
11630
11630
  *
11631
- * @param {Document} doc Document used to create elements.
11632
- * @param {['bottom', 'top'] | ['top', 'bottom']} placement Preferred placement order.
11633
- * @returns {HTMLElement} Configured dropdown element.
11634
- */
11635
- createPasteChooserDropdown(doc, placement) {
11636
- const dropdownEl = doc.createElement('vega-dropdown');
11637
- dropdownEl.trigger = 'click';
11638
- dropdownEl.selectType = 'single';
11639
- dropdownEl.selectedSourceKey = 'rich';
11640
- dropdownEl.maxWidth = 220;
11641
- dropdownEl.alignment = 'start';
11642
- dropdownEl.itemDisplayRule = 'ellipsis';
11643
- dropdownEl.isScreenPosition = true;
11644
- const triggerButton = doc.createElement('vega-rich-text-editor-toolbar-button');
11645
- const arrowIcon = placement[0] === 'top' ? 'chevron-up' : 'chevron-down';
11646
- triggerButton.setAttribute(RTEPasteChooserUI.CHOOSER_TRIGGER_ATTR, 'true');
11647
- triggerButton.setAttribute('aria-label', VegaInternalTranslation.t('Paste options'));
11648
- triggerButton.setAttribute('arrow-icon', arrowIcon);
11649
- triggerButton.icon = 'rte-paste';
11650
- triggerButton.showArrowIcon = true;
11651
- triggerButton.selected = false;
11652
- this.triggerButtonEl = triggerButton;
11653
- const tooltipEl = doc.createElement('vega-tooltip');
11654
- tooltipEl.text = VegaInternalTranslation.t('Paste options');
11655
- tooltipEl.placement = ['bottom', 'top'];
11656
- tooltipEl.append(triggerButton);
11657
- dropdownEl.append(tooltipEl);
11658
- const itemsContainer = doc.createElement('div');
11659
- itemsContainer.setAttribute('slot', 'items');
11660
- const dropdownItems = [
11661
- this.createDropdownItem(doc, RTEPasteMode.RICH, VegaInternalTranslation.t('Use rich text'), RTEPasteChooserUI.CHOOSER_RICH_ATTR),
11662
- ];
11663
- if (this.options.showWordOption) {
11664
- dropdownItems.push(this.createDropdownItem(doc, RTEPasteMode.WORD, VegaInternalTranslation.t('Use Word'), RTEPasteChooserUI.CHOOSER_WORD_ATTR));
11665
- }
11666
- itemsContainer.append(...dropdownItems);
11667
- dropdownEl.append(itemsContainer);
11668
- dropdownEl.addEventListener('vegaDropdownClick', (event) => {
11669
- const mode = event.detail;
11670
- if (mode === RTEPasteMode.RICH || mode === RTEPasteMode.WORD) {
11671
- this.callbacks.onModeSelect(mode);
11672
- }
11673
- });
11674
- return dropdownEl;
11675
- }
11676
- /**
11677
- * Creates a single dropdown item element for a paste mode.
11678
- *
11679
- * @param {Document} doc Document used to create the element.
11680
- * @param {RTEPasteMode} key Paste mode key for the item.
11681
- * @param {string} label Display label for the item.
11682
- * @param {string} dataAttrName Data attribute marker for the item.
11683
- * @returns {HTMLVegaDropdownItemElement} Configured dropdown item element.
11684
- */
11685
- createDropdownItem(doc, key, label, dataAttrName) {
11686
- const itemEl = doc.createElement('vega-dropdown-item');
11687
- itemEl.itemKey = key;
11688
- itemEl.label = label;
11689
- itemEl.setAttribute(dataAttrName, 'true');
11690
- return itemEl;
11691
- }
11692
- }
11693
- (() => {
11694
- VegaInternalIconManager.register({
11695
- 'rte-paste': paste,
11696
- });
11697
- })();
11698
- RTEPasteChooserUI.CHOOSER_ATTR = 'data-rte-paste-chooser';
11699
- RTEPasteChooserUI.CHOOSER_RICH_ATTR = 'data-rte-paste-type-rich';
11700
- RTEPasteChooserUI.CHOOSER_WORD_ATTR = 'data-rte-paste-type-word';
11701
- RTEPasteChooserUI.CHOOSER_TRIGGER_ATTR = 'data-rte-paste-trigger';
11702
-
11703
- /**
11704
- * Default paste processing strategy that acts as a fallback when no other
11705
- * strategy matches. This strategy always accepts the content and passes it
11706
- * through unchanged — the normal RTE paste pipeline (DOMParser +
11707
- * ElementToDtoStrategyProcessor) handles the rest.
11708
- */
11709
- class DefaultPasteProcessingStrategy extends AbstractPasteProcessingStrategy {
11710
- /**
11711
- * Always matches as the terminal fallback strategy.
11712
- *
11713
- * @param {string} html Raw clipboard HTML.
11714
- * @returns {boolean} Always `true`.
11715
- */
11716
- canHandle(html) {
11717
- // Default strategy is the fallback — always returns true.
11718
- return html !== undefined;
11719
- }
11720
- /**
11721
- * Returns the original HTML unchanged.
11722
- *
11723
- * @param {string} html Raw clipboard HTML.
11724
- * @returns {string} Unchanged HTML.
11631
+ * @param {string} html Raw clipboard HTML.
11632
+ * @returns {string} Unchanged HTML.
11725
11633
  */
11726
11634
  process(html) {
11727
11635
  // Current default behavior: pass through unchanged
@@ -13717,6 +13625,76 @@ WordPasteProcessingStrategy.WORD_SIGNATURE_PATTERNS = [
13717
13625
  /<\/?o:p>/i,
13718
13626
  ];
13719
13627
 
13628
+ /** Converts plain-text clipboard to paragraph-per-line HTML. */
13629
+ class PlainPasteProcessingStrategy extends AbstractPasteProcessingStrategy {
13630
+ /** @returns {RTEPasteMode} Plain-text paste mode. */
13631
+ get type() {
13632
+ return RTEPasteMode.PLAIN;
13633
+ }
13634
+ /** @returns {boolean} Always `true`; consumes `text/plain` instead of `text/html`. */
13635
+ get consumesPlainText() {
13636
+ return true;
13637
+ }
13638
+ /** @returns {boolean} Always `false`; never auto-selected. */
13639
+ canHandle() {
13640
+ return false;
13641
+ }
13642
+ /**
13643
+ * Converts plain text to paragraph HTML; every `\n` starts a new paragraph.
13644
+ *
13645
+ * @param {string} text - Clipboard `text/plain` payload.
13646
+ * @param {boolean} decodeEncodedWhitespace - Decode markers emitted by HTML conversion.
13647
+ * @returns {string} Paragraph HTML.
13648
+ */
13649
+ process(text, decodeEncodedWhitespace = false) {
13650
+ if (!text) {
13651
+ return '';
13652
+ }
13653
+ const safeDocument = tryGetDocument();
13654
+ if (!safeDocument) {
13655
+ return '';
13656
+ }
13657
+ // Line splitting and boundary whitespace handling live in `toPlainPasteLines` so the
13658
+ // emitted HTML and the RTE nodes built by `InsertPasteHandler` share one conversion.
13659
+ return plainPasteLinesToHtml(toPlainPasteLines(text, decodeEncodedWhitespace));
13660
+ }
13661
+ /**
13662
+ * @param {PasteInput} input Complete clipboard payload.
13663
+ * @returns {PasteOutput} Plain HTML, canonical text, and whitespace marker contract.
13664
+ */
13665
+ transform(input) {
13666
+ const source = this.getPlainTextSource(input);
13667
+ return {
13668
+ html: this.process(source.text, source.hasEncodedWhitespace),
13669
+ text: source.text,
13670
+ mode: this.type,
13671
+ markers: source.hasEncodedWhitespace ? { [RTE_PRESERVED_WHITESPACE_DATA_TYPE]: 'true' } : {},
13672
+ extractImages: false,
13673
+ imagesToExtract: [],
13674
+ };
13675
+ }
13676
+ /**
13677
+ * @param {PasteInput} input Clipboard content used to derive canonical plain text.
13678
+ * @returns {PlainTextSource} Canonical text and whether it contains whitespace sentinels.
13679
+ */
13680
+ getPlainTextSource(input) {
13681
+ if (!input.html) {
13682
+ return { text: input.text || '', hasEncodedWhitespace: false };
13683
+ }
13684
+ const containsTable = htmlContainsTable(input.html);
13685
+ if (input.text && input.text.includes('\t') && containsTable) {
13686
+ return { text: input.text, hasEncodedWhitespace: false };
13687
+ }
13688
+ const derived = htmlToPlainText(input.html, {
13689
+ preserveBoundaryBlankLines: !containsTable,
13690
+ keepPreservedWhitespaceMarkers: true,
13691
+ });
13692
+ return derived
13693
+ ? { text: derived, hasEncodedWhitespace: true }
13694
+ : { text: input.text || '', hasEncodedWhitespace: false };
13695
+ }
13696
+ }
13697
+
13720
13698
  /**
13721
13699
  * Centralized selector for paste processing strategies.
13722
13700
  *
@@ -13729,10 +13707,27 @@ class PasteStrategySelector {
13729
13707
  constructor() {
13730
13708
  this.defaultStrategy = new DefaultPasteProcessingStrategy();
13731
13709
  this.strategies = [
13710
+ new PlainPasteProcessingStrategy(),
13732
13711
  new WordPasteProcessingStrategy(),
13733
13712
  this.defaultStrategy, // Fallback
13734
13713
  ];
13735
13714
  }
13715
+ /**
13716
+ * Selects the strategy that will process this paste.
13717
+ *
13718
+ * When `explicitMode` is provided and not `rich`, the strategy registered for that mode
13719
+ * is used. Otherwise the highest-priority strategy whose `canHandle` matches the HTML
13720
+ * wins, falling back to the default pass-through strategy.
13721
+ *
13722
+ * @param {PasteInput} input Captured clipboard payload used for auto-detection.
13723
+ * @param {RTEPasteMode} [explicitMode] Paste mode the user picked from the chooser.
13724
+ * @returns {AbstractPasteProcessingStrategy} Strategy to run for this paste.
13725
+ */
13726
+ select(input, explicitMode) {
13727
+ return explicitMode && explicitMode !== RTEPasteMode.RICH
13728
+ ? this.selectStrategyByType(explicitMode)
13729
+ : this.selectStrategy(input.html);
13730
+ }
13736
13731
  /**
13737
13732
  * Select the appropriate strategy for the given HTML content.
13738
13733
  * Returns the highest-priority strategy that can handle the content.
@@ -14219,271 +14214,79 @@ class PendingImageRegistry {
14219
14214
  */
14220
14215
  PendingImageRegistry.pendingImages = new Map();
14221
14216
 
14222
- /**
14223
- * Vega Rich Text Editor paste extension.
14224
- * Intercepts keyboard paste and allows users to choose paste mode.
14225
- */
14226
- class VegaRTEPasteExtension extends VegaRTEExtension {
14227
- constructor(options = {}) {
14228
- super();
14229
- this.editableEl = null;
14230
- this.contentHostEl = null;
14231
- this.chooserUI = null;
14232
- this.pendingPastePayload = null;
14233
- this.listenerDocument = null;
14234
- this.listenerWindow = null;
14235
- this.options = {};
14236
- this.strategySelector = new PasteStrategySelector();
14237
- this.clipboardFileContent = null;
14238
- this.imageParser = new PasteImageParser();
14239
- /** Owns pending pasted-image previews awaiting upload and their URL replacement. */
14240
- this.pendingImageRegistry = new PendingImageRegistry();
14241
- /**
14242
- * Handles a native paste event by capturing the clipboard payload and
14243
- * rendering the paste-mode chooser.
14244
- *
14245
- * @param {ClipboardEvent} event Native clipboard paste event.
14246
- */
14247
- this.handlePasteEvent = (event) => {
14248
- var _a, _b;
14249
- const clipboardData = event.clipboardData;
14250
- if (!clipboardData) {
14251
- return;
14252
- }
14253
- // HTML is sanitized via DOMParser and ElementToDtoStrategyProcessor pipeline
14254
- const html = clipboardData.getData('text/html') || '';
14255
- const text = clipboardData.getData('text/plain') || '';
14256
- // RTF must be read synchronously here: the paste event's DataTransfer is only
14257
- // readable during event dispatch, so reading it later (after the chooser) returns ''.
14258
- const rtf = clipboardData.getData('text/rtf') || '';
14259
- if (!html && !text) {
14260
- // Empty clipboard paste should not mutate editor content.
14261
- event.preventDefault();
14262
- event.stopPropagation();
14263
- return;
14264
- }
14265
- event.preventDefault();
14266
- event.stopPropagation();
14267
- const range = this.cloneCurrentSelectionRange();
14268
- const selectedNodes = ((_b = (_a = this.extensionContext) === null || _a === void 0 ? void 0 : _a.getSelectedNodes) === null || _b === void 0 ? void 0 : _b.call(_a)) || [];
14269
- this.pendingPastePayload = { html, text, range, selectedNodes: [...selectedNodes] };
14270
- this.clipboardFileContent = {
14271
- files: clipboardData.files ? Array.from(clipboardData.files) : [],
14272
- rtf,
14273
- };
14274
- this.renderPasteChooser(event);
14275
- };
14276
- /**
14277
- * Dismisses the chooser when a pointer interaction occurs outside of it.
14278
- *
14279
- * @param {Event} event Pointer event captured on the document.
14280
- */
14281
- this.handleOutsidePointerDown = (event) => {
14282
- if (!this.chooserUI) {
14283
- return;
14284
- }
14285
- const eventPath = typeof event.composedPath === 'function' ? event.composedPath() : [];
14286
- if (this.chooserUI.includesEventPath(eventPath)) {
14287
- return;
14288
- }
14289
- this.clearPasteChooser();
14290
- };
14291
- /**
14292
- * Dismisses the chooser when the Escape key is pressed.
14293
- *
14294
- * @param {KeyboardEvent} event Keyboard event captured on the document.
14295
- */
14296
- this.handleOutsideKeyDown = (event) => {
14297
- if (event.key === 'Escape') {
14298
- this.clearPasteChooser();
14299
- }
14300
- };
14301
- /**
14302
- * Dismisses the chooser when any relevant scroll container scrolls.
14303
- */
14304
- this.handleOutsideScroll = () => {
14305
- this.clearPasteChooser();
14306
- };
14307
- this.options = options;
14308
- }
14309
- /** @inheritDoc */
14310
- initialExtensionAfterLoad(context) {
14311
- super.initialExtensionAfterLoad(context);
14312
- this.hostEl = context.host;
14313
- this.attachPasteListener();
14314
- }
14315
- /** @inheritDoc */
14316
- destroyExtension() {
14317
- this.detachPasteListener();
14318
- this.clearPasteChooser();
14319
- this.pendingImageRegistry.discardUnsentPreviews();
14217
+ /** Computes paste chooser placement from the paste pointer or saved caret range. */
14218
+ class ChooserPositioner {
14219
+ constructor(getHostElement, getSelectionRange) {
14220
+ this.getHostElement = getHostElement;
14221
+ this.getSelectionRange = getSelectionRange;
14320
14222
  }
14321
14223
  /**
14322
- * Attaches the paste listener to the editable element.
14224
+ * @param {ClipboardEvent} event Originating paste event.
14225
+ * @returns {ChooserPosition} Position in viewport coordinates.
14323
14226
  */
14324
- attachPasteListener() {
14325
- const { editableEl, contentHostEl, } = this.getEditorElements();
14326
- this.editableEl = editableEl;
14327
- this.contentHostEl = contentHostEl;
14328
- if (this.editableEl) {
14329
- this.editableEl.addEventListener('paste', this.handlePasteEvent);
14227
+ compute(event) {
14228
+ var _a, _b, _c;
14229
+ const hostEl = this.getHostElement();
14230
+ if (!hostEl) {
14231
+ return { left: 0, top: 0, placement: ['bottom', 'top'] };
14232
+ }
14233
+ const hostRect = hostEl.getBoundingClientRect();
14234
+ const viewportHeight = (_b = (_a = hostEl.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.innerHeight) !== null && _b !== void 0 ? _b : window.innerHeight;
14235
+ const pointerEvent = event;
14236
+ const hasPointer = typeof pointerEvent.clientX === 'number' &&
14237
+ pointerEvent.clientX > 0 &&
14238
+ typeof pointerEvent.clientY === 'number' &&
14239
+ pointerEvent.clientY > 0;
14240
+ const caretRect = hasPointer ? null : this.getCaretRect();
14241
+ const CHOOSER_GAP_PX = 8;
14242
+ const CHOOSER_MIN_MARGIN_PX = 12;
14243
+ const CHOOSER_WIDTH_PX = 220;
14244
+ const CHOOSER_FALLBACK_OFFSET_PX = 40;
14245
+ const CHOOSER_MIN_VISIBLE_BELOW_SPACE_PX = 88;
14246
+ const baseLeft = hasPointer
14247
+ ? pointerEvent.clientX
14248
+ : (_c = caretRect === null || caretRect === void 0 ? void 0 : caretRect.left) !== null && _c !== void 0 ? _c : hostRect.left + CHOOSER_MIN_MARGIN_PX;
14249
+ const baseTop = hasPointer
14250
+ ? pointerEvent.clientY
14251
+ : caretRect
14252
+ ? caretRect.bottom
14253
+ : hostRect.top + CHOOSER_FALLBACK_OFFSET_PX;
14254
+ const maxLeft = Math.max(hostRect.left + CHOOSER_MIN_MARGIN_PX, hostRect.right - CHOOSER_WIDTH_PX);
14255
+ const left = Math.min(Math.max(baseLeft, hostRect.left + CHOOSER_MIN_MARGIN_PX), maxLeft);
14256
+ const top = Math.max(baseTop + CHOOSER_GAP_PX, hostRect.top + CHOOSER_MIN_MARGIN_PX);
14257
+ const availableBelow = viewportHeight - top - CHOOSER_MIN_MARGIN_PX;
14258
+ const availableAbove = top - CHOOSER_MIN_MARGIN_PX;
14259
+ const placement = availableBelow >= CHOOSER_MIN_VISIBLE_BELOW_SPACE_PX || availableBelow >= availableAbove
14260
+ ? ['bottom', 'top']
14261
+ : ['top', 'bottom'];
14262
+ return { left, top, placement };
14263
+ }
14264
+ /** @returns {DOMRect | null} Best available caret rectangle. */
14265
+ getCaretRect() {
14266
+ const range = this.getSelectionRange();
14267
+ if (!range) {
14268
+ return null;
14269
+ }
14270
+ const rect = range.getBoundingClientRect();
14271
+ if (!this.isUnavailableRect(rect)) {
14272
+ return rect;
14273
+ }
14274
+ const domRectList = range.getClientRects();
14275
+ if (domRectList.length > 0) {
14276
+ return domRectList[0];
14330
14277
  }
14278
+ return this.getRangeContainerRect(range);
14331
14279
  }
14332
14280
  /**
14333
- * Detaches the paste listener from the editable element.
14281
+ * @param {DOMRect} rect Rectangle to inspect.
14282
+ * @returns {boolean} Whether the rectangle has no usable position or dimensions.
14334
14283
  */
14335
- detachPasteListener() {
14336
- if (this.editableEl) {
14337
- this.editableEl.removeEventListener('paste', this.handlePasteEvent);
14338
- }
14339
- this.editableEl = null;
14340
- this.contentHostEl = null;
14284
+ isUnavailableRect(rect) {
14285
+ return rect.width === 0 && rect.height === 0 && rect.left === 0 && rect.top === 0;
14341
14286
  }
14342
14287
  /**
14343
- * Resolves the content host and editable element from the host shadow tree.
14344
- *
14345
- * @returns {EditorElements} Editor elements.
14346
- */
14347
- getEditorElements() {
14348
- var _a, _b, _c, _d, _e;
14349
- const contentHostEl = (_c = (_b = (_a = this.hostEl) === null || _a === void 0 ? void 0 : _a.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelector('vega-rich-text-content')) !== null && _c !== void 0 ? _c : null;
14350
- const editableEl = (_e = (_d = contentHostEl === null || contentHostEl === void 0 ? void 0 : contentHostEl.shadowRoot) === null || _d === void 0 ? void 0 : _d.querySelector('.rich-text-content')) !== null && _e !== void 0 ? _e : null;
14351
- return { editableEl, contentHostEl };
14352
- }
14353
- /**
14354
- * Resolves the editable content element from the host shadow tree.
14355
- *
14356
- * @returns {HTMLDivElement | null} Editable element or `null` when unavailable.
14357
- */
14358
- getEditableElement() {
14359
- const { editableEl } = this.getEditorElements();
14360
- return editableEl;
14361
- }
14362
- /**
14363
- * Clones the current selection range so it can be restored after the user
14364
- * chooses a paste mode.
14365
- *
14366
- * @returns {Range | null} Cloned range or `null` when there is no selection.
14367
- */
14368
- cloneCurrentSelectionRange() {
14369
- var _a;
14370
- const selection = (_a = this.extensionContext) === null || _a === void 0 ? void 0 : _a.getSelection();
14371
- if (selection && selection.rangeCount > 0) {
14372
- return selection.getRangeAt(0).cloneRange();
14373
- }
14374
- return null;
14375
- }
14376
- /**
14377
- * Renders the paste-mode chooser and wires up dismissal listeners.
14378
- *
14379
- * @param {ClipboardEvent} pasteEvent Originating paste event used for positioning.
14380
- */
14381
- renderPasteChooser(pasteEvent) {
14382
- var _a, _b, _c;
14383
- const hostRoot = (_b = (_a = this.hostEl) === null || _a === void 0 ? void 0 : _a.shadowRoot) !== null && _b !== void 0 ? _b : null;
14384
- if (!hostRoot) {
14385
- return;
14386
- }
14387
- this.clearPasteChooser(false);
14388
- const position = this.computeChooserPosition(pasteEvent);
14389
- this.chooserUI = new RTEPasteChooserUI(hostRoot, {
14390
- // eslint-disable-next-line jsdoc/require-jsdoc
14391
- onModeSelect: (mode) => {
14392
- this.applyPasteMode(mode);
14393
- },
14394
- }, {
14395
- showWordOption: ((_c = this.options) === null || _c === void 0 ? void 0 : _c.enableWordPaste) === true,
14396
- });
14397
- this.chooserUI.open(position);
14398
- this.listenerDocument = this.hostEl.ownerDocument;
14399
- this.listenerWindow = this.listenerDocument.defaultView;
14400
- this.listenerDocument.addEventListener('mousedown', this.handleOutsidePointerDown, true);
14401
- this.listenerDocument.addEventListener('keydown', this.handleOutsideKeyDown, true);
14402
- this.listenerDocument.addEventListener('scroll', this.handleOutsideScroll, true);
14403
- if (this.listenerWindow) {
14404
- this.listenerWindow.addEventListener('scroll', this.handleOutsideScroll, true);
14405
- }
14406
- if (this.contentHostEl) {
14407
- this.contentHostEl.addEventListener('scroll', this.handleOutsideScroll);
14408
- }
14409
- }
14410
- /**
14411
- * Computes the on-screen position for the chooser based on pointer or caret.
14412
- *
14413
- * @param {ClipboardEvent} event Originating paste event.
14414
- * @returns {ChooserPosition} Position in viewport coordinates.
14415
- */
14416
- computeChooserPosition(event) {
14417
- var _a, _b, _c;
14418
- const hostRect = this.hostEl.getBoundingClientRect();
14419
- const viewportHeight = (_b = (_a = this.hostEl.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.innerHeight) !== null && _b !== void 0 ? _b : window.innerHeight;
14420
- const pointerEvent = event;
14421
- const hasPointer = typeof pointerEvent.clientX === 'number' &&
14422
- pointerEvent.clientX > 0 &&
14423
- typeof pointerEvent.clientY === 'number' &&
14424
- pointerEvent.clientY > 0;
14425
- // For keyboard-initiated paste (Command/Control+V) clientX/Y are 0, so anchor
14426
- // the chooser to the current caret instead of a fixed host-relative spot.
14427
- const caretRect = hasPointer ? null : this.getCaretRect();
14428
- const CHOOSER_GAP_PX = 8;
14429
- const CHOOSER_MIN_MARGIN_PX = 12;
14430
- const CHOOSER_WIDTH_PX = 220;
14431
- const CHOOSER_FALLBACK_OFFSET_PX = 40;
14432
- const CHOOSER_MIN_VISIBLE_BELOW_SPACE_PX = 88;
14433
- const baseLeft = hasPointer
14434
- ? pointerEvent.clientX
14435
- : (_c = caretRect === null || caretRect === void 0 ? void 0 : caretRect.left) !== null && _c !== void 0 ? _c : hostRect.left + CHOOSER_MIN_MARGIN_PX;
14436
- const baseTop = hasPointer
14437
- ? pointerEvent.clientY
14438
- : caretRect
14439
- ? caretRect.bottom
14440
- : hostRect.top + CHOOSER_FALLBACK_OFFSET_PX;
14441
- const maxLeft = Math.max(hostRect.left + CHOOSER_MIN_MARGIN_PX, hostRect.right - CHOOSER_WIDTH_PX);
14442
- const left = Math.min(Math.max(baseLeft, hostRect.left + CHOOSER_MIN_MARGIN_PX), maxLeft);
14443
- const top = Math.max(baseTop + CHOOSER_GAP_PX, hostRect.top + CHOOSER_MIN_MARGIN_PX);
14444
- const availableBelow = viewportHeight - top - CHOOSER_MIN_MARGIN_PX;
14445
- const availableAbove = top - CHOOSER_MIN_MARGIN_PX;
14446
- const placement = availableBelow >= CHOOSER_MIN_VISIBLE_BELOW_SPACE_PX || availableBelow >= availableAbove
14447
- ? ['bottom', 'top']
14448
- : ['top', 'bottom'];
14449
- return { left, top, placement };
14450
- }
14451
- /**
14452
- * Resolves the bounding rect of the pending caret position.
14453
- *
14454
- * @returns {DOMRect | null} Caret rect or `null` when it cannot be determined.
14455
- */
14456
- getCaretRect() {
14457
- var _a, _b;
14458
- const range = (_b = (_a = this.pendingPastePayload) === null || _a === void 0 ? void 0 : _a.range) !== null && _b !== void 0 ? _b : this.cloneCurrentSelectionRange();
14459
- if (!range) {
14460
- return null;
14461
- }
14462
- const rect = range.getBoundingClientRect();
14463
- if (this.isUnavailableRect(rect)) {
14464
- // eslint-disable-next-line spellcheck/spell-checker
14465
- const domRectList = range.getClientRects();
14466
- if (domRectList.length > 0) {
14467
- return domRectList[0];
14468
- }
14469
- return this.getRangeContainerRect(range);
14470
- }
14471
- return rect;
14472
- }
14473
- /**
14474
- * Returns whether the browser could not resolve a meaningful caret rectangle.
14475
- *
14476
- * @param {DOMRect} rect Candidate caret rect.
14477
- * @returns {boolean} Whether the rect is unusable.
14478
- */
14479
- isUnavailableRect(rect) {
14480
- return rect.width === 0 && rect.height === 0 && rect.left === 0 && rect.top === 0;
14481
- }
14482
- /**
14483
- * Falls back to the range container or neighbor child node bounds.
14484
- *
14485
- * @param {Range} range Caret/selection range.
14486
- * @returns {DOMRect | null} Best-effort caret anchor rectangle.
14288
+ * @param {Range} range Selection range whose container should be measured.
14289
+ * @returns {DOMRect | null} Best available rectangle for the range container.
14487
14290
  */
14488
14291
  getRangeContainerRect(range) {
14489
14292
  var _a, _b, _c, _d, _e, _f;
@@ -14500,10 +14303,8 @@ class VegaRTEPasteExtension extends VegaRTEExtension {
14500
14303
  return (_f = this.getNodeRect(containerNode)) !== null && _f !== void 0 ? _f : this.getNodeRect(containerNode.parentNode);
14501
14304
  }
14502
14305
  /**
14503
- * Returns an element-backed rectangle from a DOM node.
14504
- *
14505
- * @param {Node | null} node Candidate node.
14506
- * @returns {DOMRect | null} Node rectangle when resolvable.
14306
+ * @param {Node | null} node DOM node to measure.
14307
+ * @returns {DOMRect | null} Element-backed rectangle for the node.
14507
14308
  */
14508
14309
  getNodeRect(node) {
14509
14310
  var _a, _b;
@@ -14519,73 +14320,145 @@ class VegaRTEPasteExtension extends VegaRTEExtension {
14519
14320
  }
14520
14321
  return null;
14521
14322
  }
14323
+ }
14324
+
14325
+ /** Extracts local image previews from strategy output. */
14326
+ class ImageExtractor {
14327
+ constructor(parser = new PasteImageParser()) {
14328
+ this.parser = parser;
14329
+ }
14522
14330
  /**
14523
- * Applies the chosen paste mode by dispatching a synthetic paste input event.
14524
- *
14525
- * `rich` keeps auto-detection enabled; any other explicit mode forces the
14526
- * corresponding registered strategy.
14527
- *
14528
- * @param {RTEPasteMode} mode Selected paste mode.
14331
+ * @param {string} html HTML content containing local image references.
14332
+ * @param {File[]} files Clipboard image files.
14333
+ * @param {string} rtf Rich text clipboard content used to resolve images.
14334
+ * @returns {ParseLocalImagesResult} HTML and extracted local image previews.
14529
14335
  */
14530
- applyPasteMode(mode) {
14531
- var _a;
14532
- if (!this.pendingPastePayload) {
14533
- this.clearPasteChooser();
14534
- return;
14336
+ extract(html, files, rtf) {
14337
+ const clipboardFileContent = { files, rtf };
14338
+ return this.parser.parseLocalImages(html, clipboardFileContent);
14339
+ }
14340
+ }
14341
+
14342
+ /** Selects and executes one paste strategy, then performs declared post-processing. */
14343
+ class PasteProcessingPipeline {
14344
+ constructor(selector, imageExtractor, pendingImageRegistry) {
14345
+ this.selector = selector;
14346
+ this.imageExtractor = imageExtractor;
14347
+ this.pendingImageRegistry = pendingImageRegistry;
14348
+ }
14349
+ /**
14350
+ * @param {PendingPastePayload} payload Captured clipboard and selection data.
14351
+ * @param {RTEPasteMode} explicitMode Paste mode selected by the user.
14352
+ * @returns {PasteOutput} Processed paste output and image extraction metadata.
14353
+ */
14354
+ process(payload, explicitMode) {
14355
+ const input = {
14356
+ html: payload.html,
14357
+ text: payload.text,
14358
+ files: payload.files,
14359
+ rtf: payload.rtf,
14360
+ };
14361
+ const output = this.selector.select(input, explicitMode).transform(input);
14362
+ if (!output.extractImages) {
14363
+ return output;
14535
14364
  }
14536
- const editableEl = (_a = this.editableEl) !== null && _a !== void 0 ? _a : this.getEditableElement();
14537
- if (!editableEl) {
14538
- this.clearPasteChooser();
14539
- return;
14365
+ const extraction = this.imageExtractor.extract(output.html, output.imagesToExtract, input.rtf);
14366
+ if (extraction.previews.length > 0) {
14367
+ this.pendingImageRegistry.register(extraction.previews);
14540
14368
  }
14541
- editableEl.focus();
14542
- this.restoreSelectionRange(this.pendingPastePayload.range);
14543
- this.restoreSelectionControllerState(this.pendingPastePayload);
14544
- const strategy = mode === RTEPasteMode.RICH
14545
- ? this.strategySelector.selectStrategy(this.pendingPastePayload.html)
14546
- : this.strategySelector.selectStrategyByType(mode);
14547
- let processedHtml = strategy.process(this.pendingPastePayload.html);
14548
- // If the strategy supports image processing and there is clipboard file content, parse local images.
14549
- if (strategy.supportsImageProcessing && this.clipboardFileContent) {
14550
- processedHtml = this.parseLocalImages(processedHtml, this.clipboardFileContent);
14551
- }
14552
- this.clipboardFileContent = null;
14553
- const dataTransfer = this.createDataTransfer(processedHtml, this.pendingPastePayload.text, strategy.type);
14554
- this.dispatchBeforeInputPaste(editableEl, dataTransfer);
14555
- this.clearPasteChooser();
14556
- this.emitLocalImageInsertedEvent();
14369
+ return Object.assign(Object.assign({}, output), { html: extraction.html });
14557
14370
  }
14371
+ }
14372
+
14373
+ /** Builds the DataTransfer contract consumed by InsertPasteHandler. */
14374
+ class PasteDataTransferBuilder {
14558
14375
  /**
14559
- * Parses local images from the HTML and emits events for further processing.
14560
- *
14561
- * @param {string} html HTML content to parse.
14562
- * @param {ClipboardFileContent} clipboardFileContent Clipboard file content for image extraction.
14563
- * @returns {string} Processed HTML with local image references replaced.
14376
+ * @param {PasteOutput} output Processed paste output to serialize.
14377
+ * @returns {DataTransfer} Data transfer payload consumed by the paste handler.
14564
14378
  */
14565
- parseLocalImages(html, clipboardFileContent) {
14566
- const { html: result, previews } = this.imageParser.parseLocalImages(html, clipboardFileContent);
14567
- if (previews.length > 0) {
14568
- this.pendingImageRegistry.register(previews);
14379
+ build(output) {
14380
+ // Reserved keys always win over `markers` so a strategy cannot clobber the base contract.
14381
+ const safeMarkers = Object.assign({}, output.markers);
14382
+ PasteDataTransferBuilder.RESERVED_KEYS.forEach((key) => delete safeMarkers[key]);
14383
+ const values = Object.assign(Object.assign({}, safeMarkers), { 'text/html': output.html, 'text/plain': output.text, [RTE_PASTE_MODE_DATA_TYPE]: output.mode });
14384
+ if (typeof DataTransfer !== 'undefined') {
14385
+ const dataTransfer = new DataTransfer();
14386
+ Object.keys(values).forEach((type) => {
14387
+ const value = values[type];
14388
+ if (value) {
14389
+ dataTransfer.setData(type, value);
14390
+ }
14391
+ });
14392
+ return dataTransfer;
14569
14393
  }
14570
- return result;
14394
+ return {
14395
+ /**
14396
+ * @param {string} type Clipboard data type to read.
14397
+ * @returns {string} Clipboard value for the requested type.
14398
+ */
14399
+ getData: (type) => { var _a; return (_a = values[type]) !== null && _a !== void 0 ? _a : ''; },
14400
+ };
14571
14401
  }
14402
+ }
14403
+ PasteDataTransferBuilder.RESERVED_KEYS = [
14404
+ 'text/html',
14405
+ 'text/plain',
14406
+ RTE_PASTE_MODE_DATA_TYPE,
14407
+ ];
14408
+
14409
+ /** Dispatches processed paste data through the editor's existing beforeinput pipeline. */
14410
+ class PasteDispatcher {
14572
14411
  /**
14573
- * Emits the `imageInsertedCallback` for any pending previews, allowing the
14574
- * consumer to upload them and resolve their URLs.
14412
+ * @param {HTMLDivElement} editableEl Editable content element receiving the event.
14413
+ * @param {DataTransfer} dataTransfer Processed clipboard payload.
14575
14414
  */
14576
- emitLocalImageInsertedEvent() {
14577
- if (this.pendingImageRegistry.hasPendingNotifications()) {
14578
- this.pendingImageRegistry.notifyInserted(this.options.imageInsertedCallback, () => { var _a; return (_a = this.editableEl) !== null && _a !== void 0 ? _a : this.getEditableElement(); }, (imageElement) => this.getDTOEntityByDom(imageElement));
14415
+ dispatch(editableEl, dataTransfer) {
14416
+ const beforeInputEvent = new CustomEvent('beforeinput', {
14417
+ bubbles: true,
14418
+ cancelable: true,
14419
+ });
14420
+ try {
14421
+ Object.defineProperties(beforeInputEvent, {
14422
+ inputType: { value: 'insertFromPaste', configurable: true },
14423
+ dataTransfer: { value: dataTransfer, configurable: true },
14424
+ });
14425
+ }
14426
+ catch (_a) {
14427
+ Object.assign(beforeInputEvent, { inputType: 'insertFromPaste', dataTransfer });
14579
14428
  }
14429
+ editableEl.dispatchEvent(beforeInputEvent);
14430
+ }
14431
+ }
14432
+
14433
+ /** Captures and restores native and editor selection state around chooser interaction. */
14434
+ class SelectionSnapshotService {
14435
+ constructor(getContext) {
14436
+ this.getContext = getContext;
14580
14437
  }
14581
14438
  /**
14582
- * Restores SelectionController state from the captured selection so synthetic
14583
- * beforeinput paste can replace the selected content instead of appending.
14584
- *
14585
- * @param {PendingPastePayload} payload Pending paste payload.
14439
+ * @returns {SelectionSnapshot} Captured native and editor selection state.
14440
+ */
14441
+ capture() {
14442
+ var _a;
14443
+ const context = this.getContext();
14444
+ const selection = context === null || context === void 0 ? void 0 : context.getSelection();
14445
+ const range = selection && selection.rangeCount > 0 ? selection.getRangeAt(0).cloneRange() : null;
14446
+ const selectedNodes = ((_a = context === null || context === void 0 ? void 0 : context.getSelectedNodes) === null || _a === void 0 ? void 0 : _a.call(context)) || [];
14447
+ return { range, selectedNodes: [...selectedNodes] };
14448
+ }
14449
+ /**
14450
+ * @param {PendingPastePayload} payload Paste payload containing captured selection state.
14451
+ */
14452
+ restore(payload) {
14453
+ this.restoreRange(payload.range);
14454
+ this.restoreControllerState(payload);
14455
+ }
14456
+ /**
14457
+ * @param {PendingPastePayload} payload Paste payload containing editor selection state.
14586
14458
  */
14587
- restoreSelectionControllerState(payload) {
14588
- if (!payload.range || !this.extensionContext) {
14459
+ restoreControllerState(payload) {
14460
+ const context = this.getContext();
14461
+ if (!payload.range || !context) {
14589
14462
  return;
14590
14463
  }
14591
14464
  const rangeOptions = {
@@ -14594,121 +14467,492 @@ class VegaRTEPasteExtension extends VegaRTEExtension {
14594
14467
  startOffset: payload.range.startOffset,
14595
14468
  endOffset: payload.range.endOffset,
14596
14469
  };
14597
- this.extensionContext.setSelectedNodes(payload.selectedNodes || [], rangeOptions);
14470
+ context.setSelectedNodes(payload.selectedNodes || [], rangeOptions);
14598
14471
  }
14599
14472
  /**
14600
- * Restores a previously cloned selection range.
14601
- *
14602
- * @param {Range | null} range Range to restore.
14473
+ * @param {Range | null} range Native selection range to restore.
14603
14474
  */
14604
- restoreSelectionRange(range) {
14475
+ restoreRange(range) {
14605
14476
  var _a;
14606
14477
  if (!range) {
14607
14478
  return;
14608
14479
  }
14609
- const selection = (_a = this.extensionContext) === null || _a === void 0 ? void 0 : _a.getSelection();
14480
+ const selection = (_a = this.getContext()) === null || _a === void 0 ? void 0 : _a.getSelection();
14610
14481
  if (selection) {
14611
14482
  selection.removeAllRanges();
14612
14483
  selection.addRange(range);
14613
14484
  }
14614
14485
  }
14486
+ }
14487
+
14488
+ /** Owns the native paste listener and synchronous clipboard payload capture. */
14489
+ class PasteEventInterceptor {
14490
+ constructor(selectionSnapshotService, onPasteCaptured) {
14491
+ this.selectionSnapshotService = selectionSnapshotService;
14492
+ this.onPasteCaptured = onPasteCaptured;
14493
+ this.editableEl = null;
14494
+ /**
14495
+ * @param {ClipboardEvent} event Native paste event to capture.
14496
+ */
14497
+ this.handlePasteEvent = (event) => {
14498
+ const clipboardData = event.clipboardData;
14499
+ if (!clipboardData) {
14500
+ return;
14501
+ }
14502
+ const html = clipboardData.getData('text/html') || '';
14503
+ const text = clipboardData.getData('text/plain') || '';
14504
+ const rtf = clipboardData.getData('text/rtf') || '';
14505
+ if (!html && !text) {
14506
+ event.preventDefault();
14507
+ event.stopPropagation();
14508
+ return;
14509
+ }
14510
+ event.preventDefault();
14511
+ event.stopPropagation();
14512
+ const snapshot = this.selectionSnapshotService.capture();
14513
+ const files = clipboardData.files ? Array.from(clipboardData.files) : [];
14514
+ this.onPasteCaptured({ html, text, range: snapshot.range, selectedNodes: snapshot.selectedNodes, files, rtf }, event);
14515
+ };
14516
+ }
14615
14517
  /**
14616
- * Dispatches a synthetic `beforeinput` paste event into the editor pipeline.
14617
- *
14618
- * @param {HTMLDivElement} editableEl Editable content element.
14619
- * @param {DataTransfer} dataTransfer Clipboard payload for the paste.
14518
+ * @param {HTMLDivElement | null} editableEl Editable content element to observe.
14620
14519
  */
14621
- dispatchBeforeInputPaste(editableEl, dataTransfer) {
14622
- // This synthetic beforeinput event intentionally reuses the existing
14623
- // UserInputController -> insertFromPaste -> InsertPasteHandler pipeline.
14624
- const beforeInputEvent = new CustomEvent('beforeinput', {
14625
- bubbles: true,
14626
- cancelable: true,
14627
- });
14628
- try {
14629
- Object.defineProperties(beforeInputEvent, {
14630
- inputType: {
14631
- value: 'insertFromPaste',
14632
- configurable: true,
14633
- },
14634
- dataTransfer: {
14635
- value: dataTransfer,
14636
- configurable: true,
14637
- },
14638
- });
14639
- }
14640
- catch (_a) {
14641
- Object.assign(beforeInputEvent, {
14642
- inputType: 'insertFromPaste',
14643
- dataTransfer,
14644
- });
14645
- }
14646
- editableEl.dispatchEvent(beforeInputEvent);
14520
+ attach(editableEl) {
14521
+ var _a;
14522
+ this.detach();
14523
+ this.editableEl = editableEl;
14524
+ (_a = this.editableEl) === null || _a === void 0 ? void 0 : _a.addEventListener('paste', this.handlePasteEvent);
14647
14525
  }
14648
14526
  /**
14649
- * Builds a `DataTransfer` payload carrying the paste content and mode marker.
14650
- *
14651
- * @param {string} html HTML clipboard content.
14652
- * @param {string} text Plain text clipboard content.
14653
- * @param {RTEPasteMode} [mode] Selected paste mode marker.
14654
- * @returns {DataTransfer} Populated data transfer payload.
14527
+ * Detaches the current native paste listener.
14655
14528
  */
14656
- createDataTransfer(html, text, mode) {
14657
- if (typeof DataTransfer !== 'undefined') {
14658
- const dataTransfer = new DataTransfer();
14659
- if (html) {
14660
- dataTransfer.setData('text/html', html);
14661
- }
14662
- if (text) {
14663
- dataTransfer.setData('text/plain', text);
14664
- }
14665
- if (mode) {
14666
- dataTransfer.setData(RTE_PASTE_MODE_DATA_TYPE, mode);
14667
- }
14668
- return dataTransfer;
14669
- }
14670
- return {
14671
- // eslint-disable-next-line jsdoc/require-jsdoc
14672
- getData: (type) => {
14673
- if (type === 'text/html') {
14674
- return html;
14675
- }
14676
- if (type === 'text/plain') {
14677
- return text;
14678
- }
14679
- if (type === RTE_PASTE_MODE_DATA_TYPE) {
14680
- return mode !== null && mode !== void 0 ? mode : '';
14681
- }
14682
- return '';
14683
- },
14684
- };
14529
+ detach() {
14530
+ var _a;
14531
+ (_a = this.editableEl) === null || _a === void 0 ? void 0 : _a.removeEventListener('paste', this.handlePasteEvent);
14532
+ this.editableEl = null;
14533
+ }
14534
+ }
14535
+
14536
+ const paste = {
14537
+ icon: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.3.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path fill="currentColor" d="M80 96v16c0 17.7 14.3 32 32 32h60.8c16.6-28.7 47.6-48 83.2-48h62c-7.1-27.6-32.2-48-62-48H215.4C211.6 20.9 188.2 0 160 0s-51.6 20.9-55.4 48H64C28.7 48 0 76.7 0 112V384c0 35.3 28.7 64 64 64h96V400H64c-8.8 0-16-7.2-16-16V112c0-8.8 7.2-16 16-16H80zm64-40a16 16 0 1 1 32 0 16 16 0 1 1 -32 0zM256 464c-8.8 0-16-7.2-16-16V192c0-8.8 7.2-16 16-16H384v48c0 17.7 14.3 32 32 32h48V448c0 8.8-7.2 16-16 16H256zm192 48c35.3 0 64-28.7 64-64V227.9c0-12.7-5.1-24.9-14.1-33.9l-51.9-51.9c-9-9-21.2-14.1-33.9-14.1H256c-35.3 0-64 28.7-64 64V448c0 35.3 28.7 64 64 64H448z"/></svg>`,
14538
+ };
14539
+
14540
+ /**
14541
+ * Renders and manages the paste format chooser UI.
14542
+ */
14543
+ class RTEPasteChooserUI {
14544
+ constructor(hostRoot, callbacks, options = {}) {
14545
+ this.hostRoot = hostRoot;
14546
+ this.callbacks = callbacks;
14547
+ this.options = options;
14548
+ this.chooserEl = null;
14549
+ this.dropdownEl = null;
14550
+ this.triggerButtonEl = null;
14685
14551
  }
14686
14552
  /**
14687
- * Tears down the chooser UI and removes dismissal listeners.
14553
+ * Opens the paste-mode chooser at the given position.
14688
14554
  *
14689
- * @param {boolean} [clearPayload] Whether to also clear the pending payload.
14555
+ * @param {PasteChooserPosition} position Viewport position for the chooser.
14690
14556
  */
14691
- clearPasteChooser(clearPayload = true) {
14692
- if (this.contentHostEl) {
14693
- this.contentHostEl.removeEventListener('scroll', this.handleOutsideScroll);
14557
+ open(position) {
14558
+ this.destroy();
14559
+ const doc = this.hostRoot.ownerDocument;
14560
+ const chooser = doc.createElement('div');
14561
+ chooser.setAttribute(RTEPasteChooserUI.CHOOSER_ATTR, 'true');
14562
+ chooser.style.position = 'fixed';
14563
+ chooser.style.zIndex = '1000';
14564
+ chooser.style.left = `${position.left}px`;
14565
+ chooser.style.top = `${position.top}px`;
14566
+ const dropdownEl = this.createPasteChooserDropdown(doc, position.placement);
14567
+ dropdownEl.placement = position.placement;
14568
+ chooser.append(dropdownEl);
14569
+ this.hostRoot.appendChild(chooser);
14570
+ this.chooserEl = chooser;
14571
+ this.dropdownEl = dropdownEl;
14572
+ dropdownEl.addEventListener('vegaShow', () => {
14573
+ if (this.triggerButtonEl) {
14574
+ this.triggerButtonEl.selected = true;
14575
+ }
14576
+ });
14577
+ dropdownEl.addEventListener('vegaHide', () => {
14578
+ if (this.triggerButtonEl) {
14579
+ this.triggerButtonEl.selected = false;
14580
+ }
14581
+ });
14582
+ }
14583
+ /**
14584
+ * Removes the chooser from the DOM.
14585
+ */
14586
+ destroy() {
14587
+ var _a;
14588
+ if (this.dropdownEl && typeof this.dropdownEl.hide === 'function') {
14589
+ void this.dropdownEl.hide();
14590
+ }
14591
+ if ((_a = this.chooserEl) === null || _a === void 0 ? void 0 : _a.parentNode) {
14592
+ this.chooserEl.parentNode.removeChild(this.chooserEl);
14593
+ }
14594
+ if (this.triggerButtonEl) {
14595
+ this.triggerButtonEl.selected = false;
14596
+ }
14597
+ this.dropdownEl = null;
14598
+ this.chooserEl = null;
14599
+ this.triggerButtonEl = null;
14600
+ }
14601
+ /**
14602
+ * Determines whether the given event path targets the chooser.
14603
+ *
14604
+ * @param {EventTarget[]} eventPath Composed path of an event.
14605
+ * @returns {boolean} `true` when the path includes the chooser.
14606
+ */
14607
+ includesEventPath(eventPath) {
14608
+ if (!this.chooserEl) {
14609
+ return false;
14610
+ }
14611
+ const isDropdownContentClick = eventPath.some((target) => {
14612
+ return 'tagName' in target && target.tagName === 'VEGA-DROPDOWN-CONTENT-BOX';
14613
+ });
14614
+ return eventPath.includes(this.chooserEl) || isDropdownContentClick;
14615
+ }
14616
+ /**
14617
+ * Builds the dropdown element with the rich text paste option.
14618
+ *
14619
+ * @param {Document} doc Document used to create elements.
14620
+ * @param {['bottom', 'top'] | ['top', 'bottom']} placement Preferred placement order.
14621
+ * @returns {HTMLElement} Configured dropdown element.
14622
+ */
14623
+ createPasteChooserDropdown(doc, placement) {
14624
+ const dropdownEl = doc.createElement('vega-dropdown');
14625
+ dropdownEl.trigger = 'click';
14626
+ dropdownEl.selectType = 'single';
14627
+ dropdownEl.selectedSourceKey = 'rich';
14628
+ dropdownEl.maxWidth = 220;
14629
+ dropdownEl.alignment = 'start';
14630
+ dropdownEl.itemDisplayRule = 'ellipsis';
14631
+ dropdownEl.isScreenPosition = true;
14632
+ const triggerButton = doc.createElement('vega-rich-text-editor-toolbar-button');
14633
+ const arrowIcon = placement[0] === 'top' ? 'chevron-up' : 'chevron-down';
14634
+ triggerButton.setAttribute(RTEPasteChooserUI.CHOOSER_TRIGGER_ATTR, 'true');
14635
+ triggerButton.setAttribute('aria-label', VegaInternalTranslation.t('Paste options'));
14636
+ triggerButton.setAttribute('arrow-icon', arrowIcon);
14637
+ triggerButton.icon = 'rte-paste';
14638
+ triggerButton.showArrowIcon = true;
14639
+ triggerButton.selected = false;
14640
+ this.triggerButtonEl = triggerButton;
14641
+ const tooltipEl = doc.createElement('vega-tooltip');
14642
+ tooltipEl.text = VegaInternalTranslation.t('Paste options');
14643
+ tooltipEl.placement = ['bottom', 'top'];
14644
+ tooltipEl.append(triggerButton);
14645
+ dropdownEl.append(tooltipEl);
14646
+ const itemsContainer = doc.createElement('div');
14647
+ itemsContainer.setAttribute('slot', 'items');
14648
+ const dropdownItems = [
14649
+ this.createDropdownItem(doc, RTEPasteMode.RICH, VegaInternalTranslation.t('Use rich text'), RTEPasteChooserUI.CHOOSER_RICH_ATTR),
14650
+ this.createDropdownItem(doc, RTEPasteMode.PLAIN, VegaInternalTranslation.t('Use plain text'), RTEPasteChooserUI.CHOOSER_PLAIN_ATTR),
14651
+ ];
14652
+ if (this.options.showWordOption) {
14653
+ dropdownItems.push(this.createDropdownItem(doc, RTEPasteMode.WORD, VegaInternalTranslation.t('Use Word'), RTEPasteChooserUI.CHOOSER_WORD_ATTR));
14694
14654
  }
14695
- if (this.listenerWindow) {
14696
- this.listenerWindow.removeEventListener('scroll', this.handleOutsideScroll, true);
14697
- this.listenerWindow = null;
14655
+ itemsContainer.append(...dropdownItems);
14656
+ dropdownEl.append(itemsContainer);
14657
+ dropdownEl.addEventListener('vegaDropdownClick', (event) => {
14658
+ const mode = event.detail;
14659
+ if (mode === RTEPasteMode.RICH || mode === RTEPasteMode.PLAIN || mode === RTEPasteMode.WORD) {
14660
+ this.callbacks.onModeSelect(mode);
14661
+ }
14662
+ });
14663
+ return dropdownEl;
14664
+ }
14665
+ /**
14666
+ * Creates a single dropdown item element for a paste mode.
14667
+ *
14668
+ * @param {Document} doc Document used to create the element.
14669
+ * @param {RTEPasteMode} key Paste mode key for the item.
14670
+ * @param {string} label Display label for the item.
14671
+ * @param {string} dataAttrName Data attribute marker for the item.
14672
+ * @returns {HTMLVegaDropdownItemElement} Configured dropdown item element.
14673
+ */
14674
+ createDropdownItem(doc, key, label, dataAttrName) {
14675
+ const itemEl = doc.createElement('vega-dropdown-item');
14676
+ itemEl.itemKey = key;
14677
+ itemEl.label = label;
14678
+ itemEl.setAttribute(dataAttrName, 'true');
14679
+ return itemEl;
14680
+ }
14681
+ }
14682
+ (() => {
14683
+ VegaInternalIconManager.register({
14684
+ 'rte-paste': paste,
14685
+ });
14686
+ })();
14687
+ RTEPasteChooserUI.CHOOSER_ATTR = 'data-rte-paste-chooser';
14688
+ RTEPasteChooserUI.CHOOSER_RICH_ATTR = 'data-rte-paste-type-rich';
14689
+ RTEPasteChooserUI.CHOOSER_PLAIN_ATTR = 'data-rte-paste-type-plain';
14690
+ RTEPasteChooserUI.CHOOSER_WORD_ATTR = 'data-rte-paste-type-word';
14691
+ RTEPasteChooserUI.CHOOSER_TRIGGER_ATTR = 'data-rte-paste-trigger';
14692
+
14693
+ /** Owns chooser rendering and all listener bookkeeping used to dismiss it. */
14694
+ class PasteChooserController {
14695
+ constructor(positioner, onModeSelect, onClearPayload) {
14696
+ this.positioner = positioner;
14697
+ this.onModeSelect = onModeSelect;
14698
+ this.onClearPayload = onClearPayload;
14699
+ this.chooserUI = null;
14700
+ this.listenerDocument = null;
14701
+ this.listenerWindow = null;
14702
+ this.contentHostEl = null;
14703
+ /**
14704
+ * @param {Event} event Pointer event captured on the document.
14705
+ */
14706
+ this.handleOutsidePointerDown = (event) => {
14707
+ if (!this.chooserUI) {
14708
+ return;
14709
+ }
14710
+ const eventPath = typeof event.composedPath === 'function' ? event.composedPath() : [];
14711
+ if (!this.chooserUI.includesEventPath(eventPath)) {
14712
+ this.clear();
14713
+ }
14714
+ };
14715
+ /**
14716
+ * @param {KeyboardEvent} event Keyboard event captured on the document.
14717
+ */
14718
+ this.handleOutsideKeyDown = (event) => {
14719
+ if (event.key === 'Escape') {
14720
+ this.clear();
14721
+ }
14722
+ };
14723
+ /**
14724
+ * Clears the chooser when a relevant scroll container scrolls.
14725
+ *
14726
+ * @returns {void}
14727
+ */
14728
+ this.handleOutsideScroll = () => this.clear();
14729
+ }
14730
+ /**
14731
+ * @returns {RTEPasteChooserUI | null} Current chooser UI, or `null` when closed.
14732
+ */
14733
+ get ui() {
14734
+ return this.chooserUI;
14735
+ }
14736
+ /**
14737
+ * @param {HTMLElement | null} hostEl Rich text editor host element.
14738
+ * @param {HTMLElement | null} contentHostEl Scrollable content host element.
14739
+ * @param {ClipboardEvent} pasteEvent Originating paste event used for positioning.
14740
+ * @param {boolean} showWordOption Whether to display the Word paste option.
14741
+ */
14742
+ open(hostEl, contentHostEl, pasteEvent, showWordOption) {
14743
+ var _a, _b, _c;
14744
+ const hostRoot = (_a = hostEl === null || hostEl === void 0 ? void 0 : hostEl.shadowRoot) !== null && _a !== void 0 ? _a : null;
14745
+ if (!hostRoot || !hostEl) {
14746
+ return;
14698
14747
  }
14748
+ this.clear(false);
14749
+ const position = this.positioner.compute(pasteEvent);
14750
+ this.chooserUI = new RTEPasteChooserUI(hostRoot, { onModeSelect: this.onModeSelect }, { showWordOption });
14751
+ this.chooserUI.open(position);
14752
+ this.contentHostEl = contentHostEl;
14753
+ this.listenerDocument = hostEl.ownerDocument;
14754
+ this.listenerWindow = this.listenerDocument.defaultView;
14755
+ this.listenerDocument.addEventListener('mousedown', this.handleOutsidePointerDown, true);
14756
+ this.listenerDocument.addEventListener('keydown', this.handleOutsideKeyDown, true);
14757
+ this.listenerDocument.addEventListener('scroll', this.handleOutsideScroll, true);
14758
+ (_b = this.listenerWindow) === null || _b === void 0 ? void 0 : _b.addEventListener('scroll', this.handleOutsideScroll, true);
14759
+ (_c = this.contentHostEl) === null || _c === void 0 ? void 0 : _c.addEventListener('scroll', this.handleOutsideScroll);
14760
+ }
14761
+ /**
14762
+ * @param {boolean} [clearPayload] Whether to also clear the pending paste payload.
14763
+ */
14764
+ clear(clearPayload = true) {
14765
+ var _a, _b, _c;
14766
+ (_a = this.contentHostEl) === null || _a === void 0 ? void 0 : _a.removeEventListener('scroll', this.handleOutsideScroll);
14767
+ this.contentHostEl = null;
14768
+ (_b = this.listenerWindow) === null || _b === void 0 ? void 0 : _b.removeEventListener('scroll', this.handleOutsideScroll, true);
14769
+ this.listenerWindow = null;
14699
14770
  if (this.listenerDocument) {
14700
14771
  this.listenerDocument.removeEventListener('mousedown', this.handleOutsidePointerDown, true);
14701
14772
  this.listenerDocument.removeEventListener('keydown', this.handleOutsideKeyDown, true);
14702
14773
  this.listenerDocument.removeEventListener('scroll', this.handleOutsideScroll, true);
14703
14774
  this.listenerDocument = null;
14704
14775
  }
14705
- if (this.chooserUI) {
14706
- this.chooserUI.destroy();
14707
- }
14776
+ (_c = this.chooserUI) === null || _c === void 0 ? void 0 : _c.destroy();
14708
14777
  this.chooserUI = null;
14709
14778
  if (clearPayload) {
14779
+ this.onClearPayload();
14780
+ }
14781
+ }
14782
+ }
14783
+
14784
+ /**
14785
+ * Vega Rich Text Editor paste extension.
14786
+ * Intercepts keyboard paste and allows users to choose paste mode.
14787
+ */
14788
+ class VegaRTEPasteExtension extends VegaRTEExtension {
14789
+ constructor(options = {}) {
14790
+ super();
14791
+ this.editableEl = null;
14792
+ this.contentHostEl = null;
14793
+ this.pendingPastePayload = null;
14794
+ /**
14795
+ * Handles a native paste event by capturing the clipboard payload and
14796
+ * rendering the paste-mode chooser.
14797
+ *
14798
+ * @param {ClipboardEvent} event Native clipboard paste event.
14799
+ */
14800
+ this.handlePasteEvent = (event) => {
14801
+ this.pasteEventInterceptor.handlePasteEvent(event);
14802
+ };
14803
+ /**
14804
+ * Dismisses the chooser when a pointer interaction occurs outside of it.
14805
+ *
14806
+ * @param {Event} event Pointer event captured on the document.
14807
+ */
14808
+ this.handleOutsidePointerDown = (event) => {
14809
+ this.pasteChooserController.handleOutsidePointerDown(event);
14810
+ };
14811
+ /**
14812
+ * Dismisses the chooser when the Escape key is pressed.
14813
+ *
14814
+ * @param {KeyboardEvent} event Keyboard event captured on the document.
14815
+ */
14816
+ this.handleOutsideKeyDown = (event) => {
14817
+ this.pasteChooserController.handleOutsideKeyDown(event);
14818
+ };
14819
+ /**
14820
+ * Dismisses the chooser when any relevant scroll container scrolls.
14821
+ */
14822
+ this.handleOutsideScroll = () => {
14823
+ this.pasteChooserController.handleOutsideScroll();
14824
+ };
14825
+ this.options = options;
14826
+ this.strategySelector = new PasteStrategySelector();
14827
+ this.imageParser = new PasteImageParser();
14828
+ this.pendingImageRegistry = new PendingImageRegistry();
14829
+ this.chooserPositioner = new ChooserPositioner(() => this.hostEl, () => { var _a, _b; return (_b = (_a = this.pendingPastePayload) === null || _a === void 0 ? void 0 : _a.range) !== null && _b !== void 0 ? _b : this.cloneCurrentSelectionRange(); });
14830
+ this.processingPipeline = new PasteProcessingPipeline(this.strategySelector, new ImageExtractor(this.imageParser), this.pendingImageRegistry);
14831
+ this.dataTransferBuilder = new PasteDataTransferBuilder();
14832
+ this.pasteDispatcher = new PasteDispatcher();
14833
+ this.selectionSnapshotService = new SelectionSnapshotService(() => this.extensionContext);
14834
+ this.pasteEventInterceptor = new PasteEventInterceptor(this.selectionSnapshotService, (payload, event) => {
14835
+ this.pendingPastePayload = payload;
14836
+ this.renderPasteChooser(event);
14837
+ });
14838
+ this.pasteChooserController = new PasteChooserController(this.chooserPositioner, (mode) => this.applyPasteMode(mode), () => {
14710
14839
  this.pendingPastePayload = null;
14840
+ });
14841
+ }
14842
+ /** @inheritDoc */
14843
+ initialExtensionAfterLoad(context) {
14844
+ super.initialExtensionAfterLoad(context);
14845
+ this.hostEl = context.host;
14846
+ this.attachPasteListener();
14847
+ }
14848
+ /** @inheritDoc */
14849
+ destroyExtension() {
14850
+ this.detachPasteListener();
14851
+ this.clearPasteChooser();
14852
+ this.pendingImageRegistry.discardUnsentPreviews();
14853
+ }
14854
+ /** @returns {RTEPasteChooserUI | null} Currently open chooser UI, or `null` when closed. */
14855
+ get chooserUI() {
14856
+ return this.pasteChooserController.ui;
14857
+ }
14858
+ /**
14859
+ * Attaches the paste listener to the editable element.
14860
+ */
14861
+ attachPasteListener() {
14862
+ const { editableEl, contentHostEl, } = this.getEditorElements();
14863
+ this.editableEl = editableEl;
14864
+ this.contentHostEl = contentHostEl;
14865
+ this.pasteEventInterceptor.attach(this.editableEl);
14866
+ }
14867
+ /**
14868
+ * Detaches the paste listener from the editable element.
14869
+ */
14870
+ detachPasteListener() {
14871
+ this.pasteEventInterceptor.detach();
14872
+ this.editableEl = null;
14873
+ this.contentHostEl = null;
14874
+ }
14875
+ /**
14876
+ * Resolves the content host and editable element from the host shadow tree.
14877
+ *
14878
+ * @returns {EditorElements} Editor elements.
14879
+ */
14880
+ getEditorElements() {
14881
+ var _a, _b, _c, _d, _e;
14882
+ const contentHostEl = (_c = (_b = (_a = this.hostEl) === null || _a === void 0 ? void 0 : _a.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelector('vega-rich-text-content')) !== null && _c !== void 0 ? _c : null;
14883
+ const editableEl = (_e = (_d = contentHostEl === null || contentHostEl === void 0 ? void 0 : contentHostEl.shadowRoot) === null || _d === void 0 ? void 0 : _d.querySelector('.rich-text-content')) !== null && _e !== void 0 ? _e : null;
14884
+ return { editableEl, contentHostEl };
14885
+ }
14886
+ /**
14887
+ * Resolves the editable content element from the host shadow tree.
14888
+ *
14889
+ * @returns {HTMLDivElement | null} Editable element or `null` when unavailable.
14890
+ */
14891
+ getEditableElement() {
14892
+ const { editableEl } = this.getEditorElements();
14893
+ return editableEl;
14894
+ }
14895
+ /**
14896
+ * Clones the current selection range so it can be restored after the user
14897
+ * chooses a paste mode.
14898
+ *
14899
+ * @returns {Range | null} Cloned range or `null` when there is no selection.
14900
+ */
14901
+ cloneCurrentSelectionRange() {
14902
+ return this.selectionSnapshotService.capture().range;
14903
+ }
14904
+ /**
14905
+ * Renders the paste-mode chooser and wires up dismissal listeners.
14906
+ *
14907
+ * @param {ClipboardEvent} pasteEvent Originating paste event used for positioning.
14908
+ */
14909
+ renderPasteChooser(pasteEvent) {
14910
+ var _a;
14911
+ this.pasteChooserController.open(this.hostEl, this.contentHostEl, pasteEvent, ((_a = this.options) === null || _a === void 0 ? void 0 : _a.enableWordPaste) === true);
14912
+ }
14913
+ /**
14914
+ * Applies the chosen paste mode by dispatching a synthetic paste input event.
14915
+ *
14916
+ * `rich` keeps auto-detection enabled; any other explicit mode forces the
14917
+ * corresponding registered strategy.
14918
+ *
14919
+ * @param {RTEPasteMode} mode Selected paste mode.
14920
+ */
14921
+ applyPasteMode(mode) {
14922
+ var _a;
14923
+ if (!this.pendingPastePayload) {
14924
+ this.clearPasteChooser();
14925
+ return;
14711
14926
  }
14927
+ const editableEl = (_a = this.editableEl) !== null && _a !== void 0 ? _a : this.getEditableElement();
14928
+ if (!editableEl) {
14929
+ this.clearPasteChooser();
14930
+ return;
14931
+ }
14932
+ editableEl.focus();
14933
+ this.selectionSnapshotService.restore(this.pendingPastePayload);
14934
+ const output = this.processingPipeline.process(this.pendingPastePayload, mode);
14935
+ const dataTransfer = this.dataTransferBuilder.build(output);
14936
+ this.pasteDispatcher.dispatch(editableEl, dataTransfer);
14937
+ this.clearPasteChooser();
14938
+ this.emitLocalImageInsertedEvent();
14939
+ }
14940
+ /**
14941
+ * Emits the `imageInsertedCallback` for any pending previews, allowing the
14942
+ * consumer to upload them and resolve their URLs.
14943
+ */
14944
+ emitLocalImageInsertedEvent() {
14945
+ if (this.pendingImageRegistry.hasPendingNotifications()) {
14946
+ this.pendingImageRegistry.notifyInserted(this.options.imageInsertedCallback, () => { var _a; return (_a = this.editableEl) !== null && _a !== void 0 ? _a : this.getEditableElement(); }, (imageElement) => this.getDTOEntityByDom(imageElement));
14947
+ }
14948
+ }
14949
+ /**
14950
+ * Tears down the chooser UI and removes dismissal listeners.
14951
+ *
14952
+ * @param {boolean} [clearPayload] Whether to also clear the pending payload.
14953
+ */
14954
+ clearPasteChooser(clearPayload = true) {
14955
+ this.pasteChooserController.clear(clearPayload);
14712
14956
  }
14713
14957
  }
14714
14958
  (() => {