@wordpress/editor 13.24.1 → 13.25.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 (175) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/components/document-bar/index.js +152 -0
  3. package/build/components/document-bar/index.js.map +1 -0
  4. package/build/components/editor-canvas/edit-template-blocks-notification.js +106 -0
  5. package/build/components/editor-canvas/edit-template-blocks-notification.js.map +1 -0
  6. package/build/components/editor-canvas/index.js +292 -0
  7. package/build/components/editor-canvas/index.js.map +1 -0
  8. package/build/components/index.js +24 -8
  9. package/build/components/index.js.map +1 -1
  10. package/build/components/post-publish-button/index.js +1 -0
  11. package/build/components/post-publish-button/index.js.map +1 -1
  12. package/build/components/post-publish-panel/maybe-upload-media.js +2 -4
  13. package/build/components/post-publish-panel/maybe-upload-media.js.map +1 -1
  14. package/build/components/post-saved-state/index.js +1 -0
  15. package/build/components/post-saved-state/index.js.map +1 -1
  16. package/build/components/post-schedule/panel.js +1 -1
  17. package/build/components/post-schedule/panel.js.map +1 -1
  18. package/build/components/post-template/block-theme.js +99 -0
  19. package/build/components/post-template/block-theme.js.map +1 -0
  20. package/build/components/post-template/classic-theme.js +171 -0
  21. package/build/components/post-template/classic-theme.js.map +1 -0
  22. package/build/components/post-template/create-new-template-modal.js +98 -0
  23. package/build/components/post-template/create-new-template-modal.js.map +1 -0
  24. package/build/components/post-template/create-new-template.js +55 -0
  25. package/build/components/post-template/create-new-template.js.map +1 -0
  26. package/build/components/post-template/hooks.js +88 -0
  27. package/build/components/post-template/hooks.js.map +1 -0
  28. package/build/components/post-template/panel.js +71 -0
  29. package/build/components/post-template/panel.js.map +1 -0
  30. package/build/components/post-template/reset-default-template.js +48 -0
  31. package/build/components/post-template/reset-default-template.js.map +1 -0
  32. package/build/components/post-template/swap-template-button.js +84 -0
  33. package/build/components/post-template/swap-template-button.js.map +1 -0
  34. package/build/components/post-title/index.native.js +0 -1
  35. package/build/components/post-title/index.native.js.map +1 -1
  36. package/build/components/preview-dropdown/index.js +113 -0
  37. package/build/components/preview-dropdown/index.js.map +1 -0
  38. package/build/components/provider/index.js +24 -82
  39. package/build/components/provider/index.js.map +1 -1
  40. package/build/components/provider/index.native.js +17 -8
  41. package/build/components/provider/index.native.js.map +1 -1
  42. package/build/components/provider/navigation-block-editing-mode.js +40 -0
  43. package/build/components/provider/navigation-block-editing-mode.js.map +1 -0
  44. package/build/components/provider/use-block-editor-settings.js +9 -10
  45. package/build/components/provider/use-block-editor-settings.js.map +1 -1
  46. package/build/hooks/index.js +1 -0
  47. package/build/hooks/index.js.map +1 -1
  48. package/build/hooks/pattern-partial-syncing.js +49 -0
  49. package/build/hooks/pattern-partial-syncing.js.map +1 -0
  50. package/build/private-apis.js +4 -0
  51. package/build/private-apis.js.map +1 -1
  52. package/build/store/actions.js +59 -11
  53. package/build/store/actions.js.map +1 -1
  54. package/build/store/defaults.js +2 -1
  55. package/build/store/defaults.js.map +1 -1
  56. package/build/store/index.js +3 -0
  57. package/build/store/index.js.map +1 -1
  58. package/build/store/private-actions.js +52 -0
  59. package/build/store/private-actions.js.map +1 -0
  60. package/build/store/reducer.js +32 -27
  61. package/build/store/reducer.js.map +1 -1
  62. package/build/store/reducer.native.js +0 -1
  63. package/build/store/reducer.native.js.map +1 -1
  64. package/build/store/selectors.js +31 -10
  65. package/build/store/selectors.js.map +1 -1
  66. package/build-module/components/document-bar/index.js +144 -0
  67. package/build-module/components/document-bar/index.js.map +1 -0
  68. package/build-module/components/editor-canvas/edit-template-blocks-notification.js +100 -0
  69. package/build-module/components/editor-canvas/edit-template-blocks-notification.js.map +1 -0
  70. package/build-module/components/editor-canvas/index.js +283 -0
  71. package/build-module/components/editor-canvas/index.js.map +1 -0
  72. package/build-module/components/index.js +3 -1
  73. package/build-module/components/index.js.map +1 -1
  74. package/build-module/components/post-publish-button/index.js +1 -0
  75. package/build-module/components/post-publish-button/index.js.map +1 -1
  76. package/build-module/components/post-publish-panel/maybe-upload-media.js +2 -4
  77. package/build-module/components/post-publish-panel/maybe-upload-media.js.map +1 -1
  78. package/build-module/components/post-saved-state/index.js +1 -0
  79. package/build-module/components/post-saved-state/index.js.map +1 -1
  80. package/build-module/components/post-schedule/panel.js +1 -1
  81. package/build-module/components/post-schedule/panel.js.map +1 -1
  82. package/build-module/components/post-template/block-theme.js +91 -0
  83. package/build-module/components/post-template/block-theme.js.map +1 -0
  84. package/build-module/components/post-template/classic-theme.js +162 -0
  85. package/build-module/components/post-template/classic-theme.js.map +1 -0
  86. package/build-module/components/post-template/create-new-template-modal.js +91 -0
  87. package/build-module/components/post-template/create-new-template-modal.js.map +1 -0
  88. package/build-module/components/post-template/create-new-template.js +47 -0
  89. package/build-module/components/post-template/create-new-template.js.map +1 -0
  90. package/build-module/components/post-template/hooks.js +78 -0
  91. package/build-module/components/post-template/hooks.js.map +1 -0
  92. package/build-module/components/post-template/panel.js +63 -0
  93. package/build-module/components/post-template/panel.js.map +1 -0
  94. package/build-module/components/post-template/reset-default-template.js +41 -0
  95. package/build-module/components/post-template/reset-default-template.js.map +1 -0
  96. package/build-module/components/post-template/swap-template-button.js +77 -0
  97. package/build-module/components/post-template/swap-template-button.js.map +1 -0
  98. package/build-module/components/post-title/index.native.js +0 -1
  99. package/build-module/components/post-title/index.native.js.map +1 -1
  100. package/build-module/components/preview-dropdown/index.js +105 -0
  101. package/build-module/components/preview-dropdown/index.js.map +1 -0
  102. package/build-module/components/provider/index.js +25 -83
  103. package/build-module/components/provider/index.js.map +1 -1
  104. package/build-module/components/provider/index.native.js +18 -9
  105. package/build-module/components/provider/index.native.js.map +1 -1
  106. package/build-module/components/provider/navigation-block-editing-mode.js +34 -0
  107. package/build-module/components/provider/navigation-block-editing-mode.js.map +1 -0
  108. package/build-module/components/provider/use-block-editor-settings.js +9 -10
  109. package/build-module/components/provider/use-block-editor-settings.js.map +1 -1
  110. package/build-module/hooks/index.js +1 -0
  111. package/build-module/hooks/index.js.map +1 -1
  112. package/build-module/hooks/pattern-partial-syncing.js +46 -0
  113. package/build-module/hooks/pattern-partial-syncing.js.map +1 -0
  114. package/build-module/private-apis.js +4 -0
  115. package/build-module/private-apis.js.map +1 -1
  116. package/build-module/store/actions.js +53 -9
  117. package/build-module/store/actions.js.map +1 -1
  118. package/build-module/store/defaults.js +2 -1
  119. package/build-module/store/defaults.js.map +1 -1
  120. package/build-module/store/index.js +3 -0
  121. package/build-module/store/index.js.map +1 -1
  122. package/build-module/store/private-actions.js +44 -0
  123. package/build-module/store/private-actions.js.map +1 -0
  124. package/build-module/store/reducer.js +30 -26
  125. package/build-module/store/reducer.js.map +1 -1
  126. package/build-module/store/reducer.native.js +1 -2
  127. package/build-module/store/reducer.native.js.map +1 -1
  128. package/build-module/store/selectors.js +26 -6
  129. package/build-module/store/selectors.js.map +1 -1
  130. package/build-style/style-rtl.css +182 -0
  131. package/build-style/style.css +182 -0
  132. package/package.json +32 -31
  133. package/src/components/document-bar/index.js +182 -0
  134. package/src/components/document-bar/style.scss +130 -0
  135. package/src/components/editor-canvas/edit-template-blocks-notification.js +108 -0
  136. package/src/components/editor-canvas/index.js +381 -0
  137. package/src/components/index.js +3 -1
  138. package/src/components/post-publish-button/index.js +1 -0
  139. package/src/components/post-publish-panel/maybe-upload-media.js +3 -8
  140. package/src/components/post-saved-state/index.js +1 -0
  141. package/src/components/post-saved-state/test/__snapshots__/index.js.snap +2 -2
  142. package/src/components/post-schedule/panel.js +1 -1
  143. package/src/components/post-template/block-theme.js +109 -0
  144. package/src/components/post-template/classic-theme.js +213 -0
  145. package/src/components/post-template/create-new-template-modal.js +139 -0
  146. package/src/components/post-template/create-new-template.js +50 -0
  147. package/src/components/post-template/hooks.js +95 -0
  148. package/src/components/post-template/panel.js +67 -0
  149. package/src/components/post-template/reset-default-template.js +43 -0
  150. package/src/components/post-template/style.scss +52 -0
  151. package/src/components/post-template/swap-template-button.js +83 -0
  152. package/src/components/post-title/index.native.js +0 -1
  153. package/src/components/preview-dropdown/index.js +136 -0
  154. package/src/components/preview-dropdown/style.scss +5 -0
  155. package/src/components/provider/index.js +28 -118
  156. package/src/components/provider/index.native.js +26 -12
  157. package/src/components/provider/navigation-block-editing-mode.js +37 -0
  158. package/src/components/provider/use-block-editor-settings.js +6 -9
  159. package/src/hooks/index.js +1 -0
  160. package/src/hooks/pattern-partial-syncing.js +73 -0
  161. package/src/private-apis.js +4 -0
  162. package/src/store/actions.js +51 -9
  163. package/src/store/defaults.js +1 -0
  164. package/src/store/index.js +3 -0
  165. package/src/store/private-actions.js +61 -0
  166. package/src/store/reducer.js +32 -27
  167. package/src/store/reducer.native.js +0 -2
  168. package/src/store/selectors.js +64 -42
  169. package/src/store/test/selectors.js +88 -147
  170. package/src/style.scss +3 -0
  171. package/build/components/post-template/index.js +0 -66
  172. package/build/components/post-template/index.js.map +0 -1
  173. package/build-module/components/post-template/index.js +0 -57
  174. package/build-module/components/post-template/index.js.map +0 -1
  175. package/src/components/post-template/index.js +0 -64
