@wordpress/block-library 10.2.0 → 10.3.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 +16 -0
- package/build/accordion-panel/block.json +1 -0
- package/build/code/edit.cjs +3 -1
- package/build/code/edit.cjs.map +2 -2
- package/build/cover/block.json +1 -0
- package/build/cover/edit/block-controls.cjs +3 -1
- package/build/cover/edit/block-controls.cjs.map +2 -2
- package/build/cover/edit/index.cjs +75 -31
- package/build/cover/edit/index.cjs.map +2 -2
- package/build/embed/edit.cjs +1 -1
- package/build/embed/edit.cjs.map +2 -2
- package/build/embed/embed-placeholder.cjs +1 -1
- package/build/embed/embed-placeholder.cjs.map +2 -2
- package/build/gallery/dynamic-gallery.cjs +104 -61
- package/build/gallery/dynamic-gallery.cjs.map +3 -3
- package/build/gallery/use-dynamic-gallery.cjs +15 -8
- package/build/gallery/use-dynamic-gallery.cjs.map +2 -2
- package/build/heading/edit.cjs +1 -1
- package/build/heading/edit.cjs.map +2 -2
- package/build/html/modal.cjs +63 -54
- package/build/html/modal.cjs.map +3 -3
- package/build/icon/block.json +5 -3
- package/build/image/edit.cjs +1 -1
- package/build/image/edit.cjs.map +2 -2
- package/build/image/image.cjs +29 -5
- package/build/image/image.cjs.map +3 -3
- package/build/image/use-open-image-media-editor-modal.cjs +6 -2
- package/build/image/use-open-image-media-editor-modal.cjs.map +2 -2
- package/build/list-item/hooks/use-indent-list-item.cjs +10 -2
- package/build/list-item/hooks/use-indent-list-item.cjs.map +2 -2
- package/build/math/edit.cjs +39 -56
- package/build/math/edit.cjs.map +3 -3
- package/build/media-text/edit.cjs +2 -1
- package/build/media-text/edit.cjs.map +2 -2
- package/build/more/edit.cjs +2 -2
- package/build/more/edit.cjs.map +2 -2
- package/build/navigation/edit/index.cjs +30 -16
- package/build/navigation/edit/index.cjs.map +3 -3
- package/build/navigation/edit/use-layout-custom-properties.cjs +72 -0
- package/build/navigation/edit/use-layout-custom-properties.cjs.map +7 -0
- package/build/navigation/view.cjs +9 -6
- package/build/navigation/view.cjs.map +2 -2
- package/build/navigation-link/edit.cjs +3 -3
- package/build/navigation-link/edit.cjs.map +2 -2
- package/build/navigation-link/link-ui/index.cjs +2 -2
- package/build/navigation-link/link-ui/index.cjs.map +2 -2
- package/build/paragraph/block.json +0 -1
- package/build/paragraph/edit.cjs +5 -2
- package/build/paragraph/edit.cjs.map +3 -3
- package/build/paragraph/index.cjs +4 -1
- package/build/paragraph/index.cjs.map +2 -2
- package/build/playlist/context.cjs +2 -1
- package/build/playlist/context.cjs.map +2 -2
- package/build/playlist/edit.cjs +113 -26
- package/build/playlist/edit.cjs.map +2 -2
- package/build/playlist/utils.cjs +19 -4
- package/build/playlist/utils.cjs.map +2 -2
- package/build/playlist-track/edit.cjs +21 -6
- package/build/playlist-track/edit.cjs.map +2 -2
- package/build/post-content/edit.cjs +36 -15
- package/build/post-content/edit.cjs.map +2 -2
- package/build/post-featured-image/edit.cjs +3 -2
- package/build/post-featured-image/edit.cjs.map +2 -2
- package/build/post-terms/edit.cjs +2 -2
- package/build/post-terms/edit.cjs.map +2 -2
- package/build/post-title/edit.cjs +2 -2
- package/build/post-title/edit.cjs.map +2 -2
- package/build/preformatted/edit.cjs +3 -1
- package/build/preformatted/edit.cjs.map +2 -2
- package/build/pullquote/edit.cjs +5 -3
- package/build/pullquote/edit.cjs.map +2 -2
- package/build/query/edit/inspector-controls/index.cjs +4 -1
- package/build/query/edit/inspector-controls/index.cjs.map +2 -2
- package/build/query/edit/inspector-controls/offset-controls.cjs +1 -1
- package/build/query/edit/inspector-controls/offset-controls.cjs.map +2 -2
- package/build/read-more/edit.cjs +3 -1
- package/build/read-more/edit.cjs.map +2 -2
- package/build/site-tagline/edit.cjs +3 -1
- package/build/site-tagline/edit.cjs.map +2 -2
- package/build/site-title/edit.cjs +3 -1
- package/build/site-title/edit.cjs.map +2 -2
- package/build/social-links/edit.cjs +11 -4
- package/build/social-links/edit.cjs.map +2 -2
- package/build/tab-list/block.json +2 -1
- package/build/tab-list/edit.cjs +2 -0
- package/build/tab-list/edit.cjs.map +3 -3
- package/build/tab-list/tab-movers.cjs +87 -0
- package/build/tab-list/tab-movers.cjs.map +7 -0
- package/build/tab-panel/edit.cjs +1 -9
- package/build/tab-panel/edit.cjs.map +2 -2
- package/build/table/edit.cjs +1 -1
- package/build/table/edit.cjs.map +2 -2
- package/build/tabs/use-tab-actions.cjs +23 -1
- package/build/tabs/use-tab-actions.cjs.map +2 -2
- package/build/utils/caption.cjs +2 -2
- package/build/utils/caption.cjs.map +2 -2
- package/build/verse/edit.cjs +3 -1
- package/build/verse/edit.cjs.map +2 -2
- package/build/video/tracks-editor.cjs +0 -1
- package/build/video/tracks-editor.cjs.map +2 -2
- package/build-module/accordion-panel/block.json +1 -0
- package/build-module/code/edit.mjs +3 -1
- package/build-module/code/edit.mjs.map +2 -2
- package/build-module/cover/block.json +1 -0
- package/build-module/cover/edit/block-controls.mjs +3 -1
- package/build-module/cover/edit/block-controls.mjs.map +2 -2
- package/build-module/cover/edit/index.mjs +78 -34
- package/build-module/cover/edit/index.mjs.map +2 -2
- package/build-module/embed/edit.mjs +1 -1
- package/build-module/embed/edit.mjs.map +2 -2
- package/build-module/embed/embed-placeholder.mjs +1 -1
- package/build-module/embed/embed-placeholder.mjs.map +2 -2
- package/build-module/gallery/dynamic-gallery.mjs +104 -61
- package/build-module/gallery/dynamic-gallery.mjs.map +2 -2
- package/build-module/gallery/use-dynamic-gallery.mjs +16 -9
- package/build-module/gallery/use-dynamic-gallery.mjs.map +2 -2
- package/build-module/heading/edit.mjs +1 -1
- package/build-module/heading/edit.mjs.map +2 -2
- package/build-module/html/modal.mjs +68 -55
- package/build-module/html/modal.mjs.map +2 -2
- package/build-module/icon/block.json +5 -3
- package/build-module/image/edit.mjs +1 -1
- package/build-module/image/edit.mjs.map +2 -2
- package/build-module/image/image.mjs +19 -5
- package/build-module/image/image.mjs.map +2 -2
- package/build-module/image/use-open-image-media-editor-modal.mjs +6 -2
- package/build-module/image/use-open-image-media-editor-modal.mjs.map +2 -2
- package/build-module/list-item/hooks/use-indent-list-item.mjs +10 -2
- package/build-module/list-item/hooks/use-indent-list-item.mjs.map +2 -2
- package/build-module/math/edit.mjs +41 -60
- package/build-module/math/edit.mjs.map +2 -2
- package/build-module/media-text/edit.mjs +2 -1
- package/build-module/media-text/edit.mjs.map +2 -2
- package/build-module/more/edit.mjs +2 -2
- package/build-module/more/edit.mjs.map +2 -2
- package/build-module/navigation/edit/index.mjs +30 -16
- package/build-module/navigation/edit/index.mjs.map +2 -2
- package/build-module/navigation/edit/use-layout-custom-properties.mjs +51 -0
- package/build-module/navigation/edit/use-layout-custom-properties.mjs.map +7 -0
- package/build-module/navigation/view.mjs +9 -6
- package/build-module/navigation/view.mjs.map +2 -2
- package/build-module/navigation-link/edit.mjs +3 -3
- package/build-module/navigation-link/edit.mjs.map +2 -2
- package/build-module/navigation-link/link-ui/index.mjs +2 -2
- package/build-module/navigation-link/link-ui/index.mjs.map +2 -2
- package/build-module/paragraph/block.json +0 -1
- package/build-module/paragraph/edit.mjs +6 -2
- package/build-module/paragraph/edit.mjs.map +2 -2
- package/build-module/paragraph/index.mjs +4 -1
- package/build-module/paragraph/index.mjs.map +2 -2
- package/build-module/playlist/context.mjs +2 -1
- package/build-module/playlist/context.mjs.map +2 -2
- package/build-module/playlist/edit.mjs +113 -27
- package/build-module/playlist/edit.mjs.map +2 -2
- package/build-module/playlist/utils.mjs +19 -4
- package/build-module/playlist/utils.mjs.map +2 -2
- package/build-module/playlist-track/edit.mjs +21 -6
- package/build-module/playlist-track/edit.mjs.map +2 -2
- package/build-module/post-content/edit.mjs +37 -15
- package/build-module/post-content/edit.mjs.map +2 -2
- package/build-module/post-featured-image/edit.mjs +3 -2
- package/build-module/post-featured-image/edit.mjs.map +2 -2
- package/build-module/post-terms/edit.mjs +2 -2
- package/build-module/post-terms/edit.mjs.map +2 -2
- package/build-module/post-title/edit.mjs +2 -2
- package/build-module/post-title/edit.mjs.map +2 -2
- package/build-module/preformatted/edit.mjs +3 -1
- package/build-module/preformatted/edit.mjs.map +2 -2
- package/build-module/pullquote/edit.mjs +5 -3
- package/build-module/pullquote/edit.mjs.map +2 -2
- package/build-module/query/edit/inspector-controls/index.mjs +5 -2
- package/build-module/query/edit/inspector-controls/index.mjs.map +2 -2
- package/build-module/query/edit/inspector-controls/offset-controls.mjs +2 -2
- package/build-module/query/edit/inspector-controls/offset-controls.mjs.map +2 -2
- package/build-module/read-more/edit.mjs +3 -1
- package/build-module/read-more/edit.mjs.map +2 -2
- package/build-module/site-tagline/edit.mjs +3 -1
- package/build-module/site-tagline/edit.mjs.map +2 -2
- package/build-module/site-title/edit.mjs +3 -1
- package/build-module/site-title/edit.mjs.map +2 -2
- package/build-module/social-links/edit.mjs +11 -4
- package/build-module/social-links/edit.mjs.map +2 -2
- package/build-module/tab-list/block.json +2 -1
- package/build-module/tab-list/edit.mjs +2 -0
- package/build-module/tab-list/edit.mjs.map +2 -2
- package/build-module/tab-list/tab-movers.mjs +59 -0
- package/build-module/tab-list/tab-movers.mjs.map +7 -0
- package/build-module/tab-panel/edit.mjs +1 -9
- package/build-module/tab-panel/edit.mjs.map +2 -2
- package/build-module/table/edit.mjs +1 -1
- package/build-module/table/edit.mjs.map +2 -2
- package/build-module/tabs/use-tab-actions.mjs +23 -1
- package/build-module/tabs/use-tab-actions.mjs.map +2 -2
- package/build-module/utils/caption.mjs +2 -2
- package/build-module/utils/caption.mjs.map +2 -2
- package/build-module/verse/edit.mjs +3 -1
- package/build-module/verse/edit.mjs.map +2 -2
- package/build-module/video/tracks-editor.mjs +0 -1
- package/build-module/video/tracks-editor.mjs.map +2 -2
- package/build-style/cover/editor-rtl.css +3 -0
- package/build-style/cover/editor.css +3 -0
- package/build-style/editor-rtl.css +18 -41
- package/build-style/editor.css +18 -41
- package/build-style/icon/editor-rtl.css +1 -4
- package/build-style/icon/editor.css +1 -4
- package/build-style/image/editor-rtl.css +3 -32
- package/build-style/image/editor.css +3 -32
- package/build-style/playlist/editor-rtl.css +0 -5
- package/build-style/playlist/editor.css +0 -5
- package/build-style/playlist/style-rtl.css +44 -4
- package/build-style/playlist/style.css +44 -4
- package/build-style/pullquote/editor-rtl.css +4 -0
- package/build-style/pullquote/editor.css +4 -0
- package/build-style/style-rtl.css +44 -4
- package/build-style/style.css +44 -4
- package/build-style/tab-list/editor-rtl.css +101 -0
- package/build-style/tab-list/editor.css +101 -0
- package/package.json +43 -43
- package/src/accordion-panel/block.json +1 -0
- package/src/breadcrumbs/index.php +3 -1
- package/src/button/index.php +1 -1
- package/src/code/edit.js +7 -2
- package/src/cover/block.json +1 -0
- package/src/cover/edit/block-controls.js +5 -0
- package/src/cover/edit/index.js +100 -35
- package/src/cover/editor.scss +6 -0
- package/src/cover/index.php +9 -2
- package/src/editor.scss +1 -0
- package/src/embed/edit.js +3 -1
- package/src/embed/embed-placeholder.js +9 -7
- package/src/form/index.php +6 -4
- package/src/gallery/dynamic-gallery.js +133 -74
- package/src/gallery/use-dynamic-gallery.js +27 -12
- package/src/heading/edit.js +1 -1
- package/src/html/modal.js +13 -2
- package/src/icon/README.md +1 -3
- package/src/icon/block.json +5 -3
- package/src/icon/editor.scss +1 -4
- package/src/image/edit.js +1 -5
- package/src/image/editor.scss +6 -46
- package/src/image/image.js +37 -3
- package/src/image/test/use-open-image-media-editor-modal.js +37 -1
- package/src/image/use-open-image-media-editor-modal.js +8 -1
- package/src/latest-posts/index.php +3 -2
- package/src/list-item/hooks/use-indent-list-item.js +10 -1
- package/src/math/edit.js +42 -59
- package/src/media-text/edit.js +1 -0
- package/src/media-text/index.php +11 -2
- package/src/more/edit.js +7 -4
- package/src/navigation/edit/index.js +52 -36
- package/src/navigation/edit/test/layout-custom-properties.js +138 -0
- package/src/navigation/edit/use-layout-custom-properties.js +84 -0
- package/src/navigation/index.php +123 -12
- package/src/navigation/test/view.js +51 -0
- package/src/navigation/view.js +15 -14
- package/src/navigation-link/edit.js +11 -7
- package/src/navigation-link/index.php +64 -0
- package/src/navigation-link/link-ui/index.js +2 -1
- package/src/navigation-link/test/__snapshots__/hooks.js.snap +1 -1
- package/src/page-list/index.php +4 -3
- package/src/paragraph/README.md +0 -1
- package/src/paragraph/block.json +0 -1
- package/src/paragraph/edit.js +9 -2
- package/src/paragraph/index.js +4 -1
- package/src/pattern/index.php +5 -5
- package/src/playlist/context.js +1 -0
- package/src/playlist/edit.js +151 -47
- package/src/playlist/editor.scss +0 -7
- package/src/playlist/index.php +14 -9
- package/src/playlist/style.scss +3 -0
- package/src/playlist/test/edit-component.js +139 -0
- package/src/playlist/test/edit.js +30 -0
- package/src/playlist/utils.js +25 -4
- package/src/playlist-track/edit.js +22 -5
- package/src/playlist-track/index.php +8 -7
- package/src/playlist-track/test/edit.js +87 -3
- package/src/post-content/edit.js +45 -16
- package/src/post-excerpt/index.php +4 -1
- package/src/post-featured-image/edit.js +3 -2
- package/src/post-featured-image/index.php +4 -1
- package/src/post-terms/edit.js +7 -4
- package/src/post-title/edit.js +5 -3
- package/src/preformatted/edit.js +7 -2
- package/src/pullquote/edit.js +9 -4
- package/src/pullquote/editor.scss +6 -0
- package/src/query/edit/inspector-controls/index.js +5 -2
- package/src/query/edit/inspector-controls/offset-controls.js +2 -2
- package/src/read-more/edit.js +7 -2
- package/src/rss/index.php +9 -3
- package/src/site-tagline/edit.js +7 -2
- package/src/site-title/edit.js +7 -2
- package/src/social-link/index.php +19 -9
- package/src/social-links/edit.js +21 -12
- package/src/tab-list/block.json +2 -1
- package/src/tab-list/edit.js +2 -0
- package/src/tab-list/editor.scss +9 -0
- package/src/tab-list/tab-movers.js +72 -0
- package/src/tab-panel/edit.js +1 -9
- package/src/table/edit.js +1 -1
- package/src/table-of-contents/index.php +386 -1
- package/src/tabs/use-tab-actions.js +32 -3
- package/src/tag-cloud/index.php +3 -2
- package/src/template-part/index.php +2 -1
- package/src/utils/caption.js +7 -4
- package/src/utils/test/waveform-utils.js +63 -0
- package/src/verse/edit.js +7 -2
- package/src/video/index.php +2 -2
- package/src/video/tracks-editor.js +0 -1
|
@@ -75,6 +75,7 @@ import AccessibleMenuDescription from './accessible-menu-description';
|
|
|
75
75
|
import { unlock } from '../../lock-unlock';
|
|
76
76
|
import { useToolsPanelDropdownMenuProps } from '../../utils/hooks';
|
|
77
77
|
import { isWithinNavigationOverlay } from '../../utils/is-within-overlay';
|
|
78
|
+
import useLayoutCustomProperties from './use-layout-custom-properties';
|
|
78
79
|
import {
|
|
79
80
|
DEFAULT_BLOCK,
|
|
80
81
|
NAVIGATION_OVERLAY_TEMPLATE_PART_AREA,
|
|
@@ -280,6 +281,11 @@ function Navigation( {
|
|
|
280
281
|
} = attributes;
|
|
281
282
|
|
|
282
283
|
const ref = attributes.ref;
|
|
284
|
+
useLayoutCustomProperties( {
|
|
285
|
+
clientId,
|
|
286
|
+
layout: attributes.layout,
|
|
287
|
+
style: attributes.style,
|
|
288
|
+
} );
|
|
283
289
|
|
|
284
290
|
const setRef = useCallback(
|
|
285
291
|
( postId ) => {
|
|
@@ -297,22 +303,30 @@ function Navigation( {
|
|
|
297
303
|
onNavigateToEntityRecord,
|
|
298
304
|
currentTheme,
|
|
299
305
|
editorDisabledResponsive,
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
306
|
+
hasSelectedStyleState,
|
|
307
|
+
} = useSelect(
|
|
308
|
+
( select ) => {
|
|
309
|
+
const {
|
|
310
|
+
getSettings,
|
|
311
|
+
hasSelectedStyleState: hasSelectedBlockStyleState,
|
|
312
|
+
} = unlock( select( blockEditorStore ) );
|
|
313
|
+
const settings = getSettings();
|
|
314
|
+
|
|
315
|
+
return {
|
|
316
|
+
isPreviewMode: settings.isPreviewMode,
|
|
317
|
+
onNavigateToEntityRecord: settings?.onNavigateToEntityRecord,
|
|
318
|
+
// Needed to construct the template part ID for the overlay preview.
|
|
319
|
+
currentTheme: select( coreStore ).getCurrentTheme()?.stylesheet,
|
|
320
|
+
// When editing a navigation post directly in an isolated editor,
|
|
321
|
+
// always show navigation expanded (no hamburger) so users can see
|
|
322
|
+
// and interact with all menu items.
|
|
323
|
+
editorDisabledResponsive:
|
|
324
|
+
!! settings?.[ isNavigationPostEditorKey ],
|
|
325
|
+
hasSelectedStyleState: hasSelectedBlockStyleState( clientId ),
|
|
326
|
+
};
|
|
327
|
+
},
|
|
328
|
+
[ clientId ]
|
|
329
|
+
);
|
|
316
330
|
const hasAlreadyRendered = isPreviewMode ? false : recursionDetected;
|
|
317
331
|
|
|
318
332
|
const blockEditingMode = useBlockEditingMode();
|
|
@@ -924,26 +938,28 @@ function Navigation( {
|
|
|
924
938
|
/>
|
|
925
939
|
</InspectorControls>
|
|
926
940
|
) }
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
941
|
+
{ ! hasSelectedStyleState && (
|
|
942
|
+
<InspectorControls group="color">
|
|
943
|
+
{ /*
|
|
944
|
+
* Avoid useMultipleOriginColorsAndGradients and detectColors
|
|
945
|
+
* on block mount. InspectorControls only mounts this component
|
|
946
|
+
* when the block is selected.
|
|
947
|
+
* */ }
|
|
948
|
+
<ColorTools
|
|
949
|
+
textColor={ textColor }
|
|
950
|
+
setTextColor={ setTextColor }
|
|
951
|
+
backgroundColor={ backgroundColor }
|
|
952
|
+
setBackgroundColor={ setBackgroundColor }
|
|
953
|
+
overlayTextColor={ overlayTextColor }
|
|
954
|
+
setOverlayTextColor={ setOverlayTextColor }
|
|
955
|
+
overlayBackgroundColor={ overlayBackgroundColor }
|
|
956
|
+
setOverlayBackgroundColor={ setOverlayBackgroundColor }
|
|
957
|
+
clientId={ clientId }
|
|
958
|
+
navRef={ navRef }
|
|
959
|
+
hasCustomOverlay={ !! overlay }
|
|
960
|
+
/>
|
|
961
|
+
</InspectorControls>
|
|
962
|
+
) }
|
|
947
963
|
</>
|
|
948
964
|
);
|
|
949
965
|
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { renderHook } from '@testing-library/react';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* WordPress dependencies
|
|
8
|
+
*/
|
|
9
|
+
import { useSettings, useStyleOverride } from '@wordpress/block-editor';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Internal dependencies
|
|
13
|
+
*/
|
|
14
|
+
import useLayoutCustomProperties from '../use-layout-custom-properties';
|
|
15
|
+
|
|
16
|
+
const mockGetResponsiveMediaQueries = jest.fn();
|
|
17
|
+
|
|
18
|
+
jest.mock( '@wordpress/block-editor', () => ( {
|
|
19
|
+
useSettings: jest.fn(),
|
|
20
|
+
useStyleOverride: jest.fn(),
|
|
21
|
+
} ) );
|
|
22
|
+
|
|
23
|
+
jest.mock( '@wordpress/global-styles-engine', () => ( {
|
|
24
|
+
privateApis: {},
|
|
25
|
+
} ) );
|
|
26
|
+
|
|
27
|
+
jest.mock( '../../../lock-unlock', () => ( {
|
|
28
|
+
unlock: () => ( {
|
|
29
|
+
getResponsiveMediaQueries: ( ...args ) =>
|
|
30
|
+
mockGetResponsiveMediaQueries( ...args ),
|
|
31
|
+
} ),
|
|
32
|
+
} ) );
|
|
33
|
+
|
|
34
|
+
describe( 'Navigation layout custom properties', () => {
|
|
35
|
+
beforeEach( () => {
|
|
36
|
+
jest.clearAllMocks();
|
|
37
|
+
useSettings.mockReturnValue( [ { mobile: 480, tablet: 782 } ] );
|
|
38
|
+
mockGetResponsiveMediaQueries.mockReturnValue( {
|
|
39
|
+
'@tablet': '@media (480px < width <= 782px)',
|
|
40
|
+
'@mobile': '@media (width <= 480px)',
|
|
41
|
+
} );
|
|
42
|
+
} );
|
|
43
|
+
|
|
44
|
+
describe( 'vertical layouts', () => {
|
|
45
|
+
it.each( [
|
|
46
|
+
[ 'left', 'initial', 'flex-start' ],
|
|
47
|
+
[ 'center', 'center', 'center' ],
|
|
48
|
+
[ 'right', 'flex-end', 'flex-end' ],
|
|
49
|
+
[ 'space-between', 'space-between', 'flex-start' ],
|
|
50
|
+
] )(
|
|
51
|
+
'reproduces the vertical %s class cascade',
|
|
52
|
+
( justifyContent, justify, align ) => {
|
|
53
|
+
renderHook( () =>
|
|
54
|
+
useLayoutCustomProperties( {
|
|
55
|
+
clientId: 'test',
|
|
56
|
+
style: {
|
|
57
|
+
'@mobile': {
|
|
58
|
+
layout: {
|
|
59
|
+
orientation: 'vertical',
|
|
60
|
+
justifyContent,
|
|
61
|
+
flexWrap: 'nowrap',
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
} )
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
const { css } = useStyleOverride.mock.calls.at( -1 )[ 0 ];
|
|
69
|
+
expect( css ).toContain(
|
|
70
|
+
'--navigation-layout-direction: column;'
|
|
71
|
+
);
|
|
72
|
+
expect( css ).toContain( '--navigation-layout-wrap: nowrap;' );
|
|
73
|
+
expect( css ).toContain(
|
|
74
|
+
`--navigation-layout-justify: ${ justify };`
|
|
75
|
+
);
|
|
76
|
+
expect( css ).toContain(
|
|
77
|
+
`--navigation-layout-align: ${ align };`
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
} );
|
|
82
|
+
|
|
83
|
+
describe( 'responsive styles', () => {
|
|
84
|
+
it( 'merges viewport overrides with the base layout', () => {
|
|
85
|
+
renderHook( () =>
|
|
86
|
+
useLayoutCustomProperties( {
|
|
87
|
+
clientId: 'test',
|
|
88
|
+
layout: {
|
|
89
|
+
justifyContent: 'right',
|
|
90
|
+
flexWrap: 'nowrap',
|
|
91
|
+
},
|
|
92
|
+
style: {
|
|
93
|
+
'@mobile': {
|
|
94
|
+
layout: { orientation: 'vertical' },
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
} )
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
expect( useStyleOverride ).toHaveBeenCalledWith( {
|
|
101
|
+
css: '@media (width <= 480px){#block-test {--navigation-layout-justification-setting: flex-end;--navigation-layout-direction: column;--navigation-layout-wrap: nowrap;--navigation-layout-justify: flex-end;--navigation-layout-align: flex-end;}}',
|
|
102
|
+
} );
|
|
103
|
+
} );
|
|
104
|
+
|
|
105
|
+
it( 'uses default values for explicit viewport resets', () => {
|
|
106
|
+
renderHook( () =>
|
|
107
|
+
useLayoutCustomProperties( {
|
|
108
|
+
clientId: 'test',
|
|
109
|
+
layout: { justifyContent: 'right' },
|
|
110
|
+
style: {
|
|
111
|
+
'@tablet': {
|
|
112
|
+
layout: { justifyContent: null },
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
} )
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
expect( useStyleOverride ).toHaveBeenCalledWith( {
|
|
119
|
+
css: expect.stringContaining(
|
|
120
|
+
'--navigation-layout-justify: flex-start;'
|
|
121
|
+
),
|
|
122
|
+
} );
|
|
123
|
+
} );
|
|
124
|
+
|
|
125
|
+
it( 'does not emit styles without a viewport layout override', () => {
|
|
126
|
+
renderHook( () =>
|
|
127
|
+
useLayoutCustomProperties( {
|
|
128
|
+
clientId: 'test',
|
|
129
|
+
style: {
|
|
130
|
+
'@mobile': { spacing: { blockGap: '10px' } },
|
|
131
|
+
},
|
|
132
|
+
} )
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
expect( useStyleOverride ).toHaveBeenCalledWith( { css: '' } );
|
|
136
|
+
} );
|
|
137
|
+
} );
|
|
138
|
+
} );
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { useSettings, useStyleOverride } from '@wordpress/block-editor';
|
|
5
|
+
import { privateApis as globalStylesEnginePrivateApis } from '@wordpress/global-styles-engine';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Internal dependencies
|
|
9
|
+
*/
|
|
10
|
+
import { unlock } from '../../lock-unlock';
|
|
11
|
+
|
|
12
|
+
const { getResponsiveMediaQueries } = unlock( globalStylesEnginePrivateApis );
|
|
13
|
+
|
|
14
|
+
const JUSTIFICATION_VALUES = {
|
|
15
|
+
left: 'flex-start',
|
|
16
|
+
center: 'center',
|
|
17
|
+
right: 'flex-end',
|
|
18
|
+
'space-between': 'space-between',
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Adds responsive Navigation layout custom properties to the editor canvas.
|
|
23
|
+
*
|
|
24
|
+
* @param {Object} options Options.
|
|
25
|
+
* @param {string} options.clientId Block client ID.
|
|
26
|
+
* @param {Object} options.layout Base layout configuration.
|
|
27
|
+
* @param {Object} options.style Block style attribute.
|
|
28
|
+
*/
|
|
29
|
+
export default function useLayoutCustomProperties( {
|
|
30
|
+
clientId,
|
|
31
|
+
layout,
|
|
32
|
+
style,
|
|
33
|
+
} ) {
|
|
34
|
+
const [ viewportSettings ] = useSettings( 'viewport' );
|
|
35
|
+
const selector = `#block-${ clientId }`;
|
|
36
|
+
const css = Object.entries( getResponsiveMediaQueries( viewportSettings ) )
|
|
37
|
+
.map( ( [ viewport, mediaQuery ] ) => {
|
|
38
|
+
const viewportLayout = style?.[ viewport ]?.layout;
|
|
39
|
+
if (
|
|
40
|
+
! viewportLayout ||
|
|
41
|
+
typeof viewportLayout !== 'object' ||
|
|
42
|
+
Array.isArray( viewportLayout ) ||
|
|
43
|
+
! Object.keys( viewportLayout ).length
|
|
44
|
+
) {
|
|
45
|
+
return '';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const effectiveLayout = { ...layout, ...viewportLayout };
|
|
49
|
+
const justifyContent = Object.hasOwn(
|
|
50
|
+
JUSTIFICATION_VALUES,
|
|
51
|
+
effectiveLayout.justifyContent
|
|
52
|
+
)
|
|
53
|
+
? effectiveLayout.justifyContent
|
|
54
|
+
: 'left';
|
|
55
|
+
const justification = JUSTIFICATION_VALUES[ justifyContent ];
|
|
56
|
+
const isVertical = effectiveLayout.orientation === 'vertical';
|
|
57
|
+
let align = 'center';
|
|
58
|
+
if ( isVertical ) {
|
|
59
|
+
align = [ 'center', 'right' ].includes( justifyContent )
|
|
60
|
+
? justification
|
|
61
|
+
: 'flex-start';
|
|
62
|
+
}
|
|
63
|
+
const justify =
|
|
64
|
+
isVertical && justifyContent === 'left'
|
|
65
|
+
? 'initial'
|
|
66
|
+
: justification;
|
|
67
|
+
const declarations = {
|
|
68
|
+
'--navigation-layout-justification-setting': justification,
|
|
69
|
+
'--navigation-layout-direction': isVertical ? 'column' : 'row',
|
|
70
|
+
'--navigation-layout-wrap':
|
|
71
|
+
effectiveLayout.flexWrap === 'nowrap' ? 'nowrap' : 'wrap',
|
|
72
|
+
'--navigation-layout-justify': justify,
|
|
73
|
+
'--navigation-layout-align': align,
|
|
74
|
+
};
|
|
75
|
+
const cssDeclarations = Object.entries( declarations )
|
|
76
|
+
.map( ( [ property, value ] ) => `${ property }: ${ value };` )
|
|
77
|
+
.join( '' );
|
|
78
|
+
|
|
79
|
+
return `${ mediaQuery }{${ selector } {${ cssDeclarations }}}`;
|
|
80
|
+
} )
|
|
81
|
+
.join( '' );
|
|
82
|
+
|
|
83
|
+
useStyleOverride( { css } );
|
|
84
|
+
}
|
package/src/navigation/index.php
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* will always have a value even for legacy blocks. We check the legacy openSubmenusOnClick
|
|
17
17
|
* attribute first to preserve original behavior for blocks saved before the migration.
|
|
18
18
|
*
|
|
19
|
-
* @since
|
|
19
|
+
* @since 7.0.0
|
|
20
20
|
*
|
|
21
21
|
* @param array $attributes Block attributes containing submenuVisibility and/or openSubmenusOnClick.
|
|
22
22
|
* @return string The visibility mode: 'hover', 'click', or 'always'.
|
|
@@ -40,6 +40,45 @@ function block_core_navigation_get_submenu_visibility( $attributes ) {
|
|
|
40
40
|
return $submenu_visibility ?? 'hover';
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Returns the custom properties used by the Navigation block for a layout.
|
|
45
|
+
*
|
|
46
|
+
* @since 7.1.0
|
|
47
|
+
*
|
|
48
|
+
* @param array $layout Layout configuration.
|
|
49
|
+
* @return array Navigation layout custom property declarations.
|
|
50
|
+
*/
|
|
51
|
+
function block_core_navigation_get_layout_custom_property_declarations( $layout ) {
|
|
52
|
+
$justification_values = array(
|
|
53
|
+
'left' => 'flex-start',
|
|
54
|
+
'center' => 'center',
|
|
55
|
+
'right' => 'flex-end',
|
|
56
|
+
'space-between' => 'space-between',
|
|
57
|
+
);
|
|
58
|
+
$justify_content = is_array( $layout ) ? ( $layout['justifyContent'] ?? 'left' ) : 'left';
|
|
59
|
+
if ( ! is_string( $justify_content ) || ! isset( $justification_values[ $justify_content ] ) ) {
|
|
60
|
+
$justify_content = 'left';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
$justification = $justification_values[ $justify_content ];
|
|
64
|
+
$is_vertical = is_array( $layout ) && 'vertical' === ( $layout['orientation'] ?? null );
|
|
65
|
+
$align = 'center';
|
|
66
|
+
$justify = $justification;
|
|
67
|
+
|
|
68
|
+
if ( $is_vertical ) {
|
|
69
|
+
$align = in_array( $justify_content, array( 'center', 'right' ), true ) ? $justification : 'flex-start';
|
|
70
|
+
$justify = 'left' === $justify_content ? 'initial' : $justification;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return array(
|
|
74
|
+
'--navigation-layout-justification-setting' => $justification,
|
|
75
|
+
'--navigation-layout-direction' => $is_vertical ? 'column' : 'row',
|
|
76
|
+
'--navigation-layout-wrap' => is_array( $layout ) && 'nowrap' === ( $layout['flexWrap'] ?? null ) ? 'nowrap' : 'wrap',
|
|
77
|
+
'--navigation-layout-justify' => $justify,
|
|
78
|
+
'--navigation-layout-align' => $align,
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
43
82
|
/**
|
|
44
83
|
* Helper functions used to render the navigation block.
|
|
45
84
|
*
|
|
@@ -576,12 +615,13 @@ class WP_Navigation_Block_Renderer {
|
|
|
576
615
|
'space-between' => 'items-justified-space-between',
|
|
577
616
|
);
|
|
578
617
|
|
|
579
|
-
$layout_class
|
|
618
|
+
$layout_class = '';
|
|
619
|
+
$nav_justify_content = $attributes['layout']['justifyContent'] ?? null;
|
|
580
620
|
if (
|
|
581
|
-
|
|
582
|
-
isset( $layout_justification[ $
|
|
621
|
+
is_string( $nav_justify_content ) &&
|
|
622
|
+
isset( $layout_justification[ $nav_justify_content ] )
|
|
583
623
|
) {
|
|
584
|
-
$layout_class .= $layout_justification[ $
|
|
624
|
+
$layout_class .= $layout_justification[ $nav_justify_content ];
|
|
585
625
|
}
|
|
586
626
|
if ( isset( $attributes['layout']['orientation'] ) && 'vertical' === $attributes['layout']['orientation'] ) {
|
|
587
627
|
$layout_class .= ' is-vertical';
|
|
@@ -1211,7 +1251,7 @@ function block_core_navigation_add_directives_to_submenu( $tags, $block_attribut
|
|
|
1211
1251
|
)
|
|
1212
1252
|
) ) {
|
|
1213
1253
|
$tags->set_attribute( 'data-wp-on--click', 'actions.toggleMenuOnClick' );
|
|
1214
|
-
$tags->set_attribute( 'data-wp-bind--aria-expanded', 'state.
|
|
1254
|
+
$tags->set_attribute( 'data-wp-bind--aria-expanded', 'state.isSubmenuOpen' );
|
|
1215
1255
|
// The `aria-expanded` attribute for SSR is already added in the submenu block.
|
|
1216
1256
|
}
|
|
1217
1257
|
// Add directives to the submenu.
|
|
@@ -1558,13 +1598,18 @@ function register_block_core_navigation() {
|
|
|
1558
1598
|
add_action( 'init', 'register_block_core_navigation' );
|
|
1559
1599
|
|
|
1560
1600
|
/**
|
|
1561
|
-
* Adds
|
|
1601
|
+
* Adds Navigation block support classes to inner list containers.
|
|
1562
1602
|
*
|
|
1563
1603
|
* State block support adds the generated `wp-states-*` class to the outer
|
|
1564
1604
|
* block wrapper. The Navigation block renders its menu items inside an inner
|
|
1565
1605
|
* `wp-block-navigation__container` list, so the same state class is also needed
|
|
1566
1606
|
* there for state styles to apply directly to the menu list.
|
|
1567
1607
|
*
|
|
1608
|
+
* Navigation also uses layout classes on its outer wrapper to define custom
|
|
1609
|
+
* properties consumed by its inner containers. Viewport layout styles cannot
|
|
1610
|
+
* change those classes, so equivalent custom properties and a scoping class
|
|
1611
|
+
* are generated for each configured viewport layout.
|
|
1612
|
+
*
|
|
1568
1613
|
* Currently this is required as a workaround because of how difficult it is for nav
|
|
1569
1614
|
* child blocks to inherit styles through the complex responsive nav block html. The
|
|
1570
1615
|
* bug in https://github.com/WordPress/gutenberg/issues/62690 also prevents inheritance.
|
|
@@ -1575,25 +1620,83 @@ add_action( 'init', 'register_block_core_navigation' );
|
|
|
1575
1620
|
* @param array $block The full block, including name and attributes.
|
|
1576
1621
|
* @return string The updated block content.
|
|
1577
1622
|
*/
|
|
1578
|
-
function
|
|
1623
|
+
function block_core_navigation_add_support_classes_to_container( $block_content, $block ) {
|
|
1579
1624
|
if ( 'core/navigation' !== ( $block['blockName'] ?? null ) || empty( $block_content ) ) {
|
|
1580
1625
|
return $block_content;
|
|
1581
1626
|
}
|
|
1582
1627
|
|
|
1628
|
+
$attributes = is_array( $block['attrs'] ?? null ) ? $block['attrs'] : array();
|
|
1629
|
+
$style = is_array( $attributes['style'] ?? null ) ? $attributes['style'] : array();
|
|
1630
|
+
if (
|
|
1631
|
+
defined( 'IS_GUTENBERG_PLUGIN' ) &&
|
|
1632
|
+
IS_GUTENBERG_PLUGIN &&
|
|
1633
|
+
function_exists( 'gutenberg_resolve_style_state_aliases' )
|
|
1634
|
+
) {
|
|
1635
|
+
$style = gutenberg_resolve_style_state_aliases( $style, 'core/navigation' );
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
$global_settings = wp_get_global_settings();
|
|
1639
|
+
$viewport_settings = $global_settings['viewport'] ?? null;
|
|
1640
|
+
$responsive_media_queries = array();
|
|
1641
|
+
if ( method_exists( 'WP_Theme_JSON_Gutenberg', 'get_viewport_media_queries' ) ) {
|
|
1642
|
+
$responsive_media_queries = WP_Theme_JSON_Gutenberg::get_viewport_media_queries( $viewport_settings );
|
|
1643
|
+
} elseif ( method_exists( 'WP_Theme_JSON', 'get_viewport_media_queries' ) ) {
|
|
1644
|
+
$responsive_media_queries = WP_Theme_JSON::get_viewport_media_queries( $viewport_settings );
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
$styles = array();
|
|
1648
|
+
$base_layout = is_array( $attributes['layout'] ?? null ) ? $attributes['layout'] : array();
|
|
1649
|
+
foreach ( $responsive_media_queries as $breakpoint => $media_query ) {
|
|
1650
|
+
$viewport_style = is_array( $style[ $breakpoint ] ?? null ) ? $style[ $breakpoint ] : array();
|
|
1651
|
+
$viewport_layout = is_array( $viewport_style['layout'] ?? null ) ? $viewport_style['layout'] : array();
|
|
1652
|
+
if ( empty( $viewport_layout ) ) {
|
|
1653
|
+
continue;
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
$styles[] = array(
|
|
1657
|
+
'declarations' => block_core_navigation_get_layout_custom_property_declarations(
|
|
1658
|
+
array_replace( $base_layout, $viewport_layout )
|
|
1659
|
+
),
|
|
1660
|
+
'rules_group' => $media_query,
|
|
1661
|
+
);
|
|
1662
|
+
}
|
|
1663
|
+
|
|
1583
1664
|
$processor = new WP_HTML_Tag_Processor( $block_content );
|
|
1584
1665
|
if ( ! $processor->next_tag() ) {
|
|
1585
1666
|
return $block_content;
|
|
1586
1667
|
}
|
|
1587
1668
|
|
|
1588
1669
|
$class_attribute = $processor->get_attribute( 'class' );
|
|
1589
|
-
|
|
1670
|
+
$state_class = null;
|
|
1671
|
+
if ( is_string( $class_attribute ) && preg_match( '/\bwp-states-[a-f0-9]{8}\b/', $class_attribute, $matches ) ) {
|
|
1672
|
+
$state_class = $matches[0];
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
$layout_class = null;
|
|
1676
|
+
if ( ! empty( $styles ) ) {
|
|
1677
|
+
$layout_class = wp_unique_id( 'wp-block-navigation-' );
|
|
1678
|
+
// The inner selector includes both Navigation classes so it overrides the
|
|
1679
|
+
// default layout custom properties set by `.wp-block-navigation.items-*`.
|
|
1680
|
+
$selector = ".wp-block-navigation.{$layout_class},.wp-block-navigation.wp-block-navigation__container.{$layout_class}";
|
|
1681
|
+
foreach ( $styles as &$style_rule ) {
|
|
1682
|
+
$style_rule['selector'] = $selector;
|
|
1683
|
+
}
|
|
1684
|
+
unset( $style_rule );
|
|
1685
|
+
|
|
1686
|
+
$processor->add_class( $layout_class );
|
|
1687
|
+
wp_style_engine_get_stylesheet_from_css_rules(
|
|
1688
|
+
$styles,
|
|
1689
|
+
array( 'context' => 'block-supports' )
|
|
1690
|
+
);
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
if ( null === $state_class && null === $layout_class ) {
|
|
1590
1694
|
return $block_content;
|
|
1591
1695
|
}
|
|
1592
1696
|
|
|
1593
|
-
$state_class = $matches[0];
|
|
1594
1697
|
while ( $processor->next_tag() ) {
|
|
1595
1698
|
// Custom overlay content can include nested Navigation blocks.
|
|
1596
|
-
// Avoid applying the outer Navigation
|
|
1699
|
+
// Avoid applying the outer Navigation classes to an inner nav block.
|
|
1597
1700
|
if ( $processor->has_class( 'wp-block-navigation' ) && ! $processor->has_class( 'wp-block-navigation__container' ) ) {
|
|
1598
1701
|
break;
|
|
1599
1702
|
}
|
|
@@ -1602,6 +1705,14 @@ function block_core_navigation_add_state_class_to_container( $block_content, $bl
|
|
|
1602
1705
|
continue;
|
|
1603
1706
|
}
|
|
1604
1707
|
|
|
1708
|
+
if ( null !== $layout_class ) {
|
|
1709
|
+
$processor->add_class( $layout_class );
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
if ( null === $state_class ) {
|
|
1713
|
+
continue;
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1605
1716
|
$class_attribute = $processor->get_attribute( 'class' );
|
|
1606
1717
|
if ( is_string( $class_attribute ) && preg_match( '/\bwp-states-[a-f0-9]{8}\b/', $class_attribute ) ) {
|
|
1607
1718
|
continue;
|
|
@@ -1613,7 +1724,7 @@ function block_core_navigation_add_state_class_to_container( $block_content, $bl
|
|
|
1613
1724
|
return $processor->get_updated_html();
|
|
1614
1725
|
}
|
|
1615
1726
|
|
|
1616
|
-
add_filter( 'render_block', '
|
|
1727
|
+
add_filter( 'render_block', 'block_core_navigation_add_support_classes_to_container', 11, 2 );
|
|
1617
1728
|
|
|
1618
1729
|
/**
|
|
1619
1730
|
* Filter that changes the parsed attribute values of navigation blocks contain typographic presets to contain the values directly.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
let mockRegisteredStore;
|
|
2
|
+
let mockCurrentContext;
|
|
3
|
+
|
|
4
|
+
jest.mock( '@wordpress/interactivity', () => ( {
|
|
5
|
+
store: ( name, config ) => {
|
|
6
|
+
mockRegisteredStore = config;
|
|
7
|
+
return config;
|
|
8
|
+
},
|
|
9
|
+
getContext: () => mockCurrentContext,
|
|
10
|
+
getElement: () => ( { ref: {} } ),
|
|
11
|
+
withSyncEvent: ( fn ) => fn,
|
|
12
|
+
} ) );
|
|
13
|
+
|
|
14
|
+
describe( 'Navigation view script', () => {
|
|
15
|
+
beforeEach( async () => {
|
|
16
|
+
jest.resetModules();
|
|
17
|
+
mockRegisteredStore = null;
|
|
18
|
+
mockCurrentContext = null;
|
|
19
|
+
// Import the view.js script to register the store
|
|
20
|
+
await import( '../view.js' );
|
|
21
|
+
} );
|
|
22
|
+
|
|
23
|
+
it( 'updates submenuOpenedBy.hover when hovering a submenu inside an open overlay', () => {
|
|
24
|
+
// Mock the context for a submenu inside an open overlay
|
|
25
|
+
mockCurrentContext = {
|
|
26
|
+
type: 'submenu',
|
|
27
|
+
submenuOpenedBy: { click: false, hover: false, focus: false },
|
|
28
|
+
overlayOpenedBy: { click: true, hover: false, focus: false },
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const { state, actions } = mockRegisteredStore;
|
|
32
|
+
|
|
33
|
+
// Verify initial state
|
|
34
|
+
expect( state.isSubmenuOpen ).toBe( true ); // because overlay is open
|
|
35
|
+
expect( mockCurrentContext.submenuOpenedBy.hover ).toBe( false );
|
|
36
|
+
|
|
37
|
+
// Simulate hover enter
|
|
38
|
+
actions.openMenuOnHover( { pointerType: 'mouse' } );
|
|
39
|
+
|
|
40
|
+
// Verify that hover state is tracked even though submenu is already "open" visually
|
|
41
|
+
expect( mockCurrentContext.submenuOpenedBy.hover ).toBe( true );
|
|
42
|
+
expect( state.isSubmenuOpen ).toBe( true ); // remains true
|
|
43
|
+
|
|
44
|
+
// Simulate hover leave
|
|
45
|
+
actions.closeMenuOnHover( { pointerType: 'mouse' } );
|
|
46
|
+
|
|
47
|
+
// Verify hover state is cleared
|
|
48
|
+
expect( mockCurrentContext.submenuOpenedBy.hover ).toBe( false );
|
|
49
|
+
expect( state.isSubmenuOpen ).toBe( true ); // remains true because overlay is still open
|
|
50
|
+
} );
|
|
51
|
+
} );
|
package/src/navigation/view.js
CHANGED
|
@@ -80,6 +80,17 @@ const { state, actions } = store(
|
|
|
80
80
|
? ctx.overlayOpenedBy
|
|
81
81
|
: ctx.submenuOpenedBy;
|
|
82
82
|
},
|
|
83
|
+
get isSubmenuOpen() {
|
|
84
|
+
const ctx = getContext();
|
|
85
|
+
// Once the overlay itself is open, its styles always expand
|
|
86
|
+
// every submenu regardless of hover/click/focus state, so the
|
|
87
|
+
// toggle's `aria-expanded` should reflect that immediately
|
|
88
|
+
// instead of waiting for a hover/click/focus interaction.
|
|
89
|
+
const isOverlayOpen =
|
|
90
|
+
Object.values( ctx.overlayOpenedBy || {} ).filter( Boolean )
|
|
91
|
+
.length > 0;
|
|
92
|
+
return isOverlayOpen || state.isMenuOpen;
|
|
93
|
+
},
|
|
83
94
|
},
|
|
84
95
|
actions: {
|
|
85
96
|
openMenuOnHover( event ) {
|
|
@@ -88,13 +99,8 @@ const { state, actions } = store(
|
|
|
88
99
|
if ( event?.pointerType === 'touch' ) {
|
|
89
100
|
return;
|
|
90
101
|
}
|
|
91
|
-
const { type
|
|
92
|
-
if (
|
|
93
|
-
type === 'submenu' &&
|
|
94
|
-
// Only open on hover if the overlay is closed.
|
|
95
|
-
Object.values( overlayOpenedBy || {} ).filter( Boolean )
|
|
96
|
-
.length === 0
|
|
97
|
-
) {
|
|
102
|
+
const { type } = getContext();
|
|
103
|
+
if ( type === 'submenu' ) {
|
|
98
104
|
actions.openMenu( 'hover' );
|
|
99
105
|
}
|
|
100
106
|
},
|
|
@@ -102,13 +108,8 @@ const { state, actions } = store(
|
|
|
102
108
|
if ( event?.pointerType === 'touch' ) {
|
|
103
109
|
return;
|
|
104
110
|
}
|
|
105
|
-
const { type
|
|
106
|
-
if (
|
|
107
|
-
type === 'submenu' &&
|
|
108
|
-
// Only close on hover if the overlay is closed.
|
|
109
|
-
Object.values( overlayOpenedBy || {} ).filter( Boolean )
|
|
110
|
-
.length === 0
|
|
111
|
-
) {
|
|
111
|
+
const { type } = getContext();
|
|
112
|
+
if ( type === 'submenu' ) {
|
|
112
113
|
actions.closeMenu( 'hover' );
|
|
113
114
|
}
|
|
114
115
|
},
|
|
@@ -425,12 +425,15 @@ export default function NavigationLinkEdit( {
|
|
|
425
425
|
}
|
|
426
426
|
onMerge={ mergeBlocks }
|
|
427
427
|
onReplace={ onReplace }
|
|
428
|
-
__unstableOnSplitAtEnd={
|
|
429
|
-
insertBlocksAfter
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
428
|
+
__unstableOnSplitAtEnd={
|
|
429
|
+
insertBlocksAfter
|
|
430
|
+
? () =>
|
|
431
|
+
insertBlocksAfter(
|
|
432
|
+
createBlock(
|
|
433
|
+
'core/navigation-link'
|
|
434
|
+
)
|
|
435
|
+
)
|
|
436
|
+
: undefined
|
|
434
437
|
}
|
|
435
438
|
aria-label={ __(
|
|
436
439
|
'Navigation link text'
|
|
@@ -470,7 +473,8 @@ export default function NavigationLinkEdit( {
|
|
|
470
473
|
// If there is no link and no binding, remove the auto-inserted block.
|
|
471
474
|
// This avoids empty blocks which can provided a poor UX.
|
|
472
475
|
// Don't remove if binding exists (even if entity is unavailable) so user can fix it.
|
|
473
|
-
|
|
476
|
+
// `onReplace` is undefined when the block can't be removed.
|
|
477
|
+
if ( ! url && ! hasUrlBinding && onReplace ) {
|
|
474
478
|
onReplace( [] );
|
|
475
479
|
return;
|
|
476
480
|
}
|