@wordpress/edit-post 6.14.2 → 6.15.1-next.4d3b314fd5.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.
@@ -1,7 +1,13 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { shallow } from 'enzyme';
4
+ import { render, screen } from '@testing-library/react';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import { EditorKeyboardShortcutsRegister } from '@wordpress/editor';
10
+ import { ShortcutProvider } from '@wordpress/keyboard-shortcuts';
5
11
 
6
12
  /**
7
13
  * Internal dependencies
@@ -12,24 +18,35 @@ const noop = () => {};
12
18
 
13
19
  describe( 'KeyboardShortcutHelpModal', () => {
14
20
  it( 'should match snapshot when the modal is active', () => {
15
- const wrapper = shallow(
16
- <KeyboardShortcutHelpModal
17
- isModalActive={ true }
18
- toggleModal={ noop }
19
- />
21
+ render(
22
+ <ShortcutProvider>
23
+ <EditorKeyboardShortcutsRegister />
24
+ <KeyboardShortcutHelpModal isModalActive toggleModal={ noop } />
25
+ </ShortcutProvider>
20
26
  );
21
27
 
22
- expect( wrapper ).toMatchSnapshot();
28
+ expect(
29
+ screen.getByRole( 'dialog', {
30
+ name: 'Keyboard shortcuts',
31
+ } )
32
+ ).toMatchSnapshot();
23
33
  } );
24
34
 
25
- it( 'should match snapshot when the modal is not active', () => {
26
- const wrapper = shallow(
27
- <KeyboardShortcutHelpModal
28
- isModalActive={ false }
29
- toggleModal={ noop }
30
- />
35
+ it( 'should not render the modal when inactive', () => {
36
+ render(
37
+ <ShortcutProvider>
38
+ <EditorKeyboardShortcutsRegister />
39
+ <KeyboardShortcutHelpModal
40
+ isModalActive={ false }
41
+ toggleModal={ noop }
42
+ />
43
+ </ShortcutProvider>
31
44
  );
32
45
 
33
- expect( wrapper ).toMatchSnapshot();
46
+ expect(
47
+ screen.queryByRole( 'dialog', {
48
+ name: 'Keyboard shortcuts',
49
+ } )
50
+ ).not.toBeInTheDocument();
34
51
  } );
35
52
  } );
@@ -28,6 +28,8 @@ import {
28
28
  __unstableUseMouseMoveTypingReset as useMouseMoveTypingReset,
29
29
  __unstableIframe as Iframe,
30
30
  __experimentalRecursionProvider as RecursionProvider,
31
+ __experimentaluseLayoutClasses as useLayoutClasses,
32
+ __experimentaluseLayoutStyles as useLayoutStyles,
31
33
  } from '@wordpress/block-editor';
32
34
  import { useEffect, useRef, useMemo } from '@wordpress/element';
33
35
  import { Button, __unstableMotion as motion } from '@wordpress/components';
@@ -35,6 +37,7 @@ import { useSelect, useDispatch } from '@wordpress/data';
35
37
  import { useMergeRefs } from '@wordpress/compose';
36
38
  import { arrowLeft } from '@wordpress/icons';
37
39
  import { __ } from '@wordpress/i18n';
40
+ import { parse } from '@wordpress/blocks';
38
41
 
39
42
  /**
40
43
  * Internal dependencies
@@ -82,11 +85,37 @@ function MaybeIframe( {
82
85
  );
83
86
  }
84
87
 
88
+ /**
89
+ * Given an array of nested blocks, find the first Post Content
90
+ * block inside it, recursing through any nesting levels.
91
+ *
92
+ * @param {Array} blocks A list of blocks.
93
+ *
94
+ * @return {Object} The Post Content block.
95
+ */
96
+ function findPostContent( blocks ) {
97
+ for ( let i = 0; i < blocks.length; i++ ) {
98
+ if ( blocks[ i ].name === 'core/post-content' ) {
99
+ return blocks[ i ];
100
+ }
101
+ if ( blocks[ i ].innerBlocks.length ) {
102
+ const nestedPostContent = findPostContent(
103
+ blocks[ i ].innerBlocks
104
+ );
105
+
106
+ if ( nestedPostContent ) {
107
+ return nestedPostContent;
108
+ }
109
+ }
110
+ }
111
+ }
112
+
85
113
  export default function VisualEditor( { styles } ) {
86
114
  const {
87
115
  deviceType,
88
116
  isWelcomeGuideVisible,
89
117
  isTemplateMode,
118
+ editedPostTemplate = {},
90
119
  wrapperBlockName,
91
120
  wrapperUniqueId,
92
121
  } = useSelect( ( select ) => {
@@ -94,8 +123,10 @@ export default function VisualEditor( { styles } ) {
94
123
  isFeatureActive,
95
124
  isEditingTemplate,
96
125
  __experimentalGetPreviewDeviceType,
126
+ getEditedPostTemplate,
97
127
  } = select( editPostStore );
98
- const { getCurrentPostId, getCurrentPostType } = select( editorStore );
128
+ const { getCurrentPostId, getCurrentPostType, getEditorSettings } =
129
+ select( editorStore );
99
130
  const _isTemplateMode = isEditingTemplate();
100
131
  let _wrapperBlockName;
101
132
 
@@ -105,10 +136,17 @@ export default function VisualEditor( { styles } ) {
105
136
  _wrapperBlockName = 'core/post-content';
106
137
  }
107
138
 
139
+ const supportsTemplateMode = getEditorSettings().supportsTemplateMode;
140
+
108
141
  return {
109
142
  deviceType: __experimentalGetPreviewDeviceType(),
110
143
  isWelcomeGuideVisible: isFeatureActive( 'welcomeGuide' ),
111
144
  isTemplateMode: _isTemplateMode,
145
+ // Post template fetch returns a 404 on classic themes, which
146
+ // messes with e2e tests, so we check it's a block theme first.
147
+ editedPostTemplate: supportsTemplateMode
148
+ ? getEditedPostTemplate()
149
+ : {},
112
150
  wrapperBlockName: _wrapperBlockName,
113
151
  wrapperUniqueId: getCurrentPostId(),
114
152
  };
@@ -118,15 +156,20 @@ export default function VisualEditor( { styles } ) {
118
156
  ( select ) => select( editPostStore ).hasMetaBoxes(),
119
157
  []
120
158
  );
121
- const { themeHasDisabledLayoutStyles, themeSupportsLayout, assets } =
122
- useSelect( ( select ) => {
123
- const _settings = select( blockEditorStore ).getSettings();
124
- return {
125
- themeHasDisabledLayoutStyles: _settings.disableLayoutStyles,
126
- themeSupportsLayout: _settings.supportsLayout,
127
- assets: _settings.__unstableResolvedAssets,
128
- };
129
- }, [] );
159
+ const {
160
+ themeHasDisabledLayoutStyles,
161
+ themeSupportsLayout,
162
+ assets,
163
+ isFocusMode,
164
+ } = useSelect( ( select ) => {
165
+ const _settings = select( blockEditorStore ).getSettings();
166
+ return {
167
+ themeHasDisabledLayoutStyles: _settings.disableLayoutStyles,
168
+ themeSupportsLayout: _settings.supportsLayout,
169
+ assets: _settings.__unstableResolvedAssets,
170
+ isFocusMode: _settings.focusMode,
171
+ };
172
+ }, [] );
130
173
  const { clearSelectedBlock } = useDispatch( blockEditorStore );
131
174
  const { setIsEditingTemplate } = useDispatch( editPostStore );
132
175
  const desktopCanvasStyles = {
@@ -146,7 +189,7 @@ export default function VisualEditor( { styles } ) {
146
189
  borderBottom: 0,
147
190
  };
148
191
  const resizedCanvasStyles = useResizeCanvas( deviceType, isTemplateMode );
149
- const defaultLayout = useSetting( 'layout' );
192
+ const globalLayoutSettings = useSetting( 'layout' );
150
193
  const previewMode = 'is-' + deviceType.toLowerCase() + '-preview';
151
194
 
152
195
  let animatedStyles = isTemplateMode
@@ -175,7 +218,9 @@ export default function VisualEditor( { styles } ) {
175
218
 
176
219
  const blockSelectionClearerRef = useBlockSelectionClearer();
177
220
 
178
- const layout = useMemo( () => {
221
+ // fallbackLayout is used if there is no Post Content,
222
+ // and for Post Title.
223
+ const fallbackLayout = useMemo( () => {
179
224
  if ( isTemplateMode ) {
180
225
  return { type: 'default' };
181
226
  }
@@ -183,15 +228,58 @@ export default function VisualEditor( { styles } ) {
183
228
  if ( themeSupportsLayout ) {
184
229
  // We need to ensure support for wide and full alignments,
185
230
  // so we add the constrained type.
186
- return { ...defaultLayout, type: 'constrained' };
231
+ return { ...globalLayoutSettings, type: 'constrained' };
187
232
  }
188
233
  // Set default layout for classic themes so all alignments are supported.
189
234
  return { type: 'default' };
190
- }, [ isTemplateMode, themeSupportsLayout, defaultLayout ] );
235
+ }, [ isTemplateMode, themeSupportsLayout, globalLayoutSettings ] );
236
+
237
+ const postContentBlock = useMemo( () => {
238
+ // When in template editing mode, we can access the blocks directly.
239
+ if ( editedPostTemplate?.blocks ) {
240
+ return findPostContent( editedPostTemplate?.blocks );
241
+ }
242
+ // If there are no blocks, we have to parse the content string.
243
+ // Best double-check it's a string otherwise the parse function gets unhappy.
244
+ const parseableContent =
245
+ typeof editedPostTemplate?.content === 'string'
246
+ ? editedPostTemplate?.content
247
+ : '';
248
+
249
+ return findPostContent( parse( parseableContent ) ) || {};
250
+ }, [ editedPostTemplate?.content, editedPostTemplate?.blocks ] );
191
251
 
192
- const blockListLayoutClass = themeSupportsLayout
193
- ? 'is-layout-constrained'
194
- : 'is-layout-flow';
252
+ const postContentLayoutClasses = useLayoutClasses( postContentBlock );
253
+
254
+ const blockListLayoutClass = classnames(
255
+ {
256
+ 'is-layout-flow': ! themeSupportsLayout,
257
+ },
258
+ themeSupportsLayout && postContentLayoutClasses
259
+ );
260
+
261
+ const postContentLayoutStyles = useLayoutStyles(
262
+ postContentBlock,
263
+ '.block-editor-block-list__layout.is-root-container'
264
+ );
265
+
266
+ const layout = postContentBlock?.attributes?.layout || {};
267
+
268
+ // Update type for blocks using legacy layouts.
269
+ const postContentLayout =
270
+ layout &&
271
+ ( layout?.type === 'constrained' ||
272
+ layout?.inherit ||
273
+ layout?.contentSize ||
274
+ layout?.wideSize )
275
+ ? { ...globalLayoutSettings, ...layout, type: 'constrained' }
276
+ : { ...globalLayoutSettings, ...layout, type: 'default' };
277
+
278
+ // If there is a Post Content block we use its layout for the block list;
279
+ // if not, this must be a classic theme, in which case we use the fallback layout.
280
+ const blockListLayout = postContentBlock
281
+ ? postContentLayout
282
+ : fallbackLayout;
195
283
 
196
284
  const titleRef = useRef();
197
285
  useEffect( () => {
@@ -247,17 +335,33 @@ export default function VisualEditor( { styles } ) {
247
335
  { themeSupportsLayout &&
248
336
  ! themeHasDisabledLayoutStyles &&
249
337
  ! isTemplateMode && (
250
- <LayoutStyle
251
- selector=".edit-post-visual-editor__post-title-wrapper, .block-editor-block-list__layout.is-root-container"
252
- layout={ layout }
253
- layoutDefinitions={
254
- defaultLayout?.definitions
255
- }
256
- />
338
+ <>
339
+ <LayoutStyle
340
+ selector=".edit-post-visual-editor__post-title-wrapper, .block-editor-block-list__layout.is-root-container"
341
+ layout={ fallbackLayout }
342
+ layoutDefinitions={
343
+ globalLayoutSettings?.definitions
344
+ }
345
+ />
346
+ { postContentLayoutStyles && (
347
+ <LayoutStyle
348
+ layout={ postContentLayout }
349
+ css={ postContentLayoutStyles }
350
+ layoutDefinitions={
351
+ globalLayoutSettings?.definitions
352
+ }
353
+ />
354
+ ) }
355
+ </>
257
356
  ) }
258
357
  { ! isTemplateMode && (
259
358
  <div
260
- className="edit-post-visual-editor__post-title-wrapper"
359
+ className={ classnames(
360
+ 'edit-post-visual-editor__post-title-wrapper',
361
+ {
362
+ 'is-focus-mode': isFocusMode,
363
+ }
364
+ ) }
261
365
  contentEditable={ false }
262
366
  >
263
367
  <PostTitle ref={ titleRef } />
@@ -273,7 +377,7 @@ export default function VisualEditor( { styles } ) {
273
377
  ? 'wp-site-blocks'
274
378
  : `${ blockListLayoutClass } wp-block-post-content` // Ensure root level blocks receive default/flow blockGap styling rules.
275
379
  }
276
- __experimentalLayout={ layout }
380
+ __experimentalLayout={ blockListLayout }
277
381
  />
278
382
  </RecursionProvider>
279
383
  </MaybeIframe>