@wordpress/block-editor 15.22.1 → 15.23.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 (45) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/components/block-inspector/index.cjs +18 -35
  3. package/build/components/block-inspector/index.cjs.map +2 -2
  4. package/build/components/use-resize-canvas/index.cjs +16 -53
  5. package/build/components/use-resize-canvas/index.cjs.map +3 -3
  6. package/build/hooks/states.cjs +13 -21
  7. package/build/hooks/states.cjs.map +2 -2
  8. package/build/private-apis.cjs +0 -1
  9. package/build/private-apis.cjs.map +2 -2
  10. package/build/store/private-actions.cjs +16 -0
  11. package/build/store/private-actions.cjs.map +2 -2
  12. package/build/store/private-keys.cjs +0 -3
  13. package/build/store/private-keys.cjs.map +2 -2
  14. package/build/store/private-selectors.cjs +24 -6
  15. package/build/store/private-selectors.cjs.map +2 -2
  16. package/build/store/reducer.cjs +19 -3
  17. package/build/store/reducer.cjs.map +2 -2
  18. package/build-module/components/block-inspector/index.mjs +18 -35
  19. package/build-module/components/block-inspector/index.mjs.map +2 -2
  20. package/build-module/components/use-resize-canvas/index.mjs +6 -53
  21. package/build-module/components/use-resize-canvas/index.mjs.map +2 -2
  22. package/build-module/hooks/states.mjs +13 -21
  23. package/build-module/hooks/states.mjs.map +2 -2
  24. package/build-module/private-apis.mjs +0 -2
  25. package/build-module/private-apis.mjs.map +2 -2
  26. package/build-module/store/private-actions.mjs +14 -0
  27. package/build-module/store/private-actions.mjs.map +2 -2
  28. package/build-module/store/private-keys.mjs +0 -2
  29. package/build-module/store/private-keys.mjs.map +2 -2
  30. package/build-module/store/private-selectors.mjs +22 -6
  31. package/build-module/store/private-selectors.mjs.map +2 -2
  32. package/build-module/store/reducer.mjs +17 -3
  33. package/build-module/store/reducer.mjs.map +2 -2
  34. package/package.json +39 -39
  35. package/src/components/block-inspector/index.js +23 -43
  36. package/src/components/use-resize-canvas/index.js +10 -71
  37. package/src/hooks/states.js +30 -26
  38. package/src/private-apis.js +0 -2
  39. package/src/store/private-actions.js +31 -0
  40. package/src/store/private-keys.js +0 -1
  41. package/src/store/private-selectors.js +43 -7
  42. package/src/store/reducer.js +37 -2
  43. package/src/store/test/private-selectors.js +14 -10
  44. package/src/store/test/reducer.js +30 -2
  45. package/src/components/use-resize-canvas/README.md +0 -37
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/block-editor",
3
- "version": "15.22.1",
3
+ "version": "15.23.0",
4
4
  "description": "Generic block editor.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -60,43 +60,43 @@
60
60
  ],
