@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
@@ -11,28 +11,28 @@ const changeManager = require('./change-manager-a297e4d2.js');
11
11
  const domNodeSubjectObserverFactory = require('./dom-node-subject-observer-factory-c82df135.js');
12
12
  const vegaInternalEventId = require('./vega-internal-event-id-98d499d7.js');
13
13
  const staticSubjectTitle = require('./static-subject-title-70c73b16.js');
14
- const codeBlock = require('./code-block-06e6591f.js');
15
- const typeGuard = require('./type-guard-29e01bd4.js');
16
- const linkExtension = require('./link-extension-2a6133b7.js');
14
+ const codeBlock = require('./code-block-72de6c4d.js');
15
+ const typeGuard = require('./type-guard-cce6fe1f.js');
16
+ const linkExtension = require('./link-extension-1b4ed437.js');
17
17
  const internalIconManager = require('./internal-icon-manager-b9702049.js');
18
- const imageAnnotationAction = require('./image-annotation-action-25907d6b.js');
18
+ const imageAnnotationAction = require('./image-annotation-action-1ee41bc7.js');
19
19
  const vegaEventId = require('./vega-event-id-b5abf7c9.js');
20
20
  const misc = require('./misc-3d30df91.js');
21
21
  const waitForComponentDidRender = require('./wait-for-component-did-render-90edbc1a.js');
22
- const imageExtension = require('./image-extension-1cf84f27.js');
23
- const formFieldControllerSlimmer = require('./form-field-controller-slimmer-5adb86ae.js');
22
+ const imageExtension = require('./image-extension-6a92c524.js');
23
+ const formFieldControllerSlimmer = require('./form-field-controller-slimmer-124d54ea.js');
24
24
  const eventEmitSlimmer = require('./event-emit-slimmer-6bc675f6.js');
25
25
  const subStateNotifySlimmer = require('./sub-state-notify-slimmer-3b33e31c.js');
26
- const contentState = require('./content-state-8c862e5e.js');
26
+ const contentState = require('./content-state-ff40bdc6.js');
27
27
  const alignLeft = require('./align-left-4a76df69.js');
28
- const componentValueHistoryControllerSlimmer_abstract = require('./component-value-history-controller-slimmer.abstract-f29908f8.js');
28
+ const componentValueHistoryControllerSlimmer_abstract = require('./component-value-history-controller-slimmer.abstract-23d2b3d8.js');
29
29
  const observer = require('./observer-f49483e8.js');
30
30
  const timer = require('./timer-5f33058b.js');
31
31
  const darkModeStateControllerSlimmer = require('./dark-mode-state-controller-slimmer-b454645a.js');
32
32
  const ui = require('./ui-c91c37a7.js');
33
- const richTextEditorRequiredRule = require('./rich-text-editor-required-rule-5d0c76ec.js');
33
+ const richTextEditorRequiredRule = require('./rich-text-editor-required-rule-1aa75d22.js');
34
34
  const childNodesEventPreventSlimmer = require('./child-nodes-event-prevent-slimmer-574a6a1a.js');
35
- const translationSlimmer = require('./translation-slimmer-0227ee24.js');
35
+ const translationSlimmer = require('./translation-slimmer-1771d01f.js');
36
36
  const darkModeStyleController = require('./dark-mode-style-controller-ec04ece9.js');
37
37
  const autoRunWhenReRenderTaskQueueSlimmer_abstract = require('./auto-run-when-re-render-task-queue-slimmer.abstract-5734634d.js');
38
38
  const array = require('./array-249289f2.js');
@@ -48,7 +48,7 @@ require('./discriminated-3b8e72d5.js');
48
48
  require('./dynamic-slimmer-f31fdfd7.js');
49
49
  require('./breakpoints-ebde4837.js');
50
50
  require('./ui-32120990.js');
51
- require('./internal-translation-controller-eae8a8de.js');
51
+ require('./internal-translation-controller-0d67ca4d.js');
52
52
  require('./icon-manager-7d20b0ab.js');
53
53
  require('./try-get-document-c0ebd39a.js');
54
54
  require('./vega-nonce-manager-df69d3ed.js');
@@ -61,9 +61,9 @@ require('./mutation-observer-slimmer-749d5020.js');
61
61
  require('./mutation-observer-filters-38cebc6d.js');
62
62
  require('./sub-state-observer-slimmer-5b68ba3f.js');
63
63
  require('./internal-vega-event-manager-0c256d63.js');
64
- require('./range-518b95a2.js');
65
- require('./keyboard-manager-slimmer-d1974b28.js');
66
- require('./keyboard-manager-baa83a61.js');
64
+ require('./range-712fe703.js');
65
+ require('./keyboard-manager-slimmer-a2872981.js');
66
+ require('./keyboard-manager-332eec89.js');
67
67
  require('./vega-env-manager-23b8b23c.js');
68
68
  require('./feature-flag-controller-c19d0b58.js');
69
69
  require('./index-3ca118c4.js');
@@ -2465,7 +2465,17 @@ class ValueController extends globalSlimmerRegistry.VegaSlimmer {
2465
2465
  const flushChangesWithDebounce = timer.debounce(() => {
2466
2466
  void this.valueController.flushChanges(this.value);
2467
2467
  }, ValueController.VALUE_CHANGE_DEBOUNCE_TIME, this);
2468
- this.flushChangeObserver = new observer.Observer(this.isAcceptableFlushChange.bind(this), flushChangesWithDebounce);
2468
+ this.flushChangeObserver = new observer.Observer(this.isAcceptableFlushChange.bind(this), (payload) => {
2469
+ // When a handler asks to bypass the debounce (direct user gestures like `beforeinput`),
2470
+ // invoke `flushChanges` immediately with the payload as-is. Defaults live on the emitter
2471
+ // side (`BaseHandler.flushOptions`) — the observer trusts the payload and does not
2472
+ // re-apply fallback values, so there is a single source of truth.
2473
+ if (payload && payload.bypassDebounce) {
2474
+ void this.valueController.flushChanges(this.value, payload.recordHistory, payload.updateSource);
2475
+ return;
2476
+ }
2477
+ flushChangesWithDebounce();
2478
+ });
2469
2479
  changeManager.ChangeManager.register(domNodeSubjectObserverFactory.domNodeSubjectFactory.getSubject(this.host, vegaInternalEventId.VegaInternalRichTextEditorFlushChanges), this.flushChangeObserver);
2470
2480
  }
2471
2481
  /**
@@ -2626,12 +2636,44 @@ class RichTextContentController {
2626
2636
  }
2627
2637
  }
2628
2638
 
2639
+ /**
2640
+ * Applies an ordered list of leaf content actions as one flushable unit, so a `beforeinput` handler
2641
+ * emits a single flush through the shared action pipeline instead of marking each leaf action flushable.
2642
+ */
2643
+ class SequentialCompositionAction extends codeBlock.ModifyContentAction {
2644
+ constructor(steps, flushPayload = {}) {
2645
+ super();
2646
+ this.steps = steps;
2647
+ this.isFlushable = true;
2648
+ this.type = codeBlock.ModifyContentActionType.SEQUENTIAL_COMPOSITION;
2649
+ this.flushPayload = flushPayload;
2650
+ }
2651
+ }
2652
+
2629
2653
  const ROOT_CONTAINER_CLASS_NAME = 'rich-text-content';
2630
2654
  /** This code snippet is defining an abstract class named `BaseHandler` with an abstract method `execute`. */
