@wordpress/editor 14.38.0 → 14.39.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 (233) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/components/document-bar/useEditedSectionDetails.cjs +0 -3
  3. package/build/components/document-bar/useEditedSectionDetails.cjs.map +2 -2
  4. package/build/components/editor-interface/index.cjs +33 -9
  5. package/build/components/editor-interface/index.cjs.map +2 -2
  6. package/build/components/header/header-skeleton.cjs +100 -0
  7. package/build/components/header/header-skeleton.cjs.map +7 -0
  8. package/build/components/header/index.cjs +63 -106
  9. package/build/components/header/index.cjs.map +3 -3
  10. package/build/components/media/index.cjs +44 -0
  11. package/build/components/media/index.cjs.map +7 -0
  12. package/build/components/media/metadata-panel.cjs +96 -0
  13. package/build/components/media/metadata-panel.cjs.map +7 -0
  14. package/build/components/media/preview.cjs +39 -0
  15. package/build/components/media/preview.cjs.map +7 -0
  16. package/build/components/more-menu/index.cjs +3 -2
  17. package/build/components/more-menu/index.cjs.map +2 -2
  18. package/build/components/post-card-panel/index.cjs +33 -4
  19. package/build/components/post-card-panel/index.cjs.map +3 -3
  20. package/build/components/post-content-information/index.cjs +9 -0
  21. package/build/components/post-content-information/index.cjs.map +2 -2
  22. package/build/components/post-last-edited-panel/index.cjs +5 -6
  23. package/build/components/post-last-edited-panel/index.cjs.map +2 -2
  24. package/build/components/post-last-revision/index.cjs +5 -7
  25. package/build/components/post-last-revision/index.cjs.map +2 -2
  26. package/build/components/post-publish-button/label.cjs +6 -1
  27. package/build/components/post-publish-button/label.cjs.map +2 -2
  28. package/build/components/post-publish-button/post-publish-button-or-toggle.cjs +8 -3
  29. package/build/components/post-publish-button/post-publish-button-or-toggle.cjs.map +2 -2
  30. package/build/components/post-revisions-preview/index.cjs +44 -0
  31. package/build/components/post-revisions-preview/index.cjs.map +7 -0
  32. package/build/components/post-revisions-preview/revisions-canvas.cjs +82 -0
  33. package/build/components/post-revisions-preview/revisions-canvas.cjs.map +7 -0
  34. package/build/components/post-revisions-preview/revisions-header.cjs +119 -0
  35. package/build/components/post-revisions-preview/revisions-header.cjs.map +7 -0
  36. package/build/components/post-revisions-preview/revisions-slider.cjs +110 -0
  37. package/build/components/post-revisions-preview/revisions-slider.cjs.map +7 -0
  38. package/build/components/post-saved-state/index.cjs +8 -2
  39. package/build/components/post-saved-state/index.cjs.map +2 -2
  40. package/build/components/post-title/index.cjs +5 -4
  41. package/build/components/post-title/index.cjs.map +2 -2
  42. package/build/components/provider/index.cjs +19 -0
  43. package/build/components/provider/index.cjs.map +3 -3
  44. package/build/components/provider/use-block-editor-settings.cjs +2 -1
  45. package/build/components/provider/use-block-editor-settings.cjs.map +2 -2
  46. package/build/components/revision-author-panel/index.cjs +59 -0
  47. package/build/components/revision-author-panel/index.cjs.map +7 -0
  48. package/build/components/revision-created-panel/index.cjs +47 -0
  49. package/build/components/revision-created-panel/index.cjs.map +7 -0
  50. package/build/components/sidebar/header.cjs +27 -12
  51. package/build/components/sidebar/header.cjs.map +3 -3
  52. package/build/components/sidebar/index.cjs +36 -15
  53. package/build/components/sidebar/index.cjs.map +3 -3
  54. package/build/components/sidebar/post-summary.cjs +44 -19
  55. package/build/components/sidebar/post-summary.cjs.map +3 -3
  56. package/build/components/start-page-options/index.cjs +1 -1
  57. package/build/components/start-page-options/index.cjs.map +2 -2
  58. package/build/dataviews/store/private-actions.cjs +47 -26
  59. package/build/dataviews/store/private-actions.cjs.map +3 -3
  60. package/build/store/constants.cjs +3 -0
  61. package/build/store/constants.cjs.map +2 -2
  62. package/build/store/private-actions.cjs +40 -0
  63. package/build/store/private-actions.cjs.map +2 -2
  64. package/build/store/private-selectors.cjs +33 -2
  65. package/build/store/private-selectors.cjs.map +2 -2
  66. package/build/store/reducer.cjs +10 -0
  67. package/build/store/reducer.cjs.map +2 -2
  68. package/build/store/selectors.cjs +3 -0
  69. package/build/store/selectors.cjs.map +2 -2
  70. package/build/store/utils/notice-builder.cjs +4 -0
  71. package/build/store/utils/notice-builder.cjs.map +2 -2
  72. package/build-module/components/document-bar/useEditedSectionDetails.mjs +0 -3
  73. package/build-module/components/document-bar/useEditedSectionDetails.mjs.map +2 -2
  74. package/build-module/components/editor-interface/index.mjs +33 -9
  75. package/build-module/components/editor-interface/index.mjs.map +2 -2
  76. package/build-module/components/header/header-skeleton.mjs +69 -0
  77. package/build-module/components/header/header-skeleton.mjs.map +7 -0
  78. package/build-module/components/header/index.mjs +65 -107
  79. package/build-module/components/header/index.mjs.map +2 -2
  80. package/build-module/components/media/index.mjs +8 -0
  81. package/build-module/components/media/index.mjs.map +7 -0
  82. package/build-module/components/media/metadata-panel.mjs +65 -0
  83. package/build-module/components/media/metadata-panel.mjs.map +7 -0
  84. package/build-module/components/media/preview.mjs +21 -0
  85. package/build-module/components/media/preview.mjs.map +7 -0
  86. package/build-module/components/more-menu/index.mjs +3 -2
  87. package/build-module/components/more-menu/index.mjs.map +2 -2
  88. package/build-module/components/post-card-panel/index.mjs +35 -5
  89. package/build-module/components/post-card-panel/index.mjs.map +3 -3
  90. package/build-module/components/post-content-information/index.mjs +9 -0
  91. package/build-module/components/post-content-information/index.mjs.map +2 -2
  92. package/build-module/components/post-last-edited-panel/index.mjs +5 -6
  93. package/build-module/components/post-last-edited-panel/index.mjs.map +2 -2
  94. package/build-module/components/post-last-revision/index.mjs +6 -8
  95. package/build-module/components/post-last-revision/index.mjs.map +2 -2
  96. package/build-module/components/post-publish-button/label.mjs +6 -1
  97. package/build-module/components/post-publish-button/label.mjs.map +2 -2
  98. package/build-module/components/post-publish-button/post-publish-button-or-toggle.mjs +8 -3
  99. package/build-module/components/post-publish-button/post-publish-button-or-toggle.mjs.map +2 -2
  100. package/build-module/components/post-revisions-preview/index.mjs +8 -0
  101. package/build-module/components/post-revisions-preview/index.mjs.map +7 -0
  102. package/build-module/components/post-revisions-preview/revisions-canvas.mjs +54 -0
  103. package/build-module/components/post-revisions-preview/revisions-canvas.mjs.map +7 -0
  104. package/build-module/components/post-revisions-preview/revisions-header.mjs +92 -0
  105. package/build-module/components/post-revisions-preview/revisions-header.mjs.map +7 -0
  106. package/build-module/components/post-revisions-preview/revisions-slider.mjs +89 -0
  107. package/build-module/components/post-revisions-preview/revisions-slider.mjs.map +7 -0
  108. package/build-module/components/post-saved-state/index.mjs +8 -2
  109. package/build-module/components/post-saved-state/index.mjs.map +2 -2
  110. package/build-module/components/post-title/index.mjs +5 -4
  111. package/build-module/components/post-title/index.mjs.map +2 -2
  112. package/build-module/components/provider/index.mjs +19 -0
  113. package/build-module/components/provider/index.mjs.map +2 -2
  114. package/build-module/components/provider/use-block-editor-settings.mjs +2 -1
  115. package/build-module/components/provider/use-block-editor-settings.mjs.map +2 -2
  116. package/build-module/components/revision-author-panel/index.mjs +28 -0
  117. package/build-module/components/revision-author-panel/index.mjs.map +7 -0
  118. package/build-module/components/revision-created-panel/index.mjs +26 -0
  119. package/build-module/components/revision-created-panel/index.mjs.map +7 -0
  120. package/build-module/components/sidebar/header.mjs +22 -7
  121. package/build-module/components/sidebar/header.mjs.map +2 -2
  122. package/build-module/components/sidebar/index.mjs +38 -16
  123. package/build-module/components/sidebar/index.mjs.map +2 -2
  124. package/build-module/components/sidebar/post-summary.mjs +48 -20
  125. package/build-module/components/sidebar/post-summary.mjs.map +2 -2
  126. package/build-module/components/start-page-options/index.mjs +2 -1
  127. package/build-module/components/start-page-options/index.mjs.map +2 -2
  128. package/build-module/dataviews/store/private-actions.mjs +59 -27
  129. package/build-module/dataviews/store/private-actions.mjs.map +2 -2
  130. package/build-module/store/constants.mjs +2 -0
  131. package/build-module/store/constants.mjs.map +2 -2
  132. package/build-module/store/private-actions.mjs +38 -0
  133. package/build-module/store/private-actions.mjs.map +2 -2
  134. package/build-module/store/private-selectors.mjs +29 -1
  135. package/build-module/store/private-selectors.mjs.map +2 -2
  136. package/build-module/store/reducer.mjs +9 -0
  137. package/build-module/store/reducer.mjs.map +2 -2
  138. package/build-module/store/selectors.mjs +4 -0
  139. package/build-module/store/selectors.mjs.map +2 -2
  140. package/build-module/store/utils/notice-builder.mjs +4 -0
  141. package/build-module/store/utils/notice-builder.mjs.map +2 -2
  142. package/build-style/style-rtl.css +182 -16
  143. package/build-style/style.css +182 -16
  144. package/build-types/components/document-bar/useEditedSectionDetails.d.ts.map +1 -1
  145. package/build-types/components/editor-interface/index.d.ts.map +1 -1
  146. package/build-types/components/header/header-skeleton.d.ts +17 -0
  147. package/build-types/components/header/header-skeleton.d.ts.map +1 -0
  148. package/build-types/components/header/index.d.ts.map +1 -1
  149. package/build-types/components/media/index.d.ts +3 -0
  150. package/build-types/components/media/index.d.ts.map +1 -0
  151. package/build-types/components/media/metadata-panel.d.ts +12 -0
  152. package/build-types/components/media/metadata-panel.d.ts.map +1 -0
  153. package/build-types/components/media/preview.d.ts +9 -0
  154. package/build-types/components/media/preview.d.ts.map +1 -0
  155. package/build-types/components/more-menu/index.d.ts +3 -1
  156. package/build-types/components/more-menu/index.d.ts.map +1 -1
  157. package/build-types/components/post-card-panel/index.d.ts.map +1 -1
  158. package/build-types/components/post-content-information/index.d.ts.map +1 -1
  159. package/build-types/components/post-last-edited-panel/index.d.ts.map +1 -1
  160. package/build-types/components/post-last-revision/index.d.ts.map +1 -1
  161. package/build-types/components/post-publish-button/label.d.ts.map +1 -1
  162. package/build-types/components/post-publish-button/post-publish-button-or-toggle.d.ts.map +1 -1
  163. package/build-types/components/post-revisions-preview/index.d.ts +3 -0
  164. package/build-types/components/post-revisions-preview/index.d.ts.map +1 -0
  165. package/build-types/components/post-revisions-preview/revisions-canvas.d.ts +7 -0
  166. package/build-types/components/post-revisions-preview/revisions-canvas.d.ts.map +1 -0
  167. package/build-types/components/post-revisions-preview/revisions-header.d.ts +8 -0
  168. package/build-types/components/post-revisions-preview/revisions-header.d.ts.map +1 -0
  169. package/build-types/components/post-revisions-preview/revisions-slider.d.ts +8 -0
  170. package/build-types/components/post-revisions-preview/revisions-slider.d.ts.map +1 -0
  171. package/build-types/components/post-saved-state/index.d.ts.map +1 -1
  172. package/build-types/components/provider/index.d.ts.map +1 -1
  173. package/build-types/components/provider/use-block-editor-settings.d.ts.map +1 -1
  174. package/build-types/components/revision-author-panel/index.d.ts +2 -0
  175. package/build-types/components/revision-author-panel/index.d.ts.map +1 -0
  176. package/build-types/components/revision-created-panel/index.d.ts +2 -0
  177. package/build-types/components/revision-created-panel/index.d.ts.map +1 -0
  178. package/build-types/components/sidebar/index.d.ts.map +1 -1
  179. package/build-types/components/sidebar/post-summary.d.ts.map +1 -1
  180. package/build-types/components/start-page-options/index.d.ts.map +1 -1
  181. package/build-types/dataviews/store/private-actions.d.ts +1 -0
  182. package/build-types/dataviews/store/private-actions.d.ts.map +1 -1
  183. package/build-types/store/constants.d.ts +1 -0
  184. package/build-types/store/constants.d.ts.map +1 -1
  185. package/build-types/store/private-actions.d.ts +13 -0
  186. package/build-types/store/private-actions.d.ts.map +1 -1
  187. package/build-types/store/private-selectors.d.ts +25 -0
  188. package/build-types/store/private-selectors.d.ts.map +1 -1
  189. package/build-types/store/reducer.d.ts +11 -0
  190. package/build-types/store/reducer.d.ts.map +1 -1
  191. package/build-types/store/selectors.d.ts.map +1 -1
  192. package/build-types/store/utils/notice-builder.d.ts.map +1 -1
  193. package/package.json +42 -40
  194. package/src/components/document-bar/useEditedSectionDetails.js +0 -5
  195. package/src/components/editor-interface/index.js +39 -9
  196. package/src/components/header/header-skeleton.js +90 -0
  197. package/src/components/header/index.js +69 -102
  198. package/src/components/header/style.scss +4 -0
  199. package/src/components/media/index.js +2 -0
  200. package/src/components/media/metadata-panel.js +77 -0
  201. package/src/components/media/preview.js +35 -0
  202. package/src/components/more-menu/index.js +2 -1
  203. package/src/components/post-card-panel/index.js +43 -7
  204. package/src/components/post-content-information/index.js +11 -0
  205. package/src/components/post-last-edited-panel/index.js +8 -9
  206. package/src/components/post-last-revision/index.js +7 -8
  207. package/src/components/post-publish-button/label.js +9 -0
  208. package/src/components/post-publish-button/post-publish-button-or-toggle.js +13 -5
  209. package/src/components/post-revisions-preview/index.js +2 -0
  210. package/src/components/post-revisions-preview/revisions-canvas.js +73 -0
  211. package/src/components/post-revisions-preview/revisions-header.js +108 -0
  212. package/src/components/post-revisions-preview/revisions-slider.js +123 -0
  213. package/src/components/post-revisions-preview/style.scss +22 -0
  214. package/src/components/post-saved-state/index.js +8 -0
  215. package/src/components/post-title/index.js +4 -3
  216. package/src/components/provider/index.js +26 -0
  217. package/src/components/provider/use-block-editor-settings.js +2 -3
  218. package/src/components/revision-author-panel/index.js +36 -0
  219. package/src/components/revision-created-panel/index.js +36 -0
  220. package/src/components/sidebar/header.js +35 -14
  221. package/src/components/sidebar/index.js +40 -13
  222. package/src/components/sidebar/post-summary.js +45 -11
  223. package/src/components/sidebar/style.scss +7 -0
  224. package/src/components/start-page-options/index.js +2 -0
  225. package/src/dataviews/store/private-actions.ts +79 -33
  226. package/src/store/constants.ts +1 -0
  227. package/src/store/private-actions.js +70 -0
  228. package/src/store/private-selectors.js +54 -0
  229. package/src/store/reducer.js +17 -0
  230. package/src/store/selectors.js +6 -0
  231. package/src/store/test/selectors.js +7 -0
  232. package/src/store/utils/notice-builder.js +9 -0
  233. package/src/style.scss +2 -0
