@wordpress/editor 13.23.0 → 13.24.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 (112) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/components/entities-saved-states/index.js +15 -1
  3. package/build/components/entities-saved-states/index.js.map +1 -1
  4. package/build/components/index.js +26 -2
  5. package/build/components/index.js.map +1 -1
  6. package/build/components/post-author/panel.js +24 -0
  7. package/build/components/post-author/panel.js.map +1 -0
  8. package/build/components/post-panel-row/index.js +36 -0
  9. package/build/components/post-panel-row/index.js.map +1 -0
  10. package/build/components/post-saved-state/index.js +21 -16
  11. package/build/components/post-saved-state/index.js.map +1 -1
  12. package/build/components/post-schedule/panel.js +67 -0
  13. package/build/components/post-schedule/panel.js.map +1 -0
  14. package/build/components/post-sync-status/index.js +8 -4
  15. package/build/components/post-sync-status/index.js.map +1 -1
  16. package/build/components/post-title/constants.js +11 -0
  17. package/build/components/post-title/constants.js.map +1 -0
  18. package/build/components/post-title/index.js +61 -89
  19. package/build/components/post-title/index.js.map +1 -1
  20. package/build/components/post-title/post-title-raw.js +92 -0
  21. package/build/components/post-title/post-title-raw.js.map +1 -0
  22. package/build/components/post-title/use-post-title-focus.js +64 -0
  23. package/build/components/post-title/use-post-title-focus.js.map +1 -0
  24. package/build/components/post-title/use-post-title.js +41 -0
  25. package/build/components/post-title/use-post-title.js.map +1 -0
  26. package/build/components/post-url/panel.js +4 -3
  27. package/build/components/post-url/panel.js.map +1 -1
  28. package/build/components/provider/constants.js +9 -0
  29. package/build/components/provider/constants.js.map +1 -0
  30. package/build/components/provider/disable-non-page-content-blocks.js +63 -0
  31. package/build/components/provider/disable-non-page-content-blocks.js.map +1 -0
  32. package/build/components/provider/index.js +8 -7
  33. package/build/components/provider/index.js.map +1 -1
  34. package/build/private-apis.js +2 -0
  35. package/build/private-apis.js.map +1 -1
  36. package/build/store/actions.js +23 -2
  37. package/build/store/actions.js.map +1 -1
  38. package/build/store/reducer.js +10 -1
  39. package/build/store/reducer.js.map +1 -1
  40. package/build/store/selectors.js +16 -2
  41. package/build/store/selectors.js.map +1 -1
  42. package/build-module/components/entities-saved-states/index.js +16 -2
  43. package/build-module/components/entities-saved-states/index.js.map +1 -1
  44. package/build-module/components/index.js +3 -0
  45. package/build-module/components/index.js.map +1 -1
  46. package/build-module/components/post-author/panel.js +14 -0
  47. package/build-module/components/post-author/panel.js.map +1 -0
  48. package/build-module/components/post-panel-row/index.js +27 -0
  49. package/build-module/components/post-panel-row/index.js.map +1 -0
  50. package/build-module/components/post-saved-state/index.js +22 -17
  51. package/build-module/components/post-saved-state/index.js.map +1 -1
  52. package/build-module/components/post-schedule/panel.js +59 -0
  53. package/build-module/components/post-schedule/panel.js.map +1 -0
  54. package/build-module/components/post-sync-status/index.js +8 -5
  55. package/build-module/components/post-sync-status/index.js.map +1 -1
  56. package/build-module/components/post-title/constants.js +3 -0
  57. package/build-module/components/post-title/constants.js.map +1 -0
  58. package/build-module/components/post-title/index.js +62 -91
  59. package/build-module/components/post-title/index.js.map +1 -1
  60. package/build-module/components/post-title/post-title-raw.js +83 -0
  61. package/build-module/components/post-title/post-title-raw.js.map +1 -0
  62. package/build-module/components/post-title/use-post-title-focus.js +57 -0
  63. package/build-module/components/post-title/use-post-title-focus.js.map +1 -0
  64. package/build-module/components/post-title/use-post-title.js +33 -0
  65. package/build-module/components/post-title/use-post-title.js.map +1 -0
  66. package/build-module/components/post-url/panel.js +5 -4
  67. package/build-module/components/post-url/panel.js.map +1 -1
  68. package/build-module/components/provider/constants.js +2 -0
  69. package/build-module/components/provider/constants.js.map +1 -0
  70. package/build-module/components/provider/disable-non-page-content-blocks.js +56 -0
  71. package/build-module/components/provider/disable-non-page-content-blocks.js.map +1 -0
  72. package/build-module/components/provider/index.js +6 -4
  73. package/build-module/components/provider/index.js.map +1 -1
  74. package/build-module/private-apis.js +2 -0
  75. package/build-module/private-apis.js.map +1 -1
  76. package/build-module/store/actions.js +21 -0
  77. package/build-module/store/actions.js.map +1 -1
  78. package/build-module/store/reducer.js +9 -1
  79. package/build-module/store/reducer.js.map +1 -1
  80. package/build-module/store/selectors.js +11 -0
  81. package/build-module/store/selectors.js.map +1 -1
  82. package/build-style/style-rtl.css +51 -18
  83. package/build-style/style.css +51 -18
  84. package/package.json +31 -31
  85. package/src/components/entities-saved-states/index.js +16 -1
  86. package/src/components/index.js +3 -0
  87. package/src/components/post-author/panel.js +18 -0
  88. package/src/components/post-author/style.scss +7 -0
  89. package/src/components/post-panel-row/index.js +26 -0
  90. package/src/components/post-panel-row/style.scss +21 -0
  91. package/src/components/post-saved-state/index.js +46 -37
  92. package/src/components/post-schedule/panel.js +65 -0
  93. package/src/components/post-schedule/style.scss +23 -0
  94. package/src/components/post-sync-status/index.js +5 -6
  95. package/src/components/post-sync-status/style.scss +3 -17
  96. package/src/components/post-title/constants.js +4 -0
  97. package/src/components/post-title/index.js +56 -87
  98. package/src/components/post-title/post-title-raw.js +82 -0
  99. package/src/components/post-title/style.scss +5 -0
  100. package/src/components/post-title/use-post-title-focus.js +50 -0
  101. package/src/components/post-title/use-post-title.js +25 -0
  102. package/src/components/post-url/panel.js +4 -8
  103. package/src/components/post-url/style.scss +1 -12
  104. package/src/components/provider/README.md +0 -13
  105. package/src/components/provider/constants.js +5 -0
  106. package/src/components/provider/disable-non-page-content-blocks.js +55 -0
  107. package/src/components/provider/index.js +19 -9
  108. package/src/private-apis.js +2 -0
  109. package/src/store/actions.js +21 -0
  110. package/src/store/reducer.js +10 -0
  111. package/src/store/selectors.js +11 -0
  112. package/src/style.scss +4 -0
