@wordpress/editor 12.0.20 → 12.1.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 (75) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/LICENSE.md +1 -1
  3. package/build/components/deprecated.js +4 -2
  4. package/build/components/deprecated.js.map +1 -1
  5. package/build/components/editor-help/add-blocks.native.js +1 -1
  6. package/build/components/editor-help/add-blocks.native.js.map +1 -1
  7. package/build/components/editor-help/index.native.js +1 -1
  8. package/build/components/editor-help/index.native.js.map +1 -1
  9. package/build/components/entities-saved-states/index.js +18 -16
  10. package/build/components/entities-saved-states/index.js.map +1 -1
  11. package/build/components/post-locked-modal/index.js +34 -25
  12. package/build/components/post-locked-modal/index.js.map +1 -1
  13. package/build/components/post-publish-panel/maybe-category-panel.js +81 -0
  14. package/build/components/post-publish-panel/maybe-category-panel.js.map +1 -0
  15. package/build/components/post-publish-panel/prepublish.js +3 -1
  16. package/build/components/post-publish-panel/prepublish.js.map +1 -1
  17. package/build/components/post-trash/index.js +1 -1
  18. package/build/components/post-trash/index.js.map +1 -1
  19. package/build/components/provider/index.native.js +12 -6
  20. package/build/components/provider/index.native.js.map +1 -1
  21. package/build/components/provider/use-block-editor-settings.js +11 -6
  22. package/build/components/provider/use-block-editor-settings.js.map +1 -1
  23. package/build/store/actions.js +2 -1
  24. package/build/store/actions.js.map +1 -1
  25. package/build/store/selectors.js +10 -7
  26. package/build/store/selectors.js.map +1 -1
  27. package/build/store/utils/notice-builder.js +1 -1
  28. package/build/store/utils/notice-builder.js.map +1 -1
  29. package/build-module/components/deprecated.js +4 -2
  30. package/build-module/components/deprecated.js.map +1 -1
  31. package/build-module/components/editor-help/add-blocks.native.js +1 -1
  32. package/build-module/components/editor-help/add-blocks.native.js.map +1 -1
  33. package/build-module/components/editor-help/index.native.js +1 -1
  34. package/build-module/components/editor-help/index.native.js.map +1 -1
  35. package/build-module/components/entities-saved-states/index.js +19 -16
  36. package/build-module/components/entities-saved-states/index.js.map +1 -1
  37. package/build-module/components/post-locked-modal/index.js +37 -25
  38. package/build-module/components/post-locked-modal/index.js.map +1 -1
  39. package/build-module/components/post-publish-panel/maybe-category-panel.js +66 -0
  40. package/build-module/components/post-publish-panel/maybe-category-panel.js.map +1 -0
  41. package/build-module/components/post-publish-panel/prepublish.js +2 -1
  42. package/build-module/components/post-publish-panel/prepublish.js.map +1 -1
  43. package/build-module/components/post-trash/index.js +1 -1
  44. package/build-module/components/post-trash/index.js.map +1 -1
  45. package/build-module/components/provider/index.native.js +10 -7
  46. package/build-module/components/provider/index.native.js.map +1 -1
  47. package/build-module/components/provider/use-block-editor-settings.js +11 -6
  48. package/build-module/components/provider/use-block-editor-settings.js.map +1 -1
  49. package/build-module/store/actions.js +2 -1
  50. package/build-module/store/actions.js.map +1 -1
  51. package/build-module/store/selectors.js +10 -7
  52. package/build-module/store/selectors.js.map +1 -1
  53. package/build-module/store/utils/notice-builder.js +1 -1
  54. package/build-module/store/utils/notice-builder.js.map +1 -1
  55. package/build-style/style-rtl.css +9 -27
  56. package/build-style/style.css +9 -27
  57. package/package.json +34 -30
  58. package/src/components/autosave-monitor/test/index.js +1 -1
  59. package/src/components/deprecated.js +2 -0
  60. package/src/components/editor-help/add-blocks.native.js +1 -1
  61. package/src/components/editor-help/index.native.js +1 -1
  62. package/src/components/entities-saved-states/index.js +21 -15
  63. package/src/components/entities-saved-states/style.scss +0 -12
  64. package/src/components/post-locked-modal/index.js +92 -53
  65. package/src/components/post-locked-modal/style.scss +7 -17
  66. package/src/components/post-publish-panel/maybe-category-panel.js +88 -0
  67. package/src/components/post-publish-panel/prepublish.js +2 -0
  68. package/src/components/post-trash/index.js +1 -1
  69. package/src/components/provider/index.native.js +10 -7
  70. package/src/components/provider/use-block-editor-settings.js +14 -3
  71. package/src/store/actions.js +1 -0
  72. package/src/store/selectors.js +9 -5
  73. package/src/store/test/actions.js +1 -1
  74. package/src/store/utils/notice-builder.js +1 -1
  75. package/src/store/utils/test/notice-builder.js +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/editor",