@@ -31,11 +31,13 @@ import PostTransformPanel from '../post-transform-panel';
31
31
  import SidebarHeader from './header';
32
32
  import TemplateContentPanel from '../template-content-panel';
33
33
  import TemplatePartContentPanel from '../template-part-content-panel';
34
+ import { MediaMetadataPanel } from '../media';
34
35
  import useAutoSwitchEditorSidebars from '../provider/use-auto-switch-editor-sidebars';
35
36
  import { sidebars } from './constants';
36
37
  import { unlock } from '../../lock-unlock';
37
38
  import { store as editorStore } from '../../store';
38
39
  import {
40
+ ATTACHMENT_POST_TYPE,
39
41
  NAVIGATION_POST_TYPE,
40
42
  TEMPLATE_PART_POST_TYPE,
41
43
  TEMPLATE_POST_TYPE,
@@ -53,12 +55,17 @@ const SidebarContent = ( {
53
55
  keyboardShortcut,
54
56
  onActionPerformed,
55
57
  extraPanels,
58
+ postType,
56
59
  } ) => {
57
60
  const tabListRef = useRef( null );
58
61
  // Because `PluginSidebar` renders a `ComplementaryArea`, we
59
62
  // need to forward the `Tabs` context so it can be passed through the
60
63
  // underlying slot/fill.
61
64
  const tabsContextValue = useContext( Tabs.Context );
65
+ const isAttachment = postType === ATTACHMENT_POST_TYPE;
66
+ const isRevisionsMode = useSelect( ( select ) => {
67
+ return unlock( select( editorStore ) ).isRevisionsMode();
68
+ } );
62
69
 
63
70
  // This effect addresses a race condition caused by tabbing from the last
64
71
  // block in the editor into the settings sidebar. Without this effect, the
@@ -111,18 +118,34 @@ const SidebarContent = ( {
111
118
  >
112
119
  <Tabs.Context.Provider value={ tabsContextValue }>
113
120
  <Tabs.TabPanel tabId={ sidebars.document } focusable={ false }>
114
- <PostSummary onActionPerformed={ onActionPerformed } />
115
- <PluginDocumentSettingPanel.Slot />
116
- <TemplateContentPanel />
117
- <TemplatePartContentPanel />
118
- <PostTransformPanel />
119
- <PostTaxonomiesPanel />
120
- <PatternOverridesPanel />
121
- { extraPanels }
122
- </Tabs.TabPanel>
123
- <Tabs.TabPanel tabId={ sidebars.block } focusable={ false }>
124
- <BlockInspector />
121
+ { isAttachment ? (
122
+ <MediaMetadataPanel
123
+ onActionPerformed={ onActionPerformed }
124
+ />
125
+ ) : (
126
+ <>
127
+ <PostSummary
128
+ onActionPerformed={ onActionPerformed }
129
+ />
130
+ { ! isRevisionsMode && (
131
+ <>
132
+ <PluginDocumentSettingPanel.Slot />
133
+ <TemplateContentPanel />
134
+ <TemplatePartContentPanel />
135
+ <PostTransformPanel />
136
+ <PostTaxonomiesPanel />
137
+ <PatternOverridesPanel />
138
+ { extraPanels }
139
+ </>
140
+ ) }
141
+ </>
142
+ ) }
125
143
  </Tabs.TabPanel>
144
+ { ! isAttachment && (
145
+ <Tabs.TabPanel tabId={ sidebars.block } focusable={ false }>
146
+ <BlockInspector />
147
+ </Tabs.TabPanel>
148
+ ) }
126
149
  </Tabs.Context.Provider>
127
150
  </PluginSidebar>
128
151
  );
@@ -130,7 +153,7 @@ const SidebarContent = ( {
130
153
 
131
154
  const Sidebar = ( { extraPanels, onActionPerformed } ) => {
132
155
  useAutoSwitchEditorSidebars();
133
- const { tabName, keyboardShortcut, showSummary } = useSelect(
156
+ const { tabName, keyboardShortcut, showSummary, postType } = useSelect(
134
157
  ( select ) => {
135
158
  const shortcut = select(
136
159
  keyboardShortcutsStore
@@ -151,6 +174,8 @@ const Sidebar = ( { extraPanels, onActionPerformed } ) => {
151
174
  : sidebars.document;
152
175
  }
153
176
 
177
+ const _postType = select( editorStore ).getCurrentPostType();
178
+
154
179
  return {
155
180
  tabName: _tabName,
156
181
  keyboardShortcut: shortcut,
@@ -158,7 +183,8 @@ const Sidebar = ( { extraPanels, onActionPerformed } ) => {
158
183
  TEMPLATE_POST_TYPE,
159
184
  TEMPLATE_PART_POST_TYPE,
160
185
  NAVIGATION_POST_TYPE,
161
- ].includes( select( editorStore ).getCurrentPostType() ),
186
+ ].includes( _postType ),
187
+ postType: _postType,
162
188
  };
163
189
  },
164
190
  []
@@ -187,6 +213,7 @@ const Sidebar = ( { extraPanels, onActionPerformed } ) => {
187
213
  showSummary={ showSummary }
188
214
  onActionPerformed={ onActionPerformed }
189
215
  extraPanels={ extraPanels }
216
+ postType={ postType }
190
217
  />
191
218
  </Tabs>
192
219
  );
@@ -1,8 +1,13 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { __experimentalVStack as VStack } from '@wordpress/components';
4
+ import {
5
+ __experimentalVStack as VStack,
6
+ ExternalLink,
7
+ } from '@wordpress/components';
5
8
  import { useSelect } from '@wordpress/data';
9
+ import { __ } from '@wordpress/i18n';
10
+ import { addQueryArgs } from '@wordpress/url';
6
11
 
7
12
  /**
8
13
  * Internal dependencies
@@ -17,6 +22,7 @@ import { PrivatePostExcerptPanel as PostExcerptPanel } from '../post-excerpt/pan
17
22
  import PostFeaturedImagePanel from '../post-featured-image/panel';
18
23
  import PostFormatPanel from '../post-format/panel';
19
24
  import PostLastEditedPanel from '../post-last-edited-panel';
25
+ import RevisionCreatedPanel from '../revision-created-panel';
20
26
  import PostPanelSection from '../post-panel-section';
21
27
  import PostSchedulePanel from '../post-schedule/panel';
22
28
  import PostStatusPanel from '../post-status';
@@ -29,6 +35,8 @@ import SiteDiscussion from '../site-discussion';
29
35
  import { store as editorStore } from '../../store';
30
36
  import { PrivatePostLastRevision } from '../post-last-revision';
31
37
  import PostTrash from '../post-trash';
38
+ import RevisionAuthorPanel from '../revision-author-panel';
39
+ import { unlock } from '../../lock-unlock';
32
40
 
33
41
  /**
34
42
  * Module Constants
@@ -36,23 +44,27 @@ import PostTrash from '../post-trash';
36
44
  const PANEL_NAME = 'post-status';
37
45
 
38
46
  export default function PostSummary( { onActionPerformed } ) {
39
- const { isRemovedPostStatusPanel, postType, postId } = useSelect(
40
- ( select ) => {
47
+ const { isRemovedPostStatusPanel, postType, postId, revisionId } =
48
+ useSelect( ( select ) => {
41
49
  // We use isEditorPanelRemoved to hide the panel if it was programmatically removed. We do
42
50
  // not use isEditorPanelEnabled since this panel should not be disabled through the UI.
43
51
  const {
44
52
  isEditorPanelRemoved,
45
53
  getCurrentPostType,
46
54
  getCurrentPostId,
47
- } = select( editorStore );
55
+ getCurrentRevisionId,
56
+ } = unlock( select( editorStore ) );
48
57
  return {
49
58
  isRemovedPostStatusPanel: isEditorPanelRemoved( PANEL_NAME ),
50
59
  postType: getCurrentPostType(),
51
60
  postId: getCurrentPostId(),
61
+ revisionId: getCurrentRevisionId(),
52
62
  };
53
- },
54
- []
55
- );
63
+ }, [] );
64
+
65
+ const isRevisionsMode = !! revisionId;
66
+ const shouldShowPostStatusPanel =
67
+ ! isRemovedPostStatusPanel && ! isRevisionsMode;
56
68
 
57
69
  return (
58
70
  <PostPanelSection className="editor-post-summary">
@@ -65,13 +77,35 @@ export default function PostSummary( { onActionPerformed } ) {
65
77
  postId={ postId }
66
78
  onActionPerformed={ onActionPerformed }
67
79
  />
68
- <PostFeaturedImagePanel withPanelBody={ false } />
69
- <PostExcerptPanel />
80
+ { ! isRevisionsMode && (
81
+ <PostFeaturedImagePanel
82
+ withPanelBody={ false }
83
+ />
84
+ ) }
85
+ { ! isRevisionsMode && <PostExcerptPanel /> }
70
86
  <VStack spacing={ 1 }>
71
87
  <PostContentInformation />
72
- <PostLastEditedPanel />
88
+ { isRevisionsMode ? (
89
+ <RevisionCreatedPanel />
90
+ ) : (
91
+ <PostLastEditedPanel />
92
+ ) }
73
93
  </VStack>
74
- { ! isRemovedPostStatusPanel && (
94
+ { isRevisionsMode && revisionId && (
95
+ <>
96
+ <ExternalLink
97
+ href={ addQueryArgs( 'revision.php', {
98
+ revision: revisionId,
99
+ } ) }
100
+ >
101
+ { __(
102
+ 'Open classic revisions screen'
103
+ ) }
104
+ </ExternalLink>
105
+ <RevisionAuthorPanel />
106
+ </>
107
+ ) }
108
+ { shouldShowPostStatusPanel && (
75
109
  <VStack spacing={ 4 }>
76
110
  <VStack spacing={ 1 }>
77
111
  <PostStatusPanel />
@@ -1,3 +1,4 @@
1
+ @use "@wordpress/base-styles/colors" as *;
1
2
  @use "@wordpress/base-styles/mixins" as *;
2
3
  @use "@wordpress/base-styles/variables" as *;
3
4
 
@@ -20,4 +21,10 @@
20
21
 
21
22
  .editor-sidebar {
22
23
  @include reset;
24
+
25
+ &__revisions-block-message {
26
+ padding: $grid-unit-20;
27
+ color: $gray-700;
28
+ font-size: $default-font-size;
29
+ }
23
30
  }
@@ -18,6 +18,7 @@ import { store as interfaceStore } from '@wordpress/interface';
18
18
  * Internal dependencies
19
19
  */
20
20
  import {
21
+ ATTACHMENT_POST_TYPE,
21
22
  TEMPLATE_POST_TYPE,
22
23
  TEMPLATE_PART_POST_TYPE,
23
24
  } from '../../store/constants';
@@ -156,6 +157,7 @@ export default function StartPageOptions() {
156
157
  postId: getCurrentPostId(),
157
158
  enabled:
158
159
  choosePatternModalEnabled &&
160
+ ATTACHMENT_POST_TYPE !== currentPostType &&
159
161
  TEMPLATE_POST_TYPE !== currentPostType &&
160
162
  TEMPLATE_PART_POST_TYPE !== currentPostType,
161
163
  };
@@ -36,18 +36,31 @@ import {
36
36
  patternTitleField,
37
37
  notesField,
38
38
  } from '@wordpress/fields';
39
+ import {
40
+ altTextField,
41
+ attachedToField,
42
+ authorField as mediaAuthorField,
43
+ captionField,
44
+ dateAddedField,
45
+ descriptionField,
46
+ filenameField,
47
+ filesizeField,
48
+ mediaDimensionsField,
49
+ mimeTypeField,
50
+ } from '@wordpress/media-fields';
39
51
 
40
52
  /**
41
53
  * Internal dependencies
42
54
  */
43
55
  import { store as editorStore } from '../../store';
44
- import { DESIGN_POST_TYPES } from '../../store/constants';
56
+ import { ATTACHMENT_POST_TYPE, DESIGN_POST_TYPES } from '../../store/constants';
45
57
  import postPreviewField from '../fields/content-preview';
46
58
  import { unlock } from '../../lock-unlock';
47
59
 
48
60
  declare global {
49
61
  interface Window {
50
62
  __experimentalTemplateActivate?: boolean;
63
+ __experimentalMediaEditor?: boolean;
51
64
  }
52
65
  }
53
66
 
@@ -125,6 +138,31 @@ export function setIsReady( kind: string, name: string ) {
125
138
  };
126
139
  }
127
140
 
141
+ /*
142
+ * Media fields for the attachment post type.
143
+ *
144
+ * Field order follows a logical grouping:
145
+ * 1. Metadata fields in panels (date, author, file info)
146
+ * 2. Core editable fields (title, alt text, caption, description)
147
+ *
148
+ * Note: media_thumbnail is not included as it's shown in the canvas preview
149
+ */
150
+ const ORDERED_MEDIA_FIELDS = [
151
+ // Metadata in panels (collapsed by default).
152
+ dateAddedField,
153
+ mediaAuthorField,
154
+ filenameField,
155
+ mimeTypeField,
156
+ filesizeField,
157
+ mediaDimensionsField,
158
+ attachedToField,
159
+ // Regular layout fields (always visible).
160
+ titleField,
161
+ altTextField,
162
+ captionField,
163
+ descriptionField,
164
+ ];
165
+
128
166
  export const registerPostTypeSchema =
129
167
  ( postType: string ) =>
130
168
  async ( { registry }: { registry: any } ) => {
@@ -206,39 +244,47 @@ export const registerPostTypeSchema =
206
244
  permanentlyDeletePost,
207
245
  ].filter( Boolean );
208
246
 
209
- const fields = [
210
- postTypeConfig.supports?.thumbnail &&
211
- currentTheme?.theme_supports?.[ 'post-thumbnails' ] &&
212
- featuredImageField,
213
- postTypeConfig.supports?.author && authorField,
214
- statusField,
215
- ! DESIGN_POST_TYPES.includes( postTypeConfig.slug ) && dateField,
216
- slugField,
217
- postTypeConfig.supports?.[ 'page-attributes' ] && parentField,
218
- postTypeConfig.supports?.comments && commentStatusField,
219
- postTypeConfig.supports?.trackbacks && pingStatusField,
220
- ( postTypeConfig.supports?.comments ||
221
- postTypeConfig.supports?.trackbacks ) &&
222
- discussionField,
223
- templateField,
224
- passwordField,
225
- postTypeConfig.supports?.editor &&
226
- postTypeConfig.viewable &&
227
- postPreviewField,
228
- hasEditorNotesSupport( postTypeConfig.supports ) && notesField,
229
- ].filter( Boolean );
230
- if ( postTypeConfig.supports?.title ) {
231
- let _titleField;
232
- if ( postType === 'page' ) {
233
- _titleField = pageTitleField;
234
- } else if ( postType === 'wp_template' ) {
235
- _titleField = templateTitleField;
236
- } else if ( postType === 'wp_block' ) {
237
- _titleField = patternTitleField;
238
- } else {
239
- _titleField = titleField;
247
+ // Handle attachment post type separately with media-specific fields
248
+ let fields;
249
+
250
+ if ( postType === ATTACHMENT_POST_TYPE ) {
251
+ fields = ORDERED_MEDIA_FIELDS;
252
+ } else {
253
+ fields = [
254
+ postTypeConfig.supports?.thumbnail &&
255
+ currentTheme?.theme_supports?.[ 'post-thumbnails' ] &&
256
+ featuredImageField,
257
+ postTypeConfig.supports?.author && authorField,
258
+ statusField,
259
+ ! DESIGN_POST_TYPES.includes( postTypeConfig.slug ) &&
260
+ dateField,
261
+ slugField,
262
+ postTypeConfig.supports?.[ 'page-attributes' ] && parentField,
263
+ postTypeConfig.supports?.comments && commentStatusField,
264
+ postTypeConfig.supports?.trackbacks && pingStatusField,
265
+ ( postTypeConfig.supports?.comments ||
266
+ postTypeConfig.supports?.trackbacks ) &&
267
+ discussionField,
268
+ templateField,
269
+ passwordField,
270
+ postTypeConfig.supports?.editor &&
271
+ postTypeConfig.viewable &&
272
+ postPreviewField,
273
+ hasEditorNotesSupport( postTypeConfig.supports ) && notesField,
274
+ ].filter( Boolean );
275
+ if ( postTypeConfig.supports?.title ) {
276
+ let _titleField;
277
+ if ( postType === 'page' ) {
278
+ _titleField = pageTitleField;
279
+ } else if ( postType === 'wp_template' ) {
280
+ _titleField = templateTitleField;
281
+ } else if ( postType === 'wp_block' ) {
282
+ _titleField = patternTitleField;
283
+ } else {
284
+ _titleField = titleField;
285
+ }
286
+ fields.push( _titleField );
240
287
  }
241
- fields.push( _titleField );
242
288
  }
243
289
 
244
290
  registry.batch( () => {
@@ -19,6 +19,7 @@ export const TEMPLATE_POST_TYPE = 'wp_template';
19
19
  export const TEMPLATE_PART_POST_TYPE = 'wp_template_part';
20
20
  export const PATTERN_POST_TYPE = 'wp_block';
21
21
  export const NAVIGATION_POST_TYPE = 'wp_navigation';
22
+ export const ATTACHMENT_POST_TYPE = 'attachment';
22
23
  export const TEMPLATE_ORIGINS = {
23
24
  custom: 'custom',
24
25
  theme: 'theme',
@@ -576,3 +576,73 @@ export function setCanvasMinHeight( minHeight ) {
576
576
  minHeight,
577
577
  };
578
578
  }
579
+
580
+ /**
581
+ * Set the current revision ID for revisions preview mode.
582
+ * Pass a revision ID to enter revisions mode, or null to exit.
583
+ *
584
+ * @param {number|null} revisionId The revision ID, or null to exit revisions mode.
585
+ * @return {Object} Action object.
586
+ */
587
+ export function setCurrentRevisionId( revisionId ) {
588
+ return {
589
+ type: 'SET_CURRENT_REVISION_ID',
590
+ revisionId,
591
+ };
592
+ }
593
+
594
+ /**
595
+ * Restore a revision by replacing the current content with the revision's content
596
+ * and auto-saving.
597
+ *
598
+ * @param {number} revisionId The revision ID to restore.
599
+ */
600
+ export const restoreRevision =
601
+ ( revisionId ) =>
602
+ async ( { select, dispatch, registry } ) => {
603
+ const postType = select.getCurrentPostType();
604
+ const postId = select.getCurrentPostId();
605
+
606
+ const revision = registry
607
+ .select( coreStore )
608
+ .getRevision( 'postType', postType, postId, revisionId, {
609
+ context: 'edit',
610
+ } );
611
+
612
+ if ( ! revision ) {
613
+ return;
614
+ }
615
+
616
+ // Build the edits object with all restorable fields from the revision.
617
+ // Setting blocks to undefined clears edited blocks, forcing a re-parse of content.
618
+ const edits = {
619
+ blocks: undefined,
620
+ content: revision.content.raw,
621
+ };
622
+ if ( revision.title?.raw !== undefined ) {
623
+ edits.title = revision.title.raw;
624
+ }
625
+ if ( revision.excerpt?.raw !== undefined ) {
626
+ edits.excerpt = revision.excerpt.raw;
627
+ }
628
+ if ( revision.meta !== undefined ) {
629
+ edits.meta = revision.meta;
630
+ }
631
+
632
+ // Apply edits and save.
633
+ dispatch.editPost( edits );
634
+
635
+ // Exit revisions mode.
636
+ dispatch.setCurrentRevisionId( null );
637
+
638
+ // Save the post to persist the restored revision.
639
+ await dispatch.savePost();
640
+
641
+ // Show success notice.
642
+ registry
643
+ .dispatch( noticesStore )
644
+ .createSuccessNotice( __( 'Revision restored.' ), {
645
+ type: 'snackbar',
646
+ id: 'editor-revision-restored',
647
+ } );
648
+ };
@@ -300,3 +300,57 @@ export function getShowStylebook( state ) {
300
300
  export function getCanvasMinHeight( state ) {
301
301
  return state.canvasMinHeight;
302
302
  }
303
+
304
+ /**
305
+ * Returns whether the editor is in revisions preview mode.
306
+ *
307
+ * @param {Object} state Global application state.
308
+ * @return {boolean} Whether revisions mode is active.
309
+ */
310
+ export function isRevisionsMode( state ) {
311
+ return state.revisionId !== null;
312
+ }
313
+
314
+ /**
315
+ * Returns the current revision ID in revisions mode.
316
+ *
317
+ * @param {Object} state Global application state.
318
+ * @return {number|null} The revision ID, or null if not in revisions mode.
319
+ */
320
+ export function getCurrentRevisionId( state ) {
321
+ return state.revisionId;
322
+ }
323
+
324
+ /**
325
+ * Returns the current revision object in revisions mode.
326
+ *
327
+ * @param {Object} state Global application state.
328
+ * @return {Object|null|undefined} The revision object, null if loading, or undefined if not in revisions mode.
329
+ */
330
+ export const getCurrentRevision = createRegistrySelector(
331
+ ( select ) => ( state ) => {
332
+ const revisionId = getCurrentRevisionId( state );
333
+ if ( ! revisionId ) {
334
+ return undefined;
335
+ }
336
+
337
+ const { type: postType, id: postId } = getCurrentPost( state );
338
+ // - Use getRevisions (plural) instead of getRevision (singular) to
339
+ // avoid a race condition where both API calls complete around the
340
+ // same time and the single revision fetch overwrites the list in the
341
+ // store.
342
+ // - getRevision also needs to be updated to check if there's any
343
+ // received revisions from the collection API call to avoid unnecessary
344
+ // API calls.
345
+ const revisions = select( coreStore ).getRevisions(
346
+ 'postType',
347
+ postType,
348
+ postId,
349
+ { per_page: -1, context: 'edit' }
350
+ );
351
+ if ( ! revisions ) {
352
+ return null;
353
+ }
354
+ return revisions.find( ( r ) => r.id === revisionId ) ?? null;
355
+ }
356
+ );
@@ -433,6 +433,22 @@ export function canvasMinHeight( state = 0, action ) {
433
433
  return state;
434
434
  }
435
435
 
436
+ /**
437
+ * Reducer for the revisions preview mode.
438
+ * Stores the current revision ID, or null if not in revisions mode.
439
+ *
440
+ * @param {number|null} state Current revision ID.
441
+ * @param {Object} action Dispatched action.
442
+ * @return {number|null} Updated state.
443
+ */
444
+ export function revisionId( state = null, action ) {
445
+ switch ( action.type ) {
446
+ case 'SET_CURRENT_REVISION_ID':
447
+ return action.revisionId;
448
+ }
449
+ return state;
450
+ }
451
+
436
452
  export default combineReducers( {
437
453
  postId,
438
454
  postType,
@@ -455,5 +471,6 @@ export default combineReducers( {
455
471
  stylesPath,
456
472
  showStylebook,
457
473
  canvasMinHeight,
474
+ revisionId,
458
475
  dataviews: dataviewsReducer,
459
476
  } );
@@ -20,6 +20,7 @@ import { store as preferencesStore } from '@wordpress/preferences';
20
20
  * Internal dependencies
21
21
  */
22
22
  import {
23
+ ATTACHMENT_POST_TYPE,
23
24
  EDIT_MERGE_PROPERTIES,
24
25
  PERMALINK_POSTNAME_REGEX,
25
26
  ONE_MINUTE_IN_MS,
@@ -486,6 +487,11 @@ export function isEditedPostPublishable( state ) {
486
487
  //
487
488
  // See: <PostPublishButton /> (`isButtonEnabled` assigned by `isSaveable`).
488
489
 
490
+ // Attachments should only be publishable if they have unsaved changes.
491
+ if ( post.type === ATTACHMENT_POST_TYPE ) {
492
+ return isEditedPostDirty( state );
493
+ }
494
+
489
495
  return (
490
496
  isEditedPostDirty( state ) ||
491
497
  [ 'publish', 'private', 'future' ].indexOf( post.status ) === -1
@@ -206,6 +206,7 @@ describe( 'selectors', () => {
206
206
 
207
207
  beforeEach( () => {
208
208
  registerBlockType( 'core/block', {
209
+ apiVersion: 3,
209
210
  save: () => null,
210
211
  category: 'reusable',
211
212
  title: 'Reusable Block Stub',
@@ -215,6 +216,7 @@ describe( 'selectors', () => {
215
216
  } );
216
217
 
217
218
  registerBlockType( 'core/test-block-a', {
219
+ apiVersion: 3,
218
220
  save: ( props ) => props.attributes.text,
219
221
  category: 'design',
220
222
  title: 'Test Block A',
@@ -223,6 +225,7 @@ describe( 'selectors', () => {
223
225
  } );
224
226
 
225
227
  registerBlockType( 'core/test-block-b', {
228
+ apiVersion: 3,
226
229
  save: ( props ) => props.attributes.text,
227
230
  category: 'text',
228
231
  title: 'Test Block B',
@@ -234,6 +237,7 @@ describe( 'selectors', () => {
234
237
  } );
235
238
 
236
239
  registerBlockType( 'core/test-block-c', {
240
+ apiVersion: 3,
237
241
  save: ( props ) => props.attributes.text,
238
242
  category: 'text',
239
243
  title: 'Test Block C',
@@ -243,6 +247,7 @@ describe( 'selectors', () => {
243
247
  } );
244
248
 
245
249
  registerBlockType( 'core/freeform', {
250
+ apiVersion: 3,
246
251
  save: ( props ) => <RawHTML>{ props.attributes.content }</RawHTML>,
247
252
  category: 'text',
248
253
  title: 'Test Freeform Content Handler',
@@ -258,6 +263,7 @@ describe( 'selectors', () => {
258
263
  } );
259
264
 
260
265
  registerBlockType( 'core/test-default', {
266
+ apiVersion: 3,
261
267
  category: 'text',
262
268
  title: 'default',
263
269
  attributes: {
@@ -2332,6 +2338,7 @@ describe( 'selectors', () => {
2332
2338
  originalDefaultBlockName = getDefaultBlockName();
2333
2339
 
2334
2340
  registerBlockType( 'core/default', {
2341
+ apiVersion: 3,
2335
2342
  category: 'text',
2336
2343
  title: 'default',
2337
2344
  attributes: {
@@ -3,6 +3,11 @@
3
3
  */
4
4
  import { __ } from '@wordpress/i18n';
5
5
 
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import { ATTACHMENT_POST_TYPE } from '../constants';
10
+
6
11
  /**
7
12
  * Builds the arguments for a success notification dispatch.
8
13
  *
@@ -32,6 +37,10 @@ export function getNotificationArgumentsForSaveSuccess( data ) {
32
37
  if ( willTrash ) {
33
38
  noticeMessage = postType.labels.item_trashed;
34
39
  shouldShowLink = false;
40
+ } else if ( post.type === ATTACHMENT_POST_TYPE ) {
41
+ // Attachments should always show a simple updated message because they don't have a draft state.
42
+ noticeMessage = __( 'Media updated.' );
43
+ shouldShowLink = false;
35
44
  } else if ( ! isPublished && ! willPublish ) {
36
45
  // If saving a non-published post, don't show notice.
37
46
  noticeMessage = __( 'Draft saved.' );
package/src/style.scss CHANGED
@@ -2,6 +2,7 @@
2
2
  @use "@wordpress/interface/build-style/style.css" as *;
3
3
  @use "@wordpress/global-styles-ui/build-style/style.css" as *;
4
4
  @use "@wordpress/dataviews/build-style/style.css" as *;
5
+ @use "@wordpress/media-editor/build-style/style.css" as *;
5
6
  @use "./components/autocompleters/style.scss" as *;
6
7
  @use "./components/collab-sidebar/style.scss" as *;
7
8
  @use "./components/collapsible-block-toolbar/style.scss" as *;
@@ -35,6 +36,7 @@
35
36
  @use "./components/post-panel-row/style.scss" as *;
36
37
  @use "./components/post-panel-section/style.scss" as *;
37
38
  @use "./components/post-publish-panel/style.scss" as *;
39
+ @use "./components/post-revisions-preview/style.scss" as *;
38
40
  @use "./components/post-saved-state/style.scss" as *;
39
41
  @use "./components/post-schedule/style.scss" as *;
40
42
  @use "./components/post-status/style.scss" as *;