@wordpress/editor 12.8.0 → 12.11.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 (198) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/build/components/editor-help/help-section-title.native.js +43 -0
  3. package/build/components/editor-help/help-section-title.native.js.map +1 -0
  4. package/build/components/editor-help/help-topic-row.native.js +3 -2
  5. package/build/components/editor-help/help-topic-row.native.js.map +1 -1
  6. package/build/components/editor-help/icon-move-blocks.native.js +23 -0
  7. package/build/components/editor-help/icon-move-blocks.native.js.map +1 -0
  8. package/build/components/editor-help/index.native.js +10 -11
  9. package/build/components/editor-help/index.native.js.map +1 -1
  10. package/build/components/editor-help/move-blocks.native.js +14 -2
  11. package/build/components/editor-help/move-blocks.native.js.map +1 -1
  12. package/build/components/editor-help/view-sections.native.js +21 -5
  13. package/build/components/editor-help/view-sections.native.js.map +1 -1
  14. package/build/components/entities-saved-states/entity-record-item.js.map +1 -1
  15. package/build/components/entities-saved-states/index.js.map +1 -1
  16. package/build/components/global-keyboard-shortcuts/save-shortcut.js.map +1 -1
  17. package/build/components/index.js +12 -1
  18. package/build/components/index.js.map +1 -1
  19. package/build/components/local-autosave-monitor/index.js +24 -19
  20. package/build/components/local-autosave-monitor/index.js.map +1 -1
  21. package/build/components/page-attributes/parent.js +1 -1
  22. package/build/components/page-attributes/parent.js.map +1 -1
  23. package/build/components/post-author/select.js.map +1 -1
  24. package/build/components/post-comments/index.js.map +1 -1
  25. package/build/components/post-format/index.js.map +1 -1
  26. package/build/components/post-last-revision/check.js.map +1 -1
  27. package/build/components/post-last-revision/index.js.map +1 -1
  28. package/build/components/post-pending-status/check.js.map +1 -1
  29. package/build/components/post-pingbacks/index.js.map +1 -1
  30. package/build/components/post-publish-button/index.js +4 -2
  31. package/build/components/post-publish-button/index.js.map +1 -1
  32. package/build/components/post-publish-panel/index.js.map +1 -1
  33. package/build/components/post-publish-panel/maybe-category-panel.js +5 -5
  34. package/build/components/post-publish-panel/maybe-category-panel.js.map +1 -1
  35. package/build/components/post-publish-panel/maybe-post-format-panel.js.map +1 -1
  36. package/build/components/post-publish-panel/postpublish.js.map +1 -1
  37. package/build/components/post-publish-panel/prepublish.js.map +1 -1
  38. package/build/components/post-schedule/index.js +11 -18
  39. package/build/components/post-schedule/index.js.map +1 -1
  40. package/build/components/post-schedule/label.js +93 -13
  41. package/build/components/post-schedule/label.js.map +1 -1
  42. package/build/components/post-slug/index.js.map +1 -1
  43. package/build/components/post-sticky/index.js.map +1 -1
  44. package/build/components/post-switch-to-draft-button/index.js.map +1 -1
  45. package/build/components/post-taxonomies/flat-term-selector.js +7 -4
  46. package/build/components/post-taxonomies/flat-term-selector.js.map +1 -1
  47. package/build/components/post-taxonomies/hierarchical-term-selector.js.map +1 -1
  48. package/build/components/post-title/index.js.map +1 -1
  49. package/build/components/post-title/index.native.js.map +1 -1
  50. package/build/components/post-trash/check.js.map +1 -1
  51. package/build/components/post-visibility/index.js +10 -11
  52. package/build/components/post-visibility/index.js.map +1 -1
  53. package/build/components/provider/index.js.map +1 -1
  54. package/build/components/provider/index.native.js +0 -1
  55. package/build/components/provider/index.native.js.map +1 -1
  56. package/build/components/provider/use-block-editor-settings.js +3 -1
  57. package/build/components/provider/use-block-editor-settings.js.map +1 -1
  58. package/build/components/template-validation-notice/index.js.map +1 -1
  59. package/build/components/theme-support-check/index.js +1 -1
  60. package/build/components/theme-support-check/index.js.map +1 -1
  61. package/build/hooks/custom-sources-backwards-compatibility.js.map +1 -1
  62. package/build/store/actions.js +5 -1
  63. package/build/store/actions.js.map +1 -1
  64. package/build/store/reducer.js +1 -1
  65. package/build/store/reducer.js.map +1 -1
  66. package/build/store/selectors.js +2 -2
  67. package/build/store/selectors.js.map +1 -1
  68. package/build/utils/media-upload/index.js +4 -8
  69. package/build/utils/media-upload/index.js.map +1 -1
  70. package/build-module/components/editor-help/help-section-title.native.js +31 -0
  71. package/build-module/components/editor-help/help-section-title.native.js.map +1 -0
  72. package/build-module/components/editor-help/help-topic-row.native.js +3 -2
  73. package/build-module/components/editor-help/help-topic-row.native.js.map +1 -1
  74. package/build-module/components/editor-help/icon-move-blocks.native.js +13 -0
  75. package/build-module/components/editor-help/icon-move-blocks.native.js.map +1 -0
  76. package/build-module/components/editor-help/index.native.js +10 -12
  77. package/build-module/components/editor-help/index.native.js.map +1 -1
  78. package/build-module/components/editor-help/move-blocks.native.js +15 -3
  79. package/build-module/components/editor-help/move-blocks.native.js.map +1 -1
  80. package/build-module/components/editor-help/view-sections.native.js +22 -6
  81. package/build-module/components/editor-help/view-sections.native.js.map +1 -1
  82. package/build-module/components/entities-saved-states/entity-record-item.js.map +1 -1
  83. package/build-module/components/entities-saved-states/index.js.map +1 -1
  84. package/build-module/components/global-keyboard-shortcuts/save-shortcut.js.map +1 -1
  85. package/build-module/components/index.js +1 -1
  86. package/build-module/components/index.js.map +1 -1
  87. package/build-module/components/local-autosave-monitor/index.js +24 -18
  88. package/build-module/components/local-autosave-monitor/index.js.map +1 -1
  89. package/build-module/components/page-attributes/parent.js +2 -2
  90. package/build-module/components/page-attributes/parent.js.map +1 -1
  91. package/build-module/components/post-author/select.js.map +1 -1
  92. package/build-module/components/post-comments/index.js.map +1 -1
  93. package/build-module/components/post-format/index.js.map +1 -1
  94. package/build-module/components/post-last-revision/check.js.map +1 -1
  95. package/build-module/components/post-last-revision/index.js.map +1 -1
  96. package/build-module/components/post-pending-status/check.js.map +1 -1
  97. package/build-module/components/post-pingbacks/index.js.map +1 -1
  98. package/build-module/components/post-publish-button/index.js +4 -1
  99. package/build-module/components/post-publish-button/index.js.map +1 -1
  100. package/build-module/components/post-publish-panel/index.js.map +1 -1
  101. package/build-module/components/post-publish-panel/maybe-category-panel.js +5 -5
  102. package/build-module/components/post-publish-panel/maybe-category-panel.js.map +1 -1
  103. package/build-module/components/post-publish-panel/maybe-post-format-panel.js.map +1 -1
  104. package/build-module/components/post-publish-panel/postpublish.js.map +1 -1
  105. package/build-module/components/post-publish-panel/prepublish.js.map +1 -1
  106. package/build-module/components/post-schedule/index.js +12 -19
  107. package/build-module/components/post-schedule/index.js.map +1 -1
  108. package/build-module/components/post-schedule/label.js +90 -13
  109. package/build-module/components/post-schedule/label.js.map +1 -1
  110. package/build-module/components/post-slug/index.js.map +1 -1
  111. package/build-module/components/post-sticky/index.js.map +1 -1
  112. package/build-module/components/post-switch-to-draft-button/index.js.map +1 -1
  113. package/build-module/components/post-taxonomies/flat-term-selector.js +7 -4
  114. package/build-module/components/post-taxonomies/flat-term-selector.js.map +1 -1
  115. package/build-module/components/post-taxonomies/hierarchical-term-selector.js.map +1 -1
  116. package/build-module/components/post-title/index.js.map +1 -1
  117. package/build-module/components/post-title/index.native.js.map +1 -1
  118. package/build-module/components/post-trash/check.js.map +1 -1
  119. package/build-module/components/post-visibility/index.js +12 -13
  120. package/build-module/components/post-visibility/index.js.map +1 -1
  121. package/build-module/components/provider/index.js.map +1 -1
  122. package/build-module/components/provider/index.native.js +0 -1
  123. package/build-module/components/provider/index.native.js.map +1 -1
  124. package/build-module/components/provider/use-block-editor-settings.js +4 -2
  125. package/build-module/components/provider/use-block-editor-settings.js.map +1 -1
  126. package/build-module/components/template-validation-notice/index.js.map +1 -1
  127. package/build-module/components/theme-support-check/index.js +2 -2
  128. package/build-module/components/theme-support-check/index.js.map +1 -1
  129. package/build-module/hooks/custom-sources-backwards-compatibility.js.map +1 -1
  130. package/build-module/store/actions.js +5 -1
  131. package/build-module/store/actions.js.map +1 -1
  132. package/build-module/store/reducer.js +2 -2
  133. package/build-module/store/reducer.js.map +1 -1
  134. package/build-module/store/selectors.js +2 -2
  135. package/build-module/store/selectors.js.map +1 -1
  136. package/build-module/utils/media-upload/index.js +3 -5
  137. package/build-module/utils/media-upload/index.js.map +1 -1
  138. package/build-style/style-rtl.css +1 -17
  139. package/build-style/style.css +1 -17
  140. package/package.json +29 -29
  141. package/src/components/editor-help/help-section-title.native.js +29 -0
  142. package/src/components/editor-help/help-topic-row.native.js +2 -2
  143. package/src/components/editor-help/icon-move-blocks.native.js +10 -0
  144. package/src/components/editor-help/images/drag-and-drop-dark.png +0 -0
  145. package/src/components/editor-help/images/drag-and-drop-dark@2x.png +0 -0
  146. package/src/components/editor-help/images/drag-and-drop-dark@3x.png +0 -0
  147. package/src/components/editor-help/images/drag-and-drop-light.png +0 -0
  148. package/src/components/editor-help/images/drag-and-drop-light@2x.png +0 -0
  149. package/src/components/editor-help/images/drag-and-drop-light@3x.png +0 -0
  150. package/src/components/editor-help/index.native.js +26 -28
  151. package/src/components/editor-help/move-blocks.native.js +22 -2
  152. package/src/components/editor-help/style.scss +36 -4
  153. package/src/components/editor-help/view-sections.native.js +23 -8
  154. package/src/components/entities-saved-states/entity-record-item.js +6 -6
  155. package/src/components/entities-saved-states/index.js +6 -9
  156. package/src/components/global-keyboard-shortcuts/save-shortcut.js +2 -3
  157. package/src/components/index.js +4 -1
  158. package/src/components/local-autosave-monitor/index.js +39 -38
  159. package/src/components/page-attributes/parent.js +5 -8
  160. package/src/components/post-author/select.js +2 -3
  161. package/src/components/post-comments/index.js +4 -3
  162. package/src/components/post-format/index.js +2 -3
  163. package/src/components/post-last-revision/check.js +2 -4
  164. package/src/components/post-last-revision/index.js +2 -4
  165. package/src/components/post-pending-status/check.js +2 -5
  166. package/src/components/post-pingbacks/index.js +2 -3
  167. package/src/components/post-publish-button/index.js +7 -8
  168. package/src/components/post-publish-panel/index.js +2 -3
  169. package/src/components/post-publish-panel/maybe-category-panel.js +7 -5
  170. package/src/components/post-publish-panel/maybe-post-format-panel.js +2 -3
  171. package/src/components/post-publish-panel/postpublish.js +2 -5
  172. package/src/components/post-publish-panel/prepublish.js +2 -3
  173. package/src/components/post-publish-panel/test/__snapshots__/index.js.snap +1 -1
  174. package/src/components/post-schedule/index.js +6 -13
  175. package/src/components/post-schedule/label.js +111 -17
  176. package/src/components/post-schedule/test/label.js +127 -15
  177. package/src/components/post-slug/index.js +2 -3
  178. package/src/components/post-sticky/index.js +2 -3
  179. package/src/components/post-switch-to-draft-button/index.js +2 -5
  180. package/src/components/post-taxonomies/flat-term-selector.js +9 -12
  181. package/src/components/post-taxonomies/hierarchical-term-selector.js +4 -6
  182. package/src/components/post-title/index.js +21 -31
  183. package/src/components/post-title/index.native.js +10 -16
  184. package/src/components/post-title/style.scss +1 -1
  185. package/src/components/post-trash/check.js +2 -3
  186. package/src/components/post-visibility/index.js +11 -17
  187. package/src/components/post-visibility/style.scss +0 -17
  188. package/src/components/provider/index.js +2 -3
  189. package/src/components/provider/index.native.js +12 -17
  190. package/src/components/provider/use-block-editor-settings.js +4 -8
  191. package/src/components/template-validation-notice/index.js +2 -3
  192. package/src/components/theme-support-check/index.js +2 -2
  193. package/src/hooks/custom-sources-backwards-compatibility.js +45 -44
  194. package/src/store/actions.js +213 -190
  195. package/src/store/reducer.js +2 -2
  196. package/src/store/selectors.js +16 -21
  197. package/src/store/test/selectors.js +13 -16
  198. package/src/utils/media-upload/index.js +2 -5
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { noop, get, some } from 'lodash';
4
+ import { get, some } from 'lodash';
5
5
  import classnames from 'classnames';
