@wordpress/block-library 6.0.20 → 6.0.26

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 (139) hide show
  1. package/build/gallery/constants.js +5 -1
  2. package/build/gallery/constants.js.map +1 -1
  3. package/build/gallery/transforms.js +8 -2
  4. package/build/gallery/transforms.js.map +1 -1
  5. package/build/gallery/utils.js +4 -3
  6. package/build/gallery/utils.js.map +1 -1
  7. package/build/heading/edit.js +14 -2
  8. package/build/heading/edit.js.map +1 -1
  9. package/build/navigation/edit/index.js +8 -2
  10. package/build/navigation/edit/index.js.map +1 -1
  11. package/build/navigation/edit/navigation-menu-selector.js +42 -4
  12. package/build/navigation/edit/navigation-menu-selector.js.map +1 -1
  13. package/build/navigation/edit/placeholder/index.js +6 -41
  14. package/build/navigation/edit/placeholder/index.js.map +1 -1
  15. package/build/navigation/use-convert-classic-menu.js +59 -0
  16. package/build/navigation/use-convert-classic-menu.js.map +1 -0
  17. package/build/page-list/edit.js +37 -10
  18. package/build/page-list/edit.js.map +1 -1
  19. package/build/post-featured-image/dimension-controls.js +50 -30
  20. package/build/post-featured-image/dimension-controls.js.map +1 -1
  21. package/build/post-featured-image/edit.js +4 -2
  22. package/build/post-featured-image/edit.js.map +1 -1
  23. package/build/site-logo/edit.js +0 -25
  24. package/build/site-logo/edit.js.map +1 -1
  25. package/build/social-links/deprecated.js +1 -62
  26. package/build/social-links/deprecated.js.map +1 -1
  27. package/build/social-links/edit.js +1 -1
  28. package/build/social-links/edit.js.map +1 -1
  29. package/build/spacer/controls.js +111 -0
  30. package/build/spacer/controls.js.map +1 -0
  31. package/build/spacer/controls.native.js +95 -0
  32. package/build/spacer/controls.native.js.map +1 -0
  33. package/build/spacer/deprecated.js +53 -0
  34. package/build/spacer/deprecated.js.map +1 -0
  35. package/build/spacer/edit.js +111 -82
  36. package/build/spacer/edit.js.map +1 -1
  37. package/build/spacer/edit.native.js +76 -0
  38. package/build/spacer/edit.native.js.map +1 -0
  39. package/build/spacer/index.js +7 -4
  40. package/build/spacer/index.js.map +1 -1
  41. package/build/spacer/save.js +6 -3
  42. package/build/spacer/save.js.map +1 -1
  43. package/build-module/gallery/constants.js +2 -0
  44. package/build-module/gallery/constants.js.map +1 -1
  45. package/build-module/gallery/transforms.js +8 -2
  46. package/build-module/gallery/transforms.js.map +1 -1
  47. package/build-module/gallery/utils.js +5 -4
  48. package/build-module/gallery/utils.js.map +1 -1
  49. package/build-module/heading/edit.js +15 -3
  50. package/build-module/heading/edit.js.map +1 -1
  51. package/build-module/navigation/edit/index.js +7 -2
  52. package/build-module/navigation/edit/index.js.map +1 -1
  53. package/build-module/navigation/edit/navigation-menu-selector.js +39 -4
  54. package/build-module/navigation/edit/navigation-menu-selector.js.map +1 -1
  55. package/build-module/navigation/edit/placeholder/index.js +5 -41
  56. package/build-module/navigation/edit/placeholder/index.js.map +1 -1
  57. package/build-module/navigation/use-convert-classic-menu.js +47 -0
  58. package/build-module/navigation/use-convert-classic-menu.js.map +1 -0
  59. package/build-module/page-list/edit.js +38 -11
  60. package/build-module/page-list/edit.js.map +1 -1
  61. package/build-module/post-featured-image/dimension-controls.js +52 -29
  62. package/build-module/post-featured-image/dimension-controls.js.map +1 -1
  63. package/build-module/post-featured-image/edit.js +4 -2
  64. package/build-module/post-featured-image/edit.js.map +1 -1
  65. package/build-module/site-logo/edit.js +0 -25
  66. package/build-module/site-logo/edit.js.map +1 -1
  67. package/build-module/social-links/deprecated.js +1 -62
  68. package/build-module/social-links/deprecated.js.map +1 -1
  69. package/build-module/social-links/edit.js +1 -1
  70. package/build-module/social-links/edit.js.map +1 -1
  71. package/build-module/spacer/controls.js +101 -0
  72. package/build-module/spacer/controls.js.map +1 -0
  73. package/build-module/spacer/controls.native.js +82 -0
  74. package/build-module/spacer/controls.native.js.map +1 -0
  75. package/build-module/spacer/deprecated.js +44 -0
  76. package/build-module/spacer/deprecated.js.map +1 -0
  77. package/build-module/spacer/edit.js +108 -82
  78. package/build-module/spacer/edit.js.map +1 -1
  79. package/build-module/spacer/edit.native.js +61 -0
  80. package/build-module/spacer/edit.native.js.map +1 -0
  81. package/build-module/spacer/index.js +6 -4
  82. package/build-module/spacer/index.js.map +1 -1
  83. package/build-module/spacer/save.js +6 -3
  84. package/build-module/spacer/save.js.map +1 -1
  85. package/build-style/common-rtl.css +8 -0
  86. package/build-style/common.css +8 -0
  87. package/build-style/cover/style-rtl.css +60 -0
  88. package/build-style/cover/style.css +60 -0
  89. package/build-style/editor-rtl.css +8 -7
  90. package/build-style/editor.css +8 -7
  91. package/build-style/gallery/style-rtl.css +2 -1
  92. package/build-style/gallery/style.css +2 -1
  93. package/build-style/image/style-rtl.css +0 -2
  94. package/build-style/image/style.css +0 -2
  95. package/build-style/page-list/editor-rtl.css +4 -0
  96. package/build-style/page-list/editor.css +4 -0
  97. package/build-style/post-featured-image/editor-rtl.css +0 -7
  98. package/build-style/post-featured-image/editor.css +0 -7
  99. package/build-style/post-template/style-rtl.css +4 -0
  100. package/build-style/post-template/style.css +4 -0
  101. package/build-style/spacer/editor-rtl.css +4 -0
  102. package/build-style/spacer/editor.css +4 -0
  103. package/build-style/style-rtl.css +74 -3
  104. package/build-style/style.css +74 -3
  105. package/package.json +8 -8
  106. package/src/common.scss +8 -0
  107. package/src/cover/style.scss +13 -0
  108. package/src/gallery/constants.js +2 -0
  109. package/src/gallery/style.scss +4 -1
  110. package/src/gallery/transforms.js +7 -1
  111. package/src/gallery/utils.js +7 -3
  112. package/src/heading/edit.js +18 -5
  113. package/src/image/style.scss +0 -2
  114. package/src/navigation/edit/index.js +9 -1
  115. package/src/navigation/edit/navigation-menu-selector.js +65 -15
  116. package/src/navigation/edit/placeholder/index.js +9 -44
  117. package/src/navigation/use-convert-classic-menu.js +58 -0
  118. package/src/page-list/edit.js +47 -9
  119. package/src/page-list/editor.scss +4 -0
  120. package/src/page-list/index.php +5 -0
  121. package/src/post-featured-image/dimension-controls.js +75 -50
  122. package/src/post-featured-image/edit.js +6 -4
  123. package/src/post-featured-image/editor.scss +0 -8
  124. package/src/post-template/style.scss +5 -0
  125. package/src/search/index.php +6 -4
  126. package/src/site-logo/edit.js +1 -32
  127. package/src/site-logo/index.php +1 -1
  128. package/src/site-title/index.php +0 -1
  129. package/src/social-links/deprecated.js +0 -59
  130. package/src/social-links/edit.js +1 -1
  131. package/src/spacer/block.json +3 -3
  132. package/src/spacer/controls.js +108 -0
  133. package/src/spacer/controls.native.js +82 -0
  134. package/src/spacer/deprecated.js +41 -0
  135. package/src/spacer/edit.js +127 -113
  136. package/src/spacer/edit.native.js +68 -0
  137. package/src/spacer/editor.scss +6 -0
  138. package/src/spacer/index.js +2 -0
  139. package/src/spacer/save.js +5 -2
