@wordpress/block-editor 15.9.1-next.8b30e05b0.0 → 15.10.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 (196) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/README.md +8 -0
  3. package/build/components/block-alignment-matrix-control/index.js +1 -8
  4. package/build/components/block-alignment-matrix-control/index.js.map +2 -2
  5. package/build/components/block-bindings/attribute-control.js +172 -0
  6. package/build/components/block-bindings/attribute-control.js.map +7 -0
  7. package/build/components/block-bindings/index.js +47 -0
  8. package/build/components/block-bindings/index.js.map +7 -0
  9. package/build/components/block-bindings/source-fields-list.js +135 -0
  10. package/build/components/block-bindings/source-fields-list.js.map +7 -0
  11. package/build/components/block-bindings/use-block-bindings-utils.js +66 -0
  12. package/build/components/block-bindings/use-block-bindings-utils.js.map +7 -0
  13. package/build/components/block-edit/edit.js +1 -3
  14. package/build/components/block-edit/edit.js.map +2 -2
  15. package/build/components/block-inspector/edit-contents.js +93 -14
  16. package/build/components/block-inspector/edit-contents.js.map +3 -3
  17. package/build/components/block-inspector/index.js +44 -28
  18. package/build/components/block-inspector/index.js.map +2 -2
  19. package/build/components/block-settings-menu-controls/edit-section-menu-item.js +39 -9
  20. package/build/components/block-settings-menu-controls/edit-section-menu-item.js.map +3 -3
  21. package/build/components/block-styles/preview-panel.js +3 -5
  22. package/build/components/block-styles/preview-panel.js.map +2 -2
  23. package/build/components/block-styles/use-styles-for-block.js +2 -2
  24. package/build/components/block-styles/use-styles-for-block.js.map +2 -2
  25. package/build/components/block-toolbar/index.js +1 -8
  26. package/build/components/block-toolbar/index.js.map +3 -3
  27. package/build/components/content-only-controls/index.js +2 -25
  28. package/build/components/content-only-controls/index.js.map +2 -2
  29. package/build/components/content-only-controls/link/index.js +3 -3
  30. package/build/components/content-only-controls/link/index.js.map +2 -2
  31. package/build/components/content-only-controls/media/index.js +3 -3
  32. package/build/components/content-only-controls/media/index.js.map +2 -2
  33. package/build/components/content-only-controls/rich-text/index.js +3 -2
  34. package/build/components/content-only-controls/rich-text/index.js.map +2 -2
  35. package/build/components/dimensions-tool/width-height-tool.js +4 -16
  36. package/build/components/dimensions-tool/width-height-tool.js.map +3 -3
  37. package/build/components/grid/grid-item-resizer.js +9 -5
  38. package/build/components/grid/grid-item-resizer.js.map +2 -2
  39. package/build/components/image-editor/cropper.js +3 -34
  40. package/build/components/image-editor/cropper.js.map +3 -3
  41. package/build/components/image-editor/index.js +9 -3
  42. package/build/components/image-editor/index.js.map +2 -2
  43. package/build/components/image-editor/use-transform-image.js +62 -32
  44. package/build/components/image-editor/use-transform-image.js.map +2 -2
  45. package/build/components/image-editor/zoom-dropdown.js +2 -2
  46. package/build/components/image-editor/zoom-dropdown.js.map +2 -2
  47. package/build/components/index.js +7 -3
  48. package/build/components/index.js.map +2 -2
  49. package/build/components/inserter/hooks/use-insertion-point.js +5 -2
  50. package/build/components/inserter/hooks/use-insertion-point.js.map +2 -2
  51. package/build/components/inserter-draggable-blocks/index.js +8 -4
  52. package/build/components/inserter-draggable-blocks/index.js.map +2 -2
  53. package/build/components/inspector-controls-tabs/content-tab.js +3 -2
  54. package/build/components/inspector-controls-tabs/content-tab.js.map +2 -2
  55. package/build/components/link-control/index.js +1 -1
  56. package/build/components/link-control/index.js.map +2 -2
  57. package/build/components/link-control/search-input.js +2 -2
  58. package/build/components/link-control/search-input.js.map +2 -2
  59. package/build/hooks/block-bindings.js +22 -260
  60. package/build/hooks/block-bindings.js.map +3 -3
  61. package/build/layouts/grid.js +23 -28
  62. package/build/layouts/grid.js.map +2 -2
  63. package/build/private-apis.js +1 -0
  64. package/build/private-apis.js.map +2 -2
  65. package/build/store/private-keys.js +3 -0
  66. package/build/store/private-keys.js.map +2 -2
  67. package/build/store/private-selectors.js +2 -1
  68. package/build/store/private-selectors.js.map +2 -2
  69. package/build/store/reducer.js +3 -2
  70. package/build/store/reducer.js.map +2 -2
  71. package/build/utils/block-bindings.js +2 -44
  72. package/build/utils/block-bindings.js.map +3 -3
  73. package/build/utils/index.js +2 -5
  74. package/build/utils/index.js.map +2 -2
  75. package/build-module/components/block-alignment-matrix-control/index.js +1 -8
  76. package/build-module/components/block-alignment-matrix-control/index.js.map +2 -2
  77. package/build-module/components/block-bindings/attribute-control.js +150 -0
  78. package/build-module/components/block-bindings/attribute-control.js.map +7 -0
  79. package/build-module/components/block-bindings/index.js +10 -0
  80. package/build-module/components/block-bindings/index.js.map +7 -0
  81. package/build-module/components/block-bindings/source-fields-list.js +104 -0
  82. package/build-module/components/block-bindings/source-fields-list.js.map +7 -0
  83. package/build-module/components/block-bindings/use-block-bindings-utils.js +45 -0
  84. package/build-module/components/block-bindings/use-block-bindings-utils.js.map +7 -0
  85. package/build-module/components/block-edit/edit.js +1 -3
  86. package/build-module/components/block-edit/edit.js.map +2 -2
  87. package/build-module/components/block-inspector/edit-contents.js +93 -14
  88. package/build-module/components/block-inspector/edit-contents.js.map +2 -2
  89. package/build-module/components/block-inspector/index.js +44 -28
  90. package/build-module/components/block-inspector/index.js.map +2 -2
  91. package/build-module/components/block-settings-menu-controls/edit-section-menu-item.js +39 -9
  92. package/build-module/components/block-settings-menu-controls/edit-section-menu-item.js.map +2 -2
  93. package/build-module/components/block-styles/preview-panel.js +3 -5
  94. package/build-module/components/block-styles/preview-panel.js.map +2 -2
  95. package/build-module/components/block-styles/use-styles-for-block.js +2 -2
  96. package/build-module/components/block-styles/use-styles-for-block.js.map +2 -2
  97. package/build-module/components/block-toolbar/index.js +1 -8
  98. package/build-module/components/block-toolbar/index.js.map +2 -2
  99. package/build-module/components/content-only-controls/index.js +2 -25
  100. package/build-module/components/content-only-controls/index.js.map +2 -2
  101. package/build-module/components/content-only-controls/link/index.js +3 -3
  102. package/build-module/components/content-only-controls/link/index.js.map +2 -2
  103. package/build-module/components/content-only-controls/media/index.js +3 -3
  104. package/build-module/components/content-only-controls/media/index.js.map +2 -2
  105. package/build-module/components/content-only-controls/rich-text/index.js +3 -2
  106. package/build-module/components/content-only-controls/rich-text/index.js.map +2 -2
  107. package/build-module/components/dimensions-tool/width-height-tool.js +4 -6
  108. package/build-module/components/dimensions-tool/width-height-tool.js.map +2 -2
  109. package/build-module/components/grid/grid-item-resizer.js +9 -5
  110. package/build-module/components/grid/grid-item-resizer.js.map +2 -2
  111. package/build-module/components/image-editor/cropper.js +3 -34
  112. package/build-module/components/image-editor/cropper.js.map +2 -2
  113. package/build-module/components/image-editor/index.js +9 -3
  114. package/build-module/components/image-editor/index.js.map +2 -2
  115. package/build-module/components/image-editor/use-transform-image.js +63 -33
  116. package/build-module/components/image-editor/use-transform-image.js.map +2 -2
  117. package/build-module/components/image-editor/zoom-dropdown.js +2 -2
  118. package/build-module/components/image-editor/zoom-dropdown.js.map +2 -2
  119. package/build-module/components/index.js +74 -68
  120. package/build-module/components/index.js.map +2 -2
  121. package/build-module/components/inserter/hooks/use-insertion-point.js +5 -2
  122. package/build-module/components/inserter/hooks/use-insertion-point.js.map +2 -2
  123. package/build-module/components/inserter-draggable-blocks/index.js +8 -4
  124. package/build-module/components/inserter-draggable-blocks/index.js.map +2 -2
  125. package/build-module/components/inspector-controls-tabs/content-tab.js +3 -2
  126. package/build-module/components/inspector-controls-tabs/content-tab.js.map +2 -2
  127. package/build-module/components/link-control/index.js +1 -1
  128. package/build-module/components/link-control/index.js.map +2 -2
  129. package/build-module/components/link-control/search-input.js +2 -2
  130. package/build-module/components/link-control/search-input.js.map +2 -2
  131. package/build-module/hooks/block-bindings.js +27 -270
  132. package/build-module/hooks/block-bindings.js.map +2 -2
  133. package/build-module/layouts/grid.js +23 -28
  134. package/build-module/layouts/grid.js.map +2 -2
  135. package/build-module/private-apis.js +3 -1
  136. package/build-module/private-apis.js.map +2 -2
  137. package/build-module/store/private-keys.js +2 -0
  138. package/build-module/store/private-keys.js.map +2 -2
  139. package/build-module/store/private-selectors.js +4 -2
  140. package/build-module/store/private-selectors.js.map +2 -2
  141. package/build-module/store/reducer.js +4 -3
  142. package/build-module/store/reducer.js.map +2 -2
  143. package/build-module/utils/block-bindings.js +1 -42
  144. package/build-module/utils/block-bindings.js.map +2 -2
  145. package/build-module/utils/index.js +1 -3
  146. package/build-module/utils/index.js.map +2 -2
  147. package/build-style/style-rtl.css +6 -6
  148. package/build-style/style.css +6 -6
  149. package/package.json +39 -40
  150. package/src/components/block-alignment-matrix-control/index.js +1 -5
  151. package/src/components/block-bindings/attribute-control.js +174 -0
  152. package/src/components/block-bindings/index.js +6 -0
  153. package/src/components/block-bindings/source-fields-list.js +130 -0
  154. package/src/components/block-bindings/use-block-bindings-utils.js +156 -0
  155. package/src/components/block-edit/edit.js +1 -3
  156. package/src/components/block-inspector/edit-contents.js +108 -18
  157. package/src/components/block-inspector/index.js +53 -30
  158. package/src/components/block-settings-menu-controls/edit-section-menu-item.js +50 -6
  159. package/src/components/block-styles/preview-panel.js +3 -5
  160. package/src/components/block-styles/use-styles-for-block.js +2 -2
  161. package/src/components/block-toolbar/index.js +1 -6
  162. package/src/components/block-toolbar/style.scss +6 -6
  163. package/src/components/content-only-controls/index.js +2 -27
  164. package/src/components/content-only-controls/link/index.js +3 -3
  165. package/src/components/content-only-controls/media/index.js +3 -3
  166. package/src/components/content-only-controls/rich-text/index.js +3 -2
  167. package/src/components/dimensions-tool/width-height-tool.js +6 -13
  168. package/src/components/grid/grid-item-resizer.js +18 -5
  169. package/src/components/image-editor/cropper.js +3 -32
  170. package/src/components/image-editor/index.js +34 -29
  171. package/src/components/image-editor/use-transform-image.js +80 -34
  172. package/src/components/image-editor/zoom-dropdown.js +2 -2
  173. package/src/components/index.js +5 -1
  174. package/src/components/inserter/hooks/use-insertion-point.js +3 -0
  175. package/src/components/inserter/style.scss +1 -1
  176. package/src/components/inserter-draggable-blocks/index.js +19 -8
  177. package/src/components/inspector-controls-tabs/content-tab.js +6 -2
  178. package/src/components/link-control/index.js +1 -1
  179. package/src/components/link-control/search-input.js +8 -2
  180. package/src/components/link-control/test/index.js +146 -7
  181. package/src/hooks/block-bindings.js +27 -347
  182. package/src/layouts/grid.js +40 -72
  183. package/src/layouts/test/grid.js +14 -0
  184. package/src/private-apis.js +2 -0
  185. package/src/store/private-keys.js +1 -0
  186. package/src/store/private-selectors.js +8 -1
  187. package/src/store/reducer.js +10 -3
  188. package/src/utils/block-bindings.js +0 -157
  189. package/src/utils/index.js +0 -1
  190. package/tsconfig.json +1 -0
  191. package/build/components/block-toolbar/block-name-context.js +0 -30
  192. package/build/components/block-toolbar/block-name-context.js.map +0 -7
  193. package/build-module/components/block-toolbar/block-name-context.js +0 -9
  194. package/build-module/components/block-toolbar/block-name-context.js.map +0 -7
  195. package/src/components/block-toolbar/block-name-context.js +0 -9
  196. /package/src/{utils → components/block-bindings}/test/use-block-bindings-utils.js +0 -0
