@wordpress/editor 14.49.1 → 14.50.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 (87) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/components/header/index.cjs +1 -8
  3. package/build/components/header/index.cjs.map +2 -2
  4. package/build/components/preview-dropdown/index.cjs +38 -9
  5. package/build/components/preview-dropdown/index.cjs.map +3 -3
  6. package/build/components/provider/use-block-editor-settings.cjs +0 -6
  7. package/build/components/provider/use-block-editor-settings.cjs.map +2 -2
  8. package/build/components/resizable-editor/index.cjs +54 -9
  9. package/build/components/resizable-editor/index.cjs.map +3 -3
  10. package/build/components/visual-editor/index.cjs +15 -11
  11. package/build/components/visual-editor/index.cjs.map +3 -3
  12. package/build/store/actions.cjs +5 -3
  13. package/build/store/actions.cjs.map +2 -2
  14. package/build/store/constants.cjs +26 -0
  15. package/build/store/constants.cjs.map +2 -2
  16. package/build/store/private-actions.cjs +20 -16
  17. package/build/store/private-actions.cjs.map +3 -3
  18. package/build/store/private-selectors.cjs +5 -0
  19. package/build/store/private-selectors.cjs.map +2 -2
  20. package/build/store/reducer.cjs +6 -6
  21. package/build/store/reducer.cjs.map +2 -2
  22. package/build/store/selectors.cjs +3 -1
  23. package/build/store/selectors.cjs.map +2 -2
  24. package/build/utils/device-type.cjs +52 -0
  25. package/build/utils/device-type.cjs.map +7 -0
  26. package/build-module/components/header/index.mjs +1 -13
  27. package/build-module/components/header/index.mjs.map +2 -2
  28. package/build-module/components/preview-dropdown/index.mjs +38 -9
  29. package/build-module/components/preview-dropdown/index.mjs.map +2 -2
  30. package/build-module/components/provider/use-block-editor-settings.mjs +0 -6
  31. package/build-module/components/provider/use-block-editor-settings.mjs.map +2 -2
  32. package/build-module/components/resizable-editor/index.mjs +55 -10
  33. package/build-module/components/resizable-editor/index.mjs.map +2 -2
  34. package/build-module/components/visual-editor/index.mjs +16 -13
  35. package/build-module/components/visual-editor/index.mjs.map +2 -2
  36. package/build-module/store/actions.mjs +5 -3
  37. package/build-module/store/actions.mjs.map +2 -2
  38. package/build-module/store/constants.mjs +25 -0
  39. package/build-module/store/constants.mjs.map +2 -2
  40. package/build-module/store/private-actions.mjs +22 -15
  41. package/build-module/store/private-actions.mjs.map +2 -2
  42. package/build-module/store/private-selectors.mjs +4 -0
  43. package/build-module/store/private-selectors.mjs.map +2 -2
  44. package/build-module/store/reducer.mjs +5 -5
  45. package/build-module/store/reducer.mjs.map +2 -2
  46. package/build-module/store/selectors.mjs +3 -1
  47. package/build-module/store/selectors.mjs.map +2 -2
  48. package/build-module/utils/device-type.mjs +25 -0
  49. package/build-module/utils/device-type.mjs.map +7 -0
  50. package/build-style/style-rtl.css +19 -6
  51. package/build-style/style.css +19 -6
  52. package/build-types/components/header/index.d.ts.map +1 -1
  53. package/build-types/components/preview-dropdown/index.d.ts.map +1 -1
  54. package/build-types/components/provider/use-block-editor-settings.d.ts.map +1 -1
  55. package/build-types/components/resizable-editor/index.d.ts.map +1 -1
  56. package/build-types/components/visual-editor/index.d.ts.map +1 -1
  57. package/build-types/store/actions.d.ts.map +1 -1
  58. package/build-types/store/constants.d.ts +6 -0
  59. package/build-types/store/constants.d.ts.map +1 -1
  60. package/build-types/store/index.d.ts +2 -2
  61. package/build-types/store/private-actions.d.ts +9 -15
  62. package/build-types/store/private-actions.d.ts.map +1 -1
  63. package/build-types/store/private-selectors.d.ts +7 -0
  64. package/build-types/store/private-selectors.d.ts.map +1 -1
  65. package/build-types/store/reducer.d.ts +6 -7
  66. package/build-types/store/reducer.d.ts.map +1 -1
  67. package/build-types/store/selectors.d.ts +1 -1
  68. package/build-types/store/selectors.d.ts.map +1 -1
  69. package/build-types/utils/device-type.d.ts +23 -0
  70. package/build-types/utils/device-type.d.ts.map +1 -0
  71. package/package.json +46 -46
  72. package/src/components/header/index.js +1 -15
  73. package/src/components/preview-dropdown/index.js +42 -3
  74. package/src/components/provider/use-block-editor-settings.js +0 -6
  75. package/src/components/resizable-editor/index.js +71 -9
  76. package/src/components/resizable-editor/style.scss +7 -0
  77. package/src/components/styles-canvas/style.scss +1 -2
  78. package/src/components/visual-editor/index.js +19 -15
  79. package/src/components/visual-editor/style.scss +11 -4
  80. package/src/store/actions.js +6 -3
  81. package/src/store/constants.ts +45 -0
  82. package/src/store/private-actions.js +32 -26
  83. package/src/store/private-selectors.js +10 -0
  84. package/src/store/reducer.js +7 -9
  85. package/src/store/selectors.js +3 -1
  86. package/src/store/test/actions.js +31 -22
  87. package/src/utils/device-type.js +46 -0
