@wordpress/editor 14.42.0 → 14.43.1-next.v.202604091042.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 (276) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/README.md +8 -0
  3. package/build/components/autocompleters/index.cjs +3 -0
  4. package/build/components/autocompleters/index.cjs.map +2 -2
  5. package/build/components/autocompleters/link.cjs +71 -0
  6. package/build/components/autocompleters/link.cjs.map +7 -0
  7. package/build/components/collaborators-overlay/cursor-dom-utils.cjs +1 -1
  8. package/build/components/collaborators-overlay/cursor-dom-utils.cjs.map +2 -2
  9. package/build/components/collaborators-overlay/cursor-registry.cjs +86 -0
  10. package/build/components/collaborators-overlay/cursor-registry.cjs.map +7 -0
  11. package/build/components/collaborators-overlay/index.cjs +7 -2
  12. package/build/components/collaborators-overlay/index.cjs.map +2 -2
  13. package/build/components/collaborators-overlay/overlay-iframe-styles.cjs +1 -1
  14. package/build/components/collaborators-overlay/overlay-iframe-styles.cjs.map +2 -2
  15. package/build/components/collaborators-overlay/overlay.cjs +31 -1
  16. package/build/components/collaborators-overlay/overlay.cjs.map +2 -2
  17. package/build/components/collaborators-overlay/timing-utils.cjs +1 -1
  18. package/build/components/collaborators-overlay/timing-utils.cjs.map +2 -2
  19. package/build/components/collaborators-overlay/use-render-cursors.cjs.map +2 -2
  20. package/build/components/collaborators-presence/index.cjs +14 -4
  21. package/build/components/collaborators-presence/index.cjs.map +2 -2
  22. package/build/components/collaborators-presence/list.cjs +20 -4
  23. package/build/components/collaborators-presence/list.cjs.map +2 -2
  24. package/build/components/error-boundary/index.cjs +1 -1
  25. package/build/components/error-boundary/index.cjs.map +2 -2
  26. package/build/components/post-card-panel/index.cjs +4 -15
  27. package/build/components/post-card-panel/index.cjs.map +2 -2
  28. package/build/components/post-content-information/index.cjs +10 -13
  29. package/build/components/post-content-information/index.cjs.map +2 -2
  30. package/build/components/post-revisions-panel/index.cjs +164 -0
  31. package/build/components/post-revisions-panel/index.cjs.map +7 -0
  32. package/build/components/post-revisions-preview/revisions-slider.cjs +23 -12
  33. package/build/components/post-revisions-preview/revisions-slider.cjs.map +2 -2
  34. package/build/components/post-template/create-new-template-modal.cjs +39 -46
  35. package/build/components/post-template/create-new-template-modal.cjs.map +2 -2
  36. package/build/components/post-template/hooks.cjs +52 -6
  37. package/build/components/post-template/hooks.cjs.map +2 -2
  38. package/build/components/post-template/swap-template-button.cjs +31 -20
  39. package/build/components/post-template/swap-template-button.cjs.map +2 -2
  40. package/build/components/post-title/index.cjs +2 -2
  41. package/build/components/post-title/index.cjs.map +2 -2
  42. package/build/components/preferences-modal/index.cjs +35 -27
  43. package/build/components/preferences-modal/index.cjs.map +2 -2
  44. package/build/components/revision-block-diff/index.cjs +9 -32
  45. package/build/components/revision-block-diff/index.cjs.map +3 -3
  46. package/build/components/revision-diff-panel/index.cjs +68 -0
  47. package/build/components/revision-diff-panel/index.cjs.map +7 -0
  48. package/build/components/revision-fields-diff/index.cjs +96 -0
  49. package/build/components/revision-fields-diff/index.cjs.map +7 -0
  50. package/build/components/sidebar/dataform-post-summary.cjs +8 -53
  51. package/build/components/sidebar/dataform-post-summary.cjs.map +2 -2
  52. package/build/components/sidebar/index.cjs +25 -22
  53. package/build/components/sidebar/index.cjs.map +3 -3
  54. package/build/components/sidebar/post-revision-summary.cjs +74 -0
  55. package/build/components/sidebar/post-revision-summary.cjs.map +7 -0
  56. package/build/components/sidebar/post-summary.cjs +35 -42
  57. package/build/components/sidebar/post-summary.cjs.map +3 -3
  58. package/build/components/style-book/index.cjs +4 -3
  59. package/build/components/style-book/index.cjs.map +2 -2
  60. package/build/components/styles-canvas/revisions.cjs +2 -2
  61. package/build/components/styles-canvas/revisions.cjs.map +1 -1
  62. package/build/components/sync-connection-error-modal/index.cjs +58 -75
  63. package/build/components/sync-connection-error-modal/index.cjs.map +3 -3
  64. package/build/components/sync-connection-error-modal/use-retry-countdown.cjs +32 -9
  65. package/build/components/sync-connection-error-modal/use-retry-countdown.cjs.map +2 -2
  66. package/build/components/template-actions-panel/block-theme-content.cjs +188 -0
  67. package/build/components/template-actions-panel/block-theme-content.cjs.map +7 -0
  68. package/build/components/template-actions-panel/classic-theme-content.cjs +159 -0
  69. package/build/components/template-actions-panel/classic-theme-content.cjs.map +7 -0
  70. package/build/components/template-actions-panel/index.cjs +59 -0
  71. package/build/components/template-actions-panel/index.cjs.map +7 -0
  72. package/build/dataviews/store/private-actions.cjs +2 -0
  73. package/build/dataviews/store/private-actions.cjs.map +2 -2
  74. package/build/hooks/default-autocompleters.cjs +1 -1
  75. package/build/hooks/default-autocompleters.cjs.map +2 -2
  76. package/build/store/private-actions.cjs +15 -1
  77. package/build/store/private-actions.cjs.map +2 -2
  78. package/build/store/private-selectors.cjs +42 -19
  79. package/build/store/private-selectors.cjs.map +2 -2
  80. package/build/store/reducer.cjs +1 -1
  81. package/build/store/reducer.cjs.map +2 -2
  82. package/build-module/components/autocompleters/index.mjs +4 -2
  83. package/build-module/components/autocompleters/index.mjs.map +2 -2
  84. package/build-module/components/autocompleters/link.mjs +40 -0
  85. package/build-module/components/autocompleters/link.mjs.map +7 -0
  86. package/build-module/components/collaborators-overlay/cursor-dom-utils.mjs +1 -1
  87. package/build-module/components/collaborators-overlay/cursor-dom-utils.mjs.map +2 -2
  88. package/build-module/components/collaborators-overlay/cursor-registry.mjs +61 -0
  89. package/build-module/components/collaborators-overlay/cursor-registry.mjs.map +7 -0
  90. package/build-module/components/collaborators-overlay/index.mjs +7 -2
  91. package/build-module/components/collaborators-overlay/index.mjs.map +2 -2
  92. package/build-module/components/collaborators-overlay/overlay-iframe-styles.mjs +1 -1
  93. package/build-module/components/collaborators-overlay/overlay-iframe-styles.mjs.map +2 -2
  94. package/build-module/components/collaborators-overlay/overlay.mjs +32 -2
  95. package/build-module/components/collaborators-overlay/overlay.mjs.map +2 -2
  96. package/build-module/components/collaborators-overlay/timing-utils.mjs +1 -1
  97. package/build-module/components/collaborators-overlay/timing-utils.mjs.map +2 -2
  98. package/build-module/components/collaborators-overlay/use-render-cursors.mjs.map +2 -2
  99. package/build-module/components/collaborators-presence/index.mjs +14 -4
  100. package/build-module/components/collaborators-presence/index.mjs.map +2 -2
  101. package/build-module/components/collaborators-presence/list.mjs +20 -4
  102. package/build-module/components/collaborators-presence/list.mjs.map +2 -2
  103. package/build-module/components/error-boundary/index.mjs +1 -1
  104. package/build-module/components/error-boundary/index.mjs.map +2 -2
  105. package/build-module/components/post-card-panel/index.mjs +6 -17
  106. package/build-module/components/post-card-panel/index.mjs.map +2 -2
  107. package/build-module/components/post-content-information/index.mjs +6 -13
  108. package/build-module/components/post-content-information/index.mjs.map +2 -2
  109. package/build-module/components/post-revisions-panel/index.mjs +139 -0
  110. package/build-module/components/post-revisions-panel/index.mjs.map +7 -0
  111. package/build-module/components/post-revisions-preview/revisions-slider.mjs +23 -12
  112. package/build-module/components/post-revisions-preview/revisions-slider.mjs.map +2 -2
  113. package/build-module/components/post-template/create-new-template-modal.mjs +39 -46
  114. package/build-module/components/post-template/create-new-template-modal.mjs.map +2 -2
  115. package/build-module/components/post-template/hooks.mjs +53 -7
  116. package/build-module/components/post-template/hooks.mjs.map +2 -2
  117. package/build-module/components/post-template/swap-template-button.mjs +27 -20
  118. package/build-module/components/post-template/swap-template-button.mjs.map +2 -2
  119. package/build-module/components/post-title/index.mjs +2 -2
  120. package/build-module/components/post-title/index.mjs.map +2 -2
  121. package/build-module/components/preferences-modal/index.mjs +35 -27
  122. package/build-module/components/preferences-modal/index.mjs.map +2 -2
  123. package/build-module/components/revision-block-diff/index.mjs +9 -32
  124. package/build-module/components/revision-block-diff/index.mjs.map +2 -2
  125. package/build-module/components/revision-diff-panel/index.mjs +37 -0
  126. package/build-module/components/revision-diff-panel/index.mjs.map +7 -0
  127. package/build-module/components/revision-fields-diff/index.mjs +65 -0
  128. package/build-module/components/revision-fields-diff/index.mjs.map +7 -0
  129. package/build-module/components/sidebar/dataform-post-summary.mjs +8 -53
  130. package/build-module/components/sidebar/dataform-post-summary.mjs.map +2 -2
  131. package/build-module/components/sidebar/index.mjs +25 -22
  132. package/build-module/components/sidebar/index.mjs.map +2 -2
  133. package/build-module/components/sidebar/post-revision-summary.mjs +43 -0
  134. package/build-module/components/sidebar/post-revision-summary.mjs.map +7 -0
  135. package/build-module/components/sidebar/post-summary.mjs +31 -42
  136. package/build-module/components/sidebar/post-summary.mjs.map +2 -2
  137. package/build-module/components/style-book/index.mjs +4 -3
  138. package/build-module/components/style-book/index.mjs.map +2 -2
  139. package/build-module/components/styles-canvas/revisions.mjs +2 -2
  140. package/build-module/components/styles-canvas/revisions.mjs.map +1 -1
  141. package/build-module/components/sync-connection-error-modal/index.mjs +58 -76
  142. package/build-module/components/sync-connection-error-modal/index.mjs.map +2 -2
  143. package/build-module/components/sync-connection-error-modal/use-retry-countdown.mjs +33 -10
  144. package/build-module/components/sync-connection-error-modal/use-retry-countdown.mjs.map +2 -2
  145. package/build-module/components/template-actions-panel/block-theme-content.mjs +167 -0
  146. package/build-module/components/template-actions-panel/block-theme-content.mjs.map +7 -0
  147. package/build-module/components/template-actions-panel/classic-theme-content.mjs +138 -0
  148. package/build-module/components/template-actions-panel/classic-theme-content.mjs.map +7 -0
  149. package/build-module/components/template-actions-panel/index.mjs +28 -0
  150. package/build-module/components/template-actions-panel/index.mjs.map +7 -0
  151. package/build-module/dataviews/store/private-actions.mjs +5 -1
  152. package/build-module/dataviews/store/private-actions.mjs.map +2 -2
  153. package/build-module/hooks/default-autocompleters.mjs +2 -2
  154. package/build-module/hooks/default-autocompleters.mjs.map +2 -2
  155. package/build-module/store/private-actions.mjs +15 -1
  156. package/build-module/store/private-actions.mjs.map +2 -2
  157. package/build-module/store/private-selectors.mjs +42 -19
  158. package/build-module/store/private-selectors.mjs.map +2 -2
  159. package/build-module/store/reducer.mjs +1 -1
  160. package/build-module/store/reducer.mjs.map +2 -2
  161. package/build-style/style-rtl.css +124 -44
  162. package/build-style/style.css +124 -44
  163. package/build-types/bindings/post-data.d.ts +3 -3
  164. package/build-types/bindings/term-data.d.ts +14 -14
  165. package/build-types/components/autocompleters/index.d.ts +1 -0
  166. package/build-types/components/autocompleters/link.d.ts +12 -0
  167. package/build-types/components/autocompleters/link.d.ts.map +1 -0
  168. package/build-types/components/collaborators-overlay/cursor-registry.d.ts +36 -0
  169. package/build-types/components/collaborators-overlay/cursor-registry.d.ts.map +1 -0
  170. package/build-types/components/collaborators-overlay/index.d.ts +7 -4
  171. package/build-types/components/collaborators-overlay/index.d.ts.map +1 -1
  172. package/build-types/components/collaborators-overlay/overlay-iframe-styles.d.ts +1 -1
  173. package/build-types/components/collaborators-overlay/overlay-iframe-styles.d.ts.map +1 -1
  174. package/build-types/components/collaborators-overlay/overlay.d.ts +4 -1
  175. package/build-types/components/collaborators-overlay/overlay.d.ts.map +1 -1
  176. package/build-types/components/collaborators-overlay/use-render-cursors.d.ts.map +1 -1
  177. package/build-types/components/collaborators-presence/index.d.ts.map +1 -1
  178. package/build-types/components/collaborators-presence/list.d.ts +4 -1
  179. package/build-types/components/collaborators-presence/list.d.ts.map +1 -1
  180. package/build-types/components/keyboard-shortcut-help-modal/config.d.ts +11 -11
  181. package/build-types/components/post-actions/set-as-homepage.d.ts +1 -1
  182. package/build-types/components/post-actions/set-as-posts-page.d.ts +1 -1
  183. package/build-types/components/post-card-panel/index.d.ts.map +1 -1
  184. package/build-types/components/post-content-information/index.d.ts +4 -1
  185. package/build-types/components/post-content-information/index.d.ts.map +1 -1
  186. package/build-types/components/post-format/index.d.ts +10 -10
  187. package/build-types/components/post-locked-modal/index.d.ts +2 -2
  188. package/build-types/components/post-revisions-panel/index.d.ts +2 -0
  189. package/build-types/components/post-revisions-panel/index.d.ts.map +1 -0
  190. package/build-types/components/post-revisions-preview/revisions-slider.d.ts.map +1 -1
  191. package/build-types/components/post-status/index.d.ts +10 -10
  192. package/build-types/components/post-template/create-new-template-modal.d.ts.map +1 -1
  193. package/build-types/components/post-template/hooks.d.ts +1 -1
  194. package/build-types/components/post-template/hooks.d.ts.map +1 -1
  195. package/build-types/components/post-template/swap-template-button.d.ts +4 -0
  196. package/build-types/components/post-template/swap-template-button.d.ts.map +1 -1
  197. package/build-types/components/post-visibility/utils.d.ts +6 -6
  198. package/build-types/components/revision-block-diff/index.d.ts.map +1 -1
  199. package/build-types/components/revision-diff-panel/index.d.ts +14 -0
  200. package/build-types/components/revision-diff-panel/index.d.ts.map +1 -0
  201. package/build-types/components/revision-fields-diff/index.d.ts +6 -0
  202. package/build-types/components/revision-fields-diff/index.d.ts.map +1 -0
  203. package/build-types/components/sidebar/dataform-post-summary.d.ts.map +1 -1
  204. package/build-types/components/sidebar/index.d.ts.map +1 -1
  205. package/build-types/components/sidebar/post-revision-summary.d.ts +2 -0
  206. package/build-types/components/sidebar/post-revision-summary.d.ts.map +1 -0
  207. package/build-types/components/sidebar/post-summary.d.ts +3 -0
  208. package/build-types/components/sidebar/post-summary.d.ts.map +1 -1
  209. package/build-types/components/style-book/index.d.ts +2 -1
  210. package/build-types/components/style-book/index.d.ts.map +1 -1
  211. package/build-types/components/sync-connection-error-modal/index.d.ts +0 -14
  212. package/build-types/components/sync-connection-error-modal/index.d.ts.map +1 -1
  213. package/build-types/components/sync-connection-error-modal/use-retry-countdown.d.ts.map +1 -1
  214. package/build-types/components/template-actions-panel/block-theme-content.d.ts +2 -0
  215. package/build-types/components/template-actions-panel/block-theme-content.d.ts.map +1 -0
  216. package/build-types/components/template-actions-panel/classic-theme-content.d.ts +2 -0
  217. package/build-types/components/template-actions-panel/classic-theme-content.d.ts.map +1 -0
  218. package/build-types/components/template-actions-panel/index.d.ts +2 -0
  219. package/build-types/components/template-actions-panel/index.d.ts.map +1 -0
  220. package/build-types/dataviews/store/private-actions.d.ts.map +1 -1
  221. package/build-types/store/private-actions.d.ts.map +1 -1
  222. package/build-types/store/private-selectors.d.ts.map +1 -1
  223. package/build-types/store/reducer.d.ts +10 -10
  224. package/build-types/store/reducer.d.ts.map +1 -1
  225. package/build-types/utils/pageTypeBadge.d.ts +1 -1
  226. package/build-types/utils/pageTypeBadge.d.ts.map +1 -1
  227. package/package.json +45 -44
  228. package/src/components/autocompleters/index.js +1 -0
  229. package/src/components/autocompleters/link.js +47 -0
  230. package/src/components/autocompleters/style.scss +6 -0
  231. package/src/components/collaborators-overlay/cursor-dom-utils.ts +1 -1
  232. package/src/components/collaborators-overlay/cursor-registry.ts +96 -0
  233. package/src/components/collaborators-overlay/index.tsx +12 -4
  234. package/src/components/collaborators-overlay/overlay-iframe-styles.ts +1 -1
  235. package/src/components/collaborators-overlay/overlay.tsx +45 -1
  236. package/src/components/collaborators-overlay/timing-utils.ts +1 -1
  237. package/src/components/collaborators-overlay/use-render-cursors.ts +4 -2
  238. package/src/components/collaborators-presence/index.tsx +9 -1
  239. package/src/components/collaborators-presence/list.tsx +25 -1
  240. package/src/components/error-boundary/index.js +1 -1
  241. package/src/components/error-boundary/index.native.js +1 -1
  242. package/src/components/post-card-panel/index.js +7 -21
  243. package/src/components/post-content-information/index.js +5 -16
  244. package/src/components/post-revisions-panel/index.js +151 -0
  245. package/src/components/post-revisions-panel/style.scss +16 -0
  246. package/src/components/post-revisions-preview/revisions-slider.js +23 -19
  247. package/src/components/post-template/create-new-template-modal.js +1 -4
  248. package/src/components/post-template/hooks.js +65 -9
  249. package/src/components/post-template/style.scss +0 -6
  250. package/src/components/post-template/swap-template-button.js +30 -21
  251. package/src/components/post-title/index.js +3 -3
  252. package/src/components/preferences-modal/index.js +37 -25
  253. package/src/components/revision-block-diff/index.js +8 -43
  254. package/src/components/revision-diff-panel/index.js +59 -0
  255. package/src/components/revision-fields-diff/index.js +91 -0
  256. package/src/components/sidebar/dataform-post-summary.js +8 -55
  257. package/src/components/sidebar/index.js +33 -22
  258. package/src/components/sidebar/post-revision-summary.js +50 -0
  259. package/src/components/sidebar/post-summary.js +22 -40
  260. package/src/components/sidebar/style.scss +7 -0
  261. package/src/components/style-book/index.js +4 -2
  262. package/src/components/styles-canvas/revisions.js +2 -2
  263. package/src/components/sync-connection-error-modal/index.tsx +128 -155
  264. package/src/components/sync-connection-error-modal/use-retry-countdown.ts +46 -10
  265. package/src/components/template-actions-panel/block-theme-content.js +196 -0
  266. package/src/components/template-actions-panel/classic-theme-content.js +170 -0
  267. package/src/components/template-actions-panel/index.js +32 -0
  268. package/src/components/template-actions-panel/style.scss +39 -0
  269. package/src/dataviews/store/private-actions.ts +6 -0
  270. package/src/hooks/default-autocompleters.js +2 -2
  271. package/src/hooks/test/default-autocompleters.js +2 -2
  272. package/src/store/private-actions.js +18 -2
  273. package/src/store/private-selectors.js +43 -22
  274. package/src/store/reducer.js +9 -8
  275. package/src/style.scss +3 -1
  276. /package/src/components/{revision-block-diff → revision-diff-panel}/style.scss +0 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 14.43.0 (2026-04-01)