@@ -0,0 +1,156 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useDispatch, useRegistry } from '@wordpress/data';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import { store as blockEditorStore } from '../../store';
10
+ import { useBlockEditContext } from '../block-edit';
11
+
12
+ /**
13
+ * Checks if the given object is empty.
14
+ *
15
+ * @param {?Object} object The object to check.
16
+ *
17
+ * @return {boolean} Whether the object is empty.
18
+ */
19
+ function isObjectEmpty( object ) {
20
+ return ! object || Object.keys( object ).length === 0;
21
+ }
22
+
23
+ /**
24
+ * Contains utils to update the block `bindings` metadata.
25
+ *
26
+ * @typedef {Object} WPBlockBindingsUtils
27
+ *
28
+ * @property {Function} updateBlockBindings Updates the value of the bindings connected to block attributes.
29
+ * @property {Function} removeAllBlockBindings Removes the bindings property of the `metadata` attribute.
30
+ */
31
+
32
+ /**
33
+ * Retrieves the existing utils needed to update the block `bindings` metadata.
34
+ * They can be used to create, modify, or remove connections from the existing block attributes.
35
+ *
36
+ * It contains the following utils:
37
+ * - `updateBlockBindings`: Updates the value of the bindings connected to block attributes. It can be used to remove a specific binding by setting the value to `undefined`.
38
+ * - `removeAllBlockBindings`: Removes the bindings property of the `metadata` attribute.
39
+ *
40
+ * @since 6.7.0 Introduced in WordPress core.
41
+ *
42
+ * @param {?string} clientId Optional block client ID. If not set, it will use the current block client ID from the context.
43
+ *
44
+ * @return {?WPBlockBindingsUtils} Object containing the block bindings utils.
45
+ *
46
+ * @example
47
+ * ```js
48
+ * import { useBlockBindingsUtils } from '@wordpress/block-editor'
49
+ * const { updateBlockBindings, removeAllBlockBindings } = useBlockBindingsUtils();
50
+ *
51
+ * // Update url and alt attributes.
52
+ * updateBlockBindings( {
53
+ * url: {
54
+ * source: 'core/post-meta',
55
+ * args: {
56
+ * key: 'url_custom_field',
57
+ * },
58
+ * },
59
+ * alt: {
60
+ * source: 'core/post-meta',
61
+ * args: {
62
+ * key: 'text_custom_field',
63
+ * },
64
+ * },
65
+ * } );
66
+ *
67
+ * // Remove binding from url attribute.
68
+ * updateBlockBindings( { url: undefined } );
69
+ *
70
+ * // Remove bindings from all attributes.
71
+ * removeAllBlockBindings();
72
+ * ```
73
+ */
74
+ export default function useBlockBindingsUtils( clientId ) {
75
+ const { clientId: contextClientId } = useBlockEditContext();
76
+ const blockClientId = clientId || contextClientId;
77
+ const { updateBlockAttributes } = useDispatch( blockEditorStore );
78
+ const { getBlockAttributes } = useRegistry().select( blockEditorStore );
79
+
80
+ /**
81
+ * Updates the value of the bindings connected to block attributes.
82
+ * It removes the binding when the new value is `undefined`.
83
+ *
84
+ * @param {Object} bindings Bindings including the attributes to update and the new object.
85
+ * @param {string} bindings.source The source name to connect to.
86
+ * @param {Object} [bindings.args] Object containing the arguments needed by the source.
87
+ *
88
+ * @example
89
+ * ```js
90
+ * import { useBlockBindingsUtils } from '@wordpress/block-editor'
91
+ *
92
+ * const { updateBlockBindings } = useBlockBindingsUtils();
93
+ * updateBlockBindings( {
94
+ * url: {
95
+ * source: 'core/post-meta',
96
+ * args: {
97
+ * key: 'url_custom_field',
98
+ * },
99
+ * },
100
+ * alt: {
101
+ * source: 'core/post-meta',
102
+ * args: {
103
+ * key: 'text_custom_field',
104
+ * },
105
+ * }
106
+ * } );
107
+ * ```
108
+ */
109
+ const updateBlockBindings = ( bindings ) => {
110
+ const { metadata: { bindings: currentBindings, ...metadata } = {} } =
111
+ getBlockAttributes( blockClientId );
112
+ const newBindings = { ...currentBindings };
113
+
114
+ Object.entries( bindings ).forEach( ( [ attribute, binding ] ) => {
115
+ if ( ! binding && newBindings[ attribute ] ) {
116
+ delete newBindings[ attribute ];
117
+ return;
118
+ }
119
+ newBindings[ attribute ] = binding;
120
+ } );
121
+
122
+ const newMetadata = {
123
+ ...metadata,
124
+ bindings: newBindings,
125
+ };
126
+
127
+ if ( isObjectEmpty( newMetadata.bindings ) ) {
128
+ delete newMetadata.bindings;
129
+ }
130
+
131
+ updateBlockAttributes( blockClientId, {
132
+ metadata: isObjectEmpty( newMetadata ) ? undefined : newMetadata,
133
+ } );
134
+ };
135
+
136
+ /**
137
+ * Removes the bindings property of the `metadata` attribute.
138
+ *
139
+ * @example
140
+ * ```js
141
+ * import { useBlockBindingsUtils } from '@wordpress/block-editor'
142
+ *
143
+ * const { removeAllBlockBindings } = useBlockBindingsUtils();
144
+ * removeAllBlockBindings();
145
+ * ```
146
+ */
147
+ const removeAllBlockBindings = () => {
148
+ const { metadata: { bindings, ...metadata } = {} } =
149
+ getBlockAttributes( blockClientId );
150
+ updateBlockAttributes( blockClientId, {
151
+ metadata: isObjectEmpty( metadata ) ? undefined : metadata,
152
+ } );
153
+ };
154
+
155
+ return { updateBlockBindings, removeAllBlockBindings };
156
+ }
@@ -100,10 +100,10 @@ const EditWithGeneratedProps = ( props ) => {
100
100
  ),
