@wordpress/editor 13.24.0 → 13.25.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/CHANGELOG.md +2 -0
- package/build/components/document-bar/index.js +152 -0
- package/build/components/document-bar/index.js.map +1 -0
- package/build/components/editor-canvas/edit-template-blocks-notification.js +106 -0
- package/build/components/editor-canvas/edit-template-blocks-notification.js.map +1 -0
- package/build/components/editor-canvas/index.js +292 -0
- package/build/components/editor-canvas/index.js.map +1 -0
- package/build/components/index.js +24 -8
- package/build/components/index.js.map +1 -1
- package/build/components/post-publish-button/index.js +1 -0
- package/build/components/post-publish-button/index.js.map +1 -1
- package/build/components/post-publish-panel/maybe-upload-media.js +2 -4
- package/build/components/post-publish-panel/maybe-upload-media.js.map +1 -1
- package/build/components/post-saved-state/index.js +1 -0
- package/build/components/post-saved-state/index.js.map +1 -1
- package/build/components/post-schedule/panel.js +1 -1
- package/build/components/post-schedule/panel.js.map +1 -1
- package/build/components/post-template/block-theme.js +99 -0
- package/build/components/post-template/block-theme.js.map +1 -0
- package/build/components/post-template/classic-theme.js +171 -0
- package/build/components/post-template/classic-theme.js.map +1 -0
- package/build/components/post-template/create-new-template-modal.js +98 -0
- package/build/components/post-template/create-new-template-modal.js.map +1 -0
- package/build/components/post-template/create-new-template.js +55 -0
- package/build/components/post-template/create-new-template.js.map +1 -0
- package/build/components/post-template/hooks.js +88 -0
- package/build/components/post-template/hooks.js.map +1 -0
- package/build/components/post-template/panel.js +71 -0
- package/build/components/post-template/panel.js.map +1 -0
- package/build/components/post-template/reset-default-template.js +48 -0
- package/build/components/post-template/reset-default-template.js.map +1 -0
- package/build/components/post-template/swap-template-button.js +84 -0
- package/build/components/post-template/swap-template-button.js.map +1 -0
- package/build/components/post-title/index.native.js +0 -1
- package/build/components/post-title/index.native.js.map +1 -1
- package/build/components/preview-dropdown/index.js +113 -0
- package/build/components/preview-dropdown/index.js.map +1 -0
- package/build/components/provider/index.js +36 -77
- package/build/components/provider/index.js.map +1 -1
- package/build/components/provider/index.native.js +17 -8
- package/build/components/provider/index.native.js.map +1 -1
- package/build/components/provider/navigation-block-editing-mode.js +40 -0
- package/build/components/provider/navigation-block-editing-mode.js.map +1 -0
- package/build/components/provider/use-block-editor-settings.js +9 -10
- package/build/components/provider/use-block-editor-settings.js.map +1 -1
- package/build/hooks/index.js +1 -0
- package/build/hooks/index.js.map +1 -1
- package/build/hooks/pattern-partial-syncing.js +49 -0
- package/build/hooks/pattern-partial-syncing.js.map +1 -0
- package/build/private-apis.js +4 -0
- package/build/private-apis.js.map +1 -1
- package/build/store/actions.js +59 -11
- package/build/store/actions.js.map +1 -1
- package/build/store/defaults.js +2 -1
- package/build/store/defaults.js.map +1 -1
- package/build/store/index.js +3 -0
- package/build/store/index.js.map +1 -1
- package/build/store/private-actions.js +52 -0
- package/build/store/private-actions.js.map +1 -0
- package/build/store/reducer.js +32 -27
- package/build/store/reducer.js.map +1 -1
- package/build/store/reducer.native.js +0 -1
- package/build/store/reducer.native.js.map +1 -1
- package/build/store/selectors.js +31 -10
- package/build/store/selectors.js.map +1 -1
- package/build-module/components/document-bar/index.js +144 -0
- package/build-module/components/document-bar/index.js.map +1 -0
- package/build-module/components/editor-canvas/edit-template-blocks-notification.js +100 -0
- package/build-module/components/editor-canvas/edit-template-blocks-notification.js.map +1 -0
- package/build-module/components/editor-canvas/index.js +283 -0
- package/build-module/components/editor-canvas/index.js.map +1 -0
- package/build-module/components/index.js +3 -1
- package/build-module/components/index.js.map +1 -1
- package/build-module/components/post-publish-button/index.js +1 -0
- package/build-module/components/post-publish-button/index.js.map +1 -1
- package/build-module/components/post-publish-panel/maybe-upload-media.js +2 -4
- package/build-module/components/post-publish-panel/maybe-upload-media.js.map +1 -1
- package/build-module/components/post-saved-state/index.js +1 -0
- package/build-module/components/post-saved-state/index.js.map +1 -1
- package/build-module/components/post-schedule/panel.js +1 -1
- package/build-module/components/post-schedule/panel.js.map +1 -1
- package/build-module/components/post-template/block-theme.js +91 -0
- package/build-module/components/post-template/block-theme.js.map +1 -0
- package/build-module/components/post-template/classic-theme.js +162 -0
- package/build-module/components/post-template/classic-theme.js.map +1 -0
- package/build-module/components/post-template/create-new-template-modal.js +91 -0
- package/build-module/components/post-template/create-new-template-modal.js.map +1 -0
- package/build-module/components/post-template/create-new-template.js +47 -0
- package/build-module/components/post-template/create-new-template.js.map +1 -0
- package/build-module/components/post-template/hooks.js +78 -0
- package/build-module/components/post-template/hooks.js.map +1 -0
- package/build-module/components/post-template/panel.js +63 -0
- package/build-module/components/post-template/panel.js.map +1 -0
- package/build-module/components/post-template/reset-default-template.js +41 -0
- package/build-module/components/post-template/reset-default-template.js.map +1 -0
- package/build-module/components/post-template/swap-template-button.js +77 -0
- package/build-module/components/post-template/swap-template-button.js.map +1 -0
- package/build-module/components/post-title/index.native.js +0 -1
- package/build-module/components/post-title/index.native.js.map +1 -1
- package/build-module/components/preview-dropdown/index.js +105 -0
- package/build-module/components/preview-dropdown/index.js.map +1 -0
- package/build-module/components/provider/index.js +37 -78
- package/build-module/components/provider/index.js.map +1 -1
- package/build-module/components/provider/index.native.js +18 -9
- package/build-module/components/provider/index.native.js.map +1 -1
- package/build-module/components/provider/navigation-block-editing-mode.js +34 -0
- package/build-module/components/provider/navigation-block-editing-mode.js.map +1 -0
- package/build-module/components/provider/use-block-editor-settings.js +9 -10
- package/build-module/components/provider/use-block-editor-settings.js.map +1 -1
- package/build-module/hooks/index.js +1 -0
- package/build-module/hooks/index.js.map +1 -1
- package/build-module/hooks/pattern-partial-syncing.js +46 -0
- package/build-module/hooks/pattern-partial-syncing.js.map +1 -0
- package/build-module/private-apis.js +4 -0
- package/build-module/private-apis.js.map +1 -1
- package/build-module/store/actions.js +53 -9
- package/build-module/store/actions.js.map +1 -1
- package/build-module/store/defaults.js +2 -1
- package/build-module/store/defaults.js.map +1 -1
- package/build-module/store/index.js +3 -0
- package/build-module/store/index.js.map +1 -1
- package/build-module/store/private-actions.js +44 -0
- package/build-module/store/private-actions.js.map +1 -0
- package/build-module/store/reducer.js +30 -26
- package/build-module/store/reducer.js.map +1 -1
- package/build-module/store/reducer.native.js +1 -2
- package/build-module/store/reducer.native.js.map +1 -1
- package/build-module/store/selectors.js +26 -6
- package/build-module/store/selectors.js.map +1 -1
- package/build-style/style-rtl.css +182 -0
- package/build-style/style.css +182 -0
- package/package.json +32 -31
- package/src/components/document-bar/index.js +182 -0
- package/src/components/document-bar/style.scss +130 -0
- package/src/components/editor-canvas/edit-template-blocks-notification.js +108 -0
- package/src/components/editor-canvas/index.js +381 -0
- package/src/components/index.js +3 -1
- package/src/components/post-publish-button/index.js +1 -0
- package/src/components/post-publish-panel/maybe-upload-media.js +3 -8
- package/src/components/post-saved-state/index.js +1 -0
- package/src/components/post-saved-state/test/__snapshots__/index.js.snap +2 -2
- package/src/components/post-schedule/panel.js +1 -1
- package/src/components/post-template/block-theme.js +109 -0
- package/src/components/post-template/classic-theme.js +213 -0
- package/src/components/post-template/create-new-template-modal.js +139 -0
- package/src/components/post-template/create-new-template.js +50 -0
- package/src/components/post-template/hooks.js +95 -0
- package/src/components/post-template/panel.js +67 -0
- package/src/components/post-template/reset-default-template.js +43 -0
- package/src/components/post-template/style.scss +52 -0
- package/src/components/post-template/swap-template-button.js +83 -0
- package/src/components/post-title/index.native.js +0 -1
- package/src/components/preview-dropdown/index.js +136 -0
- package/src/components/preview-dropdown/style.scss +5 -0
- package/src/components/provider/index.js +39 -112
- package/src/components/provider/index.native.js +26 -12
- package/src/components/provider/navigation-block-editing-mode.js +37 -0
- package/src/components/provider/use-block-editor-settings.js +6 -9
- package/src/hooks/index.js +1 -0
- package/src/hooks/pattern-partial-syncing.js +73 -0
- package/src/private-apis.js +4 -0
- package/src/store/actions.js +51 -9
- package/src/store/defaults.js +1 -0
- package/src/store/index.js +3 -0
- package/src/store/private-actions.js +61 -0
- package/src/store/reducer.js +32 -27
- package/src/store/reducer.native.js +0 -2
- package/src/store/selectors.js +64 -42
- package/src/store/test/selectors.js +88 -147
- package/src/style.scss +3 -0
- package/build/components/post-template/index.js +0 -66
- package/build/components/post-template/index.js.map +0 -1
- package/build-module/components/post-template/index.js +0 -57
- package/build-module/components/post-template/index.js.map +0 -1
- package/src/components/post-template/index.js +0 -64
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { useMemo, useState, useCallback } from '@wordpress/element';
|
|
5
|
+
import { decodeEntities } from '@wordpress/html-entities';
|
|
6
|
+
import { __experimentalBlockPatternsList as BlockPatternsList } from '@wordpress/block-editor';
|
|
7
|
+
import { MenuItem, Modal } from '@wordpress/components';
|
|
8
|
+
import { __ } from '@wordpress/i18n';
|
|
9
|
+
import { useDispatch } from '@wordpress/data';
|
|
10
|
+
import { store as coreStore } from '@wordpress/core-data';
|
|
11
|
+
import { parse } from '@wordpress/blocks';
|
|
12
|
+
import { useAsyncList } from '@wordpress/compose';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Internal dependencies
|
|
16
|
+
*/
|
|
17
|
+
import { useAvailableTemplates, useEditedPostContext } from './hooks';
|
|
18
|
+
|
|
19
|
+
export default function SwapTemplateButton( { onClick } ) {
|
|
20
|
+
const [ showModal, setShowModal ] = useState( false );
|
|
21
|
+
const availableTemplates = useAvailableTemplates();
|
|
22
|
+
const onClose = useCallback( () => {
|
|
23
|
+
setShowModal( false );
|
|
24
|
+
}, [] );
|
|
25
|
+
const { postType, postId } = useEditedPostContext();
|
|
26
|
+
const { editEntityRecord } = useDispatch( coreStore );
|
|
27
|
+
if ( ! availableTemplates?.length ) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
const onTemplateSelect = async ( template ) => {
|
|
31
|
+
editEntityRecord(
|
|
32
|
+
'postType',
|
|
33
|
+
postType,
|
|
34
|
+
postId,
|
|
35
|
+
{ template: template.name },
|
|
36
|
+
{ undoIgnore: true }
|
|
37
|
+
);
|
|
38
|
+
onClose(); // Close the template suggestions modal first.
|
|
39
|
+
onClick();
|
|
40
|
+
};
|
|
41
|
+
return (
|
|
42
|
+
<>
|
|
43
|
+
<MenuItem onClick={ () => setShowModal( true ) }>
|
|
44
|
+
{ __( 'Swap template' ) }
|
|
45
|
+
</MenuItem>
|
|
46
|
+
{ showModal && (
|
|
47
|
+
<Modal
|
|
48
|
+
title={ __( 'Choose a template' ) }
|
|
49
|
+
onRequestClose={ onClose }
|
|
50
|
+
overlayClassName="editor-post-template__swap-template-modal"
|
|
51
|
+
isFullScreen
|
|
52
|
+
>
|
|
53
|
+
<div className="editor-post-template__swap-template-modal-content">
|
|
54
|
+
<TemplatesList onSelect={ onTemplateSelect } />
|
|
55
|
+
</div>
|
|
56
|
+
</Modal>
|
|
57
|
+
) }
|
|
58
|
+
</>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function TemplatesList( { onSelect } ) {
|
|
63
|
+
const availableTemplates = useAvailableTemplates();
|
|
64
|
+
const templatesAsPatterns = useMemo(
|
|
65
|
+
() =>
|
|
66
|
+
availableTemplates.map( ( template ) => ( {
|
|
67
|
+
name: template.slug,
|
|
68
|
+
blocks: parse( template.content.raw ),
|
|
69
|
+
title: decodeEntities( template.title.rendered ),
|
|
70
|
+
id: template.id,
|
|
71
|
+
} ) ),
|
|
72
|
+
[ availableTemplates ]
|
|
73
|
+
);
|
|
74
|
+
const shownTemplates = useAsyncList( templatesAsPatterns );
|
|
75
|
+
return (
|
|
76
|
+
<BlockPatternsList
|
|
77
|
+
label={ __( 'Templates' ) }
|
|
78
|
+
blockPatterns={ templatesAsPatterns }
|
|
79
|
+
shownPatterns={ shownTemplates }
|
|
80
|
+
onClickPattern={ onSelect }
|
|
81
|
+
/>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
@@ -155,7 +155,6 @@ class PostTitle extends Component {
|
|
|
155
155
|
tagsToEliminate={ [ 'strong' ] }
|
|
156
156
|
unstableOnFocus={ this.props.onSelect }
|
|
157
157
|
onBlur={ this.props.onBlur } // Always assign onBlur as a props.
|
|
158
|
-
multiline={ false }
|
|
159
158
|
style={ titleStyles }
|
|
160
159
|
styles={ styles }
|
|
161
160
|
fontSize={ 24 }
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { useViewportMatch } from '@wordpress/compose';
|
|
5
|
+
import {
|
|
6
|
+
DropdownMenu,
|
|
7
|
+
MenuGroup,
|
|
8
|
+
MenuItem,
|
|
9
|
+
VisuallyHidden,
|
|
10
|
+
Icon,
|
|
11
|
+
} from '@wordpress/components';
|
|
12
|
+
import { __ } from '@wordpress/i18n';
|
|
13
|
+
import { check, desktop, mobile, tablet, external } from '@wordpress/icons';
|
|
14
|
+
import { useSelect, useDispatch } from '@wordpress/data';
|
|
15
|
+
import { store as coreStore } from '@wordpress/core-data';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Internal dependencies
|
|
19
|
+
*/
|
|
20
|
+
import { store as editorStore } from '../../store';
|
|
21
|
+
import PostPreviewButton from '../post-preview-button';
|
|
22
|
+
|
|
23
|
+
export default function PreviewDropdown( {
|
|
24
|
+
showIconLabels,
|
|
25
|
+
forceIsAutosaveable,
|
|
26
|
+
disabled,
|
|
27
|
+
} ) {
|
|
28
|
+
const { deviceType, homeUrl, isTemplate, isViewable } = useSelect(
|
|
29
|
+
( select ) => {
|
|
30
|
+
const { getDeviceType, getCurrentPostType } = select( editorStore );
|
|
31
|
+
const { getUnstableBase, getPostType } = select( coreStore );
|
|
32
|
+
const _currentPostType = getCurrentPostType();
|
|
33
|
+
return {
|
|
34
|
+
deviceType: getDeviceType(),
|
|
35
|
+
homeUrl: getUnstableBase()?.home,
|
|
36
|
+
isTemplate: _currentPostType === 'wp_template',
|
|
37
|
+
isViewable: getPostType( _currentPostType )?.viewable ?? false,
|
|
38
|
+
};
|
|
39
|
+
},
|
|
40
|
+
[]
|
|
41
|
+
);
|
|
42
|
+
const { setDeviceType } = useDispatch( editorStore );
|
|
43
|
+
const isMobile = useViewportMatch( 'medium', '<' );
|
|
44
|
+
if ( isMobile ) return null;
|
|
45
|
+
|
|
46
|
+
const popoverProps = {
|
|
47
|
+
placement: 'bottom-end',
|
|
48
|
+
};
|
|
49
|
+
const toggleProps = {
|
|
50
|
+
className: 'editor-preview-dropdown__toggle',
|
|
51
|
+
size: 'compact',
|
|
52
|
+
showTooltip: ! showIconLabels,
|
|
53
|
+
disabled,
|
|
54
|
+
__experimentalIsFocusable: disabled,
|
|
55
|
+
};
|
|
56
|
+
const menuProps = {
|
|
57
|
+
'aria-label': __( 'View options' ),
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const deviceIcons = {
|
|
61
|
+
mobile,
|
|
62
|
+
tablet,
|
|
63
|
+
desktop,
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<DropdownMenu
|
|
68
|
+
className="editor-preview-dropdown"
|
|
69
|
+
popoverProps={ popoverProps }
|
|
70
|
+
toggleProps={ toggleProps }
|
|
71
|
+
menuProps={ menuProps }
|
|
72
|
+
icon={ deviceIcons[ deviceType.toLowerCase() ] }
|
|
73
|
+
label={ __( 'View' ) }
|
|
74
|
+
disableOpenOnArrowDown={ disabled }
|
|
75
|
+
>
|
|
76
|
+
{ ( { onClose } ) => (
|
|
77
|
+
<>
|
|
78
|
+
<MenuGroup>
|
|
79
|
+
<MenuItem
|
|
80
|
+
onClick={ () => setDeviceType( 'Desktop' ) }
|
|
81
|
+
icon={ deviceType === 'Desktop' && check }
|
|
82
|
+
>
|
|
83
|
+
{ __( 'Desktop' ) }
|
|
84
|
+
</MenuItem>
|
|
85
|
+
<MenuItem
|
|
86
|
+
onClick={ () => setDeviceType( 'Tablet' ) }
|
|
87
|
+
icon={ deviceType === 'Tablet' && check }
|
|
88
|
+
>
|
|
89
|
+
{ __( 'Tablet' ) }
|
|
90
|
+
</MenuItem>
|
|
91
|
+
<MenuItem
|
|
92
|
+
onClick={ () => setDeviceType( 'Mobile' ) }
|
|
93
|
+
icon={ deviceType === 'Mobile' && check }
|
|
94
|
+
>
|
|
95
|
+
{ __( 'Mobile' ) }
|
|
96
|
+
</MenuItem>
|
|
97
|
+
</MenuGroup>
|
|
98
|
+
{ isTemplate && (
|
|
99
|
+
<MenuGroup>
|
|
100
|
+
<MenuItem
|
|
101
|
+
href={ homeUrl }
|
|
102
|
+
target="_blank"
|
|
103
|
+
icon={ external }
|
|
104
|
+
onClick={ onClose }
|
|
105
|
+
>
|
|
106
|
+
{ __( 'View site' ) }
|
|
107
|
+
<VisuallyHidden as="span">
|
|
108
|
+
{
|
|
109
|
+
/* translators: accessibility text */
|
|
110
|
+
__( '(opens in a new tab)' )
|
|
111
|
+
}
|
|
112
|
+
</VisuallyHidden>
|
|
113
|
+
</MenuItem>
|
|
114
|
+
</MenuGroup>
|
|
115
|
+
) }
|
|
116
|
+
{ isViewable && (
|
|
117
|
+
<MenuGroup>
|
|
118
|
+
<PostPreviewButton
|
|
119
|
+
className="editor-preview-dropdown__button-external"
|
|
120
|
+
role="menuitem"
|
|
121
|
+
forceIsAutosaveable={ forceIsAutosaveable }
|
|
122
|
+
textContent={
|
|
123
|
+
<>
|
|
124
|
+
{ __( 'Preview in new tab' ) }
|
|
125
|
+
<Icon icon={ external } />
|
|
126
|
+
</>
|
|
127
|
+
}
|
|
128
|
+
onPreview={ onClose }
|
|
129
|
+
/>
|
|
130
|
+
</MenuGroup>
|
|
131
|
+
) }
|
|
132
|
+
</>
|
|
133
|
+
) }
|
|
134
|
+
</DropdownMenu>
|
|
135
|
+
);
|
|
136
|
+
}
|
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
BlockEditorProvider,
|
|
10
10
|
BlockContextProvider,
|
|
11
11
|
privateApis as blockEditorPrivateApis,
|
|
12
|
-
store as blockEditorStore,
|
|
13
12
|
} from '@wordpress/block-editor';
|
|
14
13
|
import { store as noticesStore } from '@wordpress/notices';
|
|
15
14
|
import { privateApis as editPatternsPrivateApis } from '@wordpress/patterns';
|
|
@@ -23,73 +22,13 @@ import { store as editorStore } from '../../store';
|
|
|
23
22
|
import useBlockEditorSettings from './use-block-editor-settings';
|
|
24
23
|
import { unlock } from '../../lock-unlock';
|
|
25
24
|
import DisableNonPageContentBlocks from './disable-non-page-content-blocks';
|
|
26
|
-
import
|
|
25
|
+
import NavigationBlockEditingMode from './navigation-block-editing-mode';
|
|
27
26
|
|
|
28
27
|
const { ExperimentalBlockEditorProvider } = unlock( blockEditorPrivateApis );
|
|
29
28
|
const { PatternsMenuItems } = unlock( editPatternsPrivateApis );
|
|
30
29
|
|
|
31
30
|
const noop = () => {};
|
|
32
31
|
|
|
33
|
-
/**
|
|
34
|
-
* For the Navigation block editor, we need to force the block editor to contentOnly for that block.
|
|
35
|
-
*
|
|
36
|
-
* Set block editing mode to contentOnly when entering Navigation focus mode.
|
|
37
|
-
* this ensures that non-content controls on the block will be hidden and thus
|
|
38
|
-
* the user can focus on editing the Navigation Menu content only.
|
|
39
|
-
*
|
|
40
|
-
* @param {string} navigationBlockClientId ClientId.
|
|
41
|
-
*/
|
|
42
|
-
function useForceFocusModeForNavigation( navigationBlockClientId ) {
|
|
43
|
-
const { setBlockEditingMode, unsetBlockEditingMode } =
|
|
44
|
-
useDispatch( blockEditorStore );
|
|
45
|
-
|
|
46
|
-
useEffect( () => {
|
|
47
|
-
if ( ! navigationBlockClientId ) {
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
setBlockEditingMode( navigationBlockClientId, 'contentOnly' );
|
|
52
|
-
|
|
53
|
-
return () => {
|
|
54
|
-
unsetBlockEditingMode( navigationBlockClientId );
|
|
55
|
-
};
|
|
56
|
-
}, [
|
|
57
|
-
navigationBlockClientId,
|
|
58
|
-
unsetBlockEditingMode,
|
|
59
|
-
setBlockEditingMode,
|
|
60
|
-
] );
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Helper method to extract the post content block types from a template.
|
|
65
|
-
*
|
|
66
|
-
* @param {Array} blocks Template blocks.
|
|
67
|
-
*
|
|
68
|
-
* @return {Array} Flattened object.
|
|
69
|
-
*/
|
|
70
|
-
function extractPageContentBlockTypesFromTemplateBlocks( blocks ) {
|
|
71
|
-
const result = [];
|
|
72
|
-
for ( let i = 0; i < blocks.length; i++ ) {
|
|
73
|
-
// Since the Query Block could contain PAGE_CONTENT_BLOCK_TYPES block types,
|
|
74
|
-
// we skip it because we only want to render stand-alone page content blocks in the block list.
|
|
75
|
-
if ( blocks[ i ].name === 'core/query' ) {
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
if ( PAGE_CONTENT_BLOCK_TYPES.includes( blocks[ i ].name ) ) {
|
|
79
|
-
result.push( createBlock( blocks[ i ].name ) );
|
|
80
|
-
}
|
|
81
|
-
if ( blocks[ i ].innerBlocks.length ) {
|
|
82
|
-
result.push(
|
|
83
|
-
...extractPageContentBlockTypesFromTemplateBlocks(
|
|
84
|
-
blocks[ i ].innerBlocks
|
|
85
|
-
)
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return result;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
32
|
/**
|
|
94
33
|
* Depending on the post, template and template mode,
|
|
95
34
|
* returns the appropriate blocks and change handlers for the block editor provider.
|
|
@@ -111,7 +50,7 @@ function useBlockEditorProps( post, template, mode ) {
|
|
|
111
50
|
useEntityBlockEditor( 'postType', template?.type, {
|
|
112
51
|
id: template?.id,
|
|
113
52
|
} );
|
|
114
|
-
const
|
|
53
|
+
const maybeNavigationBlocks = useMemo( () => {
|
|
115
54
|
if ( post.type === 'wp_navigation' ) {
|
|
116
55
|
return [
|
|
117
56
|
createBlock( 'core/navigation', {
|
|
@@ -123,33 +62,13 @@ function useBlockEditorProps( post, template, mode ) {
|
|
|
123
62
|
} ),
|
|
124
63
|
];
|
|
125
64
|
}
|
|
65
|
+
}, [ post.type, post.id ] );
|
|
126
66
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
return [
|
|
133
|
-
createBlock(
|
|
134
|
-
'core/group',
|
|
135
|
-
{
|
|
136
|
-
layout: { type: 'constrained' },
|
|
137
|
-
style: {
|
|
138
|
-
spacing: {
|
|
139
|
-
margin: {
|
|
140
|
-
top: '4em', // Mimics the post editor.
|
|
141
|
-
},
|
|
142
|
-
},
|
|
143
|
-
},
|
|
144
|
-
},
|
|
145
|
-
postContentBlocks.length
|
|
146
|
-
? postContentBlocks
|
|
147
|
-
: [
|
|
148
|
-
createBlock( 'core/post-title' ),
|
|
149
|
-
createBlock( 'core/post-content' ),
|
|
150
|
-
]
|
|
151
|
-
),
|
|
152
|
-
];
|
|
67
|
+
// It is important that we don't create a new instance of blocks on every change
|
|
68
|
+
// We should only create a new instance if the blocks them selves change, not a dependency of them.
|
|
69
|
+
const blocks = useMemo( () => {
|
|
70
|
+
if ( maybeNavigationBlocks ) {
|
|
71
|
+
return maybeNavigationBlocks;
|
|
153
72
|
}
|
|
154
73
|
|
|
155
74
|
if ( rootLevelPost === 'template' ) {
|
|
@@ -157,21 +76,14 @@ function useBlockEditorProps( post, template, mode ) {
|
|
|
157
76
|
}
|
|
158
77
|
|
|
159
78
|
return postBlocks;
|
|
160
|
-
}, [
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
post.id,
|
|
166
|
-
mode,
|
|
167
|
-
] );
|
|
79
|
+
}, [ maybeNavigationBlocks, rootLevelPost, templateBlocks, postBlocks ] );
|
|
80
|
+
|
|
81
|
+
// Handle fallback to postBlocks outside of the above useMemo, to ensure
|
|
82
|
+
// that constructed block templates that call `createBlock` are not generated
|
|
83
|
+
// too frequently. This ensures that clientIds are stable.
|
|
168
84
|
const disableRootLevelChanges =
|
|
169
85
|
( !! template && mode === 'template-locked' ) ||
|
|
170
|
-
post.type === 'wp_navigation'
|
|
171
|
-
mode === 'post-only';
|
|
172
|
-
const navigationBlockClientId =
|
|
173
|
-
post.type === 'wp_navigation' && blocks && blocks[ 0 ]?.clientId;
|
|
174
|
-
useForceFocusModeForNavigation( navigationBlockClientId );
|
|
86
|
+
post.type === 'wp_navigation';
|
|
175
87
|
if ( disableRootLevelChanges ) {
|
|
176
88
|
return [ blocks, noop, noop ];
|
|
177
89
|
}
|
|
@@ -252,11 +164,12 @@ export const ExperimentalEditorProvider = withRegistryProvider(
|
|
|
252
164
|
updatePostLock,
|
|
253
165
|
setupEditor,
|
|
254
166
|
updateEditorSettings,
|
|
255
|
-
|
|
256
|
-
|
|
167
|
+
setCurrentTemplateId,
|
|
168
|
+
setEditedPost,
|
|
169
|
+
setRenderingMode,
|
|
170
|
+
} = unlock( useDispatch( editorStore ) );
|
|
257
171
|
const { createWarningNotice } = useDispatch( noticesStore );
|
|
258
172
|
|
|
259
|
-
// Initialize and tear down the editor.
|
|
260
173
|
// Ideally this should be synced on each change and not just something you do once.
|
|
261
174
|
useLayoutEffect( () => {
|
|
262
175
|
// Assume that we don't need to initialize in the case of an error recovery.
|
|
@@ -282,17 +195,28 @@ export const ExperimentalEditorProvider = withRegistryProvider(
|
|
|
282
195
|
}
|
|
283
196
|
);
|
|
284
197
|
}
|
|
285
|
-
|
|
286
|
-
return () => {
|
|
287
|
-
__experimentalTearDownEditor();
|
|
288
|
-
};
|
|
289
198
|
}, [] );
|
|
290
199
|
|
|
200
|
+
// Synchronizes the active post with the state
|
|
201
|
+
useEffect( () => {
|
|
202
|
+
setEditedPost( post.type, post.id );
|
|
203
|
+
}, [ post.type, post.id ] );
|
|
204
|
+
|
|
291
205
|
// Synchronize the editor settings as they change.
|
|
292
206
|
useEffect( () => {
|
|
293
207
|
updateEditorSettings( settings );
|
|
294
208
|
}, [ settings, updateEditorSettings ] );
|
|
295
209
|
|
|
210
|
+
// Synchronizes the active template with the state.
|
|
211
|
+
useEffect( () => {
|
|
212
|
+
setCurrentTemplateId( template?.id );
|
|
213
|
+
}, [ template?.id, setCurrentTemplateId ] );
|
|
214
|
+
|
|
215
|
+
// Sets the right rendering mode when loading the editor.
|
|
216
|
+
useEffect( () => {
|
|
217
|
+
setRenderingMode( settings.defaultRenderingMode ?? 'post-only' );
|
|
218
|
+
}, [ settings.defaultRenderingMode, setRenderingMode ] );
|
|
219
|
+
|
|
296
220
|
if ( ! isReady ) {
|
|
297
221
|
return null;
|
|
298
222
|
}
|
|
@@ -315,9 +239,12 @@ export const ExperimentalEditorProvider = withRegistryProvider(
|
|
|
315
239
|
>
|
|
316
240
|
{ children }
|
|
317
241
|
<PatternsMenuItems />
|
|
318
|
-
{
|
|
319
|
-
|
|
320
|
-
)
|
|
242
|
+
{ mode === 'template-locked' && (
|
|
243
|
+
<DisableNonPageContentBlocks />
|
|
244
|
+
) }
|
|
245
|
+
{ type === 'wp_navigation' && (
|
|
246
|
+
<NavigationBlockEditingMode />
|
|
247
|
+
) }
|
|
321
248
|
</BlockEditorProviderComponent>
|
|
322
249
|
</BlockContextProvider>
|
|
323
250
|
</EntityProvider>
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
parse,
|
|
28
28
|
serialize,
|
|
29
29
|
getUnregisteredTypeHandlerName,
|
|
30
|
+
getBlockType,
|
|
30
31
|
createBlock,
|
|
31
32
|
} from '@wordpress/blocks';
|
|
32
33
|
import { withDispatch, withSelect } from '@wordpress/data';
|
|
@@ -35,6 +36,7 @@ import { applyFilters } from '@wordpress/hooks';
|
|
|
35
36
|
import { store as blockEditorStore } from '@wordpress/block-editor';
|
|
36
37
|
import { getGlobalStyles, getColorsAndGradients } from '@wordpress/components';
|
|
37
38
|
import { NEW_BLOCK_TYPES } from '@wordpress/block-library';
|
|
39
|
+
import { __ } from '@wordpress/i18n';
|
|
38
40
|
|
|
39
41
|
const postTypeEntities = [
|
|
40
42
|
{ name: 'post', baseURL: '/wp/v2/posts' },
|
|
@@ -94,6 +96,7 @@ class NativeEditorProvider extends Component {
|
|
|
94
96
|
componentDidMount() {
|
|
95
97
|
const {
|
|
96
98
|
capabilities,
|
|
99
|
+
createErrorNotice,
|
|
97
100
|
locale,
|
|
98
101
|
hostAppNamespace,
|
|
99
102
|
updateEditorSettings,
|
|
@@ -136,17 +139,26 @@ class NativeEditorProvider extends Component {
|
|
|
136
139
|
this.subscriptionParentMediaAppend = subscribeMediaAppend(
|
|
137
140
|
( payload ) => {
|
|
138
141
|
const blockName = 'core/' + payload.mediaType;
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
142
|
+
const blockType = getBlockType( blockName );
|
|
143
|
+
|
|
144
|
+
if ( blockType && blockType?.name ) {
|
|
145
|
+
const newBlock = createBlock( blockType.name, {
|
|
146
|
+
id: payload.mediaId,
|
|
147
|
+
[ payload.mediaType === 'image' ? 'url' : 'src' ]:
|
|
148
|
+
payload.mediaUrl,
|
|
149
|
+
} );
|
|
150
|
+
|
|
151
|
+
const indexAfterSelected =
|
|
152
|
+
this.props.selectedBlockIndex + 1;
|
|
153
|
+
const insertionIndex =
|
|
154
|
+
indexAfterSelected || this.props.blockCount;
|
|
155
|
+
|
|
156
|
+
this.props.insertBlock( newBlock, insertionIndex );
|
|
157
|
+
} else {
|
|
158
|
+
createErrorNotice(
|
|
159
|
+
__( 'File type not supported as a media file.' )
|
|
160
|
+
);
|
|
161
|
+
}
|
|
150
162
|
}
|
|
151
163
|
);
|
|
152
164
|
|
|
@@ -389,7 +401,8 @@ const ComposedNativeProvider = compose( [
|
|
|
389
401
|
dispatch( blockEditorStore );
|
|
390
402
|
const { switchEditorMode } = dispatch( editPostStore );
|
|
391
403
|
const { addEntities, receiveEntityRecords } = dispatch( coreStore );
|
|
392
|
-
const { createSuccessNotice } =
|
|
404
|
+
const { createSuccessNotice, createErrorNotice } =
|
|
405
|
+
dispatch( noticesStore );
|
|
393
406
|
|
|
394
407
|
return {
|
|
395
408
|
updateBlockEditorSettings: updateSettings,
|
|
@@ -397,6 +410,7 @@ const ComposedNativeProvider = compose( [
|
|
|
397
410
|
addEntities,
|
|
398
411
|
insertBlock,
|
|
399
412
|
createSuccessNotice,
|
|
413
|
+
createErrorNotice,
|
|
400
414
|
editTitle( title ) {
|
|
401
415
|
editPost( { title } );
|
|
402
416
|
},
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { useEffect } from '@wordpress/element';
|
|
5
|
+
import { useDispatch, useSelect } from '@wordpress/data';
|
|
6
|
+
import { store as blockEditorStore } from '@wordpress/block-editor';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* For the Navigation block editor, we need to force the block editor to contentOnly for that block.
|
|
10
|
+
*
|
|
11
|
+
* Set block editing mode to contentOnly when entering Navigation focus mode.
|
|
12
|
+
* this ensures that non-content controls on the block will be hidden and thus
|
|
13
|
+
* the user can focus on editing the Navigation Menu content only.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
export default function NavigationBlockEditingMode() {
|
|
17
|
+
// In the navigation block editor,
|
|
18
|
+
// the navigation block is the only root block.
|
|
19
|
+
const blockClientId = useSelect(
|
|
20
|
+
( select ) => select( blockEditorStore ).getBlockOrder()?.[ 0 ],
|
|
21
|
+
[]
|
|
22
|
+
);
|
|
23
|
+
const { setBlockEditingMode, unsetBlockEditingMode } =
|
|
24
|
+
useDispatch( blockEditorStore );
|
|
25
|
+
|
|
26
|
+
useEffect( () => {
|
|
27
|
+
if ( ! blockClientId ) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
setBlockEditingMode( blockClientId, 'contentOnly' );
|
|
32
|
+
|
|
33
|
+
return () => {
|
|
34
|
+
unsetBlockEditingMode( blockClientId );
|
|
35
|
+
};
|
|
36
|
+
}, [ blockClientId, unsetBlockEditingMode, setBlockEditingMode ] );
|
|
37
|
+
}
|
|
@@ -96,6 +96,8 @@ function useBlockEditorSettings( settings, postType, postId ) {
|
|
|
96
96
|
pageOnFront,
|
|
97
97
|
pageForPosts,
|
|
98
98
|
userPatternCategories,
|
|
99
|
+
restBlockPatterns,
|
|
100
|
+
restBlockPatternCategories,
|
|
99
101
|
} = useSelect(
|
|
100
102
|
( select ) => {
|
|
101
103
|
const isWeb = Platform.OS === 'web';
|
|
@@ -105,6 +107,8 @@ function useBlockEditorSettings( settings, postType, postId ) {
|
|
|
105
107
|
getEntityRecord,
|
|
106
108
|
getUserPatternCategories,
|
|
107
109
|
getEntityRecords,
|
|
110
|
+
getBlockPatterns,
|
|
111
|
+
getBlockPatternCategories,
|
|
108
112
|
} = select( coreStore );
|
|
109
113
|
|
|
110
114
|
const siteSettings = canUser( 'read', 'settings' )
|
|
@@ -127,6 +131,8 @@ function useBlockEditorSettings( settings, postType, postId ) {
|
|
|
127
131
|
pageOnFront: siteSettings?.page_on_front,
|
|
128
132
|
pageForPosts: siteSettings?.page_for_posts,
|
|
129
133
|
userPatternCategories: getUserPatternCategories(),
|
|
134
|
+
restBlockPatterns: getBlockPatterns(),
|
|
135
|
+
restBlockPatternCategories: getBlockPatternCategories(),
|
|
130
136
|
};
|
|
131
137
|
},
|
|
132
138
|
[ postType, postId ]
|
|
@@ -139,15 +145,6 @@ function useBlockEditorSettings( settings, postType, postId ) {
|
|
|
139
145
|
settings.__experimentalAdditionalBlockPatternCategories ?? // WP 6.0
|
|
140
146
|
settings.__experimentalBlockPatternCategories; // WP 5.9
|
|
141
147
|
|
|
142
|
-
const { restBlockPatterns, restBlockPatternCategories } = useSelect(
|
|
143
|
-
( select ) => ( {
|
|
144
|
-
restBlockPatterns: select( coreStore ).getBlockPatterns(),
|
|
145
|
-
restBlockPatternCategories:
|
|
146
|
-
select( coreStore ).getBlockPatternCategories(),
|
|
147
|
-
} ),
|
|
148
|
-
[]
|
|
149
|
-
);
|
|
150
|
-
|
|
151
148
|
const blockPatterns = useMemo(
|
|
152
149
|
() =>
|
|
153
150
|
[
|
package/src/hooks/index.js
CHANGED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { addFilter } from '@wordpress/hooks';
|
|
5
|
+
import { privateApis as patternsPrivateApis } from '@wordpress/patterns';
|
|
6
|
+
import { createHigherOrderComponent } from '@wordpress/compose';
|
|
7
|
+
import { useBlockEditingMode } from '@wordpress/block-editor';
|
|
8
|
+
import { hasBlockSupport } from '@wordpress/blocks';
|
|
9
|
+
import { useSelect } from '@wordpress/data';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Internal dependencies
|
|
13
|
+
*/
|
|
14
|
+
import { store as editorStore } from '../store';
|
|
15
|
+
import { unlock } from '../lock-unlock';
|
|
16
|
+
|
|
17
|
+
const {
|
|
18
|
+
PartialSyncingControls,
|
|
19
|
+
PATTERN_TYPES,
|
|
20
|
+
PARTIAL_SYNCING_SUPPORTED_BLOCKS,
|
|
21
|
+
} = unlock( patternsPrivateApis );
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Override the default edit UI to include a new block inspector control for
|
|
25
|
+
* assigning a partial syncing controls to supported blocks in the pattern editor.
|
|
26
|
+
* Currently, only the `core/paragraph` block is supported.
|
|
27
|
+
*
|
|
28
|
+
* @param {Component} BlockEdit Original component.
|
|
29
|
+
*
|
|
30
|
+
* @return {Component} Wrapped component.
|
|
31
|
+
*/
|
|
32
|
+
const withPartialSyncingControls = createHigherOrderComponent(
|
|
33
|
+
( BlockEdit ) => ( props ) => {
|
|
34
|
+
const blockEditingMode = useBlockEditingMode();
|
|
35
|
+
const hasCustomFieldsSupport = hasBlockSupport(
|
|
36
|
+
props.name,
|
|
37
|
+
'__experimentalConnections',
|
|
38
|
+
false
|
|
39
|
+
);
|
|
40
|
+
const isEditingPattern = useSelect(
|
|
41
|
+
( select ) =>
|
|
42
|
+
select( editorStore ).getCurrentPostType() ===
|
|
43
|
+
PATTERN_TYPES.user,
|
|
44
|
+
[]
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const shouldShowPartialSyncingControls =
|
|
48
|
+
hasCustomFieldsSupport &&
|
|
49
|
+
props.isSelected &&
|
|
50
|
+
isEditingPattern &&
|
|
51
|
+
blockEditingMode === 'default' &&
|
|
52
|
+
Object.keys( PARTIAL_SYNCING_SUPPORTED_BLOCKS ).includes(
|
|
53
|
+
props.name
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<>
|
|
58
|
+
<BlockEdit { ...props } />
|
|
59
|
+
{ shouldShowPartialSyncingControls && (
|
|
60
|
+
<PartialSyncingControls { ...props } />
|
|
61
|
+
) }
|
|
62
|
+
</>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
if ( window.__experimentalPatternPartialSyncing ) {
|
|
68
|
+
addFilter(
|
|
69
|
+
'editor.BlockEdit',
|
|
70
|
+
'core/editor/with-partial-syncing-controls',
|
|
71
|
+
withPartialSyncingControls
|
|
72
|
+
);
|
|
73
|
+
}
|