@wordpress/block-editor 15.8.0 → 15.8.1-next.dc3f6d3c1.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 (187) hide show
  1. package/build/components/block-inspector/edit-contents.js +19 -23
  2. package/build/components/block-inspector/edit-contents.js.map +3 -3
  3. package/build/components/block-inspector/index.js +7 -1
  4. package/build/components/block-inspector/index.js.map +2 -2
  5. package/build/components/block-list/block.js +4 -0
  6. package/build/components/block-list/block.js.map +2 -2
  7. package/build/components/block-list/use-block-props/index.js +3 -1
  8. package/build/components/block-list/use-block-props/index.js.map +2 -2
  9. package/build/components/block-list/use-block-props/use-is-hovered.js +16 -10
  10. package/build/components/block-list/use-block-props/use-is-hovered.js.map +2 -2
  11. package/build/components/block-settings-menu-controls/edit-section-menu-item.js +64 -0
  12. package/build/components/block-settings-menu-controls/edit-section-menu-item.js.map +7 -0
  13. package/build/components/block-settings-menu-controls/index.js +8 -0
  14. package/build/components/block-settings-menu-controls/index.js.map +2 -2
  15. package/build/components/block-toolbar/block-toolbar-icon.js +9 -9
  16. package/build/components/block-toolbar/block-toolbar-icon.js.map +2 -2
  17. package/build/components/block-variation-transforms/index.js +32 -5
  18. package/build/components/block-variation-transforms/index.js.map +2 -2
  19. package/build/components/border-radius-control/single-input-control.js +1 -0
  20. package/build/components/border-radius-control/single-input-control.js.map +2 -2
  21. package/build/components/content-only-controls/index.js +263 -0
  22. package/build/components/content-only-controls/index.js.map +7 -0
  23. package/build/components/content-only-controls/link/index.js +204 -0
  24. package/build/components/content-only-controls/link/index.js.map +7 -0
  25. package/build/components/content-only-controls/media/index.js +264 -0
  26. package/build/components/content-only-controls/media/index.js.map +7 -0
  27. package/build/components/content-only-controls/plain-text/index.js +68 -0
  28. package/build/components/content-only-controls/plain-text/index.js.map +7 -0
  29. package/build/components/content-only-controls/rich-text/index.js +197 -0
  30. package/build/components/content-only-controls/rich-text/index.js.map +7 -0
  31. package/build/components/content-only-controls/use-inspector-popover-placement.js +41 -0
  32. package/build/components/content-only-controls/use-inspector-popover-placement.js.map +7 -0
  33. package/build/components/global-styles/typography-panel.js +16 -10
  34. package/build/components/global-styles/typography-panel.js.map +2 -2
  35. package/build/components/inserter/media-tab/media-tab.js +1 -33
  36. package/build/components/inserter/media-tab/media-tab.js.map +3 -3
  37. package/build/components/inspector-controls-tabs/content-tab.js +6 -2
  38. package/build/components/inspector-controls-tabs/content-tab.js.map +3 -3
  39. package/build/components/inspector-controls-tabs/index.js +7 -1
  40. package/build/components/inspector-controls-tabs/index.js.map +2 -2
  41. package/build/components/list-view/block-select-button.js +11 -4
  42. package/build/components/list-view/block-select-button.js.map +2 -2
  43. package/build/components/media-placeholder/index.js +1 -31
  44. package/build/components/media-placeholder/index.js.map +3 -3
  45. package/build/components/media-replace-flow/index.js +4 -30
  46. package/build/components/media-replace-flow/index.js.map +3 -3
  47. package/build/components/rich-text/format-edit.js +9 -1
  48. package/build/components/rich-text/format-edit.js.map +2 -2
  49. package/build/components/use-block-display-information/index.js +21 -1
  50. package/build/components/use-block-display-information/index.js.map +3 -3
  51. package/build/hooks/block-bindings.js +52 -61
  52. package/build/hooks/block-bindings.js.map +3 -3
  53. package/build/hooks/use-content-only-section-edit.js +67 -0
  54. package/build/hooks/use-content-only-section-edit.js.map +7 -0
  55. package/build/layouts/constrained.js +2 -2
  56. package/build/layouts/constrained.js.map +2 -2
  57. package/build/private-apis.js +2 -3
  58. package/build/private-apis.js.map +3 -3
  59. package/build/store/private-keys.js +3 -0
  60. package/build/store/private-keys.js.map +2 -2
  61. package/build/store/private-selectors.js +1 -2
  62. package/build/store/private-selectors.js.map +2 -2
  63. package/build/store/reducer.js +1 -2
  64. package/build/store/reducer.js.map +2 -2
  65. package/build/store/selectors.js +3 -0
  66. package/build/store/selectors.js.map +2 -2
  67. package/build/utils/fit-text-utils.js +9 -1
  68. package/build/utils/fit-text-utils.js.map +2 -2
  69. package/build-module/components/block-inspector/edit-contents.js +9 -23
  70. package/build-module/components/block-inspector/edit-contents.js.map +2 -2
  71. package/build-module/components/block-inspector/index.js +7 -1
  72. package/build-module/components/block-inspector/index.js.map +2 -2
  73. package/build-module/components/block-list/block.js +4 -0
  74. package/build-module/components/block-list/block.js.map +2 -2
  75. package/build-module/components/block-list/use-block-props/index.js +3 -1
  76. package/build-module/components/block-list/use-block-props/index.js.map +2 -2
  77. package/build-module/components/block-list/use-block-props/use-is-hovered.js +16 -10
  78. package/build-module/components/block-list/use-block-props/use-is-hovered.js.map +2 -2
  79. package/build-module/components/block-settings-menu-controls/edit-section-menu-item.js +29 -0
  80. package/build-module/components/block-settings-menu-controls/edit-section-menu-item.js.map +7 -0
  81. package/build-module/components/block-settings-menu-controls/index.js +8 -0
  82. package/build-module/components/block-settings-menu-controls/index.js.map +2 -2
  83. package/build-module/components/block-toolbar/block-toolbar-icon.js +10 -10
  84. package/build-module/components/block-toolbar/block-toolbar-icon.js.map +2 -2
  85. package/build-module/components/block-variation-transforms/index.js +32 -5
  86. package/build-module/components/block-variation-transforms/index.js.map +2 -2
  87. package/build-module/components/border-radius-control/single-input-control.js +1 -0
  88. package/build-module/components/border-radius-control/single-input-control.js.map +2 -2
  89. package/build-module/components/content-only-controls/index.js +237 -0
  90. package/build-module/components/content-only-controls/index.js.map +7 -0
  91. package/build-module/components/content-only-controls/link/index.js +172 -0
  92. package/build-module/components/content-only-controls/link/index.js.map +7 -0
  93. package/build-module/components/content-only-controls/media/index.js +243 -0
  94. package/build-module/components/content-only-controls/media/index.js.map +7 -0
  95. package/build-module/components/content-only-controls/plain-text/index.js +50 -0
  96. package/build-module/components/content-only-controls/plain-text/index.js.map +7 -0
  97. package/build-module/components/content-only-controls/rich-text/index.js +174 -0
  98. package/build-module/components/content-only-controls/rich-text/index.js.map +7 -0
  99. package/build-module/components/content-only-controls/use-inspector-popover-placement.js +16 -0
  100. package/build-module/components/content-only-controls/use-inspector-popover-placement.js.map +7 -0
  101. package/build-module/components/global-styles/typography-panel.js +18 -11
  102. package/build-module/components/global-styles/typography-panel.js.map +2 -2
  103. package/build-module/components/inserter/media-tab/media-tab.js +2 -34
  104. package/build-module/components/inserter/media-tab/media-tab.js.map +2 -2
  105. package/build-module/components/inspector-controls-tabs/content-tab.js +7 -3
  106. package/build-module/components/inspector-controls-tabs/content-tab.js.map +2 -2
  107. package/build-module/components/inspector-controls-tabs/index.js +7 -1
  108. package/build-module/components/inspector-controls-tabs/index.js.map +2 -2
  109. package/build-module/components/list-view/block-select-button.js +18 -5
  110. package/build-module/components/list-view/block-select-button.js.map +2 -2
  111. package/build-module/components/media-placeholder/index.js +1 -31
  112. package/build-module/components/media-placeholder/index.js.map +2 -2
  113. package/build-module/components/media-replace-flow/index.js +4 -30
  114. package/build-module/components/media-replace-flow/index.js.map +2 -2
  115. package/build-module/components/rich-text/format-edit.js +9 -1
  116. package/build-module/components/rich-text/format-edit.js.map +2 -2
  117. package/build-module/components/use-block-display-information/index.js +21 -1
  118. package/build-module/components/use-block-display-information/index.js.map +3 -3
  119. package/build-module/hooks/block-bindings.js +57 -62
  120. package/build-module/hooks/block-bindings.js.map +2 -2
  121. package/build-module/hooks/use-content-only-section-edit.js +46 -0
  122. package/build-module/hooks/use-content-only-section-edit.js.map +7 -0
  123. package/build-module/layouts/constrained.js +2 -2
  124. package/build-module/layouts/constrained.js.map +2 -2
  125. package/build-module/private-apis.js +3 -3
  126. package/build-module/private-apis.js.map +2 -2
  127. package/build-module/store/private-keys.js +2 -0
  128. package/build-module/store/private-keys.js.map +2 -2
  129. package/build-module/store/private-selectors.js +1 -2
  130. package/build-module/store/private-selectors.js.map +2 -2
  131. package/build-module/store/reducer.js +1 -2
  132. package/build-module/store/reducer.js.map +2 -2
  133. package/build-module/store/selectors.js +3 -0
  134. package/build-module/store/selectors.js.map +2 -2
  135. package/build-module/utils/fit-text-utils.js +9 -1
  136. package/build-module/utils/fit-text-utils.js.map +2 -2
  137. package/build-style/style-rtl.css +132 -0
  138. package/build-style/style.css +132 -0
  139. package/package.json +37 -37
  140. package/src/components/block-inspector/edit-contents.js +10 -29
  141. package/src/components/block-inspector/index.js +4 -2
  142. package/src/components/block-list/block.js +6 -0
  143. package/src/components/block-list/use-block-props/index.js +3 -1
  144. package/src/components/block-list/use-block-props/use-is-hovered.js +24 -12
  145. package/src/components/block-settings-menu-controls/edit-section-menu-item.js +39 -0
  146. package/src/components/block-settings-menu-controls/index.js +7 -0
  147. package/src/components/block-switcher/block-transformations-menu.native.js +0 -1
  148. package/src/components/block-toolbar/block-toolbar-icon.js +14 -10
  149. package/src/components/block-toolbar/test/__snapshots__/block-toolbar-menu.native.js.snap +6 -4
  150. package/src/components/block-toolbar/test/block-toolbar-menu.native.js +2 -2
  151. package/src/components/block-variation-transforms/index.js +96 -35
  152. package/src/components/border-radius-control/single-input-control.js +1 -0
  153. package/src/components/content-only-controls/index.js +296 -0
  154. package/src/components/content-only-controls/link/index.js +195 -0
  155. package/src/components/content-only-controls/link/styles.scss +23 -0
  156. package/src/components/content-only-controls/media/index.js +285 -0
  157. package/src/components/content-only-controls/media/styles.scss +47 -0
  158. package/src/components/content-only-controls/plain-text/index.js +49 -0
  159. package/src/components/content-only-controls/rich-text/index.js +193 -0
  160. package/src/components/content-only-controls/rich-text/styles.scss +24 -0
  161. package/src/components/content-only-controls/styles.scss +35 -0
  162. package/src/components/content-only-controls/use-inspector-popover-placement.js +19 -0
  163. package/src/components/global-styles/typography-panel.js +12 -0
  164. package/src/components/inserter/media-tab/media-tab.js +2 -44
  165. package/src/components/inspector-controls-tabs/content-tab.js +12 -4
  166. package/src/components/inspector-controls-tabs/index.js +4 -1
  167. package/src/components/list-view/block-select-button.js +37 -24
  168. package/src/components/media-placeholder/index.js +1 -41
  169. package/src/components/media-replace-flow/index.js +3 -39
  170. package/src/components/rich-text/format-edit.js +9 -1
  171. package/src/components/use-block-display-information/index.js +30 -2
  172. package/src/hooks/block-bindings.js +71 -82
  173. package/src/hooks/use-content-only-section-edit.js +63 -0
  174. package/src/layouts/constrained.js +8 -2
  175. package/src/private-apis.js +2 -2
  176. package/src/store/private-keys.js +1 -0
  177. package/src/store/private-selectors.js +1 -2
  178. package/src/store/reducer.js +0 -3
  179. package/src/store/selectors.js +7 -0
  180. package/src/store/test/reducer.js +7 -17
  181. package/src/style.scss +1 -0
  182. package/src/utils/fit-text-utils.js +19 -1
  183. package/build/components/media-upload-modal/index.js +0 -29
  184. package/build/components/media-upload-modal/index.js.map +0 -7
  185. package/build-module/components/media-upload-modal/index.js +0 -8
  186. package/build-module/components/media-upload-modal/index.js.map +0 -7
  187. package/src/components/media-upload-modal/index.js +0 -18