101
101
  };
102
102
  }, [
103
- name,
104
103
  blockType?.usesContext,
105
104
  blockContext,
106
105
  attributes?.metadata?.bindings,
106
+ bindableAttributes,
107
107
  registeredSources,
108
108
  ] );
109
109
 
@@ -180,7 +180,6 @@ const EditWithGeneratedProps = ( props ) => {
180
180
  blockBindings,
181
181
  clientId,
182
182
  context,
183
- name,
184
183
  registeredSources,
185
184
  ]
186
185
  );
@@ -262,7 +261,6 @@ const EditWithGeneratedProps = ( props ) => {
262
261
  hasPatternOverrides,
263
262
  setAttributes,
264
263
  registeredSources,
265
- name,
266
264
  registry,
267
265
  ]
268
266
  );
@@ -3,24 +3,69 @@
3
3
  */
4
4
  import { Button, __experimentalVStack as VStack } from '@wordpress/components';
5
5
  import { __ } from '@wordpress/i18n';
6
+ import { useSelect } from '@wordpress/data';
7
+ import { isReusableBlock, isTemplatePart } from '@wordpress/blocks';
6
8
 
7
9
  /**
8
10
  * Internal dependencies
9
11
  */
10
12
  import useContentOnlySectionEdit from '../../hooks/use-content-only-section-edit';
