@wordpress/editor 13.26.0 → 13.27.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 (137) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/bindings/index.js +20 -0
  3. package/build/bindings/index.js.map +1 -0
  4. package/build/bindings/post-meta.js +52 -0
  5. package/build/bindings/post-meta.js.map +1 -0
  6. package/build/components/block-manager/category.js +106 -0
  7. package/build/components/block-manager/category.js.map +1 -0
  8. package/build/components/block-manager/checklist.js +35 -0
  9. package/build/components/block-manager/checklist.js.map +1 -0
  10. package/build/components/block-manager/index.js +130 -0
  11. package/build/components/block-manager/index.js.map +1 -0
  12. package/build/components/document-tools/index.js +58 -52
  13. package/build/components/document-tools/index.js.map +1 -1
  14. package/build/components/editor-canvas/index.js +4 -4
  15. package/build/components/editor-canvas/index.js.map +1 -1
  16. package/build/components/editor-notices/index.js +11 -11
  17. package/build/components/editor-notices/index.js.map +1 -1
  18. package/build/components/entities-saved-states/entity-type-list.js +38 -7
  19. package/build/components/entities-saved-states/entity-type-list.js.map +1 -1
  20. package/build/components/entities-saved-states/index.js +1 -1
  21. package/build/components/entities-saved-states/index.js.map +1 -1
  22. package/build/components/offline-status/index.native.js +1 -3
  23. package/build/components/offline-status/index.native.js.map +1 -1
  24. package/build/components/post-locked-modal/index.js +1 -1
  25. package/build/components/post-locked-modal/index.js.map +1 -1
  26. package/build/components/post-saved-state/index.js +10 -24
  27. package/build/components/post-saved-state/index.js.map +1 -1
  28. package/build/components/post-schedule/check.js +5 -16
  29. package/build/components/post-schedule/check.js.map +1 -1
  30. package/build/components/preferences-modal/enable-panel.js +42 -0
  31. package/build/components/preferences-modal/enable-panel.js.map +1 -0
  32. package/build/components/preferences-modal/enable-plugin-document-setting-panel.js +33 -0
  33. package/build/components/preferences-modal/enable-plugin-document-setting-panel.js.map +1 -0
  34. package/build/components/preferences-modal/index.js +186 -0
  35. package/build/components/preferences-modal/index.js.map +1 -0
  36. package/build/components/provider/disable-non-page-content-blocks.js +1 -4
  37. package/build/components/provider/disable-non-page-content-blocks.js.map +1 -1
  38. package/build/components/provider/use-block-editor-settings.js +34 -8
  39. package/build/components/provider/use-block-editor-settings.js.map +1 -1
  40. package/build/hooks/pattern-partial-syncing.js +12 -8
  41. package/build/hooks/pattern-partial-syncing.js.map +1 -1
  42. package/build/index.js +1 -0
  43. package/build/index.js.map +1 -1
  44. package/build/private-apis.js +6 -2
  45. package/build/private-apis.js.map +1 -1
  46. package/build/store/defaults.js +2 -0
  47. package/build/store/defaults.js.map +1 -1
  48. package/build/store/private-actions.js +33 -1
  49. package/build/store/private-actions.js.map +1 -1
  50. package/build/store/private-selectors.js +1 -1
  51. package/build/store/private-selectors.js.map +1 -1
  52. package/build-module/bindings/index.js +15 -0
  53. package/build-module/bindings/index.js.map +1 -0
  54. package/build-module/bindings/post-meta.js +45 -0
  55. package/build-module/bindings/post-meta.js.map +1 -0
  56. package/build-module/components/block-manager/category.js +97 -0
  57. package/build-module/components/block-manager/category.js.map +1 -0
  58. package/build-module/components/block-manager/checklist.js +27 -0
  59. package/build-module/components/block-manager/checklist.js.map +1 -0
  60. package/build-module/components/block-manager/index.js +121 -0
  61. package/build-module/components/block-manager/index.js.map +1 -0
  62. package/build-module/components/document-tools/index.js +58 -52
  63. package/build-module/components/document-tools/index.js.map +1 -1
  64. package/build-module/components/editor-canvas/index.js +4 -4
  65. package/build-module/components/editor-canvas/index.js.map +1 -1
  66. package/build-module/components/editor-notices/index.js +12 -12
  67. package/build-module/components/editor-notices/index.js.map +1 -1
  68. package/build-module/components/entities-saved-states/entity-type-list.js +39 -8
  69. package/build-module/components/entities-saved-states/entity-type-list.js.map +1 -1
  70. package/build-module/components/entities-saved-states/index.js +1 -1
  71. package/build-module/components/entities-saved-states/index.js.map +1 -1
  72. package/build-module/components/offline-status/index.native.js +1 -3
  73. package/build-module/components/offline-status/index.native.js.map +1 -1
  74. package/build-module/components/post-locked-modal/index.js +1 -1
  75. package/build-module/components/post-locked-modal/index.js.map +1 -1
  76. package/build-module/components/post-saved-state/index.js +11 -25
  77. package/build-module/components/post-saved-state/index.js.map +1 -1
  78. package/build-module/components/post-schedule/check.js +6 -15
  79. package/build-module/components/post-schedule/check.js.map +1 -1
  80. package/build-module/components/preferences-modal/enable-panel.js +34 -0
  81. package/build-module/components/preferences-modal/enable-panel.js.map +1 -0
  82. package/build-module/components/preferences-modal/enable-plugin-document-setting-panel.js +24 -0
  83. package/build-module/components/preferences-modal/enable-plugin-document-setting-panel.js.map +1 -0
  84. package/build-module/components/preferences-modal/index.js +179 -0
  85. package/build-module/components/preferences-modal/index.js.map +1 -0
  86. package/build-module/components/provider/disable-non-page-content-blocks.js +1 -4
  87. package/build-module/components/provider/disable-non-page-content-blocks.js.map +1 -1
  88. package/build-module/components/provider/use-block-editor-settings.js +35 -9
  89. package/build-module/components/provider/use-block-editor-settings.js.map +1 -1
  90. package/build-module/hooks/pattern-partial-syncing.js +12 -8
  91. package/build-module/hooks/pattern-partial-syncing.js.map +1 -1
  92. package/build-module/index.js +1 -0
  93. package/build-module/index.js.map +1 -1
  94. package/build-module/private-apis.js +6 -2
  95. package/build-module/private-apis.js.map +1 -1
  96. package/build-module/store/defaults.js +2 -0
  97. package/build-module/store/defaults.js.map +1 -1
  98. package/build-module/store/private-actions.js +29 -0
  99. package/build-module/store/private-actions.js.map +1 -1
  100. package/build-module/store/private-selectors.js +1 -1
  101. package/build-module/store/private-selectors.js.map +1 -1
  102. package/build-style/style-rtl.css +80 -12
  103. package/build-style/style.css +80 -12
  104. package/package.json +33 -33
  105. package/src/bindings/index.js +13 -0
  106. package/src/bindings/post-meta.js +42 -0
  107. package/src/components/block-manager/category.js +96 -0
  108. package/src/components/block-manager/checklist.js +30 -0
  109. package/src/components/block-manager/index.js +160 -0
  110. package/src/components/block-manager/style.scss +82 -0
  111. package/src/components/document-tools/index.js +9 -1
  112. package/src/components/editor-canvas/index.js +3 -2
  113. package/src/components/editor-notices/index.js +11 -12
  114. package/src/components/editor-notices/style.scss +0 -1
  115. package/src/components/entities-saved-states/entity-type-list.js +47 -5
  116. package/src/components/entities-saved-states/index.js +7 -7
  117. package/src/components/entities-saved-states/style.scss +4 -0
  118. package/src/components/offline-status/index.native.js +2 -4
  119. package/src/components/post-locked-modal/index.js +1 -1
  120. package/src/components/post-locked-modal/style.scss +0 -6
  121. package/src/components/post-saved-state/index.js +30 -47
  122. package/src/components/post-schedule/check.js +10 -14
  123. package/src/components/post-schedule/test/check.js +24 -9
  124. package/src/components/preferences-modal/enable-panel.js +30 -0
  125. package/src/components/preferences-modal/enable-plugin-document-setting-panel.js +23 -0
  126. package/src/components/preferences-modal/index.js +269 -0
  127. package/src/components/preferences-modal/test/index.js +28 -0
  128. package/src/components/provider/disable-non-page-content-blocks.js +3 -3
  129. package/src/components/provider/use-block-editor-settings.js +45 -17
  130. package/src/hooks/pattern-partial-syncing.js +26 -29
  131. package/src/index.js +1 -0
  132. package/src/private-apis.js +6 -2
  133. package/src/store/defaults.js +2 -0
  134. package/src/store/private-actions.js +49 -0
  135. package/src/store/private-selectors.js +1 -1
  136. package/src/style.scss +1 -1
  137. package/src/components/editor-canvas/style.scss +0 -5
