@wordpress/editor 14.41.0 → 14.41.2-next.v.202603161435.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 (326) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/build/components/collab-sidebar/index.cjs +7 -4
  3. package/build/components/collab-sidebar/index.cjs.map +2 -2
  4. package/build/components/collab-sidebar/utils.cjs +13 -15
  5. package/build/components/collab-sidebar/utils.cjs.map +2 -2
  6. package/build/components/collaborators-overlay/avatar-iframe-styles.cjs +141 -0
  7. package/build/components/collaborators-overlay/avatar-iframe-styles.cjs.map +7 -0
  8. package/build/components/collaborators-overlay/collaborator-styles.cjs +38 -2
  9. package/build/components/collaborators-overlay/collaborator-styles.cjs.map +2 -2
  10. package/build/components/collaborators-overlay/compute-selection.cjs +181 -0
  11. package/build/components/collaborators-overlay/compute-selection.cjs.map +7 -0
  12. package/build/components/collaborators-overlay/cursor-dom-utils.cjs +243 -0
  13. package/build/components/collaborators-overlay/cursor-dom-utils.cjs.map +7 -0
  14. package/build/components/collaborators-overlay/overlay-iframe-styles.cjs +148 -0
  15. package/build/components/collaborators-overlay/overlay-iframe-styles.cjs.map +7 -0
  16. package/build/components/collaborators-overlay/overlay.cjs +100 -229
  17. package/build/components/collaborators-overlay/overlay.cjs.map +3 -3
  18. package/build/components/collaborators-overlay/use-block-highlighting.cjs +90 -42
  19. package/build/components/collaborators-overlay/use-block-highlighting.cjs.map +2 -2
  20. package/build/components/collaborators-overlay/use-debounced-recompute.cjs +49 -0
  21. package/build/components/collaborators-overlay/use-debounced-recompute.cjs.map +7 -0
  22. package/build/components/collaborators-overlay/use-render-cursors.cjs +80 -171
  23. package/build/components/collaborators-overlay/use-render-cursors.cjs.map +3 -3
  24. package/build/components/collaborators-presence/avatar/component.cjs +121 -0
  25. package/build/components/collaborators-presence/avatar/component.cjs.map +7 -0
  26. package/build/components/collaborators-presence/avatar/index.cjs +37 -0
  27. package/build/components/collaborators-presence/avatar/index.cjs.map +7 -0
  28. package/build/components/collaborators-presence/avatar/types.cjs +19 -0
  29. package/build/components/collaborators-presence/avatar/types.cjs.map +7 -0
  30. package/build/components/collaborators-presence/avatar/use-image-loading-status.cjs +44 -0
  31. package/build/components/collaborators-presence/avatar/use-image-loading-status.cjs.map +7 -0
  32. package/build/components/collaborators-presence/avatar-group/component.cjs +78 -0
  33. package/build/components/collaborators-presence/avatar-group/component.cjs.map +7 -0
  34. package/build/components/collaborators-presence/avatar-group/index.cjs +37 -0
  35. package/build/components/collaborators-presence/avatar-group/index.cjs.map +7 -0
  36. package/build/components/collaborators-presence/avatar-group/types.cjs +19 -0
  37. package/build/components/collaborators-presence/avatar-group/types.cjs.map +7 -0
  38. package/build/components/collaborators-presence/index.cjs +54 -17
  39. package/build/components/collaborators-presence/index.cjs.map +3 -3
  40. package/build/components/collaborators-presence/list.cjs +43 -37
  41. package/build/components/collaborators-presence/list.cjs.map +3 -3
  42. package/build/components/collaborators-presence/use-collaborator-notifications.cjs +79 -107
  43. package/build/components/collaborators-presence/use-collaborator-notifications.cjs.map +3 -3
  44. package/build/components/editor-interface/index.cjs +9 -6
  45. package/build/components/editor-interface/index.cjs.map +2 -2
  46. package/build/components/entities-saved-states/hooks/use-is-dirty.cjs +14 -5
  47. package/build/components/entities-saved-states/hooks/use-is-dirty.cjs.map +2 -2
  48. package/build/components/global-styles/index.cjs +15 -24
  49. package/build/components/global-styles/index.cjs.map +3 -3
  50. package/build/components/global-styles-sidebar/index.cjs +6 -3
  51. package/build/components/global-styles-sidebar/index.cjs.map +2 -2
  52. package/build/components/inserter-sidebar/index.cjs +2 -1
  53. package/build/components/inserter-sidebar/index.cjs.map +2 -2
  54. package/build/components/page-attributes/parent.cjs +2 -1
  55. package/build/components/page-attributes/parent.cjs.map +2 -2
  56. package/build/components/post-revisions-preview/revisions-canvas.cjs +8 -58
  57. package/build/components/post-revisions-preview/revisions-canvas.cjs.map +3 -3
  58. package/build/components/post-revisions-preview/revisions-slider.cjs +5 -1
  59. package/build/components/post-revisions-preview/revisions-slider.cjs.map +2 -2
  60. package/build/components/post-url/panel.cjs +1 -0
  61. package/build/components/post-url/panel.cjs.map +2 -2
  62. package/build/components/preferences-modal/index.cjs +24 -0
  63. package/build/components/preferences-modal/index.cjs.map +2 -2
  64. package/build/components/provider/disable-non-page-content-blocks.cjs +31 -28
  65. package/build/components/provider/disable-non-page-content-blocks.cjs.map +3 -3
  66. package/build/components/provider/index.cjs +17 -5
  67. package/build/components/provider/index.cjs.map +2 -2
  68. package/build/components/provider/use-block-editor-settings.cjs +21 -6
  69. package/build/components/provider/use-block-editor-settings.cjs.map +3 -3
  70. package/build/components/provider/{use-post-content-blocks.cjs → use-post-content-block-types.cjs} +8 -19
  71. package/build/components/provider/use-post-content-block-types.cjs.map +7 -0
  72. package/build/components/provider/use-revision-blocks.cjs +106 -0
  73. package/build/components/provider/use-revision-blocks.cjs.map +7 -0
  74. package/build/components/sidebar/dataform-post-summary.cjs +182 -0
  75. package/build/components/sidebar/dataform-post-summary.cjs.map +7 -0
  76. package/build/components/sidebar/header.cjs +1 -1
  77. package/build/components/sidebar/header.cjs.map +2 -2
  78. package/build/components/sidebar/post-summary.cjs +11 -0
  79. package/build/components/sidebar/post-summary.cjs.map +3 -3
  80. package/build/components/sync-connection-modal/index.cjs +8 -5
  81. package/build/components/sync-connection-modal/index.cjs.map +2 -2
  82. package/build/components/template-content-panel/index.cjs +35 -31
  83. package/build/components/template-content-panel/index.cjs.map +3 -3
  84. package/build/components/visual-editor/index.cjs +1 -1
  85. package/build/components/visual-editor/index.cjs.map +2 -2
  86. package/build/dataviews/store/private-actions.cjs +4 -0
  87. package/build/dataviews/store/private-actions.cjs.map +2 -2
  88. package/build/store/private-actions.cjs +11 -2
  89. package/build/store/private-actions.cjs.map +2 -2
  90. package/build/store/private-selectors.cjs +52 -13
  91. package/build/store/private-selectors.cjs.map +2 -2
  92. package/build/store/reducer.cjs +12 -0
  93. package/build/store/reducer.cjs.map +2 -2
  94. package/build/utils/media-upload/on-success.cjs +46 -0
  95. package/build/utils/media-upload/on-success.cjs.map +7 -0
  96. package/build-module/components/collab-sidebar/index.mjs +7 -4
  97. package/build-module/components/collab-sidebar/index.mjs.map +2 -2
  98. package/build-module/components/collab-sidebar/utils.mjs +13 -15
  99. package/build-module/components/collab-sidebar/utils.mjs.map +2 -2
  100. package/build-module/components/collaborators-overlay/avatar-iframe-styles.mjs +128 -0
  101. package/build-module/components/collaborators-overlay/avatar-iframe-styles.mjs.map +7 -0
  102. package/build-module/components/collaborators-overlay/collaborator-styles.mjs +25 -1
  103. package/build-module/components/collaborators-overlay/collaborator-styles.mjs.map +2 -2
  104. package/build-module/components/collaborators-overlay/compute-selection.mjs +162 -0
  105. package/build-module/components/collaborators-overlay/compute-selection.mjs.map +7 -0
  106. package/build-module/components/collaborators-overlay/cursor-dom-utils.mjs +213 -0
  107. package/build-module/components/collaborators-overlay/cursor-dom-utils.mjs.map +7 -0
  108. package/build-module/components/collaborators-overlay/overlay-iframe-styles.mjs +130 -0
  109. package/build-module/components/collaborators-overlay/overlay-iframe-styles.mjs.map +7 -0
  110. package/build-module/components/collaborators-overlay/overlay.mjs +91 -230
  111. package/build-module/components/collaborators-overlay/overlay.mjs.map +2 -2
  112. package/build-module/components/collaborators-overlay/use-block-highlighting.mjs +91 -43
  113. package/build-module/components/collaborators-overlay/use-block-highlighting.mjs.map +2 -2
  114. package/build-module/components/collaborators-overlay/use-debounced-recompute.mjs +24 -0
  115. package/build-module/components/collaborators-overlay/use-debounced-recompute.mjs.map +7 -0
  116. package/build-module/components/collaborators-overlay/use-render-cursors.mjs +81 -172
  117. package/build-module/components/collaborators-overlay/use-render-cursors.mjs.map +2 -2
  118. package/build-module/components/collaborators-presence/avatar/component.mjs +90 -0
  119. package/build-module/components/collaborators-presence/avatar/component.mjs.map +7 -0
  120. package/build-module/components/collaborators-presence/avatar/index.mjs +6 -0
  121. package/build-module/components/collaborators-presence/avatar/index.mjs.map +7 -0
  122. package/build-module/components/collaborators-presence/avatar/types.mjs +1 -0
  123. package/build-module/components/collaborators-presence/avatar/types.mjs.map +7 -0
  124. package/build-module/components/collaborators-presence/avatar/use-image-loading-status.mjs +19 -0
  125. package/build-module/components/collaborators-presence/avatar/use-image-loading-status.mjs.map +7 -0
  126. package/build-module/components/collaborators-presence/avatar-group/component.mjs +47 -0
  127. package/build-module/components/collaborators-presence/avatar-group/component.mjs.map +7 -0
  128. package/build-module/components/collaborators-presence/avatar-group/index.mjs +6 -0
  129. package/build-module/components/collaborators-presence/avatar-group/index.mjs.map +7 -0
  130. package/build-module/components/collaborators-presence/avatar-group/types.mjs +1 -0
  131. package/build-module/components/collaborators-presence/avatar-group/types.mjs.map +7 -0
  132. package/build-module/components/collaborators-presence/index.mjs +45 -21
  133. package/build-module/components/collaborators-presence/index.mjs.map +2 -2
  134. package/build-module/components/collaborators-presence/list.mjs +35 -43
  135. package/build-module/components/collaborators-presence/list.mjs.map +2 -2
  136. package/build-module/components/collaborators-presence/use-collaborator-notifications.mjs +80 -108
  137. package/build-module/components/collaborators-presence/use-collaborator-notifications.mjs.map +2 -2
  138. package/build-module/components/editor-interface/index.mjs +10 -7
  139. package/build-module/components/editor-interface/index.mjs.map +2 -2
  140. package/build-module/components/entities-saved-states/hooks/use-is-dirty.mjs +14 -5
  141. package/build-module/components/entities-saved-states/hooks/use-is-dirty.mjs.map +2 -2
  142. package/build-module/components/global-styles/index.mjs +15 -24
  143. package/build-module/components/global-styles/index.mjs.map +2 -2
  144. package/build-module/components/global-styles-sidebar/index.mjs +6 -3
  145. package/build-module/components/global-styles-sidebar/index.mjs.map +2 -2
  146. package/build-module/components/inserter-sidebar/index.mjs +2 -1
  147. package/build-module/components/inserter-sidebar/index.mjs.map +2 -2
  148. package/build-module/components/page-attributes/parent.mjs +2 -1
  149. package/build-module/components/page-attributes/parent.mjs.map +2 -2
  150. package/build-module/components/post-revisions-preview/revisions-canvas.mjs +10 -63
  151. package/build-module/components/post-revisions-preview/revisions-canvas.mjs.map +2 -2
  152. package/build-module/components/post-revisions-preview/revisions-slider.mjs +5 -1
  153. package/build-module/components/post-revisions-preview/revisions-slider.mjs.map +2 -2
  154. package/build-module/components/post-url/panel.mjs +1 -0
  155. package/build-module/components/post-url/panel.mjs.map +2 -2
  156. package/build-module/components/preferences-modal/index.mjs +24 -0
  157. package/build-module/components/preferences-modal/index.mjs.map +2 -2
  158. package/build-module/components/provider/disable-non-page-content-blocks.mjs +31 -28
  159. package/build-module/components/provider/disable-non-page-content-blocks.mjs.map +2 -2
  160. package/build-module/components/provider/index.mjs +17 -5
  161. package/build-module/components/provider/index.mjs.map +2 -2
  162. package/build-module/components/provider/use-block-editor-settings.mjs +21 -6
  163. package/build-module/components/provider/use-block-editor-settings.mjs.map +2 -2
  164. package/build-module/components/provider/use-post-content-block-types.mjs +23 -0
  165. package/build-module/components/provider/use-post-content-block-types.mjs.map +7 -0
  166. package/build-module/components/provider/use-revision-blocks.mjs +81 -0
  167. package/build-module/components/provider/use-revision-blocks.mjs.map +7 -0
  168. package/build-module/components/sidebar/dataform-post-summary.mjs +151 -0
  169. package/build-module/components/sidebar/dataform-post-summary.mjs.map +7 -0
  170. package/build-module/components/sidebar/header.mjs +1 -1
  171. package/build-module/components/sidebar/header.mjs.map +2 -2
  172. package/build-module/components/sidebar/post-summary.mjs +11 -0
  173. package/build-module/components/sidebar/post-summary.mjs.map +2 -2
  174. package/build-module/components/sync-connection-modal/index.mjs +8 -5
  175. package/build-module/components/sync-connection-modal/index.mjs.map +2 -2
  176. package/build-module/components/template-content-panel/index.mjs +25 -31
  177. package/build-module/components/template-content-panel/index.mjs.map +2 -2
  178. package/build-module/components/visual-editor/index.mjs +1 -1
  179. package/build-module/components/visual-editor/index.mjs.map +2 -2
  180. package/build-module/dataviews/store/private-actions.mjs +8 -1
  181. package/build-module/dataviews/store/private-actions.mjs.map +2 -2
  182. package/build-module/store/private-actions.mjs +10 -2
  183. package/build-module/store/private-actions.mjs.map +2 -2
  184. package/build-module/store/private-selectors.mjs +50 -12
  185. package/build-module/store/private-selectors.mjs.map +2 -2
  186. package/build-module/store/reducer.mjs +11 -0
  187. package/build-module/store/reducer.mjs.map +2 -2
  188. package/build-module/utils/media-upload/on-success.mjs +25 -0
  189. package/build-module/utils/media-upload/on-success.mjs.map +7 -0
  190. package/build-style/style-rtl.css +961 -159
  191. package/build-style/style.css +961 -159
  192. package/build-types/components/collab-sidebar/index.d.ts.map +1 -1
  193. package/build-types/components/collab-sidebar/utils.d.ts.map +1 -1
  194. package/build-types/components/collaborators-overlay/avatar-iframe-styles.d.ts +11 -0
  195. package/build-types/components/collaborators-overlay/avatar-iframe-styles.d.ts.map +1 -0
  196. package/build-types/components/collaborators-overlay/collaborator-styles.d.ts +17 -2
  197. package/build-types/components/collaborators-overlay/collaborator-styles.d.ts.map +1 -1
  198. package/build-types/components/collaborators-overlay/compute-selection.d.ts +24 -0
  199. package/build-types/components/collaborators-overlay/compute-selection.d.ts.map +1 -0
  200. package/build-types/components/collaborators-overlay/cursor-dom-utils.d.ts +72 -0
  201. package/build-types/components/collaborators-overlay/cursor-dom-utils.d.ts.map +1 -0
  202. package/build-types/components/collaborators-overlay/overlay-iframe-styles.d.ts +6 -0
  203. package/build-types/components/collaborators-overlay/overlay-iframe-styles.d.ts.map +1 -0
  204. package/build-types/components/collaborators-overlay/overlay.d.ts.map +1 -1
  205. package/build-types/components/collaborators-overlay/use-block-highlighting.d.ts +21 -5
  206. package/build-types/components/collaborators-overlay/use-block-highlighting.d.ts.map +1 -1
  207. package/build-types/components/collaborators-overlay/use-debounced-recompute.d.ts +10 -0
  208. package/build-types/components/collaborators-overlay/use-debounced-recompute.d.ts.map +1 -0
  209. package/build-types/components/collaborators-overlay/use-render-cursors.d.ts +6 -1
  210. package/build-types/components/collaborators-overlay/use-render-cursors.d.ts.map +1 -1
  211. package/build-types/components/collaborators-presence/avatar/component.d.ts +7 -0
  212. package/build-types/components/collaborators-presence/avatar/component.d.ts.map +1 -0
  213. package/build-types/components/collaborators-presence/avatar/index.d.ts +3 -0
  214. package/build-types/components/collaborators-presence/avatar/index.d.ts.map +1 -0
  215. package/build-types/components/collaborators-presence/avatar/types.d.ts +66 -0
  216. package/build-types/components/collaborators-presence/avatar/types.d.ts.map +1 -0
  217. package/build-types/components/collaborators-presence/avatar/use-image-loading-status.d.ts +17 -0
  218. package/build-types/components/collaborators-presence/avatar/use-image-loading-status.d.ts.map +1 -0
  219. package/build-types/components/collaborators-presence/avatar-group/component.d.ts +7 -0
  220. package/build-types/components/collaborators-presence/avatar-group/component.d.ts.map +1 -0
  221. package/build-types/components/collaborators-presence/avatar-group/index.d.ts +3 -0
  222. package/build-types/components/collaborators-presence/avatar-group/index.d.ts.map +1 -0
  223. package/build-types/components/collaborators-presence/avatar-group/types.d.ts +14 -0
  224. package/build-types/components/collaborators-presence/avatar-group/types.d.ts.map +1 -0
  225. package/build-types/components/collaborators-presence/index.d.ts.map +1 -1
  226. package/build-types/components/collaborators-presence/list.d.ts +2 -1
  227. package/build-types/components/collaborators-presence/list.d.ts.map +1 -1
  228. package/build-types/components/collaborators-presence/use-collaborator-notifications.d.ts.map +1 -1
  229. package/build-types/components/editor-interface/index.d.ts.map +1 -1
  230. package/build-types/components/entities-saved-states/hooks/use-is-dirty.d.ts.map +1 -1
  231. package/build-types/components/global-styles/index.d.ts +2 -1
  232. package/build-types/components/global-styles/index.d.ts.map +1 -1
  233. package/build-types/components/global-styles-sidebar/index.d.ts.map +1 -1
  234. package/build-types/components/inserter-sidebar/index.d.ts.map +1 -1
  235. package/build-types/components/page-attributes/parent.d.ts.map +1 -1
  236. package/build-types/components/post-author/hook.d.ts +1 -1
  237. package/build-types/components/post-revisions-preview/revisions-canvas.d.ts +2 -5
  238. package/build-types/components/post-revisions-preview/revisions-canvas.d.ts.map +1 -1
  239. package/build-types/components/post-revisions-preview/revisions-slider.d.ts.map +1 -1
  240. package/build-types/components/provider/disable-non-page-content-blocks.d.ts.map +1 -1
  241. package/build-types/components/provider/index.d.ts.map +1 -1
  242. package/build-types/components/provider/use-block-editor-settings.d.ts.map +1 -1
  243. package/build-types/components/provider/use-post-content-block-types.d.ts +9 -0
  244. package/build-types/components/provider/use-post-content-block-types.d.ts.map +1 -0
  245. package/build-types/components/provider/use-revision-blocks.d.ts +10 -0
  246. package/build-types/components/provider/use-revision-blocks.d.ts.map +1 -0
  247. package/build-types/components/sidebar/dataform-post-summary.d.ts +4 -0
  248. package/build-types/components/sidebar/dataform-post-summary.d.ts.map +1 -0
  249. package/build-types/components/sidebar/post-summary.d.ts.map +1 -1
  250. package/build-types/components/sync-connection-modal/index.d.ts.map +1 -1
  251. package/build-types/components/template-content-panel/index.d.ts.map +1 -1
  252. package/build-types/dataviews/store/private-actions.d.ts.map +1 -1
  253. package/build-types/store/private-actions.d.ts +7 -0
  254. package/build-types/store/private-actions.d.ts.map +1 -1
  255. package/build-types/store/private-selectors.d.ts +7 -0
  256. package/build-types/store/private-selectors.d.ts.map +1 -1
  257. package/build-types/store/reducer.d.ts +14 -3
  258. package/build-types/store/reducer.d.ts.map +1 -1
  259. package/build-types/utils/media-upload/on-success.d.ts +9 -0
  260. package/build-types/utils/media-upload/on-success.d.ts.map +1 -0
  261. package/package.json +45 -44
  262. package/src/components/collab-sidebar/index.js +7 -4
  263. package/src/components/collab-sidebar/utils.js +9 -10
  264. package/src/components/collaborators-overlay/avatar-iframe-styles.ts +134 -0
  265. package/src/components/collaborators-overlay/collaborator-styles.ts +43 -2
  266. package/src/components/collaborators-overlay/compute-selection.ts +307 -0
  267. package/src/components/collaborators-overlay/cursor-dom-utils.ts +382 -0
  268. package/src/components/collaborators-overlay/overlay-iframe-styles.ts +131 -0
  269. package/src/components/collaborators-overlay/overlay.tsx +86 -226
  270. package/src/components/collaborators-overlay/use-block-highlighting.ts +147 -63
  271. package/src/components/collaborators-overlay/use-debounced-recompute.ts +32 -0
  272. package/src/components/collaborators-overlay/use-render-cursors.ts +113 -279
  273. package/src/components/collaborators-presence/avatar/component.tsx +123 -0
  274. package/src/components/collaborators-presence/avatar/index.ts +2 -0
  275. package/src/components/collaborators-presence/avatar/styles.scss +184 -0
  276. package/src/components/collaborators-presence/avatar/test/index.tsx +389 -0
  277. package/src/components/collaborators-presence/avatar/types.ts +66 -0
  278. package/src/components/collaborators-presence/avatar/use-image-loading-status.ts +36 -0
  279. package/src/components/collaborators-presence/avatar-group/component.tsx +55 -0
  280. package/src/components/collaborators-presence/avatar-group/index.ts +2 -0
  281. package/src/components/collaborators-presence/avatar-group/styles.scss +33 -0
  282. package/src/components/collaborators-presence/avatar-group/test/index.tsx +139 -0
  283. package/src/components/collaborators-presence/avatar-group/types.ts +13 -0
  284. package/src/components/collaborators-presence/index.tsx +34 -11
  285. package/src/components/collaborators-presence/list.tsx +44 -40
  286. package/src/components/collaborators-presence/styles/collaborators-list.scss +26 -19
  287. package/src/components/collaborators-presence/styles/collaborators-presence.scss +6 -2
  288. package/src/components/collaborators-presence/test/use-collaborator-notifications.ts +188 -246
  289. package/src/components/collaborators-presence/use-collaborator-notifications.ts +109 -166
  290. package/src/components/document-bar/style.scss +1 -1
  291. package/src/components/editor-interface/index.js +8 -6
  292. package/src/components/entities-saved-states/hooks/use-is-dirty.js +14 -5
  293. package/src/components/global-styles/index.js +20 -27
  294. package/src/components/global-styles-sidebar/index.js +3 -0
  295. package/src/components/inserter-sidebar/index.js +4 -1
  296. package/src/components/page-attributes/parent.js +2 -1
  297. package/src/components/post-publish-panel/test/__snapshots__/index.js.snap +2 -2
  298. package/src/components/post-revisions-preview/revisions-canvas.js +15 -84
  299. package/src/components/post-revisions-preview/revisions-slider.js +6 -1
  300. package/src/components/post-url/panel.js +1 -0
  301. package/src/components/post-url/style.scss +5 -0
  302. package/src/components/preferences-modal/index.js +18 -0
  303. package/src/components/provider/disable-non-page-content-blocks.js +42 -40
  304. package/src/components/provider/index.js +20 -2
  305. package/src/components/provider/use-block-editor-settings.js +24 -8
  306. package/src/components/provider/use-post-content-block-types.js +30 -0
  307. package/src/components/provider/use-revision-blocks.js +105 -0
  308. package/src/components/sidebar/dataform-post-summary.js +170 -0
  309. package/src/components/sidebar/header.js +1 -1
  310. package/src/components/sidebar/post-summary.js +15 -0
  311. package/src/components/sync-connection-modal/index.js +12 -6
  312. package/src/components/sync-connection-modal/style.scss +5 -0
  313. package/src/components/template-content-panel/index.js +30 -38
  314. package/src/components/visual-editor/index.js +1 -1
  315. package/src/dataviews/store/private-actions.ts +14 -0
  316. package/src/store/private-actions.js +21 -2
  317. package/src/store/private-selectors.js +75 -10
  318. package/src/store/reducer.js +19 -0
  319. package/src/style.scss +3 -0
  320. package/src/utils/media-upload/on-success.js +34 -0
  321. package/build/components/provider/use-post-content-blocks.cjs.map +0 -7
  322. package/build-module/components/provider/use-post-content-blocks.mjs +0 -34
  323. package/build-module/components/provider/use-post-content-blocks.mjs.map +0 -7
  324. package/build-types/components/provider/use-post-content-blocks.d.ts +0 -2
  325. package/build-types/components/provider/use-post-content-blocks.d.ts.map +0 -1
  326. package/src/components/provider/use-post-content-blocks.js +0 -42
