Skip to content

Commit

Permalink
Navigation: Refactor mobile overlay breakpoints to JS (#57520)
Browse files Browse the repository at this point in the history
* Navigation: Refactor mobile overlay breakpoints to JS

* remove unused code

* refactor to shared function

* fix PHPCS

* also get the editor working

* move the 600 value to constants

* add a comment to explain why we don't need the JS for the overlayMenu 'always' mode

* Use matchMedia instead of window.resize

* remove useEffects and use a hook for the media query

* Remove the listener when the component is unmounted

* use wp-init instead of wp-watch since we don't need to be reactive

* Don't mutate the DOM in directives

* Update packages/block-library/src/navigation/edit/index.js

Co-authored-by: Dave Smith <getdavemail@gmail.com>

* Update packages/block-library/src/navigation/edit/index.js

Co-authored-by: Dave Smith <getdavemail@gmail.com>

* Add px to the constant

* rename to NAVIGATION_MOBILE_COLLAPSE

* Add a comment to the navigation CSS

* Update lib/compat/wordpress-6.5/class-wp-navigation-block-renderer.php

Co-authored-by: Dave Smith <getdavemail@gmail.com>

---------

Co-authored-by: Dave Smith <getdavemail@gmail.com>
  • Loading branch information
scruffian and getdave authored Jan 4, 2024
1 parent 5e02c30 commit 1b75cf6
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 27 deletions.
33 changes: 24 additions & 9 deletions lib/compat/wordpress-6.5/class-wp-navigation-block-renderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -361,16 +361,25 @@ private static function get_classes( $attributes ) {
$text_decoration = $attributes['style']['typography']['textDecoration'] ?? null;
$text_decoration_class = sprintf( 'has-text-decoration-%s', $text_decoration );

// Sets the is-collapsed class when the navigation is set to always use the overlay.
// This saves us from needing to do this check in the view.js file (see the collapseNav function).
$is_collapsed_class = static::is_always_overlay( $attributes ) ? array( 'is-collapsed' ) : array();

$classes = array_merge(
$colors['css_classes'],
$font_sizes['css_classes'],
$is_responsive_menu ? array( 'is-responsive' ) : array(),
$layout_class ? array( $layout_class ) : array(),
$text_decoration ? array( $text_decoration_class ) : array()
$text_decoration ? array( $text_decoration_class ) : array(),
$is_collapsed_class
);
return implode( ' ', $classes );
}

private static function is_always_overlay( $attributes ) {
return isset( $attributes['overlayMenu'] ) && 'always' === $attributes['overlayMenu'];
}

/**
* Get styles for the navigation block.
*
Expand All @@ -397,16 +406,12 @@ private static function get_responsive_container_markup( $attributes, $inner_blo
$colors = gutenberg_block_core_navigation_build_css_colors( $attributes );
$modal_unique_id = wp_unique_id( 'modal-' );

$is_hidden_by_default = isset( $attributes['overlayMenu'] ) && 'always' === $attributes['overlayMenu'];

$responsive_container_classes = array(
'wp-block-navigation__responsive-container',
$is_hidden_by_default ? 'hidden-by-default' : '',
implode( ' ', $colors['overlay_css_classes'] ),
);
$open_button_classes = array(
'wp-block-navigation__responsive-container-open',
$is_hidden_by_default ? 'always-shown' : '',
);

$should_display_icon_label = isset( $attributes['hasIcon'] ) && true === $attributes['hasIcon'];
Expand Down Expand Up @@ -504,7 +509,7 @@ private static function get_nav_wrapper_attributes( $attributes, $inner_blocks )
);

if ( $is_responsive_menu ) {
$nav_element_directives = static::get_nav_element_directives( $should_load_view_script );
$nav_element_directives = static::get_nav_element_directives( $should_load_view_script, $attributes );
$wrapper_attributes .= ' ' . $nav_element_directives;
}

Expand All @@ -517,12 +522,12 @@ private static function get_nav_wrapper_attributes( $attributes, $inner_blocks )
* @param bool $should_load_view_script Whether or not the view script should be loaded.
* @return string the directives for the navigation element.
*/
private static function get_nav_element_directives( $should_load_view_script ) {
private static function get_nav_element_directives( $should_load_view_script, $attributes ) {
if ( ! $should_load_view_script ) {
return '';
}
// When adding to this array be mindful of security concerns.
$nav_element_context = wp_json_encode(
$nav_element_context = wp_json_encode(
array(
'overlayOpenedBy' => array(),
'type' => 'overlay',
Expand All @@ -531,10 +536,20 @@ private static function get_nav_element_directives( $should_load_view_script ) {
),
JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP
);
return '
$nav_element_directives = '
data-wp-interactive=\'{"namespace":"core/navigation"}\'
data-wp-context=\'' . $nav_element_context . '\'
';

// When the navigation overlayMenu attribute is set to "always"
// we don't need to use JavaScript to collapse the menu as we set the class manually.
if ( ! static::is_always_overlay( $attributes ) ) {
$nav_element_directives .= 'data-wp-init="callbacks.initNav"';
$nav_element_directives .= ' '; // space separator
$nav_element_directives .= 'data-wp-class--is-collapsed="context.isCollapsed"';
}

return $nav_element_directives;
}

/**
Expand Down
2 changes: 2 additions & 0 deletions packages/block-library/src/navigation/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,5 @@ export const SELECT_NAVIGATION_MENUS_ARGS = [
'wp_navigation',
PRELOADED_NAVIGATION_MENUS_QUERY,
];

export const NAVIGATION_MOBILE_COLLAPSE = '600px';
12 changes: 11 additions & 1 deletion packages/block-library/src/navigation/edit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import {
import { __, sprintf } from '@wordpress/i18n';
import { speak } from '@wordpress/a11y';
import { close, Icon } from '@wordpress/icons';
import { useInstanceId } from '@wordpress/compose';
import { useInstanceId, useMediaQuery } from '@wordpress/compose';

/**
* Internal dependencies
Expand Down Expand Up @@ -71,6 +71,7 @@ import MenuInspectorControls from './menu-inspector-controls';
import DeletedNavigationWarning from './deleted-navigation-warning';
import AccessibleDescription from './accessible-description';
import AccessibleMenuDescription from './accessible-menu-description';
import { NAVIGATION_MOBILE_COLLAPSE } from '../constants';
import { unlock } from '../../lock-unlock';

function Navigation( {
Expand Down Expand Up @@ -297,6 +298,14 @@ function Navigation( {
[ clientId ]
);
const isResponsive = 'never' !== overlayMenu;
const isMobileBreakPoint = useMediaQuery(
`(max-width: ${ NAVIGATION_MOBILE_COLLAPSE })`
);

const isCollapsed =
( 'mobile' === overlayMenu && isMobileBreakPoint ) ||
'always' === overlayMenu;

const blockProps = useBlockProps( {
ref: navRef,
className: classnames(
Expand All @@ -310,6 +319,7 @@ function Navigation( {
'is-vertical': orientation === 'vertical',
'no-wrap': flexWrap === 'nowrap',
'is-responsive': isResponsive,
'is-collapsed': isCollapsed,
'has-text-color': !! textColor.color || !! textColor?.class,
[ getColorClassName( 'color', textColor?.slug ) ]:
!! textColor?.slug,
Expand Down
2 changes: 1 addition & 1 deletion packages/block-library/src/navigation/editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ $color-control-label-height: 20px;
// These needs extra specificity in the editor.
.wp-block-navigation__responsive-container:not(.is-menu-open) {
.components-button.wp-block-navigation__responsive-container-close {
@include break-small {
.is-collapsed & {
display: none;
}
}
Expand Down
34 changes: 18 additions & 16 deletions packages/block-library/src/navigation/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -611,18 +611,19 @@ button.wp-block-navigation-item__content {
}
}

@include break-small() {
&:not(.hidden-by-default) {
&:not(.is-menu-open) {
display: block;
width: 100%;
position: relative;
z-index: auto;
background-color: inherit;

.wp-block-navigation__responsive-container-close {
display: none;
}
// When the menu is collapsed, the menu button is visible.
// We are using the > selector combined with the :not(is-collapsed) selector
// as a way to target the class being added to the parent nav element.
:not(.is-collapsed) > & {
&:not(.is-menu-open) {
display: block;
width: 100%;
position: relative;
z-index: auto;
background-color: inherit;

.wp-block-navigation__responsive-container-close {
display: none;
}
}

Expand Down Expand Up @@ -686,10 +687,11 @@ button.wp-block-navigation-item__content {
font-size: inherit;
}

&:not(.always-shown) {
@include break-small {
display: none;
}
// When the menu is collapsed, the menu button is visible.
// We are using the > selector combined with the :not(is-collapsed) selector
// as a way to target the class being added to the parent nav element.
:not(.is-collapsed) > & {
display: none;
}
}

Expand Down
26 changes: 26 additions & 0 deletions packages/block-library/src/navigation/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
*/
import { store, getContext, getElement } from '@wordpress/interactivity';

/**
* Internal dependencies
*/
import { NAVIGATION_MOBILE_COLLAPSE } from './constants';

const focusableSelectors = [
'a[href]',
'input:not([disabled]):not([type="hidden"]):not([aria-hidden])',
Expand Down Expand Up @@ -185,5 +190,26 @@ const { state, actions } = store( 'core/navigation', {
focusableElements?.[ 0 ]?.focus();
}
},
initNav() {
const context = getContext();
const mediaQuery = window.matchMedia(
`(max-width: ${ NAVIGATION_MOBILE_COLLAPSE })`
);

// Run once to set the initial state.
context.isCollapsed = mediaQuery.matches;

function handleCollapse( event ) {
context.isCollapsed = event.matches;
}

// Run on resize to update the state.
mediaQuery.addEventListener( 'change', handleCollapse );

// Remove the listener when the component is unmounted.
return () => {
mediaQuery.removeEventListener( 'change', handleCollapse );
};
},
},
} );

0 comments on commit 1b75cf6

Please sign in to comment.