6
6
 
7
7
  /**
@@ -19,15 +19,16 @@ import { __ } from '@wordpress/i18n';
19
19
  import PublishButtonLabel from './label';
20
20
  import { store as editorStore } from '../../store';
21
21
 
22
+ const noop = () => {};
23
+
22
24
  export class PostPublishButton extends Component {
23
25
  constructor( props ) {
24
26
  super( props );
25
27
  this.buttonNode = createRef();
26
28
 
27
29
  this.createOnClick = this.createOnClick.bind( this );
28
- this.closeEntitiesSavedStates = this.closeEntitiesSavedStates.bind(
29
- this
30
- );
30
+ this.closeEntitiesSavedStates =
31
+ this.closeEntitiesSavedStates.bind( this );
31
32
 
32
33
  this.state = {
33
34
  entitiesSavedStatesCallback: false,
@@ -41,10 +42,8 @@ export class PostPublishButton extends Component {
41
42
 
42
43
  createOnClick( callback ) {
43
44
  return ( ...args ) => {
44
- const {
45
- hasNonPostEntityChanges,
46
- setEntitiesSavedStatesCallback,
47
- } = this.props;
45
+ const { hasNonPostEntityChanges, setEntitiesSavedStatesCallback } =
46
+ this.props;
48
47
  // If a post with non-post entities is published, but the user
49
48
  // elects to not save changes to the non-post entities, those
50
49
  // entities will still be dirty when the Publish button is clicked.
@@ -167,9 +167,8 @@ export default compose( [
167
167
  };
168
168
  } ),
169
169
  withDispatch( ( dispatch, { isPublishSidebarEnabled } ) => {
170
- const { disablePublishSidebar, enablePublishSidebar } = dispatch(
171
- editorStore
172
- );
170
+ const { disablePublishSidebar, enablePublishSidebar } =
171
+ dispatch( editorStore );
173
172
  return {
174
173
  onTogglePublishSidebar: () => {
175
174
  if ( isPublishSidebarEnabled ) {
@@ -21,15 +21,17 @@ import { store as editorStore } from '../../store';
21
21
  function MaybeCategoryPanel() {
22
22
  const hasNoCategory = useSelect( ( select ) => {
23
23
  const postType = select( editorStore ).getCurrentPostType();
24
- const categoriesTaxonomy = select( coreStore ).getTaxonomy(
25
- 'category'
26
- );
27
- const defaultCategorySlug = 'uncategorized';
24
+ const categoriesTaxonomy =
25
+ select( coreStore ).getTaxonomy( 'category' );
26
+ const defaultCategoryId = select( coreStore ).getEntityRecord(
27
+ 'root',
28
+ 'site'
29
+ )?.default_category;
28
30
  const defaultCategory = select( coreStore ).getEntityRecords(
29
31
  'taxonomy',
30
32
  'category',
31
33
  {
32
- slug: defaultCategorySlug,
34
+ id: defaultCategoryId,
33
35
  }
34
36
  )?.[ 0 ];
35
37
  const postTypeSupportsCategories =
@@ -39,9 +39,8 @@ const PostFormatSuggestion = ( {
39
39
 
40
40
  export default function PostFormatPanel() {
41
41
  const { currentPostFormat, suggestion } = useSelect( ( select ) => {
42
- const { getEditedPostAttribute, getSuggestedPostFormat } = select(
43
- editorStore
44
- );
42
+ const { getEditedPostAttribute, getSuggestedPostFormat } =
43
+ select( editorStore );
45
44
  const supportedFormats = get(
46
45
  select( coreStore ).getThemeSupports(),
47
46
  [ 'formats' ],
@@ -163,11 +163,8 @@ class PostPublishPanelPostpublish extends Component {
163
163
  }
164
164
 
165
165
  export default withSelect( ( select ) => {
166
- const {
167
- getEditedPostAttribute,
168
- getCurrentPost,
169
- isCurrentPostScheduled,
170
- } = select( editorStore );
166
+ const { getEditedPostAttribute, getCurrentPost, isCurrentPostScheduled } =
167
+ select( editorStore );
171
168
  const { getPostType } = select( coreStore );
172
169
 
173
170
  return {
@@ -35,9 +35,8 @@ function PostPublishPanelPrepublish( { children } ) {
35
35
  siteTitle,
36
36
  siteHome,
37
37
  } = useSelect( ( select ) => {
38
- const { getCurrentPost, isEditedPostBeingScheduled } = select(
39
- editorStore
40
- );
38
+ const { getCurrentPost, isEditedPostBeingScheduled } =
39
+ select( editorStore );
41
40
  const { getEntityRecord, isResolving } = select( coreStore );
42
41
  const siteData =
43
42
  getEntityRecord( 'root', '__unstableBase', undefined ) || {};
@@ -184,7 +184,7 @@ exports[`PostPublishPanel should render the spinner if the post is being saved 1
184
184
  <div
185
185
  className="editor-post-publish-panel__content"
186
186
  >
187
- <Spinner />
187
+ <ForwardRef(UnforwardedSpinner) />
188
188
  </div>
189
189
  <div
190
190
  className="editor-post-publish-panel__footer"
@@ -3,8 +3,8 @@
3
3
  */
