@wordpress/block-library 6.0.15 → 6.0.16

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 (108) hide show
  1. package/build/group/edit.native.js +1 -1
  2. package/build/group/edit.native.js.map +1 -1
  3. package/build/group/index.js +3 -1
  4. package/build/group/index.js.map +1 -1
  5. package/build/navigation/deprecated.js +1 -3
  6. package/build/navigation/deprecated.js.map +1 -1
  7. package/build/navigation/edit/index.js +100 -44
  8. package/build/navigation/edit/index.js.map +1 -1
  9. package/build/navigation/edit/navigation-menu-selector.js +3 -2
  10. package/build/navigation/edit/navigation-menu-selector.js.map +1 -1
  11. package/build/navigation/edit/placeholder/index.js +15 -7
  12. package/build/navigation/edit/placeholder/index.js.map +1 -1
  13. package/build/navigation/edit/responsive-wrapper.js +9 -7
  14. package/build/navigation/edit/responsive-wrapper.js.map +1 -1
  15. package/build/navigation/edit/unsaved-inner-blocks.js +3 -11
  16. package/build/navigation/edit/unsaved-inner-blocks.js.map +1 -1
  17. package/build/navigation/edit/use-navigation-notice.js +54 -0
  18. package/build/navigation/edit/use-navigation-notice.js.map +1 -0
  19. package/build/navigation/index.js +1 -2
  20. package/build/navigation/index.js.map +1 -1
  21. package/build/navigation/use-navigation-menu.js +9 -2
  22. package/build/navigation/use-navigation-menu.js.map +1 -1
  23. package/build/navigation/view.js +12 -7
  24. package/build/navigation/view.js.map +1 -1
  25. package/build/post-template/edit.js +54 -13
  26. package/build/post-template/edit.js.map +1 -1
  27. package/build/site-logo/edit.js +9 -6
  28. package/build/site-logo/edit.js.map +1 -1
  29. package/build/site-logo/index.js +0 -3
  30. package/build/site-logo/index.js.map +1 -1
  31. package/build/template-part/edit/index.js +7 -1
  32. package/build/template-part/edit/index.js.map +1 -1
  33. package/build-module/group/edit.native.js +1 -1
  34. package/build-module/group/edit.native.js.map +1 -1
  35. package/build-module/group/index.js +3 -1
  36. package/build-module/group/index.js.map +1 -1
  37. package/build-module/navigation/deprecated.js +1 -3
  38. package/build-module/navigation/deprecated.js.map +1 -1
  39. package/build-module/navigation/edit/index.js +98 -44
  40. package/build-module/navigation/edit/index.js.map +1 -1
  41. package/build-module/navigation/edit/navigation-menu-selector.js +3 -2
  42. package/build-module/navigation/edit/navigation-menu-selector.js.map +1 -1
  43. package/build-module/navigation/edit/placeholder/index.js +15 -7
  44. package/build-module/navigation/edit/placeholder/index.js.map +1 -1
  45. package/build-module/navigation/edit/responsive-wrapper.js +9 -7
  46. package/build-module/navigation/edit/responsive-wrapper.js.map +1 -1
  47. package/build-module/navigation/edit/unsaved-inner-blocks.js +4 -13
  48. package/build-module/navigation/edit/unsaved-inner-blocks.js.map +1 -1
  49. package/build-module/navigation/edit/use-navigation-notice.js +44 -0
  50. package/build-module/navigation/edit/use-navigation-notice.js.map +1 -0
  51. package/build-module/navigation/index.js +1 -2
  52. package/build-module/navigation/index.js.map +1 -1
  53. package/build-module/navigation/use-navigation-menu.js +9 -2
  54. package/build-module/navigation/use-navigation-menu.js.map +1 -1
  55. package/build-module/navigation/view.js +12 -7
  56. package/build-module/navigation/view.js.map +1 -1
  57. package/build-module/post-template/edit.js +54 -15
  58. package/build-module/post-template/edit.js.map +1 -1
  59. package/build-module/site-logo/edit.js +9 -6
  60. package/build-module/site-logo/edit.js.map +1 -1
  61. package/build-module/site-logo/index.js +0 -3
  62. package/build-module/site-logo/index.js.map +1 -1
  63. package/build-module/template-part/edit/index.js +6 -1
  64. package/build-module/template-part/edit/index.js.map +1 -1
  65. package/build-style/common-rtl.css +10 -0
  66. package/build-style/common.css +10 -0
  67. package/build-style/editor-rtl.css +13 -11
  68. package/build-style/editor.css +13 -11
  69. package/build-style/navigation/editor-rtl.css +2 -0
  70. package/build-style/navigation/editor.css +2 -0
  71. package/build-style/navigation/style-rtl.css +55 -24
  72. package/build-style/navigation/style.css +55 -24
  73. package/build-style/site-logo/editor-rtl.css +1 -11
  74. package/build-style/site-logo/editor.css +1 -11
  75. package/build-style/site-logo/style-rtl.css +3 -1
  76. package/build-style/site-logo/style.css +3 -1
  77. package/build-style/style-rtl.css +68 -25
  78. package/build-style/style.css +68 -25
  79. package/package.json +14 -14
  80. package/src/common.scss +12 -0
  81. package/src/editor.scss +12 -0
  82. package/src/gallery/index.php +1 -1
  83. package/src/group/block.json +3 -1
  84. package/src/group/edit.native.js +1 -1
  85. package/src/home-link/index.php +1 -1
  86. package/src/navigation/block.json +1 -2
  87. package/src/navigation/deprecated.js +0 -2
  88. package/src/navigation/edit/index.js +153 -55
  89. package/src/navigation/edit/navigation-menu-selector.js +19 -13
  90. package/src/navigation/edit/placeholder/index.js +40 -24
  91. package/src/navigation/edit/responsive-wrapper.js +10 -7
  92. package/src/navigation/edit/unsaved-inner-blocks.js +13 -25
  93. package/src/navigation/edit/use-navigation-notice.js +37 -0
  94. package/src/navigation/editor.scss +2 -0
  95. package/src/navigation/index.php +19 -8
  96. package/src/navigation/style.scss +81 -32
  97. package/src/navigation/use-navigation-menu.js +20 -0
  98. package/src/navigation/view.js +13 -7
  99. package/src/navigation-link/index.php +1 -1
  100. package/src/navigation-submenu/index.php +1 -1
  101. package/src/page-list/index.php +1 -1
  102. package/src/post-template/edit.js +54 -17
  103. package/src/site-logo/block.json +0 -3
  104. package/src/site-logo/edit.js +6 -5
  105. package/src/site-logo/editor.scss +1 -15
  106. package/src/site-logo/index.php +0 -4
  107. package/src/site-logo/style.scss +3 -1
  108. package/src/template-part/edit/index.js +6 -1
