@wordpress/editor 13.25.0 → 13.26.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 (223) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/LICENSE.md +1 -1
  3. package/build/components/document-bar/index.js +19 -7
  4. package/build/components/document-bar/index.js.map +1 -1
  5. package/build/components/document-outline/index.js +82 -1
  6. package/build/components/document-outline/index.js.map +1 -1
  7. package/build/components/document-tools/index.js +160 -0
  8. package/build/components/document-tools/index.js.map +1 -0
  9. package/build/components/editor-canvas/index.js +10 -4
  10. package/build/components/editor-canvas/index.js.map +1 -1
  11. package/build/components/entities-saved-states/index.js +3 -1
  12. package/build/components/entities-saved-states/index.js.map +1 -1
  13. package/build/components/global-keyboard-shortcuts/index.js +12 -2
  14. package/build/components/global-keyboard-shortcuts/index.js.map +1 -1
  15. package/build/components/global-keyboard-shortcuts/register-shortcuts.js +9 -0
  16. package/build/components/global-keyboard-shortcuts/register-shortcuts.js.map +1 -1
  17. package/build/components/index.js +56 -8
  18. package/build/components/index.js.map +1 -1
  19. package/build/components/index.native.js +9 -1
  20. package/build/components/index.native.js.map +1 -1
  21. package/build/components/inserter-sidebar/index.js +77 -0
  22. package/build/components/inserter-sidebar/index.js.map +1 -0
  23. package/build/components/list-view-sidebar/index.js +150 -0
  24. package/build/components/list-view-sidebar/index.js.map +1 -0
  25. package/build/components/list-view-sidebar/list-view-outline.js +28 -0
  26. package/build/components/list-view-sidebar/list-view-outline.js.map +1 -0
  27. package/build/components/offline-status/index.native.js +85 -0
  28. package/build/components/offline-status/index.native.js.map +1 -0
  29. package/build/components/page-attributes/panel.js +63 -0
  30. package/build/components/page-attributes/panel.js.map +1 -0
  31. package/build/components/post-discussion/panel.js +59 -0
  32. package/build/components/post-discussion/panel.js.map +1 -0
  33. package/build/components/post-excerpt/check.js +19 -0
  34. package/build/components/post-excerpt/check.js.map +1 -1
  35. package/build/components/post-excerpt/panel.js +55 -0
  36. package/build/components/post-excerpt/panel.js.map +1 -0
  37. package/build/components/post-excerpt/plugin.js +72 -0
  38. package/build/components/post-excerpt/plugin.js.map +1 -0
  39. package/build/components/post-featured-image/index.js +5 -8
  40. package/build/components/post-featured-image/index.js.map +1 -1
  41. package/build/components/post-featured-image/panel.js +60 -0
  42. package/build/components/post-featured-image/panel.js.map +1 -0
  43. package/build/components/post-last-revision/panel.js +27 -0
  44. package/build/components/post-last-revision/panel.js.map +1 -0
  45. package/build/components/post-saved-state/index.js +12 -8
  46. package/build/components/post-saved-state/index.js.map +1 -1
  47. package/build/components/post-taxonomies/panel.js +68 -0
  48. package/build/components/post-taxonomies/panel.js.map +1 -0
  49. package/build/components/post-template/block-theme.js +2 -1
  50. package/build/components/post-template/block-theme.js.map +1 -1
  51. package/build/components/post-template/hooks.js +6 -6
  52. package/build/components/post-template/hooks.js.map +1 -1
  53. package/build/components/post-template/panel.js +1 -2
  54. package/build/components/post-template/panel.js.map +1 -1
  55. package/build/components/post-template/swap-template-button.js +4 -2
  56. package/build/components/post-template/swap-template-button.js.map +1 -1
  57. package/build/components/post-title/index.native.js +25 -14
  58. package/build/components/post-title/index.native.js.map +1 -1
  59. package/build/components/post-view-link/index.js +58 -0
  60. package/build/components/post-view-link/index.js.map +1 -0
  61. package/build/components/post-visibility/check.js +5 -17
  62. package/build/components/post-visibility/check.js.map +1 -1
  63. package/build/components/preview-dropdown/index.js +8 -3
  64. package/build/components/preview-dropdown/index.js.map +1 -1
  65. package/build/components/provider/index.native.js +19 -0
  66. package/build/components/provider/index.native.js.map +1 -1
  67. package/build/components/provider/use-block-editor-settings.js +29 -5
  68. package/build/components/provider/use-block-editor-settings.js.map +1 -1
  69. package/build/private-apis.js +10 -0
  70. package/build/private-apis.js.map +1 -1
  71. package/build/store/actions.js +102 -2
  72. package/build/store/actions.js.map +1 -1
  73. package/build/store/index.js +2 -0
  74. package/build/store/index.js.map +1 -1
  75. package/build/store/private-selectors.js +52 -0
  76. package/build/store/private-selectors.js.map +1 -0
  77. package/build/store/reducer.js +78 -1
  78. package/build/store/reducer.js.map +1 -1
  79. package/build/store/selectors.js +76 -2
  80. package/build/store/selectors.js.map +1 -1
  81. package/build/utils/media-upload/index.js +8 -2
  82. package/build/utils/media-upload/index.js.map +1 -1
  83. package/build-module/components/document-bar/index.js +19 -7
  84. package/build-module/components/document-bar/index.js.map +1 -1
  85. package/build-module/components/document-outline/index.js +82 -1
  86. package/build-module/components/document-outline/index.js.map +1 -1
  87. package/build-module/components/document-tools/index.js +151 -0
  88. package/build-module/components/document-tools/index.js.map +1 -0
  89. package/build-module/components/editor-canvas/index.js +10 -4
  90. package/build-module/components/editor-canvas/index.js.map +1 -1
  91. package/build-module/components/entities-saved-states/index.js +3 -1
  92. package/build-module/components/entities-saved-states/index.js.map +1 -1
  93. package/build-module/components/global-keyboard-shortcuts/index.js +12 -2
  94. package/build-module/components/global-keyboard-shortcuts/index.js.map +1 -1
  95. package/build-module/components/global-keyboard-shortcuts/register-shortcuts.js +9 -0
  96. package/build-module/components/global-keyboard-shortcuts/register-shortcuts.js.map +1 -1
  97. package/build-module/components/index.js +6 -0
  98. package/build-module/components/index.js.map +1 -1
  99. package/build-module/components/index.native.js +1 -0
  100. package/build-module/components/index.native.js.map +1 -1
  101. package/build-module/components/inserter-sidebar/index.js +70 -0
  102. package/build-module/components/inserter-sidebar/index.js.map +1 -0
  103. package/build-module/components/list-view-sidebar/index.js +142 -0
  104. package/build-module/components/list-view-sidebar/index.js.map +1 -0
  105. package/build-module/components/list-view-sidebar/list-view-outline.js +20 -0
  106. package/build-module/components/list-view-sidebar/list-view-outline.js.map +1 -0
  107. package/build-module/components/offline-status/index.native.js +77 -0
  108. package/build-module/components/offline-status/index.native.js.map +1 -0
  109. package/build-module/components/page-attributes/panel.js +53 -0
  110. package/build-module/components/page-attributes/panel.js.map +1 -0
  111. package/build-module/components/post-discussion/panel.js +50 -0
  112. package/build-module/components/post-discussion/panel.js.map +1 -0
  113. package/build-module/components/post-excerpt/check.js +19 -0
  114. package/build-module/components/post-excerpt/check.js.map +1 -1
  115. package/build-module/components/post-excerpt/panel.js +48 -0
  116. package/build-module/components/post-excerpt/panel.js.map +1 -0
  117. package/build-module/components/post-excerpt/plugin.js +64 -0
  118. package/build-module/components/post-excerpt/plugin.js.map +1 -0
  119. package/build-module/components/post-featured-image/index.js +5 -8
  120. package/build-module/components/post-featured-image/index.js.map +1 -1
  121. package/build-module/components/post-featured-image/panel.js +51 -0
  122. package/build-module/components/post-featured-image/panel.js.map +1 -0
  123. package/build-module/components/post-last-revision/panel.js +18 -0
  124. package/build-module/components/post-last-revision/panel.js.map +1 -0
  125. package/build-module/components/post-saved-state/index.js +12 -8
  126. package/build-module/components/post-saved-state/index.js.map +1 -1
  127. package/build-module/components/post-taxonomies/panel.js +59 -0
  128. package/build-module/components/post-taxonomies/panel.js.map +1 -0
  129. package/build-module/components/post-template/block-theme.js +2 -1
  130. package/build-module/components/post-template/block-theme.js.map +1 -1
  131. package/build-module/components/post-template/hooks.js +6 -6
  132. package/build-module/components/post-template/hooks.js.map +1 -1
  133. package/build-module/components/post-template/panel.js +1 -2
  134. package/build-module/components/post-template/panel.js.map +1 -1
  135. package/build-module/components/post-template/swap-template-button.js +4 -2
  136. package/build-module/components/post-template/swap-template-button.js.map +1 -1
  137. package/build-module/components/post-title/index.native.js +26 -15
  138. package/build-module/components/post-title/index.native.js.map +1 -1
  139. package/build-module/components/post-view-link/index.js +51 -0
  140. package/build-module/components/post-view-link/index.js.map +1 -0
  141. package/build-module/components/post-visibility/check.js +6 -16
  142. package/build-module/components/post-visibility/check.js.map +1 -1
  143. package/build-module/components/preview-dropdown/index.js +8 -3
  144. package/build-module/components/preview-dropdown/index.js.map +1 -1
  145. package/build-module/components/provider/index.native.js +19 -0
  146. package/build-module/components/provider/index.native.js.map +1 -1
  147. package/build-module/components/provider/use-block-editor-settings.js +29 -5
  148. package/build-module/components/provider/use-block-editor-settings.js.map +1 -1
  149. package/build-module/private-apis.js +10 -0
  150. package/build-module/private-apis.js.map +1 -1
  151. package/build-module/store/actions.js +94 -0
  152. package/build-module/store/actions.js.map +1 -1
  153. package/build-module/store/index.js +2 -0
  154. package/build-module/store/index.js.map +1 -1
  155. package/build-module/store/private-selectors.js +43 -0
  156. package/build-module/store/private-selectors.js.map +1 -0
  157. package/build-module/store/reducer.js +74 -1
  158. package/build-module/store/reducer.js.map +1 -1
  159. package/build-module/store/selectors.js +67 -0
  160. package/build-module/store/selectors.js.map +1 -1
  161. package/build-module/utils/media-upload/index.js +8 -2
  162. package/build-module/utils/media-upload/index.js.map +1 -1
  163. package/build-style/style-rtl.css +251 -0
  164. package/build-style/style.css +251 -0
  165. package/package.json +32 -32
  166. package/src/components/document-bar/index.js +39 -28
  167. package/src/components/document-outline/index.js +48 -1
  168. package/src/components/document-outline/style.scss +12 -0
  169. package/src/components/document-tools/index.js +177 -0
  170. package/src/components/document-tools/style.scss +98 -0
  171. package/src/components/editor-canvas/index.js +12 -7
  172. package/src/components/editor-canvas/style.scss +5 -0
  173. package/src/components/entities-saved-states/index.js +3 -1
  174. package/src/components/entities-saved-states/style.scss +4 -0
  175. package/src/components/global-keyboard-shortcuts/index.js +12 -2
  176. package/src/components/global-keyboard-shortcuts/register-shortcuts.js +10 -0
  177. package/src/components/index.js +6 -0
  178. package/src/components/index.native.js +1 -0
  179. package/src/components/inserter-sidebar/index.js +73 -0
  180. package/src/components/inserter-sidebar/style.scss +22 -0
  181. package/src/components/list-view-sidebar/index.js +169 -0
  182. package/src/components/list-view-sidebar/list-view-outline.js +37 -0
  183. package/src/components/list-view-sidebar/style.scss +84 -0
  184. package/src/components/offline-status/index.native.js +101 -0
  185. package/src/components/offline-status/style.native.scss +28 -0
  186. package/src/components/offline-status/test/index.native.js +108 -0
  187. package/src/components/page-attributes/panel.js +62 -0
  188. package/src/components/post-discussion/panel.js +57 -0
  189. package/src/components/post-excerpt/check.js +18 -0
  190. package/src/components/post-excerpt/panel.js +57 -0
  191. package/src/components/post-excerpt/plugin.js +61 -0
  192. package/src/components/post-excerpt/test/plugin.js +36 -0
  193. package/src/components/post-featured-image/index.js +3 -7
  194. package/src/components/post-featured-image/panel.js +55 -0
  195. package/src/components/post-last-revision/panel.js +22 -0
  196. package/src/components/post-last-revision/style.scss +10 -0
  197. package/src/components/post-saved-state/index.js +8 -8
  198. package/src/components/post-taxonomies/panel.js +66 -0
  199. package/src/components/post-template/block-theme.js +2 -1
  200. package/src/components/post-template/hooks.js +6 -6
  201. package/src/components/post-template/panel.js +1 -2
  202. package/src/components/post-template/swap-template-button.js +7 -4
  203. package/src/components/post-title/index.native.js +32 -17
  204. package/src/components/post-title/style.scss +1 -0
  205. package/src/components/post-title/test/__snapshots__/index.native.js.snap +25 -0
  206. package/src/components/post-title/test/index.native.js +78 -0
  207. package/src/components/post-view-link/index.js +47 -0
  208. package/src/components/post-visibility/check.js +10 -15
  209. package/src/components/post-visibility/test/check.js +24 -13
  210. package/src/components/preview-dropdown/index.js +7 -10
  211. package/src/components/provider/index.native.js +29 -2
  212. package/src/components/provider/use-block-editor-settings.js +36 -8
  213. package/src/private-apis.js +10 -0
  214. package/src/store/actions.js +109 -0
  215. package/src/store/index.js +2 -0
  216. package/src/store/private-selectors.js +51 -0
  217. package/src/store/reducer.js +72 -0
  218. package/src/store/selectors.js +80 -0
  219. package/src/store/test/actions.js +56 -0
  220. package/src/store/test/reducer.js +98 -0
  221. package/src/store/test/selectors.js +49 -0
  222. package/src/style.scss +4 -0
  223. package/src/utils/media-upload/index.js +9 -2