6
+
5
7
  ## 14.42.0 (2026-03-18)
6
8
 
7
9
  ### Bug Fixes
package/README.md CHANGED
@@ -454,6 +454,14 @@ _Returns_
454
454
 
455
455
  > **Deprecated** since 5.3, use `wp.blockEditor.InspectorControls` instead.
456
456
 
457
+ ### linkAutocompleter
458
+
459
+ A link completer for posts and pages.
460
+
461
+ _Type_
462
+
463
+ - `Object`
464
+
457
465
  ### LocalAutosaveMonitor
458
466
 
459
467
  Monitors local autosaves of a post in the editor. It uses several hooks and functions to manage autosave behavior:
@@ -30,12 +30,15 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // packages/editor/src/components/autocompleters/index.js
31
31
  var autocompleters_exports = {};
32
32
  __export(autocompleters_exports, {
33
+ linkAutocompleter: () => import_link.default,
33
34
  userAutocompleter: () => import_user.default
34
35
  });
35
36
  module.exports = __toCommonJS(autocompleters_exports);
37
+ var import_link = __toESM(require("./link.cjs"));
36
38
  var import_user = __toESM(require("./user.cjs"));
37
39
  // Annotate the CommonJS export names for ESM import in node:
38
40
  0 && (module.exports = {
41
+ linkAutocompleter,
39
42
  userAutocompleter
40
43
  });
41
44
  //# sourceMappingURL=index.cjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/autocompleters/index.js"],