@@ -2,7 +2,7 @@
2
2
  * External dependencies
3
3
  */
4
4
  import classnames from 'classnames';
5
- import noop from 'lodash';
5
+ import { noop } from 'lodash';
6
6
 
7
7
  /**
8
8
  * WordPress dependencies
@@ -27,7 +27,8 @@ import {
27
27
  Warning,
28
28
  } from '@wordpress/block-editor';
29
29
  import { EntityProvider, useEntityProp } from '@wordpress/core-data';
30
- import { useDispatch, useSelect } from '@wordpress/data';
30
+
31
+ import { useDispatch, useSelect, useRegistry } from '@wordpress/data';
31
32
  import {
32
33
  PanelBody,
33
34
  ToggleControl,
@@ -52,6 +53,9 @@ import NavigationMenuSelector from './navigation-menu-selector';
52
53
  import NavigationMenuNameControl from './navigation-menu-name-control';
53
54
  import UnsavedInnerBlocks from './unsaved-inner-blocks';
54
55
  import NavigationMenuDeleteControl from './navigation-menu-delete-control';
56
+ import useNavigationNotice from './use-navigation-notice';
57
+
58
+ const EMPTY_ARRAY = [];
55
59
 
56
60
  function getComputedStyle( node ) {
57
61
  return node.ownerDocument.defaultView.getComputedStyle( node );
@@ -107,7 +111,11 @@ function Navigation( {
107
111
  openSubmenusOnClick,
108
112
  overlayMenu,
109
113
  showSubmenuIcon,
110
- layout: { justifyContent, orientation = 'horizontal' } = {},
114
+ layout: {
115
+ justifyContent,
116
+ orientation = 'horizontal',
117
+ flexWrap = 'wrap',
118
+ } = {},
111
119
  } = attributes;
112
120
 
113
121
  let areaMenu,
@@ -128,6 +136,7 @@ function Navigation( {
128
136
 
129
137
  const ref = navigationArea ? navigationAreaMenu : attributes.ref;
130
138
 
139
+ const registry = useRegistry();
131
140
  const setRef = useCallback(
132
141
  ( postId ) => {
133
142
  setAttributes( { ref: postId } );
@@ -142,19 +151,41 @@ function Navigation( {
142
151
  `navigationMenu/${ ref }`
143
152
  );
144
153
 
145
- const { innerBlocks, isInnerBlockSelected } = useSelect(
154
+ const {
155
+ hasUncontrolledInnerBlocks,
156
+ uncontrolledInnerBlocks,
157
+ isInnerBlockSelected,
158
+ } = useSelect(
146
159
  ( select ) => {
147
- const { getBlocks, hasSelectedInnerBlock } = select(
160
+ const { getBlock, getBlocks, hasSelectedInnerBlock } = select(
148
161
  blockEditorStore
149
162
  );
163
+
164
+ // This relies on the fact that `getBlock` won't return controlled
165
+ // inner blocks, while `getBlocks` does. It might be more stable to
166
+ // introduce a selector like `getUncontrolledInnerBlocks`, just in
167
+ // case `getBlock` is fixed.
168
+ const _uncontrolledInnerBlocks = getBlock( clientId ).innerBlocks;
169
+ const _hasUncontrolledInnerBlocks =
170
+ _uncontrolledInnerBlocks?.length;
171
+ const _controlledInnerBlocks = _hasUncontrolledInnerBlocks
172
+ ? EMPTY_ARRAY
173
+ : getBlocks( clientId );
174
+ const innerBlocks = _hasUncontrolledInnerBlocks
175
+ ? _uncontrolledInnerBlocks
176
+ : _controlledInnerBlocks;
177
+
150
178
  return {
151
- innerBlocks: getBlocks( clientId ),
179
+ hasSubmenus: !! innerBlocks.find(
180
+ ( block ) => block.name === 'core/navigation-submenu'
181
+ ),
182
+ hasUncontrolledInnerBlocks: _hasUncontrolledInnerBlocks,
183
+ uncontrolledInnerBlocks: _uncontrolledInnerBlocks,
152
184
  isInnerBlockSelected: hasSelectedInnerBlock( clientId, true ),
153
185
  };
154
186
  },
155
187
  [ clientId ]
156
188
  );
157
- const hasExistingNavItems = !! innerBlocks.length;
158
189
  const {
159
190
  replaceInnerBlocks,
160
191
  selectBlock,
@@ -166,10 +197,10 @@ function Navigation( {
166
197
  setHasSavedUnsavedInnerBlocks,
167
198
  ] = useState( false );
168
199
 
169
- const isWithinUnassignedArea = navigationArea && ! ref;
200
+ const isWithinUnassignedArea = !! navigationArea && ! ref;
170
201
 
171
202
  const [ isPlaceholderShown, setIsPlaceholderShown ] = useState(
172
- ! hasExistingNavItems || isWithinUnassignedArea
203
+ ! hasUncontrolledInnerBlocks || isWithinUnassignedArea
173
204
  );
174
205
 
175
206
  const [ isResponsiveMenuOpen, setResponsiveMenuVisibility ] = useState(
@@ -183,6 +214,12 @@ function Navigation( {
183
214
  hasResolvedNavigationMenus,
184
215
  navigationMenus,
185
216
  navigationMenu,
217
+ canUserUpdateNavigationEntity,
218
+ hasResolvedCanUserUpdateNavigationEntity,
219
+ canUserDeleteNavigationEntity,
220
+ hasResolvedCanUserDeleteNavigationEntity,
221
+ canUserCreateNavigation,
222
+ hasResolvedCanUserCreateNavigation,
186
223
  } = useNavigationMenu( ref );
187
224
 
188
225
  const navRef = useRef();
@@ -200,6 +237,10 @@ function Navigation( {
200
237
  className: classnames( className, {
201
238
  'items-justified-right': justifyContent === 'right',
202
239
  'items-justified-space-between': justifyContent === 'space-between',
240
+ 'items-justified-left': justifyContent === 'left',
241
+ 'items-justified-center': justifyContent === 'center',
242
+ 'is-vertical': orientation === 'vertical',
243
+ 'no-wrap': flexWrap === 'nowrap',
203
244
  'is-responsive': 'never' !== overlayMenu,
204
245
  'has-text-color': !! textColor.color || !! textColor?.class,
205
246
  [ getColorClassName(
@@ -270,7 +311,7 @@ function Navigation( {
270
311
  setDetectedColor,
271
312
  setDetectedBackgroundColor
272
313
  );
273
- const subMenuElement = navRef.current.querySelector(
314
+ const subMenuElement = navRef.current?.querySelector(
274
315
  '[data-type="core/navigation-link"] [data-type="core/navigation-link"]'
275
316
  );
276
317
  if ( subMenuElement ) {
@@ -287,49 +328,105 @@ function Navigation( {
287
328
  setIsPlaceholderShown( ! isEntityAvailable );
288
329
  }, [ isEntityAvailable ] );
289
330
 
290
- // If the ref no longer exists the reset the inner blocks
291
- // to provide a clean slate.
331
+ const [ showCantEditNotice, hideCantEditNotice ] = useNavigationNotice( {
332
+ name: 'block-library/core/navigation/permissions/update',
333
+ message: __(
334
+ 'You do not have permission to edit this Menu. Any changes made will not be saved.'
335
+ ),
336
+ } );
337
+
338
+ const [ showCantCreateNotice, hideCantCreateNotice ] = useNavigationNotice(
339
+ {
340
+ name: 'block-library/core/navigation/permissions/create',
341
+ message: __(
342
+ 'You do not have permission to create Navigation Menus.'
343
+ ),
344
+ }
345
+ );
346
+
292
347
  useEffect( () => {
293
- if ( ref === undefined && innerBlocks.length > 0 ) {
294
- replaceInnerBlocks( clientId, [] );
348
+ if ( ! isSelected && ! isInnerBlockSelected ) {
349
+ hideCantEditNotice();
350
+ hideCantCreateNotice();
295
351
  }
296
- // innerBlocks are intentionally not listed as deps. This function is only concerned
297
- // with the snapshot from the time when ref became undefined.
298
- }, [ clientId, ref, innerBlocks ] );
299
352
 
300
- const startWithEmptyMenu = useCallback( () => {
301
- if ( navigationArea ) {
302
- setAreaMenu( 0 );
353
+ if ( isSelected || isInnerBlockSelected ) {
354
+ if (
355
+ hasResolvedCanUserUpdateNavigationEntity &&
356
+ ! canUserUpdateNavigationEntity
357
+ ) {
358
+ showCantEditNotice();
359
+ }
360
+
361
+ if (
362
+ ! ref &&
363
+ hasResolvedCanUserCreateNavigation &&
364
+ ! canUserCreateNavigation
365
+ ) {
366
+ showCantCreateNotice();
367
+ }
303
368
  }
304
- setAttributes( {
305
- ref: undefined,
306
- } );
369
+ }, [
370
+ isSelected,
371
+ isInnerBlockSelected,
372
+ canUserUpdateNavigationEntity,
373
+ hasResolvedCanUserUpdateNavigationEntity,
374
+ canUserCreateNavigation,
375
+ hasResolvedCanUserCreateNavigation,
376
+ ref,
377
+ ] );
307
378
 
308
- setIsPlaceholderShown( true );
309
- }, [ clientId ] );
379
+ const startWithEmptyMenu = useCallback( () => {
380
+ registry.batch( () => {
381
+ if ( navigationArea ) {
382
+ setAreaMenu( 0 );
383
+ }
384
+ setAttributes( {
385
+ ref: undefined,
386
+ } );
387
+ if ( ! ref ) {
388
+ replaceInnerBlocks( clientId, [] );
389
+ }
390
+ setIsPlaceholderShown( true );
391
+ } );
392
+ }, [ clientId, ref ] );
310
393
 
311
394
  // If the block has inner blocks, but no menu id, this was an older
312
395
  // navigation block added before the block used a wp_navigation entity.
313
396
  // Either this block was saved in the content or inserted by a pattern.
314
397
  // Consider this 'unsaved'. Offer an uncontrolled version of inner blocks,
315
398
  // that automatically saves the menu.
316
- const hasUnsavedBlocks =
317
- hasExistingNavItems && ! isEntityAvailable && ! isWithinUnassignedArea;
399
+ const hasUnsavedBlocks = hasUncontrolledInnerBlocks && ! isEntityAvailable;
318
400
  if ( hasUnsavedBlocks ) {
319
401
  return (
320
- <UnsavedInnerBlocks
321
- blockProps={ blockProps }
322
- blocks={ innerBlocks }
323
- clientId={ clientId }
324
- navigationMenus={ navigationMenus }
325
- hasSelection={ isSelected || isInnerBlockSelected }
326
- hasSavedUnsavedInnerBlocks={ hasSavedUnsavedInnerBlocks }
327
- onSave={ ( post ) => {
328
- setHasSavedUnsavedInnerBlocks( true );
329
- // Switch to using the wp_navigation entity.
330
- setRef( post.id );
331
- } }
332
- />
402
+ <nav { ...blockProps }>
403
+ <ResponsiveWrapper
404
+ id={ clientId }
405
+ onToggle={ setResponsiveMenuVisibility }
406
+ isOpen={ isResponsiveMenuOpen }
407
+ isResponsive={ 'never' !== overlayMenu }
408
+ isHiddenByDefault={ 'always' === overlayMenu }
409
+ classNames={ overlayClassnames }
410
+ styles={ overlayStyles }
411
+ >
412
+ <UnsavedInnerBlocks
413
+ blockProps={ blockProps }
414
+ blocks={ uncontrolledInnerBlocks }
415
+ clientId={ clientId }
416
+ navigationMenus={ navigationMenus }
417
+ hasSelection={ isSelected || isInnerBlockSelected }
418
+ hasSavedUnsavedInnerBlocks={
419
+ hasSavedUnsavedInnerBlocks
420
+ }
421
+ onSave={ ( post ) => {
422
+ // Set some state used as a guard to prevent the creation of multiple posts.
423
+ setHasSavedUnsavedInnerBlocks( true );
424
+ // Switch to using the wp_navigation entity.
425
+ setRef( post.id );
426
+ } }
427
+ />
428
+ </ResponsiveWrapper>
429
+ </nav>
333
430
  );
334
431
  }
335
432
 
@@ -382,6 +479,7 @@ function Navigation( {
382
479
  onClose();
383
480
  } }
384
481
  onCreateNew={ startWithEmptyMenu }
482
+ showCreate={ canUserCreateNavigation }
385
483
  />
386
484
  ) }
387
485
  </ToolbarDropdownMenu>
@@ -492,18 +590,16 @@ function Navigation( {
492
590
  </InspectorControls>
493
591
  { isEntityAvailable && (
494
592
  <InspectorControls __experimentalGroup="advanced">
495
- <NavigationMenuNameControl />
496
- <NavigationMenuDeleteControl
497
- onDelete={ () => {
498
- if ( navigationArea ) {
499
- setAreaMenu( 0 );
500
- }
501
- setAttributes( {
502
- ref: undefined,
503
- } );
504
- setIsPlaceholderShown( true );
505
- } }
506
- />
593
+ { hasResolvedCanUserUpdateNavigationEntity &&
594
+ canUserUpdateNavigationEntity && (
595
+ <NavigationMenuNameControl />
596
+ ) }
597
+ { hasResolvedCanUserDeleteNavigationEntity &&
598
+ canUserDeleteNavigationEntity && (
599
+ <NavigationMenuDeleteControl
600
+ onDelete={ startWithEmptyMenu }
601
+ />
602
+ ) }
507
603
  </InspectorControls>
508
604
  ) }
509
605
  <nav { ...blockProps }>
@@ -521,11 +617,13 @@ function Navigation( {
521
617
  hasResolvedNavigationMenus
522
618
  }
523
619
  clientId={ clientId }
620
+ canUserCreateNavigation={ canUserCreateNavigation }
524
621
  />
525
622
  ) }
526
- { ! isEntityAvailable && ! isPlaceholderShown && (
527
- <PlaceholderPreview isLoading />
528
- ) }
623
+ { ! hasResolvedCanUserCreateNavigation ||
624
+ ( ! isEntityAvailable && ! isPlaceholderShown && (
625
+ <PlaceholderPreview isLoading />
626
+ ) ) }
529
627
  { ! isPlaceholderShown && (
530
628
  <ResponsiveWrapper
531
629
  id={ clientId }
@@ -12,7 +12,11 @@ import { addQueryArgs } from '@wordpress/url';
12
12
  */
