@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
@@ -8,16 +8,16 @@ const internalVegaZIndexManager = require('./internal-vega-z-index-manager-f03dd
8
8
  const dynamicSlimmer = require('./dynamic-slimmer-f31fdfd7.js');
9
9
  const pageResizeObserverSlimmer = require('./page-resize-observer-slimmer-273d62ef.js');
10
10
  const internalVegaEventManager = require('./internal-vega-event-manager-0c256d63.js');
11
- const internalTranslationController = require('./internal-translation-controller-eae8a8de.js');
12
- const internalCalendarPeriodFactory = require('./internal-calendar-period-factory-3c5236be.js');
13
- const codeBlock = require('./code-block-06e6591f.js');
14
- const contentState = require('./content-state-8c862e5e.js');
15
- const linkExtension = require('./link-extension-2a6133b7.js');
11
+ const internalTranslationController = require('./internal-translation-controller-0d67ca4d.js');
12
+ const internalCalendarPeriodFactory = require('./internal-calendar-period-factory-c3198ea7.js');
13
+ const codeBlock = require('./code-block-72de6c4d.js');
14
+ const contentState = require('./content-state-ff40bdc6.js');
15
+ const linkExtension = require('./link-extension-1b4ed437.js');
16
16
  const internalIconManager = require('./internal-icon-manager-b9702049.js');
17
- const typeGuard = require('./type-guard-29e01bd4.js');
17
+ const typeGuard = require('./type-guard-cce6fe1f.js');
18
18
  const vegaNonceManager = require('./vega-nonce-manager-df69d3ed.js');
19
- const imageExtension = require('./image-extension-1cf84f27.js');
20
- const splitCellOperation = require('./split-cell-operation-28f6f8d9.js');
19
+ const imageExtension = require('./image-extension-6a92c524.js');
20
+ const splitCellOperation = require('./split-cell-operation-afc82323.js');
21
21
  const changeManager = require('./change-manager-a297e4d2.js');
22
22
  const domNodeSubjectObserverFactory = require('./dom-node-subject-observer-factory-c82df135.js');
23
23
  const vegaInternalEventId = require('./vega-internal-event-id-98d499d7.js');
@@ -1630,6 +1630,154 @@ const FUNCTION_ELEMENT_CLASSES = [
1630
1630
  FUNCTION_SYNTAX_CLASS,
1631
1631
  ];
1632
1632
 
1633
+ /**
1634
+ * Class representing a logic control node in the rich text editor.
1635
+ */
1636
+ class RTELogicControlNode extends codeBlock.RTENode {
1637
+ constructor(id, text, parent) {
1638
+ super(id);
1639
+ this.type = 'logic-control-node';
1640
+ this.text = '';
1641
+ this.text = text;
1642
+ this.parent = parent;
1643
+ }
1644
+ /**
1645
+ * Clone the current node instance.
1646
+ *
1647
+ * @returns {RTELogicControlNode} - A new instance of RTELogicControlNode.
1648
+ */
1649
+ clone() {
1650
+ return new RTELogicControlNode(this.id, this.text, this.parent);
1651
+ }
1652
+ /**
1653
+ * Convert the node to its HTML representation.
1654
+ *
1655
+ * @returns {string} - The HTML string of the logic control node.
1656
+ */
1657
+ toHtml() {
1658
+ return this.text;
1659
+ }
1660
+ /**
1661
+ * Convert the node to a JSON representation.
1662
+ *
1663
+ * @returns {unknown} - The JSON object of the statement syntax node.
1664
+ */
1665
+ toJSON() {
1666
+ return {
1667
+ id: this.id,
1668
+ type: this.type,
1669
+ text: this.text,
1670
+ };
1671
+ }
1672
+ /**
1673
+ * Get the end offset of the node's range.
1674
+ *
1675
+ * @returns {number} - The end offset of the node's range.
1676
+ */
1677
+ getRangeEndOffset() {
1678
+ return 1;
1679
+ }
1680
+ /**
1681
+ * Get the container element for the node's range.
1682
+ *
1683
+ * @returns {Nullable<Node>} - The container node for the range.
1684
+ */
1685
+ getRangeContainer() {
1686
+ const element = codeBlock.stateEntityRenderingRegistry.getDOMByEntity(this);
1687
+ if (element) {
1688
+ return element.parentElement;
1689
+ }
1690
+ }
1691
+ /**
1692
+ * Get the content editable state of the node.
1693
+ *
1694
+ * @returns {boolean} - The content editable state of the node.
1695
+ */
1696
+ isContentEditable() {
1697
+ return false;
1698
+ }
1699
+ /**
1700
+ * @inheritDoc
1701
+ */
1702
+ getPlainText() {
1703
+ return this.text;
1704
+ }
1705
+ }
1706
+ RTELogicControlNode.typeName = 'RTELogicControlNode';
1707
+
1708
+ /**
1709
+ * Class representing a logic control block in the rich text editor.
1710
+ */
1711
+ class RTELogicControlBlock extends codeBlock.RTEBlock {
1712
+ constructor(id, statementText, parent) {
1713
+ super(id);
1714
+ this.type = 'logic-control-block';
1715
+ this.children = [];
1716
+ this.statementText = '';
1717
+ this.statementText = statementText;
1718
+ this.children = [new RTELogicControlNode(`${id}-node-1`, statementText, this)];
1719
+ if (parent) {
1720
+ this.parent = parent;
1721
+ }
1722
+ }
1723
+ /**
1724
+ * Create a logic control block from a JSON representation.
1725
+ *
1726
+ * @param {VegaRTELogicControlBlock} json - The JSON object representing the logic control block.
1727
+ * @returns {RTELogicControlBlock} - The created logic control block.
1728
+ */
1729
+ static from(json) {
1730
+ const block = new RTELogicControlBlock(json.id, json.statementText);
1731
+ return block;
1732
+ }
1733
+ /**
1734
+ * Check the block is not empty.
1735
+ *
1736
+ * @returns {boolean} - Always true for logic control block.
1737
+ */
1738
+ isNotEmpty() {
1739
+ return true;
1740
+ }
1741
+ /**
1742
+ * Get the last node of the block.
1743
+ *
1744
+ * @returns {RTELogicControlNode} - The last node in the block.
1745
+ */
1746
+ getLastNode() {
1747
+ return this.children[this.children.length - 1];
1748
+ }
1749
+ /**
1750
+ * Convert the block to its HTML representation.
1751
+ *
1752
+ * @returns {string} - The HTML string of the logic control block.
1753
+ */
1754
+ toHtml() {
1755
+ return `<div class='${FUNCTION_SYNTAX_CLASS}' contenteditable='false'>${this.statementText}</div>`;
1756
+ }
1757
+ /**
1758
+ * Clone the current block instance.
1759
+ *
1760
+ * @param { RTEFunctionBlock } parent - The parent function block for the cloned instance.
1761
+ * @returns {RTELogicControlBlock} - A new instance of RTEStatementSyntaxBlock.
1762
+ */
1763
+ clone(parent) {
1764
+ return new RTELogicControlBlock(this.id, this.statementText, parent);
1765
+ }
1766
+ /**
1767
+ * Get the JSON representation of the block.
1768
+ *
1769
+ * @returns {VegaRTELogicControlBlock} - The JSON object of the logic control block.
1770
+ */
1771
+ toJSON() {
1772
+ return {
1773
+ id: this.id,
1774
+ type: this.type,
1775
+ statementText: this.statementText,
1776
+ };
1777
+ }
1778
+ }
1779
+ RTELogicControlBlock.typeName = 'RTELogicControlBlock';
1780
+
1633
1781
  /**
1634
1782
  * RTE Function Block
1635
1783
  */
@@ -1654,8 +1802,36 @@ class RTEFunctionBlock extends codeBlock.RTEBlock {
1654
1802
  ? Object.assign(Object.assign({}, annotations), defaultAnnotation) : defaultAnnotation;
1655
1803
  super.convertAnnotationsToMap(functionBlock.annotationMap, annotations);
1656
1804
  functionBlock.children = this.generateBlockChildren(block.children, options, functionBlock);
1805
+ this.unwrapForeachContent(functionBlock.children);
1657
1806
  return functionBlock;
1658
1807
  }
1808
+ /**
1809
+ * Removes a redundant div wrapper from FOREACH content so it is rendered inline
1810
+ * with the FOREACH control. SHOW content retains its wrapper to preserve line breaks.
1811
+ *
1812
+ * @param {RTEFunctionBlockChild[]} children - The function block children to normalize.
1813
+ */
1814
+ static unwrapForeachContent(children) {
1815
+ children.forEach((logicControlBlock, index) => {
1816
+ const contentBlock = children[index + 1];
1817
+ if (!(logicControlBlock instanceof RTELogicControlBlock) ||
1818
+ logicControlBlock.statementText !== 'FOREACH' ||
1819
+ !(contentBlock instanceof codeBlock.RTETextBlock)) {
1820
+ return;
1821
+ }
1822
+ contentBlock.children.forEach((node) => {
1823
+ const inlineHtml = node.getAnnotationByType(codeBlock.NodeAnnotationTypeEnum.INLINE_HTML);
1824
+ if ((inlineHtml === null || inlineHtml === void 0 ? void 0 : inlineHtml.htmlTag) !== 'div')
1825
+ return;
1826
+ if (inlineHtml.child) {
1827
+ node.annotationMap.set(codeBlock.NodeAnnotationTypeEnum.INLINE_HTML, inlineHtml.child);
1828
+ }
1829
+ else {
1830
+ node.annotationMap.delete(codeBlock.NodeAnnotationTypeEnum.INLINE_HTML);
1831
+ }
1832
+ });
1833
+ });
1834
+ }
1659
1835
  /**
1660
1836
  * Converts the RTEFunctionBlock and its children to an HTML string.
1661
1837
  *
@@ -1829,218 +2005,70 @@ class InsertFunctionBlockStrategy extends codeBlock.ActionHandleStrategy {
1829
2005
  }
1830
2006
 
1831
2007
  /**
1832
- * Class representing a logic control node in the rich text editor.
2008
+ * Function toolbar button renderer class.
1833
2009
  */
1834
- class RTELogicControlNode extends codeBlock.RTENode {
1835
- constructor(id, text, parent) {
1836
- super(id);
1837
- this.type = 'logic-control-node';
1838
- this.text = '';
1839
- this.text = text;
1840
- this.parent = parent;
1841
- }
1842
- /**
1843
- * Clone the current node instance.
1844
- *
1845
- * @returns {RTELogicControlNode} - A new instance of RTELogicControlNode.
1846
- */
1847
- clone() {
1848
- return new RTELogicControlNode(this.id, this.text, this.parent);
1849
- }
2010
+ class FunctionToolbarButtonRenderer extends imageExtension.VegaRTEToolbarButtonRenderer {
1850
2011
  /**
1851
- * Convert the node to its HTML representation.
1852
- *
1853
- * @returns {string} - The HTML string of the logic control node.
2012
+ * @inheritDoc
1854
2013
  */
1855
- toHtml() {
1856
- return this.text;
2014
+ render(h, editorContext) {
2015
+ return this.renderDropdown(h, editorContext, {}, [
2016
+ this.renderButton(h, editorContext, {
2017
+ label: 'Functions',
2018
+ ariaLabel: 'Functions',
2019
+ showArrowIcon: true,
2020
+ tooltip: { text: 'Insert function' },
2021
+ }),
2022
+ this.renderDropdownListTemplate(h, FunctionToolbarButtonRenderer.FUNCTION_LIST, editorContext),
2023
+ ]);
1857
2024
  }
1858
2025
  /**
1859
- * Convert the node to a JSON representation.
2026
+ * Overrides the isDisabled method to determine if the button should be disabled.
1860
2027
  *
1861
- * @returns {unknown} - The JSON object of the statement syntax node.
2028
+ * @param {VegaRTEToolbarRenderContext} editorContext The render context for the editor.
2029
+ * @returns {boolean} - true if the button should be disabled, false otherwise.
1862
2030
  */
1863
- toJSON() {
1864
- return {
1865
- id: this.id,
1866
- type: this.type,
1867
- text: this.text,
1868
- };
2031
+ isDisabled(editorContext) {
2032
+ const context = this.getExtensionContext(editorContext.host);
2033
+ if (context) {
2034
+ const { host, getSelectedNodes } = context;
2035
+ const focusNode = getSelectedNodes()[0];
2036
+ let enableInsert = true;
2037
+ if (focusNode) {
2038
+ enableInsert = codeBlock.ActionHandleStrategyRegistry.canHandle(INSERT_FUNCTION_BLOCK, focusNode.parent);
2039
+ }
2040
+ return host.disabled || !enableInsert;
2041
+ }
2042
+ return false;
1869
2043
  }
1870
- /**
1871
- * Get the end offset of the node's range.
1872
- *
1873
- * @returns {number} - The end offset of the node's range.
1874
- */
1875
- getRangeEndOffset() {
1876
- return 1;
2044
+ /* istanbul ignore next */
2045
+ // eslint-disable-next-line jsdoc/require-jsdoc
2046
+ handleButtonClick() {
2047
+ throw new Error('Method not implemented.');
1877
2048
  }
1878
2049
  /**
1879
- * Get the container element for the node's range.
2050
+ * Handles dropdown click event
1880
2051
  *
1881
- * @returns {Nullable<Node>} - The container node for the range.
2052
+ * @param {RTEExtensionFunctionType} itemKey - key of the clicked item
2053
+ * @param {VegaRTEToolbarRenderContext} editorContext The render context for the editor.
1882
2054
  */
1883
- getRangeContainer() {
1884
- const element = codeBlock.stateEntityRenderingRegistry.getDOMByEntity(this);
1885
- if (element) {
1886
- return element.parentElement;
1887
- }
1888
- }
1889
- /**
1890
- * Get the content editable state of the node.
1891
- *
1892
- * @returns {boolean} - The content editable state of the node.
1893
- */
1894
- isContentEditable() {
1895
- return false;
1896
- }
1897
- /**
1898
- * @inheritDoc
1899
- */
1900
- getPlainText() {
1901
- return this.text;
1902
- }
1903
- }
1904
- RTELogicControlNode.typeName = 'RTELogicControlNode';
1905
-
1906
- /**
1907
- * Class representing a logic control block in the rich text editor.
1908
- */
1909
- class RTELogicControlBlock extends codeBlock.RTEBlock {
1910
- constructor(id, statementText, parent) {
1911
- super(id);
1912
- this.type = 'logic-control-block';
1913
- this.children = [];
1914
- this.statementText = '';
1915
- this.statementText = statementText;
1916
- this.children = [new RTELogicControlNode(`${id}-node-1`, statementText, this)];
1917
- if (parent) {
1918
- this.parent = parent;
1919
- }
1920
- }
1921
- /**
1922
- * Create a logic control block from a JSON representation.
1923
- *
1924
- * @param {VegaRTELogicControlBlock} json - The JSON object representing the logic control block.
1925
- * @returns {RTELogicControlBlock} - The created logic control block.
1926
- */
1927
- static from(json) {
1928
- const block = new RTELogicControlBlock(json.id, json.statementText);
1929
- return block;
1930
- }
1931
- /**
1932
- * Check the block is not empty.
1933
- *
1934
- * @returns {boolean} - Always true for logic control block.
1935
- */
1936
- isNotEmpty() {
1937
- return true;
1938
- }
1939
- /**
1940
- * Get the last node of the block.
1941
- *
1942
- * @returns {RTELogicControlNode} - The last node in the block.
1943
- */
1944
- getLastNode() {
1945
- return this.children[this.children.length - 1];
1946
- }
1947
- /**
1948
- * Convert the block to its HTML representation.
1949
- *
1950
- * @returns {string} - The HTML string of the logic control block.
1951
- */
1952
- toHtml() {
1953
- return `<div class='${FUNCTION_SYNTAX_CLASS}' contenteditable='false'>${this.statementText}</div>`;
1954
- }
1955
- /**
1956
- * Clone the current block instance.
1957
- *
1958
- * @param { RTEFunctionBlock } parent - The parent function block for the cloned instance.
1959
- * @returns {RTELogicControlBlock} - A new instance of RTEStatementSyntaxBlock.
1960
- */
1961
- clone(parent) {
1962
- return new RTELogicControlBlock(this.id, this.statementText, parent);
1963
- }
1964
- /**
1965
- * Get the JSON representation of the block.
1966
- *
1967
- * @returns {VegaRTELogicControlBlock} - The JSON object of the logic control block.
1968
- */
1969
- toJSON() {
1970
- return {
1971
- id: this.id,
1972
- type: this.type,
1973
- statementText: this.statementText,
1974
- };
1975
- }
1976
- }
1977
- RTELogicControlBlock.typeName = 'RTELogicControlBlock';
1978
-
1979
- /**
1980
- * Function toolbar button renderer class.
1981
- */
1982
- class FunctionToolbarButtonRenderer extends imageExtension.VegaRTEToolbarButtonRenderer {
1983
- /**
1984
- * @inheritDoc
1985
- */
1986
- render(h, editorContext) {
1987
- return this.renderDropdown(h, editorContext, {}, [
1988
- this.renderButton(h, editorContext, {
1989
- label: 'Functions',
1990
- ariaLabel: 'Functions',
1991
- showArrowIcon: true,
1992
- tooltip: { text: 'Insert function' },
1993
- }),
1994
- this.renderDropdownListTemplate(h, FunctionToolbarButtonRenderer.FUNCTION_LIST, editorContext),
1995
- ]);
1996
- }
1997
- /**
1998
- * Overrides the isDisabled method to determine if the button should be disabled.
1999
- *
2000
- * @param {VegaRTEToolbarRenderContext} editorContext The render context for the editor.
2001
- * @returns {boolean} - true if the button should be disabled, false otherwise.
2002
- */
2003
- isDisabled(editorContext) {
2004
- const context = this.getExtensionContext(editorContext.host);
2005
- if (context) {
2006
- const { host, getSelectedNodes } = context;
2007
- const focusNode = getSelectedNodes()[0];
2008
- let enableInsert = true;
2009
- if (focusNode) {
2010
- enableInsert = codeBlock.ActionHandleStrategyRegistry.canHandle(INSERT_FUNCTION_BLOCK, focusNode.parent);
2011
- }
2012
- return host.disabled || !enableInsert;
2013
- }
2014
- return false;
2015
- }
2016
- /* istanbul ignore next */
2017
- // eslint-disable-next-line jsdoc/require-jsdoc
2018
- handleButtonClick() {
2019
- throw new Error('Method not implemented.');
2020
- }
2021
- /**
2022
- * Handles dropdown click event
2023
- *
2024
- * @param {RTEExtensionFunctionType} itemKey - key of the clicked item
2025
- * @param {VegaRTEToolbarRenderContext} editorContext The render context for the editor.
2026
- */
2027
- handleDropdownClick(itemKey, editorContext) {
2028
- if (editorContext) {
2029
- const context = this.getExtensionContext(editorContext.host);
2030
- if (context) {
2031
- const { host, getSelectedNodes } = context;
2032
- const focusNode = getSelectedNodes()[0];
2033
- const action = new InsertFunctionBlockAction(itemKey);
2034
- if (!focusNode) {
2035
- host.value.apply(action);
2036
- }
2037
- else if (focusNode.parent) {
2038
- focusNode.parent.apply(action);
2039
- }
2040
- if (action.nextFocusNode) {
2041
- host.value.apply(new contentState.UpdateCursorPositionAction(action.nextFocusNode, 1));
2042
- }
2043
- }
2055
+ handleDropdownClick(itemKey, editorContext) {
2056
+ if (editorContext) {
2057
+ const context = this.getExtensionContext(editorContext.host);
2058
+ if (context) {
2059
+ const { host, getSelectedNodes } = context;
2060
+ const focusNode = getSelectedNodes()[0];
2061
+ const action = new InsertFunctionBlockAction(itemKey);
2062
+ if (!focusNode) {
2063
+ host.value.apply(action);
2064
+ }
2065
+ else if (focusNode.parent) {
2066
+ focusNode.parent.apply(action);
2067
+ }
2068
+ if (action.nextFocusNode) {
2069
+ host.value.apply(new contentState.UpdateCursorPositionAction(action.nextFocusNode, 1));
2070
+ }
2071
+ }
2044
2072
  }
2045
2073
  }
2046
2074
  }
@@ -2194,6 +2222,7 @@ class DivToFunctionBlockStrategy extends contentState.ElementToDTOStrategy {
2194
2222
  * @inheritDoc
2195
2223
  */
2196
2224
  appendChildBlocks(currentBlock, childBlocks) {
2225
+ RTEFunctionBlock.unwrapForeachContent(childBlocks);
2197
2226
  currentBlock.children = childBlocks.map((block) => {
2198
2227
  block.parent = currentBlock;
2199
2228
  return block;
@@ -11494,6 +11523,7 @@ VegaRTEFullscreenExtension.controllerStore = VegaRTEFullscreenExtension.createSt
11494
11523
  var RTEPasteMode;
11495
11524
  (function (RTEPasteMode) {
11496
11525
  RTEPasteMode["RICH"] = "rich";
11526
+ RTEPasteMode["PLAIN"] = "plain";
11497
11527
  RTEPasteMode["WORD"] = "word";
11498
11528
  })(RTEPasteMode || (RTEPasteMode = {}));
11499
11529
  /**
@@ -11545,185 +11575,63 @@ class AbstractPasteProcessingStrategy {
11545
11575
  get supportsImageProcessing() {
11546
11576
  return false;
11547
11577
  }
11548
- }
11549
-
11550
- const paste = {
11551
- 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>`,
11552
- };
11553
-
11554
- /**
11555
- * Renders and manages the paste format chooser UI.
11556
- */
11557
- class RTEPasteChooserUI {
11558
- constructor(hostRoot, callbacks, options = {}) {
11559
- this.hostRoot = hostRoot;
11560
- this.callbacks = callbacks;
11561
- this.options = options;
11562
- this.chooserEl = null;
11563
- this.dropdownEl = null;
11564
- this.triggerButtonEl = null;
11578
+ /** @returns {boolean} Whether this strategy consumes `text/plain` instead of `text/html` (default: false). */
11579
+ get consumesPlainText() {
11580
+ return false;
11565
11581
  }
11566
11582
  /**
11567
- * Opens the paste-mode chooser at the given position.
11583
+ * Owns the complete content policy for this paste mode. Subclasses that
11584
+ * only need a different source string should override {@link getSourceContent}
11585
+ * instead of re-implementing this method.
11568
11586
  *
11569
- * @param {PasteChooserPosition} position Viewport position for the chooser.
11587
+ * @param {PasteInput} input Complete clipboard payload.
11588
+ * @returns {PasteOutput} Complete downstream paste contract.
11570
11589
  */
11571
- open(position) {
11572
- this.destroy();
11573
- const doc = this.hostRoot.ownerDocument;
11574
- const chooser = doc.createElement('div');
11575
- chooser.setAttribute(RTEPasteChooserUI.CHOOSER_ATTR, 'true');
11576
- chooser.style.position = 'fixed';
11577
- chooser.style.zIndex = '1000';
11578
- chooser.style.left = `${position.left}px`;
11579
- chooser.style.top = `${position.top}px`;
11580
- const dropdownEl = this.createPasteChooserDropdown(doc, position.placement);
11581
- dropdownEl.placement = position.placement;
11582
- chooser.append(dropdownEl);
11583
- this.hostRoot.appendChild(chooser);
11584
- this.chooserEl = chooser;
11585
- this.dropdownEl = dropdownEl;
11586
- dropdownEl.addEventListener('vegaShow', () => {
11587
- if (this.triggerButtonEl) {
11588
- this.triggerButtonEl.selected = true;
11589
- }
11590
- });
11591
- dropdownEl.addEventListener('vegaHide', () => {
11592
- if (this.triggerButtonEl) {
11593
- this.triggerButtonEl.selected = false;
11594
- }
11595
- });
11590
+ transform(input) {
11591
+ const content = this.getSourceContent(input);
11592
+ return {
11593
+ html: this.process(content),
11594
+ text: this.consumesPlainText ? content : input.text,
11595
+ mode: this.type,
11596
+ markers: {},
11597
+ extractImages: this.supportsImageProcessing,
11598
+ imagesToExtract: this.supportsImageProcessing ? input.files : [],
11599
+ };
11596
11600
  }
11597
11601
  /**
11598
- * Removes the chooser from the DOM.
11602
+ * Resolves the source string passed to {@link process}. Defaults to
11603
+ * `input.text` when {@link consumesPlainText} is true, otherwise `input.html`.
11604
+ *
11605
+ * @param {PasteInput} input Complete clipboard payload.
11606
+ * @returns {string} Content to feed into `process`.
11599
11607
  */
11600
- destroy() {
11601
- var _a;
11602
- if (this.dropdownEl && typeof this.dropdownEl.hide === 'function') {
11603
- void this.dropdownEl.hide();
11604
- }
11605
- if ((_a = this.chooserEl) === null || _a === void 0 ? void 0 : _a.parentNode) {
11606
- this.chooserEl.parentNode.removeChild(this.chooserEl);
11607
- }
11608
- if (this.triggerButtonEl) {
11609
- this.triggerButtonEl.selected = false;
11610
- }
11611
- this.dropdownEl = null;
11612
- this.chooserEl = null;
11613
- this.triggerButtonEl = null;
11608
+ getSourceContent(input) {
11609
+ return this.consumesPlainText ? input.text : input.html;
11614
11610
  }
11611
+ }
11612
+
11613
+ /**
11614
+ * Default paste processing strategy that acts as a fallback when no other
11615
+ * strategy matches. This strategy always accepts the content and passes it
11616
+ * through unchanged — the normal RTE paste pipeline (DOMParser +
11617
+ * ElementToDtoStrategyProcessor) handles the rest.
11618
+ */
11619
+ class DefaultPasteProcessingStrategy extends AbstractPasteProcessingStrategy {
11615
11620
  /**
11616
- * Determines whether the given event path targets the chooser.
11621
+ * Always matches as the terminal fallback strategy.
11617
11622
  *
11618
- * @param {EventTarget[]} eventPath Composed path of an event.
11619
- * @returns {boolean} `true` when the path includes the chooser.
11623
+ * @param {string} html Raw clipboard HTML.
11624
+ * @returns {boolean} Always `true`.
11620
11625
  */
11621
- includesEventPath(eventPath) {
11622
- if (!this.chooserEl) {
11623
- return false;
11624
- }
11625
- const isDropdownContentClick = eventPath.some((target) => {
11626
- return 'tagName' in target && target.tagName === 'VEGA-DROPDOWN-CONTENT-BOX';
11627
- });
11628
- return eventPath.includes(this.chooserEl) || isDropdownContentClick;
11626
+ canHandle(html) {
11627
+ // Default strategy is the fallback — always returns true.
11628
+ return html !== undefined;
11629
11629
  }
11630
11630
  /**
11631
- * Builds the dropdown element with the rich text paste option.
11631
+ * Returns the original HTML unchanged.
11632
11632
  *
11633
- * @param {Document} doc Document used to create elements.
11634
- * @param {['bottom', 'top'] | ['top', 'bottom']} placement Preferred placement order.
11635
- * @returns {HTMLElement} Configured dropdown element.
11636
- */
11637
- createPasteChooserDropdown(doc, placement) {
11638
- const dropdownEl = doc.createElement('vega-dropdown');
11639
- dropdownEl.trigger = 'click';
11640
- dropdownEl.selectType = 'single';
11641
- dropdownEl.selectedSourceKey = 'rich';
11642
- dropdownEl.maxWidth = 220;
11643
- dropdownEl.alignment = 'start';
11644
- dropdownEl.itemDisplayRule = 'ellipsis';
11645
- dropdownEl.isScreenPosition = true;
11646
- const triggerButton = doc.createElement('vega-rich-text-editor-toolbar-button');
11647
- const arrowIcon = placement[0] === 'top' ? 'chevron-up' : 'chevron-down';
11648
- triggerButton.setAttribute(RTEPasteChooserUI.CHOOSER_TRIGGER_ATTR, 'true');
11649
- triggerButton.setAttribute('aria-label', internalTranslationController.VegaInternalTranslation.t('Paste options'));
11650
- triggerButton.setAttribute('arrow-icon', arrowIcon);
11651
- triggerButton.icon = 'rte-paste';
11652
- triggerButton.showArrowIcon = true;
11653
- triggerButton.selected = false;
11654
- this.triggerButtonEl = triggerButton;
11655
- const tooltipEl = doc.createElement('vega-tooltip');
11656
- tooltipEl.text = internalTranslationController.VegaInternalTranslation.t('Paste options');
11657
- tooltipEl.placement = ['bottom', 'top'];
11658
- tooltipEl.append(triggerButton);
11659
- dropdownEl.append(tooltipEl);
11660
- const itemsContainer = doc.createElement('div');
11661
- itemsContainer.setAttribute('slot', 'items');
11662
- const dropdownItems = [
11663
- this.createDropdownItem(doc, RTEPasteMode.RICH, internalTranslationController.VegaInternalTranslation.t('Use rich text'), RTEPasteChooserUI.CHOOSER_RICH_ATTR),
11664
- ];
11665
- if (this.options.showWordOption) {
11666
- dropdownItems.push(this.createDropdownItem(doc, RTEPasteMode.WORD, internalTranslationController.VegaInternalTranslation.t('Use Word'), RTEPasteChooserUI.CHOOSER_WORD_ATTR));
11667
- }
11668
- itemsContainer.append(...dropdownItems);
11669
- dropdownEl.append(itemsContainer);
11670
- dropdownEl.addEventListener('vegaDropdownClick', (event) => {
11671
- const mode = event.detail;
11672
- if (mode === RTEPasteMode.RICH || mode === RTEPasteMode.WORD) {
11673
- this.callbacks.onModeSelect(mode);
11674
- }
11675
- });
11676
- return dropdownEl;
11677
- }
11678
- /**
11679
- * Creates a single dropdown item element for a paste mode.
11680
- *
11681
- * @param {Document} doc Document used to create the element.
11682
- * @param {RTEPasteMode} key Paste mode key for the item.
11683
- * @param {string} label Display label for the item.
11684
- * @param {string} dataAttrName Data attribute marker for the item.
11685
- * @returns {HTMLVegaDropdownItemElement} Configured dropdown item element.
11686
- */
11687
- createDropdownItem(doc, key, label, dataAttrName) {
11688
- const itemEl = doc.createElement('vega-dropdown-item');
11689
- itemEl.itemKey = key;
11690
- itemEl.label = label;
11691
- itemEl.setAttribute(dataAttrName, 'true');
11692
- return itemEl;
11693
- }
11694
- }
11695
- (() => {
11696
- internalIconManager.VegaInternalIconManager.register({
11697
- 'rte-paste': paste,
11698
- });
11699
- })();
11700
- RTEPasteChooserUI.CHOOSER_ATTR = 'data-rte-paste-chooser';
11701
- RTEPasteChooserUI.CHOOSER_RICH_ATTR = 'data-rte-paste-type-rich';
11702
- RTEPasteChooserUI.CHOOSER_WORD_ATTR = 'data-rte-paste-type-word';
11703
- RTEPasteChooserUI.CHOOSER_TRIGGER_ATTR = 'data-rte-paste-trigger';
11704
-
11705
- /**
11706
- * Default paste processing strategy that acts as a fallback when no other
11707
- * strategy matches. This strategy always accepts the content and passes it
11708
- * through unchanged — the normal RTE paste pipeline (DOMParser +
11709
- * ElementToDtoStrategyProcessor) handles the rest.
11710
- */
11711
- class DefaultPasteProcessingStrategy extends AbstractPasteProcessingStrategy {
11712
- /**
11713
- * Always matches as the terminal fallback strategy.
11714
- *
11715
- * @param {string} html Raw clipboard HTML.
11716
- * @returns {boolean} Always `true`.
11717
- */
11718
- canHandle(html) {
11719
- // Default strategy is the fallback — always returns true.
11720
- return html !== undefined;
11721
- }
11722
- /**
11723
- * Returns the original HTML unchanged.
11724
- *
11725
- * @param {string} html Raw clipboard HTML.
11726
- * @returns {string} Unchanged HTML.
11633
+ * @param {string} html Raw clipboard HTML.
11634
+ * @returns {string} Unchanged HTML.
11727
11635
  */
11728
11636
  process(html) {
11729
11637
  // Current default behavior: pass through unchanged
@@ -13719,6 +13627,76 @@ WordPasteProcessingStrategy.WORD_SIGNATURE_PATTERNS = [
13719
13627
  /<\/?o:p>/i,
13720
13628
  ];
13721
13629
 
13630
+ /** Converts plain-text clipboard to paragraph-per-line HTML. */
13631
+ class PlainPasteProcessingStrategy extends AbstractPasteProcessingStrategy {
13632
+ /** @returns {RTEPasteMode} Plain-text paste mode. */
13633
+ get type() {
13634
+ return RTEPasteMode.PLAIN;
13635
+ }
13636
+ /** @returns {boolean} Always `true`; consumes `text/plain` instead of `text/html`. */
13637
+ get consumesPlainText() {
13638
+ return true;
13639
+ }
13640
+ /** @returns {boolean} Always `false`; never auto-selected. */
13641
+ canHandle() {
13642
+ return false;
13643
+ }
13644
+ /**
13645
+ * Converts plain text to paragraph HTML; every `\n` starts a new paragraph.
13646
+ *
13647
+ * @param {string} text - Clipboard `text/plain` payload.
13648
+ * @param {boolean} decodeEncodedWhitespace - Decode markers emitted by HTML conversion.
13649
+ * @returns {string} Paragraph HTML.
13650
+ */
13651
+ process(text, decodeEncodedWhitespace = false) {
13652
+ if (!text) {
13653
+ return '';
13654
+ }
13655
+ const safeDocument = tryGetDocument.tryGetDocument();
13656
+ if (!safeDocument) {
13657
+ return '';
13658
+ }
13659
+ // Line splitting and boundary whitespace handling live in `toPlainPasteLines` so the
13660
+ // emitted HTML and the RTE nodes built by `InsertPasteHandler` share one conversion.
13661
+ return codeBlock.plainPasteLinesToHtml(codeBlock.toPlainPasteLines(text, decodeEncodedWhitespace));
13662
+ }
13663
+ /**
13664
+ * @param {PasteInput} input Complete clipboard payload.
13665
+ * @returns {PasteOutput} Plain HTML, canonical text, and whitespace marker contract.
13666
+ */
13667
+ transform(input) {
13668
+ const source = this.getPlainTextSource(input);
13669
+ return {
13670
+ html: this.process(source.text, source.hasEncodedWhitespace),
13671
+ text: source.text,
13672
+ mode: this.type,
13673
+ markers: source.hasEncodedWhitespace ? { [codeBlock.RTE_PRESERVED_WHITESPACE_DATA_TYPE]: 'true' } : {},
13674
+ extractImages: false,
13675
+ imagesToExtract: [],
13676
+ };
13677
+ }
13678
+ /**
13679
+ * @param {PasteInput} input Clipboard content used to derive canonical plain text.
13680
+ * @returns {PlainTextSource} Canonical text and whether it contains whitespace sentinels.
13681
+ */
13682
+ getPlainTextSource(input) {
13683
+ if (!input.html) {
13684
+ return { text: input.text || '', hasEncodedWhitespace: false };
13685
+ }
13686
+ const containsTable = imageExtension.htmlContainsTable(input.html);
13687
+ if (input.text && input.text.includes('\t') && containsTable) {
13688
+ return { text: input.text, hasEncodedWhitespace: false };
13689
+ }
13690
+ const derived = imageExtension.htmlToPlainText(input.html, {
13691
+ preserveBoundaryBlankLines: !containsTable,
13692
+ keepPreservedWhitespaceMarkers: true,
13693
+ });
13694
+ return derived
13695
+ ? { text: derived, hasEncodedWhitespace: true }
13696
+ : { text: input.text || '', hasEncodedWhitespace: false };
13697
+ }
13698
+ }
13699
+
13722
13700
  /**
13723
13701
  * Centralized selector for paste processing strategies.
13724
13702
  *
@@ -13731,10 +13709,27 @@ class PasteStrategySelector {
13731
13709
  constructor() {
13732
13710
  this.defaultStrategy = new DefaultPasteProcessingStrategy();
13733
13711
  this.strategies = [
13712
+ new PlainPasteProcessingStrategy(),
13734
13713
  new WordPasteProcessingStrategy(),
13735
13714
  this.defaultStrategy, // Fallback
13736
13715
  ];
13737
13716
  }
13717
+ /**
13718
+ * Selects the strategy that will process this paste.
13719
+ *
13720
+ * When `explicitMode` is provided and not `rich`, the strategy registered for that mode
13721
+ * is used. Otherwise the highest-priority strategy whose `canHandle` matches the HTML
13722
+ * wins, falling back to the default pass-through strategy.
13723
+ *
13724
+ * @param {PasteInput} input Captured clipboard payload used for auto-detection.
13725
+ * @param {RTEPasteMode} [explicitMode] Paste mode the user picked from the chooser.
13726
+ * @returns {AbstractPasteProcessingStrategy} Strategy to run for this paste.
13727
+ */
13728
+ select(input, explicitMode) {
13729
+ return explicitMode && explicitMode !== RTEPasteMode.RICH
13730
+ ? this.selectStrategyByType(explicitMode)
13731
+ : this.selectStrategy(input.html);
13732
+ }
13738
13733
  /**
13739
13734
  * Select the appropriate strategy for the given HTML content.
13740
13735
  * Returns the highest-priority strategy that can handle the content.
@@ -14221,271 +14216,79 @@ class PendingImageRegistry {
14221
14216
  */
14222
14217
  PendingImageRegistry.pendingImages = new Map();
14223
14218
 
14224
- /**
14225
- * Vega Rich Text Editor paste extension.
14226
- * Intercepts keyboard paste and allows users to choose paste mode.
14227
- */
14228
- class VegaRTEPasteExtension extends linkExtension.VegaRTEExtension {
14229
- constructor(options = {}) {
14230
- super();
14231
- this.editableEl = null;
14232
- this.contentHostEl = null;
14233
- this.chooserUI = null;
14234
- this.pendingPastePayload = null;
14235
- this.listenerDocument = null;
14236
- this.listenerWindow = null;
14237
- this.options = {};
14238
- this.strategySelector = new PasteStrategySelector();
14239
- this.clipboardFileContent = null;
14240
- this.imageParser = new PasteImageParser();
14241
- /** Owns pending pasted-image previews awaiting upload and their URL replacement. */
14242
- this.pendingImageRegistry = new PendingImageRegistry();
14243
- /**
14244
- * Handles a native paste event by capturing the clipboard payload and
14245
- * rendering the paste-mode chooser.
14246
- *
14247
- * @param {ClipboardEvent} event Native clipboard paste event.
14248
- */
14249
- this.handlePasteEvent = (event) => {
14250
- var _a, _b;
14251
- const clipboardData = event.clipboardData;
14252
- if (!clipboardData) {
14253
- return;
14254
- }
14255
- // HTML is sanitized via DOMParser and ElementToDtoStrategyProcessor pipeline
14256
- const html = clipboardData.getData('text/html') || '';
14257
- const text = clipboardData.getData('text/plain') || '';
14258
- // RTF must be read synchronously here: the paste event's DataTransfer is only
14259
- // readable during event dispatch, so reading it later (after the chooser) returns ''.
14260
- const rtf = clipboardData.getData('text/rtf') || '';
14261
- if (!html && !text) {
14262
- // Empty clipboard paste should not mutate editor content.
14263
- event.preventDefault();
14264
- event.stopPropagation();
14265
- return;
14266
- }
14267
- event.preventDefault();
14268
- event.stopPropagation();
14269
- const range = this.cloneCurrentSelectionRange();
14270
- const selectedNodes = ((_b = (_a = this.extensionContext) === null || _a === void 0 ? void 0 : _a.getSelectedNodes) === null || _b === void 0 ? void 0 : _b.call(_a)) || [];
14271
- this.pendingPastePayload = { html, text, range, selectedNodes: [...selectedNodes] };
14272
- this.clipboardFileContent = {
14273
- files: clipboardData.files ? Array.from(clipboardData.files) : [],
14274
- rtf,
14275
- };
14276
- this.renderPasteChooser(event);
14277
- };
14278
- /**
14279
- * Dismisses the chooser when a pointer interaction occurs outside of it.
14280
- *
14281
- * @param {Event} event Pointer event captured on the document.
14282
- */
14283
- this.handleOutsidePointerDown = (event) => {
14284
- if (!this.chooserUI) {
14285
- return;
14286
- }
14287
- const eventPath = typeof event.composedPath === 'function' ? event.composedPath() : [];
14288
- if (this.chooserUI.includesEventPath(eventPath)) {
14289
- return;
14290
- }
14291
- this.clearPasteChooser();
14292
- };
14293
- /**
14294
- * Dismisses the chooser when the Escape key is pressed.
14295
- *
14296
- * @param {KeyboardEvent} event Keyboard event captured on the document.
14297
- */
14298
- this.handleOutsideKeyDown = (event) => {
14299
- if (event.key === 'Escape') {
14300
- this.clearPasteChooser();
14301
- }
14302
- };
14303
- /**
14304
- * Dismisses the chooser when any relevant scroll container scrolls.
14305
- */
14306
- this.handleOutsideScroll = () => {
14307
- this.clearPasteChooser();
14308
- };
14309
- this.options = options;
14310
- }
14311
- /** @inheritDoc */
14312
- initialExtensionAfterLoad(context) {
14313
- super.initialExtensionAfterLoad(context);
14314
- this.hostEl = context.host;
14315
- this.attachPasteListener();
14316
- }
14317
- /** @inheritDoc */
14318
- destroyExtension() {
14319
- this.detachPasteListener();
14320
- this.clearPasteChooser();
14321
- this.pendingImageRegistry.discardUnsentPreviews();
14219
+ /** Computes paste chooser placement from the paste pointer or saved caret range. */
14220
+ class ChooserPositioner {
14221
+ constructor(getHostElement, getSelectionRange) {
14222
+ this.getHostElement = getHostElement;
14223
+ this.getSelectionRange = getSelectionRange;
14322
14224
  }
14323
14225
  /**
14324
- * Attaches the paste listener to the editable element.
14226
+ * @param {ClipboardEvent} event Originating paste event.
14227
+ * @returns {ChooserPosition} Position in viewport coordinates.
14325
14228
  */
14326
- attachPasteListener() {
14327
- const { editableEl, contentHostEl, } = this.getEditorElements();
14328
- this.editableEl = editableEl;
14329
- this.contentHostEl = contentHostEl;
14330
- if (this.editableEl) {
14331
- this.editableEl.addEventListener('paste', this.handlePasteEvent);
14229
+ compute(event) {
14230
+ var _a, _b, _c;
14231
+ const hostEl = this.getHostElement();
14232
+ if (!hostEl) {
14233
+ return { left: 0, top: 0, placement: ['bottom', 'top'] };
14234
+ }
14235
+ const hostRect = hostEl.getBoundingClientRect();
14236
+ const viewportHeight = (_b = (_a = hostEl.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.innerHeight) !== null && _b !== void 0 ? _b : window.innerHeight;
14237
+ const pointerEvent = event;
14238
+ const hasPointer = typeof pointerEvent.clientX === 'number' &&
14239
+ pointerEvent.clientX > 0 &&
14240
+ typeof pointerEvent.clientY === 'number' &&
14241
+ pointerEvent.clientY > 0;
14242
+ const caretRect = hasPointer ? null : this.getCaretRect();
14243
+ const CHOOSER_GAP_PX = 8;
14244
+ const CHOOSER_MIN_MARGIN_PX = 12;
14245
+ const CHOOSER_WIDTH_PX = 220;
14246
+ const CHOOSER_FALLBACK_OFFSET_PX = 40;
14247
+ const CHOOSER_MIN_VISIBLE_BELOW_SPACE_PX = 88;
14248
+ const baseLeft = hasPointer
14249
+ ? pointerEvent.clientX
14250
+ : (_c = caretRect === null || caretRect === void 0 ? void 0 : caretRect.left) !== null && _c !== void 0 ? _c : hostRect.left + CHOOSER_MIN_MARGIN_PX;
14251
+ const baseTop = hasPointer
14252
+ ? pointerEvent.clientY
14253
+ : caretRect
14254
+ ? caretRect.bottom
14255
+ : hostRect.top + CHOOSER_FALLBACK_OFFSET_PX;
14256
+ const maxLeft = Math.max(hostRect.left + CHOOSER_MIN_MARGIN_PX, hostRect.right - CHOOSER_WIDTH_PX);
14257
+ const left = Math.min(Math.max(baseLeft, hostRect.left + CHOOSER_MIN_MARGIN_PX), maxLeft);
14258
+ const top = Math.max(baseTop + CHOOSER_GAP_PX, hostRect.top + CHOOSER_MIN_MARGIN_PX);
14259
+ const availableBelow = viewportHeight - top - CHOOSER_MIN_MARGIN_PX;
14260
+ const availableAbove = top - CHOOSER_MIN_MARGIN_PX;
14261
+ const placement = availableBelow >= CHOOSER_MIN_VISIBLE_BELOW_SPACE_PX || availableBelow >= availableAbove
14262
+ ? ['bottom', 'top']
14263
+ : ['top', 'bottom'];
14264
+ return { left, top, placement };
14265
+ }
14266
+ /** @returns {DOMRect | null} Best available caret rectangle. */
14267
+ getCaretRect() {
14268
+ const range = this.getSelectionRange();
14269
+ if (!range) {
14270
+ return null;
14271
+ }
14272
+ const rect = range.getBoundingClientRect();
14273
+ if (!this.isUnavailableRect(rect)) {
14274
+ return rect;
14275
+ }
14276
+ const domRectList = range.getClientRects();
14277
+ if (domRectList.length > 0) {
14278
+ return domRectList[0];
14332
14279
  }
14280
+ return this.getRangeContainerRect(range);
14333
14281
  }
14334
14282
  /**
14335
- * Detaches the paste listener from the editable element.
14283
+ * @param {DOMRect} rect Rectangle to inspect.
14284
+ * @returns {boolean} Whether the rectangle has no usable position or dimensions.
14336
14285
  */
14337
- detachPasteListener() {
14338
- if (this.editableEl) {
14339
- this.editableEl.removeEventListener('paste', this.handlePasteEvent);
14340
- }
14341
- this.editableEl = null;
14342
- this.contentHostEl = null;
14286
+ isUnavailableRect(rect) {
14287
+ return rect.width === 0 && rect.height === 0 && rect.left === 0 && rect.top === 0;
14343
14288
  }
14344
14289
  /**
14345
- * Resolves the content host and editable element from the host shadow tree.
14346
- *
14347
- * @returns {EditorElements} Editor elements.
14348
- */
14349
- getEditorElements() {
14350
- var _a, _b, _c, _d, _e;
14351
- 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;
14352
- 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;
14353
- return { editableEl, contentHostEl };
14354
- }
14355
- /**
14356
- * Resolves the editable content element from the host shadow tree.
14357
- *
14358
- * @returns {HTMLDivElement | null} Editable element or `null` when unavailable.
14359
- */
14360
- getEditableElement() {
14361
- const { editableEl } = this.getEditorElements();
14362
- return editableEl;
14363
- }
14364
- /**
14365
- * Clones the current selection range so it can be restored after the user
14366
- * chooses a paste mode.
14367
- *
14368
- * @returns {Range | null} Cloned range or `null` when there is no selection.
14369
- */
14370
- cloneCurrentSelectionRange() {
14371
- var _a;
14372
- const selection = (_a = this.extensionContext) === null || _a === void 0 ? void 0 : _a.getSelection();
14373
- if (selection && selection.rangeCount > 0) {
14374
- return selection.getRangeAt(0).cloneRange();
14375
- }
14376
- return null;
14377
- }
14378
- /**
14379
- * Renders the paste-mode chooser and wires up dismissal listeners.
14380
- *
14381
- * @param {ClipboardEvent} pasteEvent Originating paste event used for positioning.
14382
- */
14383
- renderPasteChooser(pasteEvent) {
14384
- var _a, _b, _c;
14385
- const hostRoot = (_b = (_a = this.hostEl) === null || _a === void 0 ? void 0 : _a.shadowRoot) !== null && _b !== void 0 ? _b : null;
14386
- if (!hostRoot) {
14387
- return;
14388
- }
14389
- this.clearPasteChooser(false);
14390
- const position = this.computeChooserPosition(pasteEvent);
14391
- this.chooserUI = new RTEPasteChooserUI(hostRoot, {
14392
- // eslint-disable-next-line jsdoc/require-jsdoc
14393
- onModeSelect: (mode) => {
14394
- this.applyPasteMode(mode);
14395
- },
14396
- }, {
14397
- showWordOption: ((_c = this.options) === null || _c === void 0 ? void 0 : _c.enableWordPaste) === true,
14398
- });
14399
- this.chooserUI.open(position);
14400
- this.listenerDocument = this.hostEl.ownerDocument;
14401
- this.listenerWindow = this.listenerDocument.defaultView;
14402
- this.listenerDocument.addEventListener('mousedown', this.handleOutsidePointerDown, true);
14403
- this.listenerDocument.addEventListener('keydown', this.handleOutsideKeyDown, true);
14404
- this.listenerDocument.addEventListener('scroll', this.handleOutsideScroll, true);
14405
- if (this.listenerWindow) {
14406
- this.listenerWindow.addEventListener('scroll', this.handleOutsideScroll, true);
14407
- }
14408
- if (this.contentHostEl) {
14409
- this.contentHostEl.addEventListener('scroll', this.handleOutsideScroll);
14410
- }
14411
- }
14412
- /**
14413
- * Computes the on-screen position for the chooser based on pointer or caret.
14414
- *
14415
- * @param {ClipboardEvent} event Originating paste event.
14416
- * @returns {ChooserPosition} Position in viewport coordinates.
14417
- */
14418
- computeChooserPosition(event) {
14419
- var _a, _b, _c;
14420
- const hostRect = this.hostEl.getBoundingClientRect();
14421
- const viewportHeight = (_b = (_a = this.hostEl.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.innerHeight) !== null && _b !== void 0 ? _b : window.innerHeight;
14422
- const pointerEvent = event;
14423
- const hasPointer = typeof pointerEvent.clientX === 'number' &&
14424
- pointerEvent.clientX > 0 &&
14425
- typeof pointerEvent.clientY === 'number' &&
14426
- pointerEvent.clientY > 0;
14427
- // For keyboard-initiated paste (Command/Control+V) clientX/Y are 0, so anchor
14428
- // the chooser to the current caret instead of a fixed host-relative spot.
14429
- const caretRect = hasPointer ? null : this.getCaretRect();
14430
- const CHOOSER_GAP_PX = 8;
14431
- const CHOOSER_MIN_MARGIN_PX = 12;
14432
- const CHOOSER_WIDTH_PX = 220;
14433
- const CHOOSER_FALLBACK_OFFSET_PX = 40;
14434
- const CHOOSER_MIN_VISIBLE_BELOW_SPACE_PX = 88;
14435
- const baseLeft = hasPointer
14436
- ? pointerEvent.clientX
14437
- : (_c = caretRect === null || caretRect === void 0 ? void 0 : caretRect.left) !== null && _c !== void 0 ? _c : hostRect.left + CHOOSER_MIN_MARGIN_PX;
14438
- const baseTop = hasPointer
14439
- ? pointerEvent.clientY
14440
- : caretRect
14441
- ? caretRect.bottom
14442
- : hostRect.top + CHOOSER_FALLBACK_OFFSET_PX;
14443
- const maxLeft = Math.max(hostRect.left + CHOOSER_MIN_MARGIN_PX, hostRect.right - CHOOSER_WIDTH_PX);
14444
- const left = Math.min(Math.max(baseLeft, hostRect.left + CHOOSER_MIN_MARGIN_PX), maxLeft);
14445
- const top = Math.max(baseTop + CHOOSER_GAP_PX, hostRect.top + CHOOSER_MIN_MARGIN_PX);
14446
- const availableBelow = viewportHeight - top - CHOOSER_MIN_MARGIN_PX;
14447
- const availableAbove = top - CHOOSER_MIN_MARGIN_PX;
14448
- const placement = availableBelow >= CHOOSER_MIN_VISIBLE_BELOW_SPACE_PX || availableBelow >= availableAbove
14449
- ? ['bottom', 'top']
14450
- : ['top', 'bottom'];
14451
- return { left, top, placement };
14452
- }
14453
- /**
14454
- * Resolves the bounding rect of the pending caret position.
14455
- *
14456
- * @returns {DOMRect | null} Caret rect or `null` when it cannot be determined.
14457
- */
14458
- getCaretRect() {
14459
- var _a, _b;
14460
- const range = (_b = (_a = this.pendingPastePayload) === null || _a === void 0 ? void 0 : _a.range) !== null && _b !== void 0 ? _b : this.cloneCurrentSelectionRange();
14461
- if (!range) {
14462
- return null;
14463
- }
14464
- const rect = range.getBoundingClientRect();
14465
- if (this.isUnavailableRect(rect)) {
14466
- // eslint-disable-next-line spellcheck/spell-checker
14467
- const domRectList = range.getClientRects();
14468
- if (domRectList.length > 0) {
14469
- return domRectList[0];
14470
- }
14471
- return this.getRangeContainerRect(range);
14472
- }
14473
- return rect;
14474
- }
14475
- /**
14476
- * Returns whether the browser could not resolve a meaningful caret rectangle.
14477
- *
14478
- * @param {DOMRect} rect Candidate caret rect.
14479
- * @returns {boolean} Whether the rect is unusable.
14480
- */
14481
- isUnavailableRect(rect) {
14482
- return rect.width === 0 && rect.height === 0 && rect.left === 0 && rect.top === 0;
14483
- }
14484
- /**
14485
- * Falls back to the range container or neighbor child node bounds.
14486
- *
14487
- * @param {Range} range Caret/selection range.
14488
- * @returns {DOMRect | null} Best-effort caret anchor rectangle.
14290
+ * @param {Range} range Selection range whose container should be measured.
14291
+ * @returns {DOMRect | null} Best available rectangle for the range container.
14489
14292
  */
14490
14293
  getRangeContainerRect(range) {
14491
14294
  var _a, _b, _c, _d, _e, _f;
@@ -14502,10 +14305,8 @@ class VegaRTEPasteExtension extends linkExtension.VegaRTEExtension {
14502
14305
  return (_f = this.getNodeRect(containerNode)) !== null && _f !== void 0 ? _f : this.getNodeRect(containerNode.parentNode);
14503
14306
  }
14504
14307
  /**
14505
- * Returns an element-backed rectangle from a DOM node.
14506
- *
14507
- * @param {Node | null} node Candidate node.
14508
- * @returns {DOMRect | null} Node rectangle when resolvable.
14308
+ * @param {Node | null} node DOM node to measure.
14309
+ * @returns {DOMRect | null} Element-backed rectangle for the node.
14509
14310
  */
14510
14311
  getNodeRect(node) {
14511
14312
  var _a, _b;
@@ -14521,73 +14322,145 @@ class VegaRTEPasteExtension extends linkExtension.VegaRTEExtension {
14521
14322
  }
14522
14323
  return null;
14523
14324
  }
14325
+ }
14326
+
14327
+ /** Extracts local image previews from strategy output. */
14328
+ class ImageExtractor {
14329
+ constructor(parser = new PasteImageParser()) {
14330
+ this.parser = parser;
14331
+ }
14524
14332
  /**
14525
- * Applies the chosen paste mode by dispatching a synthetic paste input event.
14526
- *
14527
- * `rich` keeps auto-detection enabled; any other explicit mode forces the
14528
- * corresponding registered strategy.
14529
- *
14530
- * @param {RTEPasteMode} mode Selected paste mode.
14333
+ * @param {string} html HTML content containing local image references.
14334
+ * @param {File[]} files Clipboard image files.
14335
+ * @param {string} rtf Rich text clipboard content used to resolve images.
14336
+ * @returns {ParseLocalImagesResult} HTML and extracted local image previews.
14531
14337
  */
14532
- applyPasteMode(mode) {
14533
- var _a;
14534
- if (!this.pendingPastePayload) {
14535
- this.clearPasteChooser();
14536
- return;
14338
+ extract(html, files, rtf) {
14339
+ const clipboardFileContent = { files, rtf };
14340
+ return this.parser.parseLocalImages(html, clipboardFileContent);
14341
+ }
14342
+ }
14343
+
14344
+ /** Selects and executes one paste strategy, then performs declared post-processing. */
14345
+ class PasteProcessingPipeline {
14346
+ constructor(selector, imageExtractor, pendingImageRegistry) {
14347
+ this.selector = selector;
14348
+ this.imageExtractor = imageExtractor;
14349
+ this.pendingImageRegistry = pendingImageRegistry;
14350
+ }
14351
+ /**
14352
+ * @param {PendingPastePayload} payload Captured clipboard and selection data.
14353
+ * @param {RTEPasteMode} explicitMode Paste mode selected by the user.
14354
+ * @returns {PasteOutput} Processed paste output and image extraction metadata.
14355
+ */
14356
+ process(payload, explicitMode) {
14357
+ const input = {
14358
+ html: payload.html,
14359
+ text: payload.text,
14360
+ files: payload.files,
14361
+ rtf: payload.rtf,
14362
+ };
14363
+ const output = this.selector.select(input, explicitMode).transform(input);
14364
+ if (!output.extractImages) {
14365
+ return output;
14537
14366
  }
14538
- const editableEl = (_a = this.editableEl) !== null && _a !== void 0 ? _a : this.getEditableElement();
14539
- if (!editableEl) {
14540
- this.clearPasteChooser();
14541
- return;
14367
+ const extraction = this.imageExtractor.extract(output.html, output.imagesToExtract, input.rtf);
14368
+ if (extraction.previews.length > 0) {
14369
+ this.pendingImageRegistry.register(extraction.previews);
14542
14370
  }
14543
- editableEl.focus();
14544
- this.restoreSelectionRange(this.pendingPastePayload.range);
14545
- this.restoreSelectionControllerState(this.pendingPastePayload);
14546
- const strategy = mode === RTEPasteMode.RICH
14547
- ? this.strategySelector.selectStrategy(this.pendingPastePayload.html)
14548
- : this.strategySelector.selectStrategyByType(mode);
14549
- let processedHtml = strategy.process(this.pendingPastePayload.html);
14550
- // If the strategy supports image processing and there is clipboard file content, parse local images.
14551
- if (strategy.supportsImageProcessing && this.clipboardFileContent) {
14552
- processedHtml = this.parseLocalImages(processedHtml, this.clipboardFileContent);
14553
- }
14554
- this.clipboardFileContent = null;
14555
- const dataTransfer = this.createDataTransfer(processedHtml, this.pendingPastePayload.text, strategy.type);
14556
- this.dispatchBeforeInputPaste(editableEl, dataTransfer);
14557
- this.clearPasteChooser();
14558
- this.emitLocalImageInsertedEvent();
14371
+ return Object.assign(Object.assign({}, output), { html: extraction.html });
14559
14372
  }
14373
+ }
14374
+
14375
+ /** Builds the DataTransfer contract consumed by InsertPasteHandler. */
14376
+ class PasteDataTransferBuilder {
14560
14377
  /**
14561
- * Parses local images from the HTML and emits events for further processing.
14562
- *
14563
- * @param {string} html HTML content to parse.
14564
- * @param {ClipboardFileContent} clipboardFileContent Clipboard file content for image extraction.
14565
- * @returns {string} Processed HTML with local image references replaced.
14378
+ * @param {PasteOutput} output Processed paste output to serialize.
14379
+ * @returns {DataTransfer} Data transfer payload consumed by the paste handler.
14566
14380
  */
14567
- parseLocalImages(html, clipboardFileContent) {
14568
- const { html: result, previews } = this.imageParser.parseLocalImages(html, clipboardFileContent);
14569
- if (previews.length > 0) {
14570
- this.pendingImageRegistry.register(previews);
14381
+ build(output) {
14382
+ // Reserved keys always win over `markers` so a strategy cannot clobber the base contract.
14383
+ const safeMarkers = Object.assign({}, output.markers);
14384
+ PasteDataTransferBuilder.RESERVED_KEYS.forEach((key) => delete safeMarkers[key]);
14385
+ const values = Object.assign(Object.assign({}, safeMarkers), { 'text/html': output.html, 'text/plain': output.text, [codeBlock.RTE_PASTE_MODE_DATA_TYPE]: output.mode });
14386
+ if (typeof DataTransfer !== 'undefined') {
14387
+ const dataTransfer = new DataTransfer();
14388
+ Object.keys(values).forEach((type) => {
14389
+ const value = values[type];
14390
+ if (value) {
14391
+ dataTransfer.setData(type, value);
14392
+ }
14393
+ });
14394
+ return dataTransfer;
14571
14395
  }
14572
- return result;
14396
+ return {
14397
+ /**
14398
+ * @param {string} type Clipboard data type to read.
14399
+ * @returns {string} Clipboard value for the requested type.
14400
+ */
14401
+ getData: (type) => { var _a; return (_a = values[type]) !== null && _a !== void 0 ? _a : ''; },
14402
+ };
14573
14403
  }
14404
+ }
14405
+ PasteDataTransferBuilder.RESERVED_KEYS = [
14406
+ 'text/html',
14407
+ 'text/plain',
14408
+ codeBlock.RTE_PASTE_MODE_DATA_TYPE,
14409
+ ];
14410
+
14411
+ /** Dispatches processed paste data through the editor's existing beforeinput pipeline. */
14412
+ class PasteDispatcher {
14574
14413
  /**
14575
- * Emits the `imageInsertedCallback` for any pending previews, allowing the
14576
- * consumer to upload them and resolve their URLs.
14414
+ * @param {HTMLDivElement} editableEl Editable content element receiving the event.
14415
+ * @param {DataTransfer} dataTransfer Processed clipboard payload.
14577
14416
  */
14578
- emitLocalImageInsertedEvent() {
14579
- if (this.pendingImageRegistry.hasPendingNotifications()) {
14580
- this.pendingImageRegistry.notifyInserted(this.options.imageInsertedCallback, () => { var _a; return (_a = this.editableEl) !== null && _a !== void 0 ? _a : this.getEditableElement(); }, (imageElement) => this.getDTOEntityByDom(imageElement));
14417
+ dispatch(editableEl, dataTransfer) {
14418
+ const beforeInputEvent = new CustomEvent('beforeinput', {
14419
+ bubbles: true,
14420
+ cancelable: true,
14421
+ });
14422
+ try {
14423
+ Object.defineProperties(beforeInputEvent, {
14424
+ inputType: { value: 'insertFromPaste', configurable: true },
14425
+ dataTransfer: { value: dataTransfer, configurable: true },
14426
+ });
14427
+ }
14428
+ catch (_a) {
14429
+ Object.assign(beforeInputEvent, { inputType: 'insertFromPaste', dataTransfer });
14581
14430
  }
14431
+ editableEl.dispatchEvent(beforeInputEvent);
14432
+ }
14433
+ }
14434
+
14435
+ /** Captures and restores native and editor selection state around chooser interaction. */
14436
+ class SelectionSnapshotService {
14437
+ constructor(getContext) {
14438
+ this.getContext = getContext;
14582
14439
  }
14583
14440
  /**
14584
- * Restores SelectionController state from the captured selection so synthetic
14585
- * beforeinput paste can replace the selected content instead of appending.
14586
- *
14587
- * @param {PendingPastePayload} payload Pending paste payload.
14441
+ * @returns {SelectionSnapshot} Captured native and editor selection state.
14442
+ */
14443
+ capture() {
14444
+ var _a;
14445
+ const context = this.getContext();
14446
+ const selection = context === null || context === void 0 ? void 0 : context.getSelection();
14447
+ const range = selection && selection.rangeCount > 0 ? selection.getRangeAt(0).cloneRange() : null;
14448
+ const selectedNodes = ((_a = context === null || context === void 0 ? void 0 : context.getSelectedNodes) === null || _a === void 0 ? void 0 : _a.call(context)) || [];
14449
+ return { range, selectedNodes: [...selectedNodes] };
14450
+ }
14451
+ /**
14452
+ * @param {PendingPastePayload} payload Paste payload containing captured selection state.
14453
+ */
14454
+ restore(payload) {
14455
+ this.restoreRange(payload.range);
14456
+ this.restoreControllerState(payload);
14457
+ }
14458
+ /**
14459
+ * @param {PendingPastePayload} payload Paste payload containing editor selection state.
14588
14460
  */
14589
- restoreSelectionControllerState(payload) {
14590
- if (!payload.range || !this.extensionContext) {
14461
+ restoreControllerState(payload) {
14462
+ const context = this.getContext();
14463
+ if (!payload.range || !context) {
14591
14464
  return;
14592
14465
  }
14593
14466
  const rangeOptions = {
@@ -14596,121 +14469,492 @@ class VegaRTEPasteExtension extends linkExtension.VegaRTEExtension {
14596
14469
  startOffset: payload.range.startOffset,
14597
14470
  endOffset: payload.range.endOffset,
14598
14471
  };
14599
- this.extensionContext.setSelectedNodes(payload.selectedNodes || [], rangeOptions);
14472
+ context.setSelectedNodes(payload.selectedNodes || [], rangeOptions);
14600
14473
  }
14601
14474
  /**
14602
- * Restores a previously cloned selection range.
14603
- *
14604
- * @param {Range | null} range Range to restore.
14475
+ * @param {Range | null} range Native selection range to restore.
14605
14476
  */
14606
- restoreSelectionRange(range) {
14477
+ restoreRange(range) {
14607
14478
  var _a;
14608
14479
  if (!range) {
14609
14480
  return;
14610
14481
  }
14611
- const selection = (_a = this.extensionContext) === null || _a === void 0 ? void 0 : _a.getSelection();
14482
+ const selection = (_a = this.getContext()) === null || _a === void 0 ? void 0 : _a.getSelection();
14612
14483
  if (selection) {
14613
14484
  selection.removeAllRanges();
14614
14485
  selection.addRange(range);
14615
14486
  }
14616
14487
  }
14488
+ }
14489
+
14490
+ /** Owns the native paste listener and synchronous clipboard payload capture. */
14491
+ class PasteEventInterceptor {
14492
+ constructor(selectionSnapshotService, onPasteCaptured) {
14493
+ this.selectionSnapshotService = selectionSnapshotService;
14494
+ this.onPasteCaptured = onPasteCaptured;
14495
+ this.editableEl = null;
14496
+ /**
14497
+ * @param {ClipboardEvent} event Native paste event to capture.
14498
+ */
14499
+ this.handlePasteEvent = (event) => {
14500
+ const clipboardData = event.clipboardData;
14501
+ if (!clipboardData) {
14502
+ return;
14503
+ }
14504
+ const html = clipboardData.getData('text/html') || '';
14505
+ const text = clipboardData.getData('text/plain') || '';
14506
+ const rtf = clipboardData.getData('text/rtf') || '';
14507
+ if (!html && !text) {
14508
+ event.preventDefault();
14509
+ event.stopPropagation();
14510
+ return;
14511
+ }
14512
+ event.preventDefault();
14513
+ event.stopPropagation();
14514
+ const snapshot = this.selectionSnapshotService.capture();
14515
+ const files = clipboardData.files ? Array.from(clipboardData.files) : [];
14516
+ this.onPasteCaptured({ html, text, range: snapshot.range, selectedNodes: snapshot.selectedNodes, files, rtf }, event);
14517
+ };
14518
+ }
14617
14519
  /**
14618
- * Dispatches a synthetic `beforeinput` paste event into the editor pipeline.
14619
- *
14620
- * @param {HTMLDivElement} editableEl Editable content element.
14621
- * @param {DataTransfer} dataTransfer Clipboard payload for the paste.
14520
+ * @param {HTMLDivElement | null} editableEl Editable content element to observe.
14622
14521
  */
14623
- dispatchBeforeInputPaste(editableEl, dataTransfer) {
14624
- // This synthetic beforeinput event intentionally reuses the existing
14625
- // UserInputController -> insertFromPaste -> InsertPasteHandler pipeline.
14626
- const beforeInputEvent = new CustomEvent('beforeinput', {
14627
- bubbles: true,
14628
- cancelable: true,
14629
- });
14630
- try {
14631
- Object.defineProperties(beforeInputEvent, {
14632
- inputType: {
14633
- value: 'insertFromPaste',
14634
- configurable: true,
14635
- },
14636
- dataTransfer: {
14637
- value: dataTransfer,
14638
- configurable: true,
14639
- },
14640
- });
14641
- }
14642
- catch (_a) {
14643
- Object.assign(beforeInputEvent, {
14644
- inputType: 'insertFromPaste',
14645
- dataTransfer,
14646
- });
14647
- }
14648
- editableEl.dispatchEvent(beforeInputEvent);
14522
+ attach(editableEl) {
14523
+ var _a;
14524
+ this.detach();
14525
+ this.editableEl = editableEl;
14526
+ (_a = this.editableEl) === null || _a === void 0 ? void 0 : _a.addEventListener('paste', this.handlePasteEvent);
14649
14527
  }
14650
14528
  /**
14651
- * Builds a `DataTransfer` payload carrying the paste content and mode marker.
14652
- *
14653
- * @param {string} html HTML clipboard content.
14654
- * @param {string} text Plain text clipboard content.
14655
- * @param {RTEPasteMode} [mode] Selected paste mode marker.
14656
- * @returns {DataTransfer} Populated data transfer payload.
14529
+ * Detaches the current native paste listener.
14657
14530
  */
14658
- createDataTransfer(html, text, mode) {
14659
- if (typeof DataTransfer !== 'undefined') {
14660
- const dataTransfer = new DataTransfer();
14661
- if (html) {
14662
- dataTransfer.setData('text/html', html);
14663
- }
14664
- if (text) {
14665
- dataTransfer.setData('text/plain', text);
14666
- }
14667
- if (mode) {
14668
- dataTransfer.setData(codeBlock.RTE_PASTE_MODE_DATA_TYPE, mode);
14669
- }
14670
- return dataTransfer;
14671
- }
14672
- return {
14673
- // eslint-disable-next-line jsdoc/require-jsdoc
14674
- getData: (type) => {
14675
- if (type === 'text/html') {
14676
- return html;
14677
- }
14678
- if (type === 'text/plain') {
14679
- return text;
14680
- }
14681
- if (type === codeBlock.RTE_PASTE_MODE_DATA_TYPE) {
14682
- return mode !== null && mode !== void 0 ? mode : '';
14683
- }
14684
- return '';
14685
- },
14686
- };
14531
+ detach() {
14532
+ var _a;
14533
+ (_a = this.editableEl) === null || _a === void 0 ? void 0 : _a.removeEventListener('paste', this.handlePasteEvent);
14534
+ this.editableEl = null;
14535
+ }
14536
+ }
14537
+
14538
+ const paste = {
14539
+ 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>`,
14540
+ };
14541
+
14542
+ /**
14543
+ * Renders and manages the paste format chooser UI.
14544
+ */
14545
+ class RTEPasteChooserUI {
14546
+ constructor(hostRoot, callbacks, options = {}) {
14547
+ this.hostRoot = hostRoot;
14548
+ this.callbacks = callbacks;
14549
+ this.options = options;
14550
+ this.chooserEl = null;
14551
+ this.dropdownEl = null;
14552
+ this.triggerButtonEl = null;
14687
14553
  }
14688
14554
  /**
14689
- * Tears down the chooser UI and removes dismissal listeners.
14555
+ * Opens the paste-mode chooser at the given position.
14690
14556
  *
14691
- * @param {boolean} [clearPayload] Whether to also clear the pending payload.
14557
+ * @param {PasteChooserPosition} position Viewport position for the chooser.
14692
14558
  */
14693
- clearPasteChooser(clearPayload = true) {
14694
- if (this.contentHostEl) {
14695
- this.contentHostEl.removeEventListener('scroll', this.handleOutsideScroll);
14559
+ open(position) {
14560
+ this.destroy();
14561
+ const doc = this.hostRoot.ownerDocument;
14562
+ const chooser = doc.createElement('div');
14563
+ chooser.setAttribute(RTEPasteChooserUI.CHOOSER_ATTR, 'true');
14564
+ chooser.style.position = 'fixed';
14565
+ chooser.style.zIndex = '1000';
14566
+ chooser.style.left = `${position.left}px`;
14567
+ chooser.style.top = `${position.top}px`;
14568
+ const dropdownEl = this.createPasteChooserDropdown(doc, position.placement);
14569
+ dropdownEl.placement = position.placement;
14570
+ chooser.append(dropdownEl);
14571
+ this.hostRoot.appendChild(chooser);
14572
+ this.chooserEl = chooser;
14573
+ this.dropdownEl = dropdownEl;
14574
+ dropdownEl.addEventListener('vegaShow', () => {
14575
+ if (this.triggerButtonEl) {
14576
+ this.triggerButtonEl.selected = true;
14577
+ }
14578
+ });
14579
+ dropdownEl.addEventListener('vegaHide', () => {
14580
+ if (this.triggerButtonEl) {
14581
+ this.triggerButtonEl.selected = false;
14582
+ }
14583
+ });
14584
+ }
14585
+ /**
14586
+ * Removes the chooser from the DOM.
14587
+ */
14588
+ destroy() {
14589
+ var _a;
14590
+ if (this.dropdownEl && typeof this.dropdownEl.hide === 'function') {
14591
+ void this.dropdownEl.hide();
14592
+ }
14593
+ if ((_a = this.chooserEl) === null || _a === void 0 ? void 0 : _a.parentNode) {
14594
+ this.chooserEl.parentNode.removeChild(this.chooserEl);
14595
+ }
14596
+ if (this.triggerButtonEl) {
14597
+ this.triggerButtonEl.selected = false;
14598
+ }
14599
+ this.dropdownEl = null;
14600
+ this.chooserEl = null;
14601
+ this.triggerButtonEl = null;
14602
+ }
14603
+ /**
14604
+ * Determines whether the given event path targets the chooser.
14605
+ *
14606
+ * @param {EventTarget[]} eventPath Composed path of an event.
14607
+ * @returns {boolean} `true` when the path includes the chooser.
14608
+ */
14609
+ includesEventPath(eventPath) {
14610
+ if (!this.chooserEl) {
14611
+ return false;
14612
+ }
14613
+ const isDropdownContentClick = eventPath.some((target) => {
14614
+ return 'tagName' in target && target.tagName === 'VEGA-DROPDOWN-CONTENT-BOX';
14615
+ });
14616
+ return eventPath.includes(this.chooserEl) || isDropdownContentClick;
14617
+ }
14618
+ /**
14619
+ * Builds the dropdown element with the rich text paste option.
14620
+ *
14621
+ * @param {Document} doc Document used to create elements.
14622
+ * @param {['bottom', 'top'] | ['top', 'bottom']} placement Preferred placement order.
14623
+ * @returns {HTMLElement} Configured dropdown element.
14624
+ */
14625
+ createPasteChooserDropdown(doc, placement) {
14626
+ const dropdownEl = doc.createElement('vega-dropdown');
14627
+ dropdownEl.trigger = 'click';
14628
+ dropdownEl.selectType = 'single';
14629
+ dropdownEl.selectedSourceKey = 'rich';
14630
+ dropdownEl.maxWidth = 220;
14631
+ dropdownEl.alignment = 'start';
14632
+ dropdownEl.itemDisplayRule = 'ellipsis';
14633
+ dropdownEl.isScreenPosition = true;
14634
+ const triggerButton = doc.createElement('vega-rich-text-editor-toolbar-button');
14635
+ const arrowIcon = placement[0] === 'top' ? 'chevron-up' : 'chevron-down';
14636
+ triggerButton.setAttribute(RTEPasteChooserUI.CHOOSER_TRIGGER_ATTR, 'true');
14637
+ triggerButton.setAttribute('aria-label', internalTranslationController.VegaInternalTranslation.t('Paste options'));
14638
+ triggerButton.setAttribute('arrow-icon', arrowIcon);
14639
+ triggerButton.icon = 'rte-paste';
14640
+ triggerButton.showArrowIcon = true;
14641
+ triggerButton.selected = false;
14642
+ this.triggerButtonEl = triggerButton;
14643
+ const tooltipEl = doc.createElement('vega-tooltip');
14644
+ tooltipEl.text = internalTranslationController.VegaInternalTranslation.t('Paste options');
14645
+ tooltipEl.placement = ['bottom', 'top'];
14646
+ tooltipEl.append(triggerButton);
14647
+ dropdownEl.append(tooltipEl);
14648
+ const itemsContainer = doc.createElement('div');
14649
+ itemsContainer.setAttribute('slot', 'items');
14650
+ const dropdownItems = [
14651
+ this.createDropdownItem(doc, RTEPasteMode.RICH, internalTranslationController.VegaInternalTranslation.t('Use rich text'), RTEPasteChooserUI.CHOOSER_RICH_ATTR),
14652
+ this.createDropdownItem(doc, RTEPasteMode.PLAIN, internalTranslationController.VegaInternalTranslation.t('Use plain text'), RTEPasteChooserUI.CHOOSER_PLAIN_ATTR),
14653
+ ];
14654
+ if (this.options.showWordOption) {
14655
+ dropdownItems.push(this.createDropdownItem(doc, RTEPasteMode.WORD, internalTranslationController.VegaInternalTranslation.t('Use Word'), RTEPasteChooserUI.CHOOSER_WORD_ATTR));
14696
14656
  }
14697
- if (this.listenerWindow) {
14698
- this.listenerWindow.removeEventListener('scroll', this.handleOutsideScroll, true);
14699
- this.listenerWindow = null;
14657
+ itemsContainer.append(...dropdownItems);
14658
+ dropdownEl.append(itemsContainer);
14659
+ dropdownEl.addEventListener('vegaDropdownClick', (event) => {
14660
+ const mode = event.detail;
14661
+ if (mode === RTEPasteMode.RICH || mode === RTEPasteMode.PLAIN || mode === RTEPasteMode.WORD) {
14662
+ this.callbacks.onModeSelect(mode);
14663
+ }
14664
+ });
14665
+ return dropdownEl;
14666
+ }
14667
+ /**
14668
+ * Creates a single dropdown item element for a paste mode.
14669
+ *
14670
+ * @param {Document} doc Document used to create the element.
14671
+ * @param {RTEPasteMode} key Paste mode key for the item.
14672
+ * @param {string} label Display label for the item.
14673
+ * @param {string} dataAttrName Data attribute marker for the item.
14674
+ * @returns {HTMLVegaDropdownItemElement} Configured dropdown item element.
14675
+ */
14676
+ createDropdownItem(doc, key, label, dataAttrName) {
14677
+ const itemEl = doc.createElement('vega-dropdown-item');
14678
+ itemEl.itemKey = key;
14679
+ itemEl.label = label;
14680
+ itemEl.setAttribute(dataAttrName, 'true');
14681
+ return itemEl;
14682
+ }
14683
+ }
14684
+ (() => {
14685
+ internalIconManager.VegaInternalIconManager.register({
14686
+ 'rte-paste': paste,
14687
+ });
14688
+ })();
14689
+ RTEPasteChooserUI.CHOOSER_ATTR = 'data-rte-paste-chooser';
14690
+ RTEPasteChooserUI.CHOOSER_RICH_ATTR = 'data-rte-paste-type-rich';
14691
+ RTEPasteChooserUI.CHOOSER_PLAIN_ATTR = 'data-rte-paste-type-plain';
14692
+ RTEPasteChooserUI.CHOOSER_WORD_ATTR = 'data-rte-paste-type-word';
14693
+ RTEPasteChooserUI.CHOOSER_TRIGGER_ATTR = 'data-rte-paste-trigger';
14694
+
14695
+ /** Owns chooser rendering and all listener bookkeeping used to dismiss it. */
14696
+ class PasteChooserController {
14697
+ constructor(positioner, onModeSelect, onClearPayload) {
14698
+ this.positioner = positioner;
14699
+ this.onModeSelect = onModeSelect;
14700
+ this.onClearPayload = onClearPayload;
14701
+ this.chooserUI = null;
14702
+ this.listenerDocument = null;
14703
+ this.listenerWindow = null;
14704
+ this.contentHostEl = null;
14705
+ /**
14706
+ * @param {Event} event Pointer event captured on the document.
14707
+ */
14708
+ this.handleOutsidePointerDown = (event) => {
14709
+ if (!this.chooserUI) {
14710
+ return;
14711
+ }
14712
+ const eventPath = typeof event.composedPath === 'function' ? event.composedPath() : [];
14713
+ if (!this.chooserUI.includesEventPath(eventPath)) {
14714
+ this.clear();
14715
+ }
14716
+ };
14717
+ /**
14718
+ * @param {KeyboardEvent} event Keyboard event captured on the document.
14719
+ */
14720
+ this.handleOutsideKeyDown = (event) => {
14721
+ if (event.key === 'Escape') {
14722
+ this.clear();
14723
+ }
14724
+ };
14725
+ /**
14726
+ * Clears the chooser when a relevant scroll container scrolls.
14727
+ *
14728
+ * @returns {void}
14729
+ */
14730
+ this.handleOutsideScroll = () => this.clear();
14731
+ }
14732
+ /**
14733
+ * @returns {RTEPasteChooserUI | null} Current chooser UI, or `null` when closed.
14734
+ */
14735
+ get ui() {
14736
+ return this.chooserUI;
14737
+ }
14738
+ /**
14739
+ * @param {HTMLElement | null} hostEl Rich text editor host element.
14740
+ * @param {HTMLElement | null} contentHostEl Scrollable content host element.
14741
+ * @param {ClipboardEvent} pasteEvent Originating paste event used for positioning.
14742
+ * @param {boolean} showWordOption Whether to display the Word paste option.
14743
+ */
14744
+ open(hostEl, contentHostEl, pasteEvent, showWordOption) {
14745
+ var _a, _b, _c;
14746
+ const hostRoot = (_a = hostEl === null || hostEl === void 0 ? void 0 : hostEl.shadowRoot) !== null && _a !== void 0 ? _a : null;
14747
+ if (!hostRoot || !hostEl) {
14748
+ return;
14700
14749
  }
14750
+ this.clear(false);
14751
+ const position = this.positioner.compute(pasteEvent);
14752
+ this.chooserUI = new RTEPasteChooserUI(hostRoot, { onModeSelect: this.onModeSelect }, { showWordOption });
14753
+ this.chooserUI.open(position);
14754
+ this.contentHostEl = contentHostEl;
14755
+ this.listenerDocument = hostEl.ownerDocument;
14756
+ this.listenerWindow = this.listenerDocument.defaultView;
14757
+ this.listenerDocument.addEventListener('mousedown', this.handleOutsidePointerDown, true);
14758
+ this.listenerDocument.addEventListener('keydown', this.handleOutsideKeyDown, true);
14759
+ this.listenerDocument.addEventListener('scroll', this.handleOutsideScroll, true);
14760
+ (_b = this.listenerWindow) === null || _b === void 0 ? void 0 : _b.addEventListener('scroll', this.handleOutsideScroll, true);
14761
+ (_c = this.contentHostEl) === null || _c === void 0 ? void 0 : _c.addEventListener('scroll', this.handleOutsideScroll);
14762
+ }
14763
+ /**
14764
+ * @param {boolean} [clearPayload] Whether to also clear the pending paste payload.
14765
+ */
14766
+ clear(clearPayload = true) {
14767
+ var _a, _b, _c;
14768
+ (_a = this.contentHostEl) === null || _a === void 0 ? void 0 : _a.removeEventListener('scroll', this.handleOutsideScroll);
14769
+ this.contentHostEl = null;
14770
+ (_b = this.listenerWindow) === null || _b === void 0 ? void 0 : _b.removeEventListener('scroll', this.handleOutsideScroll, true);
14771
+ this.listenerWindow = null;
14701
14772
  if (this.listenerDocument) {
14702
14773
  this.listenerDocument.removeEventListener('mousedown', this.handleOutsidePointerDown, true);
14703
14774
  this.listenerDocument.removeEventListener('keydown', this.handleOutsideKeyDown, true);
14704
14775
  this.listenerDocument.removeEventListener('scroll', this.handleOutsideScroll, true);
14705
14776
  this.listenerDocument = null;
14706
14777
  }
14707
- if (this.chooserUI) {
14708
- this.chooserUI.destroy();
14709
- }
14778
+ (_c = this.chooserUI) === null || _c === void 0 ? void 0 : _c.destroy();
14710
14779
  this.chooserUI = null;
14711
14780
  if (clearPayload) {
14781
+ this.onClearPayload();
14782
+ }
14783
+ }
14784
+ }
14785
+
14786
+ /**
14787
+ * Vega Rich Text Editor paste extension.
14788
+ * Intercepts keyboard paste and allows users to choose paste mode.
14789
+ */
14790
+ class VegaRTEPasteExtension extends linkExtension.VegaRTEExtension {
14791
+ constructor(options = {}) {
14792
+ super();
14793
+ this.editableEl = null;
14794
+ this.contentHostEl = null;
14795
+ this.pendingPastePayload = null;
14796
+ /**
14797
+ * Handles a native paste event by capturing the clipboard payload and
14798
+ * rendering the paste-mode chooser.
14799
+ *
14800
+ * @param {ClipboardEvent} event Native clipboard paste event.
14801
+ */
14802
+ this.handlePasteEvent = (event) => {
14803
+ this.pasteEventInterceptor.handlePasteEvent(event);
14804
+ };
14805
+ /**
14806
+ * Dismisses the chooser when a pointer interaction occurs outside of it.
14807
+ *
14808
+ * @param {Event} event Pointer event captured on the document.
14809
+ */
14810
+ this.handleOutsidePointerDown = (event) => {
14811
+ this.pasteChooserController.handleOutsidePointerDown(event);
14812
+ };
14813
+ /**
14814
+ * Dismisses the chooser when the Escape key is pressed.
14815
+ *
14816
+ * @param {KeyboardEvent} event Keyboard event captured on the document.
14817
+ */
14818
+ this.handleOutsideKeyDown = (event) => {
14819
+ this.pasteChooserController.handleOutsideKeyDown(event);
14820
+ };
14821
+ /**
14822
+ * Dismisses the chooser when any relevant scroll container scrolls.
14823
+ */
14824
+ this.handleOutsideScroll = () => {
14825
+ this.pasteChooserController.handleOutsideScroll();
14826
+ };
14827
+ this.options = options;
14828
+ this.strategySelector = new PasteStrategySelector();
14829
+ this.imageParser = new PasteImageParser();
14830
+ this.pendingImageRegistry = new PendingImageRegistry();
14831
+ 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(); });
14832
+ this.processingPipeline = new PasteProcessingPipeline(this.strategySelector, new ImageExtractor(this.imageParser), this.pendingImageRegistry);
14833
+ this.dataTransferBuilder = new PasteDataTransferBuilder();
14834
+ this.pasteDispatcher = new PasteDispatcher();
14835
+ this.selectionSnapshotService = new SelectionSnapshotService(() => this.extensionContext);
14836
+ this.pasteEventInterceptor = new PasteEventInterceptor(this.selectionSnapshotService, (payload, event) => {
14837
+ this.pendingPastePayload = payload;
14838
+ this.renderPasteChooser(event);
14839
+ });
14840
+ this.pasteChooserController = new PasteChooserController(this.chooserPositioner, (mode) => this.applyPasteMode(mode), () => {
14712
14841
  this.pendingPastePayload = null;
14842
+ });
14843
+ }
14844
+ /** @inheritDoc */
14845
+ initialExtensionAfterLoad(context) {
14846
+ super.initialExtensionAfterLoad(context);
14847
+ this.hostEl = context.host;
14848
+ this.attachPasteListener();
14849
+ }
14850
+ /** @inheritDoc */
14851
+ destroyExtension() {
14852
+ this.detachPasteListener();
14853
+ this.clearPasteChooser();
14854
+ this.pendingImageRegistry.discardUnsentPreviews();
14855
+ }
14856
+ /** @returns {RTEPasteChooserUI | null} Currently open chooser UI, or `null` when closed. */
14857
+ get chooserUI() {
14858
+ return this.pasteChooserController.ui;
14859
+ }
14860
+ /**
14861
+ * Attaches the paste listener to the editable element.
14862
+ */
14863
+ attachPasteListener() {
14864
+ const { editableEl, contentHostEl, } = this.getEditorElements();
14865
+ this.editableEl = editableEl;
14866
+ this.contentHostEl = contentHostEl;
14867
+ this.pasteEventInterceptor.attach(this.editableEl);
14868
+ }
14869
+ /**
14870
+ * Detaches the paste listener from the editable element.
14871
+ */
14872
+ detachPasteListener() {
14873
+ this.pasteEventInterceptor.detach();
14874
+ this.editableEl = null;
14875
+ this.contentHostEl = null;
14876
+ }
14877
+ /**
14878
+ * Resolves the content host and editable element from the host shadow tree.
14879
+ *
14880
+ * @returns {EditorElements} Editor elements.
14881
+ */
14882
+ getEditorElements() {
14883
+ var _a, _b, _c, _d, _e;
14884
+ 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;
14885
+ 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;
14886
+ return { editableEl, contentHostEl };
14887
+ }
14888
+ /**
14889
+ * Resolves the editable content element from the host shadow tree.
14890
+ *
14891
+ * @returns {HTMLDivElement | null} Editable element or `null` when unavailable.
14892
+ */
14893
+ getEditableElement() {
14894
+ const { editableEl } = this.getEditorElements();
14895
+ return editableEl;
14896
+ }
14897
+ /**
14898
+ * Clones the current selection range so it can be restored after the user
14899
+ * chooses a paste mode.
14900
+ *
14901
+ * @returns {Range | null} Cloned range or `null` when there is no selection.
14902
+ */
14903
+ cloneCurrentSelectionRange() {
14904
+ return this.selectionSnapshotService.capture().range;
14905
+ }
14906
+ /**
14907
+ * Renders the paste-mode chooser and wires up dismissal listeners.
14908
+ *
14909
+ * @param {ClipboardEvent} pasteEvent Originating paste event used for positioning.
14910
+ */
14911
+ renderPasteChooser(pasteEvent) {
14912
+ var _a;
14913
+ this.pasteChooserController.open(this.hostEl, this.contentHostEl, pasteEvent, ((_a = this.options) === null || _a === void 0 ? void 0 : _a.enableWordPaste) === true);
14914
+ }
14915
+ /**
14916
+ * Applies the chosen paste mode by dispatching a synthetic paste input event.
14917
+ *
14918
+ * `rich` keeps auto-detection enabled; any other explicit mode forces the
14919
+ * corresponding registered strategy.
14920
+ *
14921
+ * @param {RTEPasteMode} mode Selected paste mode.
14922
+ */
14923
+ applyPasteMode(mode) {
14924
+ var _a;
14925
+ if (!this.pendingPastePayload) {
14926
+ this.clearPasteChooser();
14927
+ return;
14713
14928
  }
14929
+ const editableEl = (_a = this.editableEl) !== null && _a !== void 0 ? _a : this.getEditableElement();
14930
+ if (!editableEl) {
14931
+ this.clearPasteChooser();
14932
+ return;
14933
+ }
14934
+ editableEl.focus();
14935
+ this.selectionSnapshotService.restore(this.pendingPastePayload);
14936
+ const output = this.processingPipeline.process(this.pendingPastePayload, mode);
14937
+ const dataTransfer = this.dataTransferBuilder.build(output);
14938
+ this.pasteDispatcher.dispatch(editableEl, dataTransfer);
14939
+ this.clearPasteChooser();
14940
+ this.emitLocalImageInsertedEvent();
14941
+ }
14942
+ /**
14943
+ * Emits the `imageInsertedCallback` for any pending previews, allowing the
14944
+ * consumer to upload them and resolve their URLs.
14945
+ */
14946
+ emitLocalImageInsertedEvent() {
14947
+ if (this.pendingImageRegistry.hasPendingNotifications()) {
14948
+ this.pendingImageRegistry.notifyInserted(this.options.imageInsertedCallback, () => { var _a; return (_a = this.editableEl) !== null && _a !== void 0 ? _a : this.getEditableElement(); }, (imageElement) => this.getDTOEntityByDom(imageElement));
14949
+ }
14950
+ }
14951
+ /**
14952
+ * Tears down the chooser UI and removes dismissal listeners.
14953
+ *
14954
+ * @param {boolean} [clearPayload] Whether to also clear the pending payload.
14955
+ */
14956
+ clearPasteChooser(clearPayload = true) {
14957
+ this.pasteChooserController.clear(clearPayload);
14714
14958
  }
14715
14959
  }
14716
14960
  (() => {