@@ -0,0 +1,381 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import classnames from 'classnames';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import {
10
+ BlockList,
11
+ store as blockEditorStore,
12
+ __unstableUseTypewriter as useTypewriter,
13
+ __unstableUseTypingObserver as useTypingObserver,
14
+ useSettings,
15
+ __experimentalRecursionProvider as RecursionProvider,
16
+ privateApis as blockEditorPrivateApis,
17
+ __experimentalUseResizeCanvas as useResizeCanvas,
18
+ } from '@wordpress/block-editor';
19
+ import { useEffect, useRef, useMemo } from '@wordpress/element';
20
+ import { useSelect } from '@wordpress/data';
21
+ import { parse } from '@wordpress/blocks';
22
+ import { store as coreStore } from '@wordpress/core-data';
23
+ import { useMergeRefs } from '@wordpress/compose';
24
+
25
+ /**
26
+ * Internal dependencies
27
+ */
28
+ import PostTitle from '../post-title';
29
+ import { store as editorStore } from '../../store';
30
+ import { unlock } from '../../lock-unlock';
31
+ import EditTemplateBlocksNotification from './edit-template-blocks-notification';
32
+
33
+ const {
34
+ LayoutStyle,
35
+ useLayoutClasses,
36
+ useLayoutStyles,
37
+ ExperimentalBlockCanvas: BlockCanvas,
38
+ } = unlock( blockEditorPrivateApis );
39
+
40
+ /**
41
+ * Given an array of nested blocks, find the first Post Content
42
+ * block inside it, recursing through any nesting levels,
43
+ * and return its attributes.
44
+ *
45
+ * @param {Array} blocks A list of blocks.
46
+ *
47
+ * @return {Object | undefined} The Post Content block.
48
+ */
49
+ function getPostContentAttributes( blocks ) {
50
+ for ( let i = 0; i < blocks.length; i++ ) {
51
+ if ( blocks[ i ].name === 'core/post-content' ) {
52
+ return blocks[ i ].attributes;
53
+ }
54
+ if ( blocks[ i ].innerBlocks.length ) {
55
+ const nestedPostContent = getPostContentAttributes(
56
+ blocks[ i ].innerBlocks
57
+ );
58
+
59
+ if ( nestedPostContent ) {
60
+ return nestedPostContent;
61
+ }
62
+ }
63
+ }
64
+ }
65
+
66
+ function checkForPostContentAtRootLevel( blocks ) {
67
+ for ( let i = 0; i < blocks.length; i++ ) {
68
+ if ( blocks[ i ].name === 'core/post-content' ) {
69
+ return true;
70
+ }
71
+ }
72
+ return false;
73
+ }
74
+
75
+ function EditorCanvas( {
76
+ // Ideally as we unify post and site editors, we won't need these props.
77
+ autoFocus,
78
+ className,
79
+ renderAppender,
80
+ styles,
81
+ disableIframe = false,
82
+ iframeProps,
83
+ children,
84
+ } ) {
85
+ const {
86
+ renderingMode,
87
+ postContentAttributes,
88
+ editedPostTemplate = {},
89
+ wrapperBlockName,
90
+ wrapperUniqueId,
91
+ deviceType,
92
+ } = useSelect( ( select ) => {
93
+ const {
94
+ getCurrentPostId,
95
+ getCurrentPostType,
96
+ getCurrentTemplateId,
97
+ getEditorSettings,
98
+ getRenderingMode,
99
+ getDeviceType,
100
+ } = select( editorStore );
101
+ const { getPostType, canUser, getEditedEntityRecord } =
102
+ select( coreStore );
103
+ const postTypeSlug = getCurrentPostType();
104
+ const _renderingMode = getRenderingMode();
105
+ let _wrapperBlockName;
106
+
107
+ if ( postTypeSlug === 'wp_block' ) {
108
+ _wrapperBlockName = 'core/block';
109
+ } else if ( ! _renderingMode === 'post-only' ) {
110
+ _wrapperBlockName = 'core/post-content';
111
+ }
112
+
113
+ const editorSettings = getEditorSettings();
114
+ const supportsTemplateMode = editorSettings.supportsTemplateMode;
115
+ const postType = getPostType( postTypeSlug );
116
+ const canEditTemplate = canUser( 'create', 'templates' );
117
+ const currentTemplateId = getCurrentTemplateId();
118
+ const template = currentTemplateId
119
+ ? getEditedEntityRecord(
120
+ 'postType',
121
+ 'wp_template',
122
+ currentTemplateId
123
+ )
124
+ : undefined;
125
+
126
+ return {
127
+ renderingMode: _renderingMode,
128
+ postContentAttributes: getEditorSettings().postContentAttributes,
129
+ // Post template fetch returns a 404 on classic themes, which
130
+ // messes with e2e tests, so check it's a block theme first.
131
+ editedPostTemplate:
132
+ postType?.viewable && supportsTemplateMode && canEditTemplate
133
+ ? template
134
+ : undefined,
135
+ wrapperBlockName: _wrapperBlockName,
136
+ wrapperUniqueId: getCurrentPostId(),
137
+ deviceType: getDeviceType(),
138
+ };
139
+ }, [] );
140
+ const { isCleanNewPost } = useSelect( editorStore );
141
+ const {
142
+ hasRootPaddingAwareAlignments,
143
+ themeHasDisabledLayoutStyles,
144
+ themeSupportsLayout,
145
+ } = useSelect( ( select ) => {
146
+ const _settings = select( blockEditorStore ).getSettings();
147
+ return {
148
+ themeHasDisabledLayoutStyles: _settings.disableLayoutStyles,
149
+ themeSupportsLayout: _settings.supportsLayout,
150
+ hasRootPaddingAwareAlignments:
151
+ _settings.__experimentalFeatures?.useRootPaddingAwareAlignments,
152
+ };
153
+ }, [] );
154
+
155
+ const deviceStyles = useResizeCanvas( deviceType );
156
+ const [ globalLayoutSettings ] = useSettings( 'layout' );
157
+
158
+ // fallbackLayout is used if there is no Post Content,
159
+ // and for Post Title.
160
+ const fallbackLayout = useMemo( () => {
161
+ if ( renderingMode !== 'post-only' ) {
162
+ return { type: 'default' };
163
+ }
164
+
165
+ if ( themeSupportsLayout ) {
166
+ // We need to ensure support for wide and full alignments,
167
+ // so we add the constrained type.
168
+ return { ...globalLayoutSettings, type: 'constrained' };
169
+ }
170
+ // Set default layout for classic themes so all alignments are supported.
171
+ return { type: 'default' };
172
+ }, [ renderingMode, themeSupportsLayout, globalLayoutSettings ] );
173
+
174
+ const newestPostContentAttributes = useMemo( () => {
175
+ if (
176
+ ! editedPostTemplate?.content &&
177
+ ! editedPostTemplate?.blocks &&
178
+ postContentAttributes
179
+ ) {
180
+ return postContentAttributes;
181
+ }
182
+ // When in template editing mode, we can access the blocks directly.
183
+ if ( editedPostTemplate?.blocks ) {
184
+ return getPostContentAttributes( editedPostTemplate?.blocks );
185
+ }
186
+ // If there are no blocks, we have to parse the content string.
187
+ // Best double-check it's a string otherwise the parse function gets unhappy.
188
+ const parseableContent =
189
+ typeof editedPostTemplate?.content === 'string'
190
+ ? editedPostTemplate?.content
191
+ : '';
192
+
193
+ return getPostContentAttributes( parse( parseableContent ) ) || {};
194
+ }, [
195
+ editedPostTemplate?.content,
196
+ editedPostTemplate?.blocks,
197
+ postContentAttributes,
198
+ ] );
199
+
200
+ const hasPostContentAtRootLevel = useMemo( () => {
201
+ if ( ! editedPostTemplate?.content && ! editedPostTemplate?.blocks ) {
202
+ return false;
203
+ }
204
+ // When in template editing mode, we can access the blocks directly.
205
+ if ( editedPostTemplate?.blocks ) {
206
+ return checkForPostContentAtRootLevel( editedPostTemplate?.blocks );
207
+ }
208
+ // If there are no blocks, we have to parse the content string.
209
+ // Best double-check it's a string otherwise the parse function gets unhappy.
210
+ const parseableContent =
211
+ typeof editedPostTemplate?.content === 'string'
212
+ ? editedPostTemplate?.content
213
+ : '';
214
+
215
+ return (
216
+ checkForPostContentAtRootLevel( parse( parseableContent ) ) || false
217
+ );
218
+ }, [ editedPostTemplate?.content, editedPostTemplate?.blocks ] );
219
+
220
+ const { layout = {}, align = '' } = newestPostContentAttributes || {};
221
+
222
+ const postContentLayoutClasses = useLayoutClasses(
223
+ newestPostContentAttributes,
224
+ 'core/post-content'
225
+ );
226
+
227
+ const blockListLayoutClass = classnames(
228
+ {
229
+ 'is-layout-flow': ! themeSupportsLayout,
230
+ },
231
+ themeSupportsLayout && postContentLayoutClasses,
232
+ align && `align${ align }`
233
+ );
234
+
235
+ const postContentLayoutStyles = useLayoutStyles(
236
+ newestPostContentAttributes,
237
+ 'core/post-content',
238
+ '.block-editor-block-list__layout.is-root-container'
239
+ );
240
+
241
+ // Update type for blocks using legacy layouts.
242
+ const postContentLayout = useMemo( () => {
243
+ return layout &&
244
+ ( layout?.type === 'constrained' ||
245
+ layout?.inherit ||
246
+ layout?.contentSize ||
247
+ layout?.wideSize )
248
+ ? { ...globalLayoutSettings, ...layout, type: 'constrained' }
249
+ : { ...globalLayoutSettings, ...layout, type: 'default' };
250
+ }, [
251
+ layout?.type,
252
+ layout?.inherit,
253
+ layout?.contentSize,
254
+ layout?.wideSize,
255
+ globalLayoutSettings,
256
+ ] );
257
+
258
+ // If there is a Post Content block we use its layout for the block list;
259
+ // if not, this must be a classic theme, in which case we use the fallback layout.
260
+ const blockListLayout = postContentAttributes
261
+ ? postContentLayout
262
+ : fallbackLayout;
263
+
264
+ const postEditorLayout =
265
+ blockListLayout?.type === 'default' && ! hasPostContentAtRootLevel
266
+ ? fallbackLayout
267
+ : blockListLayout;
268
+
269
+ const observeTypingRef = useTypingObserver();
270
+ const titleRef = useRef();
271
+ useEffect( () => {
272
+ if ( ! autoFocus || ! isCleanNewPost() ) {
273
+ return;
274
+ }
275
+ titleRef?.current?.focus();
276
+ }, [ autoFocus, isCleanNewPost ] );
277
+
278
+ // Add some styles for alignwide/alignfull Post Content and its children.
279
+ const alignCSS = `.is-root-container.alignwide { max-width: var(--wp--style--global--wide-size); margin-left: auto; margin-right: auto;}
280
+ .is-root-container.alignwide:where(.is-layout-flow) > :not(.alignleft):not(.alignright) { max-width: var(--wp--style--global--wide-size);}
281
+ .is-root-container.alignfull { max-width: none; margin-left: auto; margin-right: auto;}
282
+ .is-root-container.alignfull:where(.is-layout-flow) > :not(.alignleft):not(.alignright) { max-width: none;}`;
283
+
284
+ const localRef = useRef();
285
+ const typewriterRef = useTypewriter();
286
+ const contentRef = useMergeRefs(
287
+ [
288
+ localRef,
289
+ renderingMode === 'post-only' ? typewriterRef : undefined,
290
+ ].filter( ( r ) => !! r )
291
+ );
292
+
293
+ return (
294
+ <BlockCanvas
295
+ shouldIframe={
296
+ ! disableIframe || [ 'Tablet', 'Mobile' ].includes( deviceType )
297
+ }
298
+ contentRef={ contentRef }
299
+ styles={ styles }
300
+ height="100%"
301
+ iframeProps={ {
302
+ ...iframeProps,
303
+ style: {
304
+ ...iframeProps?.style,
305
+ ...deviceStyles,
306
+ },
307
+ } }
308
+ >
309
+ { themeSupportsLayout &&
310
+ ! themeHasDisabledLayoutStyles &&
311
+ renderingMode === 'post-only' && (
312
+ <>
313
+ <LayoutStyle
314
+ selector=".editor-editor-canvas__post-title-wrapper"
315
+ layout={ fallbackLayout }
316
+ />
317
+ <LayoutStyle
318
+ selector=".block-editor-block-list__layout.is-root-container"
319
+ layout={ postEditorLayout }
320
+ />
321
+ { align && <LayoutStyle css={ alignCSS } /> }
322
+ { postContentLayoutStyles && (
323
+ <LayoutStyle
324
+ layout={ postContentLayout }
325
+ css={ postContentLayoutStyles }
326
+ />
327
+ ) }
328
+ </>
329
+ ) }
330
+ { renderingMode === 'post-only' && (
331
+ <div
332
+ className={ classnames(
333
+ 'editor-editor-canvas__post-title-wrapper',
334
+ // The following class is only here for backward comapatibility
335
+ // some themes might be using it to style the post title.
336
+ 'edit-post-visual-editor__post-title-wrapper',
337
+ {
338
+ 'has-global-padding': hasRootPaddingAwareAlignments,
339
+ }
340
+ ) }
341
+ contentEditable={ false }
342
+ ref={ observeTypingRef }
343
+ style={ {
344
+ // This is using inline styles
345
+ // so it's applied for both iframed and non iframed editors.
346
+ marginTop: '4rem',
347
+ } }
348
+ >
349
+ <PostTitle ref={ titleRef } />
350
+ </div>
351
+ ) }
352
+ <RecursionProvider
353
+ blockName={ wrapperBlockName }
354
+ uniqueId={ wrapperUniqueId }
355
+ >
356
+ <BlockList
357
+ className={ classnames(
358
+ className,
359
+ 'is-' + deviceType.toLowerCase() + '-preview',
360
+ renderingMode !== 'post-only'
361
+ ? 'wp-site-blocks'
362
+ : `${ blockListLayoutClass } wp-block-post-content` // Ensure root level blocks receive default/flow blockGap styling rules.
363
+ ) }
364
+ layout={ blockListLayout }
365
+ dropZoneElement={
366
+ // When iframed, pass in the html element of the iframe to
367
+ // ensure the drop zone extends to the edges of the iframe.
368
+ disableIframe
369
+ ? localRef.current
370
+ : localRef.current?.parentNode
371
+ }
372
+ renderAppender={ renderAppender }
373
+ />
374
+ <EditTemplateBlocksNotification contentRef={ localRef } />
375
+ </RecursionProvider>
376
+ { children }
377
+ </BlockCanvas>
378
+ );
379
+ }
380
+
381
+ export default EditorCanvas;
@@ -8,6 +8,7 @@ export * from './autocompleters';
8
8
 