3
- "version": "12.0.20",
3
+ "version": "12.1.0",
4
4
  "description": "Enhanced block editor for WordPress posts.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -31,42 +31,46 @@
31
31
  ],
32
32
  "dependencies": {
33
33
  "@babel/runtime": "^7.16.0",
34
- "@wordpress/a11y": "^3.2.4",
35
- "@wordpress/api-fetch": "^5.2.6",
36
- "@wordpress/autop": "^3.2.3",
37
- "@wordpress/blob": "^3.2.2",
38
- "@wordpress/block-editor": "^8.0.16",
39
- "@wordpress/blocks": "^11.1.5",
40
- "@wordpress/components": "^19.2.2",
41
- "@wordpress/compose": "^5.0.7",
42
- "@wordpress/core-data": "^4.0.9",
43
- "@wordpress/data": "^6.1.5",
44
- "@wordpress/data-controls": "^2.2.8",
45
- "@wordpress/date": "^4.2.3",
46
- "@wordpress/deprecated": "^3.2.3",
47
- "@wordpress/element": "^4.0.4",
48
- "@wordpress/hooks": "^3.2.2",
49
- "@wordpress/html-entities": "^3.2.3",
50
- "@wordpress/i18n": "^4.2.4",
51
- "@wordpress/icons": "^6.1.1",
52
- "@wordpress/is-shallow-equal": "^4.2.1",
53
- "@wordpress/keyboard-shortcuts": "^3.0.7",
54
- "@wordpress/keycodes": "^3.2.4",
55
- "@wordpress/media-utils": "^3.0.5",
56
- "@wordpress/notices": "^3.2.8",
57
- "@wordpress/reusable-blocks": "^3.0.22",
58
- "@wordpress/rich-text": "^5.0.8",
59
- "@wordpress/server-side-render": "^3.0.19",
60
- "@wordpress/url": "^3.3.1",
61
- "@wordpress/wordcount": "^3.2.3",
34
+ "@wordpress/a11y": "^3.3.0",
35
+ "@wordpress/api-fetch": "^6.0.0",
36
+ "@wordpress/autop": "^3.3.0",
37
+ "@wordpress/blob": "^3.3.0",
38
+ "@wordpress/block-editor": "^8.1.0",
39
+ "@wordpress/blocks": "^11.2.0",
40
+ "@wordpress/components": "^19.3.0",
41
+ "@wordpress/compose": "^5.1.0",
42
+ "@wordpress/core-data": "^4.1.0",
43
+ "@wordpress/data": "^6.2.0",
44
+ "@wordpress/data-controls": "^2.3.0",
45
+ "@wordpress/date": "^4.3.0",
46
+ "@wordpress/deprecated": "^3.3.0",
47
+ "@wordpress/element": "^4.1.0",
48
+ "@wordpress/hooks": "^3.3.0",
49
+ "@wordpress/html-entities": "^3.3.0",
50
+ "@wordpress/i18n": "^4.3.0",
51
+ "@wordpress/icons": "^6.2.0",
52
+ "@wordpress/is-shallow-equal": "^4.3.0",
53
+ "@wordpress/keyboard-shortcuts": "^3.1.0",
54
+ "@wordpress/keycodes": "^3.3.0",
55
+ "@wordpress/media-utils": "^3.1.0",
56
+ "@wordpress/notices": "^3.3.0",
57
+ "@wordpress/reusable-blocks": "^3.1.0",
58
+ "@wordpress/rich-text": "^5.1.0",
59
+ "@wordpress/server-side-render": "^3.1.0",
60
+ "@wordpress/url": "^3.4.0",
61
+ "@wordpress/wordcount": "^3.3.0",
62
62
  "classnames": "^2.3.1",
63
63
  "lodash": "^4.17.21",
64
64
  "memize": "^1.1.0",
65
65
  "react-autosize-textarea": "^7.1.0",
66
66
  "rememo": "^3.0.0"
67
67
  },