2631
2655
  class BaseHandler {
2656
+ constructor() {
2657
+ /**
2658
+ * Default flush payload emitted after `handleEvent` completes. This is the single source of
2659
+ * truth for the defaults — the observer does not re-apply any fallback values. Subclasses may override
2660
+ * this field to opt out of flushing (assign `undefined`) or to change the defaults. Each instance
2661
+ * owns its own copy so mutations from within `handleEvent` (e.g. `InsertTextHandler` updating
2662
+ * `updateSource`) never leak across handler instances.
2663
+ */
2664
+ this.flushOptions = {
2665
+ bypassDebounce: true,
2666
+ recordHistory: true,
2667
+ updateSource: codeBlock.RTEUpdateSource.Default,
2668
+ };
2669
+ }
2632
2670
  /**
2633
2671
  * The function `execute` initializes the current state and selection, and then handles an event if provided.
2634
2672
  *
2673
+ * Contract: `handleEvent` MUST be synchronous. A handler that mutates the value returns the
2674
+ * `CompositionStep[]` it applied through `applyComposition`; the flush is then routed through the
2675
+ * shared action pipeline. Handlers that do not mutate the value return nothing
2676
+ *
2635
2677
  * @param {VegaRTEContent} currentState - The current state of the VegaRTE content.
2636
2678
  * @param {SelectionController} selectionController - Manages the selection of items in the user interface.
2637
2679
  * @param {HTMLElement} richTextEditor - The current rich text editor component
@@ -2640,7 +2682,20 @@ class BaseHandler {
2640
2682
  execute(currentState, selectionController, richTextEditor, event) {
2641
2683
  this.initCurrentStateAndSelection(currentState, selectionController);
2642
2684
  this.setCurrentRichTextEditor(richTextEditor);
2643
- this.handleEvent(event);
2685
+ const steps = this.handleEvent(event);
2686
+ this.applyComposition(steps);
2687
+ }
2688
+ /**
2689
+ * Applies the collected leaf actions as a single flushable `SequentialCompositionAction`, so the value
2690
+ * update and its flush run through the same action pipeline used by every other flushable operation.
2691
+ * Handlers call this before enqueuing selection so caret math reads post-apply node state.
2692
+ *
2693
+ * @param {CompositionStep[]} steps - The ordered leaf actions to apply against their own targets.
2694
+ */
2695
+ applyComposition(steps) {
2696
+ if (Array.isArray(steps)) {
2697
+ this.currentState.apply(new SequentialCompositionAction(steps, this.flushOptions));
2698
+ }
2644
2699
  }
2645
2700
  /**
2646
2701
  * The function `isRootContainer` checks if an HTML element is a root container with a class of 'rich-text-content'.
@@ -2729,25 +2784,40 @@ class InsertTextHandler extends BaseHandler {
2729
2784
  * Update the state value when user type character
2730
2785
  *
2731
2786
  * @param {InputEvent} event - The input event object
2787
+ * @returns {Nullable<CompositionStep[]>} The content actions the base handler applies as one flushable unit.
2732
2788
  */
2733
2789
  handleEvent(event) {
2790
+ // The composition input controller stamps its synthesized `beforeinput` events with the
2791
+ // composition update source; pick that up so the flush notification carries the right
2792
+ // source without the caller having to inspect the event.
2793
+ if (this.flushOptions) {
2794
+ this.flushOptions.updateSource =
2795
+ event[codeBlock.RTE_UPDATE_SOURCE_KEY] === codeBlock.RTEUpdateSource.Composition
2796
+ ? codeBlock.RTEUpdateSource.Composition
2797
+ : codeBlock.RTEUpdateSource.Default;
2798
+ }
2734
2799
  const text = event.data;
2735
2800
  const currentRange = this.selectionController.getCurrentRange();
2736
2801
  const { startContainer, startOffset } = currentRange;
2737
2802
  const selectedNodes = this.selectionController.getSelectedNodes();
2803
+ const steps = [];
2804
+ // The caret move is appended as the final composition step so content + caret apply and flush atomically.
2805
+ let caretNode = null;
2806
+ let caretOffset = 0;
2807
+ let updateFlag = false;
2738
2808
  if (selectedNodes.length < 2) {
2739
2809
  if (!selectedNodes.length && this.isRootContainer(startContainer)) {
2740
- const cursorNode = this.insertTextToRoot(text);
2741
- this.selectionController.enqueueSelectionRangeFutureState(cursorNode, text.length);
2810
+ caretNode = this.insertTextToRoot(text, steps);
2811
+ caretOffset = text.length;
2742
2812
  }
2743
2813
  else if (selectedNodes[0] instanceof codeBlock.RTETextNode) {
2744
2814
  if (selectedNodes[0].isContentEditable()) {
2745
2815
  let nextOffset = startOffset + text.length;
2746
- let updateFlag = false;
2747
2816
  let cursorNode = selectedNodes[0];
2748
2817
  if (cursorNode.text === '\n') {
2749
- cursorNode = this.insertTextToLineBreakNode(cursorNode, text);
2750
- updateFlag = true;
2818
+ cursorNode = this.insertTextToLineBreakNode(cursorNode, text, steps);
2819
+ // UpdateTextAction replaces the \n with the input, so the caret lands at the text end.
2820
+ nextOffset = text.length;
2751
2821
  }
2752
2822
  else {
2753
2823
  if (startContainer.nodeValue === codeBlock.ZERO_WIDTH_SPACE &&
@@ -2756,40 +2826,54 @@ class InsertTextHandler extends BaseHandler {
2756
2826
  startContainer.nodeValue = '';
2757
2827
  nextOffset = nextOffset - codeBlock.ZERO_WIDTH_SPACE.length;
2758
2828
  }
2759
- if (cursorNode instanceof codeBlock.RTETextNode) {
2760
- updateFlag = true;
2761
- cursorNode.apply(new imageExtension.ReplaceSelectedTextAction(text, currentRange));
2762
- }
2829
+ steps.push({
2830
+ target: cursorNode,
2831
+ action: new imageExtension.ReplaceSelectedTextAction(text, currentRange),
2832
+ });
2763
2833
  }
2764
- updateFlag &&
2765
- this.selectionController.enqueueSelectionRangeFutureState(cursorNode, Math.min(nextOffset, cursorNode['text'].length));
2834
+ caretNode = cursorNode;
2835
+ // Content applies later via the composition, so use the post-apply offset directly (no pre-apply clamp).
2836
+ caretOffset = nextOffset;
2766
2837
  }
2767
2838
  else {
2768
- selectedNodes[0].parent.apply(new InsertTextToDecoratorNodeAction(selectedNodes[0], text, startOffset));
2839
+ steps.push({
2840
+ target: selectedNodes[0].parent,
2841
+ action: new InsertTextToDecoratorNodeAction(selectedNodes[0], text, startOffset),
2842
+ });
2769
2843
  }
2770
2844
  }
2771
2845
  }
2772
2846
  else {
2773
2847
  // The selected nodes is multiple nodes
2774
2848
  const cursorNode = this.removeSelectionRange(true);
2849
+ updateFlag = true;
2775
2850
  if (cursorNode instanceof codeBlock.RTETextNode) {
2776
- cursorNode.apply(new imageExtension.ReplaceSelectedTextAction(text, currentRange));
2777
- this.selectionController.enqueueSelectionRangeFutureState(cursorNode, Math.min(startOffset + text.length, cursorNode.text.length));
2851
+ steps.push({ target: cursorNode, action: new imageExtension.ReplaceSelectedTextAction(text, currentRange) });
2852
+ caretNode = cursorNode;
2853
+ caretOffset = startOffset + text.length;
2778
2854
  }
2779
2855
  }
2856
+ if (caretNode) {
2857
+ steps.push({
2858
+ target: this.currentState,
2859
+ action: new contentState.UpdateCursorPositionAction(caretNode, caretOffset),
2860
+ });
2861
+ }
2862
+ return updateFlag || steps.length > 0 ? steps : undefined;
2780
2863
  }
2781
2864
  /**
2782
2865
  * Insert the text in root element when root container is empty, should create text block and text node
2783
2866
  *
2784
2867
  * @param {string} text The insert text
2785
- * @returns {RTETextNode} The new create text node
2868
+ * @param {CompositionStep[]} steps The composition steps collector to append the update action to
2869
+ * @returns {Nullable<RTETextNode>} The new create text node
2786
2870
  */
2787
- insertTextToRoot(text) {
2871
+ insertTextToRoot(text, steps) {
2788
2872
  if (this.currentState &&
2789
2873
  this.currentState.children[0] &&
2790
2874
  this.currentState.children[0] instanceof codeBlock.RTETextBlock) {
2791
2875
  const firstNode = this.currentState.children[0].children[0];
2792
- firstNode.apply(new codeBlock.UpdateTextAction(text));
2876
+ steps.push({ target: firstNode, action: new codeBlock.UpdateTextAction(text) });
2793
2877
  return firstNode;
2794
2878
  }
2795
2879
  }
@@ -2798,20 +2882,24 @@ class InsertTextHandler extends BaseHandler {
2798
2882
  *
2799
2883
  * @param {RTETextNode} lineBreakNode The current line break node, the text value is \n
2800
2884
  * @param {string} text The text need to insert
2885
+ * @param {CompositionStep[]} steps The composition steps collector to append the resulting action to
2801
2886
  * @returns {Nullable<RTETextNode>} The new text node or the current line break node
2802
2887
  */
2803
- insertTextToLineBreakNode(lineBreakNode, text) {
2888
+ insertTextToLineBreakNode(lineBreakNode, text, steps) {
2804
2889
  const { startOffset, endOffset } = this.selectionController.getCurrentRange();
2805
2890
  const textBlock = lineBreakNode.parent;
2806
2891
  if (textBlock instanceof codeBlock.RTETextBlock) {
2807
2892
  const index = textBlock.children.indexOf(lineBreakNode);
2808
2893
  if (startOffset === 0 && startOffset === endOffset && textBlock.children[index + 1]) {
2809
2894
  const newTextNode = lineBreakNode.cloneWithText(text);
2810
- textBlock.apply(new codeBlock.InsertChildrenBeforeAction(lineBreakNode, newTextNode));
2895
+ steps.push({
2896
+ target: textBlock,
2897
+ action: new codeBlock.InsertChildrenBeforeAction(lineBreakNode, newTextNode),
2898
+ });
2811
2899
  return newTextNode;
2812
2900
  }
2813
2901
  else {
2814
- lineBreakNode.apply(new codeBlock.UpdateTextAction(text));
2902
+ steps.push({ target: lineBreakNode, action: new codeBlock.UpdateTextAction(text) });
2815
2903
  return lineBreakNode;
2816
2904
  }
2817
2905
  }
@@ -2822,20 +2910,19 @@ class InsertTextHandler extends BaseHandler {
2822
2910
  class InsertParagraphHandler extends BaseHandler {
2823
2911
  /**
2824
2912
  * Create new paragraph node and add node to state value
2913
+ *
2914
+ * @returns {CompositionStep[] | void} The content + caret steps applied atomically as one flushable composition.
2825
2915
  */
2826
2916
  handleEvent() {
2827
2917
  const selectedBlocks = this.selectionController.getSelectedBlocks();
2828
2918
  if (selectedBlocks.length) {
2829
- if (selectedBlocks.length < 2) {
2830
- this.breakSingleBlock();
2831
- }
2832
- else {
2833
- this.breakMultipleBlocks();
2834
- }
2919
+ return selectedBlocks.length < 2 ? this.breakSingleBlock() : this.breakMultipleBlocks();
2835
2920
  }
2836
2921
  }
2837
2922
  /**
2838
2923
  * Handles breaking blocks in an RTE editor based on the current selection and position.
2924
+ *
2925
+ * @returns {CompositionStep[]} The content + caret steps for the multi-block break.
2839
2926
  */
2840
2927
  breakMultipleBlocks() {
2841
2928
  const selectedBlocks = this.selectionController.getSelectedBlocks();
@@ -2873,36 +2960,71 @@ class InsertParagraphHandler extends BaseHandler {
2873
2960
  */
2874
2961
  if (firstBlock.type !== lastBlock.type &&
2875
2962
  range.startContainer.nodeType === range.endContainer.nodeType) {
2876
- firstBlock.apply(new contentState.MergeTwoBlocksNodesAction(lastBlock));
2877
- const splitAction = new codeBlock.SplitBlockWithNodeAction(cursorNode, cursorNode['text'].length);
2878
- firstBlock.apply(splitAction);
2879
- this.switchCaretPositionToNextElement(splitAction.newBlock);
2880
- return;
2963
+ const mergeStep = {
2964
+ target: firstBlock,
2965
+ action: new contentState.MergeTwoBlocksNodesAction(lastBlock),
2966
+ };
2967
+ // Split offset is read at apply time, after the merge step has run.
2968
+ // eslint-disable-next-line jsdoc/require-jsdoc
2969
+ const splitStep = () => ({
2970
+ target: firstBlock,
2971
+ action: new codeBlock.SplitBlockWithNodeAction(cursorNode, cursorNode['text'].length),
2972
+ });
2973
+ // eslint-disable-next-line jsdoc/require-jsdoc
2974
+ const caretStep = (context) => {
2975
+ const splitAction = context.getAction(codeBlock.ModifyContentActionType.SPLIT_BLOCK_WITH_NODE);
2976
+ if (splitAction) {
2977
+ return this.caretToNextElement(splitAction.newBlock);
2978
+ }
2979
+ };
2980
+ return [mergeStep, splitStep, caretStep];
2881
2981
  }
2882
2982
  }
2883
- this.selectionController.enqueueSelectionRangeFutureState(cursorNode, range.startOffset);
2983
+ return [
2984
+ {
2985
+ target: this.currentState,
2986
+ action: new contentState.UpdateCursorPositionAction(cursorNode, range.startOffset),
2987
+ },
2988
+ ];
2884
2989
  }
2885
2990
  /**
2886
2991
  * Handles breaking a single block in an RTE editor based on the current selection and position.
2992
+ *
2993
+ * @returns {CompositionStep[]} The content + caret steps for the single-block break.
2887
2994
  */
2888
2995
  breakSingleBlock() {
2889
2996
  const cursorNode = this.removeSelectionRange();
2890
2997
  const currentBlock = cursorNode instanceof codeBlock.RTENode ? cursorNode.parent : cursorNode;
2891
2998
  const { startOffset } = this.selectionController.getCurrentRange();
2999
+ let result = [];
2892
3000
  if (currentBlock) {
2893
- const breakAction = new contentState.InsertNewParagraphAction(cursorNode, startOffset);
2894
- currentBlock.apply(breakAction);
2895
- this.switchCaretPositionToNextElement(breakAction.newBlock);
3001
+ const breakStep = {
3002
+ target: currentBlock,
3003
+ action: new contentState.InsertNewParagraphAction(cursorNode, startOffset),
3004
+ };
3005
+ // eslint-disable-next-line jsdoc/require-jsdoc
3006
+ const caretStep = (context) => {
3007
+ const breakAction = context.getAction(codeBlock.ModifyContentActionType.INSERT_NEW_PARAGRAPH);
3008
+ if (breakAction) {
3009
+ return this.caretToNextElement(breakAction.newBlock);
3010
+ }
3011
+ };
3012
+ result = [breakStep, caretStep];
2896
3013
  }
3014
+ return result;
2897
3015
  }
2898
3016
  /**
2899
- * Moves the caret to the next block element in a rich text editor.
3017
+ * Builds the caret operation that moves onto the first child of the newly created block.
2900
3018
  *
2901
- * @param {RTEBlock} newBlock - Represents a new create block element in a rich text editor.
3019
+ * @param {Nullable<RTEBlock>} newBlock - The block created by the break, or null when none was created.
3020
+ * @returns {CompositionOperation | void} The caret operation, or nothing when there is no target block.
2902
3021
  */
2903
- switchCaretPositionToNextElement(newBlock) {
3022
+ caretToNextElement(newBlock) {
2904
3023
  if (newBlock && newBlock.children) {
2905
- this.selectionController.enqueueSelectionRangeFutureState(newBlock.children[0], 0);
3024
+ return {
3025
+ target: this.currentState,
3026
+ action: new contentState.UpdateCursorPositionAction(newBlock.children[0], 0),
3027
+ };
2906
3028
  }
2907
3029
  }
2908
3030
  }
@@ -2938,20 +3060,16 @@ class lineBreakMultipleBlocksAction extends codeBlock.ModifyContentAction {
2938
3060
  class InsertLineBreakHandler extends BaseHandler {
2939
3061
  /**
2940
3062
  * Create new line break node and add node to state value
3063
+ *
3064
+ * @returns {Nullable<CompositionStep[]>} The content + caret steps applied atomically as one flushable composition.
2941
3065
  */
2942
3066
  handleEvent() {
2943
- const range = this.selectionController.getCurrentRange();
2944
3067
  const selectedBlocks = this.selectionController.getSelectedBlocks();
2945
- if (this.isRootContainer(range.startContainer)) {
2946
- this.breakNewBlock();
2947
- }
2948
3068
  if (selectedBlocks.length) {
2949
- if (selectedBlocks.length < 2) {
2950
- this.breakSingleBlock();
2951
- }
2952
- else {
2953
- this.breakMultipleBlocks();
2954
- }
3069
+ return selectedBlocks.length < 2 ? this.breakSingleBlock() : this.breakMultipleBlocks();
3070
+ }
3071
+ else if (this.isRootContainer(this.selectionController.getCurrentRange().startContainer)) {
3072
+ return this.breakNewBlock();
2955
3073
  }
2956
3074
  }
2957
3075
  /**
@@ -2960,14 +3078,19 @@ class InsertLineBreakHandler extends BaseHandler {
2960
3078
  * <span></span>
2961
3079
  * <span></span>
2962
3080
  * </p>
3081
+ *
3082
+ * @returns {Nullable<CompositionStep[]>} The content + caret steps for the empty root break.
2963
3083
  */
2964
3084
  breakNewBlock() {
2965
3085
  if (this.currentState &&
2966
3086
  this.currentState.children[0] &&
2967
3087
  this.currentState.children[0] instanceof codeBlock.RTETextBlock) {
2968
- const lineBreakAction = new LineBreakSingleBlockAction(this.currentState.children[0].children[0], 0);
2969
- this.currentState.children[0].apply(lineBreakAction);
2970
- this.switchCaretPositionToSpecifiedNode(lineBreakAction.lineBreakNode);
3088
+ const targetBlock = this.currentState.children[0];
3089
+ const lineBreakStep = {
3090
+ target: targetBlock,
3091
+ action: new LineBreakSingleBlockAction(targetBlock.children[0], 0),
3092
+ };
3093
+ return [lineBreakStep, this.caretToSingleBlockNextNode()];
2971
3094
  }
2972
3095
  }
2973
3096
  /**
@@ -2981,36 +3104,68 @@ class InsertLineBreakHandler extends BaseHandler {
2981
3104
  * <br>
2982
3105
  * <span>xt</span>
2983
3106
  * </p>
3107
+ *
3108
+ * @returns {CompositionStep[]} The content + caret steps for the single-block break.
2984
3109
  */
2985
3110
  breakSingleBlock() {
2986
3111
  const range = this.selectionController.getCurrentRange();
2987
3112
  const cursorNode = this.removeSelectionRange();
2988
3113
  const currentBlock = cursorNode.parent;
3114
+ let result = [];
2989
3115
  if (currentBlock) {
2990
- const lineBreakAction = new LineBreakSingleBlockAction(cursorNode, range.startOffset);
2991
- currentBlock.apply(lineBreakAction);
2992
- if (lineBreakAction.lineBreakNode) {
2993
- this.switchCaretPositionToSpecifiedNode(lineBreakAction.lineBreakNode);
2994
- }
3116
+ const contentStep = {
3117
+ target: currentBlock,
3118
+ action: new LineBreakSingleBlockAction(cursorNode, range.startOffset),
3119
+ };
3120
+ result = [contentStep, this.caretToSingleBlockNextNode()];
2995
3121
  }
3122
+ return result;
2996
3123
  }
2997
3124
  /**
2998
3125
  * Handles breaking blocks in an RTE editor based on the current selection and position.
3126
+ *
3127
+ * @returns {CompositionStep[]} The content + caret steps for the multi-block break.
2999
3128
  */
3000
3129
  breakMultipleBlocks() {
3001
3130
  const selectedBlocks = this.selectionController.getSelectedBlocks();
3002
3131
  const cursorNode = this.removeSelectionRange();
3003
- const lineBreakAction = new lineBreakMultipleBlocksAction(selectedBlocks);
3004
- cursorNode.parent.apply(lineBreakAction);
3005
- this.switchCaretPositionToSpecifiedNode(lineBreakAction.lineBreakNode);
3132
+ const contentStep = {
3133
+ target: cursorNode.parent,
3134
+ action: new lineBreakMultipleBlocksAction(selectedBlocks),
3135
+ };
3136
+ // eslint-disable-next-line jsdoc/require-jsdoc
3137
+ const caretStep = (context) => {
3138
+ const lineBreakAction = context.getAction(codeBlock.ModifyContentActionType.LINE_BREAK_MULTIPLE_BLOCKS);
3139
+ if (lineBreakAction && lineBreakAction.lineBreakNode) {
3140
+ return this.caretOperationToNextNode(lineBreakAction.lineBreakNode);
3141
+ }
3142
+ };
3143
+ return [contentStep, caretStep];
3144
+ }
3145
+ /**
3146
+ * Builds the caret step that reads the applied single-block line break to place the caret after it.
3147
+ *
3148
+ * @returns {CompositionStep} The dependent caret step.
3149
+ */
3150
+ caretToSingleBlockNextNode() {
3151
+ return (context) => {
3152
+ const lineBreakAction = context.getAction(codeBlock.ModifyContentActionType.LINE_BREAK_SINGLE_BLOCK);
3153
+ if (lineBreakAction && lineBreakAction.lineBreakNode) {
3154
+ return this.caretOperationToNextNode(lineBreakAction.lineBreakNode);
3155
+ }
3156
+ };
3006
3157
  }
3007
3158
  /**
3008
- * Moves the caret to the next node element in a rich text editor.
3159
+ * Builds the caret operation that moves onto the node following the inserted line break.
3009
3160
  *
3010
- * @param {RTENode} lineBreakNode - Represents a node element in a rich text editor.
3161
+ * @param {RTENode} lineBreakNode - The inserted line break node.
3162
+ * @returns {CompositionOperation} The caret operation.
3011
3163
  */
3012
- switchCaretPositionToSpecifiedNode(lineBreakNode) {
3013
- this.selectionController.enqueueSelectionRangeFutureState(this.getNextRTENode(lineBreakNode), 0);
3164
+ caretOperationToNextNode(lineBreakNode) {
3165
+ return {
3166
+ target: this.currentState,
3167
+ action: new contentState.UpdateCursorPositionAction(this.getNextRTENode(lineBreakNode), 0),
3168
+ };
3014
3169
  }
3015
3170
  /**
3016
3171
  * Returns the next sibling node of a given block element in a rich text editor.
@@ -3047,15 +3202,76 @@ class DeleteBlockContentAction extends codeBlock.ModifyContentAction {
3047
3202
  class AbstractDeleteContentHandler extends BaseHandler {
3048
3203
  /**
3049
3204
  * Delete the selected node(s) from the current state.
3205
+ *
3206
+ * @returns {CompositionStep[]} The content + caret steps applied atomically as one flushable composition.
3050
3207
  */
3051
3208
  handleEvent() {
3052
3209
  const selectedBlocks = this.selectionController.getSelectedBlocks();
3053
3210
  if (selectedBlocks.length >= 2) {
3054
3211
  this.deleteContentWithMultipleNodes();
3212
+ return [];
3055
3213
  }
3056
- else {
3057
- this.deleteContentWithSingleBlock();
3058
- }
3214
+ return this.deleteContentWithSingleBlock();
3215
+ }
3216
+ /**
3217
+ * Builds the ordered steps for a single-block deletion: the delete runs first, then a caret step
3218
+ * reads the delete action's post-apply `previousNode`/`nextNode` to decide where the caret lands.
3219
+ *
3220
+ * @param {RTENode} resolvedNode - The node the deletion is anchored on.
3221
+ * @param {number} resolvedOffset - The caret offset within `resolvedNode` at deletion time.
3222
+ * @param {Nullable<RTENode>} caretAnchor - A node the caret must stay on regardless of the delete result.
3223
+ * @returns {CompositionStep[]} The delete step followed by the dependent caret step.
3224
+ */
3225
+ buildDeleteSteps(resolvedNode, resolvedOffset, caretAnchor) {
3226
+ // eslint-disable-next-line jsdoc/require-jsdoc
3227
+ const deleteStep = () => ({
3228
+ target: resolvedNode.parent,
3229
+ action: new DeleteBlockContentAction(resolvedNode, resolvedOffset),
3230
+ });
3231
+ // eslint-disable-next-line jsdoc/require-jsdoc
3232
+ const caretStep = (context) => {
3233
+ if (caretAnchor) {
3234
+ // A non-editable anchor (e.g. a token) expresses its caret position at the parent-block
3235
+ // level, so use its index within the parent to land right before it instead of jumping
3236
+ // to the block start.
3237
+ const caretOffset = caretAnchor.isContentEditable()
3238
+ ? 0
3239
+ : caretAnchor.parent.children.indexOf(caretAnchor);
3240
+ return {
3241
+ target: this.currentState,
3242
+ action: new contentState.UpdateCursorPositionAction(caretAnchor, caretOffset),
3243
+ };
3244
+ }
3245
+ const deleteAction = context.getAction(codeBlock.ModifyContentActionType.DELETE_BLOCK_CONTENT);
3246
+ if (deleteAction && deleteAction.previousNode) {
3247
+ const nextOffset = deleteAction.previousNode === resolvedNode
3248
+ ? Math.max(0, resolvedOffset - 1)
3249
+ : deleteAction.previousNode.getRangeEndOffset();
3250
+ return {
3251
+ target: this.currentState,
3252
+ action: new contentState.UpdateCursorPositionAction(deleteAction.previousNode, nextOffset),
3253
+ };
3254
+ }
3255
+ if (deleteAction && deleteAction.nextNode) {
3256
+ return {
3257
+ target: this.currentState,
3258
+ action: new contentState.UpdateCursorPositionAction(deleteAction.nextNode, 0),
3259
+ };
3260
+ }
3261
+ if (this.currentState.children.length === 0) {
3262
+ // Add an empty paragraph if the delete removed all content to keep a valid caret position.
3263
+ const paragraph = this.createEmptyParagraph();
3264
+ return [
3265
+ { target: this.currentState, action: new codeBlock.AppendChildrenAction([paragraph]) },
3266
+ {
3267
+ target: this.currentState,
3268
+ action: new contentState.UpdateCursorPositionAction(paragraph.children[0], 1),
3269
+ },
3270
+ ];
3271
+ }
3272
+ return undefined;
3273
+ };
3274
+ return [deleteStep, caretStep];
3059
3275
  }
3060
3276
  /**
3061
3277
  * Computes the caret position one step to the right, used to translate a forward delete into a backspace.
@@ -3184,27 +3400,21 @@ class AbstractDeleteContentHandler extends BaseHandler {
3184
3400
  block.parent.apply(new codeBlock.RemoveChildrenAction(block));
3185
3401
  }
3186
3402
  }
3187
- /**
3188
- * Creates a new paragraph element with a text node and appends it to the current state.
3189
- */
3190
- insertDefaultParagraph() {
3191
- const paragraph = this.createEmptyParagraph();
3192
- this.currentState.apply(new codeBlock.AppendChildrenAction([paragraph]));
3193
- this.selectionController.enqueueSelectionRangeFutureState(paragraph.children[0], 1);
3194
- }
3195
3403
  }
3196
3404
 
3197
3405
  /** Handles a delete (rightward) deletion of content within a VegaRTE editor. User press delete will trigger this method */
3198
3406
  class ForwardDeleteContentHandler extends AbstractDeleteContentHandler {
3199
3407
  /**
3200
3408
  * Handles a delete (rightward) deletion of content within a single block in an RTE editor.
3409
+ *
3410
+ * @returns {Nullable<CompositionStep[]>} The delete + caret steps, empty when the deletion is delegated or a no-op.
3201
3411
  */
3202
3412
  deleteContentWithSingleBlock() {
3203
3413
  const range = this.selectionController.getCurrentRange();
3204
3414
  const { startOffset, endOffset, startContainer, endContainer } = range;
3205
3415
  if (startOffset !== endOffset || startContainer !== endContainer) {
3206
3416
  this.deleteContentWithMultipleNodes();
3207
- return;
3417
+ return [];
3208
3418
  }
3209
3419
  const targetNode = this.selectionController.getSelectedNodes()[0];
3210
3420
  // The node that should hold the caret after a forward delete removes a non-editable
@@ -3228,7 +3438,8 @@ class ForwardDeleteContentHandler extends AbstractDeleteContentHandler {
3228
3438
  const forwardPosition = this.getForwardDeletePosition(targetNode, startOffset);
3229
3439
  // The caret is at the very end of the content, there is nothing to delete forward.
3230
3440
  if (!forwardPosition) {
3231
- return;
3441
+ // Nothing changes, so we return undefined to indicate no composition steps are needed.
3442
+ return undefined;
3232
3443
  }
3233
3444
  // Mirror backspace at heterogeneous block boundaries: a forward delete that crosses
3234
3445
  // into a following block of a different type (e.g. paragraph → list-item, or into an
@@ -3239,8 +3450,11 @@ class ForwardDeleteContentHandler extends AbstractDeleteContentHandler {
3239
3450
  if (targetNode &&
3240
3451
  forwardPosition.node.parent !== targetNode.parent &&
3241
3452
  forwardPosition.node.parent.type !== targetNode.parent.type) {
3242
- this.selectionController.enqueueSelectionRangeFutureState(forwardPosition.node, 0);
3243
- return;
3453
+ const caretOperation = {
3454
+ target: this.currentState,
3455
+ action: new contentState.UpdateCursorPositionAction(forwardPosition.node, 0),
3456
+ };
3457
+ return [caretOperation];
3244
3458
  }
3245
3459
  // When the caret sits at the start of a non-editable leading node (e.g. a function
3246
3460
  // keyword or a token), a forward delete removes that node. Visually the caret stays
@@ -3255,34 +3469,9 @@ class ForwardDeleteContentHandler extends AbstractDeleteContentHandler {
3255
3469
  }
3256
3470
  /* istanbul ignore next */
3257
3471
  if (!resolvedNode) {
3258
- return;
3259
- }
3260
- const deleteAction = new DeleteBlockContentAction(resolvedNode, resolvedOffset);
3261
- resolvedNode.parent.apply(deleteAction);
3262
- if (forwardCaretAnchor) {
3263
- // A non-editable anchor (e.g. a token) expresses its caret position at the
3264
- // parent-block level: its range container is the parent element, so an offset of
3265
- // 0 would put the caret at the very start of the block (jumping to the far left)
3266
- // instead of just before the anchor. Use the anchor's index within its parent so
3267
- // the caret lands right before it, on the spot the deleted node used to occupy.
3268
- const forwardCaretOffset = forwardCaretAnchor.isContentEditable()
3269
- ? 0
3270
- : forwardCaretAnchor.parent.children.indexOf(forwardCaretAnchor);
3271
- this.selectionController.enqueueSelectionRangeFutureState(forwardCaretAnchor, forwardCaretOffset);
3272
- }
3273
- else if (deleteAction.previousNode) {
3274
- const nextOffset = deleteAction.previousNode === resolvedNode
3275
- ? Math.max(0, resolvedOffset - 1)
3276
- : deleteAction.previousNode.getRangeEndOffset();
3277
- this.selectionController.enqueueSelectionRangeFutureState(deleteAction.previousNode, nextOffset);
3278
- }
3279
- else if (deleteAction.nextNode) {
3280
- this.selectionController.enqueueSelectionRangeFutureState(deleteAction.nextNode, 0);
3281
- }
3282
- else if (this.currentState.children.length === 0) {
3283
- // Add a empty paragraph if delete all content to make sure the caret position
3284
- this.insertDefaultParagraph();
3472
+ return [];
3285
3473
  }
3474
+ return this.buildDeleteSteps(resolvedNode, resolvedOffset, forwardCaretAnchor);
3286
3475
  }
3287
3476
  }
3288
3477
 
@@ -3290,33 +3479,21 @@ class ForwardDeleteContentHandler extends AbstractDeleteContentHandler {
3290
3479
  class BackwardDeleteContentHandler extends AbstractDeleteContentHandler {
3291
3480
  /**
3292
3481
  * Handles a backspace (leftward) deletion of content within a single block in an RTE editor.
3482
+ *
3483
+ * @returns {Nullable<CompositionStep[]>} The delete + caret steps, empty when the deletion is delegated or a no-op.
3293
3484
  */
3294
3485
  deleteContentWithSingleBlock() {
3295
3486
  const range = this.selectionController.getCurrentRange();
3296
3487
  const { startOffset, endOffset, startContainer, endContainer } = range;
3297
3488
  if (startOffset !== endOffset || startContainer !== endContainer) {
3298
3489
  this.deleteContentWithMultipleNodes();
3299
- return;
3490
+ return [];
3300
3491
  }
3301
3492
  const targetNode = this.selectionController.getSelectedNodes()[0];
3302
3493
  if (!targetNode) {
3303
3494
  return;
3304
3495
  }
3305
- const deleteAction = new DeleteBlockContentAction(targetNode, startOffset);
3306
- targetNode.parent.apply(deleteAction);
3307
- if (deleteAction.previousNode) {
3308
- const nextOffset = deleteAction.previousNode === targetNode
3309
- ? Math.max(0, startOffset - 1)
3310
- : deleteAction.previousNode.getRangeEndOffset();
3311
- this.selectionController.enqueueSelectionRangeFutureState(deleteAction.previousNode, nextOffset);
3312
- }
3313
- else if (deleteAction.nextNode) {
3314
- this.selectionController.enqueueSelectionRangeFutureState(deleteAction.nextNode, 0);
3315
- }
3316
- else if (this.currentState.children.length === 0) {
3317
- // Add a empty paragraph if delete all content to make sure the caret position
3318
- this.insertDefaultParagraph();
3319
- }
3496
+ return this.buildDeleteSteps(targetNode, startOffset, null);
3320
3497
  }
3321
3498
  }
3322
3499
 
@@ -3346,53 +3523,57 @@ class InsertPasteHandler extends BaseHandler {
3346
3523
  * Update the state value when user paste html elements.
3347
3524
  *
3348
3525
  * @param {InputEvent} event - Paste event.
3526
+ * @returns {CompositionStep[]} The content + caret steps applied atomically as one flushable composition.
3349
3527
  */
3350
3528
  handleEvent(event) {
3351
3529
  const currentRange = this.selectionController.getCurrentRange();
3352
3530
  const payload = this.getPastePayload(event);
3353
- if (this.insertPlainTextInline(payload, currentRange)) {
3354
- return;
3531
+ const inlineSteps = this.insertPlainTextInline(payload, currentRange);
3532
+ if (inlineSteps) {
3533
+ return inlineSteps;
3355
3534
  }
3356
- const blocks = this.parsePastedElements(event);
3535
+ const blocks = this.parsePastedElements(event, currentRange);
3357
3536
  const startContainer = (currentRange === null || currentRange === void 0 ? void 0 : currentRange.startContainer) || undefined;
3358
3537
  if (!startContainer) {
3359
3538
  // When the selection/range is unavailable (e.g. the caret was lost while
3360
3539
  // the paste-mode chooser had focus), still append the pasted content to
3361
3540
  // the root so the paste is never silently dropped.
3362
- this.insertBlocksToRoot(blocks);
3541
+ return this.insertBlocksToRoot(blocks);
3363
3542
  }
3364
- else if (this.isRootContainer(startContainer)) {
3365
- this.insertBlocksToRoot(blocks);
3543
+ if (this.isRootContainer(startContainer)) {
3366
3544
  // TODO: Need to check below logic, it seems not correct https://gethired.atlassian.net/browse/VD-7779
3545
+ return this.insertBlocksToRoot(blocks);
3367
3546
  }
3368
- else if (this.isEmptyParagraph(startContainer)) {
3369
- this.insertBlocksBeforeEmptyBlock(blocks, currentRange);
3370
- }
3371
- else {
3372
- this.insertBlocksToContent(blocks, currentRange);
3547
+ if (this.isEmptyParagraph(startContainer)) {
3548
+ return this.insertBlocksBeforeEmptyBlock(blocks, currentRange);
3373
3549
  }
3550
+ return this.insertBlocksToContent(blocks, currentRange);
3374
3551
  }
3375
3552
  /**
3376
3553
  * Inserts plain-text paste content into the current text node at caret position.
3377
3554
  *
3378
3555
  * @param {RTEPastePayload} payload - Clipboard payload.
3379
3556
  * @param {RTERange} currentRange - Current selection range.
3380
- * @returns {boolean} True when inline insertion is handled.
3557
+ * @returns {CompositionStep[] | undefined} The content + caret steps when inline insertion applies, otherwise undefined.
3381
3558
  */
3382
3559
  insertPlainTextInline(payload, currentRange) {
3383
3560
  var _a, _b;
3384
3561
  const selectedNodes = ((_b = (_a = this.selectionController).getSelectedNodes) === null || _b === void 0 ? void 0 : _b.call(_a)) || [];
3385
3562
  if (!this.shouldPasteAsInlinePlainText(payload, currentRange, selectedNodes)) {
3386
- return false;
3563
+ return undefined;
3387
3564
  }
3388
3565
  const text = payload.text.replace(/\r\n?/g, '\n');
3389
3566
  const cursorNode = selectedNodes.find((node) => node instanceof codeBlock.RTETextNode) || currentRange.startNode;
3390
3567
  if (!(cursorNode instanceof codeBlock.RTETextNode)) {
3391
- return false;
3568
+ return undefined;
3392
3569
  }
3393
- cursorNode.apply(new imageExtension.ReplaceSelectedTextAction(text, currentRange));
3394
- this.selectionController.enqueueSelectionRangeFutureState(cursorNode, currentRange.startOffset + text.length);
3395
- return true;
3570
+ return [
3571
+ { target: cursorNode, action: new imageExtension.ReplaceSelectedTextAction(text, currentRange) },
3572
+ {
3573
+ target: this.currentState,
3574
+ action: new contentState.UpdateCursorPositionAction(cursorNode, currentRange.startOffset + text.length),
3575
+ },
3576
+ ];
3396
3577
  }
3397
3578
  /**
3398
3579
  * Determines whether the payload should be inserted as inline plain text.
@@ -3457,68 +3638,116 @@ class InsertPasteHandler extends BaseHandler {
3457
3638
  * Insert the blocks to root
3458
3639
  *
3459
3640
  * @param { RTEContentBlock[]} blocks - blocks
3641
+ * @returns {CompositionStep[]} The append step for the root.
3460
3642
  */
3461
3643
  insertBlocksToRoot(blocks) {
3462
- this.currentState.apply(new codeBlock.AppendChildrenAction(blocks));
3644
+ return [{ target: this.currentState, action: new codeBlock.AppendChildrenAction(blocks) }];
3463
3645
  }
3464
3646
  /**
3465
3647
  * Insert the blocks into the current content block at the specified range.
3466
3648
  *
3467
3649
  * @param { RTEContentBlock[]} blocks - blocks
3468
3650
  * @param { RTERange } rteRange - rteRange
3651
+ * @returns {CompositionStep[]} The content + caret steps for the content branch.
3469
3652
  */
3470
3653
  insertBlocksToContent(blocks, rteRange) {
3471
- var _a;
3472
3654
  const isCollapsedRange = rteRange.startNode === rteRange.endNode && rteRange.startOffset === rteRange.endOffset;
3473
3655
  const cursorNode = isCollapsedRange
3474
3656
  ? rteRange.startNode
3475
3657
  : this.removeSelectionRange();
3476
3658
  if (cursorNode && cursorNode.parent) {
3477
- const pasteAction = new PasteContentAction(blocks, cursorNode, rteRange.startOffset, rteRange);
3478
- cursorNode.parent.apply(pasteAction);
3479
- if (pasteAction.futureFocusNode) {
3480
- this.selectionController.enqueueSelectionRangeFutureState(pasteAction.futureFocusNode, (_a = pasteAction.futureFocusNodeOffset) !== null && _a !== void 0 ? _a : 0);
3481
- }
3482
- else if (pasteAction.futureFocusBlock) {
3483
- this.switchCaretPositionToNextElement(pasteAction.futureFocusBlock, pasteAction.futureFocusAtEnd);
3484
- }
3485
- }
3486
- else {
3487
- // No resolvable cursor position: fall back to appending at the root so
3488
- // the pasted content is preserved instead of being discarded.
3489
- this.insertBlocksToRoot(blocks);
3659
+ const contentStep = {
3660
+ target: cursorNode.parent,
3661
+ action: new PasteContentAction(blocks, cursorNode, rteRange.startOffset, rteRange),
3662
+ };
3663
+ // eslint-disable-next-line jsdoc/require-jsdoc
3664
+ const caretStep = (context) => {
3665
+ var _a;
3666
+ const pasteAction = context.getAction(codeBlock.ModifyContentActionType.PASTE_CONTENT);
3667
+ if (pasteAction && pasteAction.futureFocusNode) {
3668
+ return {
3669
+ target: this.currentState,
3670
+ action: new contentState.UpdateCursorPositionAction(pasteAction.futureFocusNode, (_a = pasteAction.futureFocusNodeOffset) !== null && _a !== void 0 ? _a : 0),
3671
+ };
3672
+ }
3673
+ if (pasteAction && pasteAction.futureFocusBlock) {
3674
+ return this.caretToBlockOperation(pasteAction.futureFocusBlock, pasteAction.futureFocusAtEnd);
3675
+ }
3676
+ };
3677
+ return [contentStep, caretStep];
3490
3678
  }
3679
+ // No resolvable cursor position: fall back to appending at the root so
3680
+ // the pasted content is preserved instead of being discarded.
3681
+ return this.insertBlocksToRoot(blocks);
3491
3682
  }
3492
3683
  /**
3493
3684
  * Insert the blocks before to current block
3494
3685
  *
3495
3686
  * @param { RTEContentBlock[]} blocks - blocks
3496
3687
  * @param { RTERange } rteRange - rteRange
3688
+ * @returns {CompositionStep[]} The content + caret steps for the empty-paragraph branch.
3497
3689
  */
3498
3690
  insertBlocksBeforeEmptyBlock(blocks, rteRange) {
3499
3691
  const cursorNode = this.removeSelectionRange();
3500
3692
  const currentBlock = cursorNode === null || cursorNode === void 0 ? void 0 : cursorNode.parent;
3501
3693
  if (currentBlock) {
3502
- const pasteAction = new PasteContentAction(blocks, cursorNode, 0, rteRange);
3503
- currentBlock.apply(pasteAction);
3504
- if (pasteAction.futureFocusBlock) {
3505
- this.switchCaretPositionToNextElement(pasteAction.futureFocusBlock, pasteAction.futureFocusAtEnd);
3506
- }
3507
- }
3508
- else {
3509
- // No resolvable empty block: fall back to appending at the root so the
3510
- // pasted content is preserved instead of being discarded.
3511
- this.insertBlocksToRoot(blocks);
3694
+ const contentStep = {
3695
+ target: currentBlock,
3696
+ action: new PasteContentAction(blocks, cursorNode, 0, rteRange),
3697
+ };
3698
+ // eslint-disable-next-line jsdoc/require-jsdoc
3699
+ const caretStep = (context) => {
3700
+ const pasteAction = context.getAction(codeBlock.ModifyContentActionType.PASTE_CONTENT);
3701
+ if (pasteAction && pasteAction.futureFocusBlock) {
3702
+ return this.caretToBlockOperation(pasteAction.futureFocusBlock, pasteAction.futureFocusAtEnd);
3703
+ }
3704
+ };
3705
+ return [contentStep, caretStep];
3512
3706
  }
3707
+ // No resolvable empty block: fall back to appending at the root so the
3708
+ // pasted content is preserved instead of being discarded.
3709
+ return this.insertBlocksToRoot(blocks);
3513
3710
  }
3514
3711
  /**
3515
3712
  * Format and parse elements from user paste with simple style preservation.
3516
3713
  *
3517
3714
  * @param {InputEvent} event - Paste event.
3715
+ * @param {RTERange} [currentRange] - Optional range used to resolve the paste location.
3518
3716
  * @returns {RTEContentBlock[]} - RTEContentBlock.
3519
3717
  */
3520
- parsePastedElements(event) {
3718
+ parsePastedElements(event, currentRange) {
3719
+ var _a;
3521
3720
  const payload = this.getPastePayload(event);
3721
+ if (payload.type === codeBlock.RTE_PASTE_MODE_PLAIN) {
3722
+ // Native tables encode their layout as tab-separated cells (one row per line) in
3723
+ // text/plain, so pasting that verbatim keeps the rows/columns. Non-native tables (rich text
3724
+ // editor tables) put a blank line between cells in text/plain, so they derive from HTML
3725
+ // instead: htmlToPlainText puts each cell on its own line with no gaps while keeping in-cell breaks.
3726
+ let plainText;
3727
+ let hasEncodedWhitespace = (_a = payload.hasEncodedWhitespace) !== null && _a !== void 0 ? _a : false;
3728
+ if (payload.html &&
3729
+ payload.text &&
3730
+ payload.text.includes('\t') &&
3731
+ imageExtension.htmlContainsTable(payload.html)) {
3732
+ plainText = payload.text;
3733
+ }
3734
+ else if (payload.html && imageExtension.htmlContainsTable(payload.html)) {
3735
+ plainText = this.extractPlainTextFromHtml(payload.html, true);
3736
+ hasEncodedWhitespace = true;
3737
+ }
3738
+ else {
3739
+ plainText = '';
3740
+ if (payload.text) {
3741
+ plainText = payload.text;
3742
+ }
3743
+ else if (payload.html) {
3744
+ plainText = this.extractPlainTextFromHtml(payload.html, true);
3745
+ hasEncodedWhitespace = true;
3746
+ }
3747
+ }
3748
+ const styleSource = (currentRange === null || currentRange === void 0 ? void 0 : currentRange.startNode) instanceof codeBlock.RTETextNode ? currentRange.startNode : undefined;
3749
+ return this.buildPlainTextParagraph(plainText, styleSource, hasEncodedWhitespace);
3750
+ }
3522
3751
  let pastedHTML = payload.html || '';
3523
3752
  if (!pastedHTML) {
3524
3753
  pastedHTML = this.parsePlainText(payload.text || '');
@@ -3556,16 +3785,21 @@ class InsertPasteHandler extends BaseHandler {
3556
3785
  return resultBlocks;
3557
3786
  }
3558
3787
  /**
3559
- * Extracts readable plain text from clipboard HTML.
3788
+ * Extracts plain text from HTML when clipboard lacks `text/plain`.
3560
3789
  *
3561
3790
  * @param {string} html - Clipboard text/html payload.
3791
+ * @param {boolean} keepPreservedWhitespaceMarkers - Keep code-block indentation as sentinels so
3792
+ * the plain-mode boundary collapse in `toPlainPasteLines` does not strip it (that helper decodes
3793
+ * the sentinels). Must stay `false` for the rich path, which feeds `parsePlainText` directly.
3562
3794
  * @returns {string} - Plain text extracted from HTML.
3563
3795
  */
3564
- extractPlainTextFromHtml(html) {
3796
+ extractPlainTextFromHtml(html, keepPreservedWhitespaceMarkers = false) {
3565
3797
  // Preserve inline styles before parsing to avoid style-src-attr CSP violations.
3566
3798
  const safeHtml = contentState.StylePreservator.preserve(html).getProcessedHtml();
3567
- const parsedDoc = new DOMParser().parseFromString(safeHtml, 'text/html');
3568
- return (parsedDoc.body.textContent || '').replace(/\r\n?/g, '\n');
3799
+ return imageExtension.htmlToPlainText(safeHtml, {
3800
+ preserveBoundaryBlankLines: true,
3801
+ keepPreservedWhitespaceMarkers,
3802
+ });
3569
3803
  }
3570
3804
  /**
3571
3805
  * Builds plain-text paragraph blocks when element strategy parsing returns no output.
@@ -3574,7 +3808,7 @@ class InsertPasteHandler extends BaseHandler {
3574
3808
  * @returns {RTEContentBlock[]} Fallback text blocks.
3575
3809
  */
3576
3810
  buildPlainTextFallbackBlocks(text) {
3577
- return text.split('\n').map((line) => {
3811
+ return codeBlock.normalizePlainTextLines(text).map((line) => {
3578
3812
  const paragraph = new codeBlock.RTETextBlock(misc.generateUUID(), 'paragraph');
3579
3813
  const textNode = new codeBlock.RTETextNode(`${paragraph.id}1`, line, paragraph);
3580
3814
  paragraph.apply(new codeBlock.AppendChildrenAction([textNode]));
@@ -3582,21 +3816,66 @@ class InsertPasteHandler extends BaseHandler {
3582
3816
  });
3583
3817
  }
3584
3818
  /**
3585
- * Moves the caret to a block element in a rich text editor after paste.
3819
+ * Builds plain-text paragraphs by splitting on `\n`.
3820
+ *
3821
+ * Shares `toPlainPasteLines` with `PlainPasteProcessingStrategy` so both
3822
+ * representations of plain-mode content (HTML and RTE nodes) agree on line
3823
+ * boundaries and boundary whitespace.
3824
+ *
3825
+ * @param {string} text - Plain text clipboard content.
3826
+ * @param {RTETextNode} [styleSource] - Optional style to preserve in all nodes.
3827
+ * @param {boolean} decodeEncodedWhitespace - Decode HTML-derived whitespace markers.
3828
+ * @returns {RTEContentBlock[]} Paragraph-per-line blocks.
3829
+ */
3830
+ buildPlainTextParagraph(text, styleSource, decodeEncodedWhitespace = false) {
3831
+ const lines = codeBlock.toPlainPasteLines(text, decodeEncodedWhitespace);
3832
+ return lines.map((line, lineIndex) => {
3833
+ const paragraph = new codeBlock.RTETextBlock(misc.generateUUID(), 'paragraph');
3834
+ // Always attach a text node (empty for blank lines) so empty paragraphs
3835
+ // render with a zero-width space and keep their visible line height,
3836
+ // instead of collapsing to an invisible zero-height `<p></p>`.
3837
+ const node = this.createPlainTextNode(paragraph, lineIndex, line, styleSource);
3838
+ paragraph.apply(new codeBlock.AppendChildrenAction([node]));
3839
+ return paragraph;
3840
+ });
3841
+ }
3842
+ /**
3843
+ * Creates a text node for plain paste; optionally inherits style from source node.
3844
+ *
3845
+ * @param {RTETextBlock} paragraph - Parent paragraph.
3846
+ * @param {number} index - Character index for node ID generation.
3847
+ * @param {string} text - Text content.
3848
+ * @param {RTETextNode} [styleSource] - Optional style to inherit.
3849
+ * @returns {RTETextNode} Created text node.
3850
+ */
3851
+ createPlainTextNode(paragraph, index, text, styleSource) {
3852
+ const node = styleSource
3853
+ ? styleSource.cloneWithText(text)
3854
+ : new codeBlock.RTETextNode(`${paragraph.id}-${index}`, text, paragraph);
3855
+ node.parent = paragraph;
3856
+ return node;
3857
+ }
3858
+ /**
3859
+ * Builds the caret operation that moves onto a block element in a rich text editor after paste.
3586
3860
  *
3587
3861
  * @param {RTEBlock} newBlock - Block element to move the caret to.
3588
3862
  * @param {boolean} atEnd - When true, places the caret after the last character of the block's last node; otherwise at offset 0 of the first node.
3863
+ * @returns {CompositionOperation | void} The caret operation, or nothing when the block has no children.
3589
3864
  */
3590
- switchCaretPositionToNextElement(newBlock, atEnd = false) {
3865
+ caretToBlockOperation(newBlock, atEnd = false) {
3591
3866
  var _a, _b;
3592
3867
  if (newBlock && newBlock.children) {
3593
3868
  if (atEnd) {
3594
3869
  const lastNode = newBlock.children[newBlock.children.length - 1];
3595
- this.selectionController.enqueueSelectionRangeFutureState(lastNode, (_b = (_a = lastNode.text) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0);
3596
- }
3597
- else {
3598
- this.selectionController.enqueueSelectionRangeFutureState(newBlock.children[0], 0);
3870
+ return {
3871
+ target: this.currentState,
3872
+ action: new contentState.UpdateCursorPositionAction(lastNode, (_b = (_a = lastNode.text) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0),
3873
+ };
3599
3874
  }
3875
+ return {
3876
+ target: this.currentState,
3877
+ action: new contentState.UpdateCursorPositionAction(newBlock.children[0], 0),
3878
+ };
3600
3879
  }
3601
3880
  }
3602
3881
  /**
@@ -3816,6 +4095,7 @@ class InsertPasteHandler extends BaseHandler {
3816
4095
  html: event.dataTransfer.getData('text/html') || eventPayload.html || '',
3817
4096
  text: event.dataTransfer.getData('text/plain') || eventPayload.text || '',
3818
4097
  type: event.dataTransfer.getData(codeBlock.RTE_PASTE_MODE_DATA_TYPE) || '',
4098
+ hasEncodedWhitespace: event.dataTransfer.getData(codeBlock.RTE_PRESERVED_WHITESPACE_DATA_TYPE) === 'true',
3819
4099
  };
3820
4100
  }
3821
4101
  }
@@ -4140,6 +4420,8 @@ class UserInputController extends globalSlimmerRegistry.VegaSlimmer {
4140
4420
  };
4141
4421
  /**
4142
4422
  * When a user performs an input action within the editable element, this function is triggered.
4423
+ * Each handler owns its own `flushOptions` on `BaseHandler`, so the value update flows through
4424
+ * the shared flush-changes action pipeline without this method having to construct or forward it.
4143
4425
  *
4144
4426
  * @param {InputEvent} e the before input event object
4145
4427
  */
@@ -4153,41 +4435,26 @@ class UserInputController extends globalSlimmerRegistry.VegaSlimmer {
4153
4435
  return;
4154
4436
  }
4155
4437
  this.insertCompositionTextController.removeObserver();
4156
- let updateFlag = false;
4157
- let updateSource = codeBlock.RTEUpdateSource.Default;
4158
4438
  switch (inputType) {
4159
4439
  case 'insertParagraph':
4160
- updateFlag = true;
4161
4440
  this.insertParagraphHandler.execute(this.value, this.selectionController, this.host, e);
4162
4441
  break;
4163
4442
  case 'insertText':
4164
- updateFlag = true;
4165
- updateSource =
4166
- e[codeBlock.RTE_UPDATE_SOURCE_KEY] === codeBlock.RTEUpdateSource.Composition
4167
- ? codeBlock.RTEUpdateSource.Composition
4168
- : codeBlock.RTEUpdateSource.Default;
4169
4443
  this.insertTextHandler.execute(this.value, this.selectionController, this.host, e);
4170
4444
  break;
4171
4445
  case 'insertLineBreak':
4172
- updateFlag = true;
4173
4446
  this.insertLineBreakHandler.execute(this.value, this.selectionController, this.host, e);
4174
4447
  break;
4175
4448
  case 'deleteContentForward':
4176
- updateFlag = true;
4177
4449
  this.forwardDeleteContentHandler.execute(this.value, this.selectionController, this.host, e);
4178
4450
  break;
4179
4451
  case 'deleteContentBackward':
4180
- updateFlag = true;
4181
4452
  this.backwardDeleteContentHandler.execute(this.value, this.selectionController, this.host, e);
4182
4453
  break;
4183
4454
  case 'insertFromPaste':
4184
- updateFlag = true;
4185
4455
  this.insertPasteHandler.execute(this.value, this.selectionController, this.host, e);
4186
4456
  break;
4187
4457
  }
4188
- if (updateFlag) {
4189
- void this.valueController.flushChanges(this.value, true, updateSource);
4190
- }
4191
4458
  };
4192
4459
  }
4193
4460
  /**