@@ -0,0 +1,160 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { store as blocksStore } from '@wordpress/blocks';
5
+ import { withSelect, withDispatch } from '@wordpress/data';
6
+ import { SearchControl, Button } from '@wordpress/components';
7
+ import { __, _n, sprintf } from '@wordpress/i18n';
8
+ import { useEffect, useState } from '@wordpress/element';
9
+ import { useDebounce, compose } from '@wordpress/compose';
10
+ import { speak } from '@wordpress/a11y';
11
+ import { store as preferencesStore } from '@wordpress/preferences';
12
+
13
+ /**
14
+ * Internal dependencies
15
+ */
16
+ import { unlock } from '../../lock-unlock';
17
+ import { store as editorStore } from '../../store';
18
+ import BlockManagerCategory from './category';
19
+
20
+ function BlockManager( {
21
+ blockTypes,
22
+ categories,
23
+ hasBlockSupport,
24
+ isMatchingSearchTerm,
25
+ numberOfHiddenBlocks,
26
+ enableAllBlockTypes,
27
+ } ) {
28
+ const debouncedSpeak = useDebounce( speak, 500 );
29
+ const [ search, setSearch ] = useState( '' );
30
+
31
+ // Filtering occurs here (as opposed to `withSelect`) to avoid
32
+ // wasted renders by consequence of `Array#filter` producing
33
+ // a new value reference on each call.
34
+ blockTypes = blockTypes.filter(
35
+ ( blockType ) =>
36
+ hasBlockSupport( blockType, 'inserter', true ) &&
37
+ ( ! search || isMatchingSearchTerm( blockType, search ) ) &&
38
+ ( ! blockType.parent ||
39
+ blockType.parent.includes( 'core/post-content' ) )
40
+ );
41
+
42
+ // Announce search results on change
43
+ useEffect( () => {
44
+ if ( ! search ) {
45
+ return;
46
+ }
47
+ const count = blockTypes.length;
48
+ const resultsFoundMessage = sprintf(
49
+ /* translators: %d: number of results. */
50
+ _n( '%d result found.', '%d results found.', count ),
51
+ count
52
+ );
53
+ debouncedSpeak( resultsFoundMessage );
54
+ }, [ blockTypes.length, search, debouncedSpeak ] );
55
+
56
+ return (
57
+ <div className="editor-block-manager__content">
58
+ { !! numberOfHiddenBlocks && (
59
+ <div className="editor-block-manager__disabled-blocks-count">
60
+ { sprintf(
61
+ /* translators: %d: number of blocks. */
62
+ _n(
63
+ '%d block is hidden.',
64
+ '%d blocks are hidden.',
65
+ numberOfHiddenBlocks
66
+ ),
67
+ numberOfHiddenBlocks
68
+ ) }
69
+ <Button
70
+ variant="link"
71
+ onClick={ () => enableAllBlockTypes( blockTypes ) }
72
+ >
73
+ { __( 'Reset' ) }
74
+ </Button>
75
+ </div>
76
+ ) }
77
+ <SearchControl
78
+ __nextHasNoMarginBottom
79
+ label={ __( 'Search for a block' ) }
80
+ placeholder={ __( 'Search for a block' ) }
81
+ value={ search }
82
+ onChange={ ( nextSearch ) => setSearch( nextSearch ) }
83
+ className="editor-block-manager__search"
84
+ />
85
+ <div
86
+ tabIndex="0"
87
+ role="region"
88
+ aria-label={ __( 'Available block types' ) }
89
+ className="editor-block-manager__results"
90
+ >
91
+ { blockTypes.length === 0 && (
92
+ <p className="editor-block-manager__no-results">
93
+ { __( 'No blocks found.' ) }
94
+ </p>
95
+ ) }
96
+ { categories.map( ( category ) => (
97
+ <BlockManagerCategory
98
+ key={ category.slug }
99
+ title={ category.title }
100
+ blockTypes={ blockTypes.filter(
101
+ ( blockType ) =>
102
+ blockType.category === category.slug
103
+ ) }
104
+ />
105
+ ) ) }
106
+ <BlockManagerCategory
107
+ title={ __( 'Uncategorized' ) }
108
+ blockTypes={ blockTypes.filter(
109
+ ( { category } ) => ! category
110
+ ) }
111
+ />
112
+ </div>
113
+ </div>
114
+ );
115
+ }
116
+
117
+ export default compose( [
118
+ withSelect( ( select ) => {
119
+ const {
120
+ getBlockTypes,
121
+ getCategories,
122
+ hasBlockSupport,
123
+ isMatchingSearchTerm,
124
+ } = select( blocksStore );
125
+ const { get } = select( preferencesStore );
126
+
127
+ // Some hidden blocks become unregistered
128
+ // by removing for instance the plugin that registered them, yet
129
+ // they're still remain as hidden by the user's action.
130
+ // We consider "hidden", blocks which were hidden and
131
+ // are still registered.
132
+ const blockTypes = getBlockTypes();
133
+ const hiddenBlockTypes = (
134
+ get( 'core', 'hiddenBlockTypes' ) ?? []
135
+ ).filter( ( hiddenBlock ) => {
136
+ return blockTypes.some(
137
+ ( registeredBlock ) => registeredBlock.name === hiddenBlock
138
+ );
139
+ } );
140
+ const numberOfHiddenBlocks =
141
+ Array.isArray( hiddenBlockTypes ) && hiddenBlockTypes.length;
142
+
143
+ return {
144
+ blockTypes,
145
+ categories: getCategories(),
146
+ hasBlockSupport,
147
+ isMatchingSearchTerm,
148
+ numberOfHiddenBlocks,
149
+ };
150
+ } ),
151
+ withDispatch( ( dispatch ) => {
152
+ const { showBlockTypes } = unlock( dispatch( editorStore ) );
153
+ return {
154
+ enableAllBlockTypes: ( blockTypes ) => {
155
+ const blockNames = blockTypes.map( ( { name } ) => name );
156
+ showBlockTypes( blockNames );
157
+ },
158
+ };
159
+ } ),
160
+ ] )( BlockManager );
@@ -0,0 +1,82 @@
1
+ .editor-block-manager__no-results {
2
+ font-style: italic;
3
+ padding: $grid-unit-30 0;
4
+ text-align: center;
5
+ }
6
+
7
+ .editor-block-manager__search {
8
+ margin: $grid-unit-20 0;
9
+ }
10
+
11
+ .editor-block-manager__disabled-blocks-count {
12
+ border: 1px solid $gray-300;
13
+ border-width: 1px 0;
14
+ // Cover up horizontal areas off the sides of the box rectangle
15
+ box-shadow: -$grid-unit-40 0 0 0 $white, $grid-unit-40 0 0 0 $white;
16
+ padding: $grid-unit-10;
17
+ background-color: $white;
18
+ text-align: center;
19
+ position: sticky;
20
+ // When sticking, tuck the top border beneath the modal header border
21
+ top: ($grid-unit-05 + 1) * -1;
22
+ z-index: z-index(".editor-block-manager__disabled-blocks-count");
23
+
24
+ // Stick the category titles to the bottom
25
+ ~ .editor-block-manager__results .editor-block-manager__category-title {
26
+ top: $grid-unit-40 - 1;
27
+ }
28
+ .is-link {
29
+ margin-left: 12px;
30
+ }
31
+ }
32
+
33
+ .editor-block-manager__category {
34
+ margin: 0 0 $grid-unit-30 0;
35
+ }
36
+
37
+ .editor-block-manager__category-title {
38
+ position: sticky;
39
+ top: - $grid-unit-05; // Offsets the top padding on the modal content container
40
+ padding: $grid-unit-20 0;
41
+ background-color: $white;
42
+ z-index: z-index(".editor-block-manager__category-title");
43
+
44
+ .components-checkbox-control__label {
45
+ font-weight: 600;
46
+ }
47
+ }
48
+
49
+ .editor-block-manager__checklist {
50
+ margin-top: 0;
51
+ }
52
+
53
+ .editor-block-manager__category-title,
54
+ .editor-block-manager__checklist-item {
55
+ border-bottom: 1px solid $gray-300;
56
+ }
57
+
58
+ .editor-block-manager__checklist-item {
59
+ display: flex;
60
+ justify-content: space-between;
61
+ align-items: center;
62
+ margin-bottom: 0;
63
+ padding: $grid-unit-10 0 $grid-unit-10 $grid-unit-20;
64
+
65
+ .components-modal__content &.components-checkbox-control__input-container {
66
+ margin: 0 $grid-unit-10;
67
+ }
68
+
69
+ .block-editor-block-icon {
70
+ margin-right: 10px;
71
+ fill: $gray-900;
72
+ }
73
+ }
74
+
75
+ .editor-block-manager__results {
76
+ border-top: $border-width solid $gray-300;
77
+ }
78
+
79
+ // Remove the top border from results when adjacent to the disabled block count
80
+ .editor-block-manager__disabled-blocks-count + .editor-block-manager__results {
81
+ border-top-width: 0;
82
+ }
@@ -104,8 +104,16 @@ function DocumentTools( {
104
104
  const shortLabel = ! isInserterOpened ? __( 'Add' ) : __( 'Close' );
105
105
 
106
106
  return (
107
+ // Some plugins expect and use the `edit-post-header-toolbar` CSS class to
108
+ // find the toolbar and inject UI elements into it. This is not officially
109
+ // supported, but we're keeping it in the list of class names for backwards
110
+ // compatibility.
107
111
  <NavigableToolbar
108
- className={ classnames( 'editor-document-tools', className ) }
112
+ className={ classnames(
113
+ 'editor-document-tools',
114
+ 'edit-post-header-toolbar',
115
+ className
116
+ ) }
109
117
  aria-label={ toolbarAriaLabel }
110
118
  shouldUseKeyboardFocusShortcut={ ! blockToolbarCanBeFocused }
111
119
  variant="unstyled"
@@ -12,7 +12,7 @@ import {
12
12
  __unstableUseTypewriter as useTypewriter,
13
13
  __unstableUseTypingObserver as useTypingObserver,
14
14
  useSettings,
15
- __experimentalRecursionProvider as RecursionProvider,
15
+ RecursionProvider,
16
16
  privateApis as blockEditorPrivateApis,
17
17
  __experimentalUseResizeCanvas as useResizeCanvas,
18
18
  } from '@wordpress/block-editor';
@@ -364,7 +364,8 @@ function EditorCanvas( {
364
364
  'is-' + deviceType.toLowerCase() + '-preview',
365
365
  renderingMode !== 'post-only'
366
366
  ? 'wp-site-blocks'
367
- : `${ blockListLayoutClass } wp-block-post-content` // Ensure root level blocks receive default/flow blockGap styling rules.
367
+ : `${ blockListLayoutClass } wp-block-post-content`, // Ensure root level blocks receive default/flow blockGap styling rules.
368
+ renderingMode !== 'all' && 'is-' + renderingMode
368
369
  ) }
369
370
  layout={ blockListLayout }
370
371
  dropZoneElement={
@@ -2,8 +2,7 @@
2
2
  * WordPress dependencies
3
3
  */
4
4
  import { NoticeList } from '@wordpress/components';
5
- import { withSelect, withDispatch } from '@wordpress/data';
6
- import { compose } from '@wordpress/compose';
5
+ import { useDispatch, useSelect } from '@wordpress/data';
7
6
  import { store as noticesStore } from '@wordpress/notices';
8
7
 
9
8
  /**
@@ -11,7 +10,14 @@ import { store as noticesStore } from '@wordpress/notices';
11
10
  */
12
11
  import TemplateValidationNotice from '../template-validation-notice';
13
12
 
14
- export function EditorNotices( { notices, onRemove } ) {
13
+ export function EditorNotices() {
14
+ const { notices } = useSelect(
15
+ ( select ) => ( {
16
+ notices: select( noticesStore ).getNotices(),
17
+ } ),
18
+ []
19
+ );
20
+ const { removeNotice } = useDispatch( noticesStore );
15
21
  const dismissibleNotices = notices.filter(
16
22
  ( { isDismissible, type } ) => isDismissible && type === 'default'
17
23
  );
@@ -28,7 +34,7 @@ export function EditorNotices( { notices, onRemove } ) {
28
34
  <NoticeList
29
35
  notices={ dismissibleNotices }
30
36
  className="components-editor-notices__dismissible"
31
- onRemove={ onRemove }
37
+ onRemove={ removeNotice }
32
38
  >
33
39
  <TemplateValidationNotice />
34
40
  </NoticeList>
@@ -36,11 +42,4 @@ export function EditorNotices( { notices, onRemove } ) {
36
42
  );
37
43
  }
38
44
 
39
- export default compose( [
40
- withSelect( ( select ) => ( {
41
- notices: select( noticesStore ).getNotices(),
42
- } ) ),
43
- withDispatch( ( dispatch ) => ( {
44
- onRemove: dispatch( noticesStore ).removeNotice,
45
- } ) ),
46
- ] )( EditorNotices );
45
+ export default EditorNotices;
@@ -9,7 +9,6 @@
9
9
 
10
10
  .components-notice {
11
11
  box-sizing: border-box;
12
- margin: 0;
13
12
  border-bottom: $border-width solid rgba(0, 0, 0, 0.2);
14
13
  padding: 0 $grid-unit-15;
15
14
 
@@ -5,11 +5,18 @@ import { __ } from '@wordpress/i18n';
5
5
  import { useSelect } from '@wordpress/data';
6
6
  import { PanelBody, PanelRow } from '@wordpress/components';
7
7
  import { store as coreStore } from '@wordpress/core-data';
8
+ import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor';
9
+ import { useContext } from '@wordpress/element';
8
10
 
9
11
  /**
10
12
  * Internal dependencies
11
13
  */
12
14
  import EntityRecordItem from './entity-record-item';
15
+ import { unlock } from '../../lock-unlock';
16
+
17
+ const { getGlobalStylesChanges, GlobalStylesContext } = unlock(
18
+ blockEditorPrivateApis
19
+ );
13
20
 
14
21
  function getEntityDescription( entity, count ) {
15
22
  switch ( entity ) {
@@ -27,6 +34,44 @@ function getEntityDescription( entity, count ) {
27
34
  }
28
35
  }
29
36
 
37
+ function GlobalStylesDescription( { record } ) {
38
+ const { user: currentEditorGlobalStyles } =
39
+ useContext( GlobalStylesContext );
40
+ const savedRecord = useSelect(
41
+ ( select ) =>
42
+ select( coreStore ).getEntityRecord(
43
+ record.kind,
44
+ record.name,
45
+ record.key
46
+ ),
47
+ [ record.kind, record.name, record.key ]
48
+ );
49
+
50
+ const globalStylesChanges = getGlobalStylesChanges(
51
+ currentEditorGlobalStyles,
52
+ savedRecord,
53
+ {
54
+ maxResults: 10,
55
+ }
56
+ );
57
+ return globalStylesChanges.length ? (
58
+ <>
59
+ <h3 className="entities-saved-states__description-heading">
60
+ { __( 'Changes made to:' ) }
61
+ </h3>
62
+ <PanelRow>{ globalStylesChanges.join( ', ' ) }</PanelRow>
63
+ </>
64
+ ) : null;
65
+ }
66
+
67
+ function EntityDescription( { record, count } ) {
68
+ if ( 'globalStyles' === record?.name ) {
69
+ return <GlobalStylesDescription record={ record } />;
70
+ }
71
+ const description = getEntityDescription( record?.name, count );
72
+ return description ? <PanelRow>{ description }</PanelRow> : null;
73
+ }
74
+
30
75
  export default function EntityTypeList( {
31
76
  list,
32
77
  unselectedEntities,
@@ -42,19 +87,16 @@ export default function EntityTypeList( {
42
87
  ),
43
88
  [ firstRecord.kind, firstRecord.name ]
44
89
  );
45
- const { name } = firstRecord;
46
90
 
47
91
  let entityLabel = entityConfig.label;
48
- if ( name === 'wp_template_part' ) {
92
+ if ( firstRecord?.name === 'wp_template_part' ) {
49
93
  entityLabel =
50
94
  1 === count ? __( 'Template Part' ) : __( 'Template Parts' );
51
95
  }
52
- // Set description based on type of entity.
53
- const description = getEntityDescription( name, count );
54
96
 
55
97
  return (
56
98
  <PanelBody title={ entityLabel } initialOpen={ true }>
57
- { description && <PanelRow>{ description }</PanelRow> }
99
+ <EntityDescription record={ firstRecord } count={ count } />
58
100
  { list.map( ( record ) => {
59
101
  return (
60
102
  <EntityRecordItem
@@ -213,13 +213,13 @@ export function EntitiesSavedStatesExtensible( {
213
213
  { __( 'Are you ready to save?' ) }
214
214
  </strong>
215
215
  { additionalPrompt }
216
- { isDirty && (
217
- <p>
218
- { __(
219
- 'The following changes have been made to your site, templates, and content.'
220
- ) }
221
- </p>
222
- ) }
216
+ <p>
217
+ { isDirty
218
+ ? __(
219
+ 'The following changes have been made to your site, templates, and content.'
220
+ )
221
+ : __( 'Select the items you want to save.' ) }
222
+ </p>
223
223
  </div>
224
224
 
225
225
  { sortedPartitionedSavables.map( ( list ) => {
@@ -15,3 +15,7 @@
15
15
  margin-bottom: $grid-unit-15;
16
16
  }
17
17
  }
18
+
19
+ .entities-saved-states__description-heading {
20
+ font-size: $default-font-size;
21
+ }
@@ -90,10 +90,8 @@ const OfflineStatus = () => {
90
90
  ) }
91
91
  style={ containerStyle }
92
92
  >
93
- <View style={ containerStyle }>
94
- <Icon fill={ iconStyle.fill } icon={ offlineIcon } />
95
- <Text style={ textStyle }>{ __( 'Working Offline' ) }</Text>
96
- </View>
93
+ <Icon fill={ iconStyle.fill } icon={ offlineIcon } />
94
+ <Text style={ textStyle }>{ __( 'Working Offline' ) } </Text>
97
95
  </View>
98
96
  ) : null;
99
97
  };
@@ -172,7 +172,7 @@ export default function PostLockedModal() {
172
172
  shouldCloseOnClickOutside={ false }
173
173
  shouldCloseOnEsc={ false }
174
174
  isDismissible={ false }
175
- className="editor-post-locked-modal"
175
+ size="medium"
176
176
  >
177
177
  <HStack alignment="top" spacing={ 6 }>
178
178
  { !! userAvatar && (
@@ -1,9 +1,3 @@
1
- .editor-post-locked-modal {
2
- @include break-small() {
3
- max-width: $break-mobile;
4
- }
5
- }
6
-
7
1
  .editor-post-locked-modal__buttons {
8
2
  margin-top: $grid-unit-30;
9
3
  }
@@ -9,7 +9,6 @@ import classnames from 'classnames';
9
9
  import {
10
10
  __unstableGetAnimateClassName as getAnimateClassName,
11
11
  Button,
12
- Tooltip,
13
12
  } from '@wordpress/components';
14
13
  import { usePrevious, useViewportMatch } from '@wordpress/compose';
15
14
  import { useDispatch, useSelect } from '@wordpress/data';
@@ -129,54 +128,38 @@ export default function PostSavedState( { forceIsDirty } ) {
129
128
  text = shortLabel;
130
129
  }
131
130
 
132
- const buttonAccessibleLabel = text || label;
133
-
134
- /**
135
- * The tooltip needs to be enabled only if the button is not disabled. When
136
- * relying on the internal Button tooltip functionality, this causes the
137
- * resulting `button` element to be always removed and re-added to the DOM,
138
- * causing focus loss. An alternative approach to circumvent the issue
139
- * is not to use the `label` and `shortcut` props on `Button` (which would
140
- * trigger the tooltip), and instead manually wrap the `Button` in a separate
141
- * `Tooltip` component.
142
- */
143
- const tooltipProps = isDisabled
144
- ? undefined
145
- : {
146
- text: buttonAccessibleLabel,
147
- shortcut: displayShortcut.primary( 's' ),
148
- };
149
-
150
131
  // Use common Button instance for all saved states so that focus is not
151
132
  // lost.
152
133
  return (
153
- <Tooltip { ...tooltipProps }>
154
- <Button
155
- className={
156
- isSaveable || isSaving
157
- ? classnames( {
158
- 'editor-post-save-draft': ! isSavedState,
159
- 'editor-post-saved-state': isSavedState,
160
- 'is-saving': isSaving,
161
- 'is-autosaving': isAutosaving,
162
- 'is-saved': isSaved,
163
- [ getAnimateClassName( {
164
- type: 'loading',
165
- } ) ]: isSaving,
166
- } )
167
- : undefined
168
- }
169
- onClick={ isDisabled ? undefined : () => savePost() }
170
- variant="tertiary"
171
- size="compact"
172
- icon={ isLargeViewport ? undefined : cloudUpload }
173
- // Make sure the aria-label has always a value, as the default `text` is undefined on small screens.
174
- aria-label={ buttonAccessibleLabel }
175
- aria-disabled={ isDisabled }
176
- >
177
- { isSavedState && <Icon icon={ isSaved ? check : cloud } /> }
178
- { text }
179
- </Button>
180
- </Tooltip>
134
+ <Button
135
+ className={
136
+ isSaveable || isSaving
137
+ ? classnames( {
138
+ 'editor-post-save-draft': ! isSavedState,
139
+ 'editor-post-saved-state': isSavedState,
140
+ 'is-saving': isSaving,
141
+ 'is-autosaving': isAutosaving,
142
+ 'is-saved': isSaved,
143
+ [ getAnimateClassName( {
144
+ type: 'loading',
145
+ } ) ]: isSaving,
146
+ } )
147
+ : undefined
148
+ }
149
+ onClick={ isDisabled ? undefined : () => savePost() }
150
+ /*
151
+ * We want the tooltip to show the keyboard shortcut only when the
152
+ * button does something, i.e. when it's not disabled.
153
+ */
154
+ shortcut={ isDisabled ? undefined : displayShortcut.primary( 's' ) }
155
+ variant="tertiary"
156
+ size="compact"
157
+ icon={ isLargeViewport ? undefined : cloudUpload }
158
+ label={ text || label }
159
+ aria-disabled={ isDisabled }
160
+ >
161
+ { isSavedState && <Icon icon={ isSaved ? check : cloud } /> }
162
+ { text }
163
+ </Button>
181
164
  );
182
165
  }
@@ -1,29 +1,25 @@
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 PostScheduleCheck( { hasPublishAction, children } ) {
11
+ export default function PostScheduleCheck( { children } ) {
12
+ const hasPublishAction = useSelect( ( select ) => {
13
+ return (
14
+ select( editorStore ).getCurrentPost()._links?.[
15
+ 'wp:action-publish'
16
+ ] ?? false
17
+ );
18
+ }, [] );
19
+
13
20
  if ( ! hasPublishAction ) {
14
21
  return null;
15
22
  }
16
23
 
17
24
  return children;
18
25
  }
19
-
20
- export default compose( [
21
- withSelect( ( select ) => {
22
- const { getCurrentPost, getCurrentPostType } = select( editorStore );
23
- return {
24
- hasPublishAction:
25
- getCurrentPost()._links?.[ 'wp:action-publish' ] ?? false,
26
- postType: getCurrentPostType(),
27
- };
28
- } ),
29
- ] )( PostScheduleCheck );
@@ -3,25 +3,40 @@
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
+
6
11
  /**
7
12
  * Internal dependencies
8
13
  */
9
- import { PostScheduleCheck } from '../check';
14
+ import PostScheduleCheck from '../check';
15
+
16
+ jest.mock( '@wordpress/data/src/components/use-select', () => jest.fn() );
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( 'PostScheduleCheck', () => {
12
31
  it( "should not render anything if the user doesn't have the right capabilities", () => {
13
- render(
14
- <PostScheduleCheck hasPublishAction={ false }>
15
- yes
16
- </PostScheduleCheck>
17
- );
32
+ setupMockSelect( false );
33
+ render( <PostScheduleCheck>yes</PostScheduleCheck> );
18
34
  expect( screen.queryByText( 'yes' ) ).not.toBeInTheDocument();
19
35
  } );
20
36
 
21
37
  it( 'should render if the user has the correct capability', () => {
22
- render(
23
- <PostScheduleCheck hasPublishAction={ true }>yes</PostScheduleCheck>
24
- );
38
+ setupMockSelect( true );
39
+ render( <PostScheduleCheck>yes</PostScheduleCheck> );
25
40
  expect( screen.getByText( 'yes' ) ).toBeVisible();
26
41
  } );
27
42
  } );