@@ -0,0 +1,307 @@
1
+ import { SelectionDirection, SelectionType } from '@wordpress/core-data';
2
+ import type { ResolvedSelection } from '@wordpress/core-data';
3
+
4
+ import {
5
+ getCursorPosition,
6
+ getSelectionRects,
7
+ getFullBlockSelectionRects,
8
+ getBlocksBetween,
9
+ isNodeBefore,
10
+ } from './cursor-dom-utils';
11
+ import type { CursorCoords, SelectionRect } from './cursor-dom-utils';
12
+
13
+ /** Common parameters passed to cursor/selection computation helpers. */
14
+ interface OverlayContext {
15
+ editorDocument: Document;
16
+ overlayRect: DOMRect;
17
+ }
18
+
19
+ /** Selection rects and the resolved block element for a single-block selection. */
20
+ interface SingleBlockResult {
21
+ rects: SelectionRect[];
22
+ blockElement: HTMLElement | null;
23
+ }
24
+
25
+ /** Selection rects and the resolved block elements for a multi-block selection. */
26
+ interface MultiBlockResult {
27
+ rects: SelectionRect[];
28
+ firstBlock: HTMLElement | null;
29
+ lastBlock: HTMLElement | null;
30
+ firstBlockClientId: string | null;
31
+ }
32
+
33
+ /** Result of computing visual cursor/selection state for a single user. */
34
+ export interface SelectionVisual {
35
+ coords?: CursorCoords | null;
36
+ selectionRects?: SelectionRect[];
37
+ }
38
+
39
+ /**
40
+ * Compute cursor coords and optional selection rects for a single user's selection.
41
+ *
42
+ * @param selection - The selection state from the awareness layer.
43
+ * @param start - Start position (block clientId + text index).
44
+ * @param end - End position (only for range selections).
45
+ * @param overlayContext - Shared editor document / overlay references.
46
+ * @return Cursor coordinates and optional selection rectangles.
47
+ */
48
+ export function computeSelectionVisual(
49
+ selection: any,
50
+ start: ResolvedSelection,
51
+ end: ResolvedSelection | undefined,
52
+ overlayContext: OverlayContext
53
+ ): SelectionVisual {
54
+ if (
55
+ selection.type === SelectionType.None ||
56
+ selection.type === SelectionType.WholeBlock
57
+ ) {
58
+ return {};
59
+ }
60
+
61
+ if ( selection.type === SelectionType.Cursor ) {
62
+ return computeCursorOnly( start, overlayContext );
63
+ }
64
+
65
+ // SelectionInOneBlock or SelectionInMultipleBlocks.
66
+ if ( ! end ) {
67
+ return {};
68
+ }
69
+ return computeTextSelection( selection, start, end, overlayContext );
70
+ }
71
+
72
+ /**
73
+ * Compute cursor coordinates for a simple cursor (no highlighted text).
74
+ *
75
+ * @param start - Cursor position (block clientId + text index).
76
+ * @param overlayContext - Shared editor document / overlay references.
77
+ * @return Cursor coordinates.
78
+ */
79
+ function computeCursorOnly(
80
+ start: ResolvedSelection,
81
+ overlayContext: OverlayContext
82
+ ): SelectionVisual {
83
+ if ( ! start.localClientId ) {
84
+ return {};
85
+ }
86
+ const blockElement =
87
+ overlayContext.editorDocument.querySelector< HTMLElement >(
88
+ `[data-block="${ start.localClientId }"]`
89
+ );
90
+ return {
91
+ coords: getCursorPosition(
92
+ start.textIndex,
93
+ blockElement,
94
+ overlayContext.editorDocument,
95
+ overlayContext.overlayRect
96
+ ),
97
+ };
98
+ }
99
+
100
+ /**
101
+ * Compute cursor coordinates and selection highlight rects for a text selection
102
+ * (single-block or multi-block).
103
+ *
104
+ * @param selection - The selection state.
105
+ * @param start - Start position (block clientId + text index).
106
+ * @param end - End position (block clientId + text index).
107
+ * @param overlayContext - Shared editor document / overlay references.
108
+ * @return Cursor coordinates and optional selection rectangles.
109
+ */
110
+ function computeTextSelection(
111
+ selection: any,
112
+ start: ResolvedSelection,
113
+ end: ResolvedSelection,
114
+ overlayContext: OverlayContext
115
+ ): SelectionVisual {
116
+ if (
117
+ ! start.localClientId ||
118
+ ! end.localClientId ||
119
+ start.textIndex === null ||
120
+ end.textIndex === null
121
+ ) {
122
+ return {};
123
+ }
124
+
125
+ const isReverse =
126
+ selection.selectionDirection === SelectionDirection.Backward;
127
+ const activeEnd = isReverse ? start : end;
128
+
129
+ let allRects: SelectionRect[];
130
+ let activeEndBlock: HTMLElement | null = null;
131
+
132
+ if ( selection.type === SelectionType.SelectionInOneBlock ) {
133
+ const result = computeSingleBlockRects( start, end, overlayContext );
134
+ allRects = result.rects;
135
+ // Single block: start and end share the same block element.
136
+ activeEndBlock = result.blockElement;
137
+ } else {
138
+ const result = computeMultiBlockRects( start, end, overlayContext );
139
+ allRects = result.rects;
140
+ // Pick the block element that matches the active end.
141
+ activeEndBlock =
142
+ activeEnd.localClientId === result.firstBlockClientId
143
+ ? result.firstBlock
144
+ : result.lastBlock;
145
+ }
146
+
147
+ if ( allRects.length > 0 ) {
148
+ return {
149
+ coords: getCursorPosition(
150
+ activeEnd.textIndex,
151
+ activeEndBlock,
152
+ overlayContext.editorDocument,
153
+ overlayContext.overlayRect
154
+ ),
155
+ selectionRects: allRects,
156
+ };
157
+ }
158
+
159
+ // Fallback: cursor at start position only.
160
+ const startBlock =
161
+ overlayContext.editorDocument.querySelector< HTMLElement >(
162
+ `[data-block="${ start.localClientId }"]`
163
+ );
164
+
165
+ return {
166
+ coords: getCursorPosition(
167
+ start.textIndex,
168
+ startBlock,
169
+ overlayContext.editorDocument,
170
+ overlayContext.overlayRect
171
+ ),
172
+ };
173
+ }
174
+
175
+ /**
176
+ * Compute selection rects for a selection within a single block.
177
+ *
178
+ * @param start - Start position (block clientId + text index).
179
+ * @param end - End position (block clientId + text index).
180
+ * @param overlayContext - Shared editor document / overlay references.
181
+ * @return Array of selection rectangles.
182
+ */
183
+ function computeSingleBlockRects(
184
+ start: ResolvedSelection,
185
+ end: ResolvedSelection,
186
+ overlayContext: OverlayContext
187
+ ): SingleBlockResult {
188
+ const blockElement =
189
+ overlayContext.editorDocument.querySelector< HTMLElement >(
190
+ `[data-block="${ start.localClientId }"]`
191
+ );
192
+ if (
193
+ ! blockElement ||
194
+ start.textIndex === null ||
195
+ end.textIndex === null
196
+ ) {
197
+ return { rects: [], blockElement: null };
198
+ }
199
+ return {
200
+ rects:
201
+ getSelectionRects(
202
+ blockElement,
203
+ start.textIndex,
204
+ end.textIndex,
205
+ overlayContext.editorDocument,
206
+ overlayContext.overlayRect
207
+ ) ?? [],
208
+ blockElement,
209
+ };
210
+ }
211
+
212
+ /**
213
+ * Compute selection rects for a selection spanning multiple blocks.
214
+ *
215
+ * Normalizes to document order — for backward selections the block editor
216
+ * reports start after end.
217
+ *
218
+ * @param start - Start position (block clientId + text index).
219
+ * @param end - End position (block clientId + text index).
220
+ * @param overlayContext - Shared editor document / overlay references.
221
+ * @return Array of selection rectangles.
222
+ */
223
+ function computeMultiBlockRects(
224
+ start: ResolvedSelection,
225
+ end: ResolvedSelection,
226
+ overlayContext: OverlayContext
227
+ ): MultiBlockResult {
228
+ let docFirst = start;
229
+ let docLast = end;
230
+ let firstBlock = overlayContext.editorDocument.querySelector< HTMLElement >(
231
+ `[data-block="${ docFirst.localClientId }"]`
232
+ );
233
+ let lastBlock = overlayContext.editorDocument.querySelector< HTMLElement >(
234
+ `[data-block="${ docLast.localClientId }"]`
235
+ );
236
+
237
+ // Swap to document order if needed.
238
+ if ( firstBlock && lastBlock && isNodeBefore( lastBlock, firstBlock ) ) {
239
+ docFirst = end;
240
+ docLast = start;
241
+ [ firstBlock, lastBlock ] = [ lastBlock, firstBlock ];
242
+ }
243
+
244
+ if (
245
+ ! firstBlock ||
246
+ ! lastBlock ||
247
+ docFirst.textIndex === null ||
248
+ docLast.textIndex === null ||
249
+ ! docFirst.localClientId ||
250
+ ! docLast.localClientId
251
+ ) {
252
+ return {
253
+ rects: [],
254
+ firstBlock: null,
255
+ lastBlock: null,
256
+ firstBlockClientId: null,
257
+ };
258
+ }
259
+
260
+ const allRects: SelectionRect[] = [];
261
+
262
+ // First block: from start offset to end of block.
263
+ const startRects = getSelectionRects(
264
+ firstBlock,
265
+ docFirst.textIndex,
266
+ Number.MAX_SAFE_INTEGER,
267
+ overlayContext.editorDocument,
268
+ overlayContext.overlayRect
269
+ );
270
+ if ( startRects ) {
271
+ allRects.push( ...startRects );
272
+ }
273
+
274
+ // Intermediate blocks: full content.
275
+ const intermediateBlocks = getBlocksBetween(
276
+ docFirst.localClientId,
277
+ docLast.localClientId,
278
+ overlayContext.editorDocument
279
+ );
280
+ for ( const intermediateBlock of intermediateBlocks ) {
281
+ const rects = getFullBlockSelectionRects(
282
+ intermediateBlock,
283
+ overlayContext.editorDocument,
284
+ overlayContext.overlayRect
285
+ );
286
+ allRects.push( ...rects );
287
+ }
288
+
289
+ // Last block: from 0 to end offset.
290
+ const endRects = getSelectionRects(
291
+ lastBlock,
292
+ 0,
293
+ docLast.textIndex,
294
+ overlayContext.editorDocument,
295
+ overlayContext.overlayRect
296
+ );
297
+ if ( endRects ) {
298
+ allRects.push( ...endRects );
299
+ }
300
+
301
+ return {
302
+ rects: allRects,
303
+ firstBlock,
304
+ lastBlock,
305
+ firstBlockClientId: docFirst.localClientId,
306
+ };
307
+ }
@@ -0,0 +1,382 @@
1
+ export interface SelectionRect {
2
+ x: number;
3
+ y: number;
4
+ width: number;
5
+ height: number;
6
+ }
7
+
8
+ export interface CursorCoords {
9
+ x: number;
10
+ y: number;
11
+ height: number;
12
+ }
13
+
14
+ const MAX_NODE_OFFSET_COUNT = 500;
15
+
16
+ /**
17
+ * Given a selection, returns the coordinates of the cursor in the block.
18
+ *
19
+ * @param absolutePositionIndex - The absolute position index
20
+ * @param blockElement - The block element (or null if deleted)
21
+ * @param editorDocument - The editor document
22
+ * @param overlayRect - Pre-computed bounding rect of the overlay element
23
+ * @return The position of the cursor
24
+ */
25
+ export const getCursorPosition = (
26
+ absolutePositionIndex: number | null,
27
+ blockElement: HTMLElement | null,
28
+ editorDocument: Document,
29
+ overlayRect: DOMRect
30
+ ): CursorCoords | null => {
31
+ if ( absolutePositionIndex === null || ! blockElement ) {
32
+ return null;
33
+ }
34
+
35
+ return (
36
+ getOffsetPositionInBlock(
37
+ blockElement,
38
+ absolutePositionIndex,
39
+ editorDocument,
40
+ overlayRect
41
+ ) ?? null
42
+ );
43
+ };
44
+
45
+ /**
46
+ * Given a block element and a character offset, returns the coordinates for drawing a visual cursor in the block.
47
+ *
48
+ * @param blockElement - The block element
49
+ * @param charOffset - The character offset
50
+ * @param editorDocument - The editor document
51
+ * @param overlayRect - Pre-computed bounding rect of the overlay element
52
+ * @return The position of the cursor
53
+ */
54
+ const getOffsetPositionInBlock = (
55
+ blockElement: HTMLElement,
56
+ charOffset: number,
57
+ editorDocument: Document,
58
+ overlayRect: DOMRect
59
+ ) => {
60
+ const { node, offset } = findInnerBlockOffset(
61
+ blockElement,
62
+ charOffset,
63
+ editorDocument
64
+ );
65
+
66
+ const cursorRange = editorDocument.createRange();
67
+
68
+ try {
69
+ cursorRange.setStart( node, offset );
70
+ } catch ( error ) {
71
+ return null;
72
+ }
73
+
74
+ // Ensure the range only represents single point in the DOM.
75
+ cursorRange.collapse( true );
76
+
77
+ const cursorRect = cursorRange.getBoundingClientRect();
78
+ const blockRect = blockElement.getBoundingClientRect();
79
+
80
+ let cursorX = 0;
81
+ let cursorY = 0;
82
+
83
+ if (
84
+ cursorRect.x === 0 &&
85
+ cursorRect.y === 0 &&
86
+ cursorRect.width === 0 &&
87
+ cursorRect.height === 0
88
+ ) {
89
+ // This can happen for empty blocks.
90
+ cursorX = blockRect.left - overlayRect.left;
91
+ cursorY = blockRect.top - overlayRect.top;
92
+ } else {
93
+ cursorX = cursorRect.left - overlayRect.left;
94
+ cursorY = cursorRect.top - overlayRect.top;
95
+ }
96
+
97
+ let cursorHeight = cursorRect.height;
98
+ if ( cursorHeight === 0 ) {
99
+ const view = editorDocument.defaultView ?? window;
100
+ cursorHeight =
101
+ parseInt( view.getComputedStyle( blockElement ).lineHeight, 10 ) ||
102
+ blockRect.height;
103
+ }
104
+
105
+ return {
106
+ x: cursorX,
107
+ y: cursorY,
108
+ height: cursorHeight,
109
+ };
110
+ };
111
+
112
+ /**
113
+ * Computes selection highlight rectangles for a text range within a single block.
114
+ *
115
+ * @param blockElement - The block element
116
+ * @param startOffset - Start character offset within the block
117
+ * @param endOffset - End character offset within the block
118
+ * @param editorDocument - The editor document
119
+ * @param overlayRect - Pre-computed bounding rect of the overlay element
120
+ * @return Array of selection rectangles relative to the overlay, or null on failure
121
+ */
122
+ export const getSelectionRects = (
123
+ blockElement: HTMLElement,
124
+ startOffset: number,
125
+ endOffset: number,
126
+ editorDocument: Document,
127
+ overlayRect: DOMRect
128
+ ): SelectionRect[] | null => {
129
+ // Normalize direction.
130
+ let normalizedStart = startOffset;
131
+ let normalizedEnd = endOffset;
132
+ if ( normalizedStart > normalizedEnd ) {
133
+ [ normalizedStart, normalizedEnd ] = [ normalizedEnd, normalizedStart ];
134
+ }
135
+
136
+ const startPos = findInnerBlockOffset(
137
+ blockElement,
138
+ normalizedStart,
139
+ editorDocument
140
+ );
141
+ const endPos = findInnerBlockOffset(
142
+ blockElement,
143
+ normalizedEnd,
144
+ editorDocument
145
+ );
146
+
147
+ const range = editorDocument.createRange();
148
+ try {
149
+ range.setStart( startPos.node, startPos.offset );
150
+ range.setEnd( endPos.node, endPos.offset );
151
+ } catch {
152
+ return null;
153
+ }
154
+
155
+ const clientRects = range.getClientRects();
156
+ const rects: SelectionRect[] = [];
157
+
158
+ for ( const rect of clientRects ) {
159
+ if ( rect.width === 0 && rect.height === 0 ) {
160
+ continue;
161
+ }
162
+ const x = rect.left - overlayRect.left;
163
+ const y = rect.top - overlayRect.top;
164
+
165
+ // Range.getClientRects() can return duplicate rects at inline
166
+ // formatting boundaries (e.g. <em>, <strong>). Skip exact matches.
167
+ const isDuplicate = rects.some(
168
+ ( r ) =>
169
+ r.x === x &&
170
+ r.y === y &&
171
+ r.width === rect.width &&
172
+ r.height === rect.height
173
+ );
174
+ if ( isDuplicate ) {
175
+ continue;
176
+ }
177
+
178
+ rects.push( {
179
+ x,
180
+ y,
181
+ width: rect.width,
182
+ height: rect.height,
183
+ } );
184
+ }
185
+
186
+ return rects.length > 0 ? rects : null;
187
+ };
188
+
189
+ /**
190
+ * Computes selection highlight rectangles for the full content of a block.
191
+ * Used for intermediate blocks in a multi-block selection.
192
+ *
193
+ * @param blockElement - The block element
194
+ * @param editorDocument - The editor document
195
+ * @param overlayRect - Pre-computed bounding rect of the overlay element
196
+ * @return Array of selection rectangles relative to the overlay
197
+ */
198
+ export const getFullBlockSelectionRects = (
199
+ blockElement: HTMLElement,
200
+ editorDocument: Document,
201
+ overlayRect: DOMRect
202
+ ): SelectionRect[] => {
203
+ const range = editorDocument.createRange();
204
+ range.selectNodeContents( blockElement );
205
+ const clientRects = range.getClientRects();
206
+ const rects: SelectionRect[] = [];
207
+
208
+ for ( const rect of clientRects ) {
209
+ if ( rect.width === 0 && rect.height === 0 ) {
210
+ continue;
211
+ }
212
+ rects.push( {
213
+ x: rect.left - overlayRect.left,
214
+ y: rect.top - overlayRect.top,
215
+ width: rect.width,
216
+ height: rect.height,
217
+ } );
218
+ }
219
+
220
+ // Fallback: if getClientRects returned nothing, use the block's bounding rect.
221
+ if ( rects.length === 0 ) {
222
+ const blockRect = blockElement.getBoundingClientRect();
223
+ if ( blockRect.width > 0 && blockRect.height > 0 ) {
224
+ rects.push( {
225
+ x: blockRect.left - overlayRect.left,
226
+ y: blockRect.top - overlayRect.top,
227
+ width: blockRect.width,
228
+ height: blockRect.height,
229
+ } );
230
+ }
231
+ }
232
+
233
+ return rects;
234
+ };
235
+
236
+ /**
237
+ * Finds all block elements between two blocks in DOM order (exclusive of start and end).
238
+ *
239
+ * @param startBlockId - The clientId of the start block
240
+ * @param endBlockId - The clientId of the end block
241
+ * @param editorDocument - The editor document
242
+ * @return Array of intermediate block HTMLElements in document order
243
+ */
244
+ export const getBlocksBetween = (
245
+ startBlockId: string,
246
+ endBlockId: string,
247
+ editorDocument: Document
248
+ ): HTMLElement[] => {
249
+ const allBlocks =
250
+ editorDocument.querySelectorAll< HTMLElement >( '[data-block]' );
251
+
252
+ let startIndex = -1;
253
+ let endIndex = -1;
254
+
255
+ for ( let i = 0; i < allBlocks.length; i++ ) {
256
+ const blockId = allBlocks[ i ].getAttribute( 'data-block' );
257
+ if ( blockId === startBlockId ) {
258
+ startIndex = i;
259
+ }
260
+ if ( blockId === endBlockId ) {
261
+ endIndex = i;
262
+ }
263
+ }
264
+
265
+ if ( startIndex === -1 || endIndex === -1 ) {
266
+ return [];
267
+ }
268
+
269
+ // Normalize order.
270
+ if ( startIndex > endIndex ) {
271
+ [ startIndex, endIndex ] = [ endIndex, startIndex ];
272
+ }
273
+
274
+ const result: HTMLElement[] = [];
275
+ for ( let i = startIndex + 1; i < endIndex; i++ ) {
276
+ result.push( allBlocks[ i ] );
277
+ }
278
+ return result;
279
+ };
280
+
281
+ /**
282
+ * Given a block element and a character offset, returns an exact inner node and offset for use in a range.
283
+ *
284
+ * @param blockElement - The block element
285
+ * @param offset - The character offset
286
+ * @param editorDocument - The editor document
287
+ * @return The node and offset of the character at the offset
288
+ */
289
+ export const findInnerBlockOffset = (
290
+ blockElement: HTMLElement,
291
+ offset: number,
292
+ editorDocument: Document
293
+ ) => {
294
+ const treeWalker = editorDocument.createTreeWalker(
295
+ blockElement,
296
+ NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT // eslint-disable-line no-bitwise
297
+ );
298
+
299
+ let currentOffset = 0;
300
+ let lastTextNode: Node | null = null;
301
+
302
+ let node: Node | null = null;
303
+ let nodeCount = 1;
304
+
305
+ while ( ( node = treeWalker.nextNode() ) ) {
306
+ nodeCount++;
307
+
308
+ if ( nodeCount > MAX_NODE_OFFSET_COUNT ) {
309
+ // If we've walked too many nodes, return the last text node or the beginning of the block.
310
+ if ( lastTextNode ) {
311
+ return { node: lastTextNode, offset: 0 };
312
+ }
313
+ return { node: blockElement, offset: 0 };
314
+ }
315
+
316
+ const nodeLength = node.nodeValue?.length ?? 0;
317
+
318
+ if ( node.nodeType === Node.ELEMENT_NODE ) {
319
+ if ( node.nodeName === 'BR' ) {
320
+ // Treat <br> as a single "\n" character.
321
+
322
+ if ( currentOffset + 1 >= offset ) {
323
+ // If the <br> occurs right on the target offset, return the next text node.
324
+ const nodeAfterBr = treeWalker.nextNode();
325
+
326
+ if ( nodeAfterBr?.nodeType === Node.TEXT_NODE ) {
327
+ return { node: nodeAfterBr, offset: 0 };
328
+ } else if ( lastTextNode ) {
329
+ // If there's no text node after the <br>, return the end offset of the last text node.
330
+ return {
331
+ node: lastTextNode,
332
+ offset: lastTextNode.nodeValue?.length ?? 0,
333
+ };
334
+ }
335
+ // Just in case, if there's no last text node, return the beginning of the block.
336
+ return { node: blockElement, offset: 0 };
337
+ }
338
+
339
+ // The <br> is before the target offset. Count it as a single character.
340
+ currentOffset += 1;
341
+ continue;
342
+ } else {
343
+ // Skip other element types.
344
+ continue;
345
+ }
346
+ }
347
+
348
+ if ( nodeLength === 0 ) {
349
+ // Skip empty nodes.
350
+ continue;
351
+ }
352
+
353
+ if ( currentOffset + nodeLength >= offset ) {
354
+ // This node exceeds the target offset. Return the node and the position of the offset within it.
355
+ return { node, offset: offset - currentOffset };
356
+ }
357
+
358
+ currentOffset += nodeLength;
359
+
360
+ if ( node.nodeType === Node.TEXT_NODE ) {
361
+ lastTextNode = node;
362
+ }
363
+ }
364
+
365
+ if ( lastTextNode && lastTextNode.nodeValue?.length ) {
366
+ // We didn't reach the target offset. Return the last text node's last character.
367
+ return { node: lastTextNode, offset: lastTextNode.nodeValue.length };
368
+ }
369
+
370
+ // We didn't find any text nodes. Return the beginning of the block.
371
+ return { node: blockElement, offset: 0 };
372
+ };
373
+
374
+ /**
375
+ * Check if node `a` precedes node `b` in document order.
376
+ *
377
+ * @param a - First node.
378
+ * @param b - Second node.
379
+ * @return True if `a` comes before `b`.
380
+ */
381
+ export const isNodeBefore = ( a: Node, b: Node ): boolean =>
382
+ a.compareDocumentPosition( b ) === Node.DOCUMENT_POSITION_FOLLOWING;