diff --git a/packages/block-library/src/navigation-submenu/block.json b/packages/block-library/src/navigation-submenu/block.json index 943e3c948d969..db0791485a8cb 100644 --- a/packages/block-library/src/navigation-submenu/block.json +++ b/packages/block-library/src/navigation-submenu/block.json @@ -60,7 +60,6 @@ "reusable": false, "html": false }, - "viewScript": "file:./view.min.js", "editorStyle": "wp-block-navigation-submenu-editor", "style": "wp-block-navigation-submenu" } diff --git a/packages/block-library/src/navigation-submenu/index.php b/packages/block-library/src/navigation-submenu/index.php index 0a12cb0e93e67..fc7b78de6a8be 100644 --- a/packages/block-library/src/navigation-submenu/index.php +++ b/packages/block-library/src/navigation-submenu/index.php @@ -123,9 +123,6 @@ function block_core_navigation_submenu_render_submenu_icon() { * @return string Returns the post content with the legacy widget added. */ function render_block_core_navigation_submenu( $attributes, $content, $block ) { - if ( ! wp_script_is( 'wp-block-navigation-submenu-view' ) ) { - wp_enqueue_script( 'wp-block-navigation-submenu-view' ); - } $navigation_link_has_id = isset( $attributes['id'] ) && is_numeric( $attributes['id'] ); $is_post_type = isset( $attributes['kind'] ) && 'post-type' === $attributes['kind']; diff --git a/packages/block-library/src/navigation-submenu/style.scss b/packages/block-library/src/navigation-submenu/style.scss index 46d68e2aeb8e5..00105a188c207 100644 --- a/packages/block-library/src/navigation-submenu/style.scss +++ b/packages/block-library/src/navigation-submenu/style.scss @@ -2,25 +2,9 @@ position: relative; display: flex; - button.wp-block-navigation__submenu-icon.wp-block-navigation__submenu-icon.wp-block-navigation__submenu-icon.wp-block-navigation__submenu-icon { - padding: $grid-unit $grid-unit-20; - background-color: inherit; - color: currentColor; - border: none; - } - .wp-block-navigation__submenu-icon svg { stroke: currentColor; } - - // Show submenus on click. - .wp-block-navigation-submenu__toggle[aria-expanded="true"] + .wp-block-navigation__submenu-container { - visibility: visible; - opacity: 1; - width: auto; - height: auto; - min-width: 200px; - } } button.wp-block-navigation-item__content { diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index f2bd64737870a..5b4b03f3a420d 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -218,7 +218,7 @@ function render_block_core_navigation( $attributes, $content, $block ) { unset( $attributes['rgbTextColor'], $attributes['rgbBackgroundColor'] ); - $should_load_view_script = ! empty( $attributes['isResponsive'] ) && ! wp_script_is( 'wp-block-navigation-view' ); + $should_load_view_script = ! wp_script_is( 'wp-block-navigation-view' ) && ( ! empty( $attributes['isResponsive'] ) || $attributes['openSubmenusOnClick'] || $attributes['showSubmenuIcon'] ); if ( $should_load_view_script ) { wp_enqueue_script( 'wp-block-navigation-view' ); } diff --git a/packages/block-library/src/navigation/style.scss b/packages/block-library/src/navigation/style.scss index 4491442bcb212..42a3813a52cdb 100644 --- a/packages/block-library/src/navigation/style.scss +++ b/packages/block-library/src/navigation/style.scss @@ -90,6 +90,14 @@ stroke: currentColor; } } + + // Styles for button toggles. + button.wp-block-navigation__submenu-icon.wp-block-navigation__submenu-icon.wp-block-navigation__submenu-icon.wp-block-navigation__submenu-icon { + padding: $grid-unit $grid-unit-20; + background-color: inherit; + color: currentColor; + border: none; + } } // Styles for submenu flyout. @@ -187,6 +195,15 @@ height: auto; min-width: 200px; } + + // Show submenus on click. + .wp-block-navigation-submenu__toggle[aria-expanded="true"] + .wp-block-navigation__submenu-container { + visibility: visible; + opacity: 1; + width: auto; + height: auto; + min-width: 200px; + } } // Submenu indentation when there's a background. diff --git a/packages/block-library/src/navigation/view.js b/packages/block-library/src/navigation/view.js index 9b95463f5b3db..1b3b0dc1fdc8c 100644 --- a/packages/block-library/src/navigation/view.js +++ b/packages/block-library/src/navigation/view.js @@ -3,6 +3,7 @@ */ import MicroModal from 'micromodal'; +// Responsive navigation toggle. function navigationToggleModal( modal ) { const triggerButton = document.querySelector( `button[data-micromodal-trigger="${ modal.id }"]` @@ -25,3 +26,69 @@ MicroModal.init( { onClose: navigationToggleModal, openClass: 'is-menu-open', } ); + +// Open on click functionality. +function closeSubmenus( element ) { + element + .querySelectorAll( '[aria-expanded="true"]' ) + .forEach( function ( toggle ) { + toggle.setAttribute( 'aria-expanded', 'false' ); + } ); +} + +function toggleSubmenuOnClick( event ) { + const buttonToggle = event.target.closest( '[aria-expanded]' ); + const isSubmenuOpen = buttonToggle.getAttribute( 'aria-expanded' ); + + if ( isSubmenuOpen === 'true' ) { + closeSubmenus( buttonToggle.closest( '.wp-block-navigation-item' ) ); + } else { + // Close all sibling submenus. + const parentElement = buttonToggle.closest( + '.wp-block-navigation-item' + ); + const navigationParent = buttonToggle.closest( + '.wp-block-navigation__submenu-container, .wp-block-navigation__container, .wp-block-page-list' + ); + navigationParent + .querySelectorAll( '.wp-block-navigation-item' ) + .forEach( function ( child ) { + if ( child !== parentElement ) { + closeSubmenus( child ); + } + } ); + // Open submenu. + buttonToggle.setAttribute( 'aria-expanded', 'true' ); + } +} + +const submenuButtons = document.querySelectorAll( + '.wp-block-navigation-submenu__toggle' +); + +submenuButtons.forEach( function ( button ) { + button.addEventListener( 'click', toggleSubmenuOnClick ); +} ); + +// Close on click outside. +document.addEventListener( 'click', function ( event ) { + const navigationBlocks = document.querySelectorAll( + '.wp-block-navigation' + ); + navigationBlocks.forEach( function ( block ) { + if ( ! block.contains( event.target ) ) { + closeSubmenus( block ); + } + } ); +} ); +// Close on focus outside. +document.addEventListener( 'keyup', function ( event ) { + const submenuBlocks = document.querySelectorAll( + '.wp-block-navigation-item.has-child' + ); + submenuBlocks.forEach( function ( block ) { + if ( ! block.contains( event.target ) ) { + closeSubmenus( block ); + } + } ); +} ); diff --git a/packages/block-library/src/page-list/block.json b/packages/block-library/src/page-list/block.json index 95dce8bc0a7bf..a16a0b0abeb0f 100644 --- a/packages/block-library/src/page-list/block.json +++ b/packages/block-library/src/page-list/block.json @@ -33,6 +33,12 @@ }, "isNavigationChild": { "type": "boolean" + }, + "showSubmenuIcon": { + "type": "boolean" + }, + "openSubmenusOnClick" : { + "type": "boolean" } }, "usesContext": [ @@ -47,7 +53,8 @@ "fontSize", "customFontSize", "showSubmenuIcon", - "style" + "style", + "openSubmenusOnClick" ], "supports": { "reusable": false, diff --git a/packages/block-library/src/page-list/edit.js b/packages/block-library/src/page-list/edit.js index 58c0e1b6a2853..2311308c41b16 100644 --- a/packages/block-library/src/page-list/edit.js +++ b/packages/block-library/src/page-list/edit.js @@ -69,8 +69,7 @@ export default function PageListEdit( { context.customOverlayBackgroundColor, ] ); - const { textColor, backgroundColor, showSubmenuIcon, style } = - context || {}; + const { textColor, backgroundColor, style } = context || {}; const [ allowConvertToLinks, setAllowConvertToLinks ] = useState( false ); @@ -83,7 +82,6 @@ export default function PageListEdit( { 'background-color', backgroundColor ) ]: !! backgroundColor, - 'show-submenu-icons': !! showSubmenuIcon, } ), style: { ...style?.color }, } ); @@ -100,8 +98,12 @@ export default function PageListEdit( { ); useEffect( () => { - setAttributes( { isNavigationChild: isParentNavigation } ); - }, [] ); + setAttributes( { + isNavigationChild: isParentNavigation, + openSubmenusOnClick: !! context.openSubmenusOnClick, + showSubmenuIcon: !! context.showSubmenuIcon, + } ); + }, [ context.openSubmenusOnClick, context.showSubmenuIcon ] ); useEffect( () => { if ( isParentNavigation ) { @@ -129,6 +131,8 @@ export default function PageListEdit( { const attributesWithParentStatus = { ...attributes, isNavigationChild: isParentNavigation, + openSubmenusOnClick: !! context.openSubmenusOnClick, + showSubmenuIcon: !! context.showSubmenuIcon, }; return ( diff --git a/packages/block-library/src/page-list/editor.scss b/packages/block-library/src/page-list/editor.scss index b02c33d59d8f5..5b8d6726b0716 100644 --- a/packages/block-library/src/page-list/editor.scss +++ b/packages/block-library/src/page-list/editor.scss @@ -50,3 +50,17 @@ margin-left: $grid-unit-15; } } + +// Simulate open on click behaviour in the editor by opening on focus instead. + +.wp-block-page-list { + .open-on-click:focus-within { + > .wp-block-navigation__submenu-container { + visibility: visible; + opacity: 1; + width: auto; + height: auto; + min-width: 200px; + } + } +} diff --git a/packages/block-library/src/page-list/index.php b/packages/block-library/src/page-list/index.php index 21a9ed8b1af2e..6f99ab14c95ef 100644 --- a/packages/block-library/src/page-list/index.php +++ b/packages/block-library/src/page-list/index.php @@ -128,6 +128,8 @@ function block_core_page_list_build_css_font_sizes( $context ) { /** * Outputs Page list markup from an array of pages with nested children. * + * @param boolean $open_submenus_on_click Whether to open submenus on click instead of hover. + * @param boolean $show_submenu_icons Whether to show submenu indicator icons. * @param boolean $is_navigation_child If block is a child of Navigation block. * @param array $nested_pages The array of nested pages. * @param array $active_page_ancestor_ids An array of ancestor ids for active page. @@ -136,7 +138,7 @@ function block_core_page_list_build_css_font_sizes( $context ) { * * @return string List markup. */ -function block_core_page_list_render_nested_page_list( $is_navigation_child, $nested_pages, $active_page_ancestor_ids = array(), $colors = array(), $depth = 0 ) { +function block_core_page_list_render_nested_page_list( $open_submenus_on_click, $show_submenu_icons, $is_navigation_child, $nested_pages, $active_page_ancestor_ids = array(), $colors = array(), $depth = 0 ) { if ( empty( $nested_pages ) ) { return; } @@ -152,6 +154,12 @@ function block_core_page_list_render_nested_page_list( $is_navigation_child, $ne if ( $is_navigation_child ) { $css_class .= ' wp-block-navigation-item'; + + if ( $open_submenus_on_click ) { + $css_class .= ' open-on-click'; + } elseif ( $show_submenu_icons ) { + $css_class .= ' open-on-hover-click'; + } } $navigation_child_content_class = $is_navigation_child ? ' wp-block-navigation-item__content' : ''; @@ -165,20 +173,32 @@ function block_core_page_list_render_nested_page_list( $is_navigation_child, $ne } $markup .= '