9
9
  // Post Related Components.
10
10
  export { default as AutosaveMonitor } from './autosave-monitor';
11
+ export { default as DocumentBar } from './document-bar';
11
12
  export { default as DocumentOutline } from './document-outline';
12
13
  export { default as DocumentOutlineCheck } from './document-outline/check';
13
14
  export { EditorKeyboardShortcuts };
@@ -23,7 +24,8 @@ export { default as LocalAutosaveMonitor } from './local-autosave-monitor';
23
24
  export { default as PageAttributesCheck } from './page-attributes/check';
24
25
  export { default as PageAttributesOrder } from './page-attributes/order';
25
26
  export { default as PageAttributesParent } from './page-attributes/parent';
26
- export { default as PageTemplate } from './post-template';
27
+ export { default as PageTemplate } from './post-template/classic-theme';
28
+ export { default as PostTemplatePanel } from './post-template/panel';
27
29
  export { default as PostAuthor } from './post-author';
28
30
  export { default as PostAuthorCheck } from './post-author/check';
29
31
  export { default as PostAuthorPanel } from './post-author/panel';
@@ -176,6 +176,7 @@ export class PostPublishButton extends Component {
176
176
  className: 'editor-post-publish-panel__toggle',
177
177
  isBusy: isSaving && isPublished,
178
178
  variant: 'primary',
179
+ size: 'compact',
179
180
  onClick: this.createOnClick( onClickToggle ),
180
181
  };