4
4
  import { __experimentalGetSettings } from '@wordpress/date';
5
5
  import { useDispatch, useSelect } from '@wordpress/data';
6
- import { DateTimePicker } from '@wordpress/components';
7
- import { useRef, useState, useMemo } from '@wordpress/element';
6
+ import { __experimentalPublishDateTimePicker as PublishDateTimePicker } from '@wordpress/block-editor';
7
+ import { useState, useMemo } from '@wordpress/element';
8
8
  import { store as coreStore } from '@wordpress/core-data';
9
9
 
10
10
  /**
@@ -21,7 +21,7 @@ function getDayOfTheMonth( date = new Date(), firstDay = true ) {
21
21
  ).toISOString();
22
22
  }
23
23
 
24
- export default function PostSchedule() {
24
+ export default function PostSchedule( { onClose } ) {
25
25
  const { postDate, postType } = useSelect(
26
26
  ( select ) => ( {
27
27
  postDate: select( editorStore ).getEditedPostAttribute( 'date' ),
@@ -61,7 +61,6 @@ export default function PostSchedule() {
61
61
  [ eventsByPostType ]
62
62
  );
63
63
 
64
- const ref = useRef();
65
64
  const settings = __experimentalGetSettings();
66
65
 
67
66
  // To know if the current timezone is a 12 hour time with look for "a" in the time format
@@ -75,20 +74,14 @@ export default function PostSchedule() {
75
74
  .join( '' ) // Reverse the string and test for "a" not followed by a slash.
76
75
  );
77
76
 
78
- function onChange( newDate ) {
79
- onUpdateDate( newDate );
80
- const { ownerDocument } = ref.current;
81
- ownerDocument.activeElement.blur();
82
- }
83
-
84
77
  return (
85
- <DateTimePicker
86
- ref={ ref }
78
+ <PublishDateTimePicker
87
79
  currentDate={ postDate }
88
- onChange={ onChange }
80
+ onChange={ onUpdateDate }
89
81
  is12Hour={ is12HourTime }
90
82
  events={ events }
91
83
  onMonthPreviewed={ setPreviewedMonth }
84
+ onClose={ onClose }
92
85
  />
93
86
  );
94
87
  }
@@ -1,28 +1,122 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { __ } from '@wordpress/i18n';
5
- import { format, __experimentalGetSettings } from '@wordpress/date';
6
- import { withSelect } from '@wordpress/data';
4
+ import { __, _x, sprintf, isRTL } from '@wordpress/i18n';
5
+ import { __experimentalGetSettings, getDate, dateI18n } from '@wordpress/date';
6
+ import { useSelect } from '@wordpress/data';
7
7
 
8
8
  /**
9
9
  * Internal dependencies
10
10
  */
