@wordpress/editor 13.30.0 → 13.32.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 (219) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +857 -0
  3. package/build/bindings/index.js +3 -1
  4. package/build/bindings/index.js.map +1 -1
  5. package/build/components/block-settings-menu/plugin-block-settings-menu-item.js +107 -0
  6. package/build/components/block-settings-menu/plugin-block-settings-menu-item.js.map +1 -0
  7. package/build/components/commands/index.js +1 -1
  8. package/build/components/commands/index.js.map +1 -1
  9. package/build/components/deprecated.js +158 -0
  10. package/build/components/deprecated.js.map +1 -1
  11. package/build/components/document-bar/index.js +7 -10
  12. package/build/components/document-bar/index.js.map +1 -1
  13. package/build/components/document-outline/index.js +1 -1
  14. package/build/components/document-outline/index.js.map +1 -1
  15. package/build/components/editor-canvas/edit-template-blocks-notification.js +2 -39
  16. package/build/components/editor-canvas/edit-template-blocks-notification.js.map +1 -1
  17. package/build/components/editor-canvas/index.js +3 -0
  18. package/build/components/editor-canvas/index.js.map +1 -1
  19. package/build/components/entities-saved-states/hooks/use-is-dirty.js +10 -16
  20. package/build/components/entities-saved-states/hooks/use-is-dirty.js.map +1 -1
  21. package/build/components/entities-saved-states/index.js +28 -88
  22. package/build/components/entities-saved-states/index.js.map +1 -1
  23. package/build/components/error-boundary/index.native.js +133 -0
  24. package/build/components/error-boundary/index.native.js.map +1 -0
  25. package/build/components/index.js +33 -8
  26. package/build/components/index.js.map +1 -1
  27. package/build/components/index.native.js +9 -1
  28. package/build/components/index.native.js.map +1 -1
  29. package/build/components/inserter-sidebar/index.js +5 -1
  30. package/build/components/inserter-sidebar/index.js.map +1 -1
  31. package/build/components/list-view-sidebar/index.js +2 -1
  32. package/build/components/list-view-sidebar/index.js.map +1 -1
  33. package/build/components/pattern-overrides-panel/index.js +30 -0
  34. package/build/components/pattern-overrides-panel/index.js.map +1 -0
  35. package/build/components/plugin-document-setting-panel/index.js +123 -0
  36. package/build/components/plugin-document-setting-panel/index.js.map +1 -0
  37. package/build/components/plugin-post-publish-panel/index.js +68 -0
  38. package/build/components/plugin-post-publish-panel/index.js.map +1 -0
  39. package/build/components/plugin-pre-publish-panel/index.js +71 -0
  40. package/build/components/plugin-pre-publish-panel/index.js.map +1 -0
  41. package/build/components/post-actions/actions.js +455 -0
  42. package/build/components/post-actions/actions.js.map +1 -0
  43. package/build/components/post-card-panel/index.js +93 -0
  44. package/build/components/post-card-panel/index.js.map +1 -0
  45. package/build/components/post-featured-image/index.js +3 -8
  46. package/build/components/post-featured-image/index.js.map +1 -1
  47. package/build/components/post-featured-image/panel.js +7 -3
  48. package/build/components/post-featured-image/panel.js.map +1 -1
  49. package/build/components/post-sync-status/index.js +0 -72
  50. package/build/components/post-sync-status/index.js.map +1 -1
  51. package/build/components/post-taxonomies/flat-term-selector.js +7 -3
  52. package/build/components/post-taxonomies/flat-term-selector.js.map +1 -1
  53. package/build/components/post-title/index.native.js +1 -1
  54. package/build/components/post-title/index.native.js.map +1 -1
  55. package/build/components/provider/disable-non-page-content-blocks.js +36 -20
  56. package/build/components/provider/disable-non-page-content-blocks.js.map +1 -1
  57. package/build/components/provider/index.js +1 -1
  58. package/build/components/provider/index.js.map +1 -1
  59. package/build/components/provider/use-block-editor-settings.js +8 -9
  60. package/build/components/provider/use-block-editor-settings.js.map +1 -1
  61. package/build/components/provider/use-hide-blocks-from-inserter.js +4 -3
  62. package/build/components/provider/use-hide-blocks-from-inserter.js.map +1 -1
  63. package/build/components/template-areas/index.js +70 -0
  64. package/build/components/template-areas/index.js.map +1 -0
  65. package/build/hooks/use-select-nearest-editable-block.js +87 -0
  66. package/build/hooks/use-select-nearest-editable-block.js.map +1 -0
  67. package/build/private-apis.js +6 -2
  68. package/build/private-apis.js.map +1 -1
  69. package/build/store/actions.js +46 -6
  70. package/build/store/actions.js.map +1 -1
  71. package/build/store/constants.js +3 -1
  72. package/build/store/constants.js.map +1 -1
  73. package/build/store/private-actions.js +80 -1
  74. package/build/store/private-actions.js.map +1 -1
  75. package/build/store/private-selectors.js +56 -3
  76. package/build/store/private-selectors.js.map +1 -1
  77. package/build/store/reducer.js +14 -1
  78. package/build/store/reducer.js.map +1 -1
  79. package/build/store/selectors.js +21 -11
  80. package/build/store/selectors.js.map +1 -1
  81. package/build/store/utils/get-filtered-template-parts.js +71 -0
  82. package/build/store/utils/get-filtered-template-parts.js.map +1 -0
  83. package/build-module/bindings/index.js +3 -1
  84. package/build-module/bindings/index.js.map +1 -1
  85. package/build-module/components/block-settings-menu/plugin-block-settings-menu-item.js +100 -0
  86. package/build-module/components/block-settings-menu/plugin-block-settings-menu-item.js.map +1 -0
  87. package/build-module/components/commands/index.js +1 -1
  88. package/build-module/components/commands/index.js.map +1 -1
  89. package/build-module/components/deprecated.js +159 -0
  90. package/build-module/components/deprecated.js.map +1 -1
  91. package/build-module/components/document-bar/index.js +8 -11
  92. package/build-module/components/document-bar/index.js.map +1 -1
  93. package/build-module/components/document-outline/index.js +1 -1
  94. package/build-module/components/document-outline/index.js.map +1 -1
  95. package/build-module/components/editor-canvas/edit-template-blocks-notification.js +4 -41
  96. package/build-module/components/editor-canvas/edit-template-blocks-notification.js.map +1 -1
  97. package/build-module/components/editor-canvas/index.js +3 -0
  98. package/build-module/components/editor-canvas/index.js.map +1 -1
  99. package/build-module/components/entities-saved-states/hooks/use-is-dirty.js +10 -16
  100. package/build-module/components/entities-saved-states/hooks/use-is-dirty.js.map +1 -1
  101. package/build-module/components/entities-saved-states/index.js +29 -89
  102. package/build-module/components/entities-saved-states/index.js.map +1 -1
  103. package/build-module/components/error-boundary/index.native.js +125 -0
  104. package/build-module/components/error-boundary/index.native.js.map +1 -0
  105. package/build-module/components/index.js +5 -1
  106. package/build-module/components/index.js.map +1 -1
  107. package/build-module/components/index.native.js +1 -0
  108. package/build-module/components/index.native.js.map +1 -1
  109. package/build-module/components/inserter-sidebar/index.js +5 -1
  110. package/build-module/components/inserter-sidebar/index.js.map +1 -1
  111. package/build-module/components/list-view-sidebar/index.js +2 -1
  112. package/build-module/components/list-view-sidebar/index.js.map +1 -1
  113. package/build-module/components/pattern-overrides-panel/index.js +23 -0
  114. package/build-module/components/pattern-overrides-panel/index.js.map +1 -0
  115. package/build-module/components/plugin-document-setting-panel/index.js +115 -0
  116. package/build-module/components/plugin-document-setting-panel/index.js.map +1 -0
  117. package/build-module/components/plugin-post-publish-panel/index.js +61 -0
  118. package/build-module/components/plugin-post-publish-panel/index.js.map +1 -0
  119. package/build-module/components/plugin-pre-publish-panel/index.js +64 -0
  120. package/build-module/components/plugin-pre-publish-panel/index.js.map +1 -0
  121. package/build-module/components/post-actions/actions.js +444 -0
  122. package/build-module/components/post-actions/actions.js.map +1 -0
  123. package/build-module/components/post-card-panel/index.js +85 -0
  124. package/build-module/components/post-card-panel/index.js.map +1 -0
  125. package/build-module/components/post-featured-image/index.js +4 -9
  126. package/build-module/components/post-featured-image/index.js.map +1 -1
  127. package/build-module/components/post-featured-image/panel.js +6 -2
  128. package/build-module/components/post-featured-image/panel.js.map +1 -1
  129. package/build-module/components/post-sync-status/index.js +2 -73
  130. package/build-module/components/post-sync-status/index.js.map +1 -1
  131. package/build-module/components/post-taxonomies/flat-term-selector.js +7 -3
  132. package/build-module/components/post-taxonomies/flat-term-selector.js.map +1 -1
  133. package/build-module/components/post-title/index.native.js +1 -1
  134. package/build-module/components/post-title/index.native.js.map +1 -1
  135. package/build-module/components/provider/disable-non-page-content-blocks.js +36 -20
  136. package/build-module/components/provider/disable-non-page-content-blocks.js.map +1 -1
  137. package/build-module/components/provider/index.js +1 -1
  138. package/build-module/components/provider/index.js.map +1 -1
  139. package/build-module/components/provider/use-block-editor-settings.js +9 -10
  140. package/build-module/components/provider/use-block-editor-settings.js.map +1 -1
  141. package/build-module/components/provider/use-hide-blocks-from-inserter.js +4 -3
  142. package/build-module/components/provider/use-hide-blocks-from-inserter.js.map +1 -1
  143. package/build-module/components/template-areas/index.js +63 -0
  144. package/build-module/components/template-areas/index.js.map +1 -0
  145. package/build-module/hooks/use-select-nearest-editable-block.js +80 -0
  146. package/build-module/hooks/use-select-nearest-editable-block.js.map +1 -0
  147. package/build-module/private-apis.js +6 -2
  148. package/build-module/private-apis.js.map +1 -1
  149. package/build-module/store/actions.js +37 -3
  150. package/build-module/store/actions.js.map +1 -1
  151. package/build-module/store/constants.js +2 -0
  152. package/build-module/store/constants.js.map +1 -1
  153. package/build-module/store/private-actions.js +78 -0
  154. package/build-module/store/private-actions.js.map +1 -1
  155. package/build-module/store/private-selectors.js +54 -3
  156. package/build-module/store/private-selectors.js.map +1 -1
  157. package/build-module/store/reducer.js +13 -1
  158. package/build-module/store/reducer.js.map +1 -1
  159. package/build-module/store/selectors.js +19 -10
  160. package/build-module/store/selectors.js.map +1 -1
  161. package/build-module/store/utils/get-filtered-template-parts.js +64 -0
  162. package/build-module/store/utils/get-filtered-template-parts.js.map +1 -0
  163. package/build-style/style-rtl.css +76 -33
  164. package/build-style/style.css +76 -33
  165. package/package.json +35 -33
  166. package/src/bindings/index.js +4 -1
  167. package/src/components/block-settings-menu/plugin-block-settings-menu-item.js +108 -0
  168. package/src/components/commands/index.js +1 -1
  169. package/src/components/deprecated.js +157 -0
  170. package/src/components/document-bar/index.js +12 -17
  171. package/src/components/document-bar/style.scss +9 -12
  172. package/src/components/document-outline/index.js +2 -1
  173. package/src/components/document-tools/style.scss +4 -11
  174. package/src/components/editor-canvas/edit-template-blocks-notification.js +6 -56
  175. package/src/components/editor-canvas/index.js +4 -0
  176. package/src/components/entities-saved-states/hooks/use-is-dirty.js +18 -22
  177. package/src/components/entities-saved-states/index.js +45 -121
  178. package/src/components/entities-saved-states/test/use-is-dirty.js +3 -0
  179. package/src/components/error-boundary/index.native.js +192 -0
  180. package/src/components/error-boundary/style.native.scss +116 -0
  181. package/src/components/index.js +5 -4
  182. package/src/components/index.native.js +1 -0
  183. package/src/components/inserter-sidebar/index.js +7 -1
  184. package/src/components/list-view-sidebar/index.js +1 -0
  185. package/src/components/list-view-sidebar/style.scss +1 -1
  186. package/src/components/pattern-overrides-panel/index.js +26 -0
  187. package/src/components/plugin-document-setting-panel/index.js +121 -0
  188. package/src/components/plugin-post-publish-panel/index.js +64 -0
  189. package/src/components/plugin-post-publish-panel/test/__snapshots__/index.js.snap +39 -0
  190. package/src/components/plugin-post-publish-panel/test/index.js +33 -0
  191. package/src/components/plugin-pre-publish-panel/index.js +67 -0
  192. package/src/components/plugin-pre-publish-panel/test/index.js +33 -0
  193. package/src/components/post-actions/actions.js +582 -0
  194. package/src/components/post-card-panel/index.js +108 -0
  195. package/src/components/post-card-panel/style.scss +32 -0
  196. package/src/components/post-featured-image/index.js +6 -15
  197. package/src/components/post-featured-image/panel.js +9 -3
  198. package/src/components/post-featured-image/style.scss +9 -13
  199. package/src/components/post-sync-status/index.js +1 -94
  200. package/src/components/post-taxonomies/flat-term-selector.js +13 -8
  201. package/src/components/post-title/index.native.js +1 -1
  202. package/src/components/provider/disable-non-page-content-blocks.js +40 -20
  203. package/src/components/provider/index.js +1 -1
  204. package/src/components/provider/test/disable-non-page-content-blocks.js +35 -14
  205. package/src/components/provider/use-block-editor-settings.js +11 -11
  206. package/src/components/provider/use-hide-blocks-from-inserter.js +5 -3
  207. package/src/components/template-areas/index.js +85 -0
  208. package/src/components/template-areas/style.scss +23 -0
  209. package/src/hooks/use-select-nearest-editable-block.js +95 -0
  210. package/src/private-apis.js +6 -2
  211. package/src/store/actions.js +37 -3
  212. package/src/store/constants.js +2 -0
  213. package/src/store/private-actions.js +111 -0
  214. package/src/store/private-selectors.js +105 -17
  215. package/src/store/reducer.js +13 -0
  216. package/src/store/selectors.js +50 -40
  217. package/src/store/utils/get-filtered-template-parts.js +69 -0
  218. package/src/store/utils/test/get-filtered-template-parts.js +189 -0
  219. package/src/style.scss +2 -0