181
182
 
@@ -10,7 +10,6 @@ import {
10
10
  } from '@wordpress/components';
11
11
  import { useSelect, useDispatch } from '@wordpress/data';
12
12
  import { __ } from '@wordpress/i18n';
13
- import { upload } from '@wordpress/icons';
14
13
  import { store as blockEditorStore } from '@wordpress/block-editor';
15
14
  import { useState } from '@wordpress/element';
16
15
  import { isBlobURL } from '@wordpress/blob';
@@ -135,7 +134,7 @@ export default function PostFormatPanel() {
135
134
  <PanelBody initialOpen={ true } title={ panelBodyTitle }>
136
135
  <p>
137
136
  { __(
138
- 'There are some external images in the post which can be uploaded to the media library. Images coming from different domains may not always display correctly, load slowly for visitors, or be removed unexpectedly.'
137
+ 'Upload external images to the Media Library. Images from different domains may load slowly, display incorrectly, or be removed unexpectedly.'
139
138
  ) }
140
139
  </p>
141
140
  <div
@@ -153,12 +152,8 @@ export default function PostFormatPanel() {
153
152
  { isUploading ? (
154
153
  <Spinner />
155
154
  ) : (
156
- <Button
157
- icon={ upload }
158
- variant="primary"
159
- onClick={ uploadImages }
160
- >
161
- { __( 'Upload all' ) }
155
+ <Button variant="primary" onClick={ uploadImages }>
156
+ { __( 'Upload' ) }
162
157
  </Button>
163
158
  ) }
164
159
  </div>
@@ -168,6 +168,7 @@ export default function PostSavedState( {
168
168
  }
169
169
  onClick={ isDisabled ? undefined : () => savePost() }
170
170
  variant="tertiary"
171
+ size="compact"
171
172
  icon={ isLargeViewport ? undefined : cloudUpload }
172
173
  // Make sure the aria-label has always a value, as the default `text` is undefined on small screens.
173
174
  aria-label={ buttonAccessibleLabel }
@@ -4,7 +4,7 @@ exports[`PostSavedState returns a disabled button if the post is not saveable 1`
4
4
  <button
5
5
  aria-disabled="true"
6
6
  aria-label="Save draft"
7
- class="components-button is-tertiary has-icon"
7
+ class="components-button is-compact is-tertiary has-icon"
8
8
  type="button"
9
9
  >
10
10
  <svg
@@ -26,7 +26,7 @@ exports[`PostSavedState should return Save button if edits to be saved 1`] = `
26
26
  <button
27
27
  aria-disabled="false"
28
28
  aria-label="Save draft"
29
- class="components-button editor-post-save-draft is-tertiary"
29
+ class="components-button editor-post-save-draft is-compact is-tertiary"
30
30
  type="button"
31
31
  >
32
32
  Save draft
@@ -49,7 +49,7 @@ export default function PostSchedulePanel() {
49
49
  label
50
50
  ) }
51
51
  label={ fullLabel }
52
- showTooltip
52
+ showTooltip={ label !== fullLabel }
53
53
  aria-expanded={ isOpen }
54
54
  >
55
55
  { label }
@@ -0,0 +1,109 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useSelect, useDispatch } from '@wordpress/data';
5
+ import { decodeEntities } from '@wordpress/html-entities';
6
+ import { DropdownMenu, MenuGroup, MenuItem } from '@wordpress/components';
7
+ import { __ } from '@wordpress/i18n';
8
+ import { useEntityRecord } from '@wordpress/core-data';
9
+ import { check } from '@wordpress/icons';
10
+ import { store as noticesStore } from '@wordpress/notices';
11
+
12
+ /**
13
+ * Internal dependencies
14
+ */
15
+ import { store as editorStore } from '../../store';
16
+ import SwapTemplateButton from './swap-template-button';
17
+ import ResetDefaultTemplate from './reset-default-template';
18
+ import { unlock } from '../../lock-unlock';
19
+ import CreateNewTemplate from './create-new-template';
20
+
21
+ const POPOVER_PROPS = {
22
+ className: 'editor-post-template__dropdown',
23
+ placement: 'bottom-start',
24
+ };
25
+
26
+ export default function BlockThemeControl( { id } ) {
27
+ const { isTemplateHidden } = useSelect( ( select ) => {
28
+ const { getRenderingMode } = unlock( select( editorStore ) );
29
+ return {
30
+ isTemplateHidden: getRenderingMode() === 'post-only',
31
+ };
32
+ }, [] );
33
+ const { editedRecord: template, hasResolved } = useEntityRecord(
34
+ 'postType',
35
+ 'wp_template',
36
+ id
37
+ );
38
+ const { getEditorSettings } = useSelect( editorStore );
39
+ const { createSuccessNotice } = useDispatch( noticesStore );
40
+ const { setRenderingMode } = useDispatch( editorStore );
41
+
42
+ if ( ! hasResolved ) {
43
+ return null;
44
+ }
45
+
46
+ return (
47
+ <DropdownMenu
48
+ popoverProps={ POPOVER_PROPS }
49
+ focusOnMount
50
+ toggleProps={ {
51
+ variant: 'tertiary',
52
+ } }
53
+ label={ __( 'Template options' ) }
54
+ text={ decodeEntities( template.title ) }
55
+ icon={ null }
56
+ >
57
+ { ( { onClose } ) => (
58
+ <>
59
+ <MenuGroup>
60
+ <MenuItem
61
+ onClick={ () => {
62
+ setRenderingMode( 'template-only' );
63
+ onClose();
64
+ createSuccessNotice(
65
+ __(
66
+ 'Editing template. Changes made here affect all posts and pages that use the template.'
67
+ ),
68
+ {
69
+ type: 'snackbar',
70
+ actions: [
71
+ {
72
+ label: __( 'Go back' ),
73
+ onClick: () =>
74
+ setRenderingMode(
75
+ getEditorSettings()
76
+ .defaultRenderingMode
77
+ ),
78
+ },
79
+ ],
80
+ }
81
+ );
82
+ } }
83
+ >
84
+ { __( 'Edit template' ) }
85
+ </MenuItem>
86
+ <SwapTemplateButton onClick={ onClose } />
87
+ <ResetDefaultTemplate onClick={ onClose } />
88
+ <CreateNewTemplate onClick={ onClose } />
89
+ </MenuGroup>
90
+ <MenuGroup>
91
+ <MenuItem
92
+ icon={ ! isTemplateHidden ? check : undefined }
93
+ isPressed={ ! isTemplateHidden }
94
+ onClick={ () => {
95
+ setRenderingMode(
96
+ isTemplateHidden
97
+ ? 'template-locked'
98
+ : 'post-only'
99
+ );
100
+ } }
101
+ >
102
+ { __( 'Template preview' ) }
103
+ </MenuItem>
104
+ </MenuGroup>
105
+ </>
106
+ ) }
107
+ </DropdownMenu>
108
+ );
109
+ }