4
- "sourcesContent": ["export { default as userAutocompleter } from './user';\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAA6C;",
4
+ "sourcesContent": ["export { default as linkAutocompleter } from './link';\nexport { default as userAutocompleter } from './user';\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAA6C;AAC7C,kBAA6C;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // packages/editor/src/components/autocompleters/link.js
31
+ var link_exports = {};
32
+ __export(link_exports, {
33
+ default: () => link_default
34
+ });
35
+ module.exports = __toCommonJS(link_exports);
36
+ var import_api_fetch = __toESM(require("@wordpress/api-fetch"));
37
+ var import_url = require("@wordpress/url");
38
+ var import_icons = require("@wordpress/icons");
39
+ var import_html_entities = require("@wordpress/html-entities");
40
+ var import_jsx_runtime = require("react/jsx-runtime");
41
+ var SHOWN_SUGGESTIONS = 10;
42
+ var link_default = {
43
+ name: "links",
44
+ className: "editor-autocompleters__link",
45
+ triggerPrefix: "[[",
46
+ isDebounced: true,
47
+ async options(filterValue) {
48
+ const options = await (0, import_api_fetch.default)({
49
+ path: (0, import_url.addQueryArgs)("/wp/v2/search", {
50
+ per_page: SHOWN_SUGGESTIONS,
51
+ search: filterValue,
52
+ type: "post"
53
+ })
54
+ });
55
+ return options.filter((option) => option.title !== "");
56
+ },
57
+ getOptionKeywords(item) {
58
+ const expansionWords = item.title.split(/\s+/);
59
+ return [...expansionWords];
60
+ },
61
+ getOptionLabel(item) {
62
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
63
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.Icon, { icon: item.subtype === "page" ? import_icons.page : import_icons.post }),
64
+ (0, import_html_entities.decodeEntities)(item.title)
65
+ ] });
66
+ },
67
+ getOptionCompletion(item) {
68
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href: item.url, children: item.title });
69
+ }
70
+ };
71
+ //# sourceMappingURL=link.cjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/components/autocompleters/link.js"],
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport apiFetch from '@wordpress/api-fetch';\nimport { addQueryArgs } from '@wordpress/url';\nimport { Icon, page, post } from '@wordpress/icons';\nimport { decodeEntities } from '@wordpress/html-entities';\n\nconst SHOWN_SUGGESTIONS = 10;\n\n/**\n * A link completer for posts and pages.\n *\n * @type {Object}\n */\nexport default {\n\tname: 'links',\n\tclassName: 'editor-autocompleters__link',\n\ttriggerPrefix: '[[',\n\tisDebounced: true,\n\tasync options( filterValue ) {\n\t\tconst options = await apiFetch( {\n\t\t\tpath: addQueryArgs( '/wp/v2/search', {\n\t\t\t\tper_page: SHOWN_SUGGESTIONS,\n\t\t\t\tsearch: filterValue,\n\t\t\t\ttype: 'post',\n\t\t\t} ),\n\t\t} );\n\n\t\treturn options.filter( ( option ) => option.title !== '' );\n\t},\n\tgetOptionKeywords( item ) {\n\t\tconst expansionWords = item.title.split( /\\s+/ );\n\t\treturn [ ...expansionWords ];\n\t},\n\tgetOptionLabel( item ) {\n\t\treturn (\n\t\t\t<>\n\t\t\t\t<Icon icon={ item.subtype === 'page' ? page : post } />\n\t\t\t\t{ decodeEntities( item.title ) }\n\t\t\t</>\n\t\t);\n\t},\n\tgetOptionCompletion( item ) {\n\t\treturn <a href={ item.url }>{ item.title }</a>;\n\t},\n};\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,uBAAqB;AACrB,iBAA6B;AAC7B,mBAAiC;AACjC,2BAA+B;AA+B5B;AA7BH,IAAM,oBAAoB;AAO1B,IAAO,eAAQ;AAAA,EACd,MAAM;AAAA,EACN,WAAW;AAAA,EACX,eAAe;AAAA,EACf,aAAa;AAAA,EACb,MAAM,QAAS,aAAc;AAC5B,UAAM,UAAU,UAAM,iBAAAA,SAAU;AAAA,MAC/B,UAAM,yBAAc,iBAAiB;AAAA,QACpC,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,MAAM;AAAA,MACP,CAAE;AAAA,IACH,CAAE;AAEF,WAAO,QAAQ,OAAQ,CAAE,WAAY,OAAO,UAAU,EAAG;AAAA,EAC1D;AAAA,EACA,kBAAmB,MAAO;AACzB,UAAM,iBAAiB,KAAK,MAAM,MAAO,KAAM;AAC/C,WAAO,CAAE,GAAG,cAAe;AAAA,EAC5B;AAAA,EACA,eAAgB,MAAO;AACtB,WACC,4EACC;AAAA,kDAAC,qBAAK,MAAO,KAAK,YAAY,SAAS,oBAAO,mBAAO;AAAA,UACnD,qCAAgB,KAAK,KAAM;AAAA,OAC9B;AAAA,EAEF;AAAA,EACA,oBAAqB,MAAO;AAC3B,WAAO,4CAAC,OAAE,MAAO,KAAK,KAAQ,eAAK,OAAO;AAAA,EAC3C;AACD;",
6
+ "names": ["apiFetch"]
7
+ }
@@ -49,7 +49,7 @@ var getOffsetPositionInBlock = (blockElement, charOffset, editorDocument, overla
49
49
  const cursorRange = editorDocument.createRange();
50
50
  try {
51
51
  cursorRange.setStart(node, offset);
52
- } catch (error) {
52
+ } catch {
53
53
  return null;
54
54
  }
55
55
  cursorRange.collapse(true);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/collaborators-overlay/cursor-dom-utils.ts"],
4
- "sourcesContent": ["export interface SelectionRect {\n\tx: number;\n\ty: number;\n\twidth: number;\n\theight: number;\n}\n\nexport interface CursorCoords {\n\tx: number;\n\ty: number;\n\theight: number;\n}\n\nconst MAX_NODE_OFFSET_COUNT = 500;\n\n/**\n * Given a selection, returns the coordinates of the cursor in the block.\n *\n * @param absolutePositionIndex - The absolute position index\n * @param blockElement - The block element (or null if deleted)\n * @param editorDocument - The editor document\n * @param overlayRect - Pre-computed bounding rect of the overlay element\n * @return The position of the cursor\n */\nexport const getCursorPosition = (\n\tabsolutePositionIndex: number | null,\n\tblockElement: HTMLElement | null,\n\teditorDocument: Document,\n\toverlayRect: DOMRect\n): CursorCoords | null => {\n\tif ( absolutePositionIndex === null || ! blockElement ) {\n\t\treturn null;\n\t}\n\n\treturn (\n\t\tgetOffsetPositionInBlock(\n\t\t\tblockElement,\n\t\t\tabsolutePositionIndex,\n\t\t\teditorDocument,\n\t\t\toverlayRect\n\t\t) ?? null\n\t);\n};\n\n/**\n * Given a block element and a character offset, returns the coordinates for drawing a visual cursor in the block.\n *\n * @param blockElement - The block element\n * @param charOffset - The character offset\n * @param editorDocument - The editor document\n * @param overlayRect - Pre-computed bounding rect of the overlay element\n * @return The position of the cursor\n */\nconst getOffsetPositionInBlock = (\n\tblockElement: HTMLElement,\n\tcharOffset: number,\n\teditorDocument: Document,\n\toverlayRect: DOMRect\n) => {\n\tconst { node, offset } = findInnerBlockOffset(\n\t\tblockElement,\n\t\tcharOffset,\n\t\teditorDocument\n\t);\n\n\tconst cursorRange = editorDocument.createRange();\n\n\ttry {\n\t\tcursorRange.setStart( node, offset );\n\t} catch ( error ) {\n\t\treturn null;\n\t}\n\n\t// Ensure the range only represents single point in the DOM.\n\tcursorRange.collapse( true );\n\n\tconst cursorRect = cursorRange.getBoundingClientRect();\n\tconst blockRect = blockElement.getBoundingClientRect();\n\n\tlet cursorX = 0;\n\tlet cursorY = 0;\n\n\tif (\n\t\tcursorRect.x === 0 &&\n\t\tcursorRect.y === 0 &&\n\t\tcursorRect.width === 0 &&\n\t\tcursorRect.height === 0\n\t) {\n\t\t// This can happen for empty blocks.\n\t\tcursorX = blockRect.left - overlayRect.left;\n\t\tcursorY = blockRect.top - overlayRect.top;\n\t} else {\n\t\tcursorX = cursorRect.left - overlayRect.left;\n\t\tcursorY = cursorRect.top - overlayRect.top;\n\t}\n\n\tlet cursorHeight = cursorRect.height;\n\tif ( cursorHeight === 0 ) {\n\t\tconst view = editorDocument.defaultView ?? window;\n\t\tcursorHeight =\n\t\t\tparseInt( view.getComputedStyle( blockElement ).lineHeight, 10 ) ||\n\t\t\tblockRect.height;\n\t}\n\n\treturn {\n\t\tx: cursorX,\n\t\ty: cursorY,\n\t\theight: cursorHeight,\n\t};\n};\n\n/**\n * Computes selection highlight rectangles for a text range within a single block.\n *\n * @param blockElement - The block element\n * @param startOffset - Start character offset within the block\n * @param endOffset - End character offset within the block\n * @param editorDocument - The editor document\n * @param overlayRect - Pre-computed bounding rect of the overlay element\n * @return Array of selection rectangles relative to the overlay, or null on failure\n */\nexport const getSelectionRects = (\n\tblockElement: HTMLElement,\n\tstartOffset: number,\n\tendOffset: number,\n\teditorDocument: Document,\n\toverlayRect: DOMRect\n): SelectionRect[] | null => {\n\t// Normalize direction.\n\tlet normalizedStart = startOffset;\n\tlet normalizedEnd = endOffset;\n\tif ( normalizedStart > normalizedEnd ) {\n\t\t[ normalizedStart, normalizedEnd ] = [ normalizedEnd, normalizedStart ];\n\t}\n\n\tconst startPos = findInnerBlockOffset(\n\t\tblockElement,\n\t\tnormalizedStart,\n\t\teditorDocument\n\t);\n\tconst endPos = findInnerBlockOffset(\n\t\tblockElement,\n\t\tnormalizedEnd,\n\t\teditorDocument\n\t);\n\n\tconst range = editorDocument.createRange();\n\ttry {\n\t\trange.setStart( startPos.node, startPos.offset );\n\t\trange.setEnd( endPos.node, endPos.offset );\n\t} catch {\n\t\treturn null;\n\t}\n\n\tconst clientRects = range.getClientRects();\n\tconst rects: SelectionRect[] = [];\n\n\tfor ( const rect of clientRects ) {\n\t\tif ( rect.width === 0 && rect.height === 0 ) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst x = rect.left - overlayRect.left;\n\t\tconst y = rect.top - overlayRect.top;\n\n\t\t// Range.getClientRects() can return duplicate rects at inline\n\t\t// formatting boundaries (e.g. <em>, <strong>). Skip exact matches.\n\t\tconst isDuplicate = rects.some(\n\t\t\t( r ) =>\n\t\t\t\tr.x === x &&\n\t\t\t\tr.y === y &&\n\t\t\t\tr.width === rect.width &&\n\t\t\t\tr.height === rect.height\n\t\t);\n\t\tif ( isDuplicate ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\trects.push( {\n\t\t\tx,\n\t\t\ty,\n\t\t\twidth: rect.width,\n\t\t\theight: rect.height,\n\t\t} );\n\t}\n\n\treturn rects.length > 0 ? rects : null;\n};\n\n/**\n * Computes selection highlight rectangles for the full content of a block.\n * Used for intermediate blocks in a multi-block selection.\n *\n * @param blockElement - The block element\n * @param editorDocument - The editor document\n * @param overlayRect - Pre-computed bounding rect of the overlay element\n * @return Array of selection rectangles relative to the overlay\n */\nexport const getFullBlockSelectionRects = (\n\tblockElement: HTMLElement,\n\teditorDocument: Document,\n\toverlayRect: DOMRect\n): SelectionRect[] => {\n\tconst range = editorDocument.createRange();\n\trange.selectNodeContents( blockElement );\n\tconst clientRects = range.getClientRects();\n\tconst rects: SelectionRect[] = [];\n\n\tfor ( const rect of clientRects ) {\n\t\tif ( rect.width === 0 && rect.height === 0 ) {\n\t\t\tcontinue;\n\t\t}\n\t\trects.push( {\n\t\t\tx: rect.left - overlayRect.left,\n\t\t\ty: rect.top - overlayRect.top,\n\t\t\twidth: rect.width,\n\t\t\theight: rect.height,\n\t\t} );\n\t}\n\n\t// Fallback: if getClientRects returned nothing, use the block's bounding rect.\n\tif ( rects.length === 0 ) {\n\t\tconst blockRect = blockElement.getBoundingClientRect();\n\t\tif ( blockRect.width > 0 && blockRect.height > 0 ) {\n\t\t\trects.push( {\n\t\t\t\tx: blockRect.left - overlayRect.left,\n\t\t\t\ty: blockRect.top - overlayRect.top,\n\t\t\t\twidth: blockRect.width,\n\t\t\t\theight: blockRect.height,\n\t\t\t} );\n\t\t}\n\t}\n\n\treturn rects;\n};\n\n/**\n * Finds all block elements between two blocks in DOM order (exclusive of start and end).\n *\n * @param startBlockId - The clientId of the start block\n * @param endBlockId - The clientId of the end block\n * @param editorDocument - The editor document\n * @return Array of intermediate block HTMLElements in document order\n */\nexport const getBlocksBetween = (\n\tstartBlockId: string,\n\tendBlockId: string,\n\teditorDocument: Document\n): HTMLElement[] => {\n\tconst allBlocks =\n\t\teditorDocument.querySelectorAll< HTMLElement >( '[data-block]' );\n\n\tlet startIndex = -1;\n\tlet endIndex = -1;\n\n\tfor ( let i = 0; i < allBlocks.length; i++ ) {\n\t\tconst blockId = allBlocks[ i ].getAttribute( 'data-block' );\n\t\tif ( blockId === startBlockId ) {\n\t\t\tstartIndex = i;\n\t\t}\n\t\tif ( blockId === endBlockId ) {\n\t\t\tendIndex = i;\n\t\t}\n\t}\n\n\tif ( startIndex === -1 || endIndex === -1 ) {\n\t\treturn [];\n\t}\n\n\t// Normalize order.\n\tif ( startIndex > endIndex ) {\n\t\t[ startIndex, endIndex ] = [ endIndex, startIndex ];\n\t}\n\n\tconst result: HTMLElement[] = [];\n\tfor ( let i = startIndex + 1; i < endIndex; i++ ) {\n\t\tresult.push( allBlocks[ i ] );\n\t}\n\treturn result;\n};\n\n/**\n * Given a block element and a character offset, returns an exact inner node and offset for use in a range.\n *\n * @param blockElement - The block element\n * @param offset - The character offset\n * @param editorDocument - The editor document\n * @return The node and offset of the character at the offset\n */\nexport const findInnerBlockOffset = (\n\tblockElement: HTMLElement,\n\toffset: number,\n\teditorDocument: Document\n) => {\n\tconst treeWalker = editorDocument.createTreeWalker(\n\t\tblockElement,\n\t\tNodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT // eslint-disable-line no-bitwise\n\t);\n\n\tlet currentOffset = 0;\n\tlet lastTextNode: Node | null = null;\n\n\tlet node: Node | null = null;\n\tlet nodeCount = 1;\n\n\twhile ( ( node = treeWalker.nextNode() ) ) {\n\t\tnodeCount++;\n\n\t\tif ( nodeCount > MAX_NODE_OFFSET_COUNT ) {\n\t\t\t// If we've walked too many nodes, return the last text node or the beginning of the block.\n\t\t\tif ( lastTextNode ) {\n\t\t\t\treturn { node: lastTextNode, offset: 0 };\n\t\t\t}\n\t\t\treturn { node: blockElement, offset: 0 };\n\t\t}\n\n\t\tconst nodeLength = node.nodeValue?.length ?? 0;\n\n\t\tif ( node.nodeType === Node.ELEMENT_NODE ) {\n\t\t\tif ( node.nodeName === 'BR' ) {\n\t\t\t\t// Treat <br> as a single \"\\n\" character.\n\n\t\t\t\tif ( currentOffset + 1 >= offset ) {\n\t\t\t\t\t// If the <br> occurs right on the target offset, return the next text node.\n\t\t\t\t\tconst nodeAfterBr = treeWalker.nextNode();\n\n\t\t\t\t\tif ( nodeAfterBr?.nodeType === Node.TEXT_NODE ) {\n\t\t\t\t\t\treturn { node: nodeAfterBr, offset: 0 };\n\t\t\t\t\t} else if ( lastTextNode ) {\n\t\t\t\t\t\t// If there's no text node after the <br>, return the end offset of the last text node.\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tnode: lastTextNode,\n\t\t\t\t\t\t\toffset: lastTextNode.nodeValue?.length ?? 0,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\t// Just in case, if there's no last text node, return the beginning of the block.\n\t\t\t\t\treturn { node: blockElement, offset: 0 };\n\t\t\t\t}\n\n\t\t\t\t// The <br> is before the target offset. Count it as a single character.\n\t\t\t\tcurrentOffset += 1;\n\t\t\t\tcontinue;\n\t\t\t} else {\n\t\t\t\t// Skip other element types.\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif ( nodeLength === 0 ) {\n\t\t\t// Skip empty nodes.\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ( currentOffset + nodeLength >= offset ) {\n\t\t\t// This node exceeds the target offset. Return the node and the position of the offset within it.\n\t\t\treturn { node, offset: offset - currentOffset };\n\t\t}\n\n\t\tcurrentOffset += nodeLength;\n\n\t\tif ( node.nodeType === Node.TEXT_NODE ) {\n\t\t\tlastTextNode = node;\n\t\t}\n\t}\n\n\tif ( lastTextNode && lastTextNode.nodeValue?.length ) {\n\t\t// We didn't reach the target offset. Return the last text node's last character.\n\t\treturn { node: lastTextNode, offset: lastTextNode.nodeValue.length };\n\t}\n\n\t// We didn't find any text nodes. Return the beginning of the block.\n\treturn { node: blockElement, offset: 0 };\n};\n\n/**\n * Check if node `a` precedes node `b` in document order.\n *\n * @param a - First node.\n * @param b - Second node.\n * @return True if `a` comes before `b`.\n */\nexport const isNodeBefore = ( a: Node, b: Node ): boolean =>\n\ta.compareDocumentPosition( b ) === Node.DOCUMENT_POSITION_FOLLOWING;\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["export interface SelectionRect {\n\tx: number;\n\ty: number;\n\twidth: number;\n\theight: number;\n}\n\nexport interface CursorCoords {\n\tx: number;\n\ty: number;\n\theight: number;\n}\n\nconst MAX_NODE_OFFSET_COUNT = 500;\n\n/**\n * Given a selection, returns the coordinates of the cursor in the block.\n *\n * @param absolutePositionIndex - The absolute position index\n * @param blockElement - The block element (or null if deleted)\n * @param editorDocument - The editor document\n * @param overlayRect - Pre-computed bounding rect of the overlay element\n * @return The position of the cursor\n */\nexport const getCursorPosition = (\n\tabsolutePositionIndex: number | null,\n\tblockElement: HTMLElement | null,\n\teditorDocument: Document,\n\toverlayRect: DOMRect\n): CursorCoords | null => {\n\tif ( absolutePositionIndex === null || ! blockElement ) {\n\t\treturn null;\n\t}\n\n\treturn (\n\t\tgetOffsetPositionInBlock(\n\t\t\tblockElement,\n\t\t\tabsolutePositionIndex,\n\t\t\teditorDocument,\n\t\t\toverlayRect\n\t\t) ?? null\n\t);\n};\n\n/**\n * Given a block element and a character offset, returns the coordinates for drawing a visual cursor in the block.\n *\n * @param blockElement - The block element\n * @param charOffset - The character offset\n * @param editorDocument - The editor document\n * @param overlayRect - Pre-computed bounding rect of the overlay element\n * @return The position of the cursor\n */\nconst getOffsetPositionInBlock = (\n\tblockElement: HTMLElement,\n\tcharOffset: number,\n\teditorDocument: Document,\n\toverlayRect: DOMRect\n) => {\n\tconst { node, offset } = findInnerBlockOffset(\n\t\tblockElement,\n\t\tcharOffset,\n\t\teditorDocument\n\t);\n\n\tconst cursorRange = editorDocument.createRange();\n\n\ttry {\n\t\tcursorRange.setStart( node, offset );\n\t} catch {\n\t\treturn null;\n\t}\n\n\t// Ensure the range only represents single point in the DOM.\n\tcursorRange.collapse( true );\n\n\tconst cursorRect = cursorRange.getBoundingClientRect();\n\tconst blockRect = blockElement.getBoundingClientRect();\n\n\tlet cursorX = 0;\n\tlet cursorY = 0;\n\n\tif (\n\t\tcursorRect.x === 0 &&\n\t\tcursorRect.y === 0 &&\n\t\tcursorRect.width === 0 &&\n\t\tcursorRect.height === 0\n\t) {\n\t\t// This can happen for empty blocks.\n\t\tcursorX = blockRect.left - overlayRect.left;\n\t\tcursorY = blockRect.top - overlayRect.top;\n\t} else {\n\t\tcursorX = cursorRect.left - overlayRect.left;\n\t\tcursorY = cursorRect.top - overlayRect.top;\n\t}\n\n\tlet cursorHeight = cursorRect.height;\n\tif ( cursorHeight === 0 ) {\n\t\tconst view = editorDocument.defaultView ?? window;\n\t\tcursorHeight =\n\t\t\tparseInt( view.getComputedStyle( blockElement ).lineHeight, 10 ) ||\n\t\t\tblockRect.height;\n\t}\n\n\treturn {\n\t\tx: cursorX,\n\t\ty: cursorY,\n\t\theight: cursorHeight,\n\t};\n};\n\n/**\n * Computes selection highlight rectangles for a text range within a single block.\n *\n * @param blockElement - The block element\n * @param startOffset - Start character offset within the block\n * @param endOffset - End character offset within the block\n * @param editorDocument - The editor document\n * @param overlayRect - Pre-computed bounding rect of the overlay element\n * @return Array of selection rectangles relative to the overlay, or null on failure\n */\nexport const getSelectionRects = (\n\tblockElement: HTMLElement,\n\tstartOffset: number,\n\tendOffset: number,\n\teditorDocument: Document,\n\toverlayRect: DOMRect\n): SelectionRect[] | null => {\n\t// Normalize direction.\n\tlet normalizedStart = startOffset;\n\tlet normalizedEnd = endOffset;\n\tif ( normalizedStart > normalizedEnd ) {\n\t\t[ normalizedStart, normalizedEnd ] = [ normalizedEnd, normalizedStart ];\n\t}\n\n\tconst startPos = findInnerBlockOffset(\n\t\tblockElement,\n\t\tnormalizedStart,\n\t\teditorDocument\n\t);\n\tconst endPos = findInnerBlockOffset(\n\t\tblockElement,\n\t\tnormalizedEnd,\n\t\teditorDocument\n\t);\n\n\tconst range = editorDocument.createRange();\n\ttry {\n\t\trange.setStart( startPos.node, startPos.offset );\n\t\trange.setEnd( endPos.node, endPos.offset );\n\t} catch {\n\t\treturn null;\n\t}\n\n\tconst clientRects = range.getClientRects();\n\tconst rects: SelectionRect[] = [];\n\n\tfor ( const rect of clientRects ) {\n\t\tif ( rect.width === 0 && rect.height === 0 ) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst x = rect.left - overlayRect.left;\n\t\tconst y = rect.top - overlayRect.top;\n\n\t\t// Range.getClientRects() can return duplicate rects at inline\n\t\t// formatting boundaries (e.g. <em>, <strong>). Skip exact matches.\n\t\tconst isDuplicate = rects.some(\n\t\t\t( r ) =>\n\t\t\t\tr.x === x &&\n\t\t\t\tr.y === y &&\n\t\t\t\tr.width === rect.width &&\n\t\t\t\tr.height === rect.height\n\t\t);\n\t\tif ( isDuplicate ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\trects.push( {\n\t\t\tx,\n\t\t\ty,\n\t\t\twidth: rect.width,\n\t\t\theight: rect.height,\n\t\t} );\n\t}\n\n\treturn rects.length > 0 ? rects : null;\n};\n\n/**\n * Computes selection highlight rectangles for the full content of a block.\n * Used for intermediate blocks in a multi-block selection.\n *\n * @param blockElement - The block element\n * @param editorDocument - The editor document\n * @param overlayRect - Pre-computed bounding rect of the overlay element\n * @return Array of selection rectangles relative to the overlay\n */\nexport const getFullBlockSelectionRects = (\n\tblockElement: HTMLElement,\n\teditorDocument: Document,\n\toverlayRect: DOMRect\n): SelectionRect[] => {\n\tconst range = editorDocument.createRange();\n\trange.selectNodeContents( blockElement );\n\tconst clientRects = range.getClientRects();\n\tconst rects: SelectionRect[] = [];\n\n\tfor ( const rect of clientRects ) {\n\t\tif ( rect.width === 0 && rect.height === 0 ) {\n\t\t\tcontinue;\n\t\t}\n\t\trects.push( {\n\t\t\tx: rect.left - overlayRect.left,\n\t\t\ty: rect.top - overlayRect.top,\n\t\t\twidth: rect.width,\n\t\t\theight: rect.height,\n\t\t} );\n\t}\n\n\t// Fallback: if getClientRects returned nothing, use the block's bounding rect.\n\tif ( rects.length === 0 ) {\n\t\tconst blockRect = blockElement.getBoundingClientRect();\n\t\tif ( blockRect.width > 0 && blockRect.height > 0 ) {\n\t\t\trects.push( {\n\t\t\t\tx: blockRect.left - overlayRect.left,\n\t\t\t\ty: blockRect.top - overlayRect.top,\n\t\t\t\twidth: blockRect.width,\n\t\t\t\theight: blockRect.height,\n\t\t\t} );\n\t\t}\n\t}\n\n\treturn rects;\n};\n\n/**\n * Finds all block elements between two blocks in DOM order (exclusive of start and end).\n *\n * @param startBlockId - The clientId of the start block\n * @param endBlockId - The clientId of the end block\n * @param editorDocument - The editor document\n * @return Array of intermediate block HTMLElements in document order\n */\nexport const getBlocksBetween = (\n\tstartBlockId: string,\n\tendBlockId: string,\n\teditorDocument: Document\n): HTMLElement[] => {\n\tconst allBlocks =\n\t\teditorDocument.querySelectorAll< HTMLElement >( '[data-block]' );\n\n\tlet startIndex = -1;\n\tlet endIndex = -1;\n\n\tfor ( let i = 0; i < allBlocks.length; i++ ) {\n\t\tconst blockId = allBlocks[ i ].getAttribute( 'data-block' );\n\t\tif ( blockId === startBlockId ) {\n\t\t\tstartIndex = i;\n\t\t}\n\t\tif ( blockId === endBlockId ) {\n\t\t\tendIndex = i;\n\t\t}\n\t}\n\n\tif ( startIndex === -1 || endIndex === -1 ) {\n\t\treturn [];\n\t}\n\n\t// Normalize order.\n\tif ( startIndex > endIndex ) {\n\t\t[ startIndex, endIndex ] = [ endIndex, startIndex ];\n\t}\n\n\tconst result: HTMLElement[] = [];\n\tfor ( let i = startIndex + 1; i < endIndex; i++ ) {\n\t\tresult.push( allBlocks[ i ] );\n\t}\n\treturn result;\n};\n\n/**\n * Given a block element and a character offset, returns an exact inner node and offset for use in a range.\n *\n * @param blockElement - The block element\n * @param offset - The character offset\n * @param editorDocument - The editor document\n * @return The node and offset of the character at the offset\n */\nexport const findInnerBlockOffset = (\n\tblockElement: HTMLElement,\n\toffset: number,\n\teditorDocument: Document\n) => {\n\tconst treeWalker = editorDocument.createTreeWalker(\n\t\tblockElement,\n\t\tNodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT // eslint-disable-line no-bitwise\n\t);\n\n\tlet currentOffset = 0;\n\tlet lastTextNode: Node | null = null;\n\n\tlet node: Node | null = null;\n\tlet nodeCount = 1;\n\n\twhile ( ( node = treeWalker.nextNode() ) ) {\n\t\tnodeCount++;\n\n\t\tif ( nodeCount > MAX_NODE_OFFSET_COUNT ) {\n\t\t\t// If we've walked too many nodes, return the last text node or the beginning of the block.\n\t\t\tif ( lastTextNode ) {\n\t\t\t\treturn { node: lastTextNode, offset: 0 };\n\t\t\t}\n\t\t\treturn { node: blockElement, offset: 0 };\n\t\t}\n\n\t\tconst nodeLength = node.nodeValue?.length ?? 0;\n\n\t\tif ( node.nodeType === Node.ELEMENT_NODE ) {\n\t\t\tif ( node.nodeName === 'BR' ) {\n\t\t\t\t// Treat <br> as a single \"\\n\" character.\n\n\t\t\t\tif ( currentOffset + 1 >= offset ) {\n\t\t\t\t\t// If the <br> occurs right on the target offset, return the next text node.\n\t\t\t\t\tconst nodeAfterBr = treeWalker.nextNode();\n\n\t\t\t\t\tif ( nodeAfterBr?.nodeType === Node.TEXT_NODE ) {\n\t\t\t\t\t\treturn { node: nodeAfterBr, offset: 0 };\n\t\t\t\t\t} else if ( lastTextNode ) {\n\t\t\t\t\t\t// If there's no text node after the <br>, return the end offset of the last text node.\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tnode: lastTextNode,\n\t\t\t\t\t\t\toffset: lastTextNode.nodeValue?.length ?? 0,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\t// Just in case, if there's no last text node, return the beginning of the block.\n\t\t\t\t\treturn { node: blockElement, offset: 0 };\n\t\t\t\t}\n\n\t\t\t\t// The <br> is before the target offset. Count it as a single character.\n\t\t\t\tcurrentOffset += 1;\n\t\t\t\tcontinue;\n\t\t\t} else {\n\t\t\t\t// Skip other element types.\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif ( nodeLength === 0 ) {\n\t\t\t// Skip empty nodes.\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ( currentOffset + nodeLength >= offset ) {\n\t\t\t// This node exceeds the target offset. Return the node and the position of the offset within it.\n\t\t\treturn { node, offset: offset - currentOffset };\n\t\t}\n\n\t\tcurrentOffset += nodeLength;\n\n\t\tif ( node.nodeType === Node.TEXT_NODE ) {\n\t\t\tlastTextNode = node;\n\t\t}\n\t}\n\n\tif ( lastTextNode && lastTextNode.nodeValue?.length ) {\n\t\t// We didn't reach the target offset. Return the last text node's last character.\n\t\treturn { node: lastTextNode, offset: lastTextNode.nodeValue.length };\n\t}\n\n\t// We didn't find any text nodes. Return the beginning of the block.\n\treturn { node: blockElement, offset: 0 };\n};\n\n/**\n * Check if node `a` precedes node `b` in document order.\n *\n * @param a - First node.\n * @param b - Second node.\n * @return True if `a` comes before `b`.\n */\nexport const isNodeBefore = ( a: Node, b: Node ): boolean =>\n\ta.compareDocumentPosition( b ) === Node.DOCUMENT_POSITION_FOLLOWING;\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA,IAAM,wBAAwB;AAWvB,IAAM,oBAAoB,CAChC,uBACA,cACA,gBACA,gBACyB;AACzB,MAAK,0BAA0B,QAAQ,CAAE,cAAe;AACvD,WAAO;AAAA,EACR;AAEA,SACC;AAAA,IACC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,KAAK;AAEP;AAWA,IAAM,2BAA2B,CAChC,cACA,YACA,gBACA,gBACI;AACJ,QAAM,EAAE,MAAM,OAAO,IAAI;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,EACD;AAEA,QAAM,cAAc,eAAe,YAAY;AAE/C,MAAI;AACH,gBAAY,SAAU,MAAM,MAAO;AAAA,EACpC,QAAQ;AACP,WAAO;AAAA,EACR;AAGA,cAAY,SAAU,IAAK;AAE3B,QAAM,aAAa,YAAY,sBAAsB;AACrD,QAAM,YAAY,aAAa,sBAAsB;AAErD,MAAI,UAAU;AACd,MAAI,UAAU;AAEd,MACC,WAAW,MAAM,KACjB,WAAW,MAAM,KACjB,WAAW,UAAU,KACrB,WAAW,WAAW,GACrB;AAED,cAAU,UAAU,OAAO,YAAY;AACvC,cAAU,UAAU,MAAM,YAAY;AAAA,EACvC,OAAO;AACN,cAAU,WAAW,OAAO,YAAY;AACxC,cAAU,WAAW,MAAM,YAAY;AAAA,EACxC;AAEA,MAAI,eAAe,WAAW;AAC9B,MAAK,iBAAiB,GAAI;AACzB,UAAM,OAAO,eAAe,eAAe;AAC3C,mBACC,SAAU,KAAK,iBAAkB,YAAa,EAAE,YAAY,EAAG,KAC/D,UAAU;AAAA,EACZ;AAEA,SAAO;AAAA,IACN,GAAG;AAAA,IACH,GAAG;AAAA,IACH,QAAQ;AAAA,EACT;AACD;AAYO,IAAM,oBAAoB,CAChC,cACA,aACA,WACA,gBACA,gBAC4B;AAE5B,MAAI,kBAAkB;AACtB,MAAI,gBAAgB;AACpB,MAAK,kBAAkB,eAAgB;AACtC,KAAE,iBAAiB,aAAc,IAAI,CAAE,eAAe,eAAgB;AAAA,EACvE;AAEA,QAAM,WAAW;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACA,QAAM,SAAS;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,EACD;AAEA,QAAM,QAAQ,eAAe,YAAY;AACzC,MAAI;AACH,UAAM,SAAU,SAAS,MAAM,SAAS,MAAO;AAC/C,UAAM,OAAQ,OAAO,MAAM,OAAO,MAAO;AAAA,EAC1C,QAAQ;AACP,WAAO;AAAA,EACR;AAEA,QAAM,cAAc,MAAM,eAAe;AACzC,QAAM,QAAyB,CAAC;AAEhC,aAAY,QAAQ,aAAc;AACjC,QAAK,KAAK,UAAU,KAAK,KAAK,WAAW,GAAI;AAC5C;AAAA,IACD;AACA,UAAM,IAAI,KAAK,OAAO,YAAY;AAClC,UAAM,IAAI,KAAK,MAAM,YAAY;AAIjC,UAAM,cAAc,MAAM;AAAA,MACzB,CAAE,MACD,EAAE,MAAM,KACR,EAAE,MAAM,KACR,EAAE,UAAU,KAAK,SACjB,EAAE,WAAW,KAAK;AAAA,IACpB;AACA,QAAK,aAAc;AAClB;AAAA,IACD;AAEA,UAAM,KAAM;AAAA,MACX;AAAA,MACA;AAAA,MACA,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,IACd,CAAE;AAAA,EACH;AAEA,SAAO,MAAM,SAAS,IAAI,QAAQ;AACnC;AAWO,IAAM,6BAA6B,CACzC,cACA,gBACA,gBACqB;AACrB,QAAM,QAAQ,eAAe,YAAY;AACzC,QAAM,mBAAoB,YAAa;AACvC,QAAM,cAAc,MAAM,eAAe;AACzC,QAAM,QAAyB,CAAC;AAEhC,aAAY,QAAQ,aAAc;AACjC,QAAK,KAAK,UAAU,KAAK,KAAK,WAAW,GAAI;AAC5C;AAAA,IACD;AACA,UAAM,KAAM;AAAA,MACX,GAAG,KAAK,OAAO,YAAY;AAAA,MAC3B,GAAG,KAAK,MAAM,YAAY;AAAA,MAC1B,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,IACd,CAAE;AAAA,EACH;AAGA,MAAK,MAAM,WAAW,GAAI;AACzB,UAAM,YAAY,aAAa,sBAAsB;AACrD,QAAK,UAAU,QAAQ,KAAK,UAAU,SAAS,GAAI;AAClD,YAAM,KAAM;AAAA,QACX,GAAG,UAAU,OAAO,YAAY;AAAA,QAChC,GAAG,UAAU,MAAM,YAAY;AAAA,QAC/B,OAAO,UAAU;AAAA,QACjB,QAAQ,UAAU;AAAA,MACnB,CAAE;AAAA,IACH;AAAA,EACD;AAEA,SAAO;AACR;AAUO,IAAM,mBAAmB,CAC/B,cACA,YACA,mBACmB;AACnB,QAAM,YACL,eAAe,iBAAiC,cAAe;AAEhE,MAAI,aAAa;AACjB,MAAI,WAAW;AAEf,WAAU,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAM;AAC5C,UAAM,UAAU,UAAW,CAAE,EAAE,aAAc,YAAa;AAC1D,QAAK,YAAY,cAAe;AAC/B,mBAAa;AAAA,IACd;AACA,QAAK,YAAY,YAAa;AAC7B,iBAAW;AAAA,IACZ;AAAA,EACD;AAEA,MAAK,eAAe,MAAM,aAAa,IAAK;AAC3C,WAAO,CAAC;AAAA,EACT;AAGA,MAAK,aAAa,UAAW;AAC5B,KAAE,YAAY,QAAS,IAAI,CAAE,UAAU,UAAW;AAAA,EACnD;AAEA,QAAM,SAAwB,CAAC;AAC/B,WAAU,IAAI,aAAa,GAAG,IAAI,UAAU,KAAM;AACjD,WAAO,KAAM,UAAW,CAAE,CAAE;AAAA,EAC7B;AACA,SAAO;AACR;AAUO,IAAM,uBAAuB,CACnC,cACA,QACA,mBACI;AACJ,QAAM,aAAa,eAAe;AAAA,IACjC;AAAA,IACA,WAAW,YAAY,WAAW;AAAA;AAAA,EACnC;AAEA,MAAI,gBAAgB;AACpB,MAAI,eAA4B;AAEhC,MAAI,OAAoB;AACxB,MAAI,YAAY;AAEhB,SAAU,OAAO,WAAW,SAAS,GAAM;AAC1C;AAEA,QAAK,YAAY,uBAAwB;AAExC,UAAK,cAAe;AACnB,eAAO,EAAE,MAAM,cAAc,QAAQ,EAAE;AAAA,MACxC;AACA,aAAO,EAAE,MAAM,cAAc,QAAQ,EAAE;AAAA,IACxC;AAEA,UAAM,aAAa,KAAK,WAAW,UAAU;AAE7C,QAAK,KAAK,aAAa,KAAK,cAAe;AAC1C,UAAK,KAAK,aAAa,MAAO;AAG7B,YAAK,gBAAgB,KAAK,QAAS;AAElC,gBAAM,cAAc,WAAW,SAAS;AAExC,cAAK,aAAa,aAAa,KAAK,WAAY;AAC/C,mBAAO,EAAE,MAAM,aAAa,QAAQ,EAAE;AAAA,UACvC,WAAY,cAAe;AAE1B,mBAAO;AAAA,cACN,MAAM;AAAA,cACN,QAAQ,aAAa,WAAW,UAAU;AAAA,YAC3C;AAAA,UACD;AAEA,iBAAO,EAAE,MAAM,cAAc,QAAQ,EAAE;AAAA,QACxC;AAGA,yBAAiB;AACjB;AAAA,MACD,OAAO;AAEN;AAAA,MACD;AAAA,IACD;AAEA,QAAK,eAAe,GAAI;AAEvB;AAAA,IACD;AAEA,QAAK,gBAAgB,cAAc,QAAS;AAE3C,aAAO,EAAE,MAAM,QAAQ,SAAS,cAAc;AAAA,IAC/C;AAEA,qBAAiB;AAEjB,QAAK,KAAK,aAAa,KAAK,WAAY;AACvC,qBAAe;AAAA,IAChB;AAAA,EACD;AAEA,MAAK,gBAAgB,aAAa,WAAW,QAAS;AAErD,WAAO,EAAE,MAAM,cAAc,QAAQ,aAAa,UAAU,OAAO;AAAA,EACpE;AAGA,SAAO,EAAE,MAAM,cAAc,QAAQ,EAAE;AACxC;AASO,IAAM,eAAe,CAAE,GAAS,MACtC,EAAE,wBAAyB,CAAE,MAAM,KAAK;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // packages/editor/src/components/collaborators-overlay/cursor-registry.ts
21
+ var cursor_registry_exports = {};
22
+ __export(cursor_registry_exports, {
23
+ createCursorRegistry: () => createCursorRegistry
24
+ });
25
+ module.exports = __toCommonJS(cursor_registry_exports);
26
+ function highlightCursor(element, duration) {
27
+ element.classList.add("collaborators-overlay-cursor-highlighted");
28
+ setTimeout(() => {
29
+ element.classList.remove("collaborators-overlay-cursor-highlighted");
30
+ }, duration);
31
+ }
32
+ function createCursorRegistry() {
33
+ const cursorMap = /* @__PURE__ */ new Map();
34
+ return {
35
+ /**
36
+ * Register a cursor element when it's created.
37
+ *
38
+ * @param clientId - The clientId of the cursor to register.
39
+ * @param element - The cursor element to register.
40
+ */
41
+ registerCursor(clientId, element) {
42
+ cursorMap.set(clientId, element);
43
+ },
44
+ /**
45
+ * Unregister a cursor element when it's removed.
46
+ *
47
+ * @param clientId - The clientId of the cursor to unregister.
48
+ */
49
+ unregisterCursor(clientId) {
50
+ cursorMap.delete(clientId);
51
+ },
52
+ /**
53
+ * Scroll to a cursor by clientId.
54
+ *
55
+ * @param clientId - The clientId of the cursor to scroll to.
56
+ * @param options - The options for the scroll.
57
+ * @return true if cursor was found and scrolled to, false otherwise.
58
+ */
59
+ scrollToCursor(clientId, options) {
60
+ const cursorElement = cursorMap.get(clientId);
61
+ if (!cursorElement) {
62
+ return false;
63
+ }
64
+ cursorElement.scrollIntoView({
65
+ behavior: options?.behavior ?? "smooth",
66
+ block: options?.block ?? "center",
67
+ inline: options?.inline ?? "nearest"
68
+ });
69
+ if (options?.highlightDuration) {
70
+ highlightCursor(cursorElement, options.highlightDuration);
71
+ }
72
+ return true;
73
+ },
74
+ /**
75
+ * Clear the registry.
76
+ */
77
+ removeAll() {
78
+ cursorMap.clear();
79
+ }
80
+ };
81
+ }
82
+ // Annotate the CommonJS export names for ESM import in node:
83
+ 0 && (module.exports = {
84
+ createCursorRegistry
85
+ });
86
+ //# sourceMappingURL=cursor-registry.cjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/components/collaborators-overlay/cursor-registry.ts"],
4
+ "sourcesContent": ["interface ScrollToCursorOptions {\n\tbehavior?: ScrollBehavior;\n\tblock?: ScrollLogicalPosition;\n\tinline?: ScrollLogicalPosition;\n\thighlightDuration?: number;\n}\n\n/**\n * Cursor Registry\n * ===\n * This registry stores references to cursor elements so that we can access them\n * in different parts of the component tree. This would more ideally be solved\n * with React context or state in the awareness store, but:\n *\n * 1. EditorPresence and BlockCanvasCover slot/fill break context propagation. We\n * don't currently have a way to provide context to both the slot and fill.\n * 2. Storing pointers to the cursor elements in the awareness store might be a\n * better solution, but would require broader refactoring.\n *\n * For now, we create a single instance of this registry and pass it down to the\n * components that need it. It's important that we create a single instance and\n * not a new instance per component or render; use useState with a lazy\n * initializer to accomplish this.\n */\n\nfunction highlightCursor( element: HTMLElement, duration: number ): void {\n\telement.classList.add( 'collaborators-overlay-cursor-highlighted' );\n\n\tsetTimeout( () => {\n\t\telement.classList.remove( 'collaborators-overlay-cursor-highlighted' );\n\t}, duration );\n}\n\nexport function createCursorRegistry() {\n\tconst cursorMap = new Map< number, HTMLElement >();\n\n\treturn {\n\t\t/**\n\t\t * Register a cursor element when it's created.\n\t\t *\n\t\t * @param clientId - The clientId of the cursor to register.\n\t\t * @param element - The cursor element to register.\n\t\t */\n\t\tregisterCursor( clientId: number, element: HTMLElement ): void {\n\t\t\tcursorMap.set( clientId, element );\n\t\t},\n\n\t\t/**\n\t\t * Unregister a cursor element when it's removed.\n\t\t *\n\t\t * @param clientId - The clientId of the cursor to unregister.\n\t\t */\n\t\tunregisterCursor( clientId: number ): void {\n\t\t\tcursorMap.delete( clientId );\n\t\t},\n\n\t\t/**\n\t\t * Scroll to a cursor by clientId.\n\t\t *\n\t\t * @param clientId - The clientId of the cursor to scroll to.\n\t\t * @param options - The options for the scroll.\n\t\t * @return true if cursor was found and scrolled to, false otherwise.\n\t\t */\n\t\tscrollToCursor(\n\t\t\tclientId: number,\n\t\t\toptions?: ScrollToCursorOptions\n\t\t): boolean {\n\t\t\tconst cursorElement = cursorMap.get( clientId );\n\n\t\t\tif ( ! cursorElement ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tcursorElement.scrollIntoView( {\n\t\t\t\tbehavior: options?.behavior ?? 'smooth',\n\t\t\t\tblock: options?.block ?? 'center',\n\t\t\t\tinline: options?.inline ?? 'nearest',\n\t\t\t} );\n\n\t\t\tif ( options?.highlightDuration ) {\n\t\t\t\thighlightCursor( cursorElement, options.highlightDuration );\n\t\t\t}\n\n\t\t\treturn true;\n\t\t},\n\n\t\t/**\n\t\t * Clear the registry.\n\t\t */\n\t\tremoveAll(): void {\n\t\t\tcursorMap.clear();\n\t\t},\n\t};\n}\n\nexport type CursorRegistry = ReturnType< typeof createCursorRegistry >;\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAyBA,SAAS,gBAAiB,SAAsB,UAAyB;AACxE,UAAQ,UAAU,IAAK,0CAA2C;AAElE,aAAY,MAAM;AACjB,YAAQ,UAAU,OAAQ,0CAA2C;AAAA,EACtE,GAAG,QAAS;AACb;AAEO,SAAS,uBAAuB;AACtC,QAAM,YAAY,oBAAI,IAA2B;AAEjD,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAON,eAAgB,UAAkB,SAA6B;AAC9D,gBAAU,IAAK,UAAU,OAAQ;AAAA,IAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOA,iBAAkB,UAAyB;AAC1C,gBAAU,OAAQ,QAAS;AAAA,IAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IASA,eACC,UACA,SACU;AACV,YAAM,gBAAgB,UAAU,IAAK,QAAS;AAE9C,UAAK,CAAE,eAAgB;AACtB,eAAO;AAAA,MACR;AAEA,oBAAc,eAAgB;AAAA,QAC7B,UAAU,SAAS,YAAY;AAAA,QAC/B,OAAO,SAAS,SAAS;AAAA,QACzB,QAAQ,SAAS,UAAU;AAAA,MAC5B,CAAE;AAEF,UAAK,SAAS,mBAAoB;AACjC,wBAAiB,eAAe,QAAQ,iBAAkB;AAAA,MAC3D;AAEA,aAAO;AAAA,IACR;AAAA;AAAA;AAAA;AAAA,IAKA,YAAkB;AACjB,gBAAU,MAAM;AAAA,IACjB;AAAA,EACD;AACD;",
6
+ "names": []
7
+ }
@@ -28,7 +28,11 @@ var import_lock_unlock = require("../../lock-unlock.cjs");
28
28
  var import_overlay = require("./overlay.cjs");
29
29
  var import_jsx_runtime = require("react/jsx-runtime");
30
30
  var { BlockCanvasCover } = (0, import_lock_unlock.unlock)(import_block_editor.privateApis);
31
- function CollaboratorsOverlay({ postId, postType }) {
31
+ function CollaboratorsOverlay({
32
+ postId,
33
+ postType,
34
+ cursorRegistry
35
+ }) {
32
36
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BlockCanvasCover.Fill, { children: ({
33
37
  containerRef
34
38
  }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -36,7 +40,8 @@ function CollaboratorsOverlay({ postId, postType }) {
36
40
  {
37
41
  blockEditorDocument: containerRef.current?.ownerDocument,
38
42
  postId,
39
- postType
43
+ postType,
44
+ cursorRegistry
40
45
  }
41
46
  ) });
42
47
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/collaborators-overlay/index.tsx"],
4
- "sourcesContent": ["/**\n * WordPress dependencies\n */\n// @ts-expect-error No exported types\nimport { privateApis } from '@wordpress/block-editor';\n\n/**\n * Internal dependencies\n */\nimport { unlock } from '../../lock-unlock';\nimport { Overlay } from './overlay';\n\nconst { BlockCanvasCover } = unlock( privateApis );\n\ninterface Props {\n\tpostId: number | null;\n\tpostType: string | null;\n}\n\n/**\n * Collaborators Overlay component\n * @param props - The props for the CollaboratorsOverlay component\n * @param props.postId - The ID of the post\n * @param props.postType - The type of the post\n * @return The CollaboratorsOverlay component\n */\nexport function CollaboratorsOverlay( { postId, postType }: Props ) {\n\treturn (\n\t\t<BlockCanvasCover.Fill>\n\t\t\t{ ( {\n\t\t\t\tcontainerRef,\n\t\t\t}: {\n\t\t\t\tcontainerRef: React.MutableRefObject< HTMLElement | null >;\n\t\t\t} ) => (\n\t\t\t\t<Overlay\n\t\t\t\t\tblockEditorDocument={ containerRef.current?.ownerDocument }\n\t\t\t\t\tpostId={ postId }\n\t\t\t\t\tpostType={ postType }\n\t\t\t\t/>\n\t\t\t) }\n\t\t</BlockCanvasCover.Fill>\n\t);\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,0BAA4B;AAK5B,yBAAuB;AACvB,qBAAwB;AAwBpB;AAtBJ,IAAM,EAAE,iBAAiB,QAAI,2BAAQ,+BAAY;AAc1C,SAAS,qBAAsB,EAAE,QAAQ,SAAS,GAAW;AACnE,SACC,4CAAC,iBAAiB,MAAjB,EACE,WAAE;AAAA,IACH;AAAA,EACD,MAGC;AAAA,IAAC;AAAA;AAAA,MACA,qBAAsB,aAAa,SAAS;AAAA,MAC5C;AAAA,MACA;AAAA;AAAA,EACD,GAEF;AAEF;",
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\n// @ts-expect-error No exported types\nimport { privateApis } from '@wordpress/block-editor';\n\n/**\n * Internal dependencies\n */\nimport { unlock } from '../../lock-unlock';\nimport { Overlay } from './overlay';\nimport { type CursorRegistry } from './cursor-registry';\n\nconst { BlockCanvasCover } = unlock( privateApis );\n\ninterface Props {\n\tpostId: number | null;\n\tpostType: string | null;\n\tcursorRegistry?: CursorRegistry;\n}\n\n/**\n * Collaborators Overlay component\n * @param props - The props for the CollaboratorsOverlay component\n * @param props.postId - The ID of the post\n * @param props.postType - The type of the post\n * @param props.cursorRegistry - The shared cursor registry\n * @return The CollaboratorsOverlay component\n */\nexport function CollaboratorsOverlay( {\n\tpostId,\n\tpostType,\n\tcursorRegistry,\n}: Props ) {\n\treturn (\n\t\t<BlockCanvasCover.Fill>\n\t\t\t{ ( {\n\t\t\t\tcontainerRef,\n\t\t\t}: {\n\t\t\t\tcontainerRef: React.MutableRefObject< HTMLElement | null >;\n\t\t\t} ) => (\n\t\t\t\t<Overlay\n\t\t\t\t\tblockEditorDocument={ containerRef.current?.ownerDocument }\n\t\t\t\t\tpostId={ postId }\n\t\t\t\t\tpostType={ postType }\n\t\t\t\t\tcursorRegistry={ cursorRegistry }\n\t\t\t\t/>\n\t\t\t) }\n\t\t</BlockCanvasCover.Fill>\n\t);\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,0BAA4B;AAK5B,yBAAuB;AACvB,qBAAwB;AA+BpB;AA5BJ,IAAM,EAAE,iBAAiB,QAAI,2BAAQ,+BAAY;AAgB1C,SAAS,qBAAsB;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AACD,GAAW;AACV,SACC,4CAAC,iBAAiB,MAAjB,EACE,WAAE;AAAA,IACH;AAAA,EACD,MAGC;AAAA,IAAC;AAAA;AAAA,MACA,qBAAsB,aAAa,SAAS;AAAA,MAC5C;AAAA,MACA;AAAA,MACA;AAAA;AAAA,EACD,GAEF;AAEF;",
6
6
  "names": []
7
7
  }
@@ -131,7 +131,7 @@ var OVERLAY_IFRAME_STYLES = `
131
131
  outline-style: solid;
132
132
  outline-width: calc(var(--wp-admin-border-width-focus) / var(--wp-block-editor-iframe-zoom-out-scale, 1));
133
133
  outline-offset: calc(-1 * var(--wp-admin-border-width-focus) / var(--wp-block-editor-iframe-zoom-out-scale, 1));
134
- box-shadow: inset 0 0 0 calc(var(--wp-admin-border-width-focus, ${import_collaborator_styles.BORDER_WIDTH_FOCUS_FALLBACK}) + ${import_collaborator_styles.BORDER_WIDTH}) ${import_collaborator_styles.WHITE}, 0 0 0 ${import_collaborator_styles.BORDER_WIDTH} ${import_collaborator_styles.WHITE}, ${import_collaborator_styles.ELEVATION_X_SMALL};
134
+ box-shadow: inset 0 0 0 calc((var(--wp-admin-border-width-focus) / var(--wp-block-editor-iframe-zoom-out-scale, 1)) + 0.5px) rgba(${import_collaborator_styles.WHITE}, 0.7);
135
135
  z-index: 1;
136
136
  }
137
137
  @media (prefers-reduced-motion: reduce) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/collaborators-overlay/overlay-iframe-styles.ts"],
4
- "sourcesContent": ["/**\n * CSS for the collaborators overlay \u2014 cursor indicators, block highlights,\n * and positioning of Avatar labels inside the editor canvas iframe.\n */\n\nimport {\n\tBORDER_WIDTH,\n\tBORDER_WIDTH_FOCUS_FALLBACK,\n\tELEVATION_X_SMALL,\n\tGRID_UNIT_05,\n\tGRID_UNIT_10,\n\tWHITE,\n} from './collaborator-styles';\n\nexport const OVERLAY_IFRAME_STYLES = `\n.block-canvas-cover {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n\tpointer-events: none;\n\tz-index: 20000;\n}\n.block-canvas-cover .collaborators-overlay-full {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n}\n.block-canvas-cover .collaborators-overlay-fixed {\n\tposition: fixed;\n\twidth: 100%;\n\theight: 100%;\n}\n.collaborators-overlay-user {\n\tposition: absolute;\n}\n/* Cursor lines render below avatar labels across all users. The parent\n .collaborators-overlay-user has no z-index so it does not create a\n stacking context \u2014 children participate in the shared overlay context. */\n.collaborators-overlay-user-cursor {\n\tposition: absolute;\n\tz-index: 0;\n\twidth: ${ BORDER_WIDTH_FOCUS_FALLBACK };\n\tborder-radius: ${ BORDER_WIDTH };\n\toutline: ${ BORDER_WIDTH } solid ${ WHITE };\n\tbox-shadow: ${ ELEVATION_X_SMALL };\n\tanimation: collaborators-overlay-cursor-blink 1s infinite;\n}\n.collaborators-overlay-selection-rect {\n\tposition: absolute;\n\topacity: 0.15;\n\tpointer-events: none;\n\tborder-radius: 2px;\n}\n\n/* Overlay-specific positioning applied to the Avatar cursor label. */\n.collaborators-overlay-user-label.editor-avatar {\n\tposition: absolute;\n\tz-index: 1;\n\ttransform: translate(-11px, -100%);\n\tmargin-top: -${ GRID_UNIT_05 };\n\tpointer-events: auto;\n\toverflow: visible;\n\twidth: max-content;\n}\n/* Avatar positioned above a highlighted block as a label. */\n.collaborators-overlay-block-label.editor-avatar {\n\tposition: absolute;\n\tz-index: 1;\n\ttransform: translateY(calc(-100% - ${ GRID_UNIT_10 }));\n\tpointer-events: auto;\n\toverflow: visible;\n\twidth: max-content;\n}\n\n@keyframes collaborators-overlay-cursor-blink {\n\t0%, 45% { opacity: 1; }\n\t55%, 95% { opacity: 0; }\n\t100% { opacity: 1; }\n}\n.collaborators-overlay-cursor-highlighted .collaborators-overlay-user-cursor {\n\tanimation: collaborators-overlay-cursor-highlight 0.6s ease-in-out 3;\n}\n.collaborators-overlay-cursor-highlighted .collaborators-overlay-user-label {\n\tanimation: collaborators-overlay-label-highlight 0.6s ease-in-out 3;\n}\n@keyframes collaborators-overlay-cursor-highlight {\n\t0%, 100% {\n\t\ttransform: scale(1);\n\t\tfilter: drop-shadow(0 0 0 transparent);\n\t}\n\t50% {\n\t\ttransform: scale(1.2);\n\t\tfilter: drop-shadow(0 0 8px currentColor);\n\t}\n}\n@keyframes collaborators-overlay-label-highlight {\n\t0%, 100% {\n\t\ttransform: translate(-11px, -100%) scale(1);\n\t\tfilter: drop-shadow(0 0 0 transparent);\n\t}\n\t50% {\n\t\ttransform: translate(-11px, -100%) scale(1.1);\n\t\tfilter: drop-shadow(0 0 6px currentColor);\n\t}\n}\n.block-editor-block-list__block.is-collaborator-selected:not(:focus)::after {\n\tcontent: \"\";\n\tposition: absolute;\n\tpointer-events: none;\n\ttop: 0;\n\tright: 0;\n\tbottom: 0;\n\tleft: 0;\n\toutline-color: var(--collaborator-outline-color);\n\toutline-style: solid;\n\toutline-width: calc(var(--wp-admin-border-width-focus) / var(--wp-block-editor-iframe-zoom-out-scale, 1));\n\toutline-offset: calc(-1 * var(--wp-admin-border-width-focus) / var(--wp-block-editor-iframe-zoom-out-scale, 1));\n\tbox-shadow: inset 0 0 0 calc(var(--wp-admin-border-width-focus, ${ BORDER_WIDTH_FOCUS_FALLBACK }) + ${ BORDER_WIDTH }) ${ WHITE }, 0 0 0 ${ BORDER_WIDTH } ${ WHITE }, ${ ELEVATION_X_SMALL };\n\tz-index: 1;\n}\n@media (prefers-reduced-motion: reduce) {\n\t.collaborators-overlay-user-label,\n\t.collaborators-overlay-user-cursor {\n\t\tanimation: none;\n\t}\n}\n`;\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,iCAOO;AAEA,IAAM,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UA+B1B,sDAA4B;AAAA,kBACpB,uCAAa;AAAA,YACnB,uCAAa,UAAW,gCAAM;AAAA,eAC3B,4CAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAejB,uCAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sCASS,uCAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mEAiDgB,sDAA4B,OAAQ,uCAAa,KAAM,gCAAM,WAAY,uCAAa,IAAK,gCAAM,KAAM,4CAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
4
+ "sourcesContent": ["/**\n * CSS for the collaborators overlay \u2014 cursor indicators, block highlights,\n * and positioning of Avatar labels inside the editor canvas iframe.\n */\n\nimport {\n\tBORDER_WIDTH,\n\tBORDER_WIDTH_FOCUS_FALLBACK,\n\tELEVATION_X_SMALL,\n\tGRID_UNIT_05,\n\tGRID_UNIT_10,\n\tWHITE,\n} from './collaborator-styles';\n\nexport const OVERLAY_IFRAME_STYLES = `\n.block-canvas-cover {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n\tpointer-events: none;\n\tz-index: 20000;\n}\n.block-canvas-cover .collaborators-overlay-full {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n}\n.block-canvas-cover .collaborators-overlay-fixed {\n\tposition: fixed;\n\twidth: 100%;\n\theight: 100%;\n}\n.collaborators-overlay-user {\n\tposition: absolute;\n}\n/* Cursor lines render below avatar labels across all users. The parent\n .collaborators-overlay-user has no z-index so it does not create a\n stacking context \u2014 children participate in the shared overlay context. */\n.collaborators-overlay-user-cursor {\n\tposition: absolute;\n\tz-index: 0;\n\twidth: ${ BORDER_WIDTH_FOCUS_FALLBACK };\n\tborder-radius: ${ BORDER_WIDTH };\n\toutline: ${ BORDER_WIDTH } solid ${ WHITE };\n\tbox-shadow: ${ ELEVATION_X_SMALL };\n\tanimation: collaborators-overlay-cursor-blink 1s infinite;\n}\n.collaborators-overlay-selection-rect {\n\tposition: absolute;\n\topacity: 0.15;\n\tpointer-events: none;\n\tborder-radius: 2px;\n}\n\n/* Overlay-specific positioning applied to the Avatar cursor label. */\n.collaborators-overlay-user-label.editor-avatar {\n\tposition: absolute;\n\tz-index: 1;\n\ttransform: translate(-11px, -100%);\n\tmargin-top: -${ GRID_UNIT_05 };\n\tpointer-events: auto;\n\toverflow: visible;\n\twidth: max-content;\n}\n/* Avatar positioned above a highlighted block as a label. */\n.collaborators-overlay-block-label.editor-avatar {\n\tposition: absolute;\n\tz-index: 1;\n\ttransform: translateY(calc(-100% - ${ GRID_UNIT_10 }));\n\tpointer-events: auto;\n\toverflow: visible;\n\twidth: max-content;\n}\n\n@keyframes collaborators-overlay-cursor-blink {\n\t0%, 45% { opacity: 1; }\n\t55%, 95% { opacity: 0; }\n\t100% { opacity: 1; }\n}\n.collaborators-overlay-cursor-highlighted .collaborators-overlay-user-cursor {\n\tanimation: collaborators-overlay-cursor-highlight 0.6s ease-in-out 3;\n}\n.collaborators-overlay-cursor-highlighted .collaborators-overlay-user-label {\n\tanimation: collaborators-overlay-label-highlight 0.6s ease-in-out 3;\n}\n@keyframes collaborators-overlay-cursor-highlight {\n\t0%, 100% {\n\t\ttransform: scale(1);\n\t\tfilter: drop-shadow(0 0 0 transparent);\n\t}\n\t50% {\n\t\ttransform: scale(1.2);\n\t\tfilter: drop-shadow(0 0 8px currentColor);\n\t}\n}\n@keyframes collaborators-overlay-label-highlight {\n\t0%, 100% {\n\t\ttransform: translate(-11px, -100%) scale(1);\n\t\tfilter: drop-shadow(0 0 0 transparent);\n\t}\n\t50% {\n\t\ttransform: translate(-11px, -100%) scale(1.1);\n\t\tfilter: drop-shadow(0 0 6px currentColor);\n\t}\n}\n.block-editor-block-list__block.is-collaborator-selected:not(:focus)::after {\n\tcontent: \"\";\n\tposition: absolute;\n\tpointer-events: none;\n\ttop: 0;\n\tright: 0;\n\tbottom: 0;\n\tleft: 0;\n\toutline-color: var(--collaborator-outline-color);\n\toutline-style: solid;\n\toutline-width: calc(var(--wp-admin-border-width-focus) / var(--wp-block-editor-iframe-zoom-out-scale, 1));\n\toutline-offset: calc(-1 * var(--wp-admin-border-width-focus) / var(--wp-block-editor-iframe-zoom-out-scale, 1));\n\tbox-shadow: inset 0 0 0 calc((var(--wp-admin-border-width-focus) / var(--wp-block-editor-iframe-zoom-out-scale, 1)) + 0.5px) rgba(${ WHITE }, 0.7);\n\tz-index: 1;\n}\n@media (prefers-reduced-motion: reduce) {\n\t.collaborators-overlay-user-label,\n\t.collaborators-overlay-user-cursor {\n\t\tanimation: none;\n\t}\n}\n`;\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,iCAOO;AAEA,IAAM,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UA+B1B,sDAA4B;AAAA,kBACpB,uCAAa;AAAA,YACnB,uCAAa,UAAW,gCAAM;AAAA,eAC3B,4CAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAejB,uCAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sCASS,uCAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qIAiDkF,gCAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
6
6
  "names": []
7
7
  }
@@ -48,7 +48,8 @@ var CURSOR_REDRAW_INTERVAL_MS = 1e4;
48
48
  function Overlay({
49
49
  blockEditorDocument,
50
50
  postId,
51
- postType
51
+ postType,
52
+ cursorRegistry
52
53
  }) {
53
54
  const [overlayElement, setOverlayElement] = (0, import_element.useState)(null);
54
55
  const { cursors, rerenderCursorsAfterDelay } = (0, import_use_render_cursors.useRenderCursors)(
@@ -91,6 +92,34 @@ function Overlay({
91
92
  setOverlayElement,
92
93
  resizeObserverRef
93
94
  ]);
95
+ const cursorRefsMap = (0, import_element.useRef)(/* @__PURE__ */ new Map());
96
+ (0, import_element.useEffect)(() => {
97
+ if (!cursorRegistry) {
98
+ return;
99
+ }
100
+ const refs = cursorRefsMap.current;
101
+ const currentIds = new Set(cursors.map((c) => c.clientId));
102
+ for (const id of refs.keys()) {
103
+ if (!currentIds.has(id)) {
104
+ cursorRegistry.unregisterCursor(id);
105
+ refs.delete(id);
106
+ }
107
+ }
108
+ for (const [id, el] of refs.entries()) {
109
+ cursorRegistry.registerCursor(id, el);
110
+ }
111
+ return () => cursorRegistry.removeAll();
112
+ }, [cursors, cursorRegistry]);
113
+ const setCursorRef = (0, import_element.useCallback)(
114
+ (clientId) => (el) => {
115
+ if (el) {
116
+ cursorRefsMap.current.set(clientId, el);
117
+ } else {
118
+ cursorRefsMap.current.delete(clientId);
119
+ }
120
+ },
121
+ []
122
+ );
94
123
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "collaborators-overlay-full", ref: mergedRef, children: [
95
124
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: import_avatar_iframe_styles.AVATAR_IFRAME_STYLES + import_overlay_iframe_styles.OVERLAY_IFRAME_STYLES }),
96
125
  cursors.map((cursor) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
@@ -111,6 +140,7 @@ function Overlay({
111
140
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
112
141
  "div",
113
142
  {
143
+ ref: setCursorRef(cursor.clientId),
114
144
  className: "collaborators-overlay-user",
115
145
  style: {
116
146
  left: `${cursor.x}px`,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/collaborators-overlay/overlay.tsx"],
4
- "sourcesContent": ["import { useResizeObserver, useMergeRefs } from '@wordpress/compose';\nimport { useCallback, useEffect, useState } from '@wordpress/element';\nimport { __ } from '@wordpress/i18n';\n\nimport Avatar from '../collaborators-presence/avatar';\nimport { AVATAR_IFRAME_STYLES } from './avatar-iframe-styles';\nimport { OVERLAY_IFRAME_STYLES } from './overlay-iframe-styles';\nimport { setDelayedInterval } from './timing-utils';\nimport { useBlockHighlighting } from './use-block-highlighting';\nimport { useRenderCursors } from './use-render-cursors';\n\n// Milliseconds to wait after a change before recomputing cursor positions.\nconst RERENDER_DELAY_MS = 500;\n\n// Periodically recompute cursor positions to account for DOM layout\n// changes that don't trigger awareness state updates (e.g. a collaborator\n// applying formatting shifts text but the cursor's logical position is\n// unchanged). Only active when remote cursors are visible.\nconst CURSOR_REDRAW_INTERVAL_MS = 10_000;\n\ninterface OverlayProps {\n\tblockEditorDocument?: Document;\n\tpostId: number | null;\n\tpostType: string | null;\n}\n\n/**\n * This component is responsible for rendering the overlay components within the editor iframe.\n *\n * @param props - The overlay props.\n * @param props.blockEditorDocument - The block editor document.\n * @param props.postId - The ID of the post.\n * @param props.postType - The type of the post.\n * @return The Overlay component.\n */\nexport function Overlay( {\n\tblockEditorDocument,\n\tpostId,\n\tpostType,\n}: OverlayProps ) {\n\t// Use state for the overlay element so that the hook re-runs once the ref is attached.\n\tconst [ overlayElement, setOverlayElement ] =\n\t\tuseState< HTMLDivElement | null >( null );\n\n\tconst { cursors, rerenderCursorsAfterDelay } = useRenderCursors(\n\t\toverlayElement,\n\t\tblockEditorDocument ?? null,\n\t\tpostId ?? null,\n\t\tpostType ?? null,\n\t\tRERENDER_DELAY_MS\n\t);\n\n\tconst { highlights, rerenderHighlightsAfterDelay } = useBlockHighlighting(\n\t\toverlayElement,\n\t\tblockEditorDocument ?? null,\n\t\tpostId ?? null,\n\t\tpostType ?? null,\n\t\tRERENDER_DELAY_MS\n\t);\n\n\t// Detect layout changes on overlay (e.g. turning on \"Show Template\") and window\n\t// resizes, and re-render the cursors and block highlights.\n\tconst onResize = useCallback( () => {\n\t\trerenderCursorsAfterDelay();\n\t\trerenderHighlightsAfterDelay();\n\t}, [ rerenderCursorsAfterDelay, rerenderHighlightsAfterDelay ] );\n\tconst resizeObserverRef = useResizeObserver( onResize );\n\n\t// Trigger the initial position computation on mount.\n\tuseEffect( () => {\n\t\tconst cleanupCursors = rerenderCursorsAfterDelay();\n\t\tconst cleanupHighlights = rerenderHighlightsAfterDelay();\n\t\treturn () => {\n\t\t\tcleanupCursors();\n\t\t\tcleanupHighlights();\n\t\t};\n\t}, [ rerenderCursorsAfterDelay, rerenderHighlightsAfterDelay ] );\n\n\tuseEffect( () => {\n\t\tif ( cursors.length === 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn setDelayedInterval(\n\t\t\trerenderCursorsAfterDelay,\n\t\t\tCURSOR_REDRAW_INTERVAL_MS\n\t\t);\n\t}, [ cursors.length, rerenderCursorsAfterDelay ] );\n\n\t// Merge the refs to use the same element for both overlay and resize observation\n\tconst mergedRef = useMergeRefs< HTMLDivElement | null >( [\n\t\tsetOverlayElement,\n\t\tresizeObserverRef,\n\t] );\n\n\t// This is a full overlay that covers the entire iframe document. Good for\n\t// scrollable elements like cursor indicators.\n\treturn (\n\t\t<div className=\"collaborators-overlay-full\" ref={ mergedRef }>\n\t\t\t<style>{ AVATAR_IFRAME_STYLES + OVERLAY_IFRAME_STYLES }</style>\n\t\t\t{ cursors.map( ( cursor ) => (\n\t\t\t\t<div key={ cursor.clientId }>\n\t\t\t\t\t{ ! cursor.isMe &&\n\t\t\t\t\t\tcursor.selectionRects?.map( ( rect, index ) => (\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tkey={ `${ cursor.clientId }-sel-${ index }` }\n\t\t\t\t\t\t\t\tclassName=\"collaborators-overlay-selection-rect\"\n\t\t\t\t\t\t\t\tstyle={ {\n\t\t\t\t\t\t\t\t\tleft: `${ rect.x }px`,\n\t\t\t\t\t\t\t\t\ttop: `${ rect.y }px`,\n\t\t\t\t\t\t\t\t\twidth: `${ rect.width }px`,\n\t\t\t\t\t\t\t\t\theight: `${ rect.height }px`,\n\t\t\t\t\t\t\t\t\tbackgroundColor: cursor.color,\n\t\t\t\t\t\t\t\t} }\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t) ) }\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName=\"collaborators-overlay-user\"\n\t\t\t\t\t\tstyle={ {\n\t\t\t\t\t\t\tleft: `${ cursor.x }px`,\n\t\t\t\t\t\t\ttop: `${ cursor.y }px`,\n\t\t\t\t\t\t} }\n\t\t\t\t\t>\n\t\t\t\t\t\t{ ! cursor.isMe && (\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tclassName=\"collaborators-overlay-user-cursor\"\n\t\t\t\t\t\t\t\tstyle={ {\n\t\t\t\t\t\t\t\t\tbackgroundColor: cursor.color,\n\t\t\t\t\t\t\t\t\theight: `${ cursor.height }px`,\n\t\t\t\t\t\t\t\t} }\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t) }\n\t\t\t\t\t\t<Avatar\n\t\t\t\t\t\t\tclassName=\"collaborators-overlay-user-label\"\n\t\t\t\t\t\t\tvariant=\"badge\"\n\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\tsrc={ cursor.avatarUrl }\n\t\t\t\t\t\t\tname={ cursor.userName }\n\t\t\t\t\t\t\tlabel={ cursor.isMe ? __( 'You' ) : undefined }\n\t\t\t\t\t\t\tborderColor={ cursor.color }\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t) ) }\n\t\t\t{ highlights.map( ( highlight ) => (\n\t\t\t\t<Avatar\n\t\t\t\t\tkey={ highlight.blockId }\n\t\t\t\t\tclassName=\"collaborators-overlay-block-label\"\n\t\t\t\t\tvariant=\"badge\"\n\t\t\t\t\tsize=\"small\"\n\t\t\t\t\tsrc={ highlight.avatarUrl }\n\t\t\t\t\tname={ highlight.userName }\n\t\t\t\t\tborderColor={ highlight.color }\n\t\t\t\t\tstyle={ {\n\t\t\t\t\t\tleft: `${ highlight.x }px`,\n\t\t\t\t\t\ttop: `${ highlight.y }px`,\n\t\t\t\t\t} }\n\t\t\t\t/>\n\t\t\t) ) }\n\t\t</div>\n\t);\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { useResizeObserver, useMergeRefs } from '@wordpress/compose';\nimport { useCallback, useEffect, useRef, useState } from '@wordpress/element';\nimport { __ } from '@wordpress/i18n';\n\nimport Avatar from '../collaborators-presence/avatar';\nimport { AVATAR_IFRAME_STYLES } from './avatar-iframe-styles';\nimport { OVERLAY_IFRAME_STYLES } from './overlay-iframe-styles';\nimport { setDelayedInterval } from './timing-utils';\nimport { useBlockHighlighting } from './use-block-highlighting';\nimport { useRenderCursors } from './use-render-cursors';\nimport { type CursorRegistry } from './cursor-registry';\n\n// Milliseconds to wait after a change before recomputing cursor positions.\nconst RERENDER_DELAY_MS = 500;\n\n// Periodically recompute cursor positions to account for DOM layout\n// changes that don't trigger awareness state updates (e.g. a collaborator\n// applying formatting shifts text but the cursor's logical position is\n// unchanged). Only active when remote cursors are visible.\nconst CURSOR_REDRAW_INTERVAL_MS = 10_000;\n\ninterface OverlayProps {\n\tblockEditorDocument?: Document;\n\tpostId: number | null;\n\tpostType: string | null;\n\tcursorRegistry?: CursorRegistry;\n}\n\n/**\n * This component is responsible for rendering the overlay components within the editor iframe.\n *\n * @param props - The overlay props.\n * @param props.blockEditorDocument - The block editor document.\n * @param props.postId - The ID of the post.\n * @param props.postType - The type of the post.\n * @param props.cursorRegistry - The shared cursor registry.\n * @return The Overlay component.\n */\nexport function Overlay( {\n\tblockEditorDocument,\n\tpostId,\n\tpostType,\n\tcursorRegistry,\n}: OverlayProps ) {\n\t// Use state for the overlay element so that the hook re-runs once the ref is attached.\n\tconst [ overlayElement, setOverlayElement ] =\n\t\tuseState< HTMLDivElement | null >( null );\n\n\tconst { cursors, rerenderCursorsAfterDelay } = useRenderCursors(\n\t\toverlayElement,\n\t\tblockEditorDocument ?? null,\n\t\tpostId ?? null,\n\t\tpostType ?? null,\n\t\tRERENDER_DELAY_MS\n\t);\n\n\tconst { highlights, rerenderHighlightsAfterDelay } = useBlockHighlighting(\n\t\toverlayElement,\n\t\tblockEditorDocument ?? null,\n\t\tpostId ?? null,\n\t\tpostType ?? null,\n\t\tRERENDER_DELAY_MS\n\t);\n\n\t// Detect layout changes on overlay (e.g. turning on \"Show Template\") and window\n\t// resizes, and re-render the cursors and block highlights.\n\tconst onResize = useCallback( () => {\n\t\trerenderCursorsAfterDelay();\n\t\trerenderHighlightsAfterDelay();\n\t}, [ rerenderCursorsAfterDelay, rerenderHighlightsAfterDelay ] );\n\tconst resizeObserverRef = useResizeObserver( onResize );\n\n\t// Trigger the initial position computation on mount.\n\tuseEffect( () => {\n\t\tconst cleanupCursors = rerenderCursorsAfterDelay();\n\t\tconst cleanupHighlights = rerenderHighlightsAfterDelay();\n\t\treturn () => {\n\t\t\tcleanupCursors();\n\t\t\tcleanupHighlights();\n\t\t};\n\t}, [ rerenderCursorsAfterDelay, rerenderHighlightsAfterDelay ] );\n\n\tuseEffect( () => {\n\t\tif ( cursors.length === 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn setDelayedInterval(\n\t\t\trerenderCursorsAfterDelay,\n\t\t\tCURSOR_REDRAW_INTERVAL_MS\n\t\t);\n\t}, [ cursors.length, rerenderCursorsAfterDelay ] );\n\n\t// Merge the refs to use the same element for both overlay and resize observation\n\tconst mergedRef = useMergeRefs< HTMLDivElement | null >( [\n\t\tsetOverlayElement,\n\t\tresizeObserverRef,\n\t] );\n\n\t// Track cursor element refs for registry registration.\n\tconst cursorRefsMap = useRef< Map< number, HTMLElement > >( new Map() );\n\n\t// Keep the registry in sync whenever the rendered cursors change.\n\tuseEffect( () => {\n\t\tif ( ! cursorRegistry ) {\n\t\t\treturn;\n\t\t}\n\t\tconst refs = cursorRefsMap.current;\n\t\tconst currentIds = new Set( cursors.map( ( c ) => c.clientId ) );\n\n\t\t// Unregister cursors that are no longer rendered.\n\t\tfor ( const id of refs.keys() ) {\n\t\t\tif ( ! currentIds.has( id ) ) {\n\t\t\t\tcursorRegistry.unregisterCursor( id );\n\t\t\t\trefs.delete( id );\n\t\t\t}\n\t\t}\n\n\t\t// Register or update cursors that are currently rendered.\n\t\tfor ( const [ id, el ] of refs.entries() ) {\n\t\t\tcursorRegistry.registerCursor( id, el );\n\t\t}\n\n\t\treturn () => cursorRegistry.removeAll();\n\t}, [ cursors, cursorRegistry ] );\n\n\t// Callback ref factory to capture each cursor's DOM element.\n\tconst setCursorRef = useCallback(\n\t\t( clientId: number ) => ( el: HTMLDivElement | null ) => {\n\t\t\tif ( el ) {\n\t\t\t\tcursorRefsMap.current.set( clientId, el );\n\t\t\t} else {\n\t\t\t\tcursorRefsMap.current.delete( clientId );\n\t\t\t}\n\t\t},\n\t\t[]\n\t);\n\n\t// This is a full overlay that covers the entire iframe document. Good for\n\t// scrollable elements like cursor indicators.\n\treturn (\n\t\t<div className=\"collaborators-overlay-full\" ref={ mergedRef }>\n\t\t\t<style>{ AVATAR_IFRAME_STYLES + OVERLAY_IFRAME_STYLES }</style>\n\t\t\t{ cursors.map( ( cursor ) => (\n\t\t\t\t<div key={ cursor.clientId }>\n\t\t\t\t\t{ ! cursor.isMe &&\n\t\t\t\t\t\tcursor.selectionRects?.map( ( rect, index ) => (\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tkey={ `${ cursor.clientId }-sel-${ index }` }\n\t\t\t\t\t\t\t\tclassName=\"collaborators-overlay-selection-rect\"\n\t\t\t\t\t\t\t\tstyle={ {\n\t\t\t\t\t\t\t\t\tleft: `${ rect.x }px`,\n\t\t\t\t\t\t\t\t\ttop: `${ rect.y }px`,\n\t\t\t\t\t\t\t\t\twidth: `${ rect.width }px`,\n\t\t\t\t\t\t\t\t\theight: `${ rect.height }px`,\n\t\t\t\t\t\t\t\t\tbackgroundColor: cursor.color,\n\t\t\t\t\t\t\t\t} }\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t) ) }\n\t\t\t\t\t<div\n\t\t\t\t\t\tref={ setCursorRef( cursor.clientId ) }\n\t\t\t\t\t\tclassName=\"collaborators-overlay-user\"\n\t\t\t\t\t\tstyle={ {\n\t\t\t\t\t\t\tleft: `${ cursor.x }px`,\n\t\t\t\t\t\t\ttop: `${ cursor.y }px`,\n\t\t\t\t\t\t} }\n\t\t\t\t\t>\n\t\t\t\t\t\t{ ! cursor.isMe && (\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tclassName=\"collaborators-overlay-user-cursor\"\n\t\t\t\t\t\t\t\tstyle={ {\n\t\t\t\t\t\t\t\t\tbackgroundColor: cursor.color,\n\t\t\t\t\t\t\t\t\theight: `${ cursor.height }px`,\n\t\t\t\t\t\t\t\t} }\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t) }\n\t\t\t\t\t\t<Avatar\n\t\t\t\t\t\t\tclassName=\"collaborators-overlay-user-label\"\n\t\t\t\t\t\t\tvariant=\"badge\"\n\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\tsrc={ cursor.avatarUrl }\n\t\t\t\t\t\t\tname={ cursor.userName }\n\t\t\t\t\t\t\tlabel={ cursor.isMe ? __( 'You' ) : undefined }\n\t\t\t\t\t\t\tborderColor={ cursor.color }\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t) ) }\n\t\t\t{ highlights.map( ( highlight ) => (\n\t\t\t\t<Avatar\n\t\t\t\t\tkey={ highlight.blockId }\n\t\t\t\t\tclassName=\"collaborators-overlay-block-label\"\n\t\t\t\t\tvariant=\"badge\"\n\t\t\t\t\tsize=\"small\"\n\t\t\t\t\tsrc={ highlight.avatarUrl }\n\t\t\t\t\tname={ highlight.userName }\n\t\t\t\t\tborderColor={ highlight.color }\n\t\t\t\t\tstyle={ {\n\t\t\t\t\t\tleft: `${ highlight.x }px`,\n\t\t\t\t\t\ttop: `${ highlight.y }px`,\n\t\t\t\t\t} }\n\t\t\t\t/>\n\t\t\t) ) }\n\t\t</div>\n\t);\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["Avatar"]
7
7
  }
@@ -28,7 +28,7 @@ function setDelayedInterval(callback, delayMs) {
28
28
  const runner = () => {
29
29
  try {
30
30
  callback();
31
- } catch (error) {
31
+ } catch {
32
32
  }
33
33
  timerHandle = setTimeout(runner, delayMs);
34
34
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/collaborators-overlay/timing-utils.ts"],
4
- "sourcesContent": ["/**\n * Like setInterval but chains setTimeout calls, so the delay is measured from\n * the end of one run to the start of the next. This prevents callbacks from\n * stacking up when the main thread is busy.\n *\n * @param callback The function to call repeatedly.\n * @param delayMs Milliseconds between runs.\n * @return A cleanup function that stops the timer.\n */\nexport function setDelayedInterval( callback: () => void, delayMs: number ) {\n\tlet timerHandle: ReturnType< typeof setTimeout > | null = null;\n\n\tconst runner = () => {\n\t\ttry {\n\t\t\tcallback();\n\t\t} catch ( error ) {\n\t\t\t// Do nothing\n\t\t}\n\n\t\ttimerHandle = setTimeout( runner, delayMs );\n\t};\n\n\ttimerHandle = setTimeout( runner, delayMs );\n\n\treturn () => {\n\t\tif ( timerHandle ) {\n\t\t\tclearTimeout( timerHandle );\n\t\t}\n\t};\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AASO,SAAS,mBAAoB,UAAsB,SAAkB;AAC3E,MAAI,cAAsD;AAE1D,QAAM,SAAS,MAAM;AACpB,QAAI;AACH,eAAS;AAAA,IACV,SAAU,OAAQ;AAAA,IAElB;AAEA,kBAAc,WAAY,QAAQ,OAAQ;AAAA,EAC3C;AAEA,gBAAc,WAAY,QAAQ,OAAQ;AAE1C,SAAO,MAAM;AACZ,QAAK,aAAc;AAClB,mBAAc,WAAY;AAAA,IAC3B;AAAA,EACD;AACD;",
4
+ "sourcesContent": ["/**\n * Like setInterval but chains setTimeout calls, so the delay is measured from\n * the end of one run to the start of the next. This prevents callbacks from\n * stacking up when the main thread is busy.\n *\n * @param callback The function to call repeatedly.\n * @param delayMs Milliseconds between runs.\n * @return A cleanup function that stops the timer.\n */\nexport function setDelayedInterval( callback: () => void, delayMs: number ) {\n\tlet timerHandle: ReturnType< typeof setTimeout > | null = null;\n\n\tconst runner = () => {\n\t\ttry {\n\t\t\tcallback();\n\t\t} catch {\n\t\t\t// Do nothing\n\t\t}\n\n\t\ttimerHandle = setTimeout( runner, delayMs );\n\t};\n\n\ttimerHandle = setTimeout( runner, delayMs );\n\n\treturn () => {\n\t\tif ( timerHandle ) {\n\t\t\tclearTimeout( timerHandle );\n\t\t}\n\t};\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AASO,SAAS,mBAAoB,UAAsB,SAAkB;AAC3E,MAAI,cAAsD;AAE1D,QAAM,SAAS,MAAM;AACpB,QAAI;AACH,eAAS;AAAA,IACV,QAAQ;AAAA,IAER;AAEA,kBAAc,WAAY,QAAQ,OAAQ;AAAA,EAC3C;AAEA,gBAAc,WAAY,QAAQ,OAAQ;AAE1C,SAAO,MAAM;AACZ,QAAK,aAAc;AAClB,mBAAc,WAAY;AAAA,IAC3B;AAAA,EACD;AACD;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/collaborators-overlay/use-render-cursors.ts"],
4
- "sourcesContent": ["import {\n\tprivateApis as coreDataPrivateApis,\n\tSelectionType,\n\ttype PostEditorAwarenessState as ActiveCollaborator,\n} from '@wordpress/core-data';\nimport { useSelect } from '@wordpress/data';\nimport { useEffect, useState } from '@wordpress/element';\nimport { store as preferencesStore } from '@wordpress/preferences';\nimport type { ResolvedSelection } from '@wordpress/core-data';\n\nimport { unlock } from '../../lock-unlock';\nimport { getAvatarUrl } from './get-avatar-url';\nimport { getAvatarBorderColor } from '../collab-sidebar/utils';\nimport { computeSelectionVisual } from './compute-selection';\nimport { useDebouncedRecompute } from './use-debounced-recompute';\nimport type { SelectionRect } from './cursor-dom-utils';\n\nconst { useActiveCollaborators, useResolvedSelection } =\n\tunlock( coreDataPrivateApis );\n\nexport type { SelectionRect };\n\nexport interface CursorData {\n\tuserName: string;\n\tclientId: number;\n\tcolor: string;\n\tavatarUrl?: string;\n\tx: number;\n\ty: number;\n\theight: number;\n\tisMe?: boolean;\n\tselectionRects?: SelectionRect[];\n}\n\n/**\n * Custom hook that computes cursor positions for each remote user in the editor.\n *\n * @param overlayElement - The overlay element\n * @param blockEditorDocument - The block editor document\n * @param postId - The ID of the post\n * @param postType - The type of the post\n * @param delayMs - Milliseconds to wait before recomputing cursor positions.\n * @return An array of cursor data for rendering, and a function to trigger a delayed recompute.\n */\nexport function useRenderCursors(\n\toverlayElement: HTMLElement | null,\n\tblockEditorDocument: Document | null,\n\tpostId: number | null,\n\tpostType: string | null,\n\tdelayMs: number\n): { cursors: CursorData[]; rerenderCursorsAfterDelay: () => () => void } {\n\tconst sortedUsers = useActiveCollaborators(\n\t\tpostId ?? null,\n\t\tpostType ?? null\n\t);\n\tconst resolveSelection = useResolvedSelection(\n\t\tpostId ?? null,\n\t\tpostType ?? null\n\t);\n\n\tconst showOwnCursor = useSelect(\n\t\t( select ) =>\n\t\t\tselect( preferencesStore ).get( 'core', 'showCollaborationCursor' ),\n\t\t[]\n\t);\n\n\tconst [ cursorPositions, setCursorPositions ] = useState< CursorData[] >(\n\t\t[]\n\t);\n\n\t// Bump this counter to force the effect to re-run (e.g. after a layout shift).\n\tconst [ recomputeToken, rerenderCursorsAfterDelay ] =\n\t\tuseDebouncedRecompute( delayMs );\n\n\t// All DOM position computations live inside useEffect.\n\tuseEffect( () => {\n\t\tif ( ! overlayElement || ! blockEditorDocument ) {\n\t\t\tsetCursorPositions( [] );\n\t\t\treturn;\n\t\t}\n\n\t\t// Pre-compute the overlay rect once, same for every user.\n\t\tconst overlayRect = overlayElement.getBoundingClientRect();\n\t\tconst overlayContext = {\n\t\t\teditorDocument: blockEditorDocument,\n\t\t\toverlayRect,\n\t\t};\n\n\t\tconst results: CursorData[] = [];\n\n\t\tconst hasOtherCollaborators = sortedUsers.some(\n\t\t\t( u: ActiveCollaborator ) => ! u.isMe\n\t\t);\n\n\t\tsortedUsers.forEach( ( user: ActiveCollaborator ) => {\n\t\t\tif ( user.isMe && ( ! showOwnCursor || ! hasOtherCollaborators ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst selection = user.editorState?.selection ?? {\n\t\t\t\ttype: SelectionType.None,\n\t\t\t};\n\n\t\t\tlet start: ResolvedSelection = {\n\t\t\t\trichTextOffset: null,\n\t\t\t\tlocalClientId: null,\n\t\t\t};\n\t\t\tlet end: ResolvedSelection | undefined;\n\n\t\t\tif ( selection.type === SelectionType.Cursor ) {\n\t\t\t\ttry {\n\t\t\t\t\tstart = resolveSelection( selection );\n\t\t\t\t} catch {\n\t\t\t\t\t// Selection may reference a stale Yjs position.\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} else if (\n\t\t\t\tselection.type === SelectionType.SelectionInOneBlock ||\n\t\t\t\tselection.type === SelectionType.SelectionInMultipleBlocks\n\t\t\t) {\n\t\t\t\ttry {\n\t\t\t\t\tstart = resolveSelection( {\n\t\t\t\t\t\ttype: SelectionType.Cursor,\n\t\t\t\t\t\tcursorPosition: selection.cursorStartPosition,\n\t\t\t\t\t} );\n\n\t\t\t\t\tend = resolveSelection( {\n\t\t\t\t\t\ttype: SelectionType.Cursor,\n\t\t\t\t\t\tcursorPosition: selection.cursorEndPosition,\n\t\t\t\t\t} );\n\t\t\t\t} catch {\n\t\t\t\t\t// Selection may reference a stale Yjs position.\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst userName = user.collaboratorInfo.name;\n\t\t\tconst clientId = user.clientId;\n\t\t\tconst color = user.isMe\n\t\t\t\t? 'var(--wp-admin-theme-color)'\n\t\t\t\t: getAvatarBorderColor( user.collaboratorInfo.id );\n\t\t\tconst avatarUrl = getAvatarUrl( user.collaboratorInfo.avatar_urls );\n\n\t\t\tconst selectionVisual = computeSelectionVisual(\n\t\t\t\tselection,\n\t\t\t\tstart,\n\t\t\t\tend,\n\t\t\t\toverlayContext\n\t\t\t);\n\n\t\t\tif ( selectionVisual.coords ) {\n\t\t\t\tconst cursorData: CursorData = {\n\t\t\t\t\tuserName,\n\t\t\t\t\tclientId,\n\t\t\t\t\tcolor,\n\t\t\t\t\tavatarUrl,\n\t\t\t\t\tisMe: user.isMe,\n\t\t\t\t\t...selectionVisual.coords,\n\t\t\t\t};\n\n\t\t\t\tif ( selectionVisual.selectionRects ) {\n\t\t\t\t\tcursorData.selectionRects = selectionVisual.selectionRects;\n\t\t\t\t}\n\n\t\t\t\tresults.push( cursorData );\n\t\t\t}\n\t\t} );\n\n\t\tsetCursorPositions( results );\n\t}, [\n\t\tblockEditorDocument,\n\t\tresolveSelection,\n\t\toverlayElement,\n\t\tsortedUsers,\n\t\tshowOwnCursor,\n\t\trecomputeToken,\n\t] );\n\n\treturn { cursors: cursorPositions, rerenderCursorsAfterDelay };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\n\tprivateApis as coreDataPrivateApis,\n\tSelectionType,\n} from '@wordpress/core-data';\nimport type {\n\tResolvedSelection,\n\tPostEditorAwarenessState as ActiveCollaborator,\n} from '@wordpress/core-data';\nimport { useSelect } from '@wordpress/data';\nimport { useEffect, useState } from '@wordpress/element';\nimport { store as preferencesStore } from '@wordpress/preferences';\n\nimport { unlock } from '../../lock-unlock';\nimport { getAvatarUrl } from './get-avatar-url';\nimport { getAvatarBorderColor } from '../collab-sidebar/utils';\nimport { computeSelectionVisual } from './compute-selection';\nimport { useDebouncedRecompute } from './use-debounced-recompute';\nimport type { SelectionRect } from './cursor-dom-utils';\n\nconst { useActiveCollaborators, useResolvedSelection } =\n\tunlock( coreDataPrivateApis );\n\nexport type { SelectionRect };\n\nexport interface CursorData {\n\tuserName: string;\n\tclientId: number;\n\tcolor: string;\n\tavatarUrl?: string;\n\tx: number;\n\ty: number;\n\theight: number;\n\tisMe?: boolean;\n\tselectionRects?: SelectionRect[];\n}\n\n/**\n * Custom hook that computes cursor positions for each remote user in the editor.\n *\n * @param overlayElement - The overlay element\n * @param blockEditorDocument - The block editor document\n * @param postId - The ID of the post\n * @param postType - The type of the post\n * @param delayMs - Milliseconds to wait before recomputing cursor positions.\n * @return An array of cursor data for rendering, and a function to trigger a delayed recompute.\n */\nexport function useRenderCursors(\n\toverlayElement: HTMLElement | null,\n\tblockEditorDocument: Document | null,\n\tpostId: number | null,\n\tpostType: string | null,\n\tdelayMs: number\n): { cursors: CursorData[]; rerenderCursorsAfterDelay: () => () => void } {\n\tconst sortedUsers = useActiveCollaborators(\n\t\tpostId ?? null,\n\t\tpostType ?? null\n\t);\n\tconst resolveSelection = useResolvedSelection(\n\t\tpostId ?? null,\n\t\tpostType ?? null\n\t);\n\n\tconst showOwnCursor = useSelect(\n\t\t( select ) =>\n\t\t\tselect( preferencesStore ).get( 'core', 'showCollaborationCursor' ),\n\t\t[]\n\t);\n\n\tconst [ cursorPositions, setCursorPositions ] = useState< CursorData[] >(\n\t\t[]\n\t);\n\n\t// Bump this counter to force the effect to re-run (e.g. after a layout shift).\n\tconst [ recomputeToken, rerenderCursorsAfterDelay ] =\n\t\tuseDebouncedRecompute( delayMs );\n\n\t// All DOM position computations live inside useEffect.\n\tuseEffect( () => {\n\t\tif ( ! overlayElement || ! blockEditorDocument ) {\n\t\t\tsetCursorPositions( [] );\n\t\t\treturn;\n\t\t}\n\n\t\t// Pre-compute the overlay rect once, same for every user.\n\t\tconst overlayRect = overlayElement.getBoundingClientRect();\n\t\tconst overlayContext = {\n\t\t\teditorDocument: blockEditorDocument,\n\t\t\toverlayRect,\n\t\t};\n\n\t\tconst results: CursorData[] = [];\n\n\t\tconst hasOtherCollaborators = sortedUsers.some(\n\t\t\t( u: ActiveCollaborator ) => ! u.isMe\n\t\t);\n\n\t\tsortedUsers.forEach( ( user: ActiveCollaborator ) => {\n\t\t\tif ( user.isMe && ( ! showOwnCursor || ! hasOtherCollaborators ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst selection = user.editorState?.selection ?? {\n\t\t\t\ttype: SelectionType.None,\n\t\t\t};\n\n\t\t\tlet start: ResolvedSelection = {\n\t\t\t\trichTextOffset: null,\n\t\t\t\tlocalClientId: null,\n\t\t\t};\n\t\t\tlet end: ResolvedSelection | undefined;\n\n\t\t\tif ( selection.type === SelectionType.Cursor ) {\n\t\t\t\ttry {\n\t\t\t\t\tstart = resolveSelection( selection );\n\t\t\t\t} catch {\n\t\t\t\t\t// Selection may reference a stale Yjs position.\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} else if (\n\t\t\t\tselection.type === SelectionType.SelectionInOneBlock ||\n\t\t\t\tselection.type === SelectionType.SelectionInMultipleBlocks\n\t\t\t) {\n\t\t\t\ttry {\n\t\t\t\t\tstart = resolveSelection( {\n\t\t\t\t\t\ttype: SelectionType.Cursor,\n\t\t\t\t\t\tcursorPosition: selection.cursorStartPosition,\n\t\t\t\t\t} );\n\n\t\t\t\t\tend = resolveSelection( {\n\t\t\t\t\t\ttype: SelectionType.Cursor,\n\t\t\t\t\t\tcursorPosition: selection.cursorEndPosition,\n\t\t\t\t\t} );\n\t\t\t\t} catch {\n\t\t\t\t\t// Selection may reference a stale Yjs position.\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst userName = user.collaboratorInfo.name;\n\t\t\tconst clientId = user.clientId;\n\t\t\tconst color = user.isMe\n\t\t\t\t? 'var(--wp-admin-theme-color)'\n\t\t\t\t: getAvatarBorderColor( user.collaboratorInfo.id );\n\t\t\tconst avatarUrl = getAvatarUrl( user.collaboratorInfo.avatar_urls );\n\n\t\t\tconst selectionVisual = computeSelectionVisual(\n\t\t\t\tselection,\n\t\t\t\tstart,\n\t\t\t\tend,\n\t\t\t\toverlayContext\n\t\t\t);\n\n\t\t\tif ( selectionVisual.coords ) {\n\t\t\t\tconst cursorData: CursorData = {\n\t\t\t\t\tuserName,\n\t\t\t\t\tclientId,\n\t\t\t\t\tcolor,\n\t\t\t\t\tavatarUrl,\n\t\t\t\t\tisMe: user.isMe,\n\t\t\t\t\t...selectionVisual.coords,\n\t\t\t\t};\n\n\t\t\t\tif ( selectionVisual.selectionRects ) {\n\t\t\t\t\tcursorData.selectionRects = selectionVisual.selectionRects;\n\t\t\t\t}\n\n\t\t\t\tresults.push( cursorData );\n\t\t\t}\n\t\t} );\n\n\t\tsetCursorPositions( results );\n\t}, [\n\t\tblockEditorDocument,\n\t\tresolveSelection,\n\t\toverlayElement,\n\t\tsortedUsers,\n\t\tshowOwnCursor,\n\t\trecomputeToken,\n\t] );\n\n\treturn { cursors: cursorPositions, rerenderCursorsAfterDelay };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["coreDataPrivateApis", "preferencesStore"]
7
7
  }