@@ -7,7 +7,6 @@ import {
7
7
  DropZone,
8
8
  Button,
9
9
  Spinner,
10
- ResponsiveWrapper,
11
10
  withNotices,
12
11
  withFilters,
13
12
  __experimentalHStack as HStack,
@@ -99,10 +98,7 @@ function PostFeaturedImage( {
99
98
  const toggleRef = useRef();
100
99
  const [ isLoading, setIsLoading ] = useState( false );
101
100
  const { getSettings } = useSelect( blockEditorStore );
102
- const { mediaWidth, mediaHeight, mediaSourceUrl } = getMediaDetails(
103
- media,
104
- currentPostId
105
- );
101
+ const { mediaSourceUrl } = getMediaDetails( media, currentPostId );
106
102
 
107
103
  function onDropFiles( filesList ) {
108
104
  getSettings().mediaUpload( {
@@ -183,16 +179,11 @@ function PostFeaturedImage( {
183
179
  }
184
180
  >
185
181
  { !! featuredImageId && media && (
186
- <ResponsiveWrapper
187
- naturalWidth={ mediaWidth }
188
- naturalHeight={ mediaHeight }
189
- isInline
190
- >
191
- <img
192
- src={ mediaSourceUrl }
193
- alt=""
194
- />
195
- </ResponsiveWrapper>
182
+ <img
183
+ className="editor-post-featured-image__preview-image"
184
+ src={ mediaSourceUrl }
185
+ alt=""
186
+ />
196
187
  ) }
197
188
  { isLoading && <Spinner /> }
198
189
  { ! featuredImageId &&
@@ -15,7 +15,7 @@ import PostFeaturedImageCheck from './check';
15
15
 
16
16
  const PANEL_NAME = 'featured-image';
17
17
 
18
- function FeaturedImage() {
18
+ export default function PostFeaturedImagePanel( { withPanelBody = true } ) {
19
19
  const { postType, isEnabled, isOpened } = useSelect( ( select ) => {
20
20
  const {
21
21
  getEditedPostAttribute,
@@ -37,6 +37,14 @@ function FeaturedImage() {
37
37
  return null;
38
38
  }
39
39
 
40
+ if ( ! withPanelBody ) {
41
+ return (
42
+ <PostFeaturedImageCheck>
43
+ <PostFeaturedImage />
44
+ </PostFeaturedImageCheck>
45
+ );
46
+ }
47
+
40
48
  return (
41
49
  <PostFeaturedImageCheck>
42
50
  <PanelBody
@@ -51,5 +59,3 @@ function FeaturedImage() {
51
59
  </PostFeaturedImageCheck>
52
60
  );
53
61
  }
54
-
55
- export default FeaturedImage;
@@ -1,7 +1,6 @@
1
1
  .editor-post-featured-image {
2
2
  padding: 0;
3
3
 
4
-
5
4
  .components-spinner {
6
5
  position: absolute;
7
6
  top: 50%;
@@ -9,13 +8,6 @@
9
8
  margin-top: -9px;
10
9
  margin-left: -9px;
11
10
  }
12
-
13
- // This keeps images at their intrinsic size (eg. a 50px
14
- // image will never be wider than 50px).
15
- .components-responsive-wrapper__content {
16
- max-width: 100%;
17
- width: auto;
18
- }
19
11
  }
20
12
 
21
13
  .editor-post-featured-image__container {
@@ -38,26 +30,30 @@
38
30
  @include reduce-motion("transition");
39
31
  box-shadow: 0 0 0 0 var(--wp-admin-theme-color);
40
32
  overflow: hidden; // Ensure the focus style properly encapsulates the image.
33
+ outline-offset: -#{$border-width};
34
+ min-height: $grid-unit-50 * 2;
35
+ margin-bottom: $grid-unit-20;
41
36
 
42
- // Apply a max-height.
43
37
  display: flex;
44
38
  justify-content: center;
45
- max-height: 150px;
46
39
  }
47
40
 
48
41
  .editor-post-featured-image__preview {
49
42
  height: auto;
43
+ outline: $border-width solid rgba($black, 0.1);
50
44
 
51
- .components-responsive-wrapper {
45
+ .editor-post-featured-image__preview-image {
46
+ object-fit: cover;
52
47
  width: 100%;
53
- background: $gray-100;
48
+ object-position: 50% 50%;
49
+ aspect-ratio: 2/1;
54
50
  }
55
51
  }
56
52
 
57
53
  .editor-post-featured-image__toggle {
58
54
  border-radius: $radius-block-ui;
59
55
  background-color: $gray-100;
60
- min-height: 90px;
56
+ height: 100%;
61
57
  line-height: 20px;
62
58
  padding: $grid-unit-10 0;
63
59
  text-align: center;
@@ -1,26 +1,14 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { useSelect, useDispatch } from '@wordpress/data';
4
+ import { useSelect } from '@wordpress/data';
5
5
  import { __, _x } from '@wordpress/i18n';
6
- import {
7
- Modal,
8
- Button,
9
- __experimentalHStack as HStack,
10
- __experimentalVStack as VStack,
11
- ToggleControl,
12
- } from '@wordpress/components';
13
- import { useEffect, useState } from '@wordpress/element';
14
- import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor';
15
6
 
16
7
  /**
17
8
  * Internal dependencies
18
9
  */
19
10
  import PostPanelRow from '../post-panel-row';
20
11
  import { store as editorStore } from '../../store';
21
- import { unlock } from '../../lock-unlock';
22
-
23
- const { ReusableBlocksRenameHint } = unlock( blockEditorPrivateApis );
24
12
 
25
13
  export default function PostSyncStatus() {
26
14
  const { syncStatus, postType } = useSelect( ( select ) => {
@@ -59,84 +47,3 @@ export default function PostSyncStatus() {
59
47
  </PostPanelRow>
60
48
  );
61
49
  }
62
-
63
- export function PostSyncStatusModal() {
64
- const { editPost } = useDispatch( editorStore );
65
- const [ isModalOpen, setIsModalOpen ] = useState( false );
66
- const [ syncType, setSyncType ] = useState( undefined );
67
-
68
- const { postType, isNewPost } = useSelect( ( select ) => {
69
- const { getEditedPostAttribute, isCleanNewPost } =
70
- select( editorStore );
71
- return {
72
- postType: getEditedPostAttribute( 'type' ),
73
- isNewPost: isCleanNewPost(),
74
- };
75
- }, [] );
76
-
77
- useEffect( () => {
78
- if ( isNewPost && postType === 'wp_block' ) {
79
- setIsModalOpen( true );
80
- }
81
- // We only want the modal to open when the page is first loaded.
82
- // eslint-disable-next-line react-hooks/exhaustive-deps
83
- }, [] );
84
-
85
- const setSyncStatus = () => {
86
- editPost( {
87
- meta: {
88
- wp_pattern_sync_status: syncType,
89
- },
90
- } );
91
- };
92
-
93
- if ( postType !== 'wp_block' || ! isNewPost ) {
94
- return null;
95
- }
96
-
97
- return (
98
- <>
99
- { isModalOpen && (
100
- <Modal
101
- title={ __( 'Set pattern sync status' ) }
102
- onRequestClose={ () => {
103
- setIsModalOpen( false );
104
- } }
105
- overlayClassName="reusable-blocks-menu-items__convert-modal"
106
- >
107
- <form
108
- onSubmit={ ( event ) => {
109
- event.preventDefault();
110
- setIsModalOpen( false );
111
- setSyncStatus();
112
- } }
113
- >
114
- <VStack spacing="5">
115
- <ReusableBlocksRenameHint />
116
- <ToggleControl
117
- label={ _x(
118
- 'Synced',
119
- 'Option that makes an individual pattern synchronized'
120
- ) }
121
- help={ __(
122
- 'Sync this pattern across multiple locations.'
123
- ) }
124
- checked={ ! syncType }
125
- onChange={ () => {
126
- setSyncType(
127
- ! syncType ? 'unsynced' : undefined
128
- );
129
- } }
130
- />
131
- <HStack justify="right">
132
- <Button variant="primary" type="submit">
133
- { __( 'Create' ) }
134
- </Button>
135
- </HStack>
136
- </VStack>
137
- </form>
138
- </Modal>
139
- ) }
140
- </>
141
- );
142
- }
@@ -40,10 +40,13 @@ const isSameTermName = ( termA, termB ) =>
40
40
  unescapeString( termB ).toLowerCase();
41
41
 
42
42
  const termNamesToIds = ( names, terms ) => {
43
- return names.map(
44
- ( termName ) =>
45
- terms.find( ( term ) => isSameTermName( term.name, termName ) ).id
46
- );
43
+ return names
44
+ .map(
45
+ ( termName ) =>
46
+ terms.find( ( term ) => isSameTermName( term.name, termName ) )
47
+ ?.id
48
+ )
49
+ .filter( ( id ) => id !== undefined );
47
50
  };
48
51
 
49
52
  export function FlatTermSelector( { slug } ) {
@@ -193,9 +196,8 @@ export function FlatTermSelector( { slug } ) {
193
196
  setValues( uniqueTerms );
194
197
 
195
198
  if ( newTermNames.length === 0 ) {
196
- return onUpdateTerms(
197
- termNamesToIds( uniqueTerms, availableTerms )
198
- );
199
+ onUpdateTerms( termNamesToIds( uniqueTerms, availableTerms ) );
200
+ return;
199
201
  }
200
202
 
201
203
  if ( ! hasCreateAction ) {
@@ -209,7 +211,7 @@ export function FlatTermSelector( { slug } ) {
209
211
  )
210
212
  .then( ( newTerms ) => {
211
213
  const newAvailableTerms = availableTerms.concat( newTerms );
212
- return onUpdateTerms(
214
+ onUpdateTerms(
213
215
  termNamesToIds( uniqueTerms, newAvailableTerms )
214
216
  );
215
217
  } )
@@ -217,6 +219,9 @@ export function FlatTermSelector( { slug } ) {
217
219
  createErrorNotice( error.message, {
218
220
  type: 'snackbar',
219
221
  } );
222
+ // In case of a failure, try assigning available terms.
223
+ // This will invalidate the optimistic update.
224
+ onUpdateTerms( termNamesToIds( uniqueTerms, availableTerms ) );
220
225
  } );
221
226
  }
222
227
 
@@ -164,7 +164,7 @@ class PostTitle extends Component {
164
164
  accessibilityHint={ __( 'Updates the title.' ) }
165
165
  >
166
166
  <RichText.Raw
167
- setRef={ this.setRef }
167
+ ref={ this.setRef }
168
168
  accessibilityLabel={ this.getTitle( title, postType ) }
169
169
  tagName={ 'p' }
170
170
  tagsToEliminate={ [ 'strong' ] }
@@ -4,50 +4,70 @@
4
4
  import { useSelect, useDispatch } from '@wordpress/data';
5
5
  import { store as blockEditorStore } from '@wordpress/block-editor';
6
6
  import { useEffect } from '@wordpress/element';
7
+ import { applyFilters } from '@wordpress/hooks';
7
8
 
8
- const PAGE_CONTENT_BLOCKS = [
9
+ const CONTENT_ONLY_BLOCKS = applyFilters( 'editor.postContentBlockTypes', [
9
10
  'core/post-title',
10
11
  'core/post-featured-image',
11
12
  'core/post-content',
12
- ];
13
+ 'core/template-part',
14
+ ] );
13
15
 
14
- function useDisableNonPageContentBlocks() {
15
- const contentIds = useSelect( ( select ) => {
16
+ /**
17
+ * Component that when rendered, makes it so that the site editor allows only
18
+ * page content to be edited.
19
+ */
20
+ export default function DisableNonPageContentBlocks() {
21
+ const contentOnlyIds = useSelect( ( select ) => {
16
22
  const { getBlocksByName, getBlockParents, getBlockName } =
17
23
  select( blockEditorStore );
18
- return getBlocksByName( PAGE_CONTENT_BLOCKS ).filter( ( clientId ) =>
24
+ return getBlocksByName( CONTENT_ONLY_BLOCKS ).filter( ( clientId ) =>
19
25
  getBlockParents( clientId ).every( ( parentClientId ) => {
20
26
  const parentBlockName = getBlockName( parentClientId );
21
27
  return (
28
+ // Ignore descendents of the query block.
22
29
  parentBlockName !== 'core/query' &&
23
- ! PAGE_CONTENT_BLOCKS.includes( parentBlockName )
30
+ // Enable only the top-most block.
31
+ ! CONTENT_ONLY_BLOCKS.includes( parentBlockName )
24
32
  );
25
33
  } )
26
34
  );
27
35
  }, [] );
28
36
 
37
+ const disabledIds = useSelect( ( select ) => {
38
+ const { getBlocksByName, getBlockOrder } = select( blockEditorStore );
39
+ return getBlocksByName( [ 'core/template-part' ] ).flatMap(
40
+ ( clientId ) => getBlockOrder( clientId )
41
+ );
42
+ }, [] );
43
+
29
44
  const { setBlockEditingMode, unsetBlockEditingMode } =
30
45
  useDispatch( blockEditorStore );
31
46
 
32
47
  useEffect( () => {
33
- setBlockEditingMode( '', 'disabled' ); // Disable editing at the root level.
34
-
35
- for ( const contentId of contentIds ) {
36
- setBlockEditingMode( contentId, 'contentOnly' ); // Re-enable each content block.
48
+ setBlockEditingMode( '', 'disabled' );
49
+ for ( const clientId of contentOnlyIds ) {
50
+ setBlockEditingMode( clientId, 'contentOnly' );
37
51
  }
52
+ for ( const clientId of disabledIds ) {
53
+ setBlockEditingMode( clientId, 'disabled' );
54
+ }
55
+
38
56
  return () => {
39
57
  unsetBlockEditingMode( '' );
40
- for ( const contentId of contentIds ) {
41
- unsetBlockEditingMode( contentId );
58
+ for ( const clientId of contentOnlyIds ) {
59
+ unsetBlockEditingMode( clientId );
60
+ }
61
+ for ( const clientId of disabledIds ) {
62
+ unsetBlockEditingMode( clientId );
42
63
  }
43
64
  };
44
- }, [ contentIds, setBlockEditingMode, unsetBlockEditingMode ] );
45
- }
65
+ }, [
66
+ contentOnlyIds,
67
+ disabledIds,
68
+ setBlockEditingMode,
69
+ unsetBlockEditingMode,
70
+ ] );
46
71
 
47
- /**
48
- * Component that when rendered, makes it so that the site editor allows only
49
- * page content to be edited.
50
- */
51
- export default function DisableNonPageContentBlocks() {
52
- useDisableNonPageContentBlocks();
72
+ return null;
53
73
  }
@@ -232,7 +232,7 @@ export const ExperimentalEditorProvider = withRegistryProvider(
232
232
  setRenderingMode( settings.defaultRenderingMode ?? 'post-only' );
233
233
  }, [ settings.defaultRenderingMode, setRenderingMode ] );
234
234
 
235
- useHideBlocksFromInserter( post.type );
235
+ useHideBlocksFromInserter( post.type, mode );
236
236
 
237
237
  // Register the editor commands.
238
238
  useCommands();
@@ -55,6 +55,13 @@ describe( 'DisableNonPageContentBlocks', () => {
55
55
  getBlockName( state, clientId ) {
56
56
  return testBlocks[ clientId ];
57
57
  },
58
+ getBlockOrder( state, rootClientId ) {
59
+ return Object.keys( testBlocks ).filter(
60
+ ( clientId ) =>
61
+ clientId.startsWith( rootClientId ) &&
62
+ clientId !== rootClientId
63
+ );
64
+ },
58
65
  },
59
66
  actions: {
60
67
  setBlockEditingMode,
@@ -69,22 +76,36 @@ describe( 'DisableNonPageContentBlocks', () => {
69
76
  </RegistryProvider>
70
77
  );
71
78
 
72
- expect( setBlockEditingMode.mock.calls ).toEqual( [
73
- [ '', 'disabled' ], // root
74
- [ '10', 'contentOnly' ], // post-title
75
- [ '11', 'contentOnly' ], // post-featured-image
76
- [ '12', 'contentOnly' ], // post-content
77
- // NOT the post-featured-image nested within post-content
78
- // NOT any of the content blocks within query
79
- ] );
79
+ expect( setBlockEditingMode.mock.calls ).toEqual(
80
+ expect.arrayContaining( [
81
+ [ '', 'disabled' ], // root
82
+ [ '0', 'contentOnly' ], // core/template-part
83
+ [ '00', 'disabled' ], // core/site-title
84
+ [ '01', 'disabled' ], // core/navigation
85
+ [ '10', 'contentOnly' ], // post-title
86
+ [ '11', 'contentOnly' ], // post-featured-image
87
+ [ '12', 'contentOnly' ], // post-content
88
+ [ '3', 'contentOnly' ], // core/template-part
89
+ [ '30', 'disabled' ], // core/paragraph
90
+ // NOT the post-featured-image nested within post-content
91
+ // NOT any of the content blocks within query
92
+ ] )
93
+ );
80
94
 
81
95
  unmount();
82
96
 
83
- expect( unsetBlockEditingMode.mock.calls ).toEqual( [
84
- [ '' ], // root
85
- [ '10' ], // post-title
86
- [ '11' ], // post-featured-image
87
- [ '12' ], // post-content
88
- ] );
97
+ expect( unsetBlockEditingMode.mock.calls ).toEqual(
98
+ expect.arrayContaining( [
99
+ [ '' ], // root
100
+ [ '0' ], // core/template-part
101
+ [ '00' ], // core/site-title
102
+ [ '01' ], // core/navigation
103
+ [ '10' ], // post-title
104
+ [ '11' ], // post-featured-image
105
+ [ '12' ], // post-content
106
+ [ '3' ], // core/template-part
107
+ [ '30' ], // core/paragraph
108
+ ] )
109
+ );
89
110
  } );
90
111
  } );
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { Platform, useMemo, useCallback } from '@wordpress/element';
4
+ import { useMemo, useCallback } from '@wordpress/element';
5
5
  import { useDispatch, useSelect } from '@wordpress/data';
6
6
  import {
7
7
  store as coreStore,
@@ -24,6 +24,14 @@ import { unlock } from '../../lock-unlock';
24
24
 
25
25
  const EMPTY_BLOCKS_LIST = [];
26
26
 
27
+ function __experimentalReusableBlocksSelect( select ) {
28
+ return (
29
+ select( coreStore ).getEntityRecords( 'postType', 'wp_block', {
30
+ per_page: -1,
31
+ } ) ?? EMPTY_BLOCKS_LIST
32
+ );
33
+ }
34
+
27
35
  const BLOCK_EDITOR_SETTINGS = [
28
36
  '__experimentalBlockDirectory',
29
37
  '__experimentalDiscussionSettings',
@@ -92,7 +100,6 @@ function useBlockEditorSettings( settings, postType, postId ) {
92
100
  hasFixedToolbar,
93
101
  isDistractionFree,
94
102
  keepCaretInsideBlock,
95
- reusableBlocks,
96
103
  hasUploadPermissions,
97
104
  hiddenBlockTypes,
98
105
  canUseUnfilteredHTML,
@@ -103,13 +110,11 @@ function useBlockEditorSettings( settings, postType, postId ) {
103
110
  restBlockPatternCategories,
104
111
  } = useSelect(
105
112
  ( select ) => {
106
- const isWeb = Platform.OS === 'web';
107
113
  const {
108
114
  canUser,
109
115
  getRawEntityRecord,
110
116
  getEntityRecord,
111
117
  getUserPatternCategories,
112
- getEntityRecords,
113
118
  getBlockPatternCategories,
114
119
  } = select( coreStore );
115
120
  const { get } = select( preferencesStore );
@@ -135,11 +140,6 @@ function useBlockEditorSettings( settings, postType, postId ) {
135
140
  hiddenBlockTypes: get( 'core', 'hiddenBlockTypes' ),
136
141
  isDistractionFree: get( 'core', 'distractionFree' ),
137
142
  keepCaretInsideBlock: get( 'core', 'keepCaretInsideBlock' ),
138
- reusableBlocks: isWeb
139
- ? getEntityRecords( 'postType', 'wp_block', {
140
- per_page: -1,
141
- } )
142
- : EMPTY_BLOCKS_LIST, // Reusable blocks are fetched in the native version of this hook.
143
143
  hasUploadPermissions: canUser( 'create', 'media' ) ?? true,
144
144
  userCanCreatePages: canUser( 'create', 'pages' ),
145
145
  pageOnFront: siteSettings?.page_on_front,
@@ -249,7 +249,8 @@ function useBlockEditorSettings( settings, postType, postId ) {
249
249
  unlock( select( coreStore ) ).getBlockPatternsForPostType(
250
250
  postType
251
251
  ),
252
- __experimentalReusableBlocks: reusableBlocks,
252
+ [ unlock( privateApis ).reusableBlocksSelectKey ]:
253
+ __experimentalReusableBlocksSelect,
253
254
  __experimentalBlockPatternCategories: blockPatternCategories,
254
255
  __experimentalUserPatternCategories: userPatternCategories,
255
256
  __experimentalFetchLinkSuggestions: ( search, searchOptions ) =>
@@ -288,7 +289,6 @@ function useBlockEditorSettings( settings, postType, postId ) {
288
289
  keepCaretInsideBlock,
289
290
  settings,
290
291
  hasUploadPermissions,
291
- reusableBlocks,
292
292
  userPatternCategories,
293
293
  blockPatterns,
294
294
  blockPatternCategories,
@@ -18,8 +18,9 @@ const POST_TYPES_ALLOWING_POST_CONTENT_TEMPLATE_PART = [
18
18
  * the template part and post content blocks need to be hidden.
19
19
  *
20
20
  * @param {string} postType Post Type
21
+ * @param {string} mode Rendering mode
21
22
  */
22
- export function useHideBlocksFromInserter( postType ) {
23
+ export function useHideBlocksFromInserter( postType, mode ) {
23
24
  useEffect( () => {
24
25
  /*
25
26
  * Prevent adding template part in the editor.
@@ -32,7 +33,8 @@ export function useHideBlocksFromInserter( postType ) {
32
33
  ! POST_TYPES_ALLOWING_POST_CONTENT_TEMPLATE_PART.includes(
33
34
  postType
34
35
  ) &&
35
- blockType.name === 'core/template-part'
36
+ blockType.name === 'core/template-part' &&
37
+ mode === 'post-only'
36
38
  ) {
37
39
  return false;
38
40
  }
@@ -77,5 +79,5 @@ export function useHideBlocksFromInserter( postType ) {
77
79
  'removePostContentFromInserter'
78
80
  );
79
81
  };
80
- }, [ postType ] );
82
+ }, [ postType, mode ] );
81
83
  }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useSelect, useDispatch } from '@wordpress/data';
5
+ import {
6
+ Button,
7
+ __experimentalHeading as Heading,
8
+ } from '@wordpress/components';
9
+
10
+ import { store as blockEditorStore } from '@wordpress/block-editor';
11
+ import { __ } from '@wordpress/i18n';
12
+
13
+ /**
14
+ * Internal dependencies
15
+ */
16
+ import { store as editorStore } from '../../store';
17
+ import { unlock } from '../../lock-unlock';
18
+
19
+ function TemplateAreaItem( { area, clientId } ) {
20
+ const { selectBlock, toggleBlockHighlight } =
21
+ useDispatch( blockEditorStore );
22
+ const templatePartArea = useSelect(
23
+ ( select ) => {
24
+ const defaultAreas =
25
+ select(
26
+ editorStore
27
+ ).__experimentalGetDefaultTemplatePartAreas();
28
+
29
+ return defaultAreas.find(
30
+ ( defaultArea ) => defaultArea.area === area
31
+ );
32
+ },
33
+ [ area ]
34
+ );
35
+
36
+ const highlightBlock = () => toggleBlockHighlight( clientId, true );
37
+ const cancelHighlightBlock = () => toggleBlockHighlight( clientId, false );
38
+
39
+ return (
40
+ <Button
41
+ className="editor-template-areas__item"
42
+ icon={ templatePartArea?.icon }
43
+ onMouseOver={ highlightBlock }
44
+ onMouseLeave={ cancelHighlightBlock }
45
+ onFocus={ highlightBlock }
46
+ onBlur={ cancelHighlightBlock }
47
+ onClick={ () => {
48
+ selectBlock( clientId );
49
+ } }
50
+ >
51
+ { templatePartArea?.label }
52
+ </Button>
53
+ );
54
+ }
55
+
56
+ export default function TemplateAreas() {
57
+ const templateParts = useSelect(
58
+ ( select ) =>
59
+ unlock( select( editorStore ) ).getCurrentTemplateTemplateParts(),
60
+ []
61
+ );
62
+
63
+ if ( ! templateParts.length ) {
64
+ return null;
65
+ }
66
+
67
+ return (
68
+ <section className="editor-template-areas">
69
+ <Heading level={ 3 } className="editor-template-areas__title">
70
+ { __( 'Areas' ) }
71
+ </Heading>
72
+
73
+ <ul className="editor-template-areas__list">
74
+ { templateParts.map( ( { templatePart, block } ) => (
75
+ <li key={ block.clientId }>
76
+ <TemplateAreaItem
77
+ area={ templatePart.area }
78
+ clientId={ block.clientId }
79
+ />
80
+ </li>
81
+ ) ) }
82
+ </ul>
83
+ </section>
84
+ );
85
+ }
@@ -0,0 +1,23 @@
1
+ .editor-template-areas {
2
+ margin-top: $grid-unit-20;
3
+ &__list {
4
+ margin: 0;
5
+ > li {
6
+ margin: 0;
7
+ }
8
+ }
9
+
10
+ &__item {
11
+ width: 100%;
12
+
13
+ // Override the default padding.
14
+ &.components-button.has-icon {
15
+ padding: 0;
16
+ }
17
+ }
18
+ }
19
+
20
+ h3.components-heading.editor-template-areas__title {
21
+ font-weight: 500;
22
+ margin: 0 0 $grid-unit-10;
23
+ }