@@ -1,3 +1,5 @@
1
1
  export const LINK_DESTINATION_NONE = 'none';
2
2
  export const LINK_DESTINATION_MEDIA = 'media';
3
3
  export const LINK_DESTINATION_ATTACHMENT = 'attachment';
4
+ export const LINK_DESTINATION_MEDIA_WP_CORE = 'file';
5
+ export const LINK_DESTINATION_ATTACHMENT_WP_CORE = 'post';
@@ -30,6 +30,7 @@
30
30
  margin-top: auto;
31
31
  margin-bottom: auto;
32
32
  flex-direction: column;
33
+ max-width: 100%;
33
34
 
34
35
  > div,
35
36
  > a {
@@ -41,7 +42,9 @@
41
42
  img {
42
43
  display: block;
43
44
  height: auto;
44
- max-width: 100%;
45
+ // Ensure max-width is not overridden on the img when the parent gallery has
46
+ // wide or full alignment.
47
+ max-width: 100% !important;
45
48
  width: auto;
46
49
  }
47
50
 
@@ -291,7 +291,10 @@ const transforms = {
291
291
  url,
292
292
  alt,
293
293
  caption,
294
- imageSizeSlug,
294
+ sizeSlug: imageSizeSlug,
295
+ linkDestination,
296
+ href,
297
+ linkTarget,
295
298
  },
296
299
  } ) =>