@@ -0,0 +1,25 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`PostTitle does not update title with existing content when pasting HTML 1`] = `
4
+ "<!-- wp:heading -->
5
+ <h2 class="wp-block-heading">Howdy</h2>
6
+ <!-- /wp:heading -->
7
+
8
+ <!-- wp:heading -->
9
+ <h2 class="wp-block-heading">This is a heading.</h2>
10
+ <!-- /wp:heading -->
11
+
12
+ <!-- wp:paragraph -->
13
+ <p>This is a paragraph.</p>
14
+ <!-- /wp:paragraph -->"
15
+ `;
16
+
17
+ exports[`PostTitle populates empty title with first block content when pasting HTML 1`] = `
18
+ "<!-- wp:heading -->
19
+ <h2 class="wp-block-heading">This is a heading.</h2>
20
+ <!-- /wp:heading -->
21
+
22
+ <!-- wp:paragraph -->
23
+ <p>This is a paragraph.</p>
24
+ <!-- /wp:paragraph -->"
25
+ `;
@@ -0,0 +1,78 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import {
5
+ getEditorHtml,
6
+ getEditorTitle,
7
+ initializeEditor,
8
+ pasteIntoRichText,
9
+ selectRangeInRichText,
10
+ screen,
11
+ setupCoreBlocks,
12
+ within,
13
+ } from 'test/helpers';
14
+
15
+ setupCoreBlocks();
16
+
17
+ const HTML_MULTIPLE_TAGS = `<h2>Howdy</h2>
18
+ <h2>This is a heading.</h2>
19
+ <p>This is a paragraph.</p>`;
20
+
21
+ describe( 'PostTitle', () => {
22
+ it( 'populates empty title with first block content when pasting HTML', async () => {
23
+ await initializeEditor( { initialTitle: '' } );
24
+
25
+ const postTitle = within(
26
+ screen.getByTestId( 'post-title' )
27
+ ).getByPlaceholderText( 'Add title' );
28
+ pasteIntoRichText( postTitle, { html: HTML_MULTIPLE_TAGS } );
29
+
30
+ expect( console ).toHaveLogged();
31
+ expect( getEditorTitle() ).toBe( 'Howdy' );
32
+ expect( getEditorHtml() ).toMatchSnapshot();
33
+ } );
34
+
35
+ it( 'does not update title with existing content when pasting HTML', async () => {
36
+ const initialTitle = 'Hello';
37
+ await initializeEditor( { initialTitle } );
38
+
39
+ const postTitle = within(
40
+ screen.getByTestId( 'post-title' )
41
+ ).getByPlaceholderText( 'Add title' );
42
+ selectRangeInRichText( postTitle, 0 );
43
+ pasteIntoRichText( postTitle, { html: HTML_MULTIPLE_TAGS } );
44
+
45
+ expect( console ).toHaveLogged();
46
+ expect( getEditorTitle() ).toBe( initialTitle );
47
+ expect( getEditorHtml() ).toMatchSnapshot();
48
+ } );
49
+
50
+ it( 'updates title with existing content when pasting text', async () => {
51
+ await initializeEditor( { initialTitle: 'World' } );
52
+
53
+ const postTitle = within(
54
+ screen.getByTestId( 'post-title' )
55
+ ).getByPlaceholderText( 'Add title' );
56
+ selectRangeInRichText( postTitle, 0 );
57
+ pasteIntoRichText( postTitle, { text: 'Hello' } );
58
+
59
+ expect( console ).toHaveLogged();
60
+ expect( getEditorTitle() ).toBe( 'HelloWorld' );
61
+ expect( getEditorHtml() ).toBe( '' );
62
+ } );
63
+
64
+ it( 'does not add HTML to title when pasting span tag', async () => {
65
+ const pasteHTML = `<span style="border: 1px solid black">l</span>`;
66
+ await initializeEditor( { initialTitle: 'Helo' } );
67
+
68
+ const postTitle = within(
69
+ screen.getByTestId( 'post-title' )
70
+ ).getByPlaceholderText( 'Add title' );
71
+ selectRangeInRichText( postTitle, 2 );
72
+ pasteIntoRichText( postTitle, { html: pasteHTML } );
73
+
74
+ expect( console ).toHaveLogged();
75
+ expect( getEditorTitle() ).toBe( 'Hello' );
76
+ expect( getEditorHtml() ).toBe( '' );
77
+ } );
78
+ } );
@@ -0,0 +1,47 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __ } from '@wordpress/i18n';
5
+ import { Button } from '@wordpress/components';
6
+ import { external } from '@wordpress/icons';
7
+ import { store as coreStore } from '@wordpress/core-data';
8
+ import { useSelect } from '@wordpress/data';
9
+ import { store as preferencesStore } from '@wordpress/preferences';
10
+
11
+ /**
12
+ * Internal dependencies
13
+ */
14
+ import { store as editorStore } from '../../store';
15
+
16
+ export default function PostViewLink() {
17
+ const { hasLoaded, permalink, isPublished, label, showIconLabels } =
18
+ useSelect( ( select ) => {
19
+ // Grab post type to retrieve the view_item label.
20
+ const postTypeSlug = select( editorStore ).getCurrentPostType();
21
+ const postType = select( coreStore ).getPostType( postTypeSlug );
22
+ const { get } = select( preferencesStore );
23
+
24
+ return {
25
+ permalink: select( editorStore ).getPermalink(),
26
+ isPublished: select( editorStore ).isCurrentPostPublished(),
27
+ label: postType?.labels.view_item,
28
+ hasLoaded: !! postType,
29
+ showIconLabels: get( 'core', 'showIconLabels' ),
30
+ };
31
+ }, [] );
32
+
33
+ // Only render the view button if the post is published and has a permalink.
34
+ if ( ! isPublished || ! permalink || ! hasLoaded ) {
35
+ return null;
36
+ }
37
+
38
+ return (
39
+ <Button
40
+ icon={ external }
41
+ label={ label || __( 'View post' ) }
42
+ href={ permalink }
43
+ target="_blank"
44
+ showTooltip={ ! showIconLabels }
45
+ />
46
+ );
47
+ }
@@ -1,26 +1,21 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { compose } from '@wordpress/compose';
5
- import { withSelect } from '@wordpress/data';
4
+ import { useSelect } from '@wordpress/data';
6
5
 
