@wordpress/edit-site 4.2.0 → 4.3.2
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.
- package/CHANGELOG.md +2 -0
- package/build/components/block-editor/index.js +53 -4
- package/build/components/block-editor/index.js.map +1 -1
- package/build/components/editor/index.js +9 -5
- package/build/components/editor/index.js.map +1 -1
- package/build/components/global-styles/color-indicator-wrapper.js +37 -0
- package/build/components/global-styles/color-indicator-wrapper.js.map +1 -0
- package/build/components/global-styles/dimensions-panel.js +32 -1
- package/build/components/global-styles/dimensions-panel.js.map +1 -1
- package/build/components/global-styles/header.js +1 -4
- package/build/components/global-styles/header.js.map +1 -1
- package/build/components/global-styles/icon-with-current-color.js +34 -0
- package/build/components/global-styles/icon-with-current-color.js.map +1 -0
- package/build/components/global-styles/navigation-button.js +7 -3
- package/build/components/global-styles/navigation-button.js.map +1 -1
- package/build/components/global-styles/palette.js +8 -5
- package/build/components/global-styles/palette.js.map +1 -1
- package/build/components/global-styles/preview.js +142 -26
- package/build/components/global-styles/preview.js.map +1 -1
- package/build/components/global-styles/screen-block-list.js +50 -6
- package/build/components/global-styles/screen-block-list.js.map +1 -1
- package/build/components/global-styles/screen-colors.js +11 -3
- package/build/components/global-styles/screen-colors.js.map +1 -1
- package/build/components/global-styles/screen-root.js +7 -5
- package/build/components/global-styles/screen-root.js.map +1 -1
- package/build/components/global-styles/screen-style-variations.js +12 -5
- package/build/components/global-styles/screen-style-variations.js.map +1 -1
- package/build/components/sidebar/index.js +12 -1
- package/build/components/sidebar/index.js.map +1 -1
- package/build/components/sidebar/navigation-menu-sidebar/index.js +40 -0
- package/build/components/sidebar/navigation-menu-sidebar/index.js.map +1 -0
- package/build/components/sidebar/navigation-menu-sidebar/navigation-inspector.js +185 -0
- package/build/components/sidebar/navigation-menu-sidebar/navigation-inspector.js.map +1 -0
- package/build/components/sidebar/navigation-menu-sidebar/navigation-menu.js +54 -0
- package/build/components/sidebar/navigation-menu-sidebar/navigation-menu.js.map +1 -0
- package/build/components/template-part-converter/convert-to-regular.js +6 -0
- package/build/components/template-part-converter/convert-to-regular.js.map +1 -1
- package/build-module/components/block-editor/index.js +51 -6
- package/build-module/components/block-editor/index.js.map +1 -1
- package/build-module/components/editor/index.js +10 -6
- package/build-module/components/editor/index.js.map +1 -1
- package/build-module/components/global-styles/color-indicator-wrapper.js +25 -0
- package/build-module/components/global-styles/color-indicator-wrapper.js.map +1 -0
- package/build-module/components/global-styles/dimensions-panel.js +33 -2
- package/build-module/components/global-styles/dimensions-panel.js.map +1 -1
- package/build-module/components/global-styles/header.js +2 -5
- package/build-module/components/global-styles/header.js.map +1 -1
- package/build-module/components/global-styles/icon-with-current-color.js +22 -0
- package/build-module/components/global-styles/icon-with-current-color.js.map +1 -0
- package/build-module/components/global-styles/navigation-button.js +7 -3
- package/build-module/components/global-styles/navigation-button.js.map +1 -1
- package/build-module/components/global-styles/palette.js +8 -6
- package/build-module/components/global-styles/palette.js.map +1 -1
- package/build-module/components/global-styles/preview.js +141 -27
- package/build-module/components/global-styles/preview.js.map +1 -1
- package/build-module/components/global-styles/screen-block-list.js +49 -6
- package/build-module/components/global-styles/screen-block-list.js.map +1 -1
- package/build-module/components/global-styles/screen-colors.js +10 -3
- package/build-module/components/global-styles/screen-colors.js.map +1 -1
- package/build-module/components/global-styles/screen-root.js +8 -7
- package/build-module/components/global-styles/screen-root.js.map +1 -1
- package/build-module/components/global-styles/screen-style-variations.js +13 -6
- package/build-module/components/global-styles/screen-style-variations.js.map +1 -1
- package/build-module/components/sidebar/index.js +11 -1
- package/build-module/components/sidebar/index.js.map +1 -1
- package/build-module/components/sidebar/navigation-menu-sidebar/index.js +26 -0
- package/build-module/components/sidebar/navigation-menu-sidebar/index.js.map +1 -0
- package/build-module/components/sidebar/navigation-menu-sidebar/navigation-inspector.js +168 -0
- package/build-module/components/sidebar/navigation-menu-sidebar/navigation-inspector.js.map +1 -0
- package/build-module/components/sidebar/navigation-menu-sidebar/navigation-menu.js +45 -0
- package/build-module/components/sidebar/navigation-menu-sidebar/navigation-menu.js.map +1 -0
- package/build-module/components/template-part-converter/convert-to-regular.js +6 -0
- package/build-module/components/template-part-converter/convert-to-regular.js.map +1 -1
- package/build-style/style-rtl.css +53 -5
- package/build-style/style.css +53 -5
- package/package.json +29 -29
- package/src/components/block-editor/index.js +79 -9
- package/src/components/editor/index.js +16 -5
- package/src/components/global-styles/color-indicator-wrapper.js +23 -0
- package/src/components/global-styles/dimensions-panel.js +39 -1
- package/src/components/global-styles/header.js +2 -7
- package/src/components/global-styles/icon-with-current-color.js +21 -0
- package/src/components/global-styles/navigation-button.js +6 -4
- package/src/components/global-styles/palette.js +8 -11
- package/src/components/global-styles/preview.js +186 -29
- package/src/components/global-styles/screen-block-list.js +64 -11
- package/src/components/global-styles/screen-colors.js +7 -6
- package/src/components/global-styles/screen-root.js +15 -17
- package/src/components/global-styles/screen-style-variations.js +13 -4
- package/src/components/global-styles/style.scss +20 -7
- package/src/components/sidebar/index.js +12 -0
- package/src/components/sidebar/navigation-menu-sidebar/index.js +34 -0
- package/src/components/sidebar/navigation-menu-sidebar/navigation-inspector.js +224 -0
- package/src/components/sidebar/navigation-menu-sidebar/navigation-menu.js +62 -0
- package/src/components/sidebar/navigation-menu-sidebar/style.scss +42 -0
- package/src/components/sidebar/style.scss +1 -1
- package/src/components/template-part-converter/convert-to-regular.js +9 -0
- package/src/style.scss +1 -0
|
@@ -2,13 +2,17 @@
|
|
|
2
2
|
* WordPress dependencies
|
|
3
3
|
*/
|
|
4
4
|
import { store as blocksStore } from '@wordpress/blocks';
|
|
5
|
-
import {
|
|
6
|
-
import { __ } from '@wordpress/i18n';
|
|
5
|
+
import { __, sprintf, _n } from '@wordpress/i18n';
|
|
7
6
|
import {
|
|
8
7
|
FlexItem,
|
|
8
|
+
SearchControl,
|
|
9
9
|
__experimentalHStack as HStack,
|
|
10
10
|
} from '@wordpress/components';
|
|
11
|
+
import { useSelect } from '@wordpress/data';
|
|
12
|
+
import { useState, useMemo, useEffect, useRef } from '@wordpress/element';
|
|
11
13
|
import { BlockIcon } from '@wordpress/block-editor';
|
|
14
|
+
import { useDebounce } from '@wordpress/compose';
|
|
15
|
+
import { speak } from '@wordpress/a11y';
|
|
12
16
|
|
|
13
17
|
/**
|
|
14
18
|
* Internal dependencies
|
|
@@ -59,9 +63,7 @@ function BlockMenuItem( { block } ) {
|
|
|
59
63
|
return (
|
|
60
64
|
<NavigationButton path={ '/blocks/' + block.name }>
|
|
61
65
|
<HStack justify="flex-start">
|
|
62
|
-
<
|
|
63
|
-
<BlockIcon icon={ block.icon } />
|
|
64
|
-
</FlexItem>
|
|
66
|
+
<BlockIcon icon={ block.icon } />
|
|
65
67
|
<FlexItem>{ block.title }</FlexItem>
|
|
66
68
|
</HStack>
|
|
67
69
|
</NavigationButton>
|
|
@@ -70,6 +72,45 @@ function BlockMenuItem( { block } ) {
|
|
|
70
72
|
|
|
71
73
|
function ScreenBlockList() {
|
|
72
74
|
const sortedBlockTypes = useSortedBlockTypes();
|
|
75
|
+
const [ filterValue, setFilterValue ] = useState( '' );
|
|
76
|
+
const debouncedSpeak = useDebounce( speak, 500 );
|
|
77
|
+
const isMatchingSearchTerm = useSelect(
|
|
78
|
+
( select ) => select( blocksStore ).isMatchingSearchTerm,
|
|
79
|
+
[]
|
|
80
|
+
);
|
|
81
|
+
const filteredBlockTypes = useMemo( () => {
|
|
82
|
+
if ( ! filterValue ) {
|
|
83
|
+
return sortedBlockTypes;
|
|
84
|
+
}
|
|
85
|
+
return sortedBlockTypes.filter( ( blockType ) =>
|
|
86
|
+
isMatchingSearchTerm( blockType, filterValue )
|
|
87
|
+
);
|
|
88
|
+
}, [ filterValue, sortedBlockTypes, isMatchingSearchTerm ] );
|
|
89
|
+
|
|
90
|
+
const blockTypesListRef = useRef();
|
|
91
|
+
|
|
92
|
+
// Announce search results on change
|
|
93
|
+
useEffect( () => {
|
|
94
|
+
if ( ! filterValue ) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
// We extract the results from the wrapper div's `ref` because
|
|
98
|
+
// filtered items can contain items that will eventually not
|
|
99
|
+
// render and there is no reliable way to detect when a child
|
|
100
|
+
// will return `null`.
|
|
101
|
+
// TODO: We should find a better way of handling this as it's
|
|
102
|
+
// fragile and depends on the number of rendered elements of `BlockMenuItem`,
|
|
103
|
+
// which is now one.
|
|
104
|
+
// @see https://github.com/WordPress/gutenberg/pull/39117#discussion_r816022116
|
|
105
|
+
const count = blockTypesListRef.current.childElementCount;
|
|
106
|
+
const resultsFoundMessage = sprintf(
|
|
107
|
+
/* translators: %d: number of results. */
|
|
108
|
+
_n( '%d result found.', '%d results found.', count ),
|
|
109
|
+
count
|
|
110
|
+
);
|
|
111
|
+
debouncedSpeak( resultsFoundMessage, count );
|
|
112
|
+
}, [ filterValue, debouncedSpeak ] );
|
|
113
|
+
|
|
73
114
|
return (
|
|
74
115
|
<>
|
|
75
116
|
<ScreenHeader
|
|
@@ -78,12 +119,24 @@ function ScreenBlockList() {
|
|
|
78
119
|
'Customize the appearance of specific blocks and for the whole site.'
|
|
79
120
|
) }
|
|
80
121
|
/>
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
122
|
+
<SearchControl
|
|
123
|
+
className="edit-site-block-types-search"
|
|
124
|
+
onChange={ setFilterValue }
|
|
125
|
+
value={ filterValue }
|
|
126
|
+
label={ __( 'Search for blocks' ) }
|
|
127
|
+
placeholder={ __( 'Search' ) }
|
|
128
|
+
/>
|
|
129
|
+
<div
|
|
130
|
+
ref={ blockTypesListRef }
|
|
131
|
+
className="edit-site-block-types-item-list"
|
|
132
|
+
>
|
|
133
|
+
{ filteredBlockTypes.map( ( block ) => (
|
|
134
|
+
<BlockMenuItem
|
|
135
|
+
block={ block }
|
|
136
|
+
key={ 'menu-itemblock-' + block.name }
|
|
137
|
+
/>
|
|
138
|
+
) ) }
|
|
139
|
+
</div>
|
|
87
140
|
</>
|
|
88
141
|
);
|
|
89
142
|
}
|
|
@@ -18,6 +18,7 @@ import Palette from './palette';
|
|
|
18
18
|
import { NavigationButton } from './navigation-button';
|
|
19
19
|
import { getSupportedGlobalStylesPanels, useStyle } from './hooks';
|
|
20
20
|
import Subtitle from './subtitle';
|
|
21
|
+
import ColorIndicatorWrapper from './color-indicator-wrapper';
|
|
21
22
|
|
|
22
23
|
function BackgroundColorItem( { name, parentMenu } ) {
|
|
23
24
|
const supports = getSupportedGlobalStylesPanels( name );
|
|
@@ -34,11 +35,11 @@ function BackgroundColorItem( { name, parentMenu } ) {
|
|
|
34
35
|
return (
|
|
35
36
|
<NavigationButton path={ parentMenu + '/colors/background' }>
|
|
36
37
|
<HStack justify="flex-start">
|
|
37
|
-
<
|
|
38
|
+
<ColorIndicatorWrapper expanded={ false }>
|
|
38
39
|
<ColorIndicator
|
|
39
40
|
colorValue={ gradientValue ?? backgroundColor }
|
|
40
41
|
/>
|
|
41
|
-
</
|
|
42
|
+
</ColorIndicatorWrapper>
|
|
42
43
|
<FlexItem>{ __( 'Background' ) }</FlexItem>
|
|
43
44
|
</HStack>
|
|
44
45
|
</NavigationButton>
|
|
@@ -57,9 +58,9 @@ function TextColorItem( { name, parentMenu } ) {
|
|
|
57
58
|
return (
|
|
58
59
|
<NavigationButton path={ parentMenu + '/colors/text' }>
|
|
59
60
|
<HStack justify="flex-start">
|
|
60
|
-
<
|
|
61
|
+
<ColorIndicatorWrapper expanded={ false }>
|
|
61
62
|
<ColorIndicator colorValue={ color } />
|
|
62
|
-
</
|
|
63
|
+
</ColorIndicatorWrapper>
|
|
63
64
|
<FlexItem>{ __( 'Text' ) }</FlexItem>
|
|
64
65
|
</HStack>
|
|
65
66
|
</NavigationButton>
|
|
@@ -78,9 +79,9 @@ function LinkColorItem( { name, parentMenu } ) {
|
|
|
78
79
|
return (
|
|
79
80
|
<NavigationButton path={ parentMenu + '/colors/link' }>
|
|
80
81
|
<HStack justify="flex-start">
|
|
81
|
-
<
|
|
82
|
+
<ColorIndicatorWrapper expanded={ false }>
|
|
82
83
|
<ColorIndicator colorValue={ color } />
|
|
83
|
-
</
|
|
84
|
+
</ColorIndicatorWrapper>
|
|
84
85
|
<FlexItem>{ __( 'Links' ) }</FlexItem>
|
|
85
86
|
</HStack>
|
|
86
87
|
</NavigationButton>
|
|
@@ -10,15 +10,17 @@ import {
|
|
|
10
10
|
CardBody,
|
|
11
11
|
Card,
|
|
12
12
|
CardDivider,
|
|
13
|
+
CardMedia,
|
|
13
14
|
} from '@wordpress/components';
|
|
14
15
|
import { isRTL, __ } from '@wordpress/i18n';
|
|
15
|
-
import { chevronLeft, chevronRight
|
|
16
|
+
import { chevronLeft, chevronRight } from '@wordpress/icons';
|
|
16
17
|
import { useSelect } from '@wordpress/data';
|
|
17
18
|
import { store as coreStore } from '@wordpress/core-data';
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* Internal dependencies
|
|
21
22
|
*/
|
|
23
|
+
import { IconWithCurrentColor } from './icon-with-current-color';
|
|
22
24
|
import { NavigationButton } from './navigation-button';
|
|
23
25
|
import ContextMenu from './context-menu';
|
|
24
26
|
import StylesPreview from './preview';
|
|
@@ -37,19 +39,19 @@ function ScreenRoot() {
|
|
|
37
39
|
<CardBody>
|
|
38
40
|
<VStack spacing={ 2 }>
|
|
39
41
|
<Card>
|
|
40
|
-
<
|
|
42
|
+
<CardMedia>
|
|
43
|
+
<StylesPreview />
|
|
44
|
+
</CardMedia>
|
|
41
45
|
</Card>
|
|
42
46
|
{ !! variations?.length && (
|
|
43
47
|
<NavigationButton path="/variations">
|
|
44
48
|
<HStack justify="space-between">
|
|
45
|
-
<FlexItem>{ __( '
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
/>
|
|
52
|
-
</FlexItem>
|
|
49
|
+
<FlexItem>{ __( 'Browse styles' ) }</FlexItem>
|
|
50
|
+
<IconWithCurrentColor
|
|
51
|
+
icon={
|
|
52
|
+
isRTL() ? chevronLeft : chevronRight
|
|
53
|
+
}
|
|
54
|
+
/>
|
|
53
55
|
</HStack>
|
|
54
56
|
</NavigationButton>
|
|
55
57
|
) }
|
|
@@ -72,13 +74,9 @@ function ScreenRoot() {
|
|
|
72
74
|
<NavigationButton path="/blocks">
|
|
73
75
|
<HStack justify="space-between">
|
|
74
76
|
<FlexItem>{ __( 'Blocks' ) }</FlexItem>
|
|
75
|
-
<
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
isRTL() ? chevronLeft : chevronRight
|
|
79
|
-
}
|
|
80
|
-
/>
|
|
81
|
-
</FlexItem>
|
|
77
|
+
<IconWithCurrentColor
|
|
78
|
+
icon={ isRTL() ? chevronLeft : chevronRight }
|
|
79
|
+
/>
|
|
82
80
|
</HStack>
|
|
83
81
|
</NavigationButton>
|
|
84
82
|
</ItemGroup>
|
|
@@ -9,7 +9,7 @@ import classnames from 'classnames';
|
|
|
9
9
|
*/
|
|
10
10
|
import { store as coreStore } from '@wordpress/core-data';
|
|
11
11
|
import { useSelect } from '@wordpress/data';
|
|
12
|
-
import { useMemo, useContext } from '@wordpress/element';
|
|
12
|
+
import { useMemo, useContext, useState } from '@wordpress/element';
|
|
13
13
|
import { ENTER } from '@wordpress/keycodes';
|
|
14
14
|
import {
|
|
15
15
|
__experimentalGrid as Grid,
|
|
@@ -31,6 +31,7 @@ function compareVariations( a, b ) {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
function Variation( { variation } ) {
|
|
34
|
+
const [ isFocused, setIsFocused ] = useState( false );
|
|
34
35
|
const { base, user, setUserConfig } = useContext( GlobalStylesContext );
|
|
35
36
|
const context = useMemo( () => {
|
|
36
37
|
return {
|
|
@@ -77,8 +78,16 @@ function Variation( { variation } ) {
|
|
|
77
78
|
onClick={ selectVariation }
|
|
78
79
|
onKeyDown={ selectOnEnter }
|
|
79
80
|
tabIndex="0"
|
|
81
|
+
aria-label={ variation?.title }
|
|
82
|
+
onFocus={ () => setIsFocused( true ) }
|
|
83
|
+
onBlur={ () => setIsFocused( false ) }
|
|
80
84
|
>
|
|
81
|
-
<
|
|
85
|
+
<div className="edit-site-global-styles-variations_item-preview">
|
|
86
|
+
<StylesPreview
|
|
87
|
+
label={ variation?.title }
|
|
88
|
+
isFocused={ isFocused }
|
|
89
|
+
/>
|
|
90
|
+
</div>
|
|
82
91
|
</div>
|
|
83
92
|
</GlobalStylesContext.Provider>
|
|
84
93
|
);
|
|
@@ -96,7 +105,7 @@ function ScreenStyleVariations() {
|
|
|
96
105
|
const withEmptyVariation = useMemo( () => {
|
|
97
106
|
return [
|
|
98
107
|
{
|
|
99
|
-
|
|
108
|
+
title: __( 'Default' ),
|
|
100
109
|
settings: {},
|
|
101
110
|
styles: {},
|
|
102
111
|
},
|
|
@@ -108,7 +117,7 @@ function ScreenStyleVariations() {
|
|
|
108
117
|
<>
|
|
109
118
|
<ScreenHeader
|
|
110
119
|
back="/"
|
|
111
|
-
title={ __( '
|
|
120
|
+
title={ __( 'Browse styles' ) }
|
|
112
121
|
description={ __(
|
|
113
122
|
'Choose a different style combination for the theme styles'
|
|
114
123
|
) }
|
|
@@ -44,7 +44,8 @@
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
.edit-site-global-styles-header__description
|
|
47
|
+
.edit-site-global-styles-header__description,
|
|
48
|
+
.edit-site-block-types-search {
|
|
48
49
|
padding: 0 $grid-unit-20;
|
|
49
50
|
}
|
|
50
51
|
|
|
@@ -73,19 +74,31 @@
|
|
|
73
74
|
|
|
74
75
|
.edit-site-global-styles-variations_item {
|
|
75
76
|
box-sizing: border-box;
|
|
76
|
-
padding: $border-width * 2;
|
|
77
|
-
border-radius: $radius-block-ui;
|
|
78
|
-
border: $gray-200 $border-width solid;
|
|
79
77
|
|
|
80
|
-
|
|
78
|
+
.edit-site-global-styles-variations_item-preview {
|
|
79
|
+
padding: $border-width * 2;
|
|
80
|
+
border-radius: $radius-block-ui;
|
|
81
|
+
border: $gray-200 $border-width solid;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
&.is-active .edit-site-global-styles-variations_item-preview {
|
|
81
85
|
border: $gray-900 $border-width solid;
|
|
82
86
|
}
|
|
83
87
|
|
|
84
|
-
&:hover {
|
|
88
|
+
&:hover .edit-site-global-styles-variations_item-preview {
|
|
85
89
|
border: var(--wp-admin-theme-color) $border-width solid;
|
|
86
90
|
}
|
|
87
91
|
|
|
88
|
-
&:focus {
|
|
92
|
+
&:focus .edit-site-global-styles-variations_item-preview {
|
|
89
93
|
border: var(--wp-admin-theme-color) $border-width solid;
|
|
90
94
|
}
|
|
91
95
|
}
|
|
96
|
+
|
|
97
|
+
.edit-site-global-styles-icon-with-current-color {
|
|
98
|
+
fill: currentColor;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.edit-site-global-styles__color-indicator-wrapper {
|
|
102
|
+
// Match the height of the rest of the icons (24px).
|
|
103
|
+
height: $grid-unit * 3;
|
|
104
|
+
}
|
|
@@ -14,6 +14,7 @@ import { store as blockEditorStore } from '@wordpress/block-editor';
|
|
|
14
14
|
*/
|
|
15
15
|
import DefaultSidebar from './default-sidebar';
|
|
16
16
|
import GlobalStylesSidebar from './global-styles-sidebar';
|
|
17
|
+
import NavigationMenuSidebar from './navigation-menu-sidebar';
|
|
17
18
|
import { STORE_NAME } from '../../store/constants';
|
|
18
19
|
import SettingsHeader from './settings-header';
|
|
19
20
|
import TemplateCard from './template-card';
|
|
@@ -57,6 +58,16 @@ export function SidebarComplementaryAreaFills() {
|
|
|
57
58
|
if ( ! isEditorSidebarOpened ) {
|
|
58
59
|
sidebarName = hasBlockSelection ? SIDEBAR_BLOCK : SIDEBAR_TEMPLATE;
|
|
59
60
|
}
|
|
61
|
+
|
|
62
|
+
// Conditionally include NavMenu sidebar in Plugin only.
|
|
63
|
+
// Optimise for dead code elimination.
|
|
64
|
+
// See https://github.com/WordPress/gutenberg/blob/trunk/docs/how-to-guides/feature-flags.md#dead-code-elimination.
|
|
65
|
+
let MaybeNavigationMenuSidebar = 'Fragment';
|
|
66
|
+
|
|
67
|
+
if ( process.env.IS_GUTENBERG_PLUGIN ) {
|
|
68
|
+
MaybeNavigationMenuSidebar = NavigationMenuSidebar;
|
|
69
|
+
}
|
|
70
|
+
|
|
60
71
|
return (
|
|
61
72
|
<>
|
|
62
73
|
<DefaultSidebar
|
|
@@ -77,6 +88,7 @@ export function SidebarComplementaryAreaFills() {
|
|
|
77
88
|
) }
|
|
78
89
|
</DefaultSidebar>
|
|
79
90
|
<GlobalStylesSidebar />
|
|
91
|
+
<MaybeNavigationMenuSidebar />
|
|
80
92
|
</>
|
|
81
93
|
);
|
|
82
94
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { FlexBlock, Flex } from '@wordpress/components';
|
|
5
|
+
import { __ } from '@wordpress/i18n';
|
|
6
|
+
import { navigation } from '@wordpress/icons';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Internal dependencies
|
|
10
|
+
*/
|
|
11
|
+
import DefaultSidebar from '../default-sidebar';
|
|
12
|
+
import NavigationInspector from './navigation-inspector';
|
|
13
|
+
|
|
14
|
+
export default function NavigationMenuSidebar() {
|
|
15
|
+
return (
|
|
16
|
+
<DefaultSidebar
|
|
17
|
+
className="edit-site-navigation-menu-sidebar"
|
|
18
|
+
identifier="edit-site/navigation-menu"
|
|
19
|
+
title={ __( 'Navigation Menus' ) }
|
|
20
|
+
icon={ navigation }
|
|
21
|
+
closeLabel={ __( 'Close navigation menu sidebar' ) }
|
|
22
|
+
panelClassName="edit-site-navigation-menu-sidebar__panel"
|
|
23
|
+
header={
|
|
24
|
+
<Flex>
|
|
25
|
+
<FlexBlock>
|
|
26
|
+
<strong>{ __( 'Navigation Menus' ) }</strong>
|
|
27
|
+
</FlexBlock>
|
|
28
|
+
</Flex>
|
|
29
|
+
}
|
|
30
|
+
>
|
|
31
|
+
<NavigationInspector />
|
|
32
|
+
</DefaultSidebar>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { useSelect } from '@wordpress/data';
|
|
5
|
+
import { useState, useEffect } from '@wordpress/element';
|
|
6
|
+
import { SelectControl } from '@wordpress/components';
|
|
7
|
+
import { store as coreStore, useEntityBlockEditor } from '@wordpress/core-data';
|
|
8
|
+
import {
|
|
9
|
+
store as blockEditorStore,
|
|
10
|
+
BlockEditorProvider,
|
|
11
|
+
} from '@wordpress/block-editor';
|
|
12
|
+
import { speak } from '@wordpress/a11y';
|
|
13
|
+
import { useInstanceId } from '@wordpress/compose';
|
|
14
|
+
import { __ } from '@wordpress/i18n';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Internal dependencies
|
|
18
|
+
*/
|
|
19
|
+
import NavigationMenu from './navigation-menu';
|
|
20
|
+
|
|
21
|
+
const NAVIGATION_MENUS_QUERY = [ { per_page: -1, status: 'publish' } ];
|
|
22
|
+
|
|
23
|
+
export default function NavigationInspector() {
|
|
24
|
+
const {
|
|
25
|
+
selectedNavigationBlockId,
|
|
26
|
+
clientIdToRef,
|
|
27
|
+
navigationMenus,
|
|
28
|
+
isResolvingNavigationMenus,
|
|
29
|
+
hasResolvedNavigationMenus,
|
|
30
|
+
firstNavigationBlockId,
|
|
31
|
+
} = useSelect( ( select ) => {
|
|
32
|
+
const {
|
|
33
|
+
__experimentalGetActiveBlockIdByBlockNames,
|
|
34
|
+
__experimentalGetGlobalBlocksByName,
|
|
35
|
+
getBlock,
|
|
36
|
+
} = select( blockEditorStore );
|
|
37
|
+
|
|
38
|
+
const { getEntityRecords, hasFinishedResolution, isResolving } = select(
|
|
39
|
+
coreStore
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const navigationMenusQuery = [
|
|
43
|
+
'postType',
|
|
44
|
+
'wp_navigation',
|
|
45
|
+
NAVIGATION_MENUS_QUERY[ 0 ],
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
// Get the active Navigation block (if present).
|
|
49
|
+
const selectedNavId = __experimentalGetActiveBlockIdByBlockNames(
|
|
50
|
+
'core/navigation'
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
// Get all Navigation blocks currently within the editor canvas.
|
|
54
|
+
const navBlockIds = __experimentalGetGlobalBlocksByName(
|
|
55
|
+
'core/navigation'
|
|
56
|
+
);
|
|
57
|
+
const idToRef = {};
|
|
58
|
+
navBlockIds.forEach( ( id ) => {
|
|
59
|
+
idToRef[ id ] = getBlock( id )?.attributes?.ref;
|
|
60
|
+
} );
|
|
61
|
+
return {
|
|
62
|
+
selectedNavigationBlockId: selectedNavId,
|
|
63
|
+
firstNavigationBlockId: navBlockIds?.[ 0 ],
|
|
64
|
+
clientIdToRef: idToRef,
|
|
65
|
+
navigationMenus: getEntityRecords( ...navigationMenusQuery ),
|
|
66
|
+
isResolvingNavigationMenus: isResolving(
|
|
67
|
+
'getEntityRecords',
|
|
68
|
+
navigationMenusQuery
|
|
69
|
+
),
|
|
70
|
+
hasResolvedNavigationMenus: hasFinishedResolution(
|
|
71
|
+
'getEntityRecords',
|
|
72
|
+
navigationMenusQuery
|
|
73
|
+
),
|
|
74
|
+
};
|
|
75
|
+
}, [] );
|
|
76
|
+
|
|
77
|
+
const navMenuListId = useInstanceId(
|
|
78
|
+
NavigationMenu,
|
|
79
|
+
'edit-site-navigation-inspector-menu'
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
const firstNavRefInTemplate = clientIdToRef[ firstNavigationBlockId ];
|
|
83
|
+
const firstNavigationMenuRef = navigationMenus?.[ 0 ]?.id;
|
|
84
|
+
|
|
85
|
+
// Default Navigation Menu is either:
|
|
86
|
+
// - the Navigation Menu referenced by the first Nav block within the template.
|
|
87
|
+
// - the first of the available Navigation Menus (`wp_navigation`) posts.
|
|
88
|
+
const defaultNavigationMenuId =
|
|
89
|
+
firstNavRefInTemplate || firstNavigationMenuRef;
|
|
90
|
+
|
|
91
|
+
// The Navigation Menu manually selected by the user within the Nav inspector.
|
|
92
|
+
const [ currentMenuId, setCurrentMenuId ] = useState(
|
|
93
|
+
firstNavRefInTemplate
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
// If a Nav block is selected within the canvas then set the
|
|
97
|
+
// Navigation Menu referenced by it's `ref` attribute to be
|
|
98
|
+
// active within the Navigation sidebar.
|
|
99
|
+
useEffect( () => {
|
|
100
|
+
if ( selectedNavigationBlockId ) {
|
|
101
|
+
setCurrentMenuId( clientIdToRef[ selectedNavigationBlockId ] );
|
|
102
|
+
}
|
|
103
|
+
}, [ selectedNavigationBlockId ] );
|
|
104
|
+
|
|
105
|
+
let options = [];
|
|
106
|
+
if ( navigationMenus ) {
|
|
107
|
+
options = navigationMenus.map( ( { id, title } ) => ( {
|
|
108
|
+
value: id,
|
|
109
|
+
label: title.rendered,
|
|
110
|
+
} ) );
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const [ innerBlocks, onInput, onChange ] = useEntityBlockEditor(
|
|
114
|
+
'postType',
|
|
115
|
+
'wp_navigation',
|
|
116
|
+
{ id: currentMenuId || defaultNavigationMenuId }
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
const { isLoadingInnerBlocks, hasLoadedInnerBlocks } = useSelect(
|
|
120
|
+
( select ) => {
|
|
121
|
+
const { isResolving, hasFinishedResolution } = select( coreStore );
|
|
122
|
+
return {
|
|
123
|
+
isLoadingInnerBlocks: isResolving( 'getEntityRecord', [
|
|
124
|
+
'postType',
|
|
125
|
+
'wp_navigation',
|
|
126
|
+
currentMenuId || defaultNavigationMenuId,
|
|
127
|
+
] ),
|
|
128
|
+
hasLoadedInnerBlocks: hasFinishedResolution(
|
|
129
|
+
'getEntityRecord',
|
|
130
|
+
[
|
|
131
|
+
'postType',
|
|
132
|
+
'wp_navigation',
|
|
133
|
+
currentMenuId || defaultNavigationMenuId,
|
|
134
|
+
]
|
|
135
|
+
),
|
|
136
|
+
};
|
|
137
|
+
},
|
|
138
|
+
[ currentMenuId, defaultNavigationMenuId ]
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
const isLoading = ! ( hasResolvedNavigationMenus && hasLoadedInnerBlocks );
|
|
142
|
+
|
|
143
|
+
const hasMoreThanOneNavigationMenu = navigationMenus?.length > 1;
|
|
144
|
+
|
|
145
|
+
const hasNavigationMenus = !! navigationMenus?.length;
|
|
146
|
+
|
|
147
|
+
// Entity block editor will return entities that are not currently published.
|
|
148
|
+
// Guard by only allowing their usage if there are published Nav Menus.
|
|
149
|
+
const publishedInnerBlocks = hasNavigationMenus ? innerBlocks : [];
|
|
150
|
+
|
|
151
|
+
const hasInnerBlocks = !! publishedInnerBlocks?.length;
|
|
152
|
+
|
|
153
|
+
useEffect( () => {
|
|
154
|
+
if ( isResolvingNavigationMenus ) {
|
|
155
|
+
speak( 'Loading Navigation sidebar menus.' );
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if ( hasResolvedNavigationMenus ) {
|
|
159
|
+
speak( 'Navigation sidebar menus have loaded.' );
|
|
160
|
+
}
|
|
161
|
+
}, [ isResolvingNavigationMenus, hasResolvedNavigationMenus ] );
|
|
162
|
+
|
|
163
|
+
useEffect( () => {
|
|
164
|
+
if ( isLoadingInnerBlocks ) {
|
|
165
|
+
speak( 'Loading Navigation sidebar selected menu items.' );
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if ( hasLoadedInnerBlocks ) {
|
|
169
|
+
speak( 'Navigation sidebar selected menu items have loaded.' );
|
|
170
|
+
}
|
|
171
|
+
}, [ isLoadingInnerBlocks, hasLoadedInnerBlocks ] );
|
|
172
|
+
|
|
173
|
+
return (
|
|
174
|
+
<div className="edit-site-navigation-inspector">
|
|
175
|
+
{ hasResolvedNavigationMenus && ! hasNavigationMenus && (
|
|
176
|
+
<p className="edit-site-navigation-inspector__empty-msg">
|
|
177
|
+
{ __( 'There are no Navigation Menus.' ) }
|
|
178
|
+
</p>
|
|
179
|
+
) }
|
|
180
|
+
|
|
181
|
+
{ ! hasResolvedNavigationMenus && (
|
|
182
|
+
<div className="edit-site-navigation-inspector__placeholder" />
|
|
183
|
+
) }
|
|
184
|
+
{ hasResolvedNavigationMenus && hasMoreThanOneNavigationMenu && (
|
|
185
|
+
<SelectControl
|
|
186
|
+
aria-controls={
|
|
187
|
+
// aria-controls should only apply when referenced element is in DOM
|
|
188
|
+
hasLoadedInnerBlocks ? navMenuListId : undefined
|
|
189
|
+
}
|
|
190
|
+
value={ currentMenuId || defaultNavigationMenuId }
|
|
191
|
+
options={ options }
|
|
192
|
+
onChange={ ( newMenuId ) =>
|
|
193
|
+
setCurrentMenuId( Number( newMenuId ) )
|
|
194
|
+
}
|
|
195
|
+
/>
|
|
196
|
+
) }
|
|
197
|
+
{ isLoading && (
|
|
198
|
+
<>
|
|
199
|
+
<div className="edit-site-navigation-inspector__placeholder is-child" />
|
|
200
|
+
<div className="edit-site-navigation-inspector__placeholder is-child" />
|
|
201
|
+
<div className="edit-site-navigation-inspector__placeholder is-child" />
|
|
202
|
+
</>
|
|
203
|
+
) }
|
|
204
|
+
{ hasInnerBlocks && ! isLoading && (
|
|
205
|
+
<BlockEditorProvider
|
|
206
|
+
value={ publishedInnerBlocks }
|
|
207
|
+
onChange={ onChange }
|
|
208
|
+
onInput={ onInput }
|
|
209
|
+
>
|
|
210
|
+
<NavigationMenu
|
|
211
|
+
id={ navMenuListId }
|
|
212
|
+
innerBlocks={ publishedInnerBlocks }
|
|
213
|
+
/>
|
|
214
|
+
</BlockEditorProvider>
|
|
215
|
+
) }
|
|
216
|
+
|
|
217
|
+
{ ! hasInnerBlocks && ! isLoading && (
|
|
218
|
+
<p className="edit-site-navigation-inspector__empty-msg">
|
|
219
|
+
{ __( 'Navigation Menu is empty.' ) }
|
|
220
|
+
</p>
|
|
221
|
+
) }
|
|
222
|
+
</div>
|
|
223
|
+
);
|
|
224
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import {
|
|
5
|
+
__experimentalListView as ListView,
|
|
6
|
+
store as blockEditorStore,
|
|
7
|
+
} from '@wordpress/block-editor';
|
|
8
|
+
import { useEffect } from '@wordpress/element';
|
|
9
|
+
import { useDispatch } from '@wordpress/data';
|
|
10
|
+
|
|
11
|
+
const ALLOWED_BLOCKS = {
|
|
12
|
+
'core/navigation': [
|
|
13
|
+
'core/navigation-link',
|
|
14
|
+
'core/search',
|
|
15
|
+
'core/social-links',
|
|
16
|
+
'core/page-list',
|
|
17
|
+
'core/spacer',
|
|
18
|
+
'core/home-link',
|
|
19
|
+
'core/site-title',
|
|
20
|
+
'core/site-logo',
|
|
21
|
+
'core/navigation-submenu',
|
|
22
|
+
],
|
|
23
|
+
'core/social-links': [ 'core/social-link' ],
|
|
24
|
+
'core/navigation-submenu': [
|
|
25
|
+
'core/navigation-link',
|
|
26
|
+
'core/navigation-submenu',
|
|
27
|
+
],
|
|
28
|
+
'core/navigation-link': [
|
|
29
|
+
'core/navigation-link',
|
|
30
|
+
'core/navigation-submenu',
|
|
31
|
+
],
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default function NavigationMenu( { innerBlocks, id } ) {
|
|
35
|
+
const { updateBlockListSettings } = useDispatch( blockEditorStore );
|
|
36
|
+
|
|
37
|
+
//TODO: Block settings are normally updated as a side effect of rendering InnerBlocks in BlockList
|
|
38
|
+
//Think through a better way of doing this, possible with adding allowed blocks to block library metadata
|
|
39
|
+
useEffect( () => {
|
|
40
|
+
updateBlockListSettings( '', {
|
|
41
|
+
allowedBlocks: ALLOWED_BLOCKS[ 'core/navigation' ],
|
|
42
|
+
} );
|
|
43
|
+
innerBlocks.forEach( ( block ) => {
|
|
44
|
+
if ( ALLOWED_BLOCKS[ block.name ] ) {
|
|
45
|
+
updateBlockListSettings( block.clientId, {
|
|
46
|
+
allowedBlocks: ALLOWED_BLOCKS[ block.name ],
|
|
47
|
+
} );
|
|
48
|
+
}
|
|
49
|
+
} );
|
|
50
|
+
}, [ updateBlockListSettings, innerBlocks ] );
|
|
51
|
+
return (
|
|
52
|
+
<>
|
|
53
|
+
<ListView
|
|
54
|
+
id={ id }
|
|
55
|
+
showNestedBlocks
|
|
56
|
+
expandNested={ false }
|
|
57
|
+
__experimentalFeatures
|
|
58
|
+
__experimentalPersistentListViewFeatures
|
|
59
|
+
/>
|
|
60
|
+
</>
|
|
61
|
+
);
|
|
62
|
+
}
|