13
13
  import useNavigationMenu from '../use-navigation-menu';
14
14
 
15
- export default function NavigationMenuSelector( { onSelect, onCreateNew } ) {
15
+ export default function NavigationMenuSelector( {
16
+ onSelect,
17
+ onCreateNew,
18
+ showCreate = false,
19
+ } ) {
16
20
  const { navigationMenus } = useNavigationMenu();
17
21
  const ref = useEntityId( 'postType', 'wp_navigation' );
18
22
 
@@ -42,18 +46,20 @@ export default function NavigationMenuSelector( { onSelect, onCreateNew } ) {
42
46
  } ) }
43
47
  />
44
48
  </MenuGroup>
45
- <MenuGroup>
46
- <MenuItem onClick={ onCreateNew }>
47
- { __( 'Create new menu' ) }
48
- </MenuItem>
49
- <MenuItem
50
- href={ addQueryArgs( 'edit.php', {
51
- post_type: 'wp_navigation',
52
- } ) }
53
- >
54
- { __( 'Manage menus' ) }
55
- </MenuItem>
56
- </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>
62
+ ) }
57
63
  </>
58
64
  );
59
65
  }
@@ -31,6 +31,7 @@ const ExistingMenusDropdown = ( {
31
31
  onFinish,
32
32
  menus,
33
33
  onCreateFromMenu,
34
+ showClassicMenus = false,
34
35
  } ) => {
35
36
  const toggleProps = {
36
37
  variant: 'tertiary',
@@ -65,22 +66,24 @@ const ExistingMenusDropdown = ( {
65
66
  );
66
67
  } ) }