@@ -4,7 +4,7 @@
4
4
  import { ToolbarButton } from '@wordpress/components';
5
5
  import { __ } from '@wordpress/i18n';
6
6
  import { useSelect } from '@wordpress/data';
7
- import { copy } from '@wordpress/icons';
7
+ import { copy, symbol } from '@wordpress/icons';
8
8
  import { getBlockType, store as blocksStore } from '@wordpress/blocks';
9
9
  import { store as preferencesStore } from '@wordpress/preferences';
10
10
 
@@ -24,7 +24,6 @@ function getBlockIconVariant( { select, clientIds } ) {
24
24
  getBlockName,
25
25
  getBlockAttributes,
26
26
  getBlockParentsByBlockName,
27
- isSectionBlock,
28
27
  canRemoveBlocks,
29
28
  getTemplateLock,
30
29
  getBlockEditingMode,
@@ -40,8 +39,8 @@ function getBlockIconVariant( { select, clientIds } ) {
40
39
  const blockName = isSingleBlock && getBlockName( clientIds[ 0 ] );
41
40
  const hasBlockStyles =
42
41
  isSingleBlock && !! getBlockStyles( blockName )?.length;
43
- const isSectionInSelection = clientIds.some( ( id ) =>
44
- isSectionBlock( id )
42
+ const hasPatternNameInSelection = clientIds.some(
43
+ ( id ) => !! getBlockAttributes( id )?.metadata?.patternName
45
44
  );
46
45
  const hasPatternOverrides = clientIds.every( ( clientId ) =>
47
46
  hasPatternOverridesDefaultBinding(
@@ -59,7 +58,7 @@ function getBlockIconVariant( { select, clientIds } ) {
59
58
  getBlockEditingMode( clientIds[ 0 ] ) === 'default';
60
59
  const _hideTransformsForSections =
61
60
  window?.__experimentalContentOnlyPatternInsertion &&
62
- isSectionInSelection;
61
+ hasPatternNameInSelection;
63
62
  const _showBlockSwitcher =
64
63
  ! _hideTransformsForSections &&
65
64
  isDefaultEditingMode &&
@@ -81,19 +80,24 @@ function getBlockIcon( { select, clientIds } ) {
81
80
  const { getBlockName, getBlockAttributes } = unlock(
82
81
  select( blockEditorStore )
83
82
  );
84
- const { getActiveBlockVariation } = select( blocksStore );
85
83
 
86
84
  const _isSingleBlock = clientIds.length === 1;
87
85
  const firstClientId = clientIds[ 0 ];
86
+ const blockAttributes = getBlockAttributes( firstClientId );
87
+ if (
88
+ _isSingleBlock &&
89
+ blockAttributes?.metadata?.patternName &&
90
+ window?.__experimentalContentOnlyPatternInsertion
91
+ ) {
92
+ return symbol;
93
+ }
88
94
 
89
95
  const blockName = getBlockName( firstClientId );
90
96
  const blockType = getBlockType( blockName );
91
97
 
92
98
  if ( _isSingleBlock ) {
93
- const match = getActiveBlockVariation(
94
- blockName,
95
- getBlockAttributes( firstClientId )
96
- );
99
+ const { getActiveBlockVariation } = select( blocksStore );
100
+ const match = getActiveBlockVariation( blockName, blockAttributes );
97
101
  return match?.icon || blockType?.icon;
98
102
  }
99
103
 
@@ -68,10 +68,12 @@ exports[`Block Actions Menu block options duplicates a block 1`] = `
68
68
  <!-- /wp:heading -->"
69
69
  `;
70
70
 
71
- exports[`Block Actions Menu block options transforms a Paragraph block into a Pullquote block 1`] = `
72
- "<!-- wp:pullquote -->
73
- <figure class="wp-block-pullquote"><blockquote><p>Hello!</p></blockquote></figure>
74
- <!-- /wp:pullquote -->
71
+ exports[`Block Actions Menu block options transforms a Paragraph block into a Quote block 1`] = `
72
+ "<!-- wp:quote -->
73
+ <blockquote class="wp-block-quote"><!-- wp:paragraph -->
74
+ <p>Hello!</p>
75
+ <!-- /wp:paragraph --></blockquote>
76
+ <!-- /wp:quote -->
75
77
 
76
78
  <!-- wp:spacer -->
77
79
  <div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>
@@ -357,7 +357,7 @@ describe( 'Block Actions Menu', () => {
357
357
  expect( getEditorHtml() ).toMatchSnapshot();
358
358
  } );
359
359
 
360
- it( 'transforms a Paragraph block into a Pullquote block', async () => {
360
+ it( 'transforms a Paragraph block into a Quote block', async () => {
361
361
  const screen = await initializeEditor();
362
362
  const { getByLabelText, getByRole } = screen;
363
363
 
@@ -397,7 +397,7 @@ describe( 'Block Actions Menu', () => {
397
397
  expect( headerTitle ).toBeVisible();
398
398
 
399
399
  // Tap on the Transform block button
400
- fireEvent.press( getByLabelText( /Pullquote/ ) );
400
+ fireEvent.press( getByLabelText( /Quote/ ) );
401
401
 
402
402
  expect( getEditorHtml() ).toMatchSnapshot();
403
403
  } );
@@ -147,41 +147,102 @@ function VariationsToggleGroupControl( {
147
147
 
148
148
  function __experimentalBlockVariationTransforms( { blockClientId } ) {
149
149
  const { updateBlockAttributes } = useDispatch( blockEditorStore );
150
- const { activeBlockVariation, variations, isContentOnly, isSection } =
151
- useSelect(
152
- ( select ) => {
153
- const { getActiveBlockVariation, getBlockVariations } =
154
- select( blocksStore );
155
-
156
- const {
157
- getBlockName,
158
- getBlockAttributes,
159
- getBlockEditingMode,
160
- isSectionBlock,
161
- } = unlock( select( blockEditorStore ) );
162
-
163
- const name = blockClientId && getBlockName( blockClientId );
164
-
165
- const { hasContentRoleAttribute } = unlock(
166
- select( blocksStore )
167
- );
168
- const isContentBlock = hasContentRoleAttribute( name );
169
-
170
- return {
171
- activeBlockVariation: getActiveBlockVariation(
172
- name,
173
- getBlockAttributes( blockClientId ),
174
- 'transform'
175
- ),
176
- variations: name && getBlockVariations( name, 'transform' ),
177
- isContentOnly:
178
- getBlockEditingMode( blockClientId ) ===
179
- 'contentOnly' && ! isContentBlock,
180
- isSection: isSectionBlock( blockClientId ),
181
- };
182
- },
183
- [ blockClientId ]
184
- );
150
+ const {
151
+ activeBlockVariation,
152
+ unfilteredVariations,
153
+ blockName,
154
+ isContentOnly,
155
+ isSection,
156
+ } = useSelect(
157
+ ( select ) => {
158
+ const { getActiveBlockVariation, getBlockVariations } =
159
+ select( blocksStore );
160
+
161
+ const {
162
+ getBlockName,
163
+ getBlockAttributes,
164
+ getBlockEditingMode,
165
+ isSectionBlock,
166
+ } = unlock( select( blockEditorStore ) );
167
+
168
+ const name = blockClientId && getBlockName( blockClientId );
169
+
170
+ const { hasContentRoleAttribute } = unlock( select( blocksStore ) );
171
+ const isContentBlock = hasContentRoleAttribute( name );
172
+
173
+ return {
174
+ activeBlockVariation: getActiveBlockVariation(
175
+ name,
176
+ getBlockAttributes( blockClientId ),
177
+ 'transform'
178
+ ),
179
+ unfilteredVariations:
180
+ name && getBlockVariations( name, 'transform' ),
181
+ blockName: name,
182
+ isContentOnly:
183
+ getBlockEditingMode( blockClientId ) === 'contentOnly' &&
184
+ ! isContentBlock,
185
+ isSection: isSectionBlock( blockClientId ),
186
+ };
187
+ },
188
+ [ blockClientId ]
189
+ );
190
+
191
+ /*
192
+ * Hack for WordPress 6.9
193
+ *
194
+ * The Stretchy blocks shipped in 6.9 were ultimately
195
+ * implemented as block variations of the base types Paragraph
196
+ * and Heading. See #73056 for discussion and trade-offs.
197
+ *
198
+ * The main drawback of this choice is that the Variations API
199
+ * doesn't offer enough control over how prominent and how tied
200
+ * to the base type a variation should be.
201
+ *
202
+ * In order to ship these new "blocks" with an acceptable UX,
203
+ * we need two hacks until the Variations API is improved:
204
+ *
205
+ * - Don't show the variations switcher in the block inspector
206
+ * for Paragraph, Heading, Stretchy Paragraph and Stretchy
207
+ * Heading (implemented below). Transformations are still
208
+ * available in the block switcher.
209
+ *
210
+ * - Move the stretchy variations to the end of the core blocks
211
+ * list in the block inserter (implemented in
212
+ * getInserterItems in #73056).
213
+ */
214
+ const variations = useMemo( () => {
215
+ if ( blockName === 'core/paragraph' ) {
216
+ // Always hide options when active variation is stretchy, but
217
+ // ensure that there are no third-party variations before doing the
218
+ // same elsewhere.
219
+ if (
220
+ activeBlockVariation?.name === 'stretchy-paragraph' ||
221
+ unfilteredVariations.every( ( v ) =>
222
+ [ 'paragraph', 'stretchy-paragraph' ].includes( v.name )
223
+ )
224
+ ) {
225
+ return [];
226
+ }
227
+ // If there are other variations, only hide the stretchy one.
228
+ return unfilteredVariations.filter(
229
+ ( v ) => v.name !== 'stretchy-paragraph'
230
+ );
231
+ } else if ( blockName === 'core/heading' ) {
232
+ if (
233
+ activeBlockVariation?.name === 'stretchy-heading' ||
234
+ unfilteredVariations.every( ( v ) =>
235
+ [ 'heading', 'stretchy-heading' ].includes( v.name )
236
+ )
237
+ ) {
238
+ return [];
239
+ }
240
+ return unfilteredVariations.filter(
241
+ ( v ) => v.name !== 'stretchy-heading'
242
+ );
243
+ }
244
+ return unfilteredVariations;
245
+ }, [ activeBlockVariation?.name, blockName, unfilteredVariations ] );
185
246
 
186
247
  const selectedValue = activeBlockVariation?.name;
187
248
 
@@ -74,6 +74,7 @@ export default function SingleInputControl( {
74
74
  const onChangeUnit = ( next ) => {
75
75
  const newUnits = { ...selectedUnits };
76
76
  if ( corner === 'all' ) {
77
+ newUnits.flat = next;
77
78
  newUnits.topLeft = next;
78
79
  newUnits.topRight = next;
79
80
  newUnits.bottomLeft = next;
@@ -0,0 +1,296 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { store as blocksStore } from '@wordpress/blocks';
5
+ import {
6
+ __experimentalToolsPanel as ToolsPanel,
7
+ __experimentalHStack as HStack,
8
+ Icon,
9
+ Navigator,
10
+ } from '@wordpress/components';
11
+ import { useDispatch, useSelect } from '@wordpress/data';
12
+ import { __ } from '@wordpress/i18n';
13
+ import { arrowLeft, arrowRight } from '@wordpress/icons';
14
+
15
+ /**
16
+ * Internal dependencies
17
+ */
18
+ import { unlock } from '../../lock-unlock';
19
+ import { store as blockEditorStore } from '../../store';
20
+ import BlockIcon from '../block-icon';
21
+ import useBlockDisplayTitle from '../block-title/use-block-display-title';
22
+ import useBlockDisplayInformation from '../use-block-display-information';
23
+ import { useInspectorPopoverPlacement } from './use-inspector-popover-placement';
24
+
25
+ // controls
26
+ import PlainText from './plain-text';
27
+ import RichText from './rich-text';
28
+ import Media from './media';
29
+ import Link from './link';
30
+
31
+ const controls = {
32
+ PlainText,
33
+ RichText,
34
+ Media,
35
+ Link,
36
+ };
37
+
38
+ function BlockAttributeToolsPanelItem( {
39
+ clientId,
40
+ control,
41
+ blockType,
42
+ attributeValues,
43
+ } ) {
44
+ const { updateBlockAttributes } = useDispatch( blockEditorStore );
45
+ const ControlComponent = controls[ control.type ];
46
+
47
+ if ( ! ControlComponent ) {
48
+ return null;
49
+ }
50
+
51
+ return (
52
+ <ControlComponent
53
+ clientId={ clientId }
54
+ control={ control }
55
+ blockType={ blockType }
56
+ attributeValues={ attributeValues }
57
+ updateAttributes={ ( attributes ) =>
58
+ updateBlockAttributes( clientId, attributes )
59
+ }
60
+ />
61
+ );
62
+ }
63
+
64
+ function BlockFields( { clientId } ) {
65
+ const { attributes, blockType } = useSelect(
66
+ ( select ) => {
67
+ const { getBlockAttributes, getBlockName } =
68
+ select( blockEditorStore );
69
+ const { getBlockType } = select( blocksStore );
70
+ const blockName = getBlockName( clientId );
71
+ return {
72
+ attributes: getBlockAttributes( clientId ),
73
+ blockType: getBlockType( blockName ),
74
+ };
75
+ },
76
+ [ clientId ]
77
+ );
78
+
79
+ const blockTitle = useBlockDisplayTitle( {
80
+ clientId,
81
+ context: 'list-view',
82
+ } );
83
+ const blockInformation = useBlockDisplayInformation( clientId );
84
+ const popoverPlacementProps = useInspectorPopoverPlacement();
85
+
86
+ if ( ! blockType?.fields?.length ) {
87
+ // TODO - we might still want to show a placeholder for blocks with no fields.
88
+ // for example, a way to select the block.
89
+ return null;
90
+ }
91
+
92
+ return (
93
+ <ToolsPanel
94
+ label={
95
+ <HStack spacing={ 1 }>
96
+ <BlockIcon icon={ blockInformation?.icon } />
97
+ <div>{ blockTitle }</div>
98
+ </HStack>
99
+ }
100
+ panelId={ clientId }
101
+ dropdownMenuProps={ popoverPlacementProps }
102
+ >
103
+ { blockType?.fields?.map( ( field, index ) => (
104
+ <BlockAttributeToolsPanelItem
105
+ key={ `${ clientId }/${ index }` }
106
+ clientId={ clientId }
107
+ control={ field }
108
+ blockType={ blockType }
109
+ attributeValues={ attributes }
110
+ />
111
+ ) ) }
112
+ </ToolsPanel>
113
+ );
114
+ }
115
+
116
+ function DrillDownButton( { clientId } ) {
117
+ const blockTitle = useBlockDisplayTitle( {
118
+ clientId,
119
+ context: 'list-view',
120
+ } );
121
+ const blockInformation = useBlockDisplayInformation( clientId );
122
+ return (
123
+ <div className="block-editor-content-only-controls__button-panel">
124
+ <Navigator.Button
125
+ path={ `/${ clientId }` }
126
+ className="block-editor-content-only-controls__drill-down-button"
127
+ >
128
+ <HStack expanded justify="space-between">
129
+ <HStack justify="flex-start" spacing={ 1 }>
130
+ <BlockIcon icon={ blockInformation?.icon } />
131
+ <div>{ blockTitle }</div>
132
+ </HStack>
133
+ <Icon icon={ arrowRight } />
134
+ </HStack>
135
+ </Navigator.Button>
136
+ </div>
137
+ );
138
+ }
139
+
140
+ function ContentOnlyControlsScreen( {
141
+ rootClientId,
142
+ contentClientIds,
143
+ parentClientIds,
144
+ isNested,
145
+ } ) {
146
+ const isRootContentBlock = useSelect(
147
+ ( select ) => {
148
+ const { getBlockName } = select( blockEditorStore );
149
+ const blockName = getBlockName( rootClientId );
150
+ const { hasContentRoleAttribute } = unlock( select( blocksStore ) );
151
+ return hasContentRoleAttribute( blockName );
152
+ },
153
+ [ rootClientId ]
154
+ );
155
+
156
+ if ( ! isRootContentBlock && ! contentClientIds.length ) {
157
+ return null;
158
+ }
159
+
160
+ return (
161
+ <>
162
+ { isNested && (
163
+ <div className="block-editor-content-only-controls__button-panel">
164
+ <Navigator.BackButton className="block-editor-content-only-controls__back-button">
165
+ <HStack expanded spacing={ 1 } justify="flex-start">
166
+ <Icon icon={ arrowLeft } />
167
+ <div>{ __( 'Back' ) }</div>
168
+ </HStack>
169
+ </Navigator.BackButton>
170
+ </div>
171
+ ) }
172
+ { isRootContentBlock && <BlockFields clientId={ rootClientId } /> }
173
+ { contentClientIds.map( ( clientId ) => {
174
+ if ( parentClientIds?.[ clientId ] ) {
175
+ return (
176
+ <DrillDownButton
177
+ key={ clientId }
178
+ clientId={ clientId }
179
+ />
180
+ );
181
+ }
182
+
183
+ return <BlockFields key={ clientId } clientId={ clientId } />;
184
+ } ) }
185
+ </>
186
+ );
187
+ }
188
+
189
+ export default function ContentOnlyControls( { rootClientId } ) {
190
+ const { updatedRootClientId, nestedContentClientIds, contentClientIds } =
191
+ useSelect(
192
+ ( select ) => {
193
+ const { getClientIdsOfDescendants, getBlockEditingMode } =
194
+ select( blockEditorStore );
195
+
196
+ // _nestedContentClientIds is for content blocks within 'drilldowns'.
197
+ // It's an object where the key is the parent clientId, and the element is
198
+ // an array of child clientIds whose controls are shown within the drilldown.
199
+ const _nestedContentClientIds = {};
200
+
201
+ // _contentClientIds is the list of contentClientIds for blocks being
202
+ // shown at the root level. Includes parent blocks that might have a drilldown,
203
+ // but not the children of those blocks.
204
+ const _contentClientIds = [];
205
+
206
+ // An array of all nested client ids. Used for ensuring blocks within drilldowns
207
+ // don't appear at the root level.
208
+ let allNestedClientIds = [];
209
+
210
+ // A flattened list of all content clientIds to arrange into the
211
+ // groups above.
212
+ const allContentClientIds = getClientIdsOfDescendants(
213
+ rootClientId
214
+ ).filter(
215
+ ( clientId ) =>
216
+ getBlockEditingMode( clientId ) === 'contentOnly'
217
+ );
218
+
219
+ for ( const clientId of allContentClientIds ) {
220
+ const childClientIds = getClientIdsOfDescendants(
221
+ clientId
222
+ ).filter(
223
+ ( childClientId ) =>
224
+ getBlockEditingMode( childClientId ) ===
225
+ 'contentOnly'
226
+ );
227
+
228
+ // If there's more than one child block, use a drilldown.
229
+ if (
230
+ childClientIds.length > 1 &&
231
+ ! allNestedClientIds.includes( clientId )
232
+ ) {
233
+ _nestedContentClientIds[ clientId ] = childClientIds;
234
+ allNestedClientIds = [
235
+ allNestedClientIds,
236
+ ...childClientIds,
237
+ ];
238
+ }
239
+
240
+ if ( ! allNestedClientIds.includes( clientId ) ) {
241
+ _contentClientIds.push( clientId );
242
+ }
243
+ }
244
+
245
+ // Avoid showing only one drilldown block at the root.
246
+ if (
247
+ _contentClientIds.length === 1 &&
248
+ Object.keys( _nestedContentClientIds ).length === 1
249
+ ) {
250
+ const onlyParentClientId = Object.keys(
251
+ _nestedContentClientIds
252
+ )[ 0 ];
253
+ return {
254
+ updatedRootClientId: onlyParentClientId,
255
+ contentClientIds:
256
+ _nestedContentClientIds[ onlyParentClientId ],
257
+ nestedContentClientIds: {},
258
+ };
259
+ }
260
+
261
+ return {
262
+ nestedContentClientIds: _nestedContentClientIds,
263
+ contentClientIds: _contentClientIds,
264
+ };
265
+ },
266
+ [ rootClientId ]
267
+ );
268
+
269
+ return (
270
+ <Navigator initialPath="/">
271
+ <Navigator.Screen
272
+ path="/"
273
+ className="block-editor-content-only-controls__screen"
274
+ >
275
+ <ContentOnlyControlsScreen
276
+ rootClientId={ updatedRootClientId ?? rootClientId }
277
+ contentClientIds={ contentClientIds }
278
+ parentClientIds={ nestedContentClientIds }
279
+ />
280
+ </Navigator.Screen>
281
+ { Object.keys( nestedContentClientIds ).map( ( clientId ) => (
282
+ <Navigator.Screen
283
+ key={ clientId }
284
+ path={ `/${ clientId }` }
285
+ className="block-editor-content-only-controls__screen"
286
+ >
287
+ <ContentOnlyControlsScreen
288
+ isNested
289
+ rootClientId={ clientId }
290
+ contentClientIds={ nestedContentClientIds[ clientId ] }
291
+ />
292
+ </Navigator.Screen>
293
+ ) ) }
294
+ </Navigator>
295
+ );
296
+ }