@wordpress/editor 14.48.1 → 14.49.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 (460) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/README.md +5 -13
  3. package/build/bindings/pattern-overrides.cjs +1 -1
  4. package/build/bindings/pattern-overrides.cjs.map +2 -2
  5. package/build/components/autosave-monitor/index.cjs +40 -83
  6. package/build/components/autosave-monitor/index.cjs.map +3 -3
  7. package/build/components/collab-sidebar/note-byline.cjs +1 -1
  8. package/build/components/collab-sidebar/note-byline.cjs.map +2 -2
  9. package/build/components/collab-sidebar/note.cjs +49 -17
  10. package/build/components/collab-sidebar/note.cjs.map +3 -3
  11. package/build/components/collab-sidebar/notes.cjs.map +1 -1
  12. package/build/components/collab-sidebar/utils.cjs +1 -1
  13. package/build/components/collab-sidebar/utils.cjs.map +2 -2
  14. package/build/components/collaborators-overlay/avatar-iframe-styles.cjs.map +1 -1
  15. package/build/components/collaborators-overlay/collaborator-styles.cjs.map +1 -1
  16. package/build/components/collaborators-overlay/compute-selection.cjs.map +1 -1
  17. package/build/components/collaborators-overlay/overlay-iframe-styles.cjs +1 -1
  18. package/build/components/collaborators-overlay/overlay-iframe-styles.cjs.map +1 -1
  19. package/build/components/collaborators-overlay/use-block-highlighting.cjs.map +1 -1
  20. package/build/components/collaborators-presence/avatar/component.cjs.map +2 -2
  21. package/build/components/collaborators-presence/avatar/use-image-loading-status.cjs.map +1 -1
  22. package/build/components/document-bar/index.cjs +7 -5
  23. package/build/components/document-bar/index.cjs.map +2 -2
  24. package/build/components/global-keyboard-shortcuts/index.cjs +3 -2
  25. package/build/components/global-keyboard-shortcuts/index.cjs.map +2 -2
  26. package/build/components/global-styles-sidebar/welcome-guide.cjs +3 -3
  27. package/build/components/global-styles-sidebar/welcome-guide.cjs.map +1 -1
  28. package/build/components/local-autosave-monitor/index.cjs +14 -15
  29. package/build/components/local-autosave-monitor/index.cjs.map +2 -2
  30. package/build/components/page-attributes/parent.cjs +1 -1
  31. package/build/components/page-attributes/parent.cjs.map +2 -2
  32. package/build/components/post-card-panel/index.cjs +1 -1
  33. package/build/components/post-card-panel/index.cjs.map +2 -2
  34. package/build/components/post-excerpt/panel.cjs +1 -1
  35. package/build/components/post-excerpt/panel.cjs.map +2 -2
  36. package/build/components/post-locked-modal/index.cjs +3 -3
  37. package/build/components/post-locked-modal/index.cjs.map +1 -1
  38. package/build/components/post-preview-button/index.cjs +2 -2
  39. package/build/components/post-preview-button/index.cjs.map +2 -2
  40. package/build/components/post-publish-button/index.cjs +4 -3
  41. package/build/components/post-publish-button/index.cjs.map +2 -2
  42. package/build/components/post-publish-button/label.cjs +2 -2
  43. package/build/components/post-publish-button/label.cjs.map +2 -2
  44. package/build/components/post-publish-panel/index.cjs.map +1 -1
  45. package/build/components/post-publish-panel/postpublish.cjs +1 -2
  46. package/build/components/post-publish-panel/postpublish.cjs.map +2 -2
  47. package/build/components/post-revisions-preview/block-diff.cjs.map +1 -1
  48. package/build/components/post-revisions-preview/diff-markers.cjs.map +2 -2
  49. package/build/components/post-revisions-preview/revisions-slider.cjs +1 -1
  50. package/build/components/post-revisions-preview/revisions-slider.cjs.map +2 -2
  51. package/build/components/post-revisions-timeline/index.cjs +173 -0
  52. package/build/components/post-revisions-timeline/index.cjs.map +7 -0
  53. package/build/components/post-saved-state/index.cjs +17 -26
  54. package/build/components/post-saved-state/index.cjs.map +2 -2
  55. package/build/components/post-schedule/label.cjs +5 -5
  56. package/build/components/post-schedule/label.cjs.map +1 -1
  57. package/build/components/post-status/index.cjs +0 -1
  58. package/build/components/post-status/index.cjs.map +2 -2
  59. package/build/components/post-taxonomies/flat-term-selector.cjs +2 -1
  60. package/build/components/post-taxonomies/flat-term-selector.cjs.map +3 -3
  61. package/build/components/post-taxonomies/hierarchical-term-selector.cjs +1 -2
  62. package/build/components/post-taxonomies/hierarchical-term-selector.cjs.map +2 -2
  63. package/build/components/post-template/create-new-template-modal.cjs +0 -1
  64. package/build/components/post-template/create-new-template-modal.cjs.map +2 -2
  65. package/build/components/post-text-editor/index.cjs +51 -0
  66. package/build/components/post-text-editor/index.cjs.map +2 -2
  67. package/build/components/post-text-editor/utils.cjs +150 -0
  68. package/build/components/post-text-editor/utils.cjs.map +7 -0
  69. package/build/components/post-url/index.cjs +1 -1
  70. package/build/components/post-url/index.cjs.map +2 -2
  71. package/build/components/post-view-link/index.cjs +1 -1
  72. package/build/components/post-view-link/index.cjs.map +2 -2
  73. package/build/components/post-visibility/index.cjs +0 -1
  74. package/build/components/post-visibility/index.cjs.map +2 -2
  75. package/build/components/provider/disable-non-page-content-blocks.cjs +23 -3
  76. package/build/components/provider/disable-non-page-content-blocks.cjs.map +2 -2
  77. package/build/components/provider/index.cjs +1 -1
  78. package/build/components/provider/index.cjs.map +2 -2
  79. package/build/components/provider/navigation-block-editing-mode.cjs +9 -2
  80. package/build/components/provider/navigation-block-editing-mode.cjs.map +2 -2
  81. package/build/components/provider/use-block-editor-settings.cjs +2 -1
  82. package/build/components/provider/use-block-editor-settings.cjs.map +2 -2
  83. package/build/components/resizable-editor/resize-handle.cjs.map +2 -2
  84. package/build/components/revision-diff-panel/index.cjs +7 -2
  85. package/build/components/revision-diff-panel/index.cjs.map +2 -2
  86. package/build/components/revision-fields-diff/index.cjs +6 -2
  87. package/build/components/revision-fields-diff/index.cjs.map +2 -2
  88. package/build/components/sidebar/dataform-post-summary.cjs +189 -29
  89. package/build/components/sidebar/dataform-post-summary.cjs.map +3 -3
  90. package/build/components/sidebar/index.cjs +1 -11
  91. package/build/components/sidebar/index.cjs.map +3 -3
  92. package/build/components/sidebar/post-revision-summary.cjs +11 -17
  93. package/build/components/sidebar/post-revision-summary.cjs.map +3 -3
  94. package/build/components/sidebar/post-summary.cjs +8 -6
  95. package/build/components/sidebar/post-summary.cjs.map +3 -3
  96. package/build/components/style-book/examples.cjs +1 -1
  97. package/build/components/style-book/examples.cjs.map +1 -1
  98. package/build/components/style-book/index.cjs +1 -1
  99. package/build/components/style-book/index.cjs.map +2 -2
  100. package/build/components/sync-connection-error-modal/index.cjs +3 -3
  101. package/build/components/sync-connection-error-modal/index.cjs.map +1 -1
  102. package/build/components/template-actions-panel/block-theme-content.cjs.map +2 -2
  103. package/build/components/template-actions-panel/index.cjs +0 -9
  104. package/build/components/template-actions-panel/index.cjs.map +3 -3
  105. package/build/components/template-validation-notice/index.cjs +1 -1
  106. package/build/components/template-validation-notice/index.cjs.map +1 -1
  107. package/build/components/upload-progress-snackbar/index.cjs +3 -3
  108. package/build/components/upload-progress-snackbar/index.cjs.map +2 -2
  109. package/build/components/upload-progress-snackbar/tracker.cjs.map +1 -1
  110. package/build/components/visual-editor/edit-template-blocks-notification.cjs +1 -1
  111. package/build/components/visual-editor/edit-template-blocks-notification.cjs.map +1 -1
  112. package/build/{components/revision-author-panel → dataviews/fields/revisions}/index.cjs +18 -26
  113. package/build/dataviews/fields/revisions/index.cjs.map +7 -0
  114. package/build/dataviews/fields/revisions/revisions-view.cjs +74 -0
  115. package/build/dataviews/fields/revisions/revisions-view.cjs.map +7 -0
  116. package/build/dataviews/store/private-actions.cjs +17 -5
  117. package/build/dataviews/store/private-actions.cjs.map +3 -3
  118. package/build/hooks/push-changes-to-global-styles/index.cjs +1 -1
  119. package/build/hooks/push-changes-to-global-styles/index.cjs.map +1 -1
  120. package/build/store/actions.cjs +1 -1
  121. package/build/store/actions.cjs.map +2 -2
  122. package/build/store/private-actions.cjs +2 -2
  123. package/build/store/private-actions.cjs.map +2 -2
  124. package/build/store/private-selectors.cjs +6 -1
  125. package/build/store/private-selectors.cjs.map +2 -2
  126. package/build/utils/media-upload/index.cjs.map +1 -1
  127. package/build/utils/set-nested-value.cjs.map +1 -1
  128. package/build-module/bindings/pattern-overrides.mjs +1 -1
  129. package/build-module/bindings/pattern-overrides.mjs.map +2 -2
  130. package/build-module/components/autosave-monitor/index.mjs +42 -81
  131. package/build-module/components/autosave-monitor/index.mjs.map +2 -2
  132. package/build-module/components/collab-sidebar/note-byline.mjs +1 -1
  133. package/build-module/components/collab-sidebar/note-byline.mjs.map +2 -2
  134. package/build-module/components/collab-sidebar/note.mjs +50 -18
  135. package/build-module/components/collab-sidebar/note.mjs.map +2 -2
  136. package/build-module/components/collab-sidebar/notes.mjs.map +1 -1
  137. package/build-module/components/collab-sidebar/utils.mjs +1 -1
  138. package/build-module/components/collab-sidebar/utils.mjs.map +2 -2
  139. package/build-module/components/collaborators-overlay/avatar-iframe-styles.mjs.map +1 -1
  140. package/build-module/components/collaborators-overlay/collaborator-styles.mjs.map +1 -1
  141. package/build-module/components/collaborators-overlay/compute-selection.mjs.map +1 -1
  142. package/build-module/components/collaborators-overlay/overlay-iframe-styles.mjs +1 -1
  143. package/build-module/components/collaborators-overlay/overlay-iframe-styles.mjs.map +1 -1
  144. package/build-module/components/collaborators-overlay/use-block-highlighting.mjs.map +1 -1
  145. package/build-module/components/collaborators-presence/avatar/component.mjs.map +2 -2
  146. package/build-module/components/collaborators-presence/avatar/use-image-loading-status.mjs.map +1 -1
  147. package/build-module/components/document-bar/index.mjs +7 -5
  148. package/build-module/components/document-bar/index.mjs.map +2 -2
  149. package/build-module/components/global-keyboard-shortcuts/index.mjs +3 -2
  150. package/build-module/components/global-keyboard-shortcuts/index.mjs.map +2 -2
  151. package/build-module/components/global-styles-sidebar/welcome-guide.mjs +3 -3
  152. package/build-module/components/global-styles-sidebar/welcome-guide.mjs.map +1 -1
  153. package/build-module/components/local-autosave-monitor/index.mjs +15 -16
  154. package/build-module/components/local-autosave-monitor/index.mjs.map +2 -2
  155. package/build-module/components/page-attributes/parent.mjs +1 -1
  156. package/build-module/components/page-attributes/parent.mjs.map +2 -2
  157. package/build-module/components/post-card-panel/index.mjs +1 -1
  158. package/build-module/components/post-card-panel/index.mjs.map +2 -2
  159. package/build-module/components/post-excerpt/panel.mjs +1 -1
  160. package/build-module/components/post-excerpt/panel.mjs.map +2 -2
  161. package/build-module/components/post-locked-modal/index.mjs +3 -3
  162. package/build-module/components/post-locked-modal/index.mjs.map +1 -1
  163. package/build-module/components/post-preview-button/index.mjs +2 -2
  164. package/build-module/components/post-preview-button/index.mjs.map +2 -2
  165. package/build-module/components/post-publish-button/index.mjs +4 -3
  166. package/build-module/components/post-publish-button/index.mjs.map +2 -2
  167. package/build-module/components/post-publish-button/label.mjs +2 -2
  168. package/build-module/components/post-publish-button/label.mjs.map +2 -2
  169. package/build-module/components/post-publish-panel/index.mjs.map +1 -1
  170. package/build-module/components/post-publish-panel/postpublish.mjs +1 -2
  171. package/build-module/components/post-publish-panel/postpublish.mjs.map +2 -2
  172. package/build-module/components/post-revisions-preview/block-diff.mjs.map +1 -1
  173. package/build-module/components/post-revisions-preview/diff-markers.mjs.map +2 -2
  174. package/build-module/components/post-revisions-preview/revisions-slider.mjs +1 -1
  175. package/build-module/components/post-revisions-preview/revisions-slider.mjs.map +2 -2
  176. package/build-module/components/post-revisions-timeline/index.mjs +152 -0
  177. package/build-module/components/post-revisions-timeline/index.mjs.map +7 -0
  178. package/build-module/components/post-saved-state/index.mjs +17 -26
  179. package/build-module/components/post-saved-state/index.mjs.map +2 -2
  180. package/build-module/components/post-schedule/label.mjs +5 -5
  181. package/build-module/components/post-schedule/label.mjs.map +1 -1
  182. package/build-module/components/post-status/index.mjs +0 -1
  183. package/build-module/components/post-status/index.mjs.map +2 -2
  184. package/build-module/components/post-taxonomies/flat-term-selector.mjs +3 -6
  185. package/build-module/components/post-taxonomies/flat-term-selector.mjs.map +2 -2
  186. package/build-module/components/post-taxonomies/hierarchical-term-selector.mjs +1 -2
  187. package/build-module/components/post-taxonomies/hierarchical-term-selector.mjs.map +2 -2
  188. package/build-module/components/post-template/create-new-template-modal.mjs +0 -1
  189. package/build-module/components/post-template/create-new-template-modal.mjs.map +2 -2
  190. package/build-module/components/post-text-editor/index.mjs +51 -0
  191. package/build-module/components/post-text-editor/index.mjs.map +2 -2
  192. package/build-module/components/post-text-editor/utils.mjs +123 -0
  193. package/build-module/components/post-text-editor/utils.mjs.map +7 -0
  194. package/build-module/components/post-url/index.mjs +1 -1
  195. package/build-module/components/post-url/index.mjs.map +2 -2
  196. package/build-module/components/post-view-link/index.mjs +1 -1
  197. package/build-module/components/post-view-link/index.mjs.map +2 -2
  198. package/build-module/components/post-visibility/index.mjs +0 -1
  199. package/build-module/components/post-visibility/index.mjs.map +2 -2
  200. package/build-module/components/provider/disable-non-page-content-blocks.mjs +23 -3
  201. package/build-module/components/provider/disable-non-page-content-blocks.mjs.map +2 -2
  202. package/build-module/components/provider/index.mjs +1 -1
  203. package/build-module/components/provider/index.mjs.map +2 -2
  204. package/build-module/components/provider/navigation-block-editing-mode.mjs +10 -3
  205. package/build-module/components/provider/navigation-block-editing-mode.mjs.map +2 -2
  206. package/build-module/components/provider/use-block-editor-settings.mjs +2 -1
  207. package/build-module/components/provider/use-block-editor-settings.mjs.map +2 -2
  208. package/build-module/components/resizable-editor/resize-handle.mjs.map +2 -2
  209. package/build-module/components/revision-diff-panel/index.mjs +7 -2
  210. package/build-module/components/revision-diff-panel/index.mjs.map +2 -2
  211. package/build-module/components/revision-fields-diff/index.mjs +6 -2
  212. package/build-module/components/revision-fields-diff/index.mjs.map +2 -2
  213. package/build-module/components/sidebar/dataform-post-summary.mjs +190 -30
  214. package/build-module/components/sidebar/dataform-post-summary.mjs.map +2 -2
  215. package/build-module/components/sidebar/index.mjs +1 -11
  216. package/build-module/components/sidebar/index.mjs.map +2 -2
  217. package/build-module/components/sidebar/post-revision-summary.mjs +11 -17
  218. package/build-module/components/sidebar/post-revision-summary.mjs.map +2 -2
  219. package/build-module/components/sidebar/post-summary.mjs +8 -6
  220. package/build-module/components/sidebar/post-summary.mjs.map +2 -2
  221. package/build-module/components/style-book/examples.mjs +1 -1
  222. package/build-module/components/style-book/examples.mjs.map +1 -1
  223. package/build-module/components/style-book/index.mjs +1 -1
  224. package/build-module/components/style-book/index.mjs.map +2 -2
  225. package/build-module/components/sync-connection-error-modal/index.mjs +3 -3
  226. package/build-module/components/sync-connection-error-modal/index.mjs.map +1 -1
  227. package/build-module/components/template-actions-panel/block-theme-content.mjs.map +2 -2
  228. package/build-module/components/template-actions-panel/index.mjs +0 -9
  229. package/build-module/components/template-actions-panel/index.mjs.map +2 -2
  230. package/build-module/components/template-validation-notice/index.mjs +1 -1
  231. package/build-module/components/template-validation-notice/index.mjs.map +1 -1
  232. package/build-module/components/upload-progress-snackbar/index.mjs +3 -3
  233. package/build-module/components/upload-progress-snackbar/index.mjs.map +2 -2
  234. package/build-module/components/upload-progress-snackbar/tracker.mjs.map +1 -1
  235. package/build-module/components/visual-editor/edit-template-blocks-notification.mjs +1 -1
  236. package/build-module/components/visual-editor/edit-template-blocks-notification.mjs.map +1 -1
  237. package/build-module/dataviews/fields/revisions/index.mjs +20 -0
  238. package/build-module/dataviews/fields/revisions/index.mjs.map +7 -0
  239. package/build-module/dataviews/fields/revisions/revisions-view.mjs +53 -0
  240. package/build-module/dataviews/fields/revisions/revisions-view.mjs.map +7 -0
  241. package/build-module/dataviews/store/private-actions.mjs +28 -8
  242. package/build-module/dataviews/store/private-actions.mjs.map +2 -2
  243. package/build-module/hooks/push-changes-to-global-styles/index.mjs +1 -1
  244. package/build-module/hooks/push-changes-to-global-styles/index.mjs.map +1 -1
  245. package/build-module/store/actions.mjs +1 -1
  246. package/build-module/store/actions.mjs.map +2 -2
  247. package/build-module/store/private-actions.mjs +2 -2
  248. package/build-module/store/private-actions.mjs.map +2 -2
  249. package/build-module/store/private-selectors.mjs +7 -1
  250. package/build-module/store/private-selectors.mjs.map +2 -2
  251. package/build-module/utils/media-upload/index.mjs.map +1 -1
  252. package/build-module/utils/set-nested-value.mjs.map +1 -1
  253. package/build-style/style-rtl.css +298 -238
  254. package/build-style/style.css +298 -238
  255. package/build-types/components/autosave-monitor/index.d.ts +11 -29
  256. package/build-types/components/autosave-monitor/index.d.ts.map +1 -1
  257. package/build-types/components/collab-sidebar/note-byline.d.ts +0 -3
  258. package/build-types/components/collab-sidebar/note-byline.d.ts.map +1 -1
  259. package/build-types/components/collab-sidebar/note.d.ts.map +1 -1
  260. package/build-types/components/collaborators-presence/avatar/component.d.ts.map +1 -1
  261. package/build-types/components/document-bar/index.d.ts +2 -2
  262. package/build-types/components/document-bar/index.d.ts.map +1 -1
  263. package/build-types/components/global-keyboard-shortcuts/index.d.ts.map +1 -1
  264. package/build-types/components/local-autosave-monitor/index.d.ts.map +1 -1
  265. package/build-types/components/post-publish-button/index.d.ts.map +1 -1
  266. package/build-types/components/post-publish-panel/postpublish.d.ts.map +1 -1
  267. package/build-types/components/post-revisions-preview/diff-markers.d.ts.map +1 -1
  268. package/build-types/components/post-revisions-timeline/index.d.ts +2 -0
  269. package/build-types/components/post-revisions-timeline/index.d.ts.map +1 -0
  270. package/build-types/components/post-saved-state/index.d.ts.map +1 -1
  271. package/build-types/components/post-status/index.d.ts.map +1 -1
  272. package/build-types/components/post-taxonomies/flat-term-selector.d.ts.map +1 -1
  273. package/build-types/components/post-taxonomies/hierarchical-term-selector.d.ts.map +1 -1
  274. package/build-types/components/post-template/create-new-template-modal.d.ts.map +1 -1
  275. package/build-types/components/post-text-editor/index.d.ts +1 -1
  276. package/build-types/components/post-text-editor/index.d.ts.map +1 -1
  277. package/build-types/components/post-visibility/index.d.ts.map +1 -1
  278. package/build-types/components/provider/disable-non-page-content-blocks.d.ts.map +1 -1
  279. package/build-types/components/provider/index.d.ts.map +1 -1
  280. package/build-types/components/provider/navigation-block-editing-mode.d.ts.map +1 -1
  281. package/build-types/components/provider/use-block-editor-settings.d.ts.map +1 -1
  282. package/build-types/components/resizable-editor/resize-handle.d.ts.map +1 -1
  283. package/build-types/components/revision-diff-panel/index.d.ts +3 -1
  284. package/build-types/components/revision-diff-panel/index.d.ts.map +1 -1
  285. package/build-types/components/revision-fields-diff/index.d.ts.map +1 -1
  286. package/build-types/components/sidebar/dataform-post-summary.d.ts.map +1 -1
  287. package/build-types/components/sidebar/index.d.ts.map +1 -1
  288. package/build-types/components/sidebar/post-revision-summary.d.ts.map +1 -1
  289. package/build-types/components/sidebar/post-summary.d.ts.map +1 -1
  290. package/build-types/components/template-actions-panel/block-theme-content.d.ts.map +1 -1
  291. package/build-types/components/template-actions-panel/index.d.ts.map +1 -1
  292. package/build-types/dataviews/fields/revisions/index.d.ts +8 -0
  293. package/build-types/dataviews/fields/revisions/index.d.ts.map +1 -0
  294. package/build-types/dataviews/fields/revisions/revisions-view.d.ts +2 -0
  295. package/build-types/dataviews/fields/revisions/revisions-view.d.ts.map +1 -0
  296. package/build-types/dataviews/store/private-actions.d.ts.map +1 -1
  297. package/build-types/store/private-selectors.d.ts +1 -1
  298. package/build-types/store/private-selectors.d.ts.map +1 -1
  299. package/build-types/store/selectors.d.ts +1 -1
  300. package/build-types/store/selectors.d.ts.map +1 -1
  301. package/build-types/utils/get-template-part-icon.d.ts.map +1 -1
  302. package/package.json +53 -47
  303. package/src/bindings/pattern-overrides.js +1 -1
  304. package/src/bindings/test/pattern-overrides.js +65 -0
  305. package/src/components/autosave-monitor/index.js +69 -104
  306. package/src/components/autosave-monitor/test/index.js +137 -122
  307. package/src/components/collab-sidebar/note-byline.js +0 -1
  308. package/src/components/collab-sidebar/note.js +64 -29
  309. package/src/components/collab-sidebar/style.scss +20 -0
  310. package/src/components/collaborators-presence/avatar/component.tsx +0 -1
  311. package/src/components/collaborators-presence/avatar/test/index.tsx +0 -1
  312. package/src/components/document-bar/index.js +8 -3
  313. package/src/components/document-bar/style.scss +4 -2
  314. package/src/components/global-keyboard-shortcuts/index.js +2 -1
  315. package/src/components/local-autosave-monitor/index.js +23 -21
  316. package/src/components/plugin-post-publish-panel/test/__snapshots__/index.js.snap +1 -0
  317. package/src/components/post-card-panel/index.js +1 -1
  318. package/src/components/post-publish-button/index.js +6 -3
  319. package/src/components/post-publish-button/test/index.js +13 -0
  320. package/src/components/post-publish-panel/postpublish.js +0 -1
  321. package/src/components/post-publish-panel/test/__snapshots__/index.js.snap +7 -2
  322. package/src/components/post-revisions-preview/diff-markers.js +0 -1
  323. package/src/components/post-revisions-timeline/index.js +186 -0
  324. package/src/components/post-revisions-timeline/style.scss +43 -0
  325. package/src/components/post-saved-state/index.js +23 -26
  326. package/src/components/post-saved-state/test/__snapshots__/index.js.snap +1 -0
  327. package/src/components/post-saved-state/test/index.js +18 -0
  328. package/src/components/post-status/index.js +0 -1
  329. package/src/components/post-taxonomies/flat-term-selector.js +4 -7
  330. package/src/components/post-taxonomies/hierarchical-term-selector.js +0 -1
  331. package/src/components/post-template/create-new-template-modal.js +0 -1
  332. package/src/components/post-text-editor/index.js +65 -0
  333. package/src/components/post-text-editor/test/utils.js +210 -0
  334. package/src/components/post-text-editor/utils.js +204 -0
  335. package/src/components/post-type-support-check/test/index.js +11 -0
  336. package/src/components/post-url/index.js +1 -1
  337. package/src/components/post-view-link/index.js +1 -1
  338. package/src/components/post-view-link/test/index.js +71 -0
  339. package/src/components/post-visibility/index.js +0 -1
  340. package/src/components/provider/disable-non-page-content-blocks.js +23 -6
  341. package/src/components/provider/index.js +2 -1
  342. package/src/components/provider/navigation-block-editing-mode.js +10 -4
  343. package/src/components/provider/use-block-editor-settings.js +3 -1
  344. package/src/components/resizable-editor/resize-handle.js +0 -1
  345. package/src/components/revision-diff-panel/index.js +8 -2
  346. package/src/components/revision-fields-diff/index.js +12 -1
  347. package/src/components/sidebar/dataform-post-summary.js +291 -36
  348. package/src/components/sidebar/index.js +2 -12
  349. package/src/components/sidebar/post-revision-summary.js +8 -15
  350. package/src/components/sidebar/post-summary.js +12 -10
  351. package/src/components/style-book/index.js +1 -1
  352. package/src/components/template-actions-panel/block-theme-content.js +0 -1
  353. package/src/components/template-actions-panel/index.js +0 -15
  354. package/src/dataviews/fields/revisions/index.tsx +28 -0
  355. package/src/dataviews/fields/revisions/revisions-view.tsx +59 -0
  356. package/src/dataviews/store/private-actions.ts +35 -7
  357. package/src/store/private-actions.js +2 -2
  358. package/src/store/private-selectors.js +11 -1
  359. package/src/store/test/actions.js +2 -2
  360. package/src/store/test/private-selectors.js +69 -0
  361. package/src/style.scss +1 -1
  362. package/build/components/post-revisions-panel/index.cjs +0 -173
  363. package/build/components/post-revisions-panel/index.cjs.map +0 -7
  364. package/build/components/revision-author-panel/index.cjs.map +0 -7
  365. package/build/components/revision-created-panel/index.cjs +0 -47
  366. package/build/components/revision-created-panel/index.cjs.map +0 -7
  367. package/build-module/components/post-revisions-panel/index.mjs +0 -148
  368. package/build-module/components/post-revisions-panel/index.mjs.map +0 -7
  369. package/build-module/components/revision-author-panel/index.mjs +0 -28
  370. package/build-module/components/revision-author-panel/index.mjs.map +0 -7
  371. package/build-module/components/revision-created-panel/index.mjs +0 -26
  372. package/build-module/components/revision-created-panel/index.mjs.map +0 -7
  373. package/build-types/components/collab-sidebar/add-comment.d.ts +0 -6
  374. package/build-types/components/collab-sidebar/add-comment.d.ts.map +0 -1
  375. package/build-types/components/collab-sidebar/comment-author-info.d.ts +0 -8
  376. package/build-types/components/collab-sidebar/comment-author-info.d.ts.map +0 -1
  377. package/build-types/components/collab-sidebar/comment-form.d.ts +0 -9
  378. package/build-types/components/collab-sidebar/comment-form.d.ts.map +0 -1
  379. package/build-types/components/collab-sidebar/comment-indicator-toolbar.d.ts +0 -6
  380. package/build-types/components/collab-sidebar/comment-indicator-toolbar.d.ts.map +0 -1
  381. package/build-types/components/collab-sidebar/comment-menu-item.d.ts +0 -6
  382. package/build-types/components/collab-sidebar/comment-menu-item.d.ts.map +0 -1
  383. package/build-types/components/collab-sidebar/comments.d.ts +0 -10
  384. package/build-types/components/collab-sidebar/comments.d.ts.map +0 -1
  385. package/build-types/components/global-styles-provider/index.d.ts +0 -16
  386. package/build-types/components/global-styles-provider/index.d.ts.map +0 -1
  387. package/build-types/components/media/index.d.ts +0 -3
  388. package/build-types/components/media/index.d.ts.map +0 -1
  389. package/build-types/components/media/metadata-panel.d.ts +0 -12
  390. package/build-types/components/media/metadata-panel.d.ts.map +0 -1
  391. package/build-types/components/media/preview.d.ts +0 -9
  392. package/build-types/components/media/preview.d.ts.map +0 -1
  393. package/build-types/components/post-revisions-panel/index.d.ts +0 -2
  394. package/build-types/components/post-revisions-panel/index.d.ts.map +0 -1
  395. package/build-types/components/revision-author-panel/index.d.ts +0 -2
  396. package/build-types/components/revision-author-panel/index.d.ts.map +0 -1
  397. package/build-types/components/revision-created-panel/index.d.ts +0 -2
  398. package/build-types/components/revision-created-panel/index.d.ts.map +0 -1
  399. package/src/components/editor-help/images/add-dark.png +0 -0
  400. package/src/components/editor-help/images/add-dark@2x.png +0 -0
  401. package/src/components/editor-help/images/add-dark@3x.png +0 -0
  402. package/src/components/editor-help/images/add-light.png +0 -0
  403. package/src/components/editor-help/images/add-light@2x.png +0 -0
  404. package/src/components/editor-help/images/add-light@3x.png +0 -0
  405. package/src/components/editor-help/images/block-layout-collage.png +0 -0
  406. package/src/components/editor-help/images/block-layout-collage@2x.png +0 -0
  407. package/src/components/editor-help/images/block-layout-collage@3x.png +0 -0
  408. package/src/components/editor-help/images/build-layouts-dark.png +0 -0
  409. package/src/components/editor-help/images/build-layouts-dark@2x.png +0 -0
  410. package/src/components/editor-help/images/build-layouts-dark@3x.png +0 -0
  411. package/src/components/editor-help/images/build-layouts-light.png +0 -0
  412. package/src/components/editor-help/images/build-layouts-light@2x.png +0 -0
  413. package/src/components/editor-help/images/build-layouts-light@3x.png +0 -0
  414. package/src/components/editor-help/images/drag-and-drop-dark.png +0 -0
  415. package/src/components/editor-help/images/drag-and-drop-dark@2x.png +0 -0
  416. package/src/components/editor-help/images/drag-and-drop-dark@3x.png +0 -0
  417. package/src/components/editor-help/images/drag-and-drop-light.png +0 -0
  418. package/src/components/editor-help/images/drag-and-drop-light@2x.png +0 -0
  419. package/src/components/editor-help/images/drag-and-drop-light@3x.png +0 -0
  420. package/src/components/editor-help/images/edit-media-dark.png +0 -0
  421. package/src/components/editor-help/images/edit-media-dark@2x.png +0 -0
  422. package/src/components/editor-help/images/edit-media-dark@3x.png +0 -0
  423. package/src/components/editor-help/images/edit-media-light.png +0 -0
  424. package/src/components/editor-help/images/edit-media-light@2x.png +0 -0
  425. package/src/components/editor-help/images/edit-media-light@3x.png +0 -0
  426. package/src/components/editor-help/images/embed-media-dark.png +0 -0
  427. package/src/components/editor-help/images/embed-media-dark@2x.png +0 -0
  428. package/src/components/editor-help/images/embed-media-dark@3x.png +0 -0
  429. package/src/components/editor-help/images/embed-media-light.png +0 -0
  430. package/src/components/editor-help/images/embed-media-light@2x.png +0 -0
  431. package/src/components/editor-help/images/embed-media-light@3x.png +0 -0
  432. package/src/components/editor-help/images/move-dark.png +0 -0
  433. package/src/components/editor-help/images/move-dark@2x.png +0 -0
  434. package/src/components/editor-help/images/move-dark@3x.png +0 -0
  435. package/src/components/editor-help/images/move-light.png +0 -0
  436. package/src/components/editor-help/images/move-light@2x.png +0 -0
  437. package/src/components/editor-help/images/move-light@3x.png +0 -0
  438. package/src/components/editor-help/images/options-dark.png +0 -0
  439. package/src/components/editor-help/images/options-dark@2x.png +0 -0
  440. package/src/components/editor-help/images/options-dark@3x.png +0 -0
  441. package/src/components/editor-help/images/options-light.png +0 -0
  442. package/src/components/editor-help/images/options-light@2x.png +0 -0
  443. package/src/components/editor-help/images/options-light@3x.png +0 -0
  444. package/src/components/editor-help/images/rich-text-dark.png +0 -0
  445. package/src/components/editor-help/images/rich-text-dark@2x.png +0 -0
  446. package/src/components/editor-help/images/rich-text-dark@3x.png +0 -0
  447. package/src/components/editor-help/images/rich-text-light.png +0 -0
  448. package/src/components/editor-help/images/rich-text-light@2x.png +0 -0
  449. package/src/components/editor-help/images/rich-text-light@3x.png +0 -0
  450. package/src/components/editor-help/images/settings-dark.png +0 -0
  451. package/src/components/editor-help/images/settings-dark@2x.png +0 -0
  452. package/src/components/editor-help/images/settings-dark@3x.png +0 -0
  453. package/src/components/editor-help/images/settings-light.png +0 -0
  454. package/src/components/editor-help/images/settings-light@2x.png +0 -0
  455. package/src/components/editor-help/images/settings-light@3x.png +0 -0
  456. package/src/components/editor-help/style.scss +0 -123
  457. package/src/components/post-revisions-panel/index.js +0 -161
  458. package/src/components/post-revisions-panel/style.scss +0 -16
  459. package/src/components/revision-author-panel/index.js +0 -36
  460. package/src/components/revision-created-panel/index.js +0 -36