7
6
  /**
8
7
  * Internal dependencies
9
8
  */
10
9
  import { store as editorStore } from '../../store';
11
10
 
12
- export function PostVisibilityCheck( { hasPublishAction, render } ) {
13
- const canEdit = hasPublishAction;
11
+ export default function PostVisibilityCheck( { render } ) {
12
+ const canEdit = useSelect( ( select ) => {
13
+ return (
14
+ select( editorStore ).getCurrentPost()._links?.[
15
+ 'wp:action-publish'
16
+ ] ?? false
17
+ );
18
+ } );
19
+
14
20
  return render( { canEdit } );
15
21
  }
16
-
17
- export default compose( [
18
- withSelect( ( select ) => {
19
- const { getCurrentPost, getCurrentPostType } = select( editorStore );
20
- return {
21
- hasPublishAction:
22
- getCurrentPost()._links?.[ 'wp:action-publish' ] ?? false,
23
- postType: getCurrentPostType(),
24
- };
25
- } ),
26
- ] )( PostVisibilityCheck );
@@ -3,32 +3,43 @@
3
3
  */
4
4
  import { render, screen } from '@testing-library/react';
5
5
 
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import { useSelect } from '@wordpress/data';
10
+
11
+ jest.mock( '@wordpress/data/src/components/use-select', () => jest.fn() );
12
+
6
13
  /**
7
14
  * Internal dependencies
8
15
  */
9
- import { PostVisibilityCheck } from '../check';
16
+ import PostVisibilityCheck from '../check';
17
+
18
+ function setupMockSelect( hasPublishAction ) {
19
+ useSelect.mockImplementation( ( mapSelect ) => {
20
+ return mapSelect( () => ( {
21
+ getCurrentPost: () => ( {
22
+ _links: {
23
+ 'wp:action-publish': hasPublishAction,
24
+ },
25
+ } ),
26
+ } ) );
27
+ } );
28
+ }
10
29
 
11
30
  describe( 'PostVisibilityCheck', () => {
12
31
  const renderProp = ( { canEdit } ) => ( canEdit ? 'yes' : 'no' );
13
32
 
14
33
  it( "should not render the edit link if the user doesn't have the right capability", () => {
15
- render(
16
- <PostVisibilityCheck
17
- hasPublishAction={ false }
18
- render={ renderProp }
19
- />
20
- );
34
+ setupMockSelect( false );
35
+ render( <PostVisibilityCheck render={ renderProp } /> );
21
36
  expect( screen.queryByText( 'yes' ) ).not.toBeInTheDocument();
22
37
  expect( screen.getByText( 'no' ) ).toBeVisible();
23
38
  } );
24
39
 
25
40
  it( 'should render if the user has the correct capability', () => {
26
- render(
27
- <PostVisibilityCheck
28
- hasPublishAction={ true }
29
- render={ renderProp }
30
- />
31
- );
41
+ setupMockSelect( true );
42
+ render( <PostVisibilityCheck render={ renderProp } /> );
32
43
  expect( screen.queryByText( 'no' ) ).not.toBeInTheDocument();
33
44
  expect( screen.getByText( 'yes' ) ).toBeVisible();
34
45
  } );
@@ -13,6 +13,7 @@ import { __ } from '@wordpress/i18n';
13
13
  import { check, desktop, mobile, tablet, external } from '@wordpress/icons';
14
14
  import { useSelect, useDispatch } from '@wordpress/data';
15
15
  import { store as coreStore } from '@wordpress/core-data';
16
+ import { store as preferencesStore } from '@wordpress/preferences';
16
17
 
17
18
  /**
18
19
  * Internal dependencies
@@ -20,25 +21,21 @@ import { store as coreStore } from '@wordpress/core-data';
20
21
  import { store as editorStore } from '../../store';
21
22
  import PostPreviewButton from '../post-preview-button';
22
23
 
23
- export default function PreviewDropdown( {
24
- showIconLabels,
25
- forceIsAutosaveable,
26
- disabled,
27
- } ) {
28
- const { deviceType, homeUrl, isTemplate, isViewable } = useSelect(
29
- ( select ) => {
24
+ export default function PreviewDropdown( { forceIsAutosaveable, disabled } ) {
25
+ const { deviceType, homeUrl, isTemplate, isViewable, showIconLabels } =
26
+ useSelect( ( select ) => {
30
27
  const { getDeviceType, getCurrentPostType } = select( editorStore );
31
28
  const { getUnstableBase, getPostType } = select( coreStore );
29
+ const { get } = select( preferencesStore );
32
30
  const _currentPostType = getCurrentPostType();
33
31
  return {
34
32
  deviceType: getDeviceType(),
35
33
  homeUrl: getUnstableBase()?.home,
36
34
  isTemplate: _currentPostType === 'wp_template',
37
35
  isViewable: getPostType( _currentPostType )?.viewable ?? false,
36
+ showIconLabels: get( 'core', 'showIconLabels' ),
38
37
  };
39
- },
40
- []
41
- );
38
+ }, [] );
42
39
  const { setDeviceType } = useDispatch( editorStore );
43
40
  const isMobile = useViewportMatch( 'medium', '<' );
44
41
  if ( isMobile ) return null;
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
+ import { BackHandler } from 'react-native';
4
5
  import memize from 'memize';
5
6
  import { SafeAreaProvider } from 'react-native-safe-area-context';
6
7
 
@@ -79,6 +80,8 @@ class NativeEditorProvider extends Component {
79
80
  this.post
80
81
  );
81
82
 
83
+ this.onHardwareBackPress = this.onHardwareBackPress.bind( this );
84
+
82
85
  this.getEditorSettings = memize(
83
86
  ( settings, capabilities ) => ( {
84
87
  ...settings,
@@ -191,6 +194,11 @@ class NativeEditorProvider extends Component {
191
194
  this.setState( { isHelpVisible: true } );
192
195
  } );
193
196
 
197
+ this.hardwareBackPressListener = BackHandler.addEventListener(
198
+ 'hardwareBackPress',
199
+ this.onHardwareBackPress
200
+ );
201
+
194
202
  // Request current block impressions from native app.
195
203
  requestBlockTypeImpressions( ( storedImpressions ) => {
196
204
  const impressions = { ...NEW_BLOCK_TYPES, ...storedImpressions };
@@ -250,6 +258,10 @@ class NativeEditorProvider extends Component {
250
258
  if ( this.subscriptionParentShowEditorHelp ) {
251
259
  this.subscriptionParentShowEditorHelp.remove();
252
260
  }
261
+
262
+ if ( this.hardwareBackPressListener ) {
263
+ this.hardwareBackPressListener.remove();
264
+ }
253
265
  }
254
266
 
255
267
  getThemeColors( { rawStyles, rawFeatures } ) {
@@ -280,6 +292,16 @@ class NativeEditorProvider extends Component {
280
292
  }
281
293
  }
282
294
 
295
+ onHardwareBackPress() {
296
+ const { clearSelectedBlock, selectedBlockIndex } = this.props;
297
+
298
+ if ( selectedBlockIndex !== -1 ) {
299
+ clearSelectedBlock();
300
+ return true;
301
+ }
302
+ return false;
303
+ }
304
+
283
305
  serializeToNativeAction() {
284
306
  const title = this.props.title;
285
307
  let html;
@@ -397,8 +419,12 @@ const ComposedNativeProvider = compose( [
397
419
  withDispatch( ( dispatch ) => {
398
420
  const { editPost, resetEditorBlocks, updateEditorSettings } =
399
421
  dispatch( editorStore );
400
- const { updateSettings, insertBlock, replaceBlock } =
401
- dispatch( blockEditorStore );
422
+ const {
423
+ clearSelectedBlock,
424
+ updateSettings,
425
+ insertBlock,
426
+ replaceBlock,
427
+ } = dispatch( blockEditorStore );
402
428
  const { switchEditorMode } = dispatch( editPostStore );
403
429
  const { addEntities, receiveEntityRecords } = dispatch( coreStore );
404
430
  const { createSuccessNotice, createErrorNotice } =
@@ -411,6 +437,7 @@ const ComposedNativeProvider = compose( [
411
437
  insertBlock,
412
438
  createSuccessNotice,
413
439
  createErrorNotice,
440
+ clearSelectedBlock,
414
441
  editTitle( title ) {
415
442
  editPost( { title } );
416
443
  },
@@ -9,6 +9,8 @@ import {
9
9
  __experimentalFetchUrlData as fetchUrlData,
10
10
  } from '@wordpress/core-data';
11
11
  import { __ } from '@wordpress/i18n';
12
+ import { store as preferencesStore } from '@wordpress/preferences';
13
+ import { useViewportMatch } from '@wordpress/compose';
12
14
 
13
15
  /**
14
16
  * Internal dependencies
@@ -25,7 +27,6 @@ const BLOCK_EDITOR_SETTINGS = [
25
27
  '__experimentalFeatures',
26
28
  '__experimentalGlobalStylesBaseStyles',
27
29
  '__experimentalPreferredStyleVariations',
28
- '__experimentalSetIsInserterOpened',
29
30
  '__unstableGalleryWithImageBlocks',
30
31
  'alignWide',
31
32
  'allowedBlockTypes',
@@ -46,20 +47,16 @@ const BLOCK_EDITOR_SETTINGS = [
46
47
  'enableCustomSpacing',
47
48
  'enableCustomUnits',
48
49
  'enableOpenverseMediaCategory',
49
- 'focusMode',
50
- 'distractionFree',
51
50
  'fontSizes',
52
51
  'gradients',
53
52
  'generateAnchors',
54
- 'hasFixedToolbar',
53
+ 'getPostLinkProps',
55
54
  'hasInlineToolbar',
56
- 'isDistractionFree',
57
55
  'imageDefaultSize',
58
56
  'imageDimensions',
59
57
  'imageEditing',
60
58
  'imageSizes',
61
59
  'isRTL',
62
- 'keepCaretInsideBlock',
63
60
  'locale',
64
61
  'maxWidth',
65
62
  'onUpdateDefaultBlockStyles',
@@ -88,7 +85,13 @@ const BLOCK_EDITOR_SETTINGS = [
88
85
  * @return {Object} Block Editor Settings.
89
86
  */
90
87
  function useBlockEditorSettings( settings, postType, postId ) {
88
+ const isLargeViewport = useViewportMatch( 'medium' );
91
89
  const {
90
+ allowRightClickOverrides,
91
+ focusMode,
92
+ hasFixedToolbar,
93
+ isDistractionFree,
94
+ keepCaretInsideBlock,
92
95
  reusableBlocks,
93
96
  hasUploadPermissions,
94
97
  canUseUnfilteredHTML,
@@ -110,17 +113,27 @@ function useBlockEditorSettings( settings, postType, postId ) {
110
113
  getBlockPatterns,
111
114
  getBlockPatternCategories,
112
115
  } = select( coreStore );
116
+ const { get } = select( preferencesStore );
113
117
 
114
118
  const siteSettings = canUser( 'read', 'settings' )
115
119
  ? getEntityRecord( 'root', 'site' )
116
120
  : undefined;
117
121
 
118
122
  return {
123
+ allowRightClickOverrides: get(
124
+ 'core',
125
+ 'allowRightClickOverrides'
126
+ ),
119
127
  canUseUnfilteredHTML: getRawEntityRecord(
120
128
  'postType',
121
129
  postType,
122
130
  postId
123
131
  )?._links?.hasOwnProperty( 'wp:action-unfiltered-html' ),
132
+ focusMode: get( 'core', 'focusMode' ),
133
+ hasFixedToolbar:
134
+ get( 'core', 'fixedToolbar' ) || ! isLargeViewport,
135
+ isDistractionFree: get( 'core', 'distractionFree' ),
136
+ keepCaretInsideBlock: get( 'core', 'keepCaretInsideBlock' ),
124
137
  reusableBlocks: isWeb
125
138
  ? getEntityRecords( 'postType', 'wp_block', {
126
139
  per_page: -1,
@@ -135,7 +148,7 @@ function useBlockEditorSettings( settings, postType, postId ) {
135
148
  restBlockPatternCategories: getBlockPatternCategories(),
136
149
  };
137
150
  },
138
- [ postType, postId ]
151
+ [ postType, postId, isLargeViewport ]
139
152
  );
140
153
 
141
154
  const settingsBlockPatterns =
@@ -177,7 +190,7 @@ function useBlockEditorSettings( settings, postType, postId ) {
177
190
  [ settingsBlockPatternCategories, restBlockPatternCategories ]
178
191
  );
179
192
 
180
- const { undo } = useDispatch( editorStore );
193
+ const { undo, setIsInserterOpened } = useDispatch( editorStore );
181
194
 
182
195
  const { saveEntityRecord } = useDispatch( coreStore );
183
196
 
@@ -202,6 +215,8 @@ function useBlockEditorSettings( settings, postType, postId ) {
202
215
  [ saveEntityRecord, userCanCreatePages ]
203
216
  );
204
217
 
218
+ const forceDisableFocusMode = settings.focusMode === false;
219
+
205
220
  return useMemo(
206
221
  () => ( {
207
222
  ...Object.fromEntries(
@@ -209,6 +224,11 @@ function useBlockEditorSettings( settings, postType, postId ) {
209
224
  BLOCK_EDITOR_SETTINGS.includes( key )
210
225
  )
211
226
  ),
227
+ allowRightClickOverrides,
228
+ focusMode: focusMode && ! forceDisableFocusMode,
229
+ hasFixedToolbar,
230
+ isDistractionFree,
231
+ keepCaretInsideBlock,
212
232
  mediaUpload: hasUploadPermissions ? mediaUpload : undefined,
213
233
  __experimentalReusableBlocks: reusableBlocks,
214
234
  __experimentalBlockPatterns: blockPatterns,
@@ -238,8 +258,15 @@ function useBlockEditorSettings( settings, postType, postId ) {
238
258
  postType === 'wp_navigation'
239
259
  ? [ [ 'core/navigation', {}, [] ] ]
240
260
  : settings.template,
261
+ __experimentalSetIsInserterOpened: setIsInserterOpened,
241
262
  } ),
242
263
  [
264
+ allowRightClickOverrides,
265
+ focusMode,
266
+ forceDisableFocusMode,
267
+ hasFixedToolbar,
268
+ isDistractionFree,
269
+ keepCaretInsideBlock,
243
270
  settings,
244
271
  hasUploadPermissions,
245
272
  reusableBlocks,
@@ -253,6 +280,7 @@ function useBlockEditorSettings( settings, postType, postId ) {
253
280
  pageOnFront,
254
281
  pageForPosts,
255
282
  postType,
283
+ setIsInserterOpened,
256
284
  ]
257
285
  );
258
286
  }
@@ -6,16 +6,26 @@ import { ExperimentalEditorProvider } from './components/provider';
6
6
  import { lock } from './lock-unlock';
7
7
  import { EntitiesSavedStatesExtensible } from './components/entities-saved-states';
8
8
  import useBlockEditorSettings from './components/provider/use-block-editor-settings';
9
+ import DocumentTools from './components/document-tools';
10
+ import InserterSidebar from './components/inserter-sidebar';
11
+ import ListViewSidebar from './components/list-view-sidebar';
9
12
  import PostPanelRow from './components/post-panel-row';
13
+ import PostViewLink from './components/post-view-link';
10
14
  import PreviewDropdown from './components/preview-dropdown';
15
+ import PluginPostExcerpt from './components/post-excerpt/plugin';
11
16
 
12
17
  export const privateApis = {};
13
18
  lock( privateApis, {
19
+ DocumentTools,
14
20
  EditorCanvas,
15
21
  ExperimentalEditorProvider,
16
22
  EntitiesSavedStatesExtensible,
23
+ InserterSidebar,
24
+ ListViewSidebar,
17
25
  PostPanelRow,
26
+ PostViewLink,
18
27
  PreviewDropdown,
28
+ PluginPostExcerpt,
19
29
 
20
30
  // This is a temporary private API while we're updating the site editor to use EditorProvider.
21
31
  useBlockEditorSettings,
@@ -611,6 +611,115 @@ export function setDeviceType( deviceType ) {
611
611
  };
612
612
  }
613
613
 
614
+ /**
615
+ * Returns an action object used to enable or disable a panel in the editor.
616
+ *
617
+ * @param {string} panelName A string that identifies the panel to enable or disable.
618
+ *
619
+ * @return {Object} Action object.
620
+ */
621
+ export const toggleEditorPanelEnabled =
622
+ ( panelName ) =>
623
+ ( { registry } ) => {
624
+ const inactivePanels =
625
+ registry
626
+ .select( preferencesStore )
627
+ .get( 'core', 'inactivePanels' ) ?? [];
628
+
629
+ const isPanelInactive = !! inactivePanels?.includes( panelName );
630
+
631
+ // If the panel is inactive, remove it to enable it, else add it to
632
+ // make it inactive.
633
+ let updatedInactivePanels;
634
+ if ( isPanelInactive ) {
635
+ updatedInactivePanels = inactivePanels.filter(
636
+ ( invactivePanelName ) => invactivePanelName !== panelName
637
+ );
638
+ } else {
639
+ updatedInactivePanels = [ ...inactivePanels, panelName ];
640
+ }
641
+
642
+ registry
643
+ .dispatch( preferencesStore )
644
+ .set( 'core', 'inactivePanels', updatedInactivePanels );
645
+ };
646
+
647
+ /**
648
+ * Opens a closed panel and closes an open panel.
649
+ *
650
+ * @param {string} panelName A string that identifies the panel to open or close.
651
+ */
652
+ export const toggleEditorPanelOpened =
653
+ ( panelName ) =>
654
+ ( { registry } ) => {
655
+ const openPanels =
656
+ registry.select( preferencesStore ).get( 'core', 'openPanels' ) ??
657
+ [];
658
+
659
+ const isPanelOpen = !! openPanels?.includes( panelName );
660
+
661
+ // If the panel is open, remove it to close it, else add it to
662
+ // make it open.
663
+ let updatedOpenPanels;
664
+ if ( isPanelOpen ) {
665
+ updatedOpenPanels = openPanels.filter(
666
+ ( openPanelName ) => openPanelName !== panelName
667
+ );
668
+ } else {
669
+ updatedOpenPanels = [ ...openPanels, panelName ];
670
+ }
671
+
672
+ registry
673
+ .dispatch( preferencesStore )
674
+ .set( 'core', 'openPanels', updatedOpenPanels );
675
+ };
676
+
677
+ /**
678
+ * Returns an action object used to remove a panel from the editor.
679
+ *
680
+ * @param {string} panelName A string that identifies the panel to remove.
681
+ *
682
+ * @return {Object} Action object.
683
+ */
684
+ export function removeEditorPanel( panelName ) {
685
+ return {
686
+ type: 'REMOVE_PANEL',
687
+ panelName,
688
+ };
689
+ }
690
+
691
+ /**
692
+ * Returns an action object used to open/close the inserter.
693
+ *
694
+ * @param {boolean|Object} value Whether the inserter should be
695
+ * opened (true) or closed (false).
696
+ * To specify an insertion point,
697
+ * use an object.
698
+ * @param {string} value.rootClientId The root client ID to insert at.
699
+ * @param {number} value.insertionIndex The index to insert at.
700
+ *
701
+ * @return {Object} Action object.
702
+ */
703
+ export function setIsInserterOpened( value ) {
704
+ return {
705
+ type: 'SET_IS_INSERTER_OPENED',
706
+ value,
707
+ };
708
+ }
709
+
710
+ /**
711
+ * Returns an action object used to open/close the list view.
712
+ *
713
+ * @param {boolean} isOpen A boolean representing whether the list view should be opened or closed.
714
+ * @return {Object} Action object.
715
+ */
716
+ export function setIsListViewOpened( isOpen ) {
717
+ return {
718
+ type: 'SET_IS_LIST_VIEW_OPENED',
719
+ isOpen,
720
+ };
721
+ }
722
+
614
723
  /**
615
724
  * Backward compatibility
616
725
  */
@@ -10,6 +10,7 @@ import reducer from './reducer';
10
10
  import * as selectors from './selectors';
11
11
  import * as actions from './actions';
12
12
  import * as privateActions from './private-actions';
13
+ import * as privateSelectors from './private-selectors';
13
14
  import { STORE_NAME } from './constants';
14
15
  import { unlock } from '../lock-unlock';
15
16
 
@@ -39,3 +40,4 @@ export const store = createReduxStore( STORE_NAME, {
39
40
 
40
41
  register( store );
41
42
  unlock( store ).registerPrivateActions( privateActions );
43
+ unlock( store ).registerPrivateSelectors( privateSelectors );