11
11
  import { store as editorStore } from '../../store';
12
12
 
13
- export function PostScheduleLabel( { date, isFloating } ) {
14
- const settings = __experimentalGetSettings();
15
- return date && ! isFloating
16
- ? format(
17
- `${ settings.formats.date } ${ settings.formats.time }`,
18
- date
19
- )
20
- : __( 'Immediately' );
13
+ export default function PostScheduleLabel( props ) {
14
+ return usePostScheduleLabel( props );
21
15
  }
22
16
 
23
- export default withSelect( ( select ) => {
24
- return {
25
- date: select( editorStore ).getEditedPostAttribute( 'date' ),
26
- isFloating: select( editorStore ).isEditedPostDateFloating(),
27
- };
28
- } )( PostScheduleLabel );
17
+ export function usePostScheduleLabel( { full } ) {
18
+ const { date, isFloating } = useSelect(
19
+ ( select ) => ( {
20
+ date: select( editorStore ).getEditedPostAttribute( 'date' ),
21
+ isFloating: select( editorStore ).isEditedPostDateFloating(),
22
+ } ),
23
+ []
24
+ );
25
+
26
+ return full
27
+ ? getFullPostScheduleLabel( date )
28
+ : getPostScheduleLabel( date, { isFloating } );
29
+ }
30
+
31
+ export function getFullPostScheduleLabel( dateAttribute ) {
32
+ const date = getDate( dateAttribute );
33
+
34
+ const timezoneAbbreviation = getTimezoneAbbreviation();
35
+ const formattedDate = dateI18n(
36
+ // translators: If using a space between 'g:i' and 'a', use a non-breaking sapce.
37
+ _x( 'F j, Y g:i\xa0a', 'post schedule full date format' ),
38
+ date
39
+ );
40
+ return isRTL()
41
+ ? `${ timezoneAbbreviation } ${ formattedDate }`
42
+ : `${ formattedDate } ${ timezoneAbbreviation }`;
43
+ }
44
+
45
+ export function getPostScheduleLabel(
46
+ dateAttribute,
47
+ { isFloating = false, now = new Date() } = {}
48
+ ) {
49
+ if ( ! dateAttribute || isFloating ) {
50
+ return __( 'Immediately' );
51
+ }
52
+
53
+ // If the user timezone does not equal the site timezone then using words
54
+ // like 'tomorrow' is confusing, so show the full date.
55
+ if ( ! isTimezoneSameAsSiteTimezone( now ) ) {
56
+ return getFullPostScheduleLabel( dateAttribute );
57
+ }
58
+
59
+ const date = getDate( dateAttribute );
60
+
61
+ if ( isSameDay( date, now ) ) {
62
+ return sprintf(
63
+ // translators: %s: Time of day the post is scheduled for.
64
+ __( 'Today at %s' ),
65
+ // translators: If using a space between 'g:i' and 'a', use a non-breaking sapce.
66
+ dateI18n( _x( 'g:i\xa0a', 'post schedule time format' ), date )
67
+ );
68
+ }
69
+
70
+ const tomorrow = new Date( now );
71
+ tomorrow.setDate( tomorrow.getDate() + 1 );
72
+
73
+ if ( isSameDay( date, tomorrow ) ) {
74
+ return sprintf(
75
+ // translators: %s: Time of day the post is scheduled for.
76
+ __( 'Tomorrow at %s' ),
77
+ // translators: If using a space between 'g:i' and 'a', use a non-breaking sapce.
78
+ dateI18n( _x( 'g:i\xa0a', 'post schedule time format' ), date )
79
+ );
80
+ }
81
+
82
+ if ( date.getFullYear() === now.getFullYear() ) {
83
+ return dateI18n(
84
+ // translators: If using a space between 'g:i' and 'a', use a non-breaking sapce.
85
+ _x( 'F j g:i\xa0a', 'post schedule date format without year' ),
86
+ date
87
+ );
88
+ }
89
+
90
+ return dateI18n(
91
+ // translators: Use a non-breaking space between 'g:i' and 'a' if appropriate.
92
+ _x( 'F j, Y g:i\xa0a', 'post schedule full date format' ),
93
+ date
94
+ );
95
+ }
96
+
97
+ function getTimezoneAbbreviation() {
98
+ const { timezone } = __experimentalGetSettings();
99
+
100
+ if ( timezone.abbr && isNaN( Number( timezone.abbr ) ) ) {
101
+ return timezone.abbr;
102
+ }
103
+
104
+ const symbol = timezone.offset < 0 ? '' : '+';
105
+ return `UTC${ symbol }${ timezone.offset }`;
106
+ }
107
+
108
+ function isTimezoneSameAsSiteTimezone( date ) {
109
+ const { timezone } = __experimentalGetSettings();
110
+
111
+ const siteOffset = Number( timezone.offset );
112
+ const dateOffset = -1 * ( date.getTimezoneOffset() / 60 );
113
+ return siteOffset === dateOffset;
114
+ }
115
+
116
+ function isSameDay( left, right ) {
117
+ return (
118
+ left.getDate() === right.getDate() &&
119
+ left.getMonth() === right.getMonth() &&
120
+ left.getFullYear() === right.getFullYear()
121
+ );
122
+ }
@@ -1,32 +1,144 @@
1
1
  /**
2
- * External dependencies
2
+ * WordPress dependencies
3
3
  */
4
- import { shallow } from 'enzyme';
4
+ import { __experimentalGetSettings, setSettings } from '@wordpress/date';
5
5
 
6
6
  /**
7
7
  * Internal dependencies
8
8
  */
9
- import { PostScheduleLabel } from '../label';
9
+ import { getFullPostScheduleLabel, getPostScheduleLabel } from '../label';
10
10
 
11
- describe( 'PostScheduleLabel', () => {
11
+ describe( 'getFullPostScheduleLabel', () => {
12
+ it( 'should show a date', () => {
13
+ const label = getFullPostScheduleLabel( '2022-04-28T15:30:00' );
14
+ expect( label ).toBe( 'April 28, 2022 3:30\xa0pm UTC+0' ); // Unused, for backwards compatibility.
15
+ } );
16
+
17
+ it( "should show site's timezone abbr", () => {
18
+ const settings = __experimentalGetSettings();
19
+
20
+ setSettings( {
21
+ ...settings,
22
+ timezone: { offset: 10, string: 'Australia/Sydney', abbr: 'AEST' },
23
+ } );
24
+
25
+ const label = getFullPostScheduleLabel( '2022-04-28T15:30:00' );
26
+ expect( label ).toBe( 'April 28, 2022 3:30\xa0pm AEST' );
27
+
28
+ setSettings( settings );
29
+ } );
30
+
31
+ it( "should show site's timezone offset", () => {
32
+ const settings = __experimentalGetSettings();
33
+
34
+ setSettings( {
35
+ ...settings,
36
+ timezone: { offset: 10 },
37
+ } );
38
+
39
+ const label = getFullPostScheduleLabel( '2022-04-28T15:30:00' );
40
+ expect( label ).toBe( 'April 28, 2022 3:30\xa0pm UTC+10' );
41
+
42
+ setSettings( settings );
43
+ } );
44
+ } );
45
+
46
+ describe( 'getPostScheduleLabel', () => {
12
47
  it( 'should show the post will be published immediately if no publish date is set', () => {
13
- const wrapper = shallow( <PostScheduleLabel date={ undefined } /> );
14
- expect( wrapper.text() ).toBe( 'Immediately' );
48
+ const label = getPostScheduleLabel( undefined );
49
+ expect( label ).toBe( 'Immediately' );
15
50
  } );
16
51
 
17
52
  it( 'should show the post will be published immediately if it has a floating date', () => {
18
- const date = '2018-09-17T01:23:45.678Z';
19
- const wrapper = shallow(
20
- <PostScheduleLabel date={ date } isFloating={ true } />
53
+ const label = getPostScheduleLabel( '2022-04-28T15:30:00', {
54
+ isFloating: true,
55
+ } );
56
+ expect( label ).toBe( 'Immediately' );
57
+ } );
58
+
59
+ it( "should show full date if user timezone does not equal site's timezone", () => {
60
+ const now = new Date( '2022-04-28T13:00:00.000Z' );
61
+ jest.spyOn( now, 'getTimezoneOffset' ).mockImplementationOnce(
62
+ () => 10 * -60 // UTC+10
21
63
  );
22
- expect( wrapper.text() ).toBe( 'Immediately' );
64
+
65
+ const label = getPostScheduleLabel( '2022-04-28T15:30:00', { now } );
66
+ expect( label ).toBe( 'April 28, 2022 3:30\xa0pm UTC+0' );
23
67
  } );
24
68
 
25
- it( 'should show the scheduled publish date if a date has been set', () => {
26
- const date = '2018-09-17T01:23:45.678Z';
27
- const wrapper = shallow(
28
- <PostScheduleLabel date={ date } isFloating={ false } />
69
+ it( "should show today if date is same day as now and user timezone equals site's timezone", () => {
70
+ const settings = __experimentalGetSettings();
71
+
72
+ setSettings( {
73
+ ...settings,
74
+ timezone: { offset: 10 },
75
+ } );
76
+
77
+ const now = new Date( '2022-04-28T03:00:00.000Z' );
78
+ jest.spyOn( now, 'getTimezoneOffset' ).mockImplementationOnce(
79
+ () => 10 * -60 // UTC+10
29
80
  );
30
- expect( wrapper.text() ).not.toBe( 'Immediately' );
81
+
82
+ const label = getPostScheduleLabel( '2022-04-28T15:30:00', { now } );
83
+ expect( label ).toBe( 'Today at 3:30\xa0pm' );
84
+
85
+ setSettings( settings );
86
+ } );
87
+
88
+ it( "should show tomorrow if date is same day as now + 1 day and user timezone equals site's timezone", () => {
89
+ const settings = __experimentalGetSettings();
90
+
91
+ setSettings( {
92
+ ...settings,
93
+ timezone: { offset: 10 },
94
+ } );
95
+
96
+ const now = new Date( '2022-04-28T03:00:00.000Z' );
97
+ jest.spyOn( now, 'getTimezoneOffset' ).mockImplementationOnce(
98
+ () => 10 * -60 // UTC+10
99
+ );
100
+
101
+ const label = getPostScheduleLabel( '2022-04-29T15:30:00', { now } );
102
+ expect( label ).toBe( 'Tomorrow at 3:30\xa0pm' );
103
+
104
+ setSettings( settings );
105
+ } );
106
+
107
+ it( "should hide year if date is same year as now and user timezone equals site's timezone", () => {
108
+ const settings = __experimentalGetSettings();
109
+
110
+ setSettings( {
111
+ ...settings,
112
+ timezone: { offset: 10 },
113
+ } );
114
+
115
+ const now = new Date( '2022-04-28T03:00:00.000Z' );
116
+ jest.spyOn( now, 'getTimezoneOffset' ).mockImplementationOnce(
117
+ () => 10 * -60 // UTC+10
118
+ );
119
+
120
+ const label = getPostScheduleLabel( '2022-12-25T15:30:00', { now } );
121
+ expect( label ).toBe( 'December 25 3:30\xa0pm' );
122
+
123
+ setSettings( settings );
124
+ } );
125
+
126
+ it( "should show year if date is not same year as now and user timezone equals site's timezone", () => {
127
+ const settings = __experimentalGetSettings();
128
+
129
+ setSettings( {
130
+ ...settings,
131
+ timezone: { offset: 10 },
132
+ } );
133
+
134
+ const now = new Date( '2022-04-28T03:00:00.000Z' );
135
+ jest.spyOn( now, 'getTimezoneOffset' ).mockImplementationOnce(
136
+ () => 10 * -60 // UTC+10
137
+ );
138
+
139
+ const label = getPostScheduleLabel( '2023-04-28T15:30:00', { now } );
140
+ expect( label ).toBe( 'April 28, 2023 3:30\xa0pm' );
141
+
142
+ setSettings( settings );
31
143
  } );
32
144
  } );
@@ -68,9 +68,8 @@ export class PostSlug extends Component {
68
68
 
69
69
  export default compose( [
70
70
  withSelect( ( select ) => {
71
- const { getCurrentPost, getEditedPostAttribute } = select(
72
- editorStore
73
- );
71
+ const { getCurrentPost, getEditedPostAttribute } =
72
+ select( editorStore );
74
73
 
75
74
  const { id } = getCurrentPost();
76
75
  return {
@@ -27,9 +27,8 @@ export function PostSticky( { onUpdateSticky, postSticky = false } ) {
27
27
  export default compose( [
28
28
  withSelect( ( select ) => {
29
29
  return {
30
- postSticky: select( editorStore ).getEditedPostAttribute(
31
- 'sticky'
32
- ),
30
+ postSticky:
31
+ select( editorStore ).getEditedPostAttribute( 'sticky' ),
33
32
  };
34
33
  } ),
35
34
  withDispatch( ( dispatch ) => {
@@ -65,11 +65,8 @@ function PostSwitchToDraftButton( {
65
65
 
66
66
  export default compose( [
67
67
  withSelect( ( select ) => {
68
- const {
69
- isSavingPost,
70
- isCurrentPostPublished,
71
- isCurrentPostScheduled,
72
- } = select( editorStore );
68
+ const { isSavingPost, isCurrentPostPublished, isCurrentPostScheduled } =
69
+ select( editorStore );
73
70
  return {
74
71
  isSaving: isSavingPost(),
75
72
  isPublished: isCurrentPostPublished(),
@@ -55,11 +55,11 @@ const termNamesToIds = ( names, terms ) => {
55
55
  };
56
56
 
57
57
  // Tries to create a term or fetch it if it already exists.
58
- function findOrCreateTerm( termName, restBase ) {
58
+ function findOrCreateTerm( termName, restBase, namespace ) {
59
59
  const escapedTermName = escapeString( termName );
60
60
 
61
61
  return apiFetch( {
62
- path: `/wp/v2/${ restBase }`,
62
+ path: `/${ namespace }/${ restBase }`,
63
63
  method: 'POST',
64
64
  data: { name: escapedTermName },
65
65
  } )
@@ -68,7 +68,7 @@ function findOrCreateTerm( termName, restBase ) {
68
68
  if ( errorCode === 'term_exists' ) {
69
69
  // If the terms exist, fetch it instead of creating a new one.
70
70
  const addRequest = apiFetch( {
71
- path: addQueryArgs( `/wp/v2/${ restBase }`, {
71
+ path: addQueryArgs( `/${ namespace }/${ restBase }`, {
72
72
  ...DEFAULT_QUERY,
73
73
  search: escapedTermName,
74
74
  } ),
@@ -100,14 +100,10 @@ function FlatTermSelector( { slug } ) {
100
100
  hasResolvedTerms,
101
101
  } = useSelect(
102
102
  ( select ) => {
103
- const { getCurrentPost, getEditedPostAttribute } = select(
104
- editorStore
105
- );
106
- const {
107
- getEntityRecords,
108
- getTaxonomy,
109
- hasFinishedResolution,
110
- } = select( coreStore );
103
+ const { getCurrentPost, getEditedPostAttribute } =
104
+ select( editorStore );
105
+ const { getEntityRecords, getTaxonomy, hasFinishedResolution } =
106
+ select( coreStore );
111
107
  const post = getCurrentPost();
112
108
  const _taxonomy = getTaxonomy( slug );
113
109
  const _termIds = _taxonomy
@@ -228,9 +224,10 @@ function FlatTermSelector( { slug } ) {
228
224
  return;
229
225
  }
230
226
 
227
+ const namespace = taxonomy?.rest_namespace ?? 'wp/v2';
231
228
  Promise.all(
232
229
  newTermNames.map( ( termName ) =>
233
- findOrCreateTerm( termName, taxonomy.rest_base )
230
+ findOrCreateTerm( termName, taxonomy.rest_base, namespace )
234
231
  )
235
232
  ).then( ( newTerms ) => {
236
233
  const newAvailableTerms = availableTerms.concat( newTerms );
@@ -173,12 +173,10 @@ function HierarchicalTermSelector( { slug } ) {
173
173
  taxonomy,
174
174
  } = useSelect(
175
175
  ( select ) => {
176
- const { getCurrentPost, getEditedPostAttribute } = select(
177
- editorStore
178
- );
179
- const { getTaxonomy, getEntityRecords, isResolving } = select(
180
- coreStore
181
- );
176
+ const { getCurrentPost, getEditedPostAttribute } =
177
+ select( editorStore );
178
+ const { getTaxonomy, getEntityRecords, isResolving } =
179
+ select( coreStore );
182
180
  const _taxonomy = getTaxonomy( slug );
183
181
 
184
182
  return {
@@ -37,37 +37,27 @@ function PostTitle( _, forwardedRef ) {
37
37
  const ref = useRef();
38
38
  const [ isSelected, setIsSelected ] = useState( false );
39
39
  const { editPost } = useDispatch( editorStore );
40
- const {
41
- insertDefaultBlock,
42
- clearSelectedBlock,
43
- insertBlocks,
44
- } = useDispatch( blockEditorStore );
45
- const {
46
- isCleanNewPost,
47
- title,
48
- placeholder,
49
- isFocusMode,
50
- hasFixedToolbar,
51
- } = useSelect( ( select ) => {
52
- const {
53
- getEditedPostAttribute,
54
- isCleanNewPost: _isCleanNewPost,
55
- } = select( editorStore );
56
- const { getSettings } = select( blockEditorStore );
57
- const {
58
- titlePlaceholder,
59
- focusMode,
60
- hasFixedToolbar: _hasFixedToolbar,
61
- } = getSettings();
62
-
63
- return {
64
- isCleanNewPost: _isCleanNewPost(),
65
- title: getEditedPostAttribute( 'title' ),
66
- placeholder: titlePlaceholder,
67
- isFocusMode: focusMode,
68
- hasFixedToolbar: _hasFixedToolbar,
69
- };
70
- }, [] );
40
+ const { insertDefaultBlock, clearSelectedBlock, insertBlocks } =
41
+ useDispatch( blockEditorStore );
42
+ const { isCleanNewPost, title, placeholder, isFocusMode, hasFixedToolbar } =
43
+ useSelect( ( select ) => {
44
+ const { getEditedPostAttribute, isCleanNewPost: _isCleanNewPost } =
45
+ select( editorStore );
46
+ const { getSettings } = select( blockEditorStore );
47
+ const {
48
+ titlePlaceholder,
49
+ focusMode,
50
+ hasFixedToolbar: _hasFixedToolbar,
51
+ } = getSettings();
52
+
53
+ return {
54
+ isCleanNewPost: _isCleanNewPost(),
55
+ title: getEditedPostAttribute( 'title' ),
56
+ placeholder: titlePlaceholder,
57
+ isFocusMode: focusMode,
58
+ hasFixedToolbar: _hasFixedToolbar,
59
+ };
60
+ }, [] );
71
61
 
72
62
  useImperativeHandle( forwardedRef, () => ( {
73
63
  focus: () => {