@@ -1,9 +1,8 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { Component } from '@wordpress/element';
5
- import { compose } from '@wordpress/compose';
6
- import { withSelect, withDispatch } from '@wordpress/data';
4
+ import { useEffect, useRef } from '@wordpress/element';
5
+ import { useSelect, useDispatch } from '@wordpress/data';
7
6
  import { store as coreStore } from '@wordpress/core-data';
8
7
 
9
8
  /**
@@ -11,123 +10,89 @@ import { store as coreStore } from '@wordpress/core-data';
11
10
  */
12
11
  import { store as editorStore } from '../../store';
13
12
 
14
- export class AutosaveMonitor extends Component {
15
- constructor( props ) {
16
- super( props );
17
- this.needsAutosave = !! ( props.isDirty && props.isAutosaveable );
18
- }
19
-
20
- componentDidMount() {
21
- if ( ! this.props.disableIntervalChecks ) {
22
- this.setAutosaveTimer();
23
- }
24
- }
25
-
26
- componentDidUpdate( prevProps ) {
27
- if ( this.props.disableIntervalChecks ) {
28
- if ( this.props.editsReference !== prevProps.editsReference ) {
29
- this.props.autosave();
30
- }
31
- return;
32
- }
33
-
34
- if ( this.props.interval !== prevProps.interval ) {
35
- clearTimeout( this.timerId );
36
- this.setAutosaveTimer();
37
- }
38
-
39
- if ( ! this.props.isDirty ) {
40
- this.needsAutosave = false;
41
- return;
42
- }
43
-
44
- if ( this.props.isAutosaving && ! prevProps.isAutosaving ) {
45
- this.needsAutosave = false;
46
- return;
47
- }
48
-
49
- if ( this.props.editsReference !== prevProps.editsReference ) {
50
- this.needsAutosave = true;
51
- }
52
- }
53
-
54
- componentWillUnmount() {
55
- clearTimeout( this.timerId );
56
- }
13
+ /**
14
+ * Calls `callback` every `intervalInSeconds`. The latest `callback` is always
15
+ * invoked without resetting the timer.
16
+ *
17
+ * @param {Function} callback Function to call on each tick.
18
+ * @param {number} intervalInSeconds Seconds between ticks.
19
+ */
20
+ function useInterval( callback, intervalInSeconds ) {
21
+ const callbackRef = useRef( callback );
57
22
 
58
- setAutosaveTimer( timeout = this.props.interval * 1000 ) {
59
- this.timerId = setTimeout( () => {
60
- this.autosaveTimerHandler();
61
- }, timeout );
62
- }
23
+ useEffect( () => {
24
+ callbackRef.current = callback;
25
+ }, [ callback ] );
63
26
 
64
- autosaveTimerHandler() {
65
- if ( ! this.props.isAutosaveable ) {
66
- this.setAutosaveTimer( 1000 );
27
+ useEffect( () => {
28
+ // Interval can be undefined before editor settings are populated.
29
+ if ( ! intervalInSeconds ) {
67
30
  return;
68
31
  }
69
32
 
70
- if ( this.needsAutosave ) {
71
- this.needsAutosave = false;
72
- this.props.autosave();
73
- }
74
-
75
- this.setAutosaveTimer();
76
- }
77
-
78
- render() {
79
- return null;
80
- }
33
+ const id = setInterval(
34
+ () => callbackRef.current(),
35
+ intervalInSeconds * 1000
36
+ );
37
+ return () => clearInterval( id );
38
+ }, [ intervalInSeconds ] );
81
39
  }
82
40
 
83
41
  /**
84
42
  * Monitors the changes made to the edited post and triggers autosave if necessary.
85
43
  *
86
- * The logic is straightforward: a check is performed every `props.interval` seconds. If any changes are detected, `props.autosave()` is called.
87
- * The time between the change and the autosave varies but is no larger than `props.interval` seconds. Refer to the code below for more details, such as
88
- * the specific way of detecting changes.
44
+ * The post is checked every `interval` seconds and autosaved when there is something new to save.
89
45
  *
90
- * There are two caveats:
91
- * * If `props.isAutosaveable` happens to be false at a time of checking for changes, the check is retried every second.
92
- * * The timer may be disabled by setting `props.disableIntervalChecks` to `true`. In that mode, any change will immediately trigger `props.autosave()`.
93
- *
94
- * @param {Object} props - The properties passed to the component.
95
- * @param {Function} props.autosave - The function to call when changes need to be saved.
96
- * @param {number} props.interval - The maximum time in seconds between an unsaved change and an autosave.
97
- * @param {boolean} props.isAutosaveable - If false, the check for changes is retried every second.
98
- * @param {boolean} props.disableIntervalChecks - If true, disables the timer and any change will immediately trigger `props.autosave()`.
99
- * @param {boolean} props.isDirty - Indicates if there are unsaved changes.
46
+ * @param {Object} props The component props.
47
+ * @param {number} [props.interval] Time in seconds between checks. Defaults to the editor's
48
+ * `autosaveInterval` setting.
49
+ * @param {Function} [props.autosave] Function to call when changes need to be saved. Defaults to the
50
+ * editor store's `autosave` action.
100
51
  *
101
52
  * @example
102
53
  * ```jsx
103
- * <AutosaveMonitor interval={30000} />
54
+ * <AutosaveMonitor interval={ 30 } />
104
55
  * ```
105
56
  */
106
- export default compose( [
107
- withSelect( ( select, ownProps ) => {
108
- const { getReferenceByDistinctEdits } = select( coreStore );
57
+ export default function AutosaveMonitor( { interval, autosave } ) {
58
+ const { autosave: autosaveAction } = useDispatch( editorStore );
59
+ const triggerAutosave = autosave ?? autosaveAction;
60
+
61
+ const { getReferenceByDistinctEdits } = useSelect( coreStore );
62
+ const { isEditedPostDirty, isEditedPostAutosaveable, isAutosavingPost } =
63
+ useSelect( editorStore );
64
+
65
+ const autosaveInterval = useSelect(
66
+ ( select ) => {
67
+ if ( interval !== undefined ) {
68
+ return interval;
69
+ }
109
70
 
110
- const {
111
- isEditedPostDirty,
112
- isEditedPostAutosaveable,
113
- isAutosavingPost,
114
- getEditorSettings,
115
- } = select( editorStore );
71
+ return select( editorStore ).getEditorSettings().autosaveInterval;
72
+ },
73
+ [ interval ]
74
+ );
116
75
 
117
- const { interval = getEditorSettings().autosaveInterval } = ownProps;
76
+ // Reference of the edits last considered for autosaving. Mutable state that
77
+ // must not trigger a re-render, hence a ref.
78
+ const lastEditsReferenceRef = useRef();
118
79
 
119
- return {
120
- editsReference: getReferenceByDistinctEdits(),
121
- isDirty: isEditedPostDirty(),
122
- isAutosaveable: isEditedPostAutosaveable(),
123
- isAutosaving: isAutosavingPost(),
124
- interval,
125
- };
126
- } ),
127
- withDispatch( ( dispatch, ownProps ) => ( {
128
- autosave() {
129
- const { autosave = dispatch( editorStore ).autosave } = ownProps;
130
- autosave();
131
- },
132
- } ) ),
133
- ] )( AutosaveMonitor );
80
+ useInterval( () => {
81
+ // The post can't be autosaved yet (e.g. its existing autosave is still
82
+ // loading). Keep any pending edits and try again on the next tick.
83
+ if ( ! isEditedPostAutosaveable() ) {
84
+ return;
85
+ }
86
+
87
+ const editsReference = getReferenceByDistinctEdits();
88
+ const hasNewEdits = editsReference !== lastEditsReferenceRef.current;
89
+ if ( hasNewEdits && isEditedPostDirty() && ! isAutosavingPost() ) {
90
+ // Only consume the edits reference when we autosave,
91
+ // so edits made during an in-flight autosave aren't skipped.
92
+ lastEditsReferenceRef.current = editsReference;
93
+ triggerAutosave();
94
+ }
95
+ }, autosaveInterval );
96
+
97
+ return null;
98
+ }
@@ -3,195 +3,210 @@
3
3
  */
4
4
  import { render } from '@testing-library/react';
5
5
 
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import { useSelect, useDispatch } from '@wordpress/data';
10
+
6
11
  /**
7
12
  * Internal dependencies
8
13
  */
9
- import { AutosaveMonitor } from '../';
14
+ import AutosaveMonitor from '../';
15
+
16
+ jest.mock( '@wordpress/data/src/components/use-select', () => jest.fn() );
17
+ jest.mock( '@wordpress/data/src/components/use-dispatch', () => ( {
18
+ useDispatch: jest.fn(),
19
+ } ) );
10
20
 
11
21
  jest.useFakeTimers();
12
- jest.spyOn( global, 'clearTimeout' );
13
- jest.spyOn( global, 'setTimeout' );
22
+ jest.spyOn( global, 'clearInterval' );
23
+ jest.spyOn( global, 'setInterval' );
24
+
25
+ // The current edited-post state, read live by the mocked selectors so it can be
26
+ // changed between timer ticks without re-rendering the component.
27
+ let state;
28
+
29
+ function setState( overrides = {} ) {
30
+ state = {
31
+ editsReference: 1,
32
+ isDirty: false,
33
+ isAutosaveable: false,
34
+ isAutosaving: false,
35
+ autosaveInterval: 10,
36
+ ...overrides,
37
+ };
38
+ }
14
39
 
15
40
  describe( 'AutosaveMonitor', () => {
16
- let setAutosaveTimerSpy;
17
41
  beforeEach( () => {
18
- setAutosaveTimerSpy = jest.spyOn(
19
- AutosaveMonitor.prototype,
20
- 'setAutosaveTimer'
21
- );
22
- } );
23
-
24
- afterEach( () => {
25
- setAutosaveTimerSpy.mockClear();
42
+ setState();
43
+ // `useSelect( store )` (static mode) returns bound selectors; the
44
+ // component destructures the ones it needs from each call. The mapping
45
+ // form `useSelect( mapSelect )` receives a `select` that resolves to the
46
+ // same selectors.
47
+ useSelect.mockImplementation( ( mapSelectOrStore ) => {
48
+ const selectors = {
49
+ getReferenceByDistinctEdits: () => state.editsReference,
50
+ isEditedPostDirty: () => state.isDirty,
51
+ isEditedPostAutosaveable: () => state.isAutosaveable,
52
+ isAutosavingPost: () => state.isAutosaving,
53
+ getEditorSettings: () => ( {
54
+ autosaveInterval: state.autosaveInterval,
55
+ } ),
56
+ };
57
+ if ( typeof mapSelectOrStore === 'function' ) {
58
+ return mapSelectOrStore( () => selectors );
59
+ }
60
+ return selectors;
61
+ } );
62
+ useDispatch.mockReturnValue( { autosave: jest.fn() } );
63
+ setInterval.mockClear();
64
+ clearInterval.mockClear();
26
65
  } );
27
66
 
28
67
  it( 'should render nothing', () => {
29
- const { container } = render( <AutosaveMonitor isDirty /> );
68
+ const { container } = render( <AutosaveMonitor /> );
30
69
 
31
70
  expect( container ).toBeEmptyDOMElement();
32
71
  } );
33
72
 
34
- it( 'should start autosave timer after being mounted', () => {
35
- render( <AutosaveMonitor isDirty /> );
73
+ it( 'should start the autosave timer after being mounted', () => {
74
+ render( <AutosaveMonitor /> );
36
75
 
37
- expect( setAutosaveTimerSpy ).toHaveBeenCalled();
76
+ expect( setInterval ).toHaveBeenCalled();
38
77
  } );
39
78
 
40
79
  it( 'should clear the autosave timer after being unmounted', () => {
41
- const { rerender } = render( <AutosaveMonitor isDirty /> );
80
+ const { rerender } = render( <AutosaveMonitor /> );
42
81
 
43
82
  rerender( <div /> );
44
83
 
45
- expect( clearTimeout ).toHaveBeenCalled();
84
+ expect( clearInterval ).toHaveBeenCalled();
46
85
  } );
47
86
 
48
- it( 'should clear and restart autosave timer when the interval changes', () => {
49
- const { rerender } = render( <AutosaveMonitor isDirty /> );
87
+ it( 'should restart the autosave timer when the interval changes', () => {
88
+ const { rerender } = render( <AutosaveMonitor interval={ 10 } /> );
50
89
 
51
- rerender( <AutosaveMonitor isDirty interval={ 999 } /> );
90
+ setInterval.mockClear();
91
+ clearInterval.mockClear();
92
+ rerender( <AutosaveMonitor interval={ 999 } /> );
52
93
 
53
- expect( clearTimeout ).toHaveBeenCalled();
54
- expect( setAutosaveTimerSpy ).toHaveBeenCalledTimes( 2 );
94
+ expect( clearInterval ).toHaveBeenCalled();
95
+ expect( setInterval ).toHaveBeenCalledTimes( 1 );
55
96
  } );
56
97
 
57
- it( 'should autosave when `editReference` changes', () => {
58
- const autosave = jest.fn();
59
- const { rerender } = render(
60
- <AutosaveMonitor isDirty isAutosaveable autosave={ autosave } />
61
- );
62
-
63
- expect( autosave ).not.toHaveBeenCalled();
98
+ it( 'should schedule the timer using the interval in seconds', () => {
99
+ render( <AutosaveMonitor interval={ 5 } /> );
64
100
 
65
- rerender(
66
- <AutosaveMonitor
67
- isDirty
68
- isAutosaveable
69
- autosave={ autosave }
70
- editsReference={ [] }
71
- />
101
+ expect( setInterval ).toHaveBeenLastCalledWith(
102
+ expect.any( Function ),
103
+ 5000
72
104
  );
105
+ } );
73
106
 
74
- jest.runOnlyPendingTimers();
107
+ it( 'should fall back to the editor autosaveInterval setting', () => {
108
+ setState( { autosaveInterval: 7 } );
109
+ render( <AutosaveMonitor /> );
75
110
 
76
- expect( autosave ).toHaveBeenCalledTimes( 1 );
111
+ expect( setInterval ).toHaveBeenLastCalledWith(
112
+ expect.any( Function ),
113
+ 7000
114
+ );
77
115
  } );
78
116
 
79
- it( 'should autosave when `editReference` changes and the post becomes dirty', () => {
117
+ it( 'should autosave a dirty, autosaveable post on the timer tick', () => {
80
118
  const autosave = jest.fn();
81
- const { rerender } = render(
82
- <AutosaveMonitor isAutosaveable autosave={ autosave } />
83
- );
119
+ setState( { isDirty: true, isAutosaveable: true } );
120
+ render( <AutosaveMonitor autosave={ autosave } interval={ 5 } /> );
84
121
 
85
122
  expect( autosave ).not.toHaveBeenCalled();
86
123
 
87
- rerender(
88
- <AutosaveMonitor
89
- isDirty
90
- isAutosaveable
91
- autosave={ autosave }
92
- editsReference={ [] }
93
- />
94
- );
95
-
96
- jest.runOnlyPendingTimers();
124
+ jest.advanceTimersByTime( 5000 );
97
125
 
98
126
  expect( autosave ).toHaveBeenCalledTimes( 1 );
99
127
  } );
100
128
 
101
- it( 'should not autosave when `editReference` changes and the post is not dirty anymore', () => {
129
+ it( 'should not autosave when the post is not dirty', () => {
102
130
  const autosave = jest.fn();
103
- const { rerender } = render(
104
- <AutosaveMonitor isDirty isAutosaveable autosave={ autosave } />
105
- );
131
+ setState( { isDirty: false, isAutosaveable: true } );
132
+ render( <AutosaveMonitor autosave={ autosave } interval={ 5 } /> );
133
+
134
+ jest.advanceTimersByTime( 5000 );
106
135
 
107
136
  expect( autosave ).not.toHaveBeenCalled();
137
+ } );
108
138
 
109
- rerender(
110
- <AutosaveMonitor
111
- isAutosaveable
112
- autosave={ autosave }
113
- editsReference={ [] }
114
- />
115
- );
139
+ it( 'should not autosave while an autosave is already in progress', () => {
140
+ const autosave = jest.fn();
141
+ setState( { isDirty: true, isAutosaveable: true, isAutosaving: true } );
142
+ render( <AutosaveMonitor autosave={ autosave } interval={ 5 } /> );
116
143
 
117
- jest.runOnlyPendingTimers();
144
+ jest.advanceTimersByTime( 5000 );
118
145
 
119
146
  expect( autosave ).not.toHaveBeenCalled();
120
147
  } );
121
148
 
122
- it( 'should not autosave when `editReference` changes and the post is not autosaving', () => {
149
+ it( 'should autosave edits made during an in-progress autosave once it finishes', () => {
123
150
  const autosave = jest.fn();
124
- const { rerender } = render(
125
- <AutosaveMonitor isAutosaveable autosave={ autosave } />
126
- );
127
-
151
+ setState( { isDirty: true, isAutosaveable: true } );
152
+ render( <AutosaveMonitor autosave={ autosave } interval={ 5 } /> );
153
+
154
+ // New edit arrives while an autosave is already in progress: the tick
155
+ // should not consume the edits reference nor trigger an autosave.
156
+ setState( {
157
+ isDirty: true,
158
+ isAutosaveable: true,
159
+ isAutosaving: true,
160
+ editsReference: 2,
161
+ } );
162
+ jest.advanceTimersByTime( 5000 );
128
163
  expect( autosave ).not.toHaveBeenCalled();
129
164
 
130
- rerender(
131
- <AutosaveMonitor
132
- isAutosaveable
133
- autosave={ autosave }
134
- isAutosaving={ false }
135
- editsReference={ [] }
136
- />
137
- );
138
-
139
- jest.runOnlyPendingTimers();
140
-
141
- expect( autosave ).not.toHaveBeenCalled();
165
+ // Once the autosave finishes, the pending edit must still be autosaved.
166
+ setState( { isDirty: true, isAutosaveable: true, editsReference: 2 } );
167
+ jest.advanceTimersByTime( 5000 );
168
+ expect( autosave ).toHaveBeenCalledTimes( 1 );
142
169
  } );
143
170
 
144
- it( 'should not autosave when `editReference` changes and the post started autosaving', () => {
171
+ it( 'should not autosave again until there are new edits', () => {
145
172
  const autosave = jest.fn();
146
- const { rerender } = render(
147
- <AutosaveMonitor
148
- isAutosaveable
149
- autosave={ autosave }
150
- isAutosaving={ false }
151
- />
152
- );
173
+ setState( { isDirty: true, isAutosaveable: true } );
174
+ render( <AutosaveMonitor autosave={ autosave } interval={ 5 } /> );
153
175
 
154
- expect( autosave ).not.toHaveBeenCalled();
155
-
156
- rerender(
157
- <AutosaveMonitor
158
- isAutosaveable
159
- autosave={ autosave }
160
- isAutosaving
161
- editsReference={ [] }
162
- />
163
- );
176
+ jest.advanceTimersByTime( 5000 );
177
+ expect( autosave ).toHaveBeenCalledTimes( 1 );
164
178
 
165
- jest.runOnlyPendingTimers();
179
+ // No new edits: a subsequent tick should not autosave again.
180
+ jest.advanceTimersByTime( 5000 );
181
+ expect( autosave ).toHaveBeenCalledTimes( 1 );
166
182
 
167
- expect( autosave ).not.toHaveBeenCalled();
183
+ // A new distinct edit triggers another autosave.
184
+ setState( { isDirty: true, isAutosaveable: true, editsReference: 2 } );
185
+ jest.advanceTimersByTime( 5000 );
186
+ expect( autosave ).toHaveBeenCalledTimes( 2 );
168
187
  } );
169
188
 
170
- it( 'should schedule itself in another {interval} ms', () => {
171
- const { rerender } = render( <AutosaveMonitor isDirty /> );
172
-
173
- rerender( <AutosaveMonitor isDirty isAutosaveable interval={ 5 } /> );
189
+ it( 'should keep pending edits and retry once the post becomes autosaveable', () => {
190
+ const autosave = jest.fn();
191
+ setState( { isDirty: true, isAutosaveable: false, editsReference: 2 } );
192
+ render( <AutosaveMonitor autosave={ autosave } interval={ 5 } /> );
174
193
 
175
- jest.runOnlyPendingTimers();
194
+ jest.advanceTimersByTime( 5000 );
195
+ expect( autosave ).not.toHaveBeenCalled();
176
196
 
177
- expect( setTimeout ).toHaveBeenLastCalledWith(
178
- expect.any( Function ),
179
- 5000
180
- );
197
+ setState( { isDirty: true, isAutosaveable: true, editsReference: 2 } );
198
+ jest.advanceTimersByTime( 5000 );
199
+ expect( autosave ).toHaveBeenCalledTimes( 1 );
181
200
  } );
182
201
 
183
- it( 'should schedule itself in 1000 ms if the post is not autosaveable at a time', () => {
184
- const { rerender } = render( <AutosaveMonitor isDirty /> );
185
-
186
- rerender(
187
- <AutosaveMonitor isDirty isAutosaveable={ false } interval={ 5 } />
188
- );
202
+ it( 'should fall back to the editor store autosave action', () => {
203
+ const autosave = jest.fn();
204
+ useDispatch.mockReturnValue( { autosave } );
205
+ setState( { isDirty: true, isAutosaveable: true } );
206
+ render( <AutosaveMonitor interval={ 5 } /> );
189
207
 
190
- jest.runOnlyPendingTimers();
208
+ jest.advanceTimersByTime( 5000 );
191
209
 
192
- expect( setTimeout ).toHaveBeenLastCalledWith(
193
- expect.any( Function ),
194
- 1000
195
- );
210
+ expect( autosave ).toHaveBeenCalledTimes( 1 );
196
211
  } );
197
212
  } );
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- // eslint-disable-next-line @wordpress/use-recommended-components -- `Tooltip` is not yet on the recommended `@wordpress/ui` allow-list; landing as a migration step ahead of the wider rollout.
5
4
  import { Stack, Tooltip } from '@wordpress/ui';
6
5
  import { __, _x } from '@wordpress/i18n';
7
6
  import {
@@ -6,12 +6,14 @@ import clsx from 'clsx';
6
6
  /**
7
7
  * WordPress dependencies
8
8
  */
9
- import { RawHTML, useRef, useState } from '@wordpress/element';
9
+ import { useRef, useState, useLayoutEffect } from '@wordpress/element';
10
10
  import {
11
11
  __experimentalConfirmDialog as ConfirmDialog,
12
12
  Button,
13
13
  privateApis as componentsPrivateApis,
14
14
  } from '@wordpress/components';
15
+ // eslint-disable-next-line @wordpress/use-recommended-components
16
+ import { Button as UIButton } from '@wordpress/ui';
15
17
  import { __, _x, sprintf } from '@wordpress/i18n';
16
18
  import { moreVertical, published } from '@wordpress/icons';
17
19
 
@@ -66,6 +68,28 @@ export function Note( {
66
68
  const [ actionState, setActionState ] = useState( null );
67
69
  const actionButtonRef = useRef( null );
68
70
 
71
+ const commentRef = useRef( null );
72
+ const rawContent = note?.content?.raw;
73
+ const [ prevContent, setPrevContent ] = useState( rawContent );
74
+ const [ isExpanded, setIsExpanded ] = useState( false );
75
+ const [ isOverflowing, setIsOverflowing ] = useState( false );
76
+
77
+ // Collapse whenever the content changes so it can be re-measured.
78
+ if ( prevContent !== rawContent ) {
79
+ setPrevContent( rawContent );
80
+ setIsExpanded( false );
81
+ }
82
+
83
+ // Measure the (clamped) content to decide whether the toggle is needed.
84
+ useLayoutEffect( () => {
85
+ const commentElement = commentRef.current;
86
+ if ( commentElement ) {
87
+ setIsOverflowing(
88
+ commentElement.scrollHeight > commentElement.clientHeight
89
+ );
90
+ }
91
+ }, [ rawContent ] );
92
+
69
93
  const canResolve = note.parent === 0;
70
94
  const isResolutionNote =
71
95
  note.type === 'note' &&
@@ -132,36 +156,37 @@ export function Note( {
132
156
  } }
133
157
  />
134
158
  );
135
- } else if ( isResolutionNote ) {
136
- const actionText =
137
- note.meta._wp_note_status === 'resolved'
138
- ? __( 'Marked as resolved' )
139
- : __( 'Reopened' );
140
- const raw = note?.content?.raw;
141
- const text =
142
- raw && typeof raw === 'string' && raw.trim() !== ''
143
- ? sprintf(
144
- // translators: %1$s: action label ("Marked as resolved" or "Reopened"); %2$s: note text.
145
- __( '%1$s: %2$s' ),
146
- actionText,
147
- raw
148
- )
149
- : actionText;
150
- body = (
151
- <RawHTML
152
- className={ clsx(
153
- 'editor-collab-sidebar-panel__note-content',
154
- 'editor-collab-sidebar-panel__resolution-text'
155
- ) }
156
- >
157
- { text }
158
- </RawHTML>
159
- );
160
159
  } else {
160
+ let content;
161
+ if ( isResolutionNote ) {
162
+ const actionText =
163
+ note.meta._wp_note_status === 'resolved'
164
+ ? __( 'Marked as resolved' )
165
+ : __( 'Reopened' );
166
+ const raw = note?.content?.raw;
167
+ content =
168
+ raw && typeof raw === 'string' && raw.trim() !== ''
169
+ ? sprintf(
170
+ // translators: %1$s: action label ("Marked as resolved" or "Reopened"); %2$s: note text.
171
+ __( '%1$s: %2$s' ),
172
+ actionText,
173
+ raw
174
+ )
175
+ : actionText;
176
+ } else {
177
+ content = note?.content?.rendered;
178
+ }
179
+
161
180
  body = (
162
- <RawHTML className="editor-collab-sidebar-panel__note-content">
163
- { note?.content?.rendered }
164
- </RawHTML>
181
+ <div
182
+ ref={ commentRef }
183
+ className={ clsx( 'editor-collab-sidebar-panel__note-content', {
184
+ 'editor-collab-sidebar-panel__resolution-text':
185
+ isResolutionNote,
186
+ 'is-collapsed': ! isExpanded,
187
+ } ) }
188
+ dangerouslySetInnerHTML={ { __html: content ?? '' } }
189
+ />
165
190
  );
166
191
  }
167
192
 
@@ -204,6 +229,16 @@ export function Note( {
204
229
  { deleteConfirmMessage }
205
230
  </ConfirmDialog>
206
231
  ) }
232
+ { isOverflowing && 'edit' !== actionState && (
233
+ <UIButton
234
+ className="editor-collab-sidebar-panel__show-more-button"
235
+ variant="unstyled"
236
+ size="small"
237
+ onClick={ () => setIsExpanded( ! isExpanded ) }
238
+ >
239
+ { ! isExpanded ? __( 'Show more' ) : __( 'Show less' ) }
240
+ </UIButton>
241
+ ) }
207
242
  </NoteCard>
208
243
  );
209
244
  }