61
61
  "dependencies": {
62
62
  "@react-spring/web": "^9.4.5",
63
- "@wordpress/a11y": "^4.49.0",
64
- "@wordpress/base-styles": "^10.1.0",
65
- "@wordpress/blob": "^4.49.0",
66
- "@wordpress/block-serialization-default-parser": "^5.49.0",
67
- "@wordpress/blocks": "^15.22.0",
68
- "@wordpress/commands": "^1.49.1",
69
- "@wordpress/components": "^36.0.1",
70
- "@wordpress/compose": "^8.2.0",
71
- "@wordpress/data": "^10.49.0",
72
- "@wordpress/dataviews": "^17.0.1",
73
- "@wordpress/date": "^5.49.0",
74
- "@wordpress/deprecated": "^4.49.0",
75
- "@wordpress/dom": "^4.49.0",
76
- "@wordpress/element": "^8.1.0",
77
- "@wordpress/escape-html": "^3.49.0",
78
- "@wordpress/global-styles-engine": "^1.16.0",
79
- "@wordpress/hooks": "^4.49.0",
80
- "@wordpress/html-entities": "^4.49.0",
81
- "@wordpress/i18n": "^6.22.0",
82
- "@wordpress/icons": "^15.0.0",
83
- "@wordpress/image-cropper": "^1.13.1",
84
- "@wordpress/interactivity": "^6.49.0",
85
- "@wordpress/is-shallow-equal": "^5.49.0",
86
- "@wordpress/keyboard-shortcuts": "^5.49.0",
87
- "@wordpress/keycodes": "^4.49.0",
88
- "@wordpress/notices": "^5.49.1",
89
- "@wordpress/preferences": "^4.49.1",
90
- "@wordpress/priority-queue": "^3.49.0",
91
- "@wordpress/private-apis": "^1.49.0",
92
- "@wordpress/rich-text": "^7.49.0",
93
- "@wordpress/style-engine": "^2.49.0",
94
- "@wordpress/token-list": "^3.49.0",
95
- "@wordpress/ui": "^0.16.1",
96
- "@wordpress/upload-media": "^0.34.1",
97
- "@wordpress/url": "^4.49.0",
98
- "@wordpress/warning": "^3.49.0",
99
- "@wordpress/wordcount": "^4.49.0",
63
+ "@wordpress/a11y": "^4.50.0",
64
+ "@wordpress/base-styles": "^10.2.0",
65
+ "@wordpress/blob": "^4.50.0",
66
+ "@wordpress/block-serialization-default-parser": "^5.50.0",
67
+ "@wordpress/blocks": "^15.23.0",
68
+ "@wordpress/commands": "^1.50.0",
69
+ "@wordpress/components": "^36.1.0",
70
+ "@wordpress/compose": "^8.3.0",
71
+ "@wordpress/data": "^10.50.0",
72
+ "@wordpress/dataviews": "^17.1.0",
73
+ "@wordpress/date": "^5.50.0",
74
+ "@wordpress/deprecated": "^4.50.0",
75
+ "@wordpress/dom": "^4.50.0",
76
+ "@wordpress/element": "^8.2.0",
77
+ "@wordpress/escape-html": "^3.50.0",
78
+ "@wordpress/global-styles-engine": "^1.17.0",
79
+ "@wordpress/hooks": "^4.50.0",
80
+ "@wordpress/html-entities": "^4.50.0",
81
+ "@wordpress/i18n": "^6.23.0",
82
+ "@wordpress/icons": "^15.1.0",
83
+ "@wordpress/image-cropper": "^1.14.0",
84
+ "@wordpress/interactivity": "^6.50.0",
85
+ "@wordpress/is-shallow-equal": "^5.50.0",
86
+ "@wordpress/keyboard-shortcuts": "^5.50.0",
87
+ "@wordpress/keycodes": "^4.50.0",
88
+ "@wordpress/notices": "^5.50.0",
89
+ "@wordpress/preferences": "^4.50.0",
90
+ "@wordpress/priority-queue": "^3.50.0",
91
+ "@wordpress/private-apis": "^1.50.0",
92
+ "@wordpress/rich-text": "^7.50.0",
93
+ "@wordpress/style-engine": "^2.50.0",
94
+ "@wordpress/token-list": "^3.50.0",
95
+ "@wordpress/ui": "^0.17.0",
96
+ "@wordpress/upload-media": "^0.35.0",
97
+ "@wordpress/url": "^4.50.0",
98
+ "@wordpress/warning": "^3.50.0",
99
+ "@wordpress/wordcount": "^4.50.0",
100
100
  "change-case": "^4.1.2",
101
101
  "clsx": "^2.1.1",
102
102
  "colord": "^2.9.3",
@@ -133,5 +133,5 @@
133
133
  "publishConfig": {
134
134
  "access": "public"
135
135
  },
136
- "gitHead": "9a75283890dda96ae1d37197b5070fae8c9cf66f"
136
+ "gitHead": "fee6e24e8e63d36f6bbcf487c193461e9bd79753"
137
137
  }