@@ -14,7 +14,6 @@ import {
14
14
  useSettings,
15
15
  RecursionProvider,
16
16
  privateApis as blockEditorPrivateApis,
17
- __experimentalUseResizeCanvas as useResizeCanvas,
18
17
  } from '@wordpress/block-editor';
19
18
  import { useEffect, useRef, useMemo } from '@wordpress/element';
20
19
  import { useSelect } from '@wordpress/data';
@@ -112,6 +111,7 @@ function VisualEditor( {
112
111
  postType,
113
112
  isPreview,
114
113
  styles,
114
+ hasCanvasWidth,
115
115
  } = useSelect( ( select ) => {
116
116
  const {
117
117
  getCurrentPostId,
@@ -120,6 +120,7 @@ function VisualEditor( {
120
120
  getEditorSettings,
121
121
  getRenderingMode,
122
122
  getDeviceType,
123
+ getCanvasWidth,
123
124
  } = unlock( select( editorStore ) );
124
125
  const { getPostType, getEditedEntityRecord } = select( coreStore );
125
126
  const postTypeSlug = getCurrentPostType();
@@ -161,6 +162,7 @@ function VisualEditor( {
161
162
  postType: postTypeSlug,
162
163
  isPreview: editorSettings.isPreviewMode,
163
164
  styles: editorSettings.styles,
165
+ hasCanvasWidth: getCanvasWidth() !== undefined,
164
166
  };
165
167
  }, [] );
166
168
  const { isCleanNewPost } = useSelect( editorStore );
@@ -185,7 +187,6 @@ function VisualEditor( {
185
187
  }, [] );
186
188
 
187
189
  const localRef = useRef();
188
- const deviceStyles = useResizeCanvas( deviceType );
189
190
  const [ globalLayoutSettings ] = useSettings( 'layout' );
190
191
 
191
192
  // fallbackLayout is used if there is no Post Content,
@@ -319,17 +320,19 @@ function VisualEditor( {
319
320
  .is-root-container.alignfull:where(.is-layout-flow) > :not(.alignleft):not(.alignright) { max-width: none;}`;
320
321
 
321
322
  const enableResizing =
322
- [
323
+ ( [
323
324
  NAVIGATION_POST_TYPE,
324
325
  TEMPLATE_PART_POST_TYPE,
325
326
  PATTERN_POST_TYPE,
326
327
  ].includes( postType ) &&
327
- // Disable in previews / view mode.
328
- ! isPreview &&
329
- // Disable resizing in mobile viewport.
330
- ! isMobileViewport &&
331
- // Disable resizing in zoomed-out mode.
332
- ! isZoomedOut;
328
+ // Disable in previews / view mode.
329
+ ! isPreview &&
330
+ // Disable resizing in mobile viewport.
331
+ ! isMobileViewport &&
332
+ // Disable resizing in zoomed-out mode.
333
+ ! isZoomedOut ) ||
334
+ // When the canvas has an explicit width, always allow resizing.
335
+ hasCanvasWidth;
333
336
 
334
337
  const isNavigationPreview = postType === NAVIGATION_POST_TYPE && isPreview;
335
338
 
@@ -394,8 +397,12 @@ function VisualEditor( {
394
397
  'edit-post-visual-editor',
395
398
  className,
396
399
  {
397
- 'has-padding': isFocusedEntity || enableResizing,
398
- 'is-resizable': enableResizing,
400
+ // Vertical padding frames a width-constrained canvas
401
+ // (device preview or after a resize) as a centered preview.
402
+ 'has-vertical-padding': isFocusedEntity || hasCanvasWidth,
403
+ // Horizontal padding leaves room for the resize handles
404
+ // that appear on the left/right of a resizable canvas.
405
+ 'has-horizontal-padding': isFocusedEntity || enableResizing,
399
406
  'is-iframed': ! disableIframe,
400
407
  }
401
408
  ) }
@@ -409,10 +416,7 @@ function VisualEditor( {
409
416
  height="100%"
410
417
  iframeProps={ {
411
418
  ...iframeProps,
412
- style: {
413
- ...iframeProps?.style,
414
- ...deviceStyles,
415
- },
419
+ style: iframeProps?.style,
416
420
  } }
417
421
  >
418
422
  { themeSupportsLayout &&
@@ -3,6 +3,7 @@
3
3
  .editor-visual-editor {
4
4
  position: relative;
5
5
  display: flex;
6
+ max-height: 100%;
6
7
 
7
8
  // This duplicates the iframe background but it's necessary in some situations
8
9
  // when the iframe doesn't cover the whole canvas
@@ -19,12 +20,18 @@
19
20
  // Centralize the editor horizontally (flex-direction is column).
20
21
  align-items: center;
21
22
 
22
- &.is-resizable {
23
- max-height: 100%;
23
+ @media (prefers-reduced-motion: no-preference) {
24
+ transition: padding 0.2s ease-out;
24
25
  }
25
26
 
26
- &.has-padding {
27
- padding: $grid-unit-30 $grid-unit-30 0;
27
+ &.has-vertical-padding {
28
+ padding-top: $grid-unit-30;
29
+ padding-bottom: $grid-unit-30;
30
+ }
31
+
32
+ &.has-horizontal-padding {
33
+ padding-left: $grid-unit-30;
34
+ padding-right: $grid-unit-30;
28
35
  }
29
36
 
30
37
  // In the iframed canvas this keeps extra scrollbars from appearing (when block toolbars overflow). In the
@@ -30,6 +30,9 @@ import {
30
30
  getNotificationArgumentsForTrashFail,
31
31
  } from './utils/notice-builder';
32
32
  import { unlock } from '../lock-unlock';
33
+ import { setCanvasWidth } from './private-actions';
34
+ import { getCanvasWidthByDeviceType } from '../utils/device-type';
35
+
33
36
  /**
34
37
  * Returns an action generator used in signalling that editor has initialized with
35
38
  * the specified post object and editor settings.
@@ -757,9 +760,9 @@ export const setRenderingMode =
757
760
  * @return {Object} Action object.
758
761
  */
759
762
  export function setDeviceType( deviceType ) {
760
- return {
761
- type: 'SET_DEVICE_TYPE',
762
- deviceType,
763
+ return ( { dispatch } ) => {
764
+ const width = getCanvasWidthByDeviceType( deviceType );
765
+ dispatch( setCanvasWidth( width ) );
763
766
  };
764
767
  }
765
768
 
@@ -1,3 +1,9 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __ } from '@wordpress/i18n';
5
+ import { desktop, tablet, mobile } from '@wordpress/icons';
6
+
1
7
  /**
2
8
  * Set of post properties for which edits should assume a merging behavior,
3
9
  * assuming an object value.
@@ -37,3 +43,42 @@ export const DESIGN_POST_TYPES = [
37
43
  PATTERN_POST_TYPE,
38
44
  NAVIGATION_POST_TYPE,
39
45
  ];
46
+
47
+ /*
48
+ * Contains the device types and their corresponding canvas width.
49
+ * Matches the breakpoints in packages/base-styles/_breakpoints.scss,
50
+ * and breakpoints in packages/compose/src/hooks/use-viewport-match/index.js.
51
+ * minus 1 to trigger the media query for device preview.
52
+ *
53
+ * These breakpoints are currently hardcoded, but are expected to become
54
+ * customizable via the `settings.viewport` values in theme.json in the future.
55
+ * See https://github.com/WordPress/gutenberg/pull/79104.
56
+ */
57
+ export const DEVICE_TYPES: Record<
58
+ string,
59
+ {
60
+ value: string;
61
+ label: string;
62
+ icon: React.JSX.Element;
63
+ canvasWidth: number | undefined;
64
+ }
65
+ > = {
66
+ Desktop: {
67
+ value: 'Desktop',
68
+ label: __( 'Desktop' ),
69
+ icon: desktop,
70
+ canvasWidth: undefined,
71
+ },
72
+ Tablet: {
73
+ value: 'Tablet',
74
+ label: __( 'Tablet' ),
75
+ icon: tablet,
76
+ canvasWidth: 782 - 1, // preview for useViewportMatch( 'medium', '<' )
77
+ },
78
+ Mobile: {
79
+ value: 'Mobile',
80
+ label: __( 'Mobile' ),
81
+ icon: mobile,
82
+ canvasWidth: 480 - 1, // preview for useViewportMatch( 'mobile', '<' )
83
+ },
84
+ };
@@ -17,35 +17,13 @@ import { dateI18n, getSettings as getDateSettings } from '@wordpress/date';
17
17
  */
18
18
  import isTemplateRevertable from './utils/is-template-revertable';
19
19
  import { buildRevisionsPageQuery } from './private-selectors';
20
+ import {
21
+ getDeviceTypeByCanvasWidth,
22
+ VIEWPORT_STATE_BY_DEVICE_TYPE,
23
+ } from '../utils/device-type';
20
24
  import { unlock } from '../lock-unlock';
21
25
  export * from '../dataviews/store/private-actions';
22
26
 
23
- const DEVICE_TYPE_BY_VIEWPORT_STATE = {
24
- '@mobile': 'Mobile',
25
- '@tablet': 'Tablet',
26
- };
27
-
28
- /**
29
- * Updates the editor preview device in response to a block-editor viewport
30
- * state signal.
31
- *
32
- * @param {Object} options Viewport state change options.
33
- * @param {string} options.viewport Selected viewport state.
34
- * @param {boolean} options.showStateOnCanvas Whether canvas preview is enabled.
35
- */
36
- export const updateDeviceTypeForViewportState =
37
- ( { viewport = 'default', showStateOnCanvas = true } = {} ) =>
38
- ( { dispatch, registry } ) => {
39
- if ( ! showStateOnCanvas ) {
40
- return;
41
- }
42
-
43
- dispatch.setDeviceType(
44
- DEVICE_TYPE_BY_VIEWPORT_STATE[ viewport ] ?? 'Desktop'
45
- );
46
- unlock( registry.dispatch( blockEditorStore ) ).resetZoomLevel();
47
- };
48
-
49
27
  /**
50
28
  * Returns an action object used to set which template is currently being used/edited.
51
29
  *
@@ -603,6 +581,34 @@ export function resetStylesNavigation() {
603
581
  };
604
582
  }
605
583
 
584
+ /**
585
+ * Set the width of the canvas.
586
+ *
587
+ * @param {number} width The width of the canvas in pixels.
588
+ */
589
+ export function setCanvasWidth( width ) {
590
+ return ( { dispatch, registry } ) => {
591
+ dispatch( {
592
+ type: 'SET_CANVAS_WIDTH',
593
+ width,
594
+ } );
595
+
596
+ // While Responsive editing is enabled, the canvas width also drives the
597
+ // viewport style state, whether changed via the device preview or by
598
+ // manually resizing the canvas.
599
+ if (
600
+ unlock( registry.select( blockEditorStore ) ).isResponsiveEditing()
601
+ ) {
602
+ const deviceType = getDeviceTypeByCanvasWidth( width );
603
+ unlock(
604
+ registry.dispatch( blockEditorStore )
605
+ ).setStyleStateViewport(
606
+ VIEWPORT_STATE_BY_DEVICE_TYPE[ deviceType ] ?? 'default'
607
+ );
608
+ }
609
+ };
610
+ }
611
+
606
612
  /**
607
613
  * Set the current revision ID for revisions preview mode.
608
614
  * Pass a revision ID to enter revisions mode, or null to exit.
@@ -353,6 +353,16 @@ export function getShowStylebook( state ) {
353
353
  return state.showStylebook ?? false;
354
354
  }
355
355
 
356
+ /**
357
+ * Get the canvas width.
358
+ *
359
+ * @param {Object} state Global application state.
360
+ * @return {number} The canvas width in pixels.
361
+ */
362
+ export function getCanvasWidth( state ) {
363
+ return state.canvasWidth;
364
+ }
365
+
356
366
  /**
357
367
  * Returns the current revisions page number.
358
368
  *
@@ -277,19 +277,17 @@ export function renderingMode( state = 'post-only', action ) {
277
277
  }
278
278
 
279
279
  /**
280
- * Reducer returning the editing canvas device type.
280
+ * Reducer for the canvas width.
281
281
  *
282
- * @param {Object} state Current state.
282
+ * @param {number} state Current state.
283
283
  * @param {Object} action Dispatched action.
284
- *
285
- * @return {Object} Updated state.
284
+ * @return {number} Updated state.
286
285
  */
287
- export function deviceType( state = 'Desktop', action ) {
286
+ export function canvasWidth( state = undefined, action ) {
288
287
  switch ( action.type ) {
289
- case 'SET_DEVICE_TYPE':
290
- return action.deviceType;
288
+ case 'SET_CANVAS_WIDTH':
289
+ return action.width;
291
290
  }
292
-
293
291
  return state;
294
292
  }
295
293
 
@@ -500,7 +498,7 @@ export default combineReducers( {
500
498
  editorSettings,
501
499
  postAutosavingLock,
502
500
  renderingMode,
503
- deviceType,
501
+ canvasWidth,
504
502
  removedPanels,
505
503
  blockInserterPanel,
506
504
  inserterSidebarToggleRef,
@@ -29,6 +29,7 @@ import { getPostRawValue } from './reducer';
29
29
  import { getTemplatePartIcon } from '../utils/get-template-part-icon';
30
30
  import { unlock } from '../lock-unlock';
31
31
  import { getTemplateInfo } from '../utils/get-template-info';
32
+ import { getDeviceTypeByCanvasWidth } from '../utils/device-type';
32
33
 
33
34
  /**
34
35
  * Shared reference to an empty object for cases where it is important to avoid
@@ -1352,7 +1353,8 @@ export const getDeviceType = createRegistrySelector(
1352
1353
  if ( isZoomOut ) {
1353
1354
  return 'Desktop';
1354
1355
  }
1355
- return state.deviceType;
1356
+ const canvasWidth = state.canvasWidth;
1357
+ return getDeviceTypeByCanvasWidth( canvasWidth );
1356
1358
  }
1357
1359
  );
1358
1360
 
@@ -12,8 +12,8 @@ import { store as preferencesStore } from '@wordpress/preferences';
12
12
  * Internal dependencies
13
13
  */
14
14
 
15
- import * as actions from '../actions';
16
15
  import { store as editorStore } from '..';
16
+ import * as actions from '../actions';
17
17
  import { unlock } from '../../lock-unlock';
18
18
 
19
19
  const postId = 44;
@@ -64,36 +64,45 @@ const getMethod = ( options ) =>
64
64
  options.headers?.[ 'X-HTTP-Method-Override' ] || options.method || 'GET';
65
65
 
66
66
  describe( 'Post actions', () => {
67
- describe( 'updateDeviceTypeForViewportState', () => {
68
- it( 'updates the editor device type for a viewport state', () => {
67
+ describe( 'setCanvasWidth', () => {
68
+ it( 'syncs the viewport style state while Responsive editing is enabled', () => {
69
69
  const registry = createRegistryWithStores();
70
+ const getViewport = () =>
71
+ unlock(
72
+ registry.select( blockEditorStore )
73
+ ).getStyleStateViewport();
74
+ const setCanvasWidth = ( width ) =>
75
+ unlock( registry.dispatch( editorStore ) ).setCanvasWidth(
76
+ width
77
+ );
70
78
 
71
79
  unlock(
72
- registry.dispatch( editorStore )
73
- ).updateDeviceTypeForViewportState( {
74
- viewport: '@mobile',
75
- showStateOnCanvas: true,
76
- } );
80
+ registry.dispatch( blockEditorStore )
81
+ ).setResponsiveEditing( true );
77
82
 
78
- expect( registry.select( editorStore ).getDeviceType() ).toBe(
79
- 'Mobile'
80
- );
83
+ // A tablet-sized canvas selects the tablet viewport.
84
+ setCanvasWidth( 600 );
85
+ expect( getViewport() ).toBe( '@tablet' );
86
+
87
+ // A mobile-sized canvas selects the mobile viewport.
88
+ setCanvasWidth( 400 );
89
+ expect( getViewport() ).toBe( '@mobile' );
90
+
91
+ // A full-width (desktop) canvas resets to the default viewport.
92
+ setCanvasWidth( undefined );
93
+ expect( getViewport() ).toBe( 'default' );
81
94
  } );
82
95
 
83
- it( 'keeps the editor device type when canvas preview is disabled', () => {
96
+ it( 'leaves the viewport style state untouched while Responsive editing is disabled', () => {
84
97
  const registry = createRegistryWithStores();
85
- registry.dispatch( editorStore ).setDeviceType( 'Tablet' );
98
+ const getViewport = () =>
99
+ unlock(
100
+ registry.select( blockEditorStore )
101
+ ).getStyleStateViewport();
86
102
 
87
- unlock(
88
- registry.dispatch( editorStore )
89
- ).updateDeviceTypeForViewportState( {
90
- viewport: '@mobile',
91
- showStateOnCanvas: false,
92
- } );
103
+ unlock( registry.dispatch( editorStore ) ).setCanvasWidth( 400 );
93
104
 
94
- expect( registry.select( editorStore ).getDeviceType() ).toBe(
95
- 'Tablet'
96
- );
105
+ expect( getViewport() ).toBe( 'default' );
97
106
  } );
98
107
  } );
99
108
 
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import { DEVICE_TYPES } from '../store/constants';
5
+
6
+ /**
7
+ * Maps a device preview type to its corresponding viewport style state. Used
8
+ * when Responsive editing is enabled so the device preview drives which
9
+ * viewport block style edits are applied to.
10
+ *
11
+ * @type {Object}
12
+ */
13
+ export const VIEWPORT_STATE_BY_DEVICE_TYPE = {
14
+ Desktop: 'default',
15
+ Tablet: '@tablet',
16
+ Mobile: '@mobile',
17
+ };
18
+
19
+ /**
20
+ * Gets the most appropriate device type based on the canvas width.
21
+ *
22
+ * @param {number} canvasWidth The canvas width in pixels.
23
+ * @return {string} The device type.
24
+ */
25
+ export function getDeviceTypeByCanvasWidth( canvasWidth ) {
26
+ // Mobile
27
+ if ( canvasWidth && canvasWidth <= DEVICE_TYPES.Mobile.canvasWidth ) {
28
+ return DEVICE_TYPES.Mobile.value;
29
+ }
30
+ // Tablet
31
+ if ( canvasWidth && canvasWidth <= DEVICE_TYPES.Tablet.canvasWidth ) {
32
+ return DEVICE_TYPES.Tablet.value;
33
+ }
34
+ // Desktop
35
+ return DEVICE_TYPES.Desktop.value;
36
+ }
37
+
38
+ /**
39
+ * Get the canvas width by device type.
40
+ *
41
+ * @param {string} deviceType The device type.
42
+ * @return {number|undefined} The canvas width in pixels.
43
+ */
44
+ export function getCanvasWidthByDeviceType( deviceType ) {
45
+ return DEVICE_TYPES[ deviceType ]?.canvasWidth;
46
+ }