68
+ "peerDependencies": {
69
+ "react": "^17.0.0",
70
+ "react-dom": "^17.0.0"
71
+ },
68
72
  "publishConfig": {
69
73
  "access": "public"
70
74
  },
71
- "gitHead": "cac1a1f3c854fc282d67b91a74936c3fe42d7d0a"
75
+ "gitHead": "d95ccb9366e249133cdb1d7b25c382446b9ee502"
72
76
  }
@@ -12,7 +12,7 @@ describe( 'AutosaveMonitor', () => {
12
12
  let wrapper;
13
13
  let setAutosaveTimerSpy;
14
14
  beforeEach( () => {
15
- jest.useFakeTimers();
15
+ jest.useFakeTimers( 'legacy' );
16
16
  setAutosaveTimerSpy = jest.spyOn(
17
17
  AutosaveMonitor.prototype,
18
18
  'setAutosaveTimer'
@@ -67,6 +67,7 @@ function deprecateComponent( name, Wrapped, staticsToHoist = [] ) {
67
67
  deprecated( 'wp.editor.' + name, {
68
68
  since: '5.3',
69
69
  alternative: 'wp.blockEditor.' + name,
70
+ version: '6.2',
70
71
  } );
71
72
 
72
73
  return <Wrapped ref={ ref } { ...props } />;
@@ -87,6 +88,7 @@ function deprecateFunction( name, func ) {
87
88
  deprecated( 'wp.editor.' + name, {
88
89
  since: '5.3',
89
90
  alternative: 'wp.blockEditor.' + name,
91
+ version: '6.2',
90
92
  } );
91
93
 
92
94
  return func( ...args );
@@ -24,7 +24,7 @@ const AddBlocks = () => {
24
24
  <View style={ styles.helpDetailContainer }>
25
25
  <HelpDetailBodyText
26
26
  text={ __(
27
- 'Add a new block at any time by tapping on the + icon in the toolbar on the bottom left. '
27
+ 'Add a new block at any time by tapping on the + icon in the toolbar on the bottom left.'
28
28
  ) }
29
29
  />
30
30
  <HelpDetailBodyText
@@ -197,7 +197,7 @@ function EditorHelpTopics( { close, isVisible, onClose } ) {
197
197
  content={ view }
198
198
  label={ label }
199
199
  options={ {
200
- gestureEnabled: true,
200
+ gestureEnabled: false,
201
201
  ...TransitionPresets.DefaultTransition,
202
202
  } }
203
203
  />
@@ -6,14 +6,13 @@ import { some, groupBy } from 'lodash';
6
6
  /**
7
7
  * WordPress dependencies
8
8
  */
9
- import { Button } from '@wordpress/components';
9
+ import { Button, Flex, FlexItem } from '@wordpress/components';
10
10
  import { __ } from '@wordpress/i18n';
11
11
  import { useSelect, useDispatch } from '@wordpress/data';
12
12
  import { useState, useCallback, useRef } from '@wordpress/element';
13
13
  import { store as coreStore } from '@wordpress/core-data';
14
14
  import { store as blockEditorStore } from '@wordpress/block-editor';
15
15
  import { __experimentalUseDialog as useDialog } from '@wordpress/compose';
16
- import { close as closeIcon } from '@wordpress/icons';
17
16
  import { store as noticesStore } from '@wordpress/notices';
18
17
 
19
18
  /**
@@ -77,13 +76,15 @@ export default function EntitiesSavedStates( { close } ) {
77
76
  saveEditedEntityRecord,
78
77
  __experimentalSaveSpecifiedEntityEdits: saveSpecifiedEntityEdits,
79
78
  } = useDispatch( coreStore );
80
- const { createSuccessNotice, createErrorNotice } = useDispatch(
81
- noticesStore
82
- );
79
+
83
80
  const { __unstableMarkLastChangeAsPersistent } = useDispatch(
84
81
  blockEditorStore
85
82
  );
86
83
 
84
+ const { createSuccessNotice, createErrorNotice } = useDispatch(
85
+ noticesStore
86
+ );
87
+
87
88
  // To group entities by type.
88
89
  const partitionedSavables = groupBy( dirtyEntityRecords, 'name' );
89
90
 
@@ -174,6 +175,8 @@ export default function EntitiesSavedStates( { close } ) {
174
175
  );
175
176
  }
176
177
 
178
+ __unstableMarkLastChangeAsPersistent();
179
+
177
180
  Promise.all( pendingSavedRecords )
178
181
  .then( ( values ) => {
179
182
  if (
@@ -189,8 +192,6 @@ export default function EntitiesSavedStates( { close } ) {
189
192
  .catch( ( error ) =>
190
193
  createErrorNotice( `${ __( 'Saving failed.' ) } ${ error }` )
191
194
  );
192
-
193
- __unstableMarkLastChangeAsPersistent();
194
195
  };
195
196
 
196
197
  // Explicitly define this with no argument passed. Using `close` on
@@ -207,8 +208,10 @@ export default function EntitiesSavedStates( { close } ) {
207
208
  { ...saveDialogProps }
208
209
  className="entities-saved-states__panel"
209
210
  >
210
- <div className="entities-saved-states__panel-header">
211
- <Button
211
+ <Flex className="entities-saved-states__panel-header" gap={ 2 }>
212
+ <FlexItem
213
+ isBlock
214
+ as={ Button }
212
215
  ref={ saveButtonRef }
213
216
  variant="primary"
214
217
  disabled={
@@ -220,13 +223,16 @@ export default function EntitiesSavedStates( { close } ) {
220
223
  className="editor-entities-saved-states__save-button"
221
224
  >
222
225
  { __( 'Save' ) }
223
- </Button>
224
- <Button
225
- icon={ closeIcon }
226
+ </FlexItem>
227
+ <FlexItem
228
+ isBlock
229
+ as={ Button }
230
+ variant="secondary"
226
231
  onClick={ dismissPanel }
227
- label={ __( 'Close panel' ) }
228
- />
229
- </div>
232
+ >
233
+ { __( 'Cancel' ) }
234
+ </FlexItem>
235
+ </Flex>
230
236
 
231
237
  <div className="entities-saved-states__text-prompt">
232
238
  <strong>{ __( 'Are you ready to save?' ) }</strong>
@@ -41,18 +41,6 @@
41
41
  padding-right: $grid-unit-10;
42
42
  height: $header-height + $border-width;
43
43
  border-bottom: $border-width solid $gray-300;
44
- display: flex;
45
- align-items: center;
46
- align-content: space-between;
47
-
48
- .editor-entities-saved-states__save-button {
49
- margin: auto;
50
- }
51
-
52
- .components-button.has-icon {
53
- position: absolute;
54
- right: $grid-unit-10;
55
- }
56
44
  }
57
45
 
58
46
  .entities-saved-states__text-prompt {
@@ -7,10 +7,16 @@ import { get } from 'lodash';
7
7
  * WordPress dependencies
8
8
  */
9
9
  import { __, sprintf } from '@wordpress/i18n';
10
- import { Modal, Button } from '@wordpress/components';
10
+ import {
11
+ Modal,
12
+ Button,
13
+ ExternalLink,
14
+ Flex,
15
+ FlexItem,
16
+ } from '@wordpress/components';
11
17
  import { useSelect, useDispatch } from '@wordpress/data';
12
18
  import { addQueryArgs } from '@wordpress/url';
13
- import { useEffect } from '@wordpress/element';
19
+ import { useEffect, createInterpolateElement } from '@wordpress/element';
14
20
  import { addAction, removeAction } from '@wordpress/hooks';
15
21
  import { useInstanceId } from '@wordpress/compose';
16
22
  import { store as coreStore } from '@wordpress/core-data';
@@ -19,7 +25,6 @@ import { store as coreStore } from '@wordpress/core-data';
19
25
  * Internal dependencies
20
26
  */
21
27
  import { getWPAdminURL } from '../../utils/url';
22
- import PostPreviewButton from '../post-preview-button';
23
28
  import { store as editorStore } from '../../store';
24
29
 
25
30
  export default function PostLockedModal() {
@@ -34,6 +39,7 @@ export default function PostLockedModal() {
34
39
  postLockUtils,
35
40
  activePostLock,
36
41
  postType,
42
+ previewLink,
37
43
  } = useSelect( ( select ) => {
38
44
  const {
39
45
  isPostLocked,
@@ -42,6 +48,7 @@ export default function PostLockedModal() {
42
48
  getCurrentPostId,
43
49
  getActivePostLock,
44
50
  getEditedPostAttribute,
51
+ getEditedPostPreviewLink,
45
52
  getEditorSettings,
46
53
  } = select( editorStore );
47
54
  const { getPostType } = select( coreStore );
@@ -53,6 +60,7 @@ export default function PostLockedModal() {
53
60
  postLockUtils: getEditorSettings().postLockUtils,
54
61
  activePostLock: getActivePostLock(),
55
62
  postType: getPostType( getEditedPostAttribute( 'type' ) ),
63
+ previewLink: getEditedPostPreviewLink(),
56
64
  };
57
65
  }, [] );
58
66
 
@@ -94,7 +102,8 @@ export default function PostLockedModal() {
94
102
  isLocked: true,
95
103
  isTakeover: true,
96
104
  user: {
97
- avatar: received.lock_error.avatar_src,
105
+ name: received.lock_error.name,
106
+ avatar: received.lock_error.avatar_src_2x,
98
107
  },
99
108
  } );
100
109
  } else if ( received.new_lock ) {
@@ -158,13 +167,13 @@ export default function PostLockedModal() {
158
167
  const allPostsUrl = getWPAdminURL( 'edit.php', {
159
168
  post_type: get( postType, [ 'slug' ] ),
160
169
  } );
161
- const allPostsLabel = __( 'Exit the Editor' );
170
+ const allPostsLabel = __( 'Exit editor' );
162
171
  return (
163
172
  <Modal
164
173
  title={
165
174
  isTakeover
166
- ? __( 'Someone else has taken over this post.' )
167
- : __( 'This post is already being edited.' )
175
+ ? __( 'Someone else has taken over this post' )
176
+ : __( 'This post is already being edited' )
168
177
  }
169
178
  focusOnMount={ true }
170
179
  shouldCloseOnClickOutside={ false }
@@ -177,58 +186,88 @@ export default function PostLockedModal() {
177
186
  src={ userAvatar }
178
187
  alt={ __( 'Avatar' ) }
179
188
  className="editor-post-locked-modal__avatar"
189
+ width={ 64 }
190
+ height={ 64 }
180
191
  />
181
192
  ) }
182
- { !! isTakeover && (
183
- <div>
184
- <div>
185
- { userDisplayName
186
- ? sprintf(
187
- /* translators: %s: user's display name */
188
- __(
189
- '%s now has editing control of this post. Don’t worry, your changes up to this moment have been saved.'
193
+ <div>
194
+ { !! isTakeover && (
195
+ <p>
196
+ { createInterpolateElement(
197
+ userDisplayName
198
+ ? sprintf(
199
+ /* translators: %s: user's display name */
200
+ __(
201
+ '<strong>%s</strong> now has editing control of this posts (<PreviewLink />). Don’t worry, your changes up to this moment have been saved.'
202
+ ),
203
+ userDisplayName
204
+ )
205
+ : __(
206
+ 'Another user now has editing control of this post (<PreviewLink />). Don’t worry, your changes up to this moment have been saved.'
207
+ ),
208
+ {
209
+ strong: <strong />,
210
+ PreviewLink: (
211
+ <ExternalLink href={ previewLink }>
212
+ { __( 'preview' ) }
213
+ </ExternalLink>
214
+ ),
215
+ }
216
+ ) }
217
+ </p>
218
+ ) }
219
+ { ! isTakeover && (
220
+ <>
221
+ <p>
222
+ { createInterpolateElement(
223
+ userDisplayName
224
+ ? sprintf(
225
+ /* translators: %s: user's display name */
226
+ __(
227
+ '<strong>%s</strong> is currently working on this post (<PreviewLink />), which means you cannot make changes, unless you take over.'
228
+ ),
229
+ userDisplayName
230
+ )
231
+ : __(
232
+ 'Another user is currently working on this post (<PreviewLink />), which means you cannot make changes, unless you take over.'
233
+ ),
234
+ {
235
+ strong: <strong />,
236
+ PreviewLink: (
237
+ <ExternalLink href={ previewLink }>
238
+ { __( 'preview' ) }
239
+ </ExternalLink>
190
240
  ),
191
- userDisplayName
192
- )
193
- : __(
194
- 'Another user now has editing control of this post. Don’t worry, your changes up to this moment have been saved.'
195
- ) }
196
- </div>
197
-
198
- <div className="editor-post-locked-modal__buttons">
241
+ }
242
+ ) }
243
+ </p>
244
+ <p>
245
+ { __(
246
+ 'If you take over, the other user will lose editing control to the post, but their changes will be saved.'
247
+ ) }
248
+ </p>
249
+ </>
250
+ ) }
251
+
252
+ <Flex
253
+ className="editor-post-locked-modal__buttons"
254
+ justify="flex-end"
255
+ expanded={ false }
256
+ >
257
+ { ! isTakeover && (
258
+ <FlexItem>
259
+ <Button variant="tertiary" href={ unlockUrl }>
260
+ { __( 'Take over' ) }
261
+ </Button>
262
+ </FlexItem>
263
+ ) }
264
+ <FlexItem>
199
265
  <Button variant="primary" href={ allPostsUrl }>
200
266
  { allPostsLabel }
201
267
  </Button>
202
- </div>
203
- </div>
204
- ) }
205
- { ! isTakeover && (
206
- <div>
207
- <div>
208
- { userDisplayName
209
- ? sprintf(
210
- /* translators: %s: user's display name */
211
- __(
212
- '%s is currently working on this post, which means you cannot make changes, unless you take over.'
213
- ),
214
- userDisplayName
215
- )
216
- : __(
217
- 'Another user is currently working on this post, which means you cannot make changes, unless you take over.'
218
- ) }
219
- </div>
220
-
221
- <div className="editor-post-locked-modal__buttons">
222
- <Button variant="secondary" href={ allPostsUrl }>
223
- { allPostsLabel }
224
- </Button>
225
- <PostPreviewButton />
226
- <Button variant="primary" href={ unlockUrl }>
227
- { __( 'Take Over' ) }
228
- </Button>
229
- </div>
230
- </div>
231
- ) }
268
+ </FlexItem>
269
+ </Flex>
270
+ </div>
232
271
  </Modal>
233
272
  );
234
273
  }
@@ -1,29 +1,19 @@
1
1
  .editor-post-locked-modal {
2
- height: auto;
3
- padding-right: 10px;
4
- padding-left: 10px;
5
- padding-top: 10px;
6
- max-width: 480px;
7
-
8
- .components-modal__header {
9
- height: 36px;
2
+ @include break-small() {
3
+ max-width: $break-mobile;
10
4
  }
11
5
 
12
6
  .components-modal__content {
13
- height: auto;
7
+ display: flex;
14
8
  }
15
9
  }
16
10
 
17
11
  .editor-post-locked-modal__buttons {
18
- margin-top: 10px;
19
-
20
- .components-button {
21
- margin-right: 5px;
22
- }
12
+ margin-top: $grid-unit-30;
23
13
  }
24
14
 
25
15
  .editor-post-locked-modal__avatar {
26
- float: left;
27
- margin: 5px;
28
- margin-right: 15px;
16
+ border-radius: $radius-block-ui;
17
+ margin-top: $grid-unit-20;
18
+ margin-right: $grid-unit-30;
29
19
  }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { some } from 'lodash';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import { __ } from '@wordpress/i18n';
10
+ import { useSelect } from '@wordpress/data';
11
+ import { PanelBody } from '@wordpress/components';
12
+ import { store as coreStore } from '@wordpress/core-data';
13
+ import { useState, useEffect } from '@wordpress/element';
14
+
15
+ /**
16
+ * Internal dependencies
17
+ */
18
+ import HierarchicalTermSelector from '../post-taxonomies/hierarchical-term-selector';
19
+ import { store as editorStore } from '../../store';
20
+
21
+ function MaybeCategoryPanel() {
22
+ const hasNoCategory = useSelect( ( select ) => {
23
+ const postType = select( editorStore ).getCurrentPostType();
24
+ const categoriesTaxonomy = select( coreStore ).getTaxonomy(
25
+ 'category'
26
+ );
27
+ const defaultCategorySlug = 'uncategorized';
28
+ const defaultCategory = select( coreStore ).getEntityRecords(
29
+ 'taxonomy',
30
+ 'category',
31
+ {
32
+ slug: defaultCategorySlug,
33
+ }
34
+ )?.[ 0 ];
35
+ const postTypeSupportsCategories =
36
+ categoriesTaxonomy &&
37
+ some( categoriesTaxonomy.types, ( type ) => type === postType );
38
+ const categories =
39
+ categoriesTaxonomy &&
40
+ select( editorStore ).getEditedPostAttribute(
41
+ categoriesTaxonomy.rest_base
42
+ );
43
+
44
+ // This boolean should return true if everything is loaded
45
+ // ( categoriesTaxonomy, defaultCategory )
46
+ // and the post has not been assigned a category different than "uncategorized".
47
+ return (
48
+ !! categoriesTaxonomy &&
49
+ !! defaultCategory &&
50
+ postTypeSupportsCategories &&
51
+ ( categories?.length === 0 ||
52
+ ( categories?.length === 1 &&
53
+ defaultCategory.id === categories[ 0 ] ) )
54
+ );
55
+ }, [] );
56
+ const [ shouldShowPanel, setShouldShowPanel ] = useState( false );
57
+ useEffect( () => {
58
+ // We use state to avoid hiding the panel if the user edits the categories
59
+ // and adds one within the panel itself (while visible).
60
+ if ( hasNoCategory ) {
61
+ setShouldShowPanel( true );
62
+ }
63
+ }, [ hasNoCategory ] );
64
+
65
+ if ( ! shouldShowPanel ) {
66
+ return null;
67
+ }
68
+
69
+ const panelBodyTitle = [
70
+ __( 'Suggestion:' ),
71
+ <span className="editor-post-publish-panel__link" key="label">
72
+ { __( 'Assign a category' ) }
73
+ </span>,
74
+ ];
75
+
76
+ return (
77
+ <PanelBody initialOpen={ false } title={ panelBodyTitle }>
78
+ <p>
79
+ { __(
80
+ 'Categories provide a helpful way to group related posts together and to quickly tell readers what a post is about.'
81
+ ) }
82
+ </p>
83
+ <HierarchicalTermSelector slug="category" />
84
+ </PanelBody>
85
+ );
86
+ }
87
+
88
+ export default MaybeCategoryPanel;
@@ -24,6 +24,7 @@ import PostScheduleLabel from '../post-schedule/label';
24
24
  import MaybeTagsPanel from './maybe-tags-panel';
25
25
  import MaybePostFormatPanel from './maybe-post-format-panel';
26
26
  import { store as editorStore } from '../../store';
27
+ import MaybeCategoryPanel from './maybe-category-panel';
27
28
 
28
29
  function PostPublishPanelPrepublish( { children } ) {
29
30
  const {
@@ -145,6 +146,7 @@ function PostPublishPanelPrepublish( { children } ) {
145
146
  ) }
146
147
  <MaybePostFormatPanel />
147
148
  <MaybeTagsPanel />
149
+ <MaybeCategoryPanel />
148
150
  { children }
149
151
  </div>
150
152
  );
@@ -22,7 +22,7 @@ function PostTrash( { isNew, postId, postType, ...props } ) {
22
22
  <Button
23
23
  className="editor-post-trash"
24
24
  isDestructive
25
- variant="tertiary"
25
+ variant="secondary"
26
26
  onClick={ onClick }
27
27
  >
28
28
  { __( 'Move to trash' ) }
@@ -56,7 +56,10 @@ const postTypeEntities = [
56
56
  },
57
57
  rawAttributes: [ 'title', 'excerpt', 'content' ],
58
58
  } ) );
59
- import { EditorHelpTopics } from '@wordpress/editor';
59
+ import { EditorHelpTopics, store as editorStore } from '@wordpress/editor';
60
+ import { store as noticesStore } from '@wordpress/notices';
61
+ import { store as coreStore } from '@wordpress/core-data';
62
+ import { store as editPostStore } from '@wordpress/edit-post';
60
63
 
61
64
  /**
62
65
  * Internal dependencies
@@ -350,8 +353,8 @@ export default compose( [
350
353
  getEditorBlocks,
351
354
  getEditedPostAttribute,
352
355
  getEditedPostContent,
353
- } = select( 'core/editor' );
354
- const { getEditorMode } = select( 'core/edit-post' );
356
+ } = select( editorStore );
357
+ const { getEditorMode } = select( editPostStore );
355
358
 
356
359
  const {
357
360
  getBlockIndex,
@@ -374,16 +377,16 @@ export default compose( [
374
377
  };
375
378
  } ),
376
379
  withDispatch( ( dispatch ) => {
377
- const { editPost, resetEditorBlocks } = dispatch( 'core/editor' );
380
+ const { editPost, resetEditorBlocks } = dispatch( editorStore );
378
381
  const {
379
382
  updateSettings,
380
383
  clearSelectedBlock,
381
384
  insertBlock,
382
385
  replaceBlock,
383
386
  } = dispatch( blockEditorStore );
384
- const { switchEditorMode } = dispatch( 'core/edit-post' );
385
- const { addEntities, receiveEntityRecords } = dispatch( 'core' );
386
- const { createSuccessNotice } = dispatch( 'core/notices' );
387
+ const { switchEditorMode } = dispatch( editPostStore );
388
+ const { addEntities, receiveEntityRecords } = dispatch( coreStore );
389
+ const { createSuccessNotice } = dispatch( noticesStore );
387
390
 
388
391
  return {
389
392
  updateSettings,