@wordpress/block-library 9.30.0 → 9.30.1-next.6870dfe5b.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.
- package/build/accordion-content/edit.js +8 -8
- package/build/accordion-content/edit.js.map +1 -1
- package/build/accordion-content/index.js +2 -1
- package/build/accordion-content/index.js.map +1 -1
- package/build/accordion-panel/index.js +2 -1
- package/build/accordion-panel/index.js.map +1 -1
- package/build/navigation/constants.js +5 -1
- package/build/navigation/constants.js.map +1 -1
- package/build/navigation/edit/index.js +45 -1
- package/build/navigation/edit/index.js.map +1 -1
- package/build/navigation/edit/leaf-more-menu.js +0 -1
- package/build/navigation/edit/leaf-more-menu.js.map +1 -1
- package/build/navigation/edit/menu-inspector-controls.js +40 -5
- package/build/navigation/edit/menu-inspector-controls.js.map +1 -1
- package/build/navigation-link/block-inserter.js +69 -0
- package/build/navigation-link/block-inserter.js.map +1 -0
- package/build/navigation-link/dialog-wrapper.js +80 -0
- package/build/navigation-link/dialog-wrapper.js.map +1 -0
- package/build/navigation-link/link-ui.js +80 -120
- package/build/navigation-link/link-ui.js.map +1 -1
- package/build/navigation-link/page-creator.js +137 -0
- package/build/navigation-link/page-creator.js.map +1 -0
- package/build/search/edit.js +22 -14
- package/build/search/edit.js.map +1 -1
- package/build-module/accordion-content/edit.js +8 -8
- package/build-module/accordion-content/edit.js.map +1 -1
- package/build-module/accordion-content/index.js +2 -1
- package/build-module/accordion-content/index.js.map +1 -1
- package/build-module/accordion-panel/index.js +2 -1
- package/build-module/accordion-panel/index.js.map +1 -1
- package/build-module/navigation/constants.js +5 -1
- package/build-module/navigation/constants.js.map +1 -1
- package/build-module/navigation/edit/index.js +50 -4
- package/build-module/navigation/edit/index.js.map +1 -1
- package/build-module/navigation/edit/leaf-more-menu.js +0 -1
- package/build-module/navigation/edit/leaf-more-menu.js.map +1 -1
- package/build-module/navigation/edit/menu-inspector-controls.js +40 -5
- package/build-module/navigation/edit/menu-inspector-controls.js.map +1 -1
- package/build-module/navigation-link/block-inserter.js +61 -0
- package/build-module/navigation-link/block-inserter.js.map +1 -0
- package/build-module/navigation-link/dialog-wrapper.js +75 -0
- package/build-module/navigation-link/dialog-wrapper.js.map +1 -0
- package/build-module/navigation-link/link-ui.js +85 -125
- package/build-module/navigation-link/link-ui.js.map +1 -1
- package/build-module/navigation-link/page-creator.js +130 -0
- package/build-module/navigation-link/page-creator.js.map +1 -0
- package/build-module/search/edit.js +22 -14
- package/build-module/search/edit.js.map +1 -1
- package/build-style/accordion/style-rtl.css +5 -6
- package/build-style/accordion/style.css +5 -6
- package/build-style/editor-rtl.css +14 -0
- package/build-style/editor.css +14 -0
- package/build-style/form-input/style-rtl.css +4 -3
- package/build-style/form-input/style.css +4 -3
- package/build-style/navigation-link/editor-rtl.css +14 -0
- package/build-style/navigation-link/editor.css +14 -0
- package/build-style/navigation-link/style-rtl.css +1 -1
- package/build-style/navigation-link/style.css +1 -1
- package/build-style/post-comments-form/style-rtl.css +8 -5
- package/build-style/post-comments-form/style.css +8 -5
- package/build-style/search/style-rtl.css +11 -12
- package/build-style/search/style.css +11 -12
- package/build-style/style-rtl.css +29 -27
- package/build-style/style.css +29 -27
- package/package.json +35 -35
- package/src/accordion/style.scss +6 -6
- package/src/accordion-content/block.json +2 -1
- package/src/accordion-content/edit.js +21 -27
- package/src/accordion-panel/block.json +2 -1
- package/src/cover/test/edit.js +1 -5
- package/src/form-input/style.scss +3 -2
- package/src/navigation/constants.js +4 -0
- package/src/navigation/edit/index.js +50 -1
- package/src/navigation/edit/leaf-more-menu.js +0 -1
- package/src/navigation/edit/menu-inspector-controls.js +40 -5
- package/src/navigation-link/block-inserter.js +65 -0
- package/src/navigation-link/dialog-wrapper.js +74 -0
- package/src/navigation-link/editor.scss +17 -0
- package/src/navigation-link/link-ui.js +108 -164
- package/src/navigation-link/page-creator.js +157 -0
- package/src/navigation-link/style.scss +1 -1
- package/src/post-comments-form/style.scss +11 -11
- package/src/search/edit.js +44 -13
- package/src/search/index.php +16 -2
- package/src/search/style.scss +15 -16
|
@@ -35,7 +35,8 @@ const BLOCKS_WITH_LINK_UI_SUPPORT = [
|
|
|
35
35
|
const { PrivateListView } = unlock( blockEditorPrivateApis );
|
|
36
36
|
|
|
37
37
|
function AdditionalBlockContent( { block, insertedBlock, setInsertedBlock } ) {
|
|
38
|
-
const { updateBlockAttributes } =
|
|
38
|
+
const { updateBlockAttributes, removeBlock } =
|
|
39
|
+
useDispatch( blockEditorStore );
|
|
39
40
|
|
|
40
41
|
const supportsLinkControls = BLOCKS_WITH_LINK_UI_SUPPORT?.includes(
|
|
41
42
|
insertedBlock?.name
|
|
@@ -47,6 +48,27 @@ function AdditionalBlockContent( { block, insertedBlock, setInsertedBlock } ) {
|
|
|
47
48
|
return null;
|
|
48
49
|
}
|
|
49
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Cleanup function for auto-inserted Navigation Link blocks.
|
|
53
|
+
*
|
|
54
|
+
* Removes the block if it has no URL and clears the inserted block state.
|
|
55
|
+
* This ensures consistent cleanup behavior across different contexts.
|
|
56
|
+
*/
|
|
57
|
+
const cleanupInsertedBlock = () => {
|
|
58
|
+
// Prevent automatic block selection when removing blocks in list view context
|
|
59
|
+
// This avoids focus stealing that would close the list view and switch to canvas
|
|
60
|
+
const shouldAutoSelectBlock = false;
|
|
61
|
+
|
|
62
|
+
// Follows the exact same pattern as Navigation Link block's onClose handler
|
|
63
|
+
// If there is no URL then remove the auto-inserted block to avoid empty blocks
|
|
64
|
+
if ( ! insertedBlock?.attributes?.url && insertedBlock?.clientId ) {
|
|
65
|
+
// Remove the block entirely to avoid poor UX
|
|
66
|
+
// This matches the Navigation Link block's behavior
|
|
67
|
+
removeBlock( insertedBlock.clientId, shouldAutoSelectBlock );
|
|
68
|
+
}
|
|
69
|
+
setInsertedBlock( null );
|
|
70
|
+
};
|
|
71
|
+
|
|
50
72
|
const setInsertedBlockAttributes =
|
|
51
73
|
( _insertedBlockClientId ) => ( _updatedAttributes ) => {
|
|
52
74
|
if ( ! _insertedBlockClientId ) {
|
|
@@ -55,12 +77,28 @@ function AdditionalBlockContent( { block, insertedBlock, setInsertedBlock } ) {
|
|
|
55
77
|
updateBlockAttributes( _insertedBlockClientId, _updatedAttributes );
|
|
56
78
|
};
|
|
57
79
|
|
|
80
|
+
// Wrapper function to clean up original block when a new block is selected
|
|
81
|
+
const handleSetInsertedBlock = ( newBlock ) => {
|
|
82
|
+
// Prevent automatic block selection when removing blocks in list view context
|
|
83
|
+
// This avoids focus stealing that would close the list view and switch to canvas
|
|
84
|
+
const shouldAutoSelectBlock = false;
|
|
85
|
+
|
|
86
|
+
// If we have an existing inserted block and a new block is being set,
|
|
87
|
+
// remove the original block to avoid duplicates
|
|
88
|
+
if ( insertedBlock?.clientId && newBlock ) {
|
|
89
|
+
removeBlock( insertedBlock.clientId, shouldAutoSelectBlock );
|
|
90
|
+
}
|
|
91
|
+
setInsertedBlock( newBlock );
|
|
92
|
+
};
|
|
93
|
+
|
|
58
94
|
return (
|
|
59
95
|
<LinkUI
|
|
60
96
|
clientId={ insertedBlock?.clientId }
|
|
61
97
|
link={ insertedBlock?.attributes }
|
|
98
|
+
onBlockInsert={ handleSetInsertedBlock }
|
|
62
99
|
onClose={ () => {
|
|
63
|
-
|
|
100
|
+
// Use cleanup function
|
|
101
|
+
cleanupInsertedBlock();
|
|
64
102
|
} }
|
|
65
103
|
onChange={ ( updatedValue ) => {
|
|
66
104
|
updateAttributes(
|
|
@@ -70,9 +108,6 @@ function AdditionalBlockContent( { block, insertedBlock, setInsertedBlock } ) {
|
|
|
70
108
|
);
|
|
71
109
|
setInsertedBlock( null );
|
|
72
110
|
} }
|
|
73
|
-
onCancel={ () => {
|
|
74
|
-
setInsertedBlock( null );
|
|
75
|
-
} }
|
|
76
111
|
/>
|
|
77
112
|
);
|
|
78
113
|
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { __ } from '@wordpress/i18n';
|
|
5
|
+
import { useSelect } from '@wordpress/data';
|
|
6
|
+
import {
|
|
7
|
+
store as blockEditorStore,
|
|
8
|
+
privateApis as blockEditorPrivateApis,
|
|
9
|
+
} from '@wordpress/block-editor';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Internal dependencies
|
|
13
|
+
*/
|
|
14
|
+
import DialogWrapper from './dialog-wrapper';
|
|
15
|
+
import { unlock } from '../lock-unlock';
|
|
16
|
+
|
|
17
|
+
const { PrivateQuickInserter: QuickInserter } = unlock(
|
|
18
|
+
blockEditorPrivateApis
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Component for inserting blocks within the Navigation Link UI.
|
|
23
|
+
*
|
|
24
|
+
* @param {Object} props Component props.
|
|
25
|
+
* @param {string} props.clientId Client ID of the navigation link block.
|
|
26
|
+
* @param {Function} props.onBack Callback when user wants to go back.
|
|
27
|
+
* @param {Function} props.onBlockInsert Callback when a block is inserted.
|
|
28
|
+
*/
|
|
29
|
+
function LinkUIBlockInserter( { clientId, onBack, onBlockInsert } ) {
|
|
30
|
+
const { rootBlockClientId } = useSelect(
|
|
31
|
+
( select ) => {
|
|
32
|
+
const { getBlockRootClientId } = select( blockEditorStore );
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
rootBlockClientId: getBlockRootClientId( clientId ),
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
[ clientId ]
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
if ( ! clientId ) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<DialogWrapper
|
|
47
|
+
className="link-ui-block-inserter"
|
|
48
|
+
title={ __( 'Add block' ) }
|
|
49
|
+
description={ __( 'Choose a block to add to your Navigation.' ) }
|
|
50
|
+
onBack={ onBack }
|
|
51
|
+
>
|
|
52
|
+
<QuickInserter
|
|
53
|
+
rootClientId={ rootBlockClientId }
|
|
54
|
+
clientId={ clientId }
|
|
55
|
+
isAppender={ false }
|
|
56
|
+
prioritizePatterns={ false }
|
|
57
|
+
selectBlockOnInsert={ ! onBlockInsert }
|
|
58
|
+
onSelect={ onBlockInsert ? onBlockInsert : undefined }
|
|
59
|
+
hasSearch={ false }
|
|
60
|
+
/>
|
|
61
|
+
</DialogWrapper>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export default LinkUIBlockInserter;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { Button, VisuallyHidden } from '@wordpress/components';
|
|
5
|
+
import { __, isRTL } from '@wordpress/i18n';
|
|
6
|
+
import { chevronLeftSmall, chevronRightSmall } from '@wordpress/icons';
|
|
7
|
+
import { useInstanceId, useFocusOnMount } from '@wordpress/compose';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Shared BackButton component for consistent navigation across LinkUI sub-components.
|
|
11
|
+
*
|
|
12
|
+
* @param {Object} props Component props.
|
|
13
|
+
* @param {string} props.className CSS class name for the button.
|
|
14
|
+
* @param {Function} props.onBack Callback when user wants to go back.
|
|
15
|
+
*/
|
|
16
|
+
function BackButton( { className, onBack } ) {
|
|
17
|
+
return (
|
|
18
|
+
<Button
|
|
19
|
+
className={ className }
|
|
20
|
+
icon={ isRTL() ? chevronRightSmall : chevronLeftSmall }
|
|
21
|
+
onClick={ ( e ) => {
|
|
22
|
+
e.preventDefault();
|
|
23
|
+
onBack();
|
|
24
|
+
} }
|
|
25
|
+
size="small"
|
|
26
|
+
>
|
|
27
|
+
{ __( 'Back' ) }
|
|
28
|
+
</Button>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Shared DialogWrapper component for consistent dialog structure across LinkUI sub-components.
|
|
34
|
+
*
|
|
35
|
+
* @param {Object} props Component props.
|
|
36
|
+
* @param {string} props.className CSS class name for the dialog container.
|
|
37
|
+
* @param {string} props.title Dialog title for accessibility.
|
|
38
|
+
* @param {string} props.description Dialog description for accessibility.
|
|
39
|
+
* @param {Function} props.onBack Callback when user wants to go back.
|
|
40
|
+
* @param {Object} props.children Child components to render inside the dialog.
|
|
41
|
+
*/
|
|
42
|
+
function DialogWrapper( { className, title, description, onBack, children } ) {
|
|
43
|
+
const dialogTitleId = useInstanceId(
|
|
44
|
+
DialogWrapper,
|
|
45
|
+
'link-ui-dialog-title'
|
|
46
|
+
);
|
|
47
|
+
const dialogDescriptionId = useInstanceId(
|
|
48
|
+
DialogWrapper,
|
|
49
|
+
'link-ui-dialog-description'
|
|
50
|
+
);
|
|
51
|
+
const focusOnMountRef = useFocusOnMount( 'firstElement' );
|
|
52
|
+
const backButtonClassName = `${ className }__back`;
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<div
|
|
56
|
+
className={ className }
|
|
57
|
+
role="dialog"
|
|
58
|
+
aria-labelledby={ dialogTitleId }
|
|
59
|
+
aria-describedby={ dialogDescriptionId }
|
|
60
|
+
ref={ focusOnMountRef }
|
|
61
|
+
>
|
|
62
|
+
<VisuallyHidden>
|
|
63
|
+
<h2 id={ dialogTitleId }>{ title }</h2>
|
|
64
|
+
<p id={ dialogDescriptionId }>{ description }</p>
|
|
65
|
+
</VisuallyHidden>
|
|
66
|
+
|
|
67
|
+
<BackButton className={ backButtonClassName } onBack={ onBack } />
|
|
68
|
+
|
|
69
|
+
{ children }
|
|
70
|
+
</div>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export default DialogWrapper;
|
|
@@ -122,3 +122,20 @@
|
|
|
122
122
|
gap: $grid-unit-10;
|
|
123
123
|
height: auto;
|
|
124
124
|
}
|
|
125
|
+
|
|
126
|
+
.link-ui-page-creator {
|
|
127
|
+
// Match LinkControl width constraints for consistent UI sizing
|
|
128
|
+
max-width: 350px;
|
|
129
|
+
min-width: auto;
|
|
130
|
+
width: 90vw;
|
|
131
|
+
padding-top: $grid-unit-10;
|
|
132
|
+
|
|
133
|
+
&__inner {
|
|
134
|
+
padding: $grid-unit-20;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
&__back {
|
|
138
|
+
margin-left: $grid-unit-10;
|
|
139
|
+
text-transform: uppercase;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -8,38 +8,24 @@ import {
|
|
|
8
8
|
VisuallyHidden,
|
|
9
9
|
__experimentalVStack as VStack,
|
|
10
10
|
} from '@wordpress/components';
|
|
11
|
-
import { __
|
|
11
|
+
import { __ } from '@wordpress/i18n';
|
|
12
|
+
import { LinkControl, useBlockEditingMode } from '@wordpress/block-editor';
|
|
12
13
|
import {
|
|
13
|
-
LinkControl,
|
|
14
|
-
store as blockEditorStore,
|
|
15
|
-
privateApis as blockEditorPrivateApis,
|
|
16
|
-
useBlockEditingMode,
|
|
17
|
-
} from '@wordpress/block-editor';
|
|
18
|
-
import {
|
|
19
|
-
createInterpolateElement,
|
|
20
14
|
useMemo,
|
|
21
15
|
useState,
|
|
22
16
|
useRef,
|
|
23
17
|
useEffect,
|
|
24
18
|
forwardRef,
|
|
25
19
|
} from '@wordpress/element';
|
|
26
|
-
import {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
} from '@wordpress/core-data';
|
|
30
|
-
import { decodeEntities } from '@wordpress/html-entities';
|
|
31
|
-
import { useSelect, useDispatch } from '@wordpress/data';
|
|
32
|
-
import { chevronLeftSmall, chevronRightSmall, plus } from '@wordpress/icons';
|
|
33
|
-
import { useInstanceId, useFocusOnMount } from '@wordpress/compose';
|
|
20
|
+
import { useResourcePermissions } from '@wordpress/core-data';
|
|
21
|
+
import { plus } from '@wordpress/icons';
|
|
22
|
+
import { useInstanceId } from '@wordpress/compose';
|
|
34
23
|
|
|
35
24
|
/**
|
|
36
25
|
* Internal dependencies
|
|
37
26
|
*/
|
|
38
|
-
import {
|
|
39
|
-
|
|
40
|
-
const { PrivateQuickInserter: QuickInserter } = unlock(
|
|
41
|
-
blockEditorPrivateApis
|
|
42
|
-
);
|
|
27
|
+
import { LinkUIPageCreator } from './page-creator';
|
|
28
|
+
import LinkUIBlockInserter from './block-inserter';
|
|
43
29
|
|
|
44
30
|
/**
|
|
45
31
|
* Given the Link block's type attribute, return the query params to give to
|
|
@@ -79,114 +65,19 @@ export function getSuggestionsQuery( type, kind ) {
|
|
|
79
65
|
}
|
|
80
66
|
}
|
|
81
67
|
|
|
82
|
-
function LinkUIBlockInserter( { clientId, onBack } ) {
|
|
83
|
-
const { rootBlockClientId } = useSelect(
|
|
84
|
-
( select ) => {
|
|
85
|
-
const { getBlockRootClientId } = select( blockEditorStore );
|
|
86
|
-
|
|
87
|
-
return {
|
|
88
|
-
rootBlockClientId: getBlockRootClientId( clientId ),
|
|
89
|
-
};
|
|
90
|
-
},
|
|
91
|
-
[ clientId ]
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
const focusOnMountRef = useFocusOnMount( 'firstElement' );
|
|
95
|
-
|
|
96
|
-
const dialogTitleId = useInstanceId(
|
|
97
|
-
LinkControl,
|
|
98
|
-
`link-ui-block-inserter__title`
|
|
99
|
-
);
|
|
100
|
-
const dialogDescriptionId = useInstanceId(
|
|
101
|
-
LinkControl,
|
|
102
|
-
`link-ui-block-inserter__description`
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
if ( ! clientId ) {
|
|
106
|
-
return null;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
return (
|
|
110
|
-
<div
|
|
111
|
-
className="link-ui-block-inserter"
|
|
112
|
-
role="dialog"
|
|
113
|
-
aria-labelledby={ dialogTitleId }
|
|
114
|
-
aria-describedby={ dialogDescriptionId }
|
|
115
|
-
ref={ focusOnMountRef }
|
|
116
|
-
>
|
|
117
|
-
<VisuallyHidden>
|
|
118
|
-
<h2 id={ dialogTitleId }>{ __( 'Add block' ) }</h2>
|
|
119
|
-
|
|
120
|
-
<p id={ dialogDescriptionId }>
|
|
121
|
-
{ __( 'Choose a block to add to your Navigation.' ) }
|
|
122
|
-
</p>
|
|
123
|
-
</VisuallyHidden>
|
|
124
|
-
|
|
125
|
-
<Button
|
|
126
|
-
className="link-ui-block-inserter__back"
|
|
127
|
-
icon={ isRTL() ? chevronRightSmall : chevronLeftSmall }
|
|
128
|
-
onClick={ ( e ) => {
|
|
129
|
-
e.preventDefault();
|
|
130
|
-
onBack();
|
|
131
|
-
} }
|
|
132
|
-
size="small"
|
|
133
|
-
>
|
|
134
|
-
{ __( 'Back' ) }
|
|
135
|
-
</Button>
|
|
136
|
-
|
|
137
|
-
<QuickInserter
|
|
138
|
-
rootClientId={ rootBlockClientId }
|
|
139
|
-
clientId={ clientId }
|
|
140
|
-
isAppender={ false }
|
|
141
|
-
prioritizePatterns={ false }
|
|
142
|
-
selectBlockOnInsert
|
|
143
|
-
hasSearch={ false }
|
|
144
|
-
/>
|
|
145
|
-
</div>
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
68
|
function UnforwardedLinkUI( props, ref ) {
|
|
150
69
|
const { label, url, opensInNewTab, type, kind } = props.link;
|
|
151
70
|
const postType = type || 'page';
|
|
152
71
|
|
|
153
72
|
const [ addingBlock, setAddingBlock ] = useState( false );
|
|
73
|
+
const [ addingPage, setAddingPage ] = useState( false );
|
|
154
74
|
const [ focusAddBlockButton, setFocusAddBlockButton ] = useState( false );
|
|
155
|
-
const
|
|
75
|
+
const [ focusAddPageButton, setFocusAddPageButton ] = useState( false );
|
|
156
76
|
const permissions = useResourcePermissions( {
|
|
157
77
|
kind: 'postType',
|
|
158
78
|
name: postType,
|
|
159
79
|
} );
|
|
160
80
|
|
|
161
|
-
// Check if we're in contentOnly mode
|
|
162
|
-
const blockEditingMode = useBlockEditingMode();
|
|
163
|
-
const isDefaultBlockEditingMode = blockEditingMode === 'default';
|
|
164
|
-
|
|
165
|
-
async function handleCreate( pageTitle ) {
|
|
166
|
-
const page = await saveEntityRecord( 'postType', postType, {
|
|
167
|
-
title: pageTitle,
|
|
168
|
-
status: 'draft',
|
|
169
|
-
} );
|
|
170
|
-
|
|
171
|
-
return {
|
|
172
|
-
id: page.id,
|
|
173
|
-
type: postType,
|
|
174
|
-
// Make `title` property consistent with that in `fetchLinkSuggestions` where the `rendered` title (containing HTML entities)
|
|
175
|
-
// is also being decoded. By being consistent in both locations we avoid having to branch in the rendering output code.
|
|
176
|
-
// Ideally in the future we will update both APIs to utilise the "raw" form of the title which is better suited to edit contexts.
|
|
177
|
-
// e.g.
|
|
178
|
-
// - title.raw = "Yes & No"
|
|
179
|
-
// - title.rendered = "Yes & No"
|
|
180
|
-
// - decodeEntities( title.rendered ) = "Yes & No"
|
|
181
|
-
// See:
|
|
182
|
-
// - https://github.com/WordPress/gutenberg/pull/41063
|
|
183
|
-
// - https://github.com/WordPress/gutenberg/blob/a1e1fdc0e6278457e9f4fc0b31ac6d2095f5450b/packages/core-data/src/fetch/__experimental-fetch-link-suggestions.js#L212-L218
|
|
184
|
-
title: decodeEntities( page.title.rendered ),
|
|
185
|
-
url: page.link,
|
|
186
|
-
kind: 'post-type',
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
|
|
190
81
|
// Memoize link value to avoid overriding the LinkControl's internal state.
|
|
191
82
|
// This is a temporary fix. See https://github.com/WordPress/gutenberg/issues/50976#issuecomment-1568226407.
|
|
192
83
|
const link = useMemo(
|
|
@@ -198,15 +89,24 @@ function UnforwardedLinkUI( props, ref ) {
|
|
|
198
89
|
[ label, opensInNewTab, url ]
|
|
199
90
|
);
|
|
200
91
|
|
|
92
|
+
const handlePageCreated = ( pageLink ) => {
|
|
93
|
+
// Set the new page as the current link
|
|
94
|
+
props.onChange( pageLink );
|
|
95
|
+
// Return to main Link UI
|
|
96
|
+
setAddingPage( false );
|
|
97
|
+
};
|
|
98
|
+
|
|
201
99
|
const dialogTitleId = useInstanceId(
|
|
202
100
|
LinkUI,
|
|
203
|
-
|
|
101
|
+
'link-ui-link-control__title'
|
|
204
102
|
);
|
|
205
103
|
const dialogDescriptionId = useInstanceId(
|
|
206
104
|
LinkUI,
|
|
207
|
-
|
|
105
|
+
'link-ui-link-control__description'
|
|
208
106
|
);
|
|
209
107
|
|
|
108
|
+
const blockEditingMode = useBlockEditingMode();
|
|
109
|
+
|
|
210
110
|
return (
|
|
211
111
|
<Popover
|
|
212
112
|
ref={ ref }
|
|
@@ -215,7 +115,7 @@ function UnforwardedLinkUI( props, ref ) {
|
|
|
215
115
|
anchor={ props.anchor }
|
|
216
116
|
shift
|
|
217
117
|
>
|
|
218
|
-
{ ! addingBlock && (
|
|
118
|
+
{ ! addingBlock && ! addingPage && (
|
|
219
119
|
<div
|
|
220
120
|
role="dialog"
|
|
221
121
|
aria-labelledby={ dialogTitleId }
|
|
@@ -235,48 +135,41 @@ function UnforwardedLinkUI( props, ref ) {
|
|
|
235
135
|
hasRichPreviews
|
|
236
136
|
value={ link }
|
|
237
137
|
showInitialSuggestions
|
|
238
|
-
withCreateSuggestion={
|
|
239
|
-
createSuggestion={ handleCreate }
|
|
240
|
-
createSuggestionButtonText={ ( searchTerm ) => {
|
|
241
|
-
let format;
|
|
242
|
-
|
|
243
|
-
if ( type === 'post' ) {
|
|
244
|
-
/* translators: %s: search term. */
|
|
245
|
-
format = __(
|
|
246
|
-
'Create draft post: <mark>%s</mark>'
|
|
247
|
-
);
|
|
248
|
-
} else {
|
|
249
|
-
/* translators: %s: search term. */
|
|
250
|
-
format = __(
|
|
251
|
-
'Create draft page: <mark>%s</mark>'
|
|
252
|
-
);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
return createInterpolateElement(
|
|
256
|
-
sprintf( format, searchTerm ),
|
|
257
|
-
{
|
|
258
|
-
mark: <mark />,
|
|
259
|
-
}
|
|
260
|
-
);
|
|
261
|
-
} }
|
|
138
|
+
withCreateSuggestion={ false }
|
|
262
139
|
noDirectEntry={ !! type }
|
|
263
140
|
noURLSuggestion={ !! type }
|
|
264
141
|
suggestionsQuery={ getSuggestionsQuery( type, kind ) }
|
|
265
142
|
onChange={ props.onChange }
|
|
266
143
|
onRemove={ props.onRemove }
|
|
267
144
|
onCancel={ props.onCancel }
|
|
268
|
-
renderControlBottom={ () =>
|
|
269
|
-
|
|
270
|
-
|
|
145
|
+
renderControlBottom={ () => {
|
|
146
|
+
// Don't show the tools when there is submitted link (preview state).
|
|
147
|
+
if ( link?.url?.length ) {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return (
|
|
271
152
|
<LinkUITools
|
|
272
153
|
focusAddBlockButton={ focusAddBlockButton }
|
|
154
|
+
focusAddPageButton={ focusAddPageButton }
|
|
273
155
|
setAddingBlock={ () => {
|
|
274
156
|
setAddingBlock( true );
|
|
275
157
|
setFocusAddBlockButton( false );
|
|
276
158
|
} }
|
|
159
|
+
setAddingPage={ () => {
|
|
160
|
+
setAddingPage( true );
|
|
161
|
+
setFocusAddPageButton( false );
|
|
162
|
+
} }
|
|
163
|
+
canAddPage={
|
|
164
|
+
permissions?.canCreate &&
|
|
165
|
+
type === 'page'
|
|
166
|
+
}
|
|
167
|
+
canAddBlock={
|
|
168
|
+
blockEditingMode === 'default'
|
|
169
|
+
}
|
|
277
170
|
/>
|
|
278
|
-
)
|
|
279
|
-
}
|
|
171
|
+
);
|
|
172
|
+
} }
|
|
280
173
|
/>
|
|
281
174
|
</div>
|
|
282
175
|
) }
|
|
@@ -287,7 +180,22 @@ function UnforwardedLinkUI( props, ref ) {
|
|
|
287
180
|
onBack={ () => {
|
|
288
181
|
setAddingBlock( false );
|
|
289
182
|
setFocusAddBlockButton( true );
|
|
183
|
+
setFocusAddPageButton( false );
|
|
184
|
+
} }
|
|
185
|
+
onBlockInsert={ props?.onBlockInsert }
|
|
186
|
+
/>
|
|
187
|
+
) }
|
|
188
|
+
|
|
189
|
+
{ addingPage && (
|
|
190
|
+
<LinkUIPageCreator
|
|
191
|
+
postType={ postType }
|
|
192
|
+
onBack={ () => {
|
|
193
|
+
setAddingPage( false );
|
|
194
|
+
setFocusAddPageButton( true );
|
|
195
|
+
setFocusAddBlockButton( false );
|
|
290
196
|
} }
|
|
197
|
+
onPageCreated={ handlePageCreated }
|
|
198
|
+
initialTitle={ link?.url || '' }
|
|
291
199
|
/>
|
|
292
200
|
) }
|
|
293
201
|
</Popover>
|
|
@@ -296,9 +204,17 @@ function UnforwardedLinkUI( props, ref ) {
|
|
|
296
204
|
|
|
297
205
|
export const LinkUI = forwardRef( UnforwardedLinkUI );
|
|
298
206
|
|
|
299
|
-
const LinkUITools = ( {
|
|
207
|
+
const LinkUITools = ( {
|
|
208
|
+
setAddingBlock,
|
|
209
|
+
setAddingPage,
|
|
210
|
+
focusAddBlockButton,
|
|
211
|
+
focusAddPageButton,
|
|
212
|
+
canAddPage,
|
|
213
|
+
canAddBlock,
|
|
214
|
+
} ) => {
|
|
300
215
|
const blockInserterAriaRole = 'listbox';
|
|
301
216
|
const addBlockButtonRef = useRef();
|
|
217
|
+
const addPageButtonRef = useRef();
|
|
302
218
|
|
|
303
219
|
// Focus the add block button when the popover is opened.
|
|
304
220
|
useEffect( () => {
|
|
@@ -307,20 +223,48 @@ const LinkUITools = ( { setAddingBlock, focusAddBlockButton } ) => {
|
|
|
307
223
|
}
|
|
308
224
|
}, [ focusAddBlockButton ] );
|
|
309
225
|
|
|
226
|
+
// Focus the add page button when the popover is opened.
|
|
227
|
+
useEffect( () => {
|
|
228
|
+
if ( focusAddPageButton ) {
|
|
229
|
+
addPageButtonRef.current?.focus();
|
|
230
|
+
}
|
|
231
|
+
}, [ focusAddPageButton ] );
|
|
232
|
+
|
|
233
|
+
// Don't render anything if neither button should be shown
|
|
234
|
+
if ( ! canAddPage && ! canAddBlock ) {
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
|
|
310
238
|
return (
|
|
311
|
-
<VStack className="link-ui-tools">
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
e
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
239
|
+
<VStack spacing={ 0 } className="link-ui-tools">
|
|
240
|
+
{ canAddPage && (
|
|
241
|
+
<Button
|
|
242
|
+
__next40pxDefaultSize
|
|
243
|
+
ref={ addPageButtonRef }
|
|
244
|
+
icon={ plus }
|
|
245
|
+
onClick={ ( e ) => {
|
|
246
|
+
e.preventDefault();
|
|
247
|
+
setAddingPage( true );
|
|
248
|
+
} }
|
|
249
|
+
aria-haspopup={ blockInserterAriaRole }
|
|
250
|
+
>
|
|
251
|
+
{ __( 'Create page' ) }
|
|
252
|
+
</Button>
|
|
253
|
+
) }
|
|
254
|
+
{ canAddBlock && (
|
|
255
|
+
<Button
|
|
256
|
+
__next40pxDefaultSize
|
|
257
|
+
ref={ addBlockButtonRef }
|
|
258
|
+
icon={ plus }
|
|
259
|
+
onClick={ ( e ) => {
|
|
260
|
+
e.preventDefault();
|
|
261
|
+
setAddingBlock( true );
|
|
262
|
+
} }
|
|
263
|
+
aria-haspopup={ blockInserterAriaRole }
|
|
264
|
+
>
|
|
265
|
+
{ __( 'Add block' ) }
|
|
266
|
+
</Button>
|
|
267
|
+
) }
|
|
324
268
|
</VStack>
|
|
325
269
|
);
|
|
326
270
|
};
|