@@ -7,18 +7,12 @@ import classnames from 'classnames';
7
7
  * WordPress dependencies
8
8
  */
9
9
  import { __ } from '@wordpress/i18n';
10
- import {
11
- forwardRef,
12
- useEffect,
13
- useImperativeHandle,
14
- useRef,
15
- useState,
16
- } from '@wordpress/element';
10
+ import { forwardRef, useState } from '@wordpress/element';
17
11
  import { decodeEntities } from '@wordpress/html-entities';
18
- import { ENTER } from '@wordpress/keycodes';
19
12
  import { useSelect, useDispatch } from '@wordpress/data';
20
- import { pasteHandler } from '@wordpress/blocks';
21
13
  import { store as blockEditorStore } from '@wordpress/block-editor';
14
+ import { ENTER } from '@wordpress/keycodes';
15
+ import { pasteHandler } from '@wordpress/blocks';
22
16
  import {
23
17
  __unstableUseRichText as useRichText,
24
18
  create,
@@ -31,78 +25,45 @@ import { __unstableStripHTML as stripHTML } from '@wordpress/dom';
31
25
  /**
32
26
  * Internal dependencies
33
27
  */
34
- import PostTypeSupportCheck from '../post-type-support-check';
35
28
  import { store as editorStore } from '../../store';
36
-
37
- /**
38
- * Constants
39
- */
40
- const REGEXP_NEWLINES = /[\r\n]+/g;
29
+ import { DEFAULT_CLASSNAMES, REGEXP_NEWLINES } from './constants';
30
+ import usePostTitleFocus from './use-post-title-focus';
31
+ import usePostTitle from './use-post-title';
32
+ import PostTypeSupportCheck from '../post-type-support-check';
41
33
 
42
34
  function PostTitle( _, forwardedRef ) {
43
- const ref = useRef();
35
+ const { placeholder, hasFixedToolbar } = useSelect( ( select ) => {
36
+ const { getEditedPostAttribute } = select( editorStore );
37
+ const { getSettings } = select( blockEditorStore );
38
+ const { titlePlaceholder, hasFixedToolbar: _hasFixedToolbar } =
39
+ getSettings();
40
+
41
+ return {
42
+ title: getEditedPostAttribute( 'title' ),
43
+ placeholder: titlePlaceholder,
44
+ hasFixedToolbar: _hasFixedToolbar,
45
+ };
46
+ }, [] );
47
+
44
48
  const [ isSelected, setIsSelected ] = useState( false );
45
- const { editPost } = useDispatch( editorStore );
46
- const { insertDefaultBlock, clearSelectedBlock, insertBlocks } =
47
- useDispatch( blockEditorStore );
48
- const { isCleanNewPost, title, placeholder, hasFixedToolbar } = useSelect(
49
- ( select ) => {
50
- const { getEditedPostAttribute, isCleanNewPost: _isCleanNewPost } =
51
- select( editorStore );
52
- const { getSettings } = select( blockEditorStore );
53
- const { titlePlaceholder, hasFixedToolbar: _hasFixedToolbar } =
54
- getSettings();
55
-
56
- return {
57
- isCleanNewPost: _isCleanNewPost(),
58
- title: getEditedPostAttribute( 'title' ),
59
- placeholder: titlePlaceholder,
60
- hasFixedToolbar: _hasFixedToolbar,
61
- };
62
- },
63
- []
64
- );
65
49
 
66
- useImperativeHandle( forwardedRef, () => ( {
67
- focus: () => {
68
- ref?.current?.focus();
69
- },
70
- } ) );
50
+ const { ref: focusRef } = usePostTitleFocus( forwardedRef );
71
51
 
72
- useEffect( () => {
73
- if ( ! ref.current ) {
74
- return;
75
- }
52
+ const { title, setTitle: onUpdate } = usePostTitle();
76
53
 
77
- const { defaultView } = ref.current.ownerDocument;
78
- const { name, parent } = defaultView;
79
- const ownerDocument =
80
- name === 'editor-canvas' ? parent.document : defaultView.document;
81
- const { activeElement, body } = ownerDocument;
82
-
83
- // Only autofocus the title when the post is entirely empty. This should
84
- // only happen for a new post, which means we focus the title on new
85
- // post so the author can start typing right away, without needing to
86
- // click anything.
87
- if ( isCleanNewPost && ( ! activeElement || body === activeElement ) ) {
88
- ref.current.focus();
89
- }
90
- }, [ isCleanNewPost ] );
54
+ const [ selection, setSelection ] = useState( {} );
91
55
 
92
- function onEnterPress() {
93
- insertDefaultBlock( undefined, undefined, 0 );
56
+ const { clearSelectedBlock, insertBlocks, insertDefaultBlock } =
57
+ useDispatch( blockEditorStore );
58
+
59
+ function onChange( value ) {
60
+ onUpdate( value.replace( REGEXP_NEWLINES, ' ' ) );
94
61
  }
95
62
 
96
63
  function onInsertBlockAfter( blocks ) {
97
64
  insertBlocks( blocks, 0 );
98
65
  }
99
66
 
100
- function onUpdate( newTitle ) {
101
- editPost( { title: newTitle } );
102
- }
103
-
104
- const [ selection, setSelection ] = useState( {} );
105
-
106
67
  function onSelect() {
107
68
  setIsSelected( true );
108
69
  clearSelectedBlock();
@@ -113,8 +74,8 @@ function PostTitle( _, forwardedRef ) {
113
74
  setSelection( {} );
114
75
  }
115
76
 
116
- function onChange( value ) {
117
- onUpdate( value.replace( REGEXP_NEWLINES, ' ' ) );
77
+ function onEnterPress() {
78
+ insertDefaultBlock( undefined, undefined, 0 );
118
79
  }
119
80
 
120
81
  function onKeyDown( event ) {
@@ -170,7 +131,13 @@ function PostTitle( _, forwardedRef ) {
170
131
  ( firstBlock.name === 'core/heading' ||
171
132
  firstBlock.name === 'core/paragraph' )
172
133
  ) {
173
- onUpdate( stripHTML( firstBlock.attributes.content ) );
134
+ // Strip HTML to avoid unwanted HTML being added to the title.
135
+ // In the majority of cases it is assumed that HTML in the title
136
+ // is undesirable.
137
+ const contentNoHTML = stripHTML(
138
+ firstBlock.attributes.content
139
+ );
140
+ onUpdate( contentNoHTML );
174
141
  onInsertBlockAfter( content.slice( 1 ) );
175
142
  } else {
176
143
  onInsertBlockAfter( content );
@@ -180,10 +147,13 @@ function PostTitle( _, forwardedRef ) {
180
147
  ...create( { html: title } ),
181
148
  ...selection,
182
149
  };
183
- const newValue = insert(
184
- value,
185
- create( { html: stripHTML( content ) } )
186
- );
150
+
151
+ // Strip HTML to avoid unwanted HTML being added to the title.
152
+ // In the majority of cases it is assumed that HTML in the title
153
+ // is undesirable.
154
+ const contentNoHTML = stripHTML( content );
155
+
156
+ const newValue = insert( value, create( { html: contentNoHTML } ) );
187
157
  onUpdate( toHTMLString( { value: newValue } ) );
188
158
  setSelection( {
189
159
  start: newValue.start,
@@ -192,17 +162,9 @@ function PostTitle( _, forwardedRef ) {
192
162
  }
193
163
  }
194
164
 
195
- // The wp-block className is important for editor styles.
196
- // This same block is used in both the visual and the code editor.
197
- const className = classnames(
198
- 'wp-block wp-block-post-title block-editor-block-list__block editor-post-title editor-post-title__input rich-text',
199
- {
200
- 'is-selected': isSelected,
201
- 'has-fixed-toolbar': hasFixedToolbar,
202
- }
203
- );
204
165
  const decodedPlaceholder =
205
166
  decodeEntities( placeholder ) || __( 'Add title' );
167
+
206
168
  const { ref: richTextRef } = useRichText( {
207
169
  value: title,
208
170
  onChange,
@@ -221,14 +183,21 @@ function PostTitle( _, forwardedRef ) {
221
183
  };
222
184
  } );
223
185
  },
224
- __unstableDisableFormats: true,
186
+ __unstableDisableFormats: false,
187
+ } );
188
+
189
+ // The wp-block className is important for editor styles.
190
+ // This same block is used in both the visual and the code editor.
191
+ const className = classnames( DEFAULT_CLASSNAMES, {
192
+ 'is-selected': isSelected,
193
+ 'has-fixed-toolbar': hasFixedToolbar,
225
194
  } );
226
195
 
227
- /* eslint-disable jsx-a11y/heading-has-content, jsx-a11y/no-noninteractive-element-to-interactive-role */
228
196
  return (
197
+ /* eslint-disable jsx-a11y/heading-has-content, jsx-a11y/no-noninteractive-element-to-interactive-role */
229
198
  <PostTypeSupportCheck supportKeys="title">
230
199
  <h1
231
- ref={ useMergeRefs( [ richTextRef, ref ] ) }
200
+ ref={ useMergeRefs( [ richTextRef, focusRef ] ) }
232
201
  contentEditable
233
202
  className={ className }
234
203
  aria-label={ decodedPlaceholder }
@@ -241,8 +210,8 @@ function PostTitle( _, forwardedRef ) {
241
210
  onPaste={ onPaste }
242
211
  />
243
212
  </PostTypeSupportCheck>
213
+ /* eslint-enable jsx-a11y/heading-has-content, jsx-a11y/no-noninteractive-element-to-interactive-role */
244
214
  );
245
- /* eslint-enable jsx-a11y/heading-has-content, jsx-a11y/no-noninteractive-element-to-interactive-role */
246
215
  }
247
216
 
248
217
  export default forwardRef( PostTitle );
@@ -0,0 +1,82 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import classnames from 'classnames';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import { TextareaControl } from '@wordpress/components';
10
+ import { __ } from '@wordpress/i18n';
11
+ import { decodeEntities } from '@wordpress/html-entities';
12
+ import { useSelect } from '@wordpress/data';
13
+ import { store as blockEditorStore } from '@wordpress/block-editor';
14
+ import { useState, forwardRef } from '@wordpress/element';
15
+
16
+ /**
17
+ * Internal dependencies
18
+ */
19
+ import { DEFAULT_CLASSNAMES, REGEXP_NEWLINES } from './constants';
20
+ import usePostTitleFocus from './use-post-title-focus';
21
+ import usePostTitle from './use-post-title';
22
+
23
+ function PostTitleRaw( _, forwardedRef ) {
24
+ const { placeholder, hasFixedToolbar } = useSelect( ( select ) => {
25
+ const { getSettings } = select( blockEditorStore );
26
+ const { titlePlaceholder, hasFixedToolbar: _hasFixedToolbar } =
27
+ getSettings();
28
+
29
+ return {
30
+ placeholder: titlePlaceholder,
31
+ hasFixedToolbar: _hasFixedToolbar,
32
+ };
33
+ }, [] );
34
+
35
+ const [ isSelected, setIsSelected ] = useState( false );
36
+
37
+ const { title, setTitle: onUpdate } = usePostTitle();
38
+ const { ref: focusRef } = usePostTitleFocus( forwardedRef );
39
+
40
+ function onChange( value ) {
41
+ onUpdate( value.replace( REGEXP_NEWLINES, ' ' ) );
42
+ }
43
+
44
+ function onSelect() {
45
+ setIsSelected( true );
46
+ }
47
+
48
+ function onUnselect() {
49
+ setIsSelected( false );
50
+ }
51
+
52
+ // The wp-block className is important for editor styles.
53
+ // This same block is used in both the visual and the code editor.
54
+ const className = classnames( DEFAULT_CLASSNAMES, {
55
+ 'is-selected': isSelected,
56
+ 'has-fixed-toolbar': hasFixedToolbar,
57
+ 'is-raw-text': true,
58
+ } );
59
+
60
+ const decodedPlaceholder =
61
+ decodeEntities( placeholder ) || __( 'Add title' );
62
+
63
+ return (
64
+ <TextareaControl
65
+ ref={ focusRef }
66
+ value={ title }
67
+ onChange={ onChange }
68
+ onFocus={ onSelect }
69
+ onBlur={ onUnselect }
70
+ label={ placeholder }
71
+ className={ className }
72
+ placeholder={ decodedPlaceholder }
73
+ hideLabelFromVision={ true }
74
+ autoComplete="off"
75
+ dir="auto"
76
+ rows={ 1 }
77
+ __nextHasNoMarginBottom
78
+ />
79
+ );
80
+ }
81
+
82
+ export default forwardRef( PostTitleRaw );
@@ -0,0 +1,5 @@
1
+ // Raw Text Variant
2
+ .edit-post-text-editor__body .editor-post-title.is-raw-text {
3
+ margin-bottom: $grid-unit-30;
4
+ margin-top: 2px; // space for focus outline to appear.
5
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useEffect, useImperativeHandle, useRef } from '@wordpress/element';
5
+ import { useSelect } from '@wordpress/data';
6
+
7
+ /**
8
+ * Internal dependencies
9
+ */
10
+ import { store as editorStore } from '../../store';
11
+
12
+ export default function usePostTitleFocus( forwardedRef ) {
13
+ const ref = useRef();
14
+
15
+ const { isCleanNewPost } = useSelect( ( select ) => {
16
+ const { isCleanNewPost: _isCleanNewPost } = select( editorStore );
17
+
18
+ return {
19
+ isCleanNewPost: _isCleanNewPost(),
20
+ };
21
+ }, [] );
22
+
23
+ useImperativeHandle( forwardedRef, () => ( {
24
+ focus: () => {
25
+ ref?.current?.focus();
26
+ },
27
+ } ) );
28
+
29
+ useEffect( () => {
30
+ if ( ! ref.current ) {
31
+ return;
32
+ }
33
+
34
+ const { defaultView } = ref.current.ownerDocument;
35
+ const { name, parent } = defaultView;
36
+ const ownerDocument =
37
+ name === 'editor-canvas' ? parent.document : defaultView.document;
38
+ const { activeElement, body } = ownerDocument;
39
+
40
+ // Only autofocus the title when the post is entirely empty. This should
41
+ // only happen for a new post, which means we focus the title on new
42
+ // post so the author can start typing right away, without needing to
43
+ // click anything.
44
+ if ( isCleanNewPost && ( ! activeElement || body === activeElement ) ) {
45
+ ref.current.focus();
46
+ }
47
+ }, [ isCleanNewPost ] );
48
+
49
+ return { ref };
50
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useSelect, useDispatch } from '@wordpress/data';
5
+ /**
6
+ * Internal dependencies
7
+ */
8
+ import { store as editorStore } from '../../store';
9
+
10
+ export default function usePostTitle() {
11
+ const { editPost } = useDispatch( editorStore );
12
+ const { title } = useSelect( ( select ) => {
13
+ const { getEditedPostAttribute } = select( editorStore );
14
+
15
+ return {
16
+ title: getEditedPostAttribute( 'title' ),
17
+ };
18
+ }, [] );
19
+
20
+ function updateTitle( newTitle ) {
21
+ editPost( { title: newTitle } );
22
+ }
23
+
24
+ return { title, setTitle: updateTitle };
25
+ }
@@ -2,11 +2,7 @@
2
2
  * WordPress dependencies
3
3
  */
4
4
  import { useMemo, useState } from '@wordpress/element';
5
- import {
6
- __experimentalHStack as HStack,
7
- Dropdown,
8
- Button,
9
- } from '@wordpress/components';
5
+ import { Dropdown, Button } from '@wordpress/components';
10
6
  import { __, sprintf } from '@wordpress/i18n';
11
7
 
12
8
  /**
@@ -15,6 +11,7 @@ import { __, sprintf } from '@wordpress/i18n';
15
11
  import PostURLCheck from './check';
16
12
  import PostURL from './index';
17
13
  import { usePostURLLabel } from './label';
14
+ import PostPanelRow from '../post-panel-row';
18
15
 
19
16
  export default function PostURLPanel() {
20
17
  // Use internal state instead of a ref to make sure that the component
@@ -28,8 +25,7 @@ export default function PostURLPanel() {
28
25
 
29
26
  return (
30
27
  <PostURLCheck>
31
- <HStack className="editor-post-url__panel" ref={ setPopoverAnchor }>
32
- <span>{ __( 'URL' ) }</span>
28
+ <PostPanelRow label={ __( 'URL' ) } ref={ setPopoverAnchor }>
33
29
  <Dropdown
34
30
  popoverProps={ popoverProps }
35
31
  className="editor-post-url__panel-dropdown"
@@ -42,7 +38,7 @@ export default function PostURLPanel() {
42
38
  <PostURL onClose={ onClose } />
43
39
  ) }
44
40
  />
45
- </HStack>
41
+ </PostPanelRow>
46
42
  </PostURLCheck>
47
43
  );
48
44
  }
@@ -1,16 +1,5 @@
1
- .editor-post-url__panel {
2
- width: 100%;
3
- justify-content: flex-start;
4
- align-items: flex-start;
5
-
6
- span {
7
- display: block;
8
- width: 30%;
9
- }
10
- }
11
-
12
1
  .editor-post-url__panel-dropdown {
13
- width: 70%;
2
+ width: 100%;
14
3
  }
15
4
 
16
5
  .components-button.editor-post-url__panel-toggle {
@@ -22,19 +22,6 @@ The post object to edit
22
22
 
23
23
  The template object wrapper the edited post. This is optional and can only be used when the post type supports templates (like posts and pages).
24
24
 
25
- ### `mode`
26
-
27
- - **Type:** `String`
28
- - **Required** `no`
29
- - **default** `all`
30
-
31
- This is the rendering mode of the post editor. We support multiple rendering modes:
32
-
33
- - `all`: This is the default mode. It renders the post editor with all the features available. If a template is provided, it's preferred over the post.
34
- - `template-only`: This mode renders the editor with only the template blocks visible.
35
- - `post-only`: This mode extracts the post blocks from the template and renders only those. The idea is to allow the user to edit the post/page in isolation without the wrapping template.
36
- - `template-locked`: This mode renders both the template and the post blocks but the template blocks are locked and can't be edited. The post blocks are editable.
37
-
38
25
  ### `settings`
39
26
 
40
27
  - **Type:** `Object`
@@ -0,0 +1,5 @@
1
+ export const PAGE_CONTENT_BLOCK_TYPES = [
2
+ 'core/post-title',
3
+ 'core/post-featured-image',
4
+ 'core/post-content',
5
+ ];
@@ -0,0 +1,55 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useSelect, useDispatch } from '@wordpress/data';
5
+ import {
6
+ useBlockEditingMode,
7
+ store as blockEditorStore,
8
+ } from '@wordpress/block-editor';
9
+ import { useEffect } from '@wordpress/element';
10
+
11
+ /**
12
+ * Internal dependencies
13
+ */
14
+ import { PAGE_CONTENT_BLOCK_TYPES } from './constants';
15
+
16
+ function DisableBlock( { clientId } ) {
17
+ const isDescendentOfQueryLoop = useSelect(
18
+ ( select ) => {
19
+ const { getBlockParentsByBlockName } = select( blockEditorStore );
20
+ return (
21
+ getBlockParentsByBlockName( clientId, 'core/query' ).length !==
22
+ 0
23
+ );
24
+ },
25
+ [ clientId ]
26
+ );
27
+ const mode = isDescendentOfQueryLoop ? undefined : 'contentOnly';
28
+ const { setBlockEditingMode, unsetBlockEditingMode } =
29
+ useDispatch( blockEditorStore );
30
+ useEffect( () => {
31
+ if ( mode ) {
32
+ setBlockEditingMode( clientId, mode );
33
+ return () => {
34
+ unsetBlockEditingMode( clientId );
35
+ };
36
+ }
37
+ }, [ clientId, mode, setBlockEditingMode, unsetBlockEditingMode ] );
38
+ }
39
+
40
+ /**
41
+ * Component that when rendered, makes it so that the site editor allows only
42
+ * page content to be edited.
43
+ */
44
+ export default function DisableNonPageContentBlocks() {
45
+ useBlockEditingMode( 'disabled' );
46
+ const clientIds = useSelect( ( select ) => {
47
+ const { __experimentalGetGlobalBlocksByName } =
48
+ select( blockEditorStore );
49
+ return __experimentalGetGlobalBlocksByName( PAGE_CONTENT_BLOCK_TYPES );
50
+ }, [] );
51
+
52
+ return clientIds.map( ( clientId ) => {
53
+ return <DisableBlock key={ clientId } clientId={ clientId } />;
54
+ } );
55
+ }
@@ -22,16 +22,13 @@ import withRegistryProvider from './with-registry-provider';
22
22
  import { store as editorStore } from '../../store';
23
23
  import useBlockEditorSettings from './use-block-editor-settings';
24
24
  import { unlock } from '../../lock-unlock';
25
+ import DisableNonPageContentBlocks from './disable-non-page-content-blocks';
26
+ import { PAGE_CONTENT_BLOCK_TYPES } from './constants';
25
27
 
26
28
  const { ExperimentalBlockEditorProvider } = unlock( blockEditorPrivateApis );
27
29
  const { PatternsMenuItems } = unlock( editPatternsPrivateApis );
28
30
 
29
31
  const noop = () => {};
30
- export const PAGE_CONTENT_BLOCK_TYPES = [
31
- 'core/post-title',
32
- 'core/post-featured-image',
33
- 'core/post-content',
34
- ];
35
32
 
36
33
  /**
37
34
  * For the Navigation block editor, we need to force the block editor to contentOnly for that block.
@@ -128,6 +125,10 @@ function useBlockEditorProps( post, template, mode ) {
128
125
  }
129
126
 
130
127
  if ( mode === 'post-only' ) {
128
+ const postContentBlocks =
129
+ extractPageContentBlockTypesFromTemplateBlocks(
130
+ templateBlocks
131
+ );
131
132
  return [
132
133
  createBlock(
133
134
  'core/group',
@@ -141,9 +142,12 @@ function useBlockEditorProps( post, template, mode ) {
141
142
  },
142
143
  },
143
144
  },
144
- extractPageContentBlockTypesFromTemplateBlocks(
145
- templateBlocks
146
- )
145
+ postContentBlocks.length
146
+ ? postContentBlocks
147
+ : [
148
+ createBlock( 'core/post-title' ),
149
+ createBlock( 'core/post-content' ),
150
+ ]
147
151
  ),
148
152
  ];
149
153
  }
@@ -181,7 +185,6 @@ function useBlockEditorProps( post, template, mode ) {
181
185
 
182
186
  export const ExperimentalEditorProvider = withRegistryProvider(
183
187
  ( {
184
- mode = 'all',
185
188
  post,
186
189
  settings,
187
190
  recovery,
@@ -190,6 +193,10 @@ export const ExperimentalEditorProvider = withRegistryProvider(
190
193
  BlockEditorProviderComponent = ExperimentalBlockEditorProvider,
191
194
  __unstableTemplate: template,
192
195
  } ) => {
196
+ const mode = useSelect(
197
+ ( select ) => select( editorStore ).getRenderingMode(),
198
+ []
199
+ );
193
200
  const shouldRenderTemplate = !! template && mode !== 'post-only';
194
201
  const rootLevelPost = shouldRenderTemplate ? template : post;
195
202
  const defaultBlockContext = useMemo( () => {
@@ -308,6 +315,9 @@ export const ExperimentalEditorProvider = withRegistryProvider(
308
315
  >
309
316
  { children }
310
317
  <PatternsMenuItems />
318
+ { [ 'post-only', 'template-locked' ].includes(
319
+ mode
320
+ ) && <DisableNonPageContentBlocks /> }
311
321
  </BlockEditorProviderComponent>
312
322
  </BlockContextProvider>
313
323
  </EntityProvider>
@@ -5,11 +5,13 @@ import { ExperimentalEditorProvider } from './components/provider';
5
5
  import { lock } from './lock-unlock';
6
6
  import { EntitiesSavedStatesExtensible } from './components/entities-saved-states';
7
7
  import useBlockEditorSettings from './components/provider/use-block-editor-settings';
8
+ import PostPanelRow from './components/post-panel-row';
8
9
 
9
10
  export const privateApis = {};
10
11
  lock( privateApis, {
11
12
  ExperimentalEditorProvider,
12
13
  EntitiesSavedStatesExtensible,
14
+ PostPanelRow,
13
15
 
14
16
  // This is a temporary private API while we're updating the site editor to use EditorProvider.
15
17
  useBlockEditorSettings,
@@ -548,6 +548,27 @@ export function updateEditorSettings( settings ) {
548
548
  };
549
549
  }
550
550
 
551
+ /**
552
+ * Returns an action used to set the rendering mode of the post editor. We support multiple rendering modes:
553
+ *
554
+ * - `all`: This is the default mode. It renders the post editor with all the features available. If a template is provided, it's preferred over the post.
555
+ * - `template-only`: This mode renders the editor with only the template blocks visible.
556
+ * - `post-only`: This mode extracts the post blocks from the template and renders only those. The idea is to allow the user to edit the post/page in isolation without the wrapping template.
557
+ * - `template-locked`: This mode renders both the template and the post blocks but the template blocks are locked and can't be edited. The post blocks are editable.
558
+ *
559
+ * @param {string} mode Mode (one of 'template-only', 'post-only', 'template-locked' or 'all').
560
+ */
561
+ export const setRenderingMode =
562
+ ( mode ) =>
563
+ ( { dispatch, registry } ) => {
564
+ registry.dispatch( blockEditorStore ).clearSelectedBlock();
565
+
566
+ dispatch( {
567
+ type: 'SET_RENDERING_MODE',
568
+ mode,
569
+ } );
570
+ };
571
+
551
572
  /**
552
573
  * Backward compatibility
553
574
  */
@@ -279,6 +279,15 @@ export function editorSettings( state = EDITOR_SETTINGS_DEFAULTS, action ) {
279
279
  return state;
280
280
  }
281
281
 
282
+ export function renderingMode( state = 'all', action ) {
283
+ switch ( action.type ) {
284
+ case 'SET_RENDERING_MODE':
285
+ return action.mode;
286
+ }
287
+
288
+ return state;
289
+ }
290
+
282
291
  export default combineReducers( {
283
292
  postId,
284
293
  postType,
@@ -290,4 +299,5 @@ export default combineReducers( {
290
299
  isReady,
291
300
  editorSettings,
292
301
  postAutosavingLock,
302
+ renderingMode,
293
303
  } );
@@ -1188,6 +1188,17 @@ export function getEditorSettings( state ) {
1188
1188
  return state.editorSettings;
1189
1189
  }
1190
1190
 
1191
+ /**
1192
+ * Returns the post editor's rendering mode.
1193
+ *
1194
+ * @param {Object} state Editor state.
1195
+ *
1196
+ * @return {string} Rendering mode.
1197
+ */
1198
+ export function getRenderingMode( state ) {
1199
+ return state.renderingMode;
1200
+ }
1201
+
1191
1202
  /*
1192
1203
  * Backward compatibility
1193
1204
  */