@wordpress/block-library 9.41.0 → 9.41.1-next.v.202603161435.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/cover/edit/cover-placeholder.cjs +7 -0
- package/build/cover/edit/cover-placeholder.cjs.map +2 -2
- package/build/html/block.json +2 -1
- package/build/html/modal.cjs +142 -147
- package/build/html/modal.cjs.map +3 -3
- package/build/icon/block.json +3 -12
- package/build/image/edit.cjs +7 -0
- package/build/image/edit.cjs.map +2 -2
- package/build/image/image.cjs +5 -9
- package/build/image/image.cjs.map +2 -2
- package/build/media-text/media-container.cjs +6 -0
- package/build/media-text/media-container.cjs.map +2 -2
- package/build/navigation/edit/index.cjs +21 -14
- package/build/navigation/edit/index.cjs.map +3 -3
- package/build/navigation/view.cjs +9 -2
- package/build/navigation/view.cjs.map +2 -2
- package/build/navigation-link/block.json +5 -0
- package/build/navigation-link/shared/use-link-preview.cjs +29 -0
- package/build/navigation-link/shared/use-link-preview.cjs.map +2 -2
- package/build/nextpage/block.json +0 -1
- package/build/paragraph/edit.cjs +1 -1
- package/build/paragraph/edit.cjs.map +1 -1
- package/build/playlist/edit.cjs +3 -23
- package/build/playlist/edit.cjs.map +3 -3
- package/build/playlist/utils.cjs +48 -0
- package/build/playlist/utils.cjs.map +7 -0
- package/build/playlist-track/block.json +0 -0
- package/build/post-excerpt/block.json +1 -3
- package/build/post-excerpt/deprecated.cjs +112 -0
- package/build/post-excerpt/deprecated.cjs.map +7 -0
- package/build/post-excerpt/edit.cjs +11 -30
- package/build/post-excerpt/edit.cjs.map +3 -3
- package/build/post-excerpt/index.cjs +3 -1
- package/build/post-excerpt/index.cjs.map +3 -3
- package/build/private-apis.cjs +3 -1
- package/build/private-apis.cjs.map +2 -2
- package/build/shortcode/block.json +2 -1
- package/build/site-logo/edit.cjs +1 -3
- package/build/site-logo/edit.cjs.map +2 -2
- package/build/tab/add-tab-toolbar-control.cjs +22 -5
- package/build/tab/add-tab-toolbar-control.cjs.map +2 -2
- package/build/tab/remove-tab-toolbar-control.cjs +19 -1
- package/build/tab/remove-tab-toolbar-control.cjs.map +2 -2
- package/build/tabs/edit.cjs +85 -7
- package/build/tabs/edit.cjs.map +2 -2
- package/build/tabs/index.cjs +12 -2
- package/build/tabs/index.cjs.map +2 -2
- package/build/tabs-menu/block.json +1 -6
- package/build/tabs-menu/edit.cjs +11 -151
- package/build/tabs-menu/edit.cjs.map +3 -3
- package/build/tabs-menu/save.cjs.map +2 -2
- package/build/tabs-menu-item/block.json +14 -11
- package/build/tabs-menu-item/controls.cjs +2 -133
- package/build/tabs-menu-item/controls.cjs.map +3 -3
- package/build/tabs-menu-item/edit.cjs +44 -56
- package/build/tabs-menu-item/edit.cjs.map +3 -3
- package/build/tabs-menu-item/save.cjs +0 -1
- package/build/tabs-menu-item/save.cjs.map +2 -2
- package/build/template-part/edit/index.cjs +6 -4
- package/build/template-part/edit/index.cjs.map +2 -2
- package/build/utils/media-control.cjs +72 -29
- package/build/utils/media-control.cjs.map +3 -3
- package/build-module/cover/edit/cover-placeholder.mjs +7 -0
- package/build-module/cover/edit/cover-placeholder.mjs.map +2 -2
- package/build-module/html/block.json +2 -1
- package/build-module/html/modal.mjs +144 -149
- package/build-module/html/modal.mjs.map +2 -2
- package/build-module/icon/block.json +3 -12
- package/build-module/image/edit.mjs +7 -0
- package/build-module/image/edit.mjs.map +2 -2
- package/build-module/image/image.mjs +5 -9
- package/build-module/image/image.mjs.map +2 -2
- package/build-module/media-text/media-container.mjs +7 -1
- package/build-module/media-text/media-container.mjs.map +2 -2
- package/build-module/navigation/edit/index.mjs +22 -14
- package/build-module/navigation/edit/index.mjs.map +2 -2
- package/build-module/navigation/view.mjs +9 -2
- package/build-module/navigation/view.mjs.map +2 -2
- package/build-module/navigation-link/block.json +5 -0
- package/build-module/navigation-link/shared/use-link-preview.mjs +28 -0
- package/build-module/navigation-link/shared/use-link-preview.mjs.map +2 -2
- package/build-module/nextpage/block.json +0 -1
- package/build-module/paragraph/edit.mjs +2 -2
- package/build-module/paragraph/edit.mjs.map +1 -1
- package/build-module/playlist/edit.mjs +2 -18
- package/build-module/playlist/edit.mjs.map +2 -2
- package/build-module/playlist/utils.mjs +23 -0
- package/build-module/playlist/utils.mjs.map +7 -0
- package/build-module/playlist-track/block.json +0 -0
- package/build-module/post-excerpt/block.json +1 -3
- package/build-module/post-excerpt/deprecated.mjs +81 -0
- package/build-module/post-excerpt/deprecated.mjs.map +7 -0
- package/build-module/post-excerpt/edit.mjs +12 -34
- package/build-module/post-excerpt/edit.mjs.map +2 -2
- package/build-module/post-excerpt/index.mjs +3 -1
- package/build-module/post-excerpt/index.mjs.map +2 -2
- package/build-module/private-apis.mjs +3 -1
- package/build-module/private-apis.mjs.map +2 -2
- package/build-module/shortcode/block.json +2 -1
- package/build-module/site-logo/edit.mjs +1 -3
- package/build-module/site-logo/edit.mjs.map +2 -2
- package/build-module/tab/add-tab-toolbar-control.mjs +22 -5
- package/build-module/tab/add-tab-toolbar-control.mjs.map +2 -2
- package/build-module/tab/remove-tab-toolbar-control.mjs +19 -1
- package/build-module/tab/remove-tab-toolbar-control.mjs.map +2 -2
- package/build-module/tabs/edit.mjs +87 -9
- package/build-module/tabs/edit.mjs.map +2 -2
- package/build-module/tabs/index.mjs +12 -2
- package/build-module/tabs/index.mjs.map +2 -2
- package/build-module/tabs-menu/block.json +1 -6
- package/build-module/tabs-menu/edit.mjs +13 -162
- package/build-module/tabs-menu/edit.mjs.map +2 -2
- package/build-module/tabs-menu/save.mjs.map +2 -2
- package/build-module/tabs-menu-item/block.json +14 -11
- package/build-module/tabs-menu-item/controls.mjs +4 -143
- package/build-module/tabs-menu-item/controls.mjs.map +2 -2
- package/build-module/tabs-menu-item/edit.mjs +45 -57
- package/build-module/tabs-menu-item/edit.mjs.map +3 -3
- package/build-module/tabs-menu-item/save.mjs +0 -1
- package/build-module/tabs-menu-item/save.mjs.map +2 -2
- package/build-module/template-part/edit/index.mjs +6 -4
- package/build-module/template-part/edit/index.mjs.map +2 -2
- package/build-module/utils/media-control.mjs +73 -30
- package/build-module/utils/media-control.mjs.map +2 -2
- package/build-style/common-rtl.css +1 -0
- package/build-style/common.css +1 -0
- package/build-style/editor-rtl.css +55 -17
- package/build-style/editor.css +55 -17
- package/build-style/html/editor-rtl.css +10 -6
- package/build-style/html/editor.css +10 -6
- package/build-style/navigation/style-rtl.css +15 -1
- package/build-style/navigation/style.css +15 -1
- package/build-style/navigation-overlay-close/style-rtl.css +3 -3
- package/build-style/navigation-overlay-close/style.css +3 -3
- package/build-style/playlist/style-rtl.css +4 -0
- package/build-style/playlist/style.css +4 -0
- package/build-style/style-rtl.css +23 -4
- package/build-style/style.css +23 -4
- package/build-style/tabs-menu/editor-rtl.css +5 -3
- package/build-style/tabs-menu/editor.css +5 -3
- package/package.json +38 -38
- package/src/accordion-item/index.php +17 -5
- package/src/common.scss +1 -0
- package/src/cover/edit/cover-placeholder.js +8 -0
- package/src/cover/index.php +8 -0
- package/src/details/index.php +47 -0
- package/src/html/block.json +2 -1
- package/src/html/editor.scss +15 -5
- package/src/html/modal.js +26 -22
- package/src/icon/block.json +3 -12
- package/src/image/edit.js +8 -0
- package/src/image/image.js +8 -13
- package/src/media-text/media-container.js +8 -1
- package/src/navigation/edit/index.js +26 -14
- package/src/navigation/index.php +27 -13
- package/src/navigation/style.scss +17 -1
- package/src/navigation/view.js +14 -2
- package/src/navigation-link/block.json +5 -0
- package/src/navigation-link/index.php +10 -10
- package/src/navigation-link/shared/test/use-link-preview.test.js +149 -0
- package/src/navigation-link/shared/use-link-preview.js +43 -1
- package/src/navigation-overlay-close/style.scss +3 -3
- package/src/navigation-submenu/index.php +17 -11
- package/src/nextpage/block.json +0 -1
- package/src/paragraph/edit.js +2 -2
- package/src/playlist/edit.js +1 -34
- package/src/playlist/style.scss +5 -0
- package/src/playlist/test/edit.js +1 -1
- package/src/playlist/utils.js +42 -0
- package/src/playlist-track/block.json +0 -0
- package/src/playlist-track/edit.js +0 -0
- package/src/playlist-track/index.js +0 -0
- package/src/playlist-track/index.php +0 -0
- package/src/playlist-track/init.js +0 -0
- package/src/playlist-track/style.scss +0 -0
- package/src/post-excerpt/block.json +1 -3
- package/src/post-excerpt/deprecated.js +84 -0
- package/src/post-excerpt/edit.js +14 -39
- package/src/post-excerpt/index.js +2 -0
- package/src/private-apis.js +2 -0
- package/src/shortcode/block.json +2 -1
- package/src/site-logo/edit.js +1 -3
- package/src/tab/add-tab-toolbar-control.js +48 -23
- package/src/tab/remove-tab-toolbar-control.js +30 -10
- package/src/tabs/edit.js +133 -10
- package/src/tabs/index.js +12 -2
- package/src/tabs-menu/block.json +1 -6
- package/src/tabs-menu/edit.js +13 -214
- package/src/tabs-menu/editor.scss +7 -3
- package/src/tabs-menu/index.php +42 -27
- package/src/tabs-menu/save.js +0 -4
- package/src/tabs-menu-item/block.json +14 -11
- package/src/tabs-menu-item/controls.js +4 -167
- package/src/tabs-menu-item/edit.js +60 -69
- package/src/tabs-menu-item/index.php +11 -23
- package/src/tabs-menu-item/save.js +0 -1
- package/src/template-part/edit/index.js +5 -1
- package/src/utils/media-control.js +61 -21
- package/src/utils/media-control.scss +54 -18
package/src/html/modal.js
CHANGED
|
@@ -10,11 +10,12 @@ import {
|
|
|
10
10
|
Flex,
|
|
11
11
|
Notice,
|
|
12
12
|
privateApis as componentsPrivateApis,
|
|
13
|
+
__experimentalVStack as VStack,
|
|
13
14
|
__experimentalHStack as HStack,
|
|
14
|
-
__experimentalGrid as Grid,
|
|
15
15
|
} from '@wordpress/components';
|
|
16
16
|
import { PlainText, store as blockEditorStore } from '@wordpress/block-editor';
|
|
17
17
|
import { fullscreen, square } from '@wordpress/icons';
|
|
18
|
+
import { useViewportMatch } from '@wordpress/compose';
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* Internal dependencies
|
|
@@ -40,6 +41,8 @@ export default function HTMLEditModal( {
|
|
|
40
41
|
const [ showUnsavedWarning, setShowUnsavedWarning ] = useState( false );
|
|
41
42
|
const [ isFullscreen, setIsFullscreen ] = useState( false );
|
|
42
43
|
|
|
44
|
+
const isMobileViewport = useViewportMatch( 'small', '<' );
|
|
45
|
+
|
|
43
46
|
// Check if user has permission to save scripts and get editor styles
|
|
44
47
|
const { canUserUseUnfilteredHTML } = useSelect( ( select ) => {
|
|
45
48
|
const settings = select( blockEditorStore ).getSettings();
|
|
@@ -121,12 +124,7 @@ export default function HTMLEditModal( {
|
|
|
121
124
|
__experimentalHideHeader
|
|
122
125
|
>
|
|
123
126
|
<Tabs orientation="horizontal" defaultTabId="html">
|
|
124
|
-
<
|
|
125
|
-
columns={ 1 }
|
|
126
|
-
templateRows="auto 1fr auto"
|
|
127
|
-
gap={ 4 }
|
|
128
|
-
style={ { height: '100%' } }
|
|
129
|
-
>
|
|
127
|
+
<VStack expanded>
|
|
130
128
|
<HStack
|
|
131
129
|
justify="space-between"
|
|
132
130
|
className="block-library-html__modal-header"
|
|
@@ -144,15 +142,21 @@ export default function HTMLEditModal( {
|
|
|
144
142
|
) }
|
|
145
143
|
</Tabs.TabList>
|
|
146
144
|
</div>
|
|
147
|
-
|
|
148
|
-
<
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
145
|
+
{ ! isMobileViewport && (
|
|
146
|
+
<div>
|
|
147
|
+
<Button
|
|
148
|
+
__next40pxDefaultSize
|
|
149
|
+
icon={
|
|
150
|
+
isFullscreen ? square : fullscreen
|
|
151
|
+
}
|
|
152
|
+
label={ __(
|
|
153
|
+
'Enable/disable fullscreen'
|
|
154
|
+
) }
|
|
155
|
+
onClick={ toggleFullscreen }
|
|
156
|
+
variant="tertiary"
|
|
157
|
+
/>
|
|
158
|
+
</div>
|
|
159
|
+
) }
|
|
156
160
|
</HStack>
|
|
157
161
|
{ hasRestrictedContent && (
|
|
158
162
|
<Notice
|
|
@@ -165,11 +169,11 @@ export default function HTMLEditModal( {
|
|
|
165
169
|
) }
|
|
166
170
|
</Notice>
|
|
167
171
|
) }
|
|
168
|
-
<
|
|
169
|
-
|
|
170
|
-
justify="flex-start"
|
|
171
|
-
spacing={ 4 }
|
|
172
|
+
<Flex
|
|
173
|
+
direction={ isMobileViewport ? 'column' : 'row' }
|
|
172
174
|
className="block-library-html__modal-tabs"
|
|
175
|
+
align="stretch"
|
|
176
|
+
gap={ 8 }
|
|
173
177
|
>
|
|
174
178
|
<div className="block-library-html__modal-content">
|
|
175
179
|
<Tabs.TabPanel
|
|
@@ -227,7 +231,7 @@ export default function HTMLEditModal( {
|
|
|
227
231
|
} ) }
|
|
228
232
|
/>
|
|
229
233
|
</div>
|
|
230
|
-
</
|
|
234
|
+
</Flex>
|
|
231
235
|
<HStack
|
|
232
236
|
alignment="center"
|
|
233
237
|
justify="flex-end"
|
|
@@ -249,7 +253,7 @@ export default function HTMLEditModal( {
|
|
|
249
253
|
{ __( 'Update' ) }
|
|
250
254
|
</Button>
|
|
251
255
|
</HStack>
|
|
252
|
-
</
|
|
256
|
+
</VStack>
|
|
253
257
|
</Tabs>
|
|
254
258
|
</Modal>
|
|
255
259
|
|
package/src/icon/block.json
CHANGED
|
@@ -59,19 +59,10 @@
|
|
|
59
59
|
}
|
|
60
60
|
},
|
|
61
61
|
"selectors": {
|
|
62
|
-
"root": ".wp-block-icon",
|
|
63
|
-
"
|
|
64
|
-
"root": ".wp-block-icon svg"
|
|
65
|
-
},
|
|
66
|
-
"border": {
|
|
67
|
-
"root": ".wp-block-icon svg"
|
|
68
|
-
},
|
|
62
|
+
"root": ".wp-block-icon svg",
|
|
63
|
+
"css": ".wp-block-icon",
|
|
69
64
|
"spacing": {
|
|
70
|
-
"
|
|
71
|
-
},
|
|
72
|
-
"dimensions": {
|
|
73
|
-
"root": ".wp-block-icon svg",
|
|
74
|
-
"width": ".wp-block-icon svg"
|
|
65
|
+
"margin": ".wp-block-icon"
|
|
75
66
|
}
|
|
76
67
|
},
|
|
77
68
|
"style": "wp-block-icon",
|
package/src/image/edit.js
CHANGED
|
@@ -159,6 +159,7 @@ export function ImageEdit( {
|
|
|
159
159
|
const { createErrorNotice } = useDispatch( noticesStore );
|
|
160
160
|
function onUploadError( message ) {
|
|
161
161
|
createErrorNotice( message, { type: 'snackbar' } );
|
|
162
|
+
setTemporaryURL();
|
|
162
163
|
setAttributes( {
|
|
163
164
|
src: undefined,
|
|
164
165
|
id: undefined,
|
|
@@ -167,6 +168,12 @@ export function ImageEdit( {
|
|
|
167
168
|
} );
|
|
168
169
|
}
|
|
169
170
|
|
|
171
|
+
function onFilesPreUpload( files ) {
|
|
172
|
+
if ( files.length === 1 ) {
|
|
173
|
+
setTemporaryURL( createBlobURL( files[ 0 ] ) );
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
170
177
|
function onSelectImagesList( images ) {
|
|
171
178
|
const win = containerRef.current?.ownerDocument.defaultView;
|
|
172
179
|
|
|
@@ -479,6 +486,7 @@ export function ImageEdit( {
|
|
|
479
486
|
icon={ <BlockIcon icon={ icon } /> }
|
|
480
487
|
onSelect={ onSelectImage }
|
|
481
488
|
onSelectURL={ onSelectURL }
|
|
489
|
+
onFilesPreUpload={ onFilesPreUpload }
|
|
482
490
|
onError={ onUploadError }
|
|
483
491
|
placeholder={ placeholder }
|
|
484
492
|
allowedTypes={ ALLOWED_MEDIA_TYPES }
|
package/src/image/image.js
CHANGED
|
@@ -323,20 +323,15 @@ export default function Image( {
|
|
|
323
323
|
)
|
|
324
324
|
: null;
|
|
325
325
|
|
|
326
|
-
// Check edit permissions
|
|
327
|
-
//
|
|
328
|
-
// Only check when the image is selected to avoid unnecessary API requests.
|
|
326
|
+
// Check edit permissions when the media editor experiment is enabled.
|
|
327
|
+
// Only check when imageRecord is available to avoid unnecessary API requests.
|
|
329
328
|
let canEdit = false;
|
|
330
|
-
if (
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
'attachment',
|
|
337
|
-
id
|
|
338
|
-
);
|
|
339
|
-
canEdit = permissions?.update || false;
|
|
329
|
+
if ( imageRecord && window?.__experimentalMediaEditor ) {
|
|
330
|
+
canEdit = !! select( coreStore ).canUser( 'update', {
|
|
331
|
+
kind: 'postType',
|
|
332
|
+
name: 'attachment',
|
|
333
|
+
id,
|
|
334
|
+
} );
|
|
340
335
|
}
|
|
341
336
|
|
|
342
337
|
return {
|
|
@@ -18,7 +18,7 @@ import { __ } from '@wordpress/i18n';
|
|
|
18
18
|
import { useViewportMatch } from '@wordpress/compose';
|
|
19
19
|
import { useDispatch } from '@wordpress/data';
|
|
20
20
|
import { forwardRef } from '@wordpress/element';
|
|
21
|
-
import { isBlobURL } from '@wordpress/blob';
|
|
21
|
+
import { createBlobURL, isBlobURL } from '@wordpress/blob';
|
|
22
22
|
import { store as noticesStore } from '@wordpress/notices';
|
|
23
23
|
import { media as icon } from '@wordpress/icons';
|
|
24
24
|
|
|
@@ -82,6 +82,12 @@ function PlaceholderContainer( {
|
|
|
82
82
|
createErrorNotice( message, { type: 'snackbar' } );
|
|
83
83
|
};
|
|
84
84
|
|
|
85
|
+
const onFilesPreUpload = ( files ) => {
|
|
86
|
+
if ( files.length === 1 ) {
|
|
87
|
+
onSelectMedia( { url: createBlobURL( files[ 0 ] ) } );
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
85
91
|
return (
|
|
86
92
|
<MediaPlaceholder
|
|
87
93
|
icon={ <BlockIcon icon={ icon } /> }
|
|
@@ -92,6 +98,7 @@ function PlaceholderContainer( {
|
|
|
92
98
|
onSelect={ onSelectMedia }
|
|
93
99
|
onToggleFeaturedImage={ toggleUseFeaturedImage }
|
|
94
100
|
allowedTypes={ ALLOWED_MEDIA_TYPES }
|
|
101
|
+
onFilesPreUpload={ onFilesPreUpload }
|
|
95
102
|
onError={ onUploadError }
|
|
96
103
|
disableMediaButtons={ mediaUrl }
|
|
97
104
|
/>
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
useBlockProps,
|
|
19
19
|
RecursionProvider,
|
|
20
20
|
useHasRecursion,
|
|
21
|
+
privateApis as blockEditorPrivateApis,
|
|
21
22
|
store as blockEditorStore,
|
|
22
23
|
withColors,
|
|
23
24
|
ContrastChecker,
|
|
@@ -85,6 +86,8 @@ import {
|
|
|
85
86
|
NAVIGATION_OVERLAY_TEMPLATE_PART_AREA,
|
|
86
87
|
} from '../constants';
|
|
87
88
|
|
|
89
|
+
const { isNavigationPostEditorKey } = unlock( blockEditorPrivateApis );
|
|
90
|
+
|
|
88
91
|
/**
|
|
89
92
|
* Component that renders the Add page button for the Navigation block.
|
|
90
93
|
*
|
|
@@ -319,19 +322,27 @@ function Navigation( {
|
|
|
319
322
|
|
|
320
323
|
// Skip recursion check when in preview mode.
|
|
321
324
|
const recursionDetected = useHasRecursion( recursionId );
|
|
322
|
-
const {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
325
|
+
const {
|
|
326
|
+
isPreviewMode,
|
|
327
|
+
onNavigateToEntityRecord,
|
|
328
|
+
currentTheme,
|
|
329
|
+
editorDisabledResponsive,
|
|
330
|
+
} = useSelect( ( select ) => {
|
|
331
|
+
const { getSettings } = select( blockEditorStore );
|
|
332
|
+
const settings = getSettings();
|
|
333
|
+
|
|
334
|
+
return {
|
|
335
|
+
isPreviewMode: settings.isPreviewMode,
|
|
336
|
+
onNavigateToEntityRecord: settings?.onNavigateToEntityRecord,
|
|
337
|
+
// Needed to construct the template part ID for the overlay preview.
|
|
338
|
+
currentTheme: select( coreStore ).getCurrentTheme()?.stylesheet,
|
|
339
|
+
// When editing a navigation post directly in an isolated editor,
|
|
340
|
+
// always show navigation expanded (no hamburger) so users can see
|
|
341
|
+
// and interact with all menu items.
|
|
342
|
+
editorDisabledResponsive:
|
|
343
|
+
!! settings?.[ isNavigationPostEditorKey ],
|
|
344
|
+
};
|
|
345
|
+
}, [] );
|
|
335
346
|
const hasAlreadyRendered = isPreviewMode ? false : recursionDetected;
|
|
336
347
|
|
|
337
348
|
const blockEditingMode = useBlockEditingMode();
|
|
@@ -603,7 +614,8 @@ function Navigation( {
|
|
|
603
614
|
setAttributes,
|
|
604
615
|
] );
|
|
605
616
|
|
|
606
|
-
const isResponsive = 'never' !== overlayMenu;
|
|
617
|
+
const isResponsive = 'never' !== overlayMenu && ! editorDisabledResponsive;
|
|
618
|
+
|
|
607
619
|
const blockProps = useBlockProps( {
|
|
608
620
|
ref: navRef,
|
|
609
621
|
className: clsx(
|
package/src/navigation/index.php
CHANGED
|
@@ -710,6 +710,12 @@ class WP_Navigation_Block_Renderer {
|
|
|
710
710
|
$tags = new WP_HTML_Tag_Processor( $overlay_blocks_html );
|
|
711
711
|
$overlay_blocks_html = block_core_navigation_add_directives_to_overlay_close( $tags );
|
|
712
712
|
}
|
|
713
|
+
// Images in the overlay are hidden until the menu is opened. Pre-set
|
|
714
|
+
// fetchpriority="low" so that when wp_filter_content_tags() processes the
|
|
715
|
+
// parent template part, it sees the attribute already present and calls
|
|
716
|
+
// wp_get_loading_optimization_attributes() with fetchpriority="low", which both prevents
|
|
717
|
+
// fetchpriority="high" from being added and stops the LCP counter from being incremented.
|
|
718
|
+
$overlay_blocks_html = block_core_navigation_set_overlay_image_fetch_priority( $overlay_blocks_html );
|
|
713
719
|
}
|
|
714
720
|
|
|
715
721
|
$has_custom_overlay = ! empty( $overlay_blocks_html );
|
|
@@ -1111,6 +1117,25 @@ function block_core_navigation_add_directives_to_overlay_close( $tags ) {
|
|
|
1111
1117
|
return $tags->get_updated_html();
|
|
1112
1118
|
}
|
|
1113
1119
|
|
|
1120
|
+
/**
|
|
1121
|
+
* Sets fetchpriority="low" on all IMG tags within the navigation overlay.
|
|
1122
|
+
*
|
|
1123
|
+
* Images in the overlay are hidden until the menu is opened, so they should
|
|
1124
|
+
* not compete with any actual LCP element image on the page.
|
|
1125
|
+
*
|
|
1126
|
+
* @since 7.0.0
|
|
1127
|
+
*
|
|
1128
|
+
* @param string $overlay_blocks_html The rendered HTML of the overlay blocks.
|
|
1129
|
+
* @return string Modified HTML with fetchpriority="low" on all IMG tags.
|
|
1130
|
+
*/
|
|
1131
|
+
function block_core_navigation_set_overlay_image_fetch_priority( string $overlay_blocks_html ): string {
|
|
1132
|
+
$tags = new WP_HTML_Tag_Processor( $overlay_blocks_html );
|
|
1133
|
+
while ( $tags->next_tag( 'IMG' ) ) {
|
|
1134
|
+
$tags->set_attribute( 'fetchpriority', 'low' );
|
|
1135
|
+
}
|
|
1136
|
+
return $tags->get_updated_html();
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1114
1139
|
/**
|
|
1115
1140
|
* Add Interactivity API directives to the navigation-submenu and page-list
|
|
1116
1141
|
* blocks markup using the Tag Processor.
|
|
@@ -1146,8 +1171,8 @@ function block_core_navigation_add_directives_to_submenu( $tags, $block_attribut
|
|
|
1146
1171
|
$open_on_hover = 'hover' === $computed_visibility;
|
|
1147
1172
|
|
|
1148
1173
|
if ( $open_on_hover ) {
|
|
1149
|
-
$tags->set_attribute( 'data-wp-on--
|
|
1150
|
-
$tags->set_attribute( 'data-wp-on--
|
|
1174
|
+
$tags->set_attribute( 'data-wp-on--pointerenter', 'actions.openMenuOnHover' );
|
|
1175
|
+
$tags->set_attribute( 'data-wp-on--pointerleave', 'actions.closeMenuOnHover' );
|
|
1151
1176
|
}
|
|
1152
1177
|
|
|
1153
1178
|
// Add directives to the toggle submenu button.
|
|
@@ -1301,17 +1326,6 @@ function block_core_navigation_build_css_font_sizes( $attributes ) {
|
|
|
1301
1326
|
return $font_sizes;
|
|
1302
1327
|
}
|
|
1303
1328
|
|
|
1304
|
-
/**
|
|
1305
|
-
* Returns the top-level submenu SVG chevron icon.
|
|
1306
|
-
*
|
|
1307
|
-
* @since 5.9.0
|
|
1308
|
-
*
|
|
1309
|
-
* @return string
|
|
1310
|
-
*/
|
|
1311
|
-
function block_core_navigation_render_submenu_icon() {
|
|
1312
|
-
return '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none" aria-hidden="true" focusable="false"><path d="M1.50002 4L6.00002 8L10.5 4" stroke-width="1.5"></path></svg>';
|
|
1313
|
-
}
|
|
1314
|
-
|
|
1315
1329
|
/**
|
|
1316
1330
|
* Filter out empty "null" blocks from the block list.
|
|
1317
1331
|
* 'parse_blocks' includes a null block with '\n\n' as the content when
|
|
@@ -247,7 +247,13 @@ $navigation-icon-size: 24px;
|
|
|
247
247
|
}
|
|
248
248
|
|
|
249
249
|
// Show submenus on hover unless they open on click.
|
|
250
|
-
|
|
250
|
+
// Restricted to true-hover devices to prevent sticky touch-hover on mobile.
|
|
251
|
+
@media (hover: hover) {
|
|
252
|
+
&:not(.open-on-click):hover > .wp-block-navigation__submenu-container {
|
|
253
|
+
@include show-submenu;
|
|
254
|
+
min-width: 200px;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
251
257
|
// Keep submenus open when focus is within.
|
|
252
258
|
&:not(.open-on-click):not(.open-on-hover-click):focus-within > .wp-block-navigation__submenu-container,
|
|
253
259
|
// Show submenus on click.
|
|
@@ -694,8 +700,18 @@ button.wp-block-navigation-item__content {
|
|
|
694
700
|
display: none;
|
|
695
701
|
}
|
|
696
702
|
|
|
703
|
+
// Override justification dropdown menu positioning rules inside custom overlays.
|
|
704
|
+
// Mirrors the protection at lines 674-678 for default overlays, which does not
|
|
705
|
+
// apply here. Prevents .items-justified-right descendant rules from cascading
|
|
706
|
+
// right: 0 into the overlay and anchoring submenus off the left edge of the viewport.
|
|
707
|
+
// See: https://github.com/WordPress/gutenberg/issues/76276
|
|
697
708
|
.wp-block-navigation__overlay-container {
|
|
698
709
|
display: block;
|
|
710
|
+
|
|
711
|
+
.wp-block-navigation__submenu-container {
|
|
712
|
+
right: auto;
|
|
713
|
+
left: 0;
|
|
714
|
+
}
|
|
699
715
|
}
|
|
700
716
|
}
|
|
701
717
|
}
|
package/src/navigation/view.js
CHANGED
|
@@ -82,7 +82,12 @@ const { state, actions } = store(
|
|
|
82
82
|
},
|
|
83
83
|
},
|
|
84
84
|
actions: {
|
|
85
|
-
openMenuOnHover() {
|
|
85
|
+
openMenuOnHover( event ) {
|
|
86
|
+
// Pointer events from touch should not open the submenu on hover;
|
|
87
|
+
// touch devices toggle via the click action instead.
|
|
88
|
+
if ( event?.pointerType === 'touch' ) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
86
91
|
const { type, overlayOpenedBy } = getContext();
|
|
87
92
|
if (
|
|
88
93
|
type === 'submenu' &&
|
|
@@ -93,7 +98,10 @@ const { state, actions } = store(
|
|
|
93
98
|
actions.openMenu( 'hover' );
|
|
94
99
|
}
|
|
95
100
|
},
|
|
96
|
-
closeMenuOnHover() {
|
|
101
|
+
closeMenuOnHover( event ) {
|
|
102
|
+
if ( event?.pointerType === 'touch' ) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
97
105
|
const { type, overlayOpenedBy } = getContext();
|
|
98
106
|
if (
|
|
99
107
|
type === 'submenu' &&
|
|
@@ -128,6 +136,10 @@ const { state, actions } = store(
|
|
|
128
136
|
if ( menuOpenedBy.click || menuOpenedBy.focus ) {
|
|
129
137
|
actions.closeMenu( 'click' );
|
|
130
138
|
actions.closeMenu( 'focus' );
|
|
139
|
+
// Also clear hover in case it was set by a synthetic pointerenter
|
|
140
|
+
// on touch (e.g. the browser-fired mouseenter-equivalent before
|
|
141
|
+
// the click event), ensuring the submenu fully closes.
|
|
142
|
+
actions.closeMenu( 'hover' );
|
|
131
143
|
} else {
|
|
132
144
|
ctx.previousFocus = ref;
|
|
133
145
|
actions.openMenu( 'click' );
|
|
@@ -5,14 +5,8 @@
|
|
|
5
5
|
* @package WordPress
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
require_once __DIR__ . '/shared/item-should-render.php';
|
|
11
|
-
require_once __DIR__ . '/shared/render-submenu-icon.php';
|
|
12
|
-
} else {
|
|
13
|
-
require_once __DIR__ . '/navigation-link/shared/item-should-render.php';
|
|
14
|
-
require_once __DIR__ . '/navigation-link/shared/render-submenu-icon.php';
|
|
15
|
-
}
|
|
8
|
+
require_once __DIR__ . '/navigation-link/shared/item-should-render.php';
|
|
9
|
+
require_once __DIR__ . '/navigation-link/shared/render-submenu-icon.php';
|
|
16
10
|
|
|
17
11
|
/**
|
|
18
12
|
* Build an array with CSS classes and inline styles defining the colors
|
|
@@ -262,7 +256,13 @@ function render_block_core_navigation_link( $attributes, $content, $block ) {
|
|
|
262
256
|
|
|
263
257
|
if ( isset( $block->context['showSubmenuIcon'] ) && $block->context['showSubmenuIcon'] && $has_submenu ) {
|
|
264
258
|
// The submenu icon can be hidden by a CSS rule on the Navigation Block.
|
|
265
|
-
$html .= '<span class="wp-block-navigation__submenu-icon">'
|
|
259
|
+
$html .= '<span class="wp-block-navigation__submenu-icon">';
|
|
260
|
+
if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) {
|
|
261
|
+
$html .= gutenberg_block_core_shared_navigation_render_submenu_icon();
|
|
262
|
+
} else {
|
|
263
|
+
$html .= block_core_shared_navigation_render_submenu_icon();
|
|
264
|
+
}
|
|
265
|
+
$html .= '</span>';
|
|
266
266
|
}
|
|
267
267
|
|
|
268
268
|
if ( $has_submenu ) {
|
|
@@ -485,4 +485,4 @@ add_action( 'init', 'register_block_core_navigation_link' );
|
|
|
485
485
|
* Creates all variations for post types / taxonomies dynamically (= each time when variations are requested).
|
|
486
486
|
* Do not use variation_callback, to also account for unregistering post types/taxonomies later on.
|
|
487
487
|
*/
|
|
488
|
-
|
|
488
|
+
add_filter( 'get_block_type_variations', 'block_core_navigation_link_filter_variations', 10, 2 );
|
|
@@ -36,6 +36,7 @@ jest.mock( '../../../lock-unlock', () => ( {
|
|
|
36
36
|
import {
|
|
37
37
|
computeDisplayUrl,
|
|
38
38
|
computeBadges,
|
|
39
|
+
isHomepage,
|
|
39
40
|
useLinkPreview,
|
|
40
41
|
} from '../use-link-preview';
|
|
41
42
|
|
|
@@ -144,6 +145,74 @@ describe( 'computeDisplayUrl', () => {
|
|
|
144
145
|
} );
|
|
145
146
|
} );
|
|
146
147
|
|
|
148
|
+
describe( 'isHomepage', () => {
|
|
149
|
+
const host = 'homepage.com';
|
|
150
|
+
const homeUrl = 'https://' + host;
|
|
151
|
+
|
|
152
|
+
test.each( [
|
|
153
|
+
[ '/', homeUrl ],
|
|
154
|
+
[ '/', undefined ],
|
|
155
|
+
] )( 'should return true for root path "%s"', ( url, homeUrlParam ) => {
|
|
156
|
+
expect( isHomepage( url, homeUrlParam ) ).toBe( true );
|
|
157
|
+
} );
|
|
158
|
+
|
|
159
|
+
// Check combinations of http/s and trailing slash
|
|
160
|
+
test.each( [
|
|
161
|
+
[ `http://${ host }`, homeUrl ],
|
|
162
|
+
[ `https://${ host }`, homeUrl ],
|
|
163
|
+
[ `http://${ host }/`, homeUrl ],
|
|
164
|
+
[ `https://${ host }/`, homeUrl ],
|
|
165
|
+
] )( 'should return true for site URL "%s"', ( url ) => {
|
|
166
|
+
expect( isHomepage( url, homeUrl ) ).toBe( true );
|
|
167
|
+
} );
|
|
168
|
+
|
|
169
|
+
test.each( [
|
|
170
|
+
[ '', homeUrl ],
|
|
171
|
+
[ `https://${ host }`, '' ],
|
|
172
|
+
[ `https://${ host }`, undefined ],
|
|
173
|
+
] )(
|
|
174
|
+
'should return false when url or homeUrl is empty and not a / path',
|
|
175
|
+
( url, homeUrlParam ) => {
|
|
176
|
+
expect( isHomepage( url, homeUrlParam ) ).toBe( false );
|
|
177
|
+
}
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
const subdomain = 'sub.' + host;
|
|
181
|
+
test.each( [
|
|
182
|
+
[ false, `http://${ subdomain }/`, homeUrl ],
|
|
183
|
+
[ false, `https://${ subdomain }`, homeUrl ],
|
|
184
|
+
[ true, `http://${ subdomain }/`, `https://${ subdomain }` ],
|
|
185
|
+
[ true, `https://${ subdomain }`, `https://${ subdomain }` ],
|
|
186
|
+
] )(
|
|
187
|
+
'should return %s for subdomain (url=%s, homeUrl=%s)',
|
|
188
|
+
( expected, url, homeUrlParam ) => {
|
|
189
|
+
expect( isHomepage( url, homeUrlParam ) ).toBe( expected );
|
|
190
|
+
}
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
const path = '/wordpress';
|
|
194
|
+
const subdirHomeUrl = 'https://' + host + path;
|
|
195
|
+
|
|
196
|
+
test.each( [
|
|
197
|
+
[ `https://${ host }${ path }`, subdirHomeUrl ],
|
|
198
|
+
[ `https://${ host }${ path }/`, subdirHomeUrl ],
|
|
199
|
+
[ `http://${ host }${ path }`, subdirHomeUrl ],
|
|
200
|
+
[ `http://${ host }${ path }/`, subdirHomeUrl ],
|
|
201
|
+
] )( 'should return true for subdirectory homepage "%s"', ( url ) => {
|
|
202
|
+
expect( isHomepage( url, subdirHomeUrl ) ).toBe( true );
|
|
203
|
+
} );
|
|
204
|
+
|
|
205
|
+
test.each( [
|
|
206
|
+
[ `https://${ host }/page`, homeUrl ],
|
|
207
|
+
[ '/page', homeUrl ],
|
|
208
|
+
[ `https://${ host }`, subdirHomeUrl ],
|
|
209
|
+
[ `https://${ host }/`, subdirHomeUrl ],
|
|
210
|
+
[ `https://${ host }${ path }/page`, subdirHomeUrl ],
|
|
211
|
+
] )( 'should return false for non-homepage "%s"', ( url, homeUrlParam ) => {
|
|
212
|
+
expect( isHomepage( url, homeUrlParam ) ).toBe( false );
|
|
213
|
+
} );
|
|
214
|
+
} );
|
|
215
|
+
|
|
147
216
|
describe( 'computeBadges', () => {
|
|
148
217
|
describe( 'kind badges', () => {
|
|
149
218
|
it( 'should show "External link" badge for external links', () => {
|
|
@@ -183,6 +252,67 @@ describe( 'computeBadges', () => {
|
|
|
183
252
|
} );
|
|
184
253
|
} );
|
|
185
254
|
|
|
255
|
+
it( 'should show "Homepage" badge for root path', () => {
|
|
256
|
+
const badges = computeBadges( {
|
|
257
|
+
url: '/',
|
|
258
|
+
isExternal: false,
|
|
259
|
+
} );
|
|
260
|
+
|
|
261
|
+
expect( badges ).toContainEqual( {
|
|
262
|
+
label: 'Homepage',
|
|
263
|
+
intent: 'default',
|
|
264
|
+
} );
|
|
265
|
+
} );
|
|
266
|
+
|
|
267
|
+
test.each( [
|
|
268
|
+
[ 'https://example.com' ],
|
|
269
|
+
[ 'https://example.com/' ],
|
|
270
|
+
[ 'http://example.com' ],
|
|
271
|
+
[ 'http://example.com/' ],
|
|
272
|
+
] )( 'should show "Homepage" badge when url is "%s"', ( url ) => {
|
|
273
|
+
const badges = computeBadges( {
|
|
274
|
+
url,
|
|
275
|
+
homeUrl: 'https://example.com',
|
|
276
|
+
isExternal: false,
|
|
277
|
+
} );
|
|
278
|
+
expect( badges ).toContainEqual( {
|
|
279
|
+
label: 'Homepage',
|
|
280
|
+
intent: 'default',
|
|
281
|
+
} );
|
|
282
|
+
} );
|
|
283
|
+
|
|
284
|
+
test.each( [ [ 'https://sub.example.com/', 'https://example.com' ] ] )(
|
|
285
|
+
'should not show Homepage badge when subdomain url "%s" does not match homeUrl "%s"',
|
|
286
|
+
( url, homeUrl ) => {
|
|
287
|
+
const badges = computeBadges( {
|
|
288
|
+
url,
|
|
289
|
+
homeUrl,
|
|
290
|
+
isExternal: false,
|
|
291
|
+
} );
|
|
292
|
+
expect( badges ).not.toContainEqual( {
|
|
293
|
+
label: 'Homepage',
|
|
294
|
+
intent: 'default',
|
|
295
|
+
} );
|
|
296
|
+
}
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
test.each( [
|
|
300
|
+
[ 'https://sub.example.com/', 'https://sub.example.com' ],
|
|
301
|
+
] )(
|
|
302
|
+
'should show Homepage badge when subdomain url "%s" matches homeUrl "%s"',
|
|
303
|
+
( url, homeUrl ) => {
|
|
304
|
+
const badges = computeBadges( {
|
|
305
|
+
url,
|
|
306
|
+
homeUrl,
|
|
307
|
+
isExternal: false,
|
|
308
|
+
} );
|
|
309
|
+
expect( badges ).toContainEqual( {
|
|
310
|
+
label: 'Homepage',
|
|
311
|
+
intent: 'default',
|
|
312
|
+
} );
|
|
313
|
+
}
|
|
314
|
+
);
|
|
315
|
+
|
|
186
316
|
it( 'should show page badge for relative paths', () => {
|
|
187
317
|
const badges = computeBadges( {
|
|
188
318
|
url: '/relative-path',
|
|
@@ -269,6 +399,25 @@ it( 'should show "Internal link" badge for hash links even when type is present'
|
|
|
269
399
|
} );
|
|
270
400
|
} );
|
|
271
401
|
|
|
402
|
+
it( 'should show "Homepage" badge for root path even when type is present', () => {
|
|
403
|
+
const badges = computeBadges( {
|
|
404
|
+
url: '/',
|
|
405
|
+
type: 'page',
|
|
406
|
+
isExternal: false,
|
|
407
|
+
} );
|
|
408
|
+
|
|
409
|
+
// Should prioritize homepage detection over type
|
|
410
|
+
expect( badges ).toContainEqual( {
|
|
411
|
+
label: 'Homepage',
|
|
412
|
+
intent: 'default',
|
|
413
|
+
} );
|
|
414
|
+
// Should NOT show Page badge
|
|
415
|
+
expect( badges ).not.toContainEqual( {
|
|
416
|
+
label: 'Page',
|
|
417
|
+
intent: 'default',
|
|
418
|
+
} );
|
|
419
|
+
} );
|
|
420
|
+
|
|
272
421
|
test.each( [
|
|
273
422
|
[ 'www.test.com', 'URLs without protocol' ],
|
|
274
423
|
[ 'google.com', 'domain-only URLs without protocol' ],
|