@wordpress/editor 14.18.0 → 14.19.1

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 (160) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/README.md +2 -0
  3. package/build/components/document-bar/index.js +3 -2
  4. package/build/components/document-bar/index.js.map +1 -1
  5. package/build/components/document-outline/index.js +37 -17
  6. package/build/components/document-outline/index.js.map +1 -1
  7. package/build/components/document-outline/item.js +32 -20
  8. package/build/components/document-outline/item.js.map +1 -1
  9. package/build/components/entities-saved-states/entity-record-item.js +4 -3
  10. package/build/components/entities-saved-states/entity-record-item.js.map +1 -1
  11. package/build/components/entities-saved-states/entity-type-list.js +2 -1
  12. package/build/components/entities-saved-states/entity-type-list.js.map +1 -1
  13. package/build/components/entities-saved-states/index.js +66 -42
  14. package/build/components/entities-saved-states/index.js.map +1 -1
  15. package/build/components/post-actions/index.js +19 -28
  16. package/build/components/post-actions/index.js.map +1 -1
  17. package/build/components/post-card-panel/index.js +5 -5
  18. package/build/components/post-card-panel/index.js.map +1 -1
  19. package/build/components/post-featured-image/index.js +4 -2
  20. package/build/components/post-featured-image/index.js.map +1 -1
  21. package/build/components/post-template/block-theme.js +68 -48
  22. package/build/components/post-template/block-theme.js.map +1 -1
  23. package/build/components/post-template/classic-theme.js +30 -18
  24. package/build/components/post-template/classic-theme.js.map +1 -1
  25. package/build/components/post-template/create-new-template-modal.js +3 -1
  26. package/build/components/post-template/create-new-template-modal.js.map +1 -1
  27. package/build/components/post-template/panel.js +3 -11
  28. package/build/components/post-template/panel.js.map +1 -1
  29. package/build/components/preferences-modal/block-visibility.js +2 -1
  30. package/build/components/preferences-modal/block-visibility.js.map +1 -1
  31. package/build/components/preferences-modal/index.js +1 -1
  32. package/build/components/preferences-modal/index.js.map +1 -1
  33. package/build/components/preview-dropdown/index.js +6 -3
  34. package/build/components/preview-dropdown/index.js.map +1 -1
  35. package/build/components/provider/index.js +19 -18
  36. package/build/components/provider/index.js.map +1 -1
  37. package/build/components/sidebar/header.js +1 -1
  38. package/build/components/sidebar/header.js.map +1 -1
  39. package/build/components/sidebar/index.js +1 -1
  40. package/build/components/sidebar/index.js.map +1 -1
  41. package/build/components/start-page-options/index.js +148 -23
  42. package/build/components/start-page-options/index.js.map +1 -1
  43. package/build/components/visual-editor/edit-template-blocks-notification.js +1 -1
  44. package/build/components/visual-editor/edit-template-blocks-notification.js.map +1 -1
  45. package/build/store/private-actions.js +29 -2
  46. package/build/store/private-actions.js.map +1 -1
  47. package/build/store/private-selectors.js +45 -1
  48. package/build/store/private-selectors.js.map +1 -1
  49. package/build/store/selectors.js +8 -7
  50. package/build/store/selectors.js.map +1 -1
  51. package/build/utils/media-upload/index.js +5 -2
  52. package/build/utils/media-upload/index.js.map +1 -1
  53. package/build-module/components/document-bar/index.js +3 -2
  54. package/build-module/components/document-bar/index.js.map +1 -1
  55. package/build-module/components/document-outline/index.js +38 -18
  56. package/build-module/components/document-outline/index.js.map +1 -1
  57. package/build-module/components/document-outline/item.js +32 -20
  58. package/build-module/components/document-outline/item.js.map +1 -1
  59. package/build-module/components/entities-saved-states/entity-record-item.js +4 -3
  60. package/build-module/components/entities-saved-states/entity-record-item.js.map +1 -1
  61. package/build-module/components/entities-saved-states/entity-type-list.js +2 -1
  62. package/build-module/components/entities-saved-states/entity-type-list.js.map +1 -1
  63. package/build-module/components/entities-saved-states/index.js +67 -43
  64. package/build-module/components/entities-saved-states/index.js.map +1 -1
  65. package/build-module/components/post-actions/index.js +19 -28
  66. package/build-module/components/post-actions/index.js.map +1 -1
  67. package/build-module/components/post-card-panel/index.js +5 -5
  68. package/build-module/components/post-card-panel/index.js.map +1 -1
  69. package/build-module/components/post-featured-image/index.js +4 -2
  70. package/build-module/components/post-featured-image/index.js.map +1 -1
  71. package/build-module/components/post-template/block-theme.js +68 -48
  72. package/build-module/components/post-template/block-theme.js.map +1 -1
  73. package/build-module/components/post-template/classic-theme.js +30 -18
  74. package/build-module/components/post-template/classic-theme.js.map +1 -1
  75. package/build-module/components/post-template/create-new-template-modal.js +3 -1
  76. package/build-module/components/post-template/create-new-template-modal.js.map +1 -1
  77. package/build-module/components/post-template/panel.js +3 -11
  78. package/build-module/components/post-template/panel.js.map +1 -1
  79. package/build-module/components/preferences-modal/block-visibility.js +2 -1
  80. package/build-module/components/preferences-modal/block-visibility.js.map +1 -1
  81. package/build-module/components/preferences-modal/index.js +1 -1
  82. package/build-module/components/preferences-modal/index.js.map +1 -1
  83. package/build-module/components/preview-dropdown/index.js +6 -3
  84. package/build-module/components/preview-dropdown/index.js.map +1 -1
  85. package/build-module/components/provider/index.js +19 -18
  86. package/build-module/components/provider/index.js.map +1 -1
  87. package/build-module/components/sidebar/header.js +1 -1
  88. package/build-module/components/sidebar/header.js.map +1 -1
  89. package/build-module/components/sidebar/index.js +1 -1
  90. package/build-module/components/sidebar/index.js.map +1 -1
  91. package/build-module/components/start-page-options/index.js +148 -24
  92. package/build-module/components/start-page-options/index.js.map +1 -1
  93. package/build-module/components/visual-editor/edit-template-blocks-notification.js +1 -1
  94. package/build-module/components/visual-editor/edit-template-blocks-notification.js.map +1 -1
  95. package/build-module/store/private-actions.js +25 -0
  96. package/build-module/store/private-actions.js.map +1 -1
  97. package/build-module/store/private-selectors.js +44 -1
  98. package/build-module/store/private-selectors.js.map +1 -1
  99. package/build-module/store/selectors.js +8 -7
  100. package/build-module/store/selectors.js.map +1 -1
  101. package/build-module/utils/media-upload/index.js +5 -2
  102. package/build-module/utils/media-upload/index.js.map +1 -1
  103. package/build-style/style-rtl.css +51 -9
  104. package/build-style/style.css +51 -9
  105. package/build-types/components/document-outline/index.d.ts.map +1 -1
  106. package/build-types/components/document-outline/item.d.ts +2 -1
  107. package/build-types/components/document-outline/item.d.ts.map +1 -1
  108. package/build-types/components/entities-saved-states/entity-record-item.d.ts.map +1 -1
  109. package/build-types/components/entities-saved-states/entity-type-list.d.ts.map +1 -1
  110. package/build-types/components/entities-saved-states/index.d.ts +6 -2
  111. package/build-types/components/entities-saved-states/index.d.ts.map +1 -1
  112. package/build-types/components/post-actions/index.d.ts.map +1 -1
  113. package/build-types/components/post-card-panel/index.d.ts.map +1 -1
  114. package/build-types/components/post-template/block-theme.d.ts.map +1 -1
  115. package/build-types/components/post-template/classic-theme.d.ts.map +1 -1
  116. package/build-types/components/post-template/create-new-template-modal.d.ts.map +1 -1
  117. package/build-types/components/post-template/panel.d.ts.map +1 -1
  118. package/build-types/components/preferences-modal/block-visibility.d.ts.map +1 -1
  119. package/build-types/components/preview-dropdown/index.d.ts.map +1 -1
  120. package/build-types/components/provider/index.d.ts.map +1 -1
  121. package/build-types/components/start-page-options/index.d.ts +2 -1
  122. package/build-types/components/start-page-options/index.d.ts.map +1 -1
  123. package/build-types/store/private-actions.d.ts +4 -0
  124. package/build-types/store/private-actions.d.ts.map +1 -1
  125. package/build-types/store/private-selectors.d.ts +13 -0
  126. package/build-types/store/private-selectors.d.ts.map +1 -1
  127. package/build-types/store/selectors.d.ts.map +1 -1
  128. package/build-types/utils/media-upload/index.d.ts +3 -1
  129. package/build-types/utils/media-upload/index.d.ts.map +1 -1
  130. package/package.json +37 -37
  131. package/src/components/document-bar/index.js +2 -2
  132. package/src/components/document-outline/index.js +49 -17
  133. package/src/components/document-outline/item.js +38 -23
  134. package/src/components/document-outline/style.scss +2 -0
  135. package/src/components/entities-saved-states/entity-record-item.js +2 -4
  136. package/src/components/entities-saved-states/entity-type-list.js +6 -2
  137. package/src/components/entities-saved-states/index.js +98 -58
  138. package/src/components/entities-saved-states/style.scss +40 -5
  139. package/src/components/post-actions/index.js +19 -37
  140. package/src/components/post-card-panel/index.js +9 -7
  141. package/src/components/post-featured-image/index.js +2 -0
  142. package/src/components/post-template/block-theme.js +76 -56
  143. package/src/components/post-template/classic-theme.js +31 -15
  144. package/src/components/post-template/create-new-template-modal.js +1 -0
  145. package/src/components/post-template/panel.js +2 -12
  146. package/src/components/post-text-editor/style.scss +0 -2
  147. package/src/components/preferences-modal/block-visibility.js +2 -1
  148. package/src/components/preferences-modal/index.js +1 -1
  149. package/src/components/preview-dropdown/index.js +8 -6
  150. package/src/components/provider/index.js +21 -30
  151. package/src/components/sidebar/header.js +1 -1
  152. package/src/components/sidebar/index.js +1 -1
  153. package/src/components/start-page-options/index.js +149 -23
  154. package/src/components/start-page-options/style.scss +27 -0
  155. package/src/components/visual-editor/edit-template-blocks-notification.js +1 -1
  156. package/src/store/private-actions.js +33 -0
  157. package/src/store/private-selectors.js +59 -4
  158. package/src/store/selectors.js +9 -14
  159. package/src/utils/media-upload/index.js +3 -0
  160. package/tsconfig.tsbuildinfo +1 -1