13
+ import { store as blockEditorStore } from '../../store';
11
14
 
12
- export default function EditContents( { clientId } ) {
13
- const {
14
- isWithinSection,
15
- isWithinEditedSection,
16
- editedContentOnlySection,
17
- editContentOnlySection,
18
- stopEditingContentOnlySection,
19
- } = useContentOnlySectionEdit( clientId );
15
+ function IsolatedEditButton( {
16
+ block,
17
+ onNavigateToEntityRecord,
18
+ isSyncedPattern,
19
+ isTemplatePartBlock,
20
+ } ) {
21
+ const blockAttributes = block?.attributes || {};
20
22
 
21
- if ( ! isWithinSection && ! isWithinEditedSection ) {
22
- return null;
23
- }
23
+ const handleClick = () => {
24
+ if ( isSyncedPattern ) {
25
+ onNavigateToEntityRecord( {
26
+ postId: blockAttributes.ref,
27
+ postType: 'wp_block',
28
+ } );
29
+ } else if ( isTemplatePartBlock ) {
30
+ const { theme, slug } = blockAttributes;
31
+ const templatePartId =
32
+ theme && slug ? `${ theme }//${ slug }` : null;
33
+ if ( templatePartId ) {
34
+ onNavigateToEntityRecord( {
35
+ postId: templatePartId,
36
+ postType: 'wp_template_part',
37
+ } );
38
+ }
39
+ }
40
+ };
41
+
42
+ return (
43
+ <VStack className="block-editor-block-inspector-edit-contents" expanded>
44
+ <Button
45
+ className="block-editor-block-inspector-edit-contents__button"
46
+ __next40pxDefaultSize
47
+ variant="secondary"
48
+ onClick={ handleClick }
49
+ >
50
+ { __( 'Edit section' ) }
51
+ </Button>
52
+ </VStack>
53
+ );
54
+ }
55
+
56
+ function InlineEditButton( {
57
+ clientId,
58
+ editedContentOnlySection,
59
+ editContentOnlySection,
60
+ stopEditingContentOnlySection,
61
+ } ) {
62
+ const handleClick = () => {
63
+ if ( ! editedContentOnlySection ) {
64
+ editContentOnlySection( clientId );
65
+ } else {
66
+ stopEditingContentOnlySection();
67
+ }
68
+ };
24
69
 
25
70
  return (
26
71
  <VStack className="block-editor-block-inspector-edit-contents" expanded>
@@ -28,13 +73,7 @@ export default function EditContents( { clientId } ) {
28
73
  className="block-editor-block-inspector-edit-contents__button"
29
74
  __next40pxDefaultSize
30
75
  variant="secondary"
31
- onClick={ () => {
32
- if ( ! editedContentOnlySection ) {
33
- editContentOnlySection( clientId );
34
- } else {
35
- stopEditingContentOnlySection();
36
- }
37
- } }
76
+ onClick={ handleClick }
38
77
  >
39
78
  { editedContentOnlySection
40
79
  ? __( 'Exit section' )
@@ -43,3 +82,54 @@ export default function EditContents( { clientId } ) {
43
82
  </VStack>
44
83
  );
45
84
  }
85
+
86
+ export default function EditContents( { clientId } ) {
87
+ const {
88
+ isWithinSection,
89
+ isWithinEditedSection,
90
+ editedContentOnlySection,
91
+ editContentOnlySection,
92
+ stopEditingContentOnlySection,
93
+ } = useContentOnlySectionEdit( clientId );
94
+
95
+ const { block, onNavigateToEntityRecord } = useSelect(
96
+ ( select ) => {
97
+ const { getBlock, getSettings } = select( blockEditorStore );
98
+ return {
99
+ block: getBlock( clientId ),
100
+ onNavigateToEntityRecord:
101
+ getSettings().onNavigateToEntityRecord,
102
+ };
103
+ },
104
+ [ clientId ]
105
+ );
106
+
107
+ if ( ! isWithinSection && ! isWithinEditedSection ) {
108
+ return null;
109
+ }
110
+
111
+ const isSyncedPattern = isReusableBlock( block );
112
+ const isTemplatePartBlock = isTemplatePart( block );
113
+ const shouldUseIsolatedEditor =
114
+ ( isSyncedPattern || isTemplatePartBlock ) && onNavigateToEntityRecord;
115
+
116
+ if ( shouldUseIsolatedEditor ) {
117
+ return (
118
+ <IsolatedEditButton
119
+ block={ block }
120
+ onNavigateToEntityRecord={ onNavigateToEntityRecord }
121
+ isSyncedPattern={ isSyncedPattern }
122
+ isTemplatePartBlock={ isTemplatePartBlock }
123
+ />
124
+ );
125
+ }
126
+
127
+ return (
128
+ <InlineEditButton
129
+ clientId={ clientId }
130
+ editedContentOnlySection={ editedContentOnlySection }
131
+ editContentOnlySection={ editContentOnlySection }
132
+ stopEditingContentOnlySection={ stopEditingContentOnlySection }
133
+ />
134
+ );
135
+ }
@@ -86,8 +86,9 @@ function StyleInspectorSlots( {
86
86
  function BlockInspector() {
87
87
  const {
88
88
  selectedBlockCount,
89
- selectedBlockName,
90
89
  selectedBlockClientId,
90
+ renderedBlockName,
91
+ renderedBlockClientId,
91
92
  blockType,
92
93
  isSectionBlock,
93
94
  isSectionBlockInSelection,
@@ -109,29 +110,30 @@ function BlockInspector() {
109
110
  const isWithinEditedSection = isWithinEditedContentOnlySection(
110
111
  _selectedBlockClientId
111
112
  );
112
- const renderedBlockClientId = isWithinEditedSection
113
+ const _renderedBlockClientId = isWithinEditedSection
113
114
  ? _selectedBlockClientId
114
115
  : getParentSectionBlock( _selectedBlockClientId ) ||
115
116
  _selectedBlockClientId;
116
- const _selectedBlockName =
117
- renderedBlockClientId && getBlockName( renderedBlockClientId );
117
+ const _renderedBlockName =
118
+ _renderedBlockClientId && getBlockName( _renderedBlockClientId );
118
119
  const _blockType =
119
- _selectedBlockName && getBlockType( _selectedBlockName );
120
+ _renderedBlockName && getBlockType( _renderedBlockName );
120
121
  const selectedBlockClientIds = getSelectedBlockClientIds();
121
122
  const _isSectionBlockInSelection = selectedBlockClientIds.some(
122
123
  ( id ) => _isSectionBlock( id )
123
124
  );
124
125
  const blockStyles =
125
- _selectedBlockName && getBlockStyles( _selectedBlockName );
126
+ _renderedBlockName && getBlockStyles( _renderedBlockName );
126
127
  const _hasBlockStyles = blockStyles && blockStyles.length > 0;
127
128
 
128
129
  return {
129
130
  selectedBlockCount: getSelectedBlockCount(),
130
- selectedBlockClientId: renderedBlockClientId,
131
- selectedBlockName: _selectedBlockName,
131
+ selectedBlockClientId: _selectedBlockClientId,
132
+ renderedBlockClientId: _renderedBlockClientId,
133
+ renderedBlockName: _renderedBlockName,
132
134
  blockType: _blockType,
133
135
  isSectionBlockInSelection: _isSectionBlockInSelection,
134
- isSectionBlock: _isSectionBlock( renderedBlockClientId ),
136
+ isSectionBlock: _isSectionBlock( _renderedBlockClientId ),
135
137
  hasBlockStyles: _hasBlockStyles,
136
138
  editedContentOnlySection: getEditedContentOnlySection(),
137
139
  };
@@ -140,7 +142,7 @@ function BlockInspector() {
140
142
  // Separate useSelect for contentClientIds with proper dependencies
141
143
  const contentClientIds = useSelect(
142
144
  ( select ) => {
143
- if ( ! isSectionBlock || ! selectedBlockClientId ) {
145
+ if ( ! isSectionBlock || ! renderedBlockClientId ) {
144
146
  return [];
145
147
  }
146
148
 
@@ -151,7 +153,7 @@ function BlockInspector() {
151
153
  } = unlock( select( blockEditorStore ) );
152
154
 
153
155
  const descendants = getClientIdsOfDescendants(
154
- selectedBlockClientId
156
+ renderedBlockClientId
155
157
  );
156
158
 
157
159
  // Temporary workaround for issue #71991
@@ -182,7 +184,7 @@ function BlockInspector() {
182
184
  );
183
185
  } );
184
186
  },
185
- [ isSectionBlock, selectedBlockClientId ]
187
+ [ isSectionBlock, renderedBlockClientId ]
186
188
  );
187
189
 
188
190
  const availableTabs = useInspectorControlsTabs(
@@ -212,7 +214,7 @@ function BlockInspector() {
212
214
  <InspectorControlsTabs tabs={ availableTabs } />
213
215
  ) : (
214
216
  <StyleInspectorSlots
215
- blockName={ selectedBlockName }
217
+ blockName={ renderedBlockName }
216
218
  showAdvancedControls={ false }
217
219
  showPositionControls={ false }
218
220
  showBindingsControls={ false }
@@ -230,15 +232,15 @@ function BlockInspector() {
230
232
  );
231
233
  }
232
234
 
233
- const isSelectedBlockUnregistered =
234
- selectedBlockName === getUnregisteredTypeHandlerName();
235
+ const isRenderedBlockUnregistered =
236
+ renderedBlockName === getUnregisteredTypeHandlerName();
235
237
 
236
238
  /*
237
- * If the selected block is of an unregistered type, avoid showing it as an actual selection
239
+ * If the rendered block is of an unregistered type, avoid showing it as an actual selection
238
240
  * because we want the user to focus on the unregistered block warning, not block settings.
239
241
  */
240
242
  const shouldShowWarning =
241
- ! blockType || ! selectedBlockClientId || isSelectedBlockUnregistered;
243
+ ! blockType || ! renderedBlockClientId || isRenderedBlockUnregistered;
242
244
 
243
245
  if ( shouldShowWarning ) {
244
246
  return (
@@ -256,14 +258,15 @@ function BlockInspector() {
256
258
  blockInspectorAnimationSettings={
257
259
  blockInspectorAnimationSettings
258
260
  }
259
- selectedBlockClientId={ selectedBlockClientId }
261
+ renderedBlockClientId={ renderedBlockClientId }
260
262
  >
261
263
  { children }
262
264
  </AnimatedContainer>
263
265
  ) }
264
266
  >
265
267
  <BlockInspectorSingleBlock
266
- clientId={ selectedBlockClientId }
268
+ renderedBlockClientId={ renderedBlockClientId }
269
+ selectedBlockClientId={ selectedBlockClientId }
267
270
  blockName={ blockType.name }
268
271
  isSectionBlock={ isSectionBlock }
269
272
  availableTabs={ availableTabs }
@@ -281,7 +284,7 @@ const BlockInspectorSingleBlockWrapper = ( { animate, wrapper, children } ) => {
281
284
 
282
285
  const AnimatedContainer = ( {
283
286
  blockInspectorAnimationSettings,
284
- selectedBlockClientId,
287
+ renderedBlockClientId,
285
288
  children,
286
289
  } ) => {
287
290
  const animationOrigin =
@@ -304,7 +307,7 @@ const AnimatedContainer = ( {
304
307
  x: animationOrigin,
305
308
  opacity: 0,
306
309
  } }
307
- key={ selectedBlockClientId }
310
+ key={ renderedBlockClientId }
308
311
  >
309
312
  { children }
310
313
  </motion.div>
@@ -312,7 +315,13 @@ const AnimatedContainer = ( {
312
315
  };
313
316
 
314
317
  const BlockInspectorSingleBlock = ( {
315
- clientId,
318
+ // The block that is displayed in the inspector. This is the block whose
319
+ // controls and information are shown to the user.
320
+ renderedBlockClientId,
321
+ // The actual block that is selected in the editor. This may or may not
322
+ // be the same as the rendered block (e.g., when a child block is selected
323
+ // but its parent section block is the main one rendered in the inspector).
324
+ selectedBlockClientId,
316
325
  blockName,
317
326
  isSectionBlock,
318
327
  availableTabs,
@@ -324,13 +333,18 @@ const BlockInspectorSingleBlock = ( {
324
333
  const hasParentChildBlockCards =
325
334
  window?.__experimentalContentOnlyPatternInsertion &&
326
335
  editedContentOnlySection &&
327
- editedContentOnlySection !== clientId;
336
+ editedContentOnlySection !== renderedBlockClientId;
328
337
  const parentBlockInformation = useBlockDisplayInformation(
329
338
  editedContentOnlySection
330
339
  );
331
- const blockInformation = useBlockDisplayInformation( clientId );
340
+ const blockInformation = useBlockDisplayInformation(
341
+ renderedBlockClientId
342
+ );
332
343
  const isBlockSynced = blockInformation.isSynced;
333
344
  const shouldShowTabs = ! isBlockSynced && hasMultipleTabs;
345
+ const isSectionBlockSelected =
346
+ window?.__experimentalContentOnlyPatternInsertion &&
347
+ selectedBlockClientId === renderedBlockClientId;
334
348
 
335
349
  return (
336
350
  <div className="block-editor-block-inspector">
@@ -346,16 +360,16 @@ const BlockInspectorSingleBlock = ( {
346
360
  allowParentNavigation
347
361
  className={ isBlockSynced && 'is-synced' }
348
362
  isChild={ hasParentChildBlockCards }
349
- clientId={ clientId }
363
+ clientId={ renderedBlockClientId }
350
364
  />
351
365
  { window?.__experimentalContentOnlyPatternInsertion && (
352
- <EditContents clientId={ clientId } />
366
+ <EditContents clientId={ renderedBlockClientId } />
353
367
  ) }
354
- <BlockVariationTransforms blockClientId={ clientId } />
368
+ <BlockVariationTransforms blockClientId={ renderedBlockClientId } />
355
369
  { shouldShowTabs && (
356
370
  <InspectorControlsTabs
357
371
  hasBlockStyles={ hasBlockStyles }
358
- clientId={ clientId }
372
+ clientId={ renderedBlockClientId }
359
373
  blockName={ blockName }
360
374
  tabs={ availableTabs }
361
375
  isSectionBlock={ isSectionBlock }
@@ -365,10 +379,10 @@ const BlockInspectorSingleBlock = ( {
365
379
  { ! shouldShowTabs && (
366
380
  <>
367
381
  { hasBlockStyles && (
368
- <BlockStylesPanel clientId={ clientId } />
382
+ <BlockStylesPanel clientId={ renderedBlockClientId } />
369
383
  ) }
370
384
  <ContentTab
371
- rootClientId={ clientId }
385
+ rootClientId={ renderedBlockClientId }
372
386
  contentClientIds={ contentClientIds }
373
387
  />
374
388
  { ! isSectionBlock && (
@@ -377,6 +391,15 @@ const BlockInspectorSingleBlock = ( {
377
391
  showListControls
378
392
  />
379
393
  ) }
394
+ { isSectionBlock &&
395
+ isBlockSynced &&
396
+ isSectionBlockSelected && (
397
+ <>
398
+ <InspectorControls.Slot />
399
+ { /* Allow AdvancedControls so users can adjust local attributes (e.g. additional CSS classes, HTML element). */ }
400
+ <AdvancedControls />
401
+ </>
402
+ ) }
380
403
  </>
381
404
  ) }
382
405
  <SkipToSelectedBlock key="back" />
@@ -3,11 +3,14 @@
3
3
  */
4
4
  import { MenuItem } from '@wordpress/components';
5
5
  import { _x } from '@wordpress/i18n';
6
+ import { useSelect } from '@wordpress/data';
7
+ import { isReusableBlock, isTemplatePart } from '@wordpress/blocks';
6
8
 
7
9
  /**
8
10
  * Internal dependencies
9
11
  */
10
12
  import useContentOnlySectionEdit from '../../hooks/use-content-only-section-edit';
13
+ import { store as blockEditorStore } from '../../store';
11
14
 
12
15
  export function EditSectionMenuItem( { clientId, onClose } ) {
13
16
  const {
@@ -16,6 +19,18 @@ export function EditSectionMenuItem( { clientId, onClose } ) {
16
19
  editContentOnlySection,
17
20
  } = useContentOnlySectionEdit( clientId );
18
21
 
22
+ const { block, onNavigateToEntityRecord } = useSelect(
23
+ ( select ) => {
24
+ const { getBlock, getSettings } = select( blockEditorStore );
25
+ return {
26
+ block: getBlock( clientId ),
27
+ onNavigateToEntityRecord:
28
+ getSettings().onNavigateToEntityRecord,
29
+ };
30
+ },
31
+ [ clientId ]
32
+ );
33
+
19
34
  // Only show when the experiment is enabled, the block is a section block,
20
35
  // and we're not already editing it
21
36
  if (
@@ -26,13 +41,42 @@ export function EditSectionMenuItem( { clientId, onClose } ) {
26
41
  return null;
27
42
  }
28
43
 
44
+ const blockAttributes = block?.attributes || {};
45
+
46
+ // Synced patterns and template parts should navigate to the isolated editor
47
+ const isSyncedPattern = isReusableBlock( block );
48
+ const isTemplatePartBlock = isTemplatePart( block );
49
+ const shouldNavigateToIsolatedEditor =
50
+ ( isSyncedPattern || isTemplatePartBlock ) && onNavigateToEntityRecord;
51
+
52
+ const handleClick = () => {
53
+ if ( shouldNavigateToIsolatedEditor ) {
54
+ // Navigate to isolated editor for synced patterns and template parts
55
+ if ( isSyncedPattern ) {
56
+ onNavigateToEntityRecord( {
57
+ postId: blockAttributes.ref,
58
+ postType: 'wp_block',
59
+ } );
60
+ } else if ( isTemplatePartBlock ) {
61
+ const { theme, slug } = blockAttributes;
62
+ const templatePartId =
63
+ theme && slug ? `${ theme }//${ slug }` : null;
64
+ if ( templatePartId ) {
65
+ onNavigateToEntityRecord( {
66
+ postId: templatePartId,
67
+ postType: 'wp_template_part',
68
+ } );
69
+ }
70
+ }
71
+ } else {
72
+ // Use spotlight mode for unsynced patterns
73
+ editContentOnlySection( clientId );
74
+ }
75
+ onClose();
76
+ };
77
+
29
78
  return (
30
- <MenuItem
31
- onClick={ () => {
32
- editContentOnlySection( clientId );
33
- onClose();
34
- } }
35
- >
79
+ <MenuItem onClick={ handleClick }>
36
80
  { _x( 'Edit section', 'Editing a section in the Editor' ) }
37
81
  </MenuItem>
38
82
  );
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { getBlockType } from '@wordpress/blocks';
5
4
  import { useMemo } from '@wordpress/element';
6
5
 
7
6
  /**
@@ -16,11 +15,10 @@ export default function BlockStylesPreviewPanel( {
16
15
  className,
17
16
  activeStyle,
18
17
  } ) {
19
- const example = getBlockType( genericPreviewBlock.name )?.example;
20
18
  const styleClassName = replaceActiveStyle( className, activeStyle, style );
21
19
  const previewBlocks = useMemo( () => {
22
20
  return {
23
- ...genericPreviewBlock,
21
+ name: genericPreviewBlock.name,
24
22
  title: style.label || style.name,
25
23
  description: style.description,
26
24
  initialAttributes: {
@@ -29,9 +27,9 @@ export default function BlockStylesPreviewPanel( {
29
27
  styleClassName +
30
28
  ' block-editor-block-styles__block-preview-container',
31
29
  },
32
- example,
30
+ example: genericPreviewBlock,
33
31
  };
34
- }, [ genericPreviewBlock, styleClassName ] );
32
+ }, [ genericPreviewBlock, style, styleClassName ] );
35
33
 
36
34
  return <InserterPreviewPanel item={ previewBlocks } />;
37
35
  }
@@ -37,7 +37,7 @@ function useGenericPreviewBlock( block, type ) {
37
37
  if ( block ) {
38
38
  return cloneBlock( block );
39
39
  }
40
- }, [ type?.example ? block?.name : block, type ] );
40
+ }, [ block, type?.example, type?.name ] );
41
41
  }
42
42
 
43
43
  /**
@@ -63,7 +63,7 @@ export default function useStylesForBlocks( { clientId, onSwitch } ) {
63
63
  const { getBlockStyles } = select( blocksStore );
64
64
 
65
65
  return {
66
- block,
66
+ block: ! blockType?.example ? block : null,
67
67
  blockType,
68
68
  styles: getBlockStyles( block.name ),
69
69
  className: block.attributes.className || '',