@wordpress/block-editor 12.10.3 → 12.10.4
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/components/block-styles/index.js +1 -2
- package/build/components/block-styles/index.js.map +1 -1
- package/build/components/iframe/index.js +9 -1
- package/build/components/iframe/index.js.map +1 -1
- package/build/components/inserter/block-patterns-filter.js +11 -10
- package/build/components/inserter/block-patterns-filter.js.map +1 -1
- package/build/components/inserter/block-patterns-tab.js +1 -1
- package/build/components/inserter/block-patterns-tab.js.map +1 -1
- package/build/components/inserter/media-tab/hooks.js +4 -33
- package/build/components/inserter/media-tab/hooks.js.map +1 -1
- package/build/components/list-view/block.js +1 -32
- package/build/components/list-view/block.js.map +1 -1
- package/build/components/list-view/branch.js +8 -1
- package/build/components/list-view/branch.js.map +1 -1
- package/build/components/list-view/index.js +8 -3
- package/build/components/list-view/index.js.map +1 -1
- package/build/components/list-view/utils.js +35 -0
- package/build/components/list-view/utils.js.map +1 -1
- package/build/store/actions.js +8 -12
- package/build/store/actions.js.map +1 -1
- package/build/store/private-selectors.js +55 -1
- package/build/store/private-selectors.js.map +1 -1
- package/build/store/reducer.js +19 -1
- package/build/store/reducer.js.map +1 -1
- package/build/utils/transform-styles/transforms/wrap.js +5 -0
- package/build/utils/transform-styles/transforms/wrap.js.map +1 -1
- package/build-module/components/block-styles/index.js +1 -2
- package/build-module/components/block-styles/index.js.map +1 -1
- package/build-module/components/iframe/index.js +9 -1
- package/build-module/components/iframe/index.js.map +1 -1
- package/build-module/components/inserter/block-patterns-filter.js +13 -12
- package/build-module/components/inserter/block-patterns-filter.js.map +1 -1
- package/build-module/components/inserter/block-patterns-tab.js +1 -1
- package/build-module/components/inserter/block-patterns-tab.js.map +1 -1
- package/build-module/components/inserter/media-tab/hooks.js +5 -34
- package/build-module/components/inserter/media-tab/hooks.js.map +1 -1
- package/build-module/components/list-view/block.js +3 -34
- package/build-module/components/list-view/block.js.map +1 -1
- package/build-module/components/list-view/branch.js +8 -1
- package/build-module/components/list-view/branch.js.map +1 -1
- package/build-module/components/list-view/index.js +8 -3
- package/build-module/components/list-view/index.js.map +1 -1
- package/build-module/components/list-view/utils.js +34 -0
- package/build-module/components/list-view/utils.js.map +1 -1
- package/build-module/store/actions.js +8 -12
- package/build-module/store/actions.js.map +1 -1
- package/build-module/store/private-selectors.js +52 -0
- package/build-module/store/private-selectors.js.map +1 -1
- package/build-module/store/reducer.js +18 -1
- package/build-module/store/reducer.js.map +1 -1
- package/build-module/utils/transform-styles/transforms/wrap.js +5 -0
- package/build-module/utils/transform-styles/transforms/wrap.js.map +1 -1
- package/build-style/style-rtl.css +1 -1
- package/build-style/style.css +1 -1
- package/package.json +32 -32
- package/src/components/block-styles/index.js +1 -4
- package/src/components/iframe/index.js +8 -1
- package/src/components/inserter/block-patterns-filter.js +22 -10
- package/src/components/inserter/block-patterns-tab.js +0 -3
- package/src/components/inserter/media-tab/hooks.js +10 -44
- package/src/components/inserter/style.scss +1 -1
- package/src/components/list-view/block.js +3 -43
- package/src/components/list-view/branch.js +11 -1
- package/src/components/list-view/index.js +8 -4
- package/src/components/list-view/utils.js +37 -0
- package/src/store/actions.js +7 -11
- package/src/store/private-selectors.js +72 -0
- package/src/store/reducer.js +17 -0
- package/src/store/test/actions.js +10 -16
- package/src/utils/transform-styles/transforms/test/__snapshots__/wrap.js.snap +13 -6
- package/src/utils/transform-styles/transforms/test/wrap.js +9 -0
- package/src/utils/transform-styles/transforms/wrap.js +5 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordpress/block-editor",
|
|
3
|
-
"version": "12.10.
|
|
3
|
+
"version": "12.10.4",
|
|
4
4
|
"description": "Generic block editor.",
|
|
5
5
|
"author": "The WordPress Contributors",
|
|
6
6
|
"license": "GPL-2.0-or-later",
|
|
@@ -35,36 +35,36 @@
|
|
|
35
35
|
"@emotion/react": "^11.7.1",
|
|
36
36
|
"@emotion/styled": "^11.6.0",
|
|
37
37
|
"@react-spring/web": "^9.4.5",
|
|
38
|
-
"@wordpress/a11y": "^3.42.
|
|
39
|
-
"@wordpress/api-fetch": "^6.39.
|
|
40
|
-
"@wordpress/blob": "^3.42.
|
|
41
|
-
"@wordpress/blocks": "^12.19.
|
|
42
|
-
"@wordpress/commands": "^0.13.
|
|
43
|
-
"@wordpress/components": "^25.8.
|
|
44
|
-
"@wordpress/compose": "^6.19.
|
|
45
|
-
"@wordpress/data": "^9.12.
|
|
46
|
-
"@wordpress/date": "^4.42.
|
|
47
|
-
"@wordpress/deprecated": "^3.42.
|
|
48
|
-
"@wordpress/dom": "^3.42.
|
|
49
|
-
"@wordpress/element": "^5.19.
|
|
50
|
-
"@wordpress/escape-html": "^2.42.
|
|
51
|
-
"@wordpress/hooks": "^3.42.
|
|
52
|
-
"@wordpress/html-entities": "^3.42.
|
|
53
|
-
"@wordpress/i18n": "^4.42.
|
|
54
|
-
"@wordpress/icons": "^9.33.
|
|
55
|
-
"@wordpress/is-shallow-equal": "^4.42.
|
|
56
|
-
"@wordpress/keyboard-shortcuts": "^4.19.
|
|
57
|
-
"@wordpress/keycodes": "^3.42.
|
|
58
|
-
"@wordpress/notices": "^4.10.
|
|
59
|
-
"@wordpress/preferences": "^3.19.
|
|
60
|
-
"@wordpress/private-apis": "^0.24.
|
|
61
|
-
"@wordpress/rich-text": "^6.19.
|
|
62
|
-
"@wordpress/shortcode": "^3.42.
|
|
63
|
-
"@wordpress/style-engine": "^1.25.
|
|
64
|
-
"@wordpress/token-list": "^2.42.
|
|
65
|
-
"@wordpress/url": "^3.43.
|
|
66
|
-
"@wordpress/warning": "^2.42.
|
|
67
|
-
"@wordpress/wordcount": "^3.42.
|
|
38
|
+
"@wordpress/a11y": "^3.42.4",
|
|
39
|
+
"@wordpress/api-fetch": "^6.39.4",
|
|
40
|
+
"@wordpress/blob": "^3.42.4",
|
|
41
|
+
"@wordpress/blocks": "^12.19.4",
|
|
42
|
+
"@wordpress/commands": "^0.13.4",
|
|
43
|
+
"@wordpress/components": "^25.8.4",
|
|
44
|
+
"@wordpress/compose": "^6.19.4",
|
|
45
|
+
"@wordpress/data": "^9.12.4",
|
|
46
|
+
"@wordpress/date": "^4.42.4",
|
|
47
|
+
"@wordpress/deprecated": "^3.42.4",
|
|
48
|
+
"@wordpress/dom": "^3.42.4",
|
|
49
|
+
"@wordpress/element": "^5.19.4",
|
|
50
|
+
"@wordpress/escape-html": "^2.42.4",
|
|
51
|
+
"@wordpress/hooks": "^3.42.4",
|
|
52
|
+
"@wordpress/html-entities": "^3.42.4",
|
|
53
|
+
"@wordpress/i18n": "^4.42.4",
|
|
54
|
+
"@wordpress/icons": "^9.33.4",
|
|
55
|
+
"@wordpress/is-shallow-equal": "^4.42.4",
|
|
56
|
+
"@wordpress/keyboard-shortcuts": "^4.19.4",
|
|
57
|
+
"@wordpress/keycodes": "^3.42.4",
|
|
58
|
+
"@wordpress/notices": "^4.10.4",
|
|
59
|
+
"@wordpress/preferences": "^3.19.4",
|
|
60
|
+
"@wordpress/private-apis": "^0.24.4",
|
|
61
|
+
"@wordpress/rich-text": "^6.19.4",
|
|
62
|
+
"@wordpress/shortcode": "^3.42.4",
|
|
63
|
+
"@wordpress/style-engine": "^1.25.4",
|
|
64
|
+
"@wordpress/token-list": "^2.42.4",
|
|
65
|
+
"@wordpress/url": "^3.43.4",
|
|
66
|
+
"@wordpress/warning": "^2.42.4",
|
|
67
|
+
"@wordpress/wordcount": "^3.42.4",
|
|
68
68
|
"change-case": "^4.1.2",
|
|
69
69
|
"classnames": "^2.3.1",
|
|
70
70
|
"colord": "^2.7.0",
|
|
@@ -86,5 +86,5 @@
|
|
|
86
86
|
"publishConfig": {
|
|
87
87
|
"access": "public"
|
|
88
88
|
},
|
|
89
|
-
"gitHead": "
|
|
89
|
+
"gitHead": "d1072bbcaf037a18d414da7865ebaf366a0e7062"
|
|
90
90
|
}
|
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
Popover,
|
|
15
15
|
} from '@wordpress/components';
|
|
16
16
|
import deprecated from '@wordpress/deprecated';
|
|
17
|
-
import { __ } from '@wordpress/i18n';
|
|
18
17
|
|
|
19
18
|
/**
|
|
20
19
|
* Internal dependencies
|
|
@@ -65,9 +64,7 @@ function BlockStyles( { clientId, onSwitch = noop, onHoverClassName = noop } ) {
|
|
|
65
64
|
<div className="block-editor-block-styles">
|
|
66
65
|
<div className="block-editor-block-styles__variants">
|
|
67
66
|
{ stylesToRender.map( ( style ) => {
|
|
68
|
-
const buttonText = style.
|
|
69
|
-
? __( 'Default' )
|
|
70
|
-
: style.label || style.name;
|
|
67
|
+
const buttonText = style.label || style.name;
|
|
71
68
|
|
|
72
69
|
return (
|
|
73
70
|
<Button
|
|
@@ -38,7 +38,14 @@ function bubbleEvent( event, Constructor, frame ) {
|
|
|
38
38
|
init[ key ] = event[ key ];
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
if
|
|
41
|
+
// Check if the event is a MouseEvent generated within the iframe.
|
|
42
|
+
// If so, adjust the coordinates to be relative to the position of
|
|
43
|
+
// the iframe. This ensures that components such as Draggable
|
|
44
|
+
// receive coordinates relative to the window, instead of relative
|
|
45
|
+
// to the iframe. Without this, the Draggable event handler would
|
|
46
|
+
// result in components "jumping" position as soon as the user
|
|
47
|
+
// drags over the iframe.
|
|
48
|
+
if ( event instanceof frame.contentDocument.defaultView.MouseEvent ) {
|
|
42
49
|
const rect = frame.getBoundingClientRect();
|
|
43
50
|
init.clientX += rect.left;
|
|
44
51
|
init.clientY += rect.top;
|
|
@@ -7,10 +7,11 @@ import {
|
|
|
7
7
|
DropdownMenu,
|
|
8
8
|
MenuGroup,
|
|
9
9
|
MenuItemsChoice,
|
|
10
|
+
ExternalLink,
|
|
10
11
|
} from '@wordpress/components';
|
|
11
12
|
import { __ } from '@wordpress/i18n';
|
|
12
13
|
import { Icon } from '@wordpress/icons';
|
|
13
|
-
import { useMemo } from '@wordpress/element';
|
|
14
|
+
import { useMemo, createInterpolateElement } from '@wordpress/element';
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Internal dependencies
|
|
@@ -73,13 +74,11 @@ export function BlockPatternsSyncFilter( {
|
|
|
73
74
|
{
|
|
74
75
|
value: SYNC_TYPES.full,
|
|
75
76
|
label: __( 'Synced' ),
|
|
76
|
-
info: __( 'Updated everywhere' ),
|
|
77
77
|
disabled: shouldDisableSyncFilter,
|
|
78
78
|
},
|
|
79
79
|
{
|
|
80
80
|
value: SYNC_TYPES.unsynced,
|
|
81
|
-
label: __( '
|
|
82
|
-
info: __( 'Edit freely' ),
|
|
81
|
+
label: __( 'Not synced' ),
|
|
83
82
|
disabled: shouldDisableSyncFilter,
|
|
84
83
|
},
|
|
85
84
|
],
|
|
@@ -95,20 +94,17 @@ export function BlockPatternsSyncFilter( {
|
|
|
95
94
|
},
|
|
96
95
|
{
|
|
97
96
|
value: PATTERN_TYPES.directory,
|
|
98
|
-
label: __( 'Directory' ),
|
|
99
|
-
info: __( 'Pattern directory & core' ),
|
|
97
|
+
label: __( 'Pattern Directory' ),
|
|
100
98
|
disabled: shouldDisableNonUserSources,
|
|
101
99
|
},
|
|
102
100
|
{
|
|
103
101
|
value: PATTERN_TYPES.theme,
|
|
104
|
-
label: __( 'Theme' ),
|
|
105
|
-
info: __( 'Bundled with the theme' ),
|
|
102
|
+
label: __( 'Theme & Plugins' ),
|
|
106
103
|
disabled: shouldDisableNonUserSources,
|
|
107
104
|
},
|
|
108
105
|
{
|
|
109
106
|
value: PATTERN_TYPES.user,
|
|
110
107
|
label: __( 'User' ),
|
|
111
|
-
info: __( 'Custom created' ),
|
|
112
108
|
},
|
|
113
109
|
],
|
|
114
110
|
[ shouldDisableNonUserSources ]
|
|
@@ -149,7 +145,7 @@ export function BlockPatternsSyncFilter( {
|
|
|
149
145
|
>
|
|
150
146
|
{ () => (
|
|
151
147
|
<>
|
|
152
|
-
<MenuGroup label={ __( '
|
|
148
|
+
<MenuGroup label={ __( 'Source' ) }>
|
|
153
149
|
<MenuItemsChoice
|
|
154
150
|
choices={ patternSourceMenuOptions }
|
|
155
151
|
onSelect={ ( value ) => {
|
|
@@ -175,6 +171,22 @@ export function BlockPatternsSyncFilter( {
|
|
|
175
171
|
value={ patternSyncFilter }
|
|
176
172
|
/>
|
|
177
173
|
</MenuGroup>
|
|
174
|
+
<div className="block-editor-tool-selector__help">
|
|
175
|
+
{ createInterpolateElement(
|
|
176
|
+
__(
|
|
177
|
+
'Patterns are available from the <Link>WordPress.org Pattern Directory</Link>, bundled in the active theme, or created by users on this site. Only patterns created on this site can be synced.'
|
|
178
|
+
),
|
|
179
|
+
{
|
|
180
|
+
Link: (
|
|
181
|
+
<ExternalLink
|
|
182
|
+
href={ __(
|
|
183
|
+
'https://wordpress.org/patterns/'
|
|
184
|
+
) }
|
|
185
|
+
/>
|
|
186
|
+
),
|
|
187
|
+
}
|
|
188
|
+
) }
|
|
189
|
+
</div>
|
|
178
190
|
</>
|
|
179
191
|
) }
|
|
180
192
|
</DropdownMenu>
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* WordPress dependencies
|
|
3
3
|
*/
|
|
4
|
-
import { useEffect, useState, useRef
|
|
4
|
+
import { useEffect, useState, useRef } from '@wordpress/element';
|
|
5
5
|
import { useSelect } from '@wordpress/data';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Internal dependencies
|
|
9
9
|
*/
|
|
10
10
|
import { store as blockEditorStore } from '../../../store';
|
|
11
|
+
import { unlock } from '../../../lock-unlock';
|
|
11
12
|
|
|
12
|
-
/** @typedef {import('
|
|
13
|
-
/** @typedef {import('
|
|
13
|
+
/** @typedef {import('../../../store/actions').InserterMediaRequest} InserterMediaRequest */
|
|
14
|
+
/** @typedef {import('../../../store/actions').InserterMediaItem} InserterMediaItem */
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Fetches media items based on the provided category.
|
|
@@ -50,48 +51,14 @@ export function useMediaResults( category, query = {} ) {
|
|
|
50
51
|
return { mediaList, isLoading };
|
|
51
52
|
}
|
|
52
53
|
|
|
53
|
-
function useInserterMediaCategories() {
|
|
54
|
-
const {
|
|
55
|
-
inserterMediaCategories,
|
|
56
|
-
allowedMimeTypes,
|
|
57
|
-
enableOpenverseMediaCategory,
|
|
58
|
-
} = useSelect( ( select ) => {
|
|
59
|
-
const settings = select( blockEditorStore ).getSettings();
|
|
60
|
-
return {
|
|
61
|
-
inserterMediaCategories: settings.inserterMediaCategories,
|
|
62
|
-
allowedMimeTypes: settings.allowedMimeTypes,
|
|
63
|
-
enableOpenverseMediaCategory: settings.enableOpenverseMediaCategory,
|
|
64
|
-
};
|
|
65
|
-
}, [] );
|
|
66
|
-
// The allowed `mime_types` can be altered by `upload_mimes` filter and restrict
|
|
67
|
-
// some of them. In this case we shouldn't add the category to the available media
|
|
68
|
-
// categories list in the inserter.
|
|
69
|
-
const allowedCategories = useMemo( () => {
|
|
70
|
-
if ( ! inserterMediaCategories || ! allowedMimeTypes ) {
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
return inserterMediaCategories.filter( ( category ) => {
|
|
74
|
-
// Check if Openverse category is enabled.
|
|
75
|
-
if (
|
|
76
|
-
! enableOpenverseMediaCategory &&
|
|
77
|
-
category.name === 'openverse'
|
|
78
|
-
) {
|
|
79
|
-
return false;
|
|
80
|
-
}
|
|
81
|
-
return Object.values( allowedMimeTypes ).some( ( mimeType ) =>
|
|
82
|
-
mimeType.startsWith( `${ category.mediaType }/` )
|
|
83
|
-
);
|
|
84
|
-
} );
|
|
85
|
-
}, [
|
|
86
|
-
inserterMediaCategories,
|
|
87
|
-
allowedMimeTypes,
|
|
88
|
-
enableOpenverseMediaCategory,
|
|
89
|
-
] );
|
|
90
|
-
return allowedCategories;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
54
|
export function useMediaCategories( rootClientId ) {
|
|
94
55
|
const [ categories, setCategories ] = useState( [] );
|
|
56
|
+
|
|
57
|
+
const inserterMediaCategories = useSelect(
|
|
58
|
+
( select ) =>
|
|
59
|
+
unlock( select( blockEditorStore ) ).getInserterMediaCategories(),
|
|
60
|
+
[]
|
|
61
|
+
);
|
|
95
62
|
const { canInsertImage, canInsertVideo, canInsertAudio } = useSelect(
|
|
96
63
|
( select ) => {
|
|
97
64
|
const { canInsertBlockType } = select( blockEditorStore );
|
|
@@ -112,7 +79,6 @@ export function useMediaCategories( rootClientId ) {
|
|
|
112
79
|
},
|
|
113
80
|
[ rootClientId ]
|
|
114
81
|
);
|
|
115
|
-
const inserterMediaCategories = useInserterMediaCategories();
|
|
116
82
|
useEffect( () => {
|
|
117
83
|
( async () => {
|
|
118
84
|
const _categories = [];
|
|
@@ -13,16 +13,9 @@ import {
|
|
|
13
13
|
} from '@wordpress/components';
|
|
14
14
|
import { useInstanceId } from '@wordpress/compose';
|
|
15
15
|
import { moreVertical } from '@wordpress/icons';
|
|
16
|
-
import {
|
|
17
|
-
useState,
|
|
18
|
-
useRef,
|
|
19
|
-
useEffect,
|
|
20
|
-
useCallback,
|
|
21
|
-
memo,
|
|
22
|
-
} from '@wordpress/element';
|
|
16
|
+
import { useState, useRef, useCallback, memo } from '@wordpress/element';
|
|
23
17
|
import { useDispatch, useSelect } from '@wordpress/data';
|
|
24
18
|
import { sprintf, __ } from '@wordpress/i18n';
|
|
25
|
-
import { focus } from '@wordpress/dom';
|
|
26
19
|
import { ESCAPE } from '@wordpress/keycodes';
|
|
27
20
|
|
|
28
21
|
/**
|
|
@@ -36,7 +29,7 @@ import {
|
|
|
36
29
|
} from '../block-mover/button';
|
|
37
30
|
import ListViewBlockContents from './block-contents';
|
|
38
31
|
import { useListViewContext } from './context';
|
|
39
|
-
import { getBlockPositionDescription } from './utils';
|
|
32
|
+
import { getBlockPositionDescription, focusListItem } from './utils';
|
|
40
33
|
import { store as blockEditorStore } from '../../store';
|
|
41
34
|
import useBlockDisplayInformation from '../use-block-display-information';
|
|
42
35
|
import { useBlockLock } from '../block-lock';
|
|
@@ -120,7 +113,6 @@ function ListViewBlock( {
|
|
|
120
113
|
);
|
|
121
114
|
|
|
122
115
|
const {
|
|
123
|
-
isTreeGridMounted,
|
|
124
116
|
expand,
|
|
125
117
|
collapse,
|
|
126
118
|
BlockSettingsMenu,
|
|
@@ -142,15 +134,6 @@ function ListViewBlock( {
|
|
|
142
134
|
{ 'is-visible': isHovered || isFirstSelectedBlock }
|
|
143
135
|
);
|
|
144
136
|
|
|
145
|
-
// If ListView has experimental features related to the Persistent List View,
|
|
146
|
-
// only focus the selected list item on mount; otherwise the list would always
|
|
147
|
-
// try to steal the focus from the editor canvas.
|
|
148
|
-
useEffect( () => {
|
|
149
|
-
if ( ! isTreeGridMounted && isSelected ) {
|
|
150
|
-
cellRef.current.focus();
|
|
151
|
-
}
|
|
152
|
-
}, [] );
|
|
153
|
-
|
|
154
137
|
// If multiple blocks are selected, deselect all blocks when the user
|
|
155
138
|
// presses the escape key.
|
|
156
139
|
const onKeyDown = ( event ) => {
|
|
@@ -188,30 +171,7 @@ function ListViewBlock( {
|
|
|
188
171
|
selectBlock( undefined, focusClientId, null, null );
|
|
189
172
|
}
|
|
190
173
|
|
|
191
|
-
|
|
192
|
-
const row = treeGridElementRef.current?.querySelector(
|
|
193
|
-
`[role=row][data-block="${ focusClientId }"]`
|
|
194
|
-
);
|
|
195
|
-
if ( ! row ) return null;
|
|
196
|
-
// Focus the first focusable in the row, which is the ListViewBlockSelectButton.
|
|
197
|
-
return focus.focusable.find( row )[ 0 ];
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
let focusElement = getFocusElement();
|
|
201
|
-
if ( focusElement ) {
|
|
202
|
-
focusElement.focus();
|
|
203
|
-
} else {
|
|
204
|
-
// The element hasn't been painted yet. Defer focusing on the next frame.
|
|
205
|
-
// This could happen when all blocks have been deleted and the default block
|
|
206
|
-
// hasn't been added to the editor yet.
|
|
207
|
-
window.requestAnimationFrame( () => {
|
|
208
|
-
focusElement = getFocusElement();
|
|
209
|
-
// Ignore if the element still doesn't exist.
|
|
210
|
-
if ( focusElement ) {
|
|
211
|
-
focusElement.focus();
|
|
212
|
-
}
|
|
213
|
-
} );
|
|
214
|
-
}
|
|
174
|
+
focusListItem( focusClientId, treeGridElementRef );
|
|
215
175
|
},
|
|
216
176
|
[ selectBlock, treeGridElementRef ]
|
|
217
177
|
);
|
|
@@ -168,8 +168,18 @@ function ListViewBranch( props ) {
|
|
|
168
168
|
);
|
|
169
169
|
const isSelectedBranch =
|
|
170
170
|
isBranchSelected || ( isSelected && hasNestedBlocks );
|
|
171
|
+
|
|
172
|
+
// To avoid performance issues, we only render blocks that are in view,
|
|
173
|
+
// or blocks that are selected or dragged. If a block is selected,
|
|
174
|
+
// it is only counted if it is the first of the block selection.
|
|
175
|
+
// This prevents the entire tree from being rendered when a branch is
|
|
176
|
+
// selected, or a user selects all blocks, while still enabling scroll
|
|
177
|
+
// into view behavior when selecting a block or opening the list view.
|
|
171
178
|
const showBlock =
|
|
172
|
-
isDragged ||
|
|
179
|
+
isDragged ||
|
|
180
|
+
blockInView ||
|
|
181
|
+
isBranchDragged ||
|
|
182
|
+
( isSelected && clientId === selectedClientIds[ 0 ] );
|
|
173
183
|
return (
|
|
174
184
|
<AsyncModeProvider key={ clientId } value={ ! isSelected }>
|
|
175
185
|
{ showBlock && (
|
|
@@ -32,6 +32,7 @@ import useListViewDropZone from './use-list-view-drop-zone';
|
|
|
32
32
|
import useListViewExpandSelectedItem from './use-list-view-expand-selected-item';
|
|
33
33
|
import { store as blockEditorStore } from '../../store';
|
|
34
34
|
import { BlockSettingsDropdown } from '../block-settings-menu/block-settings-dropdown';
|
|
35
|
+
import { focusListItem } from './utils';
|
|
35
36
|
|
|
36
37
|
const expanded = ( state, action ) => {
|
|
37
38
|
if ( Array.isArray( action.clientIds ) ) {
|
|
@@ -132,8 +133,6 @@ function ListViewComponent(
|
|
|
132
133
|
const elementRef = useRef();
|
|
133
134
|
const treeGridRef = useMergeRefs( [ elementRef, dropZoneRef, ref ] );
|
|
134
135
|
|
|
135
|
-
const isMounted = useRef( false );
|
|
136
|
-
|
|
137
136
|
const [ insertedBlock, setInsertedBlock ] = useState( null );
|
|
138
137
|
|
|
139
138
|
const { setSelectedTreeId } = useListViewExpandSelectedItem( {
|
|
@@ -156,7 +155,13 @@ function ListViewComponent(
|
|
|
156
155
|
[ setSelectedTreeId, updateBlockSelection, onSelect, getBlock ]
|
|
157
156
|
);
|
|
158
157
|
useEffect( () => {
|
|
159
|
-
|
|
158
|
+
// If a blocks are already selected when the list view is initially
|
|
159
|
+
// mounted, shift focus to the first selected block.
|
|
160
|
+
if ( selectedClientIds?.length ) {
|
|
161
|
+
focusListItem( selectedClientIds[ 0 ], elementRef );
|
|
162
|
+
}
|
|
163
|
+
// Disable reason: Only focus on the selected item when the list view is mounted.
|
|
164
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
160
165
|
}, [] );
|
|
161
166
|
|
|
162
167
|
const expand = useCallback(
|
|
@@ -204,7 +209,6 @@ function ListViewComponent(
|
|
|
204
209
|
|
|
205
210
|
const contextValue = useMemo(
|
|
206
211
|
() => ( {
|
|
207
|
-
isTreeGridMounted: isMounted.current,
|
|
208
212
|
draggedClientIds,
|
|
209
213
|
expandedState,
|
|
210
214
|
expand,
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* WordPress dependencies
|
|
3
3
|
*/
|
|
4
4
|
import { __, sprintf } from '@wordpress/i18n';
|
|
5
|
+
import { focus } from '@wordpress/dom';
|
|
5
6
|
|
|
6
7
|
export const getBlockPositionDescription = ( position, siblingCount, level ) =>
|
|
7
8
|
sprintf(
|
|
@@ -56,3 +57,39 @@ export function getCommonDepthClientIds(
|
|
|
56
57
|
end,
|
|
57
58
|
};
|
|
58
59
|
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Shift focus to the list view item associated with a particular clientId.
|
|
63
|
+
*
|
|
64
|
+
* @typedef {import('@wordpress/element').RefObject} RefObject
|
|
65
|
+
*
|
|
66
|
+
* @param {string} focusClientId The client ID of the block to focus.
|
|
67
|
+
* @param {RefObject<HTMLElement>} treeGridElementRef The container element to search within.
|
|
68
|
+
*/
|
|
69
|
+
export function focusListItem( focusClientId, treeGridElementRef ) {
|
|
70
|
+
const getFocusElement = () => {
|
|
71
|
+
const row = treeGridElementRef.current?.querySelector(
|
|
72
|
+
`[role=row][data-block="${ focusClientId }"]`
|
|
73
|
+
);
|
|
74
|
+
if ( ! row ) return null;
|
|
75
|
+
// Focus the first focusable in the row, which is the ListViewBlockSelectButton.
|
|
76
|
+
return focus.focusable.find( row )[ 0 ];
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
let focusElement = getFocusElement();
|
|
80
|
+
if ( focusElement ) {
|
|
81
|
+
focusElement.focus();
|
|
82
|
+
} else {
|
|
83
|
+
// The element hasn't been painted yet. Defer focusing on the next frame.
|
|
84
|
+
// This could happen when all blocks have been deleted and the default block
|
|
85
|
+
// hasn't been added to the editor yet.
|
|
86
|
+
window.requestAnimationFrame( () => {
|
|
87
|
+
focusElement = getFocusElement();
|
|
88
|
+
|
|
89
|
+
// Ignore if the element still doesn't exist.
|
|
90
|
+
if ( focusElement ) {
|
|
91
|
+
focusElement.focus();
|
|
92
|
+
}
|
|
93
|
+
} );
|
|
94
|
+
}
|
|
95
|
+
}
|
package/src/store/actions.js
CHANGED
|
@@ -1893,9 +1893,10 @@ export const registerInserterMediaCategory =
|
|
|
1893
1893
|
);
|
|
1894
1894
|
return;
|
|
1895
1895
|
}
|
|
1896
|
-
const
|
|
1896
|
+
const registeredInserterMediaCategories =
|
|
1897
|
+
select.getRegisteredInserterMediaCategories();
|
|
1897
1898
|
if (
|
|
1898
|
-
|
|
1899
|
+
registeredInserterMediaCategories.some(
|
|
1899
1900
|
( { name } ) => name === category.name
|
|
1900
1901
|
)
|
|
1901
1902
|
) {
|
|
@@ -1905,8 +1906,8 @@ export const registerInserterMediaCategory =
|
|
|
1905
1906
|
return;
|
|
1906
1907
|
}
|
|
1907
1908
|
if (
|
|
1908
|
-
|
|
1909
|
-
( { labels: { name } } ) => name === category.labels?.name
|
|
1909
|
+
registeredInserterMediaCategories.some(
|
|
1910
|
+
( { labels: { name } = {} } ) => name === category.labels?.name
|
|
1910
1911
|
)
|
|
1911
1912
|
) {
|
|
1912
1913
|
console.error(
|
|
@@ -1919,13 +1920,8 @@ export const registerInserterMediaCategory =
|
|
|
1919
1920
|
// private, so extenders can only add new inserter media categories and don't have any
|
|
1920
1921
|
// control over the core media categories.
|
|
1921
1922
|
dispatch( {
|
|
1922
|
-
type: '
|
|
1923
|
-
|
|
1924
|
-
inserterMediaCategories: [
|
|
1925
|
-
...inserterMediaCategories,
|
|
1926
|
-
{ ...category, isExternalResource: true },
|
|
1927
|
-
],
|
|
1928
|
-
},
|
|
1923
|
+
type: 'REGISTER_INSERTER_MEDIA_CATEGORY',
|
|
1924
|
+
category: { ...category, isExternalResource: true },
|
|
1929
1925
|
} );
|
|
1930
1926
|
};
|
|
1931
1927
|
|
|
@@ -164,3 +164,75 @@ export function getOpenedBlockSettingsMenu( state ) {
|
|
|
164
164
|
export function getStyleOverrides( state ) {
|
|
165
165
|
return state.styleOverrides;
|
|
166
166
|
}
|
|
167
|
+
|
|
168
|
+
/** @typedef {import('./actions').InserterMediaCategory} InserterMediaCategory */
|
|
169
|
+
/**
|
|
170
|
+
* Returns the registered inserter media categories through the public API.
|
|
171
|
+
*
|
|
172
|
+
* @param {Object} state Editor state.
|
|
173
|
+
*
|
|
174
|
+
* @return {InserterMediaCategory[]} Inserter media categories.
|
|
175
|
+
*/
|
|
176
|
+
export function getRegisteredInserterMediaCategories( state ) {
|
|
177
|
+
return state.registeredInserterMediaCategories;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Returns an array containing the allowed inserter media categories.
|
|
182
|
+
* It merges the registered media categories from extenders with the
|
|
183
|
+
* core ones. It also takes into account the allowed `mime_types`, which
|
|
184
|
+
* can be altered by `upload_mimes` filter and restrict some of them.
|
|
185
|
+
*
|
|
186
|
+
* @param {Object} state Global application state.
|
|
187
|
+
*
|
|
188
|
+
* @return {InserterMediaCategory[]} Client IDs of descendants.
|
|
189
|
+
*/
|
|
190
|
+
export const getInserterMediaCategories = createSelector(
|
|
191
|
+
( state ) => {
|
|
192
|
+
const {
|
|
193
|
+
settings: {
|
|
194
|
+
inserterMediaCategories,
|
|
195
|
+
allowedMimeTypes,
|
|
196
|
+
enableOpenverseMediaCategory,
|
|
197
|
+
},
|
|
198
|
+
registeredInserterMediaCategories,
|
|
199
|
+
} = state;
|
|
200
|
+
// The allowed `mime_types` can be altered by `upload_mimes` filter and restrict
|
|
201
|
+
// some of them. In this case we shouldn't add the category to the available media
|
|
202
|
+
// categories list in the inserter.
|
|
203
|
+
if (
|
|
204
|
+
( ! inserterMediaCategories &&
|
|
205
|
+
! registeredInserterMediaCategories.length ) ||
|
|
206
|
+
! allowedMimeTypes
|
|
207
|
+
) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
const coreInserterMediaCategoriesNames =
|
|
211
|
+
inserterMediaCategories?.map( ( { name } ) => name ) || [];
|
|
212
|
+
const mergedCategories = [
|
|
213
|
+
...( inserterMediaCategories || [] ),
|
|
214
|
+
...( registeredInserterMediaCategories || [] ).filter(
|
|
215
|
+
( { name } ) =>
|
|
216
|
+
! coreInserterMediaCategoriesNames.includes( name )
|
|
217
|
+
),
|
|
218
|
+
];
|
|
219
|
+
return mergedCategories.filter( ( category ) => {
|
|
220
|
+
// Check if Openverse category is enabled.
|
|
221
|
+
if (
|
|
222
|
+
! enableOpenverseMediaCategory &&
|
|
223
|
+
category.name === 'openverse'
|
|
224
|
+
) {
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
return Object.values( allowedMimeTypes ).some( ( mimeType ) =>
|
|
228
|
+
mimeType.startsWith( `${ category.mediaType }/` )
|
|
229
|
+
);
|
|
230
|
+
} );
|
|
231
|
+
},
|
|
232
|
+
( state ) => [
|
|
233
|
+
state.settings.inserterMediaCategories,
|
|
234
|
+
state.settings.allowedMimeTypes,
|
|
235
|
+
state.settings.enableOpenverseMediaCategory,
|
|
236
|
+
state.registeredInserterMediaCategories,
|
|
237
|
+
]
|
|
238
|
+
);
|
package/src/store/reducer.js
CHANGED
|
@@ -1949,6 +1949,22 @@ export function styleOverrides( state = new Map(), action ) {
|
|
|
1949
1949
|
return state;
|
|
1950
1950
|
}
|
|
1951
1951
|
|
|
1952
|
+
/**
|
|
1953
|
+
* Reducer returning a map of the registered inserter media categories.
|
|
1954
|
+
*
|
|
1955
|
+
* @param {Array} state Current state.
|
|
1956
|
+
* @param {Object} action Dispatched action.
|
|
1957
|
+
*
|
|
1958
|
+
* @return {Array} Updated state.
|
|
1959
|
+
*/
|
|
1960
|
+
export function registeredInserterMediaCategories( state = [], action ) {
|
|
1961
|
+
switch ( action.type ) {
|
|
1962
|
+
case 'REGISTER_INSERTER_MEDIA_CATEGORY':
|
|
1963
|
+
return [ ...state, action.category ];
|
|
1964
|
+
}
|
|
1965
|
+
return state;
|
|
1966
|
+
}
|
|
1967
|
+
|
|
1952
1968
|
const combinedReducers = combineReducers( {
|
|
1953
1969
|
blocks,
|
|
1954
1970
|
isTyping,
|
|
@@ -1976,6 +1992,7 @@ const combinedReducers = combineReducers( {
|
|
|
1976
1992
|
removalPromptData,
|
|
1977
1993
|
blockRemovalRules,
|
|
1978
1994
|
openedBlockSettingsMenu,
|
|
1995
|
+
registeredInserterMediaCategories,
|
|
1979
1996
|
} );
|
|
1980
1997
|
|
|
1981
1998
|
function withAutomaticChangeReset( reducer ) {
|