@@ -4,12 +4,18 @@
4
4
  import { useSelect, useDispatch } from '@wordpress/data';
5
5
  import { decodeEntities } from '@wordpress/html-entities';
6
6
  import { DropdownMenu, MenuGroup, MenuItem } from '@wordpress/components';
7
+ import { useState, useMemo } from '@wordpress/element';
7
8
  import { __ } from '@wordpress/i18n';
8
9
  import { useEntityRecord, store as coreStore } from '@wordpress/core-data';
9
10
  import { check } from '@wordpress/icons';
10
11
  import { store as noticesStore } from '@wordpress/notices';
11
12
  import { store as preferencesStore } from '@wordpress/preferences';
12
13
 
14
+ /**
15
+ * Internal dependencies
16
+ */
17
+ import PostPanelRow from '../post-panel-row';
18
+
13
19
  /**
14
20
  * Internal dependencies
15
21
  */
@@ -19,11 +25,6 @@ import ResetDefaultTemplate from './reset-default-template';
19
25
  import { unlock } from '../../lock-unlock';
20
26
  import CreateNewTemplate from './create-new-template';
21
27
 
22
- const POPOVER_PROPS = {
23
- className: 'editor-post-template__dropdown',
24
- placement: 'bottom-start',
25
- };
26
-
27
28
  export default function BlockThemeControl( { id } ) {
28
29
  const {
29
30
  isTemplateHidden,
@@ -52,7 +53,9 @@ export default function BlockThemeControl( { id } ) {
52
53
  id
53
54
  );
54
55
  const { createSuccessNotice } = useDispatch( noticesStore );
55
- const { setRenderingMode } = useDispatch( editorStore );
56
+ const { setRenderingMode, setDefaultRenderingMode } = unlock(
57
+ useDispatch( editorStore )
58
+ );
56
59
 
57
60
  const canCreateTemplate = useSelect(
58
61
  ( select ) =>
@@ -63,6 +66,21 @@ export default function BlockThemeControl( { id } ) {
63
66
  []
64
67
  );
65
68
 
69
+ const [ popoverAnchor, setPopoverAnchor ] = useState( null );
70
+ // Memoize popoverProps to avoid returning a new object every time.
71
+ const popoverProps = useMemo(
72
+ () => ( {
73
+ // Anchor the popover to the middle of the entire row so that it doesn't
74
+ // move around when the label changes.
75
+ anchor: popoverAnchor,
76
+ className: 'editor-post-template__dropdown',
77
+ placement: 'left-start',
78
+ offset: 36,
79
+ shift: true,
80
+ } ),
81
+ [ popoverAnchor ]
82
+ );
83
+
66
84
  if ( ! hasResolved ) {
67
85
  return null;
68
86
  }
@@ -90,60 +108,62 @@ export default function BlockThemeControl( { id } ) {
90
108
  }
91
109
  };
92
110
  return (
93
- <DropdownMenu
94
- popoverProps={ POPOVER_PROPS }
95
- focusOnMount
96
- toggleProps={ {
97
- size: 'compact',
98
- variant: 'tertiary',
99
- tooltipPosition: 'middle left',
100
- } }
101
- label={ __( 'Template options' ) }
102
- text={ decodeEntities( template.title ) }
103
- icon={ null }
104
- >
105
- { ( { onClose } ) => (
106
- <>
107
- <MenuGroup>
108
- { canCreateTemplate && (
111
+ <PostPanelRow label={ __( 'Template' ) } ref={ setPopoverAnchor }>
112
+ <DropdownMenu
113
+ popoverProps={ popoverProps }
114
+ focusOnMount
115
+ toggleProps={ {
116
+ size: 'compact',
117
+ variant: 'tertiary',
118
+ tooltipPosition: 'middle left',
119
+ } }
120
+ label={ __( 'Template options' ) }
121
+ text={ decodeEntities( template.title ) }
122
+ icon={ null }
123
+ >
124
+ { ( { onClose } ) => (
125
+ <>
126
+ <MenuGroup>
127
+ { canCreateTemplate && (
128
+ <MenuItem
129
+ onClick={ () => {
130
+ onNavigateToEntityRecord( {
131
+ postId: template.id,
132
+ postType: 'wp_template',
133
+ } );
134
+ onClose();
135
+ mayShowTemplateEditNotice();
136
+ } }
137
+ >
138
+ { __( 'Edit template' ) }
139
+ </MenuItem>
140
+ ) }
141
+
142
+ <SwapTemplateButton onClick={ onClose } />
143
+ <ResetDefaultTemplate onClick={ onClose } />
144
+ { canCreateTemplate && (
145
+ <CreateNewTemplate onClick={ onClose } />
146
+ ) }
147
+ </MenuGroup>
148
+ <MenuGroup>
109
149
  <MenuItem
150
+ icon={ ! isTemplateHidden ? check : undefined }
151
+ isSelected={ ! isTemplateHidden }
152
+ role="menuitemcheckbox"
110
153
  onClick={ () => {
111
- onNavigateToEntityRecord( {
112
- postId: template.id,
113
- postType: 'wp_template',
114
- } );
115
- onClose();
116
- mayShowTemplateEditNotice();
154
+ const newRenderingMode = isTemplateHidden
155
+ ? 'template-locked'
156
+ : 'post-only';
157
+ setRenderingMode( newRenderingMode );
158
+ setDefaultRenderingMode( newRenderingMode );
117
159
  } }
118
160
  >
119
- { __( 'Edit template' ) }
161
+ { __( 'Show template' ) }
120
162
  </MenuItem>
121
- ) }
122
-
123
- <SwapTemplateButton onClick={ onClose } />
124
- <ResetDefaultTemplate onClick={ onClose } />
125
- { canCreateTemplate && (
126
- <CreateNewTemplate onClick={ onClose } />
127
- ) }
128
- </MenuGroup>
129
- <MenuGroup>
130
- <MenuItem
131
- icon={ ! isTemplateHidden ? check : undefined }
132
- isSelected={ ! isTemplateHidden }
133
- role="menuitemcheckbox"
134
- onClick={ () => {
135
- setRenderingMode(
136
- isTemplateHidden
137
- ? 'template-locked'
138
- : 'post-only'
139
- );
140
- } }
141
- >
142
- { __( 'Show template' ) }
143
- </MenuItem>
144
- </MenuGroup>
145
- </>
146
- ) }
147
- </DropdownMenu>
163
+ </MenuGroup>
164
+ </>
165
+ ) }
166
+ </DropdownMenu>
167
+ </PostPanelRow>
148
168
  );
149
169
  }
@@ -16,11 +16,7 @@ import { store as noticesStore } from '@wordpress/notices';
16
16
  import { store as editorStore } from '../../store';
17
17
  import CreateNewTemplateModal from './create-new-template-modal';
18
18
  import { useAllowSwitchingTemplates } from './hooks';
19
-
20
- const POPOVER_PROPS = {
21
- className: 'editor-post-template__dropdown',
22
- placement: 'bottom-start',
23
- };
19
+ import PostPanelRow from '../post-panel-row';
24
20
 
25
21
  function PostTemplateToggle( { isOpen, onClick } ) {
26
22
  const templateTitle = useSelect( ( select ) => {
@@ -216,17 +212,37 @@ function PostTemplateDropdownContent( { onClose } ) {
216
212
  }
217
213
 
218
214
  function ClassicThemeControl() {
215
+ const [ popoverAnchor, setPopoverAnchor ] = useState( null );
216
+ // Memoize popoverProps to avoid returning a new object every time.
217
+ const popoverProps = useMemo(
218
+ () => ( {
219
+ // Anchor the popover to the middle of the entire row so that it doesn't
220
+ // move around when the label changes.
221
+ anchor: popoverAnchor,
222
+ className: 'editor-post-template__dropdown',
223
+ placement: 'left-start',
224
+ offset: 36,
225
+ shift: true,
226
+ } ),
227
+ [ popoverAnchor ]
228
+ );
229
+
219
230
  return (
220
- <Dropdown
221
- popoverProps={ POPOVER_PROPS }
222
- focusOnMount
223
- renderToggle={ ( { isOpen, onToggle } ) => (
224
- <PostTemplateToggle isOpen={ isOpen } onClick={ onToggle } />
225
- ) }
226
- renderContent={ ( { onClose } ) => (
227
- <PostTemplateDropdownContent onClose={ onClose } />
228
- ) }
229
- />
231
+ <PostPanelRow label={ __( 'Template' ) } ref={ setPopoverAnchor }>
232
+ <Dropdown
233
+ popoverProps={ popoverProps }
234
+ focusOnMount
235
+ renderToggle={ ( { isOpen, onToggle } ) => (
236
+ <PostTemplateToggle
237
+ isOpen={ isOpen }
238
+ onClick={ onToggle }
239
+ />
240
+ ) }
241
+ renderContent={ ( { onClose } ) => (
242
+ <PostTemplateDropdownContent onClose={ onClose } />
243
+ ) }
244
+ />
245
+ </PostPanelRow>
230
246
  );
231
247
  }
232
248
 
@@ -126,6 +126,7 @@ export default function CreateNewTemplateModal( { onClose } ) {
126
126
  placeholder={ DEFAULT_TITLE }
127
127
  disabled={ isBusy }
128
128
  help={ __(
129
+ // eslint-disable-next-line no-restricted-syntax -- 'sidebar' is a common web design term for layouts
129
130
  'Describe the template, e.g. "Post with sidebar". A custom template can be manually applied to any post or page.'
130
131
  ) }
131
132
  />
@@ -2,7 +2,6 @@
2
2
  * WordPress dependencies
3
3
  */
4
4
  import { useSelect } from '@wordpress/data';
5
- import { __ } from '@wordpress/i18n';
6
5
  import { store as coreStore } from '@wordpress/core-data';
7
6
 
8
7
  /**
@@ -11,7 +10,6 @@ import { store as coreStore } from '@wordpress/core-data';
11
10
  import { store as editorStore } from '../../store';
12
11
  import ClassicThemeControl from './classic-theme';
13
12
  import BlockThemeControl from './block-theme';
14
- import PostPanelRow from '../post-panel-row';
15
13
 
16
14
  /**
17
15
  * Displays the template controls based on the current editor settings and user permissions.
@@ -65,19 +63,11 @@ export default function PostTemplatePanel() {
65
63
  }, [] );
66
64
 
67
65
  if ( ( ! isBlockTheme || ! canViewTemplates ) && isVisible ) {
68
- return (
69
- <PostPanelRow label={ __( 'Template' ) }>
70
- <ClassicThemeControl />
71
- </PostPanelRow>
72
- );
66
+ return <ClassicThemeControl />;
73
67
  }
74
68
 
75
69
  if ( isBlockTheme && !! templateId ) {
76
- return (
77
- <PostPanelRow label={ __( 'Template' ) }>
78
- <BlockThemeControl id={ templateId } />
79
- </PostPanelRow>
80
- );
70
+ return <BlockThemeControl id={ templateId } />;
81
71
  }
82
72
  return null;
83
73
  }
@@ -41,8 +41,6 @@ textarea.editor-post-text-editor {
41
41
 
42
42
  &::-moz-placeholder {
43
43
  color: $dark-gray-placeholder;
44
- // Override Firefox default.
45
- opacity: 1;
46
44
  }
47
45
 
48
46
  &:-ms-input-placeholder {
@@ -14,6 +14,7 @@ import { store as editorStore } from '../../store';
14
14
  import { unlock } from '../../lock-unlock';
15
15
 
16
16
  const { BlockManager } = unlock( blockEditorPrivateApis );
17
+ const EMPTY_ARRAY = [];
17
18
 
18
19
  export default function BlockVisibility() {
19
20
  const { showBlockTypes, hideBlockTypes } = unlock(
@@ -31,7 +32,7 @@ export default function BlockVisibility() {
31
32
  select( editorStore ).getEditorSettings().allowedBlockTypes,
32
33
  hiddenBlockTypes:
33
34
  select( preferencesStore ).get( 'core', 'hiddenBlockTypes' ) ??
34
- [],
35
+ EMPTY_ARRAY,
35
36
  };
36
37
  }, [] );
37
38
 
@@ -88,7 +88,7 @@ function PreferencesModalContents( { extraSections = {} } ) {
88
88
  scope="core"
89
89
  featureName="showListViewByDefault"
90
90
  help={ __(
91
- 'Opens the List View sidebar by default.'
91
+ 'Opens the List View panel by default.'
92
92
  ) }
93
93
  label={ __( 'Always open List View' ) }
94
94
  />
@@ -56,7 +56,9 @@ export default function PreviewDropdown( { forceIsAutosaveable, disabled } ) {
56
56
  templateId: getCurrentTemplateId(),
57
57
  };
58
58
  }, [] );
59
- const { setDeviceType, setRenderingMode } = useDispatch( editorStore );
59
+ const { setDeviceType, setRenderingMode, setDefaultRenderingMode } = unlock(
60
+ useDispatch( editorStore )
61
+ );
60
62
  const { resetZoomLevel } = unlock( useDispatch( blockEditorStore ) );
61
63
 
62
64
  const handleDevicePreviewChange = ( newDeviceType ) => {
@@ -160,11 +162,11 @@ export default function PreviewDropdown( { forceIsAutosaveable, disabled } ) {
160
162
  isSelected={ ! isTemplateHidden }
161
163
  role="menuitemcheckbox"
162
164
  onClick={ () => {
163
- setRenderingMode(
164
- isTemplateHidden
165
- ? 'template-locked'
166
- : 'post-only'
167
- );
165
+ const newRenderingMode = isTemplateHidden
166
+ ? 'template-locked'
167
+ : 'post-only';
168
+ setRenderingMode( newRenderingMode );
169
+ setDefaultRenderingMode( newRenderingMode );
168
170
  } }
169
171
  >
170
172
  { __( 'Show template' ) }
@@ -56,11 +56,6 @@ const NON_CONTEXTUAL_POST_TYPES = [
56
56
  'wp_template_part',
57
57
  ];
58
58
 
59
- /**
60
- * These are rendering modes that the editor supports.
61
- */
62
- const RENDERING_MODES = [ 'post-only', 'template-locked' ];
63
-
64
59
  /**
65
60
  * Depending on the post, template and template mode,
66
61
  * returns the appropriate blocks and change handlers for the block editor provider.
@@ -183,34 +178,28 @@ export const ExperimentalEditorProvider = withRegistryProvider(
183
178
  getEditorSelection,
184
179
  getRenderingMode,
185
180
  __unstableIsEditorReady,
186
- } = select( editorStore );
187
- const {
188
- getEntitiesConfig,
189
- getPostType,
190
- hasFinishedResolution,
191
- } = select( coreStore );
181
+ getDefaultRenderingMode,
182
+ } = unlock( select( editorStore ) );
183
+ const { getEntitiesConfig } = select( coreStore );
192
184
 
193
- const postTypeSupports = getPostType( post.type )?.supports;
194
- const hasLoadedPostObject = hasFinishedResolution(
195
- 'getPostType',
196
- [ post.type ]
197
- );
198
-
199
- const _defaultMode = Array.isArray( postTypeSupports?.editor )
200
- ? postTypeSupports.editor.find(
201
- ( features ) => 'default-mode' in features
202
- )?.[ 'default-mode' ]
203
- : undefined;
204
- const hasDefaultMode = RENDERING_MODES.includes( _defaultMode );
185
+ const _defaultMode = getDefaultRenderingMode( post.type );
186
+ /**
187
+ * To avoid content "flash", wait until rendering mode has been resolved.
188
+ * This is important for the initial render of the editor.
189
+ *
190
+ * - Wait for template to be resolved if the default mode is 'template-locked'.
191
+ * - Wait for default mode to be resolved otherwise.
192
+ */
193
+ const hasResolvedMode =
194
+ _defaultMode === 'template-locked'
195
+ ? hasTemplate
196
+ : _defaultMode !== undefined;
205
197
 
206
198
  return {
207
199
  editorSettings: getEditorSettings(),
208
- isReady: __unstableIsEditorReady() && hasLoadedPostObject,
200
+ isReady: __unstableIsEditorReady() && hasResolvedMode,
209
201
  mode: getRenderingMode(),
210
- defaultMode:
211
- hasTemplate && hasDefaultMode
212
- ? _defaultMode
213
- : 'post-only',
202
+ defaultMode: _defaultMode,
214
203
  selection: getEditorSelection(),
215
204
  postTypeEntities:
216
205
  post.type === 'wp_template'
@@ -221,7 +210,7 @@ export const ExperimentalEditorProvider = withRegistryProvider(
221
210
  [ post.type, hasTemplate ]
222
211
  );
223
212
 
224
- const shouldRenderTemplate = !! template && mode !== 'post-only';
213
+ const shouldRenderTemplate = hasTemplate && mode !== 'post-only';
225
214
  const rootLevelPost = shouldRenderTemplate ? template : post;
226
215
  const defaultBlockContext = useMemo( () => {
227
216
  const postContext = {};
@@ -338,7 +327,9 @@ export const ExperimentalEditorProvider = withRegistryProvider(
338
327
 
339
328
  // Sets the right rendering mode when loading the editor.
340
329
  useEffect( () => {
341
- setRenderingMode( defaultMode );
330
+ if ( defaultMode ) {
331
+ setRenderingMode( defaultMode );
332
+ }
342
333
  }, [ defaultMode, setRenderingMode ] );
343
334
 
344
335
  useHideBlocksFromInserter( post.type, mode );
@@ -22,7 +22,7 @@ const SidebarHeader = ( _, ref ) => {
22
22
  return {
23
23
  documentLabel:
24
24
  // translators: Default label for the Document sidebar tab, not selected.
25
- getPostTypeLabel() || _x( 'Document', 'noun, sidebar' ),
25
+ getPostTypeLabel() || _x( 'Document', 'noun, panel' ),
26
26
  };
27
27
  }, [] );
28
28
 
@@ -103,7 +103,7 @@ const SidebarContent = ( {
103
103
  headerClassName="editor-sidebar__panel-tabs"
104
104
  title={
105
105
  /* translators: button label text should, if possible, be under 16 characters. */
106
- _x( 'Settings', 'sidebar button label' )
106
+ _x( 'Settings', 'panel button label' )
107
107
  }
108
108
  toggleShortcut={ keyboardShortcut }
109
109
  icon={ isRTL() ? drawerLeft : drawerRight }
@@ -1,8 +1,16 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { useEffect } from '@wordpress/element';
4
+ import { Flex, FlexItem, Modal, ToggleControl } from '@wordpress/components';
5
+ import { __ } from '@wordpress/i18n';
6
+ import { useState, useMemo, useEffect } from '@wordpress/element';
7
+ import {
8
+ store as blockEditorStore,
9
+ __experimentalBlockPatternsList as BlockPatternsList,
10
+ } from '@wordpress/block-editor';
5
11
  import { useSelect, useDispatch } from '@wordpress/data';
12
+ import { store as coreStore } from '@wordpress/core-data';
13
+ import { __unstableSerializeAndClean } from '@wordpress/blocks';
6
14
  import { store as preferencesStore } from '@wordpress/preferences';
7
15
  import { store as interfaceStore } from '@wordpress/interface';
8
16
 
@@ -11,11 +19,132 @@ import { store as interfaceStore } from '@wordpress/interface';
11
19
  */
12
20
  import { store as editorStore } from '../../store';
13
21
 
22
+ export function useStartPatterns() {
23
+ // A pattern is a start pattern if it includes 'core/post-content' in its blockTypes,
24
+ // and it has no postTypes declared and the current post type is page or if
25
+ // the current post type is part of the postTypes declared.
26
+ const { blockPatternsWithPostContentBlockType, postType } = useSelect(
27
+ ( select ) => {
28
+ const { getPatternsByBlockTypes, getBlocksByName } =
29
+ select( blockEditorStore );
30
+ const { getCurrentPostType, getRenderingMode } =
31
+ select( editorStore );
32
+ const rootClientId =
33
+ getRenderingMode() === 'post-only'
34
+ ? ''
35
+ : getBlocksByName( 'core/post-content' )?.[ 0 ];
36
+ return {
37
+ blockPatternsWithPostContentBlockType: getPatternsByBlockTypes(
38
+ 'core/post-content',
39
+ rootClientId
40
+ ),
41
+ postType: getCurrentPostType(),
42
+ };
43
+ },
44
+ []
45
+ );
46
+
47
+ return useMemo( () => {
48
+ if ( ! blockPatternsWithPostContentBlockType?.length ) {
49
+ return [];
50
+ }
51
+
52
+ /*
53
+ * Filter patterns without postTypes declared if the current postType is page
54
+ * or patterns that declare the current postType in its post type array.
55
+ */
56
+ return blockPatternsWithPostContentBlockType.filter( ( pattern ) => {
57
+ return (
58
+ ( postType === 'page' && ! pattern.postTypes ) ||
59
+ ( Array.isArray( pattern.postTypes ) &&
60
+ pattern.postTypes.includes( postType ) )
61
+ );
62
+ } );
63
+ }, [ postType, blockPatternsWithPostContentBlockType ] );
64
+ }
65
+
66
+ function PatternSelection( { blockPatterns, onChoosePattern } ) {
67
+ const { editEntityRecord } = useDispatch( coreStore );
68
+ const { postType, postId } = useSelect( ( select ) => {
69
+ const { getCurrentPostType, getCurrentPostId } = select( editorStore );
70
+
71
+ return {
72
+ postType: getCurrentPostType(),
73
+ postId: getCurrentPostId(),
74
+ };
75
+ }, [] );
76
+ return (
77
+ <BlockPatternsList
78
+ blockPatterns={ blockPatterns }
79
+ onClickPattern={ ( _pattern, blocks ) => {
80
+ editEntityRecord( 'postType', postType, postId, {
81
+ blocks,
82
+ content: ( { blocks: blocksForSerialization = [] } ) =>
83
+ __unstableSerializeAndClean( blocksForSerialization ),
84
+ } );
85
+ onChoosePattern();
86
+ } }
87
+ />
88
+ );
89
+ }
90
+
91
+ function StartPageOptionsModal( { onClose } ) {
92
+ const [ showStartPatterns, setShowStartPatterns ] = useState( true );
93
+ const { set: setPreference } = useDispatch( preferencesStore );
94
+ const startPatterns = useStartPatterns();
95
+ const hasStartPattern = startPatterns.length > 0;
96
+
97
+ if ( ! hasStartPattern ) {
98
+ return null;
99
+ }
100
+
101
+ function handleClose() {
102
+ onClose();
103
+ setPreference( 'core', 'enableChoosePatternModal', showStartPatterns );
104
+ }
105
+
106
+ return (
107
+ <Modal
108
+ className="editor-start-page-options__modal"
109
+ title={ __( 'Choose a pattern' ) }
110
+ isFullScreen
111
+ onRequestClose={ handleClose }
112
+ >
113
+ <div className="editor-start-page-options__modal-content">
114
+ <PatternSelection
115
+ blockPatterns={ startPatterns }
116
+ onChoosePattern={ handleClose }
117
+ />
118
+ </div>
119
+ <Flex
120
+ className="editor-start-page-options__modal__actions"
121
+ justify="flex-end"
122
+ expanded={ false }
123
+ >
124
+ <FlexItem>
125
+ <ToggleControl
126
+ __nextHasNoMarginBottom
127
+ checked={ showStartPatterns }
128
+ label={ __( 'Show starter patterns' ) }
129
+ help={ __(
130
+ 'Shows starter patterns when creating a new page.'
131
+ ) }
132
+ onChange={ ( newValue ) => {
133
+ setShowStartPatterns( newValue );
134
+ } }
135
+ />
136
+ </FlexItem>
137
+ </Flex>
138
+ </Modal>
139
+ );
140
+ }
141
+
14
142
  export default function StartPageOptions() {
15
- const { postId, enabled } = useSelect( ( select ) => {
143
+ const [ isOpen, setIsOpen ] = useState( false );
144
+ const { isEditedPostDirty, isEditedPostEmpty } = useSelect( editorStore );
145
+ const { isModalActive } = useSelect( interfaceStore );
146
+ const { enabled, postId } = useSelect( ( select ) => {
16
147
  const { getCurrentPostId, getCurrentPostType } = select( editorStore );
17
- const preferencesModalActive =
18
- select( interfaceStore ).isModalActive( 'editor/preferences' );
19
148
  const choosePatternModalEnabled = select( preferencesStore ).get(
20
149
  'core',
21
150
  'enableChoosePatternModal'
@@ -23,36 +152,33 @@ export default function StartPageOptions() {
23
152
  return {
24
153
  postId: getCurrentPostId(),
25
154
  enabled:
26
- choosePatternModalEnabled &&
27
- ! preferencesModalActive &&
28
- 'page' === getCurrentPostType(),
155
+ choosePatternModalEnabled && 'page' === getCurrentPostType(),
29
156
  };
30
157
  }, [] );
31
- const { isEditedPostDirty, isEditedPostEmpty } = useSelect( editorStore );
32
- const { setIsInserterOpened } = useDispatch( editorStore );
33
158
 
159
+ // Note: The `postId` ensures the effect re-runs when pages are switched without remounting the component.
160
+ // Examples: changing pages in the List View, creating a new page via Command Palette.
34
161
  useEffect( () => {
35
- if ( ! enabled ) {
36
- return;
37
- }
38
-
39
162
  const isFreshPage = ! isEditedPostDirty() && isEditedPostEmpty();
40
- if ( isFreshPage ) {
41
- setIsInserterOpened( {
42
- tab: 'patterns',
43
- category: 'core/starter-content',
44
- } );
163
+ // Prevents immediately opening when features is enabled via preferences modal.
164
+ const isPreferencesModalActive = isModalActive( 'editor/preferences' );
165
+ if ( ! enabled || ! isFreshPage || isPreferencesModalActive ) {
166
+ return;
45
167
  }
46
168
 
47
- // Note: The `postId` ensures the effect re-runs when pages are switched without remounting the component.
48
- // Examples: changing pages in the List View, creating a new page via Command Palette.
169
+ // Open the modal after the initial render for a new page.
170
+ setIsOpen( true );
49
171
  }, [
50
- postId,
51
172
  enabled,
52
- setIsInserterOpened,
173
+ postId,
53
174
  isEditedPostDirty,
54
175
  isEditedPostEmpty,
176
+ isModalActive,
55
177
  ] );
56
178
 
57
- return null;
179
+ if ( ! isOpen ) {
180
+ return null;
181
+ }
182
+
183
+ return <StartPageOptionsModal onClose={ () => setIsOpen( false ) } />;
58
184
  }