67
68
  </MenuGroup>
68
- <MenuGroup label={ __( 'Classic Menus' ) }>
69
- { menus?.map( ( menu ) => {
70
- return (
71
- <MenuItem
72
- onClick={ () => {
73
- setSelectedMenu( menu.id );
74
- onCreateFromMenu( menu.name );
75
- } }
76
- onClose={ onClose }
77
- key={ menu.id }
78
- >
79
- { decodeEntities( menu.name ) }
80
- </MenuItem>
81
- );
82
- } ) }
83
- </MenuGroup>
69
+ { showClassicMenus && (
70
+ <MenuGroup label={ __( 'Classic Menus' ) }>
71
+ { menus?.map( ( menu ) => {
72
+ return (
73
+ <MenuItem
74
+ onClick={ () => {
75
+ setSelectedMenu( menu.id );
76
+ onCreateFromMenu( menu.name );
77
+ } }
78
+ onClose={ onClose }
79
+ key={ menu.id }
80
+ >
81
+ { decodeEntities( menu.name ) }
82
+ </MenuItem>
83
+ );
84
+ } ) }
85
+ </MenuGroup>
86
+ ) }
84
87
  </>
85
88
  ) }
86
89
  </DropdownMenu>
@@ -92,6 +95,7 @@ export default function NavigationPlaceholder( {
92
95
  onFinish,
93
96
  canSwitchNavigationMenu,
94
97
  hasResolvedNavigationMenus,
98
+ canUserCreateNavigation = false,
95
99
  } ) {
96
100
  const [ selectedMenu, setSelectedMenu ] = useState();
97
101
  const [ isCreatingFromMenu, setIsCreatingFromMenu ] = useState( false );
@@ -102,6 +106,10 @@ export default function NavigationPlaceholder( {
102
106
  blocks,
103
107
  navigationMenuTitle = null
104
108
  ) => {
109
+ if ( ! canUserCreateNavigation ) {
110
+ return;
111
+ }
112
+
105
113
  const navigationMenu = await createNavigationMenu(
106
114
  navigationMenuTitle,
107
115
  blocks
@@ -176,8 +184,10 @@ export default function NavigationPlaceholder( {
176
184
  <Icon icon={ navigation } />{ ' ' }
177
185
  { __( 'Navigation' ) }
178
186
  </div>
187
+
179
188
  <hr />
180
- { hasMenus || navigationMenus.length ? (
189
+
190
+ { hasMenus || navigationMenus?.length ? (
181
191
  <>
182
192
  <ExistingMenusDropdown
183
193
  canSwitchNavigationMenu={
@@ -188,11 +198,14 @@ export default function NavigationPlaceholder( {
188
198
  onFinish={ onFinish }
189
199
  menus={ menus }
190
200
  onCreateFromMenu={ onCreateFromMenu }
201
+ showClassicMenus={
202
+ canUserCreateNavigation
203
+ }
191
204
  />
192
205
  <hr />
193
206
  </>
194
207
  ) : undefined }
195
- { hasPages ? (
208
+ { canUserCreateNavigation && hasPages ? (
196
209
  <>
197
210
  <Button
198
211
  variant="tertiary"
@@ -203,12 +216,15 @@ export default function NavigationPlaceholder( {
203
216
  <hr />
204
217
  </>
205
218
  ) : undefined }
206
- <Button
207
- variant="tertiary"
208
- onClick={ onCreateEmptyMenu }
209
- >
210
- { __( 'Start empty' ) }
211
- </Button>
219
+
220
+ { canUserCreateNavigation && (
221
+ <Button
222
+ variant="tertiary"
223
+ onClick={ onCreateEmptyMenu }
224
+ >
225
+ { __( 'Start empty' ) }
226
+ </Button>
227
+ ) }
212
228
  </div>
213
229
  </div>
214
230
  </Placeholder>
@@ -39,12 +39,20 @@ export default function ResponsiveWrapper( {
39
39
 
40
40
  const modalId = `${ id }-modal`;
41
41
 
42
+ const dialogProps = {
43
+ className: 'wp-block-navigation__responsive-dialog',
44
+ ...( isOpen && {
45
+ role: 'dialog',
46
+ 'aria-modal': true,
47
+ 'aria-label': __( 'Menu' ),
48
+ } ),
49
+ };
50
+
42
51
  return (
43
52
  <>
44
53
  { ! isOpen && (
45
54
  <Button
46
55
  aria-haspopup="true"
47
- aria-expanded={ isOpen }
48
56
  aria-label={ __( 'Open menu' ) }
49
57
  className={ openButtonClasses }
50
58
  onClick={ () => onToggle( true ) }
@@ -73,12 +81,7 @@ export default function ResponsiveWrapper( {
73
81
  className="wp-block-navigation__responsive-close"
74
82
  tabIndex="-1"
75
83
  >
76
- <div
77
- className="wp-block-navigation__responsive-dialog"
78
- role="dialog"
79
- aria-modal="true"
80
- aria-labelledby={ `${ modalId }-title` }
81
- >
84
+ <div { ...dialogProps }>
82
85
  <Button
83
86
  className="wp-block-navigation__responsive-container-close"
84
87
  aria-label={ __( 'Close menu' ) }
@@ -18,7 +18,6 @@ import { useContext, useEffect, useRef } from '@wordpress/element';
18
18
  import useNavigationMenu from '../use-navigation-menu';
19
19
  import useCreateNavigationMenu from './use-create-navigation-menu';
20
20
 
21
- const NOOP = () => {};
22
21
  const EMPTY_OBJECT = {};
23
22
  const DRAFT_MENU_PARAMS = [
24
23
  'postType',
@@ -41,13 +40,6 @@ export default function UnsavedInnerBlocks( {
41
40
 
42
41
  const innerBlocksProps = useInnerBlocksProps( blockProps, {
43
42
  renderAppender: hasSelection ? undefined : false,
44
-
45
- // Make the inner blocks 'controlled'. This allows the block to always
46
- // work with controlled inner blocks, smoothing out the switch to using
47
- // an entity.
48
- value: blocks,
49
- onChange: NOOP,
50
- onInput: NOOP,
51
43
  } );
52
44
 
53
45
  const {
@@ -125,22 +117,18 @@ export default function UnsavedInnerBlocks( {
125
117
  ] );
126
118
 
127
119
  return (
128
- <>
129
- <nav { ...blockProps }>
130
- <div className="wp-block-navigation__unsaved-changes">
131
- <Disabled
132
- className={ classnames(
133
- 'wp-block-navigation__unsaved-changes-overlay',
134
- {
135
- 'is-saving': hasSelection,
136
- }
137
- ) }
138
- >
139
- <div { ...innerBlocksProps } />
140
- </Disabled>
141
- { hasSelection && <Spinner /> }
142
- </div>
143
- </nav>
144
- </>
120
+ <div className="wp-block-navigation__unsaved-changes">
121
+ <Disabled
122
+ className={ classnames(
123
+ 'wp-block-navigation__unsaved-changes-overlay',
124
+ {
125
+ 'is-saving': hasSelection,
126
+ }
127
+ ) }
128
+ >
129
+ <div { ...innerBlocksProps } />
130
+ </Disabled>
131
+ { hasSelection && <Spinner /> }
132
+ </div>
145
133
  );
146
134
  }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useRef } from '@wordpress/element';
5
+ import { useDispatch } from '@wordpress/data';
6
+ import { store as noticeStore } from '@wordpress/notices';
7
+
8
+ function useNavigationNotice( { name, message } = {} ) {
9
+ const noticeRef = useRef();
10
+
11
+ const { createWarningNotice, removeNotice } = useDispatch( noticeStore );
12
+
13
+ const showNotice = () => {
14
+ if ( noticeRef.current ) {
15
+ return;
16
+ }
17
+
18
+ noticeRef.current = name;
19
+
20
+ createWarningNotice( message, {
21
+ id: noticeRef.current,
22
+ type: 'snackbar',
23
+ } );
24
+ };
25
+
26
+ const hideNotice = () => {
27
+ if ( ! noticeRef.current ) {
28
+ return;
29
+ }
30
+ removeNotice( noticeRef.current );
31
+ noticeRef.current = null;
32
+ };
33
+
34
+ return [ showNotice, hideNotice ];
35
+ }
36
+
37
+ export default useNavigationNotice;
@@ -100,6 +100,7 @@
100
100
  .is-editing > .wp-block-navigation__submenu-container > .block-list-appender {
101
101
  display: block;
102
102
  position: static;
103
+ width: 100%;
103
104
  }
104
105
 
105
106
  // Hide when hovering.
@@ -371,6 +372,7 @@ $color-control-label-height: 20px;
371
372
  font-size: $default-font-size;
372
373
  font-family: $default-font;
373
374
  gap: $grid-unit-15 * 0.5;
375
+ align-items: center;
374
376
 
375
377
  // Margins.
376
378
  .components-dropdown,