@@ -45,7 +45,6 @@ import {
45
45
  hasViewportBlockStyleState,
46
46
  isDefaultBlockStyleState,
47
47
  } from '../../hooks/block-style-state';
48
- import { onViewportStateChangeKey } from '../../store/private-keys';
49
48
 
50
49
  function StyleInspectorSlots( {
51
50
  blockName,
@@ -150,7 +149,7 @@ function BlockInspector() {
150
149
  blockEditingMode,
151
150
  selectedBlockStyleState,
152
151
  showStateOnCanvas,
153
- onViewportStateChange,
152
+ isResponsiveEditing,
154
153
  } = useSelect( ( select ) => {
155
154
  const {
156
155
  getSelectedBlockClientId,
@@ -164,8 +163,8 @@ function BlockInspector() {
164
163
  getBlockEditingMode,
165
164
  getSelectedBlockStyleState,
166
165
  isSelectedBlockStyleStateShownOnCanvas,
166
+ isResponsiveEditing: _isResponsiveEditing,
167
167
  } = unlock( select( blockEditorStore ) );
168
- const blockEditorSettings = select( blockEditorStore ).getSettings();
169
168
  const { getBlockStyles } = select( blocksStore );
170
169
  const _selectedBlockClientId = getSelectedBlockClientId();
171
170
  const isWithinEditedSection = isWithinEditedContentOnlySection(
@@ -203,8 +202,7 @@ function BlockInspector() {
203
202
  showStateOnCanvas: isSelectedBlockStyleStateShownOnCanvas(
204
203
  _renderedBlockClientId
205
204
  ),
206
- onViewportStateChange:
207
- blockEditorSettings?.[ onViewportStateChangeKey ],
205
+ isResponsiveEditing: _isResponsiveEditing(),
208
206
  };
209
207
  }, [] );
210
208
 
@@ -339,7 +337,7 @@ function BlockInspector() {
339
337
  blockEditingMode={ blockEditingMode }
340
338
  selectedBlockStyleState={ selectedBlockStyleState }
341
339
  showStateOnCanvas={ showStateOnCanvas }
342
- onViewportStateChange={ onViewportStateChange }
340
+ isResponsiveEditing={ isResponsiveEditing }
343
341
  isBlockStyleStateSelected={ isBlockStyleStateSelected }
344
342
  />
345
343
  </BlockInspectorSingleBlockWrapper>
@@ -395,11 +393,14 @@ const BlockInspectorSingleBlock = ( {
395
393
  blockEditingMode,
396
394
  selectedBlockStyleState,
397
395
  showStateOnCanvas,
398
- onViewportStateChange,
396
+ isResponsiveEditing,
399
397
  isBlockStyleStateSelected,
400
398
  } ) => {
401
399
  const listViewRef = useRef( null );
402
400
  const hasMultipleTabs = availableTabs?.length > 1;
401
+ const hasPseudoState = hasPseudoBlockStyleState( selectedBlockStyleState );
402
+ const isEditingStyleState =
403
+ isBlockStyleStateSelected || isResponsiveEditing;
403
404
  const hasParentChildBlockCards =
404
405
  editedContentOnlySection &&
405
406
  editedContentOnlySection !== renderedBlockClientId;
@@ -415,32 +416,10 @@ const BlockInspectorSingleBlock = ( {
415
416
  setSelectedBlockStyleStateCanvasPreview,
416
417
  } = unlock( useDispatch( blockEditorStore ) );
417
418
  const onBlockStyleStateChange = ( value ) => {
418
- const nextSelectedBlockStyleState = {
419
- ...selectedBlockStyleState,
420
- ...value,
421
- };
422
-
423
- setSelectedBlockStyleState(
424
- renderedBlockClientId,
425
- nextSelectedBlockStyleState
426
- );
427
-
428
- if ( value.viewport ) {
429
- onViewportStateChange?.( {
430
- viewport: nextSelectedBlockStyleState.viewport,
431
- showStateOnCanvas,
432
- } );
433
- }
419
+ setSelectedBlockStyleState( renderedBlockClientId, value );
434
420
  };
435
421
  const onShowStateOnCanvasChange = ( value ) => {
436
422
  setSelectedBlockStyleStateCanvasPreview( renderedBlockClientId, value );
437
-
438
- if ( value ) {
439
- onViewportStateChange?.( {
440
- viewport: selectedBlockStyleState.viewport,
441
- showStateOnCanvas: value,
442
- } );
443
- }
444
423
  };
445
424
 
446
425
  return (
@@ -470,34 +449,37 @@ const BlockInspectorSingleBlock = ( {
470
449
  )
471
450
  }
472
451
  />
473
- { blockEditingMode === 'default' && isBlockStyleStateSelected && (
452
+ { blockEditingMode === 'default' && isEditingStyleState && (
474
453
  <Spacer paddingX={ 4 } paddingY={ 2 }>
475
- <ToggleControl
476
- label={ __( 'Show state on canvas' ) }
477
- checked={ showStateOnCanvas }
478
- onChange={ onShowStateOnCanvasChange }
479
- />
454
+ { hasPseudoState && (
455
+ <ToggleControl
456
+ label={ __( 'Show state on canvas' ) }
457
+ checked={ showStateOnCanvas }
458
+ onChange={ onShowStateOnCanvasChange }
459
+ />
460
+ ) }
480
461
  <BlockStateBadges
481
462
  name={ blockName }
482
463
  value={ selectedBlockStyleState }
464
+ isResponsiveEditing={ isResponsiveEditing }
483
465
  />
484
466
  </Spacer>
485
467
  ) }
486
468
  <ViewportVisibilityInfo clientId={ renderedBlockClientId } />
487
469
  <EditContents clientId={ renderedBlockClientId } />
488
- { ! isBlockStyleStateSelected && (
470
+ { ! isEditingStyleState && (
489
471
  <BlockVariationTransforms
490
472
  blockClientId={ renderedBlockClientId }
491
473
  />
492
474
  ) }
493
475
  <BlockInspectorPreTabsSlot />
494
- { isBlockStyleStateSelected && ! isSectionBlock && (
476
+ { isEditingStyleState && ! isSectionBlock && (
495
477
  <StyleStateInspectorSlots
496
478
  blockName={ blockName }
497
479
  selectedBlockStyleState={ selectedBlockStyleState }
498
480
  />
499
481
  ) }
500
- { ! isBlockStyleStateSelected && hasMultipleTabs && (
482
+ { ! isEditingStyleState && hasMultipleTabs && (
501
483
  <>
502
484
  <InspectorControlsTabs
503
485
  hasBlockStyles={ hasBlockStyles }
@@ -509,7 +491,7 @@ const BlockInspectorSingleBlock = ( {
509
491
  />
510
492
  </>
511
493
  ) }
512
- { ! isBlockStyleStateSelected && ! hasMultipleTabs && (
494
+ { ! isEditingStyleState && ! hasMultipleTabs && (
513
495
  <>
514
496
  { hasBlockStyles && (
515
497
  <BlockStyles clientId={ renderedBlockClientId } />
@@ -523,9 +505,7 @@ const BlockInspectorSingleBlock = ( {
523
505
  ) }
524
506
  </>
525
507
  ) }
526
- { ! isBlockStyleStateSelected && (
527
- <InspectorControlsLastItem.Slot />
528
- ) }
508
+ { ! isEditingStyleState && <InspectorControlsLastItem.Slot /> }
529
509
  <SkipToSelectedBlock key="back" />
530
510
  </div>
531
511
  );
@@ -1,79 +1,18 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { useEffect, useState } from '@wordpress/element';
4
+ import deprecated from '@wordpress/deprecated';
5
5
 
6
6
  /**
7
- * Function to resize the editor window.
7
+ * Previously returned inline styles that sized the editor canvas to emulate a
8
+ * device preview width. Device preview is now handled by the editor's resizable
9
+ * canvas, so this hook is a no-op kept for backward compatibility.
8
10
  *
9
- * @param {string} deviceType Used for determining the size of the container (e.g. Desktop, Tablet, Mobile)
10
- *
11
- * @return {Object} Inline styles to be added to resizable container.
11
+ * @deprecated
12
12
  */
13
- export default function useResizeCanvas( deviceType ) {
14
- const [ actualWidth, updateActualWidth ] = useState( window.innerWidth );
15
-
16
- useEffect( () => {
17
- if ( deviceType === 'Desktop' ) {
18
- return;
19
- }
20
-
21
- const resizeListener = () => updateActualWidth( window.innerWidth );
22
- window.addEventListener( 'resize', resizeListener );
23
-
24
- return () => {
25
- window.removeEventListener( 'resize', resizeListener );
26
- };
27
- }, [ deviceType ] );
28
-
29
- const getCanvasWidth = ( device ) => {
30
- let deviceWidth;
31
-
32
- /*
33
- * Matches the breakpoints in packages/base-styles/_breakpoints.scss,
34
- * and breakpoints in packages/compose/src/hooks/use-viewport-match/index.js.
35
- * minus 1 to trigger the media query for device preview.
36
- */
37
- switch ( device ) {
38
- case 'Tablet':
39
- deviceWidth = 782 - 1; // preview for useViewportMatch( 'medium', '<' )
40
- break;
41
- case 'Mobile':
42
- deviceWidth = 480 - 1; // preview for useViewportMatch( 'mobile', '<' )
43
- break;
44
- default:
45
- return null;
46
- }
47
-
48
- return deviceWidth < actualWidth ? deviceWidth : actualWidth;
49
- };
50
-
51
- const contentInlineStyles = ( device ) => {
52
- const height = device === 'Mobile' ? '768px' : '1024px';
53
- const marginVertical = '40px';
54
- const marginHorizontal = 'auto';
55
-
56
- switch ( device ) {
57
- case 'Tablet':
58
- case 'Mobile':
59
- return {
60
- width: getCanvasWidth( device ),
61
- // Keeping margin styles separate to avoid warnings
62
- // when those props get overridden in the iframe component
63
- marginTop: marginVertical,
64
- marginBottom: marginVertical,
65
- marginLeft: marginHorizontal,
66
- marginRight: marginHorizontal,
67
- height,
68
- overflowY: 'auto',
69
- };
70
- default:
71
- return {
72
- marginLeft: marginHorizontal,
73
- marginRight: marginHorizontal,
74
- };
75
- }
76
- };
77
-
78
- return contentInlineStyles( deviceType );
13
+ export default function useResizeCanvas() {
14
+ deprecated( 'wp.blockEditor.useResizeCanvas', {
15
+ since: '7.1',
16
+ hint: 'Device preview is now handled by the editor canvas. This hook no longer does anything.',
17
+ } );
79
18
  }
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { getBlockType } from '@wordpress/blocks';
5
4
  import { __ } from '@wordpress/i18n';
6
5
 
7
6
  /**
@@ -23,6 +22,19 @@ export const RESPONSIVE_STATE_LABELS = {
23
22
  '@mobile': __( 'Mobile' ),
24
23
  };
25
24
 
25
+ // Viewport states are selected globally via the editor's device preview
26
+ // (Responsive editing). 'default' maps to the Desktop device, the remaining
27
+ // options are derived from the shared responsive-state labels.
28
+ const DEVICE_STATE_OPTIONS = [
29
+ { value: 'default', label: __( 'Desktop' ) },
30
+ ...Object.entries( RESPONSIVE_STATE_LABELS ).map(
31
+ ( [ value, label ] ) => ( {
32
+ value,
33
+ label,
34
+ } )
35
+ ),
36
+ ];
37
+
26
38
  // Keep in sync with WP_Theme_JSON_Gutenberg::VALID_BLOCK_PSEUDO_SELECTORS
27
39
  // and packages/global-styles-engine/src/core/render.tsx.
28
40
  export const VALID_BLOCK_PSEUDO_STATES = {
@@ -43,23 +55,11 @@ function getPseudoStateOptions( name ) {
43
55
 
44
56
  const DEFAULT_STATE_VALUE = 'default';
45
57
 
46
- function getViewportStateOptions( name ) {
47
- if ( ! getBlockType( name )?.attributes?.style ) {
48
- return [];
49
- }
50
-
51
- return Object.entries( RESPONSIVE_STATE_LABELS ).map(
52
- ( [ value, label ] ) => ( {
53
- value,
54
- label,
55
- } )
56
- );
57
- }
58
-
59
58
  /**
60
- * Renders a style-state selector in the block card header.
61
- * Viewport states are shown for blocks with a style attribute, while
62
- * pseudo-states are shown for blocks with configured pseudo-state support.
59
+ * Renders a pseudo-state selector in the block card header.
60
+ *
61
+ * Viewport states are selected globally via the editor's device preview
62
+ * (Responsive editing), so only pseudo-states are exposed here.
63
63
  *
64
64
  * @param {Object} props Component props.
65
65
  * @param {string} props.name Block name.
@@ -68,21 +68,17 @@ function getViewportStateOptions( name ) {
68
68
  * @return {Element|null} State control component, or null if not applicable.
69
69
  */
70
70
  export function BlockStatesControl( { name, value, onChange } ) {
71
- const viewportStateOptions = getViewportStateOptions( name );
72
71
  const pseudoStateOptions = getPseudoStateOptions( name );
73
72
  const dropdownMenuProps = useToolsPanelDropdownMenuProps();
74
73
 
75
- if ( ! viewportStateOptions.length && ! pseudoStateOptions.length ) {
74
+ if ( ! pseudoStateOptions.length ) {
76
75
  return null;
77
76
  }
78
77
 
79
78
  return (
80
79
  <StateControl
81
- viewportStates={ viewportStateOptions }
82
80
  pseudoStates={ pseudoStateOptions }
83
- viewportValue={ value?.viewport ?? DEFAULT_STATE_VALUE }
84
81
  pseudoStateValue={ value?.pseudo ?? DEFAULT_STATE_VALUE }
85
- onChangeViewport={ ( viewport ) => onChange( { viewport } ) }
86
82
  onChangePseudoState={ ( pseudo ) => onChange( { pseudo } ) }
87
83
  popoverProps={ dropdownMenuProps.popoverProps }
88
84
  showText={ false }
@@ -90,17 +86,25 @@ export function BlockStatesControl( { name, value, onChange } ) {
90
86
  );
91
87
  }
92
88
 
93
- export function BlockStateBadges( { name, value } ) {
94
- const viewportStateOptions = getViewportStateOptions( name );
89
+ /**
90
+ * Renders badges for the active style states of a block.
91
+ *
92
+ * @param {Object} props Component props.
93
+ * @param {string} props.name Block name.
94
+ * @param {Object} props.value Currently selected style-state value.
95
+ * @param {boolean} props.isResponsiveEditing Whether Responsive editing is enabled.
96
+ * @return {Element|null} Badges component, or null if there is nothing to show.
97
+ */
98
+ export function BlockStateBadges( { name, value, isResponsiveEditing } ) {
95
99
  const pseudoStateOptions = getPseudoStateOptions( name );
96
100
 
97
- if ( ! viewportStateOptions.length && ! pseudoStateOptions.length ) {
101
+ if ( ! pseudoStateOptions.length && ! isResponsiveEditing ) {
98
102
  return null;
99
103
  }
100
104
 
101
105
  return (
102
106
  <StateControlBadges
103
- viewportStates={ viewportStateOptions }
107
+ viewportStates={ isResponsiveEditing ? DEVICE_STATE_OPTIONS : [] }
104
108
  pseudoStates={ pseudoStateOptions }
105
109
  viewportValue={ value?.viewport ?? DEFAULT_STATE_VALUE }
106
110
  pseudoStateValue={ value?.pseudo ?? DEFAULT_STATE_VALUE }
@@ -52,7 +52,6 @@ import {
52
52
  mediaEditKey,
53
53
  getMediaSelectKey,
54
54
  deviceTypeKey,
55
- onViewportStateChangeKey,
56
55
  isIsolatedEditorKey,
57
56
  isNavigationOverlayContextKey,
58
57
  isNavigationPostEditorKey,
@@ -141,7 +140,6 @@ lock( privateApis, {
141
140
  mediaEditKey,
142
141
  getMediaSelectKey,
143
142
  deviceTypeKey,
144
- onViewportStateChangeKey,
145
143
  isIsolatedEditorKey,
146
144
  isNavigationOverlayContextKey,
147
145
  isNavigationPostEditorKey,
@@ -558,3 +558,34 @@ export function setSelectedBlockStyleStateCanvasPreview( clientId, value ) {
558
558
  value,
559
559
  };
560
560
  }
561
+
562
+ /**
563
+ * Sets the globally selected viewport style state. When set to a value other
564
+ * than 'default', block style edits in the inspector apply to that viewport.
565
+ * Driven by the editor's device preview while Responsive editing is enabled.
566
+ *
567
+ * @param {string} viewport The selected viewport state (e.g. 'default', 'tablet', 'mobile').
568
+ *
569
+ * @return {Object} Action object.
570
+ */
571
+ export function setStyleStateViewport( viewport ) {
572
+ return {
573
+ type: 'SET_STYLE_STATE_VIEWPORT',
574
+ viewport,
575
+ };
576
+ }
577
+
578
+ /**
579
+ * Sets whether Responsive editing is enabled. When enabled, the device preview
580
+ * also drives which viewport block style edits are applied to. Session-only.
581
+ *
582
+ * @param {boolean} enabled Whether Responsive editing is enabled.
583
+ *
584
+ * @return {Object} Action object.
585
+ */
586
+ export function setResponsiveEditing( enabled ) {
587
+ return {
588
+ type: 'SET_RESPONSIVE_EDITING',
589
+ enabled,
590
+ };
591
+ }
@@ -10,7 +10,6 @@ export const mediaEditKey = Symbol( 'mediaEditKey' );
10
10
  export const getMediaSelectKey = Symbol( 'getMediaSelect' );
11
11
  export const isIsolatedEditorKey = Symbol( 'isIsolatedEditor' );
12
12
  export const deviceTypeKey = Symbol( 'deviceTypeKey' );
13
- export const onViewportStateChangeKey = Symbol( 'onViewportStateChangeKey' );
14
13
  export const isNavigationOverlayContextKey = Symbol(
15
14
  'isNavigationOverlayContext'
16
15
  );
@@ -1152,6 +1152,30 @@ const DEFAULT_BLOCK_STYLE_STATE = {
1152
1152
  pseudo: 'default',
1153
1153
  };
1154
1154
 
1155
+ /**
1156
+ * Returns the globally selected viewport style state. When set to a value other
1157
+ * than 'default', block style edits in the inspector apply to that viewport.
1158
+ *
1159
+ * @param {Object} state Global application state.
1160
+ *
1161
+ * @return {string} The selected viewport style state.
1162
+ */
1163
+ export function getStyleStateViewport( state ) {
1164
+ return state.styleStateViewport ?? DEFAULT_BLOCK_STYLE_STATE.viewport;
1165
+ }
1166
+
1167
+ /**
1168
+ * Returns whether Responsive editing is enabled. When enabled, the device
1169
+ * preview also drives which viewport block style edits are applied to.
1170
+ *
1171
+ * @param {Object} state Global application state.
1172
+ *
1173
+ * @return {boolean} Whether Responsive editing is enabled.
1174
+ */
1175
+ export function isResponsiveEditing( state ) {
1176
+ return state.isResponsiveEditing;
1177
+ }
1178
+
1155
1179
  /**
1156
1180
  * Returns the selected style state for a block's style controls.
1157
1181
  *
@@ -1160,13 +1184,25 @@ const DEFAULT_BLOCK_STYLE_STATE = {
1160
1184
  *
1161
1185
  * @return {Object} The selected block style state.
1162
1186
  */
1163
- export function getSelectedBlockStyleState( state, clientId ) {
1164
- if ( state.selectedBlockStyleState?.clientId !== clientId ) {
1165
- return DEFAULT_BLOCK_STYLE_STATE;
1166
- }
1167
-
1168
- return state.selectedBlockStyleState.value ?? DEFAULT_BLOCK_STYLE_STATE;
1169
- }
1187
+ export const getSelectedBlockStyleState = createSelector(
1188
+ ( state, clientId ) => {
1189
+ const perBlockState =
1190
+ state.selectedBlockStyleState?.clientId === clientId
1191
+ ? state.selectedBlockStyleState.value ??
1192
+ DEFAULT_BLOCK_STYLE_STATE
1193
+ : DEFAULT_BLOCK_STYLE_STATE;
1194
+
1195
+ return {
1196
+ ...perBlockState,
1197
+ // The viewport is tracked globally, so inject it here. This way
1198
+ // consumers receive a single combined state object instead of
1199
+ // merging the global viewport themselves, and selectors derived
1200
+ // from this stay consistent.
1201
+ viewport: getStyleStateViewport( state ),
1202
+ };
1203
+ },
1204
+ ( state ) => [ state.styleStateViewport, state.selectedBlockStyleState ]
1205
+ );
1170
1206
 
1171
1207
  /**
1172
1208
  * Returns whether a non-default style state is selected for a block.
@@ -2312,7 +2312,6 @@ export function selectedBlockStyleState( state = undefined, action ) {
2312
2312
  clientId: action.clientId,
2313
2313
  showStateOnCanvas,
2314
2314
  value: {
2315
- viewport: 'default',
2316
2315
  pseudo: 'default',
2317
2316
  ...previousValue,
2318
2317
  ...action.value,
@@ -2332,7 +2331,6 @@ export function selectedBlockStyleState( state = undefined, action ) {
2332
2331
  clientId: action.clientId,
2333
2332
  showStateOnCanvas: action.value,
2334
2333
  value: {
2335
- viewport: 'default',
2336
2334
  pseudo: 'default',
2337
2335
  ...previousValue,
2338
2336
  },
@@ -2390,6 +2388,41 @@ export function selectedBlockStyleState( state = undefined, action ) {
2390
2388
  return state;
2391
2389
  }
2392
2390
 
2391
+ /**
2392
+ * Reducer holding the globally selected viewport style state. When set to a
2393
+ * value other than 'default', block style edits in the inspector are applied to
2394
+ * that viewport. Driven by the editor's device preview (Responsive editing).
2395
+ *
2396
+ * @param {string} state Current state.
2397
+ * @param {Object} action Dispatched action.
2398
+ *
2399
+ * @return {string} Updated state.
2400
+ */
2401
+ export function styleStateViewport( state = 'default', action ) {
2402
+ if ( action.type === 'SET_STYLE_STATE_VIEWPORT' ) {
2403
+ return action.viewport ?? 'default';
2404
+ }
2405
+
2406
+ return state;
2407
+ }
2408
+
2409
+ /**
2410
+ * Reducer for whether Responsive editing is enabled. When enabled, the device
2411
+ * preview also drives which viewport block style edits are applied to.
2412
+ *
2413
+ * @param {boolean} state Current state.
2414
+ * @param {Object} action Dispatched action.
2415
+ *
2416
+ * @return {boolean} Updated state.
2417
+ */
2418
+ export function isResponsiveEditing( state = false, action ) {
2419
+ if ( action.type === 'SET_RESPONSIVE_EDITING' ) {
2420
+ return action.enabled;
2421
+ }
2422
+
2423
+ return state;
2424
+ }
2425
+
2393
2426
  const combinedReducers = combineReducers( {
2394
2427
  blocks,
2395
2428
  isDragging,
@@ -2426,6 +2459,8 @@ const combinedReducers = combineReducers( {
2426
2459
  listViewContentPanelOpen,
2427
2460
  requestedInspectorTab,
2428
2461
  selectedBlockStyleState,
2462
+ styleStateViewport,
2463
+ isResponsiveEditing,
2429
2464
  } );
2430
2465
 
2431
2466
  /**