297
300
  createBlock( 'core/image', {
@@ -301,6 +304,9 @@ const transforms = {
301
304
  caption,
302
305
  sizeSlug: imageSizeSlug,
303
306
  align,
307
+ linkDestination,
308
+ href,
309
+ linkTarget,
304
310
  } )
305
311
  );
306
312
  }
@@ -5,6 +5,8 @@ import {
5
5
  LINK_DESTINATION_ATTACHMENT,
6
6
  LINK_DESTINATION_MEDIA,
7
7
  LINK_DESTINATION_NONE,
8
+ LINK_DESTINATION_MEDIA_WP_CORE,
9
+ LINK_DESTINATION_ATTACHMENT_WP_CORE,
8
10
  } from './constants';
9
11
  import {
10
12
  LINK_DESTINATION_ATTACHMENT as IMAGE_LINK_DESTINATION_ATTACHMENT,
@@ -21,15 +23,17 @@ import {
21
23
  * @return {Object} New attributes to assign to image block.
22
24
  */
23
25
  export function getHrefAndDestination( image, destination ) {
24
- // Need to determine the URL that the selected destination maps to.
25
- // Gutenberg and WordPress use different constants so the new link
26
- // destination also needs to be tweaked.
26
+ // Gutenberg and WordPress use different constants so if image_default_link_type
27
+ // option is set we need to map from the WP Core values.
28
+
27
29
  switch ( destination ) {
30
+ case LINK_DESTINATION_MEDIA_WP_CORE:
28
31
  case LINK_DESTINATION_MEDIA:
29
32
  return {
30
33
  href: image?.source_url || image?.url, // eslint-disable-line camelcase
31
34
  linkDestination: IMAGE_LINK_DESTINATION_MEDIA,
32
35
  };
36
+ case LINK_DESTINATION_ATTACHMENT_WP_CORE:
33
37
  case LINK_DESTINATION_ATTACHMENT:
34
38
  return {
35
39
  href: image?.link,
@@ -8,7 +8,7 @@ import classnames from 'classnames';
8
8
  */
9
9
  import { __ } from '@wordpress/i18n';
10
10
  import { useEffect } from '@wordpress/element';
11
- import { useDispatch } from '@wordpress/data';
11
+ import { useDispatch, useSelect } from '@wordpress/data';
12
12
  import { createBlock, getDefaultBlockName } from '@wordpress/blocks';
13
13
  import {
14
14
  AlignmentControl,
@@ -41,6 +41,14 @@ function HeadingEdit( {
41
41
  style,
42
42
  } );
43
43
 
44
+ const { canGenerateAnchors } = useSelect( ( select ) => {
45
+ const settings = select( blockEditorStore ).getSettings();
46
+
47
+ return {
48
+ canGenerateAnchors: !! settings.__experimentalGenerateAnchors,
49
+ };
50
+ }, [] );
51
+
44
52
  const { __unstableMarkNextChangeAsNotPersistent } = useDispatch(
45
53
  blockEditorStore
46
54
  );
@@ -48,6 +56,10 @@ function HeadingEdit( {
48
56
  // Initially set anchor for headings that have content but no anchor set.
49
57
  // This is used when transforming a block to heading, or for legacy anchors.
50
58
  useEffect( () => {
59
+ if ( ! canGenerateAnchors ) {
60
+ return;
61
+ }
62
+
51
63
  if ( ! anchor && content ) {
52
64
  // This side-effect should not create an undo level.
53
65
  __unstableMarkNextChangeAsNotPersistent();
@@ -59,14 +71,15 @@ function HeadingEdit( {
59
71
 
60
72
  // Remove anchor map when block unmounts.
61
73
  return () => setAnchor( clientId, null );
62
- }, [ content, anchor ] );
74
+ }, [ anchor, content, clientId, canGenerateAnchors ] );
63
75
 
64
76
  const onContentChange = ( value ) => {
65
77
  const newAttrs = { content: value };
66
78
  if (
67
- ! anchor ||
68
- ! value ||
69
- generateAnchor( clientId, content ) === anchor
79
+ canGenerateAnchors &&
80
+ ( ! anchor ||
81
+ ! value ||
82
+ generateAnchor( clientId, content ) === anchor )
70
83
  ) {
71
84
  newAttrs.anchor = generateAnchor( clientId, value );
72
85
  }
@@ -2,8 +2,6 @@
2
2
  margin: 0 0 1em 0;
3
3
 
4
4
  img {
5
- height: auto;
6
- max-width: 100%;
7
5
  vertical-align: bottom;
8
6
  }
9
7
 
@@ -45,6 +45,7 @@ import { __ } from '@wordpress/i18n';
45
45
  */
46
46
  import useListViewModal from './use-list-view-modal';
47
47
  import useNavigationMenu from '../use-navigation-menu';
48
+ import useNavigationEntities from '../use-navigation-entities';
48
49
  import Placeholder from './placeholder';
49
50
  import PlaceholderPreview from './placeholder/placeholder-preview';
50
51
  import ResponsiveWrapper from './responsive-wrapper';
@@ -151,6 +152,10 @@ function Navigation( {
151
152
  `navigationMenu/${ ref }`
152
153
  );
153
154
 
155
+ // Preload classic menus, so that they don't suddenly pop-in when viewing
156
+ // the Select Menu dropdown.
157
+ useNavigationEntities();
158
+
154
159
  const {
155
160
  hasUncontrolledInnerBlocks,
156
161
  uncontrolledInnerBlocks,
@@ -474,12 +479,15 @@ function Navigation( {
474
479
  >
475
480
  { ( { onClose } ) => (
476
481
  <NavigationMenuSelector
482
+ clientId={ clientId }
477
483
  onSelect={ ( { id } ) => {
478
484
  setRef( id );
479
485
  onClose();
480
486
  } }
481
487
  onCreateNew={ startWithEmptyMenu }
482
- showCreate={ canUserCreateNavigation }
488
+ canUserCreateNavigation={
489
+ canUserCreateNavigation
490
+ }
483
491
  />
484
492
  ) }
485
493
  </ToolbarDropdownMenu>
@@ -11,18 +11,47 @@ import { addQueryArgs } from '@wordpress/url';
11
11
  * Internal dependencies
12
12
  */
13
13
  import useNavigationMenu from '../use-navigation-menu';
14
+ import useNavigationEntities from '../use-navigation-entities';
15
+ import useConvertClassicMenu from '../use-convert-classic-menu';
16
+ import useCreateNavigationMenu from './use-create-navigation-menu';
14
17
 
15
18
  export default function NavigationMenuSelector( {
19
+ clientId,
16
20
  onSelect,
17
21
  onCreateNew,
18
- showCreate = false,
22
+ canUserCreateNavigation = false,
19
23
  } ) {
24
+ const {
25
+ menus: classicMenus,
26
+ hasMenus: hasClassicMenus,
27
+ } = useNavigationEntities();
20
28
  const { navigationMenus } = useNavigationMenu();
21
29
  const ref = useEntityId( 'postType', 'wp_navigation' );
22
30
 
31
+ const createNavigationMenu = useCreateNavigationMenu( clientId );
32
+
33
+ const onFinishMenuCreation = async (
34
+ blocks,
35
+ navigationMenuTitle = null
36
+ ) => {
37
+ if ( ! canUserCreateNavigation ) {
38
+ return;
39
+ }
40
+
41
+ const navigationMenu = await createNavigationMenu(
42
+ navigationMenuTitle,
43
+ blocks
44
+ );
45
+ onSelect( navigationMenu );
46
+ };
47
+
48
+ const convertClassicMenuToBlocks = useConvertClassicMenu(
49
+ onFinishMenuCreation
50
+ );
51
+
23
52
  return (
24
53
  <>
25
- <MenuGroup>
54
+ <MenuGroup label={ __( 'Menus' ) }>
26
55
  <MenuItemsChoice
27
56
  value={ ref }
28
57
  onSelect={ ( selectedId ) =>
@@ -46,19 +75,40 @@ export default function NavigationMenuSelector( {
46
75
  } ) }
47
76
  />
48
77
  </MenuGroup>
49
- { showCreate && (
50
- <MenuGroup>
51
- <MenuItem onClick={ onCreateNew }>
52
- { __( 'Create new menu' ) }
53
- </MenuItem>
54
- <MenuItem
55
- href={ addQueryArgs( 'edit.php', {
56
- post_type: 'wp_navigation',
57
- } ) }
58
- >
59
- { __( 'Manage menus' ) }
60
- </MenuItem>
61
- </MenuGroup>
78
+ { canUserCreateNavigation && (
79
+ <>
80
+ { hasClassicMenus && (
81
+ <MenuGroup label={ __( 'Classic Menus' ) }>
82
+ { classicMenus.map( ( menu ) => {
83
+ return (
84
+ <MenuItem
85
+ onClick={ () => {
86
+ convertClassicMenuToBlocks(
87
+ menu.id,
88
+ menu.name
89
+ );
90
+ } }
91
+ key={ menu.id }
92
+ >
93
+ { decodeEntities( menu.name ) }
94
+ </MenuItem>
95
+ );
96
+ } ) }
97
+ </MenuGroup>
98
+ ) }
99
+ <MenuGroup label={ __( 'Tools' ) }>
100
+ <MenuItem onClick={ onCreateNew }>
101
+ { __( 'Create new menu' ) }
102
+ </MenuItem>
103
+ <MenuItem
104
+ href={ addQueryArgs( 'edit.php', {
105
+ post_type: 'wp_navigation',
106
+ } ) }
107
+ >
108
+ { __( 'Manage menus' ) }
109
+ </MenuItem>
110
+ </MenuGroup>
111
+ </>
62
112
  ) }
63
113
  </>
64
114
  );
@@ -9,7 +9,6 @@ import {
9
9
  MenuGroup,
10
10
  MenuItem,
11
11
  } from '@wordpress/components';
12
- import { useCallback, useState, useEffect } from '@wordpress/element';
13
12
  import { __ } from '@wordpress/i18n';
14
13
  import { navigation, Icon } from '@wordpress/icons';
15
14
  import { decodeEntities } from '@wordpress/html-entities';
@@ -20,14 +19,13 @@ import { decodeEntities } from '@wordpress/html-entities';
20
19
 
21
20
  import useNavigationEntities from '../../use-navigation-entities';
22
21
  import PlaceholderPreview from './placeholder-preview';
23
- import menuItemsToBlocks from '../../menu-items-to-blocks';
24
22
  import useNavigationMenu from '../../use-navigation-menu';
25
23
  import useCreateNavigationMenu from '../use-create-navigation-menu';
24
+ import useConvertClassicMenu from '../../use-convert-classic-menu';
26
25
 
27
26
  const ExistingMenusDropdown = ( {
28
27
  canSwitchNavigationMenu,
29
28
  navigationMenus,
30
- setSelectedMenu,
31
29
  onFinish,
32
30
  menus,
33
31
  onCreateFromMenu,
@@ -53,7 +51,6 @@ const ExistingMenusDropdown = ( {
53
51
  return (
54
52
  <MenuItem
55
53
  onClick={ () => {
56
- setSelectedMenu( menu.id );
57
54
  onFinish( menu );
58
55
  } }
59
56
  onClose={ onClose }
@@ -72,8 +69,10 @@ const ExistingMenusDropdown = ( {
72
69
  return (
73
70
  <MenuItem
74
71
  onClick={ () => {
75
- setSelectedMenu( menu.id );
76
- onCreateFromMenu( menu.name );
72
+ onCreateFromMenu(
73
+ menu.id,
74
+ menu.name
75
+ );
77
76
  } }
78
77
  onClose={ onClose }
79
78
  key={ menu.id }
@@ -97,9 +96,6 @@ export default function NavigationPlaceholder( {
97
96
  hasResolvedNavigationMenus,
98
97
  canUserCreateNavigation = false,
99
98
  } ) {
100
- const [ selectedMenu, setSelectedMenu ] = useState();
101
- const [ isCreatingFromMenu, setIsCreatingFromMenu ] = useState( false );
102
- const [ menuName, setMenuName ] = useState( '' );
103
99
  const createNavigationMenu = useCreateNavigationMenu( clientId );
104
100
 
105
101
  const onFinishMenuCreation = async (
@@ -117,39 +113,18 @@ export default function NavigationPlaceholder( {
117
113
  onFinish( navigationMenu, blocks );
118
114
  };
119
115
 
116
+ const convertClassicMenu = useConvertClassicMenu( onFinishMenuCreation );
117
+
120
118
  const {
121
119
  isResolvingPages,
122
120
  menus,
123
121
  isResolvingMenus,
124
- menuItems,
125
- hasResolvedMenuItems,
126
122
  hasPages,
127
123
  hasMenus,
128
- } = useNavigationEntities( selectedMenu );
124
+ } = useNavigationEntities();
129
125
 
130
126
  const isStillLoading = isResolvingPages || isResolvingMenus;
131
127
 
132
- const createFromMenu = useCallback(
133
- ( name ) => {
134
- const { innerBlocks: blocks } = menuItemsToBlocks( menuItems );
135
- onFinishMenuCreation( blocks, name );
136
- },
137
- [ menuItems, menuItemsToBlocks, onFinish ]
138
- );
139
-
140
- const onCreateFromMenu = ( name ) => {
141
- // If we have menu items, create the block right away.
142
- if ( hasResolvedMenuItems ) {
143
- createFromMenu( name );
144
- return;
145
- }
146
-
147
- // Otherwise, create the block when resolution finishes.
148
- setIsCreatingFromMenu( true );
149
- // Store the name to use later.
150
- setMenuName( name );
151
- };
152
-
153
128
  const onCreateEmptyMenu = () => {
154
129
  onFinishMenuCreation( [] );
155
130
  };
@@ -159,15 +134,6 @@ export default function NavigationPlaceholder( {
159
134
  onFinishMenuCreation( block );
160
135
  };
161
136
 
162
- useEffect( () => {
163
- // If the user selected a menu but we had to wait for menu items to
164
- // finish resolving, then create the block once resolution finishes.
165
- if ( isCreatingFromMenu && hasResolvedMenuItems ) {
166
- createFromMenu( menuName );
167
- setIsCreatingFromMenu( false );
168
- }
169
- }, [ isCreatingFromMenu, hasResolvedMenuItems, menuName ] );
170
-
171
137
  const { navigationMenus } = useNavigationMenu();
172
138
 
173
139
  return (
@@ -194,10 +160,9 @@ export default function NavigationPlaceholder( {
194
160
  canSwitchNavigationMenu
195
161
  }
196
162
  navigationMenus={ navigationMenus }
197
- setSelectedMenu={ setSelectedMenu }
198
163
  onFinish={ onFinish }
199
164
  menus={ menus }
200
- onCreateFromMenu={ onCreateFromMenu }
165
+ onCreateFromMenu={ convertClassicMenu }
201
166
  showClassicMenus={
202
167
  canUserCreateNavigation
203
168
  }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useCallback, useState, useEffect } from '@wordpress/element';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import useNavigationEntities from './use-navigation-entities';
10
+ import menuItemsToBlocks from './menu-items-to-blocks';
11
+
12
+ export default function useConvertClassicMenu( onFinish ) {
13
+ const [ selectedMenu, setSelectedMenu ] = useState();
14
+ const [
15
+ isAwaitingMenuItemResolution,
16
+ setIsAwaitingMenuItemResolution,
17
+ ] = useState( false );
18
+ const [ menuName, setMenuName ] = useState( '' );
19
+
20
+ const { menuItems, hasResolvedMenuItems } = useNavigationEntities(
21
+ selectedMenu
22
+ );
23
+
24
+ const createFromMenu = useCallback(
25
+ ( name ) => {
26
+ const { innerBlocks: blocks } = menuItemsToBlocks( menuItems );
27
+ onFinish( blocks, name );
28
+ },
29
+ [ menuItems, menuItemsToBlocks, onFinish ]
30
+ );
31
+
32
+ useEffect( () => {
33
+ // If the user selected a menu but we had to wait for menu items to
34
+ // finish resolving, then create the block once resolution finishes.
35
+ if ( isAwaitingMenuItemResolution && hasResolvedMenuItems ) {
36
+ createFromMenu( menuName );
37
+ setIsAwaitingMenuItemResolution( false );
38
+ }
39
+ }, [ isAwaitingMenuItemResolution, hasResolvedMenuItems, menuName ] );
40
+
41
+ return useCallback(
42
+ ( id, name ) => {
43
+ setSelectedMenu( id );
44
+
45
+ // If we have menu items, create the block right away.
46
+ if ( hasResolvedMenuItems ) {
47
+ createFromMenu( name );
48
+ return;
49
+ }
50
+
51
+ // Otherwise, create the block when resolution finishes.
52
+ setIsAwaitingMenuItemResolution( true );
53
+ // Store the name to use later.
54
+ setMenuName( name );
55
+ },
56
+ [ hasResolvedMenuItems, createFromMenu ]
57
+ );
58
+ }
@@ -12,7 +12,12 @@ import {
12
12
  useBlockProps,
13
13
  getColorClassName,
14
14
  } from '@wordpress/block-editor';
15
- import { ToolbarButton, Placeholder, Spinner } from '@wordpress/components';
15
+ import {
16
+ ToolbarButton,
17
+ Placeholder,
18
+ Spinner,
19
+ Notice,
20
+ } from '@wordpress/components';
16
21
  import { __ } from '@wordpress/i18n';
17
22
  import { useMemo, useState, memo } from '@wordpress/element';
18
23
  import { useSelect } from '@wordpress/data';
@@ -29,7 +34,7 @@ import { ItemSubmenuIcon } from '../navigation-link/icons';
29
34
  const MAX_PAGE_COUNT = 100;
30
35
 
31
36
  export default function PageListEdit( { context, clientId } ) {
32
- const { pagesByParentId, totalPages } = usePagesByParentId();
37
+ const { pagesByParentId, totalPages, hasResolvedPages } = usePageData();
33
38
 
34
39
  const isNavigationChild = 'showSubmenuIcon' in context;
35
40
  const allowConvertToLinks =
@@ -70,16 +75,29 @@ export default function PageListEdit( { context, clientId } ) {
70
75
  clientId={ clientId }
71
76
  />
72
77
  ) }
73
- { totalPages === undefined && (
78
+ { ! hasResolvedPages && (
74
79
  <div { ...blockProps }>
75
80
  <Placeholder>
76
81
  <Spinner />
77
82
  </Placeholder>
78
83
  </div>
79
84
  ) }
85
+
86
+ { hasResolvedPages && totalPages === null && (
87
+ <div { ...blockProps }>
88
+ <div { ...blockProps }>
89
+ <Notice status={ 'warning' } isDismissible={ false }>
90
+ { __( 'Page List: Cannot retrieve Pages.' ) }
91
+ </Notice>
92
+ </div>
93
+ </div>
94
+ ) }
95
+
80
96
  { totalPages === 0 && (
81
97
  <div { ...blockProps }>
82
- <span>{ __( 'Page List: No pages to show.' ) }</span>
98
+ <Notice status={ 'info' } isDismissible={ false }>
99
+ { __( 'Page List: Cannot retrieve Pages.' ) }
100
+ </Notice>
83
101
  </div>
84
102
  ) }
85
103
  { totalPages > 0 && (
@@ -94,9 +112,16 @@ export default function PageListEdit( { context, clientId } ) {
94
112
  );
95
113
  }
96
114
 
97
- function usePagesByParentId() {
98
- const { pages } = useSelect( ( select ) => {
99
- const { getEntityRecords } = select( coreStore );
115
+ function useFrontPageId() {
116
+ return useSelect( ( select ) => {
117
+ const site = select( coreStore ).getEntityRecord( 'root', 'site' );
118
+ return site?.show_on_front === 'page' && site?.page_on_front;
119
+ }, [] );
120
+ }
121
+
122
+ function usePageData() {
123
+ const { pages, hasResolvedPages } = useSelect( ( select ) => {
124
+ const { getEntityRecords, hasFinishedResolution } = select( coreStore );
100
125
 
101
126
  return {
102
127
  pages: getEntityRecords( 'postType', 'page', {
@@ -105,6 +130,16 @@ function usePagesByParentId() {
105
130
  _fields: [ 'id', 'link', 'parent', 'title', 'menu_order' ],
106
131
  per_page: -1,
107
132
  } ),
133
+ hasResolvedPages: hasFinishedResolution( 'getEntityRecords', [
134
+ 'postType',
135
+ 'page',
136
+ {
137
+ orderby: 'menu_order',
138
+ order: 'asc',
139
+ _fields: [ 'id', 'link', 'parent', 'title', 'menu_order' ],
140
+ per_page: -1,
141
+ },
142
+ ] ),
108
143
  };
109
144
  }, [] );
110
145
 
@@ -125,9 +160,10 @@ function usePagesByParentId() {
125
160
 
126
161
  return {
127
162
  pagesByParentId,
128
- totalPages: pages?.length,
163
+ hasResolvedPages,
164
+ totalPages: pages?.length ?? null,
129
165
  };
130
- }, [ pages ] );
166
+ }, [ pages, hasResolvedPages ] );
131
167
  }
132
168
 
133
169
  const PageItems = memo( function PageItems( {
@@ -137,6 +173,7 @@ const PageItems = memo( function PageItems( {
137
173
  depth = 0,
138
174
  } ) {
139
175
  const pages = pagesByParentId.get( parentId );
176
+ const frontPageId = useFrontPageId();
140
177
 
141
178
  if ( ! pages?.length ) {
142
179
  return [];
@@ -155,6 +192,7 @@ const PageItems = memo( function PageItems( {
155
192
  'open-on-hover-click':
156
193
  ! context.openSubmenusOnClick &&
157
194
  context.showSubmenuIcon,
195
+ 'menu-item-home': page.id === frontPageId,
158
196
  } ) }
159
197
  >
160
198
  { hasChildren && context.openSubmenusOnClick ? (
@@ -64,3 +64,7 @@
64
64
  }
65
65
  }
66
66
  }
67
+
68
+ .wp-block-page-list .components-notice {
69
+ margin-left: 0;
70
+ }
@@ -173,6 +173,11 @@ function block_core_page_list_render_nested_page_list( $open_submenus_on_click,
173
173
  }
174
174
  }
175
175
 
176
+ $front_page_id = (int) get_option( 'page_on_front' );
177
+ if ( (int) $page['page_id'] === $front_page_id ) {
178
+ $css_class .= ' menu-item-home';
179
+ }
180
+
176
181
  $title = wp_kses( $page['title'], wp_kses_allowed_html( 'post' ) );
177
182
  $aria_label = sprintf(
178
183
  /* translators: Accessibility text. %s: Parent page title. */