Skip to content

Commit

Permalink
rough pass to add the script that calculates if the nav is wrapping o…
Browse files Browse the repository at this point in the history
…r not
  • Loading branch information
MaggieCabrera authored and scruffian committed Jan 2, 2024
1 parent b62a1e6 commit cef2e2c
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 9 deletions.
35 changes: 27 additions & 8 deletions lib/compat/wordpress-6.5/class-wp-navigation-block-renderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@ private static function is_responsive( $attributes ) {
return isset( $attributes['overlayMenu'] ) && 'never' !== $attributes['overlayMenu'] || $has_old_responsive_attribute;
}

/**
* Returns whether or not the navigation has a flexible breakpoint.
*
* @param array $attributes The block attributes.
* @return bool Returns whether or not this is responsive navigation.
*/
private static function has_flexible_breakpoint( $attributes ) {
return $attributes['flexibleBreakpoint'] ? 'true' : 'false';
}

/**
* Returns whether or not a navigation has a submenu.
*
Expand Down Expand Up @@ -495,9 +505,9 @@ private static function get_nav_wrapper_attributes( $attributes, $inner_blocks )
$is_responsive_menu = static::is_responsive( $attributes );
$style = static::get_styles( $attributes );
$class = static::get_classes( $attributes );
$has_flexible_breakpoint = $attributes['flexibleBreakpoint'] ? 'true' : 'false';
$has_flexible_breakpoint = static::has_flexible_breakpoint( $attributes );

$wrapper_attributes = get_block_wrapper_attributes(
$wrapper_attributes = get_block_wrapper_attributes(
array(
'class' => $class,
'style' => $style,
Expand All @@ -517,6 +527,7 @@ private static function get_nav_wrapper_attributes( $attributes, $inner_blocks )
* Get the nav element directives
*
* @param bool $should_load_view_script Whether or not the view script should be loaded.
* @param bool $has_flexible_breakpoint Whether or not the nav block will have a flexible breakpoint.
* @return string the directives for the navigation element.
*/
private static function get_nav_element_directives( $should_load_view_script, $has_flexible_breakpoint ) {
Expand All @@ -526,17 +537,25 @@ private static function get_nav_element_directives( $should_load_view_script, $h
// When adding to this array be mindful of security concerns.
$nav_element_context = wp_json_encode(
array(
'overlayOpenedBy' => array(),
'type' => 'overlay',
'roleAttribute' => '',
'ariaLabel' => __( 'Menu' ),
'has_flexible_breakpoint' => $has_flexible_breakpoint,
'overlayOpenedBy' => array(),
'type' => 'overlay',
'roleAttribute' => '',
'ariaLabel' => __( 'Menu' ),
'has_flexible_breakpoint' => $has_flexible_breakpoint,
),
JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP
);

$flexible_breakpoint_directives = '';

if ( $has_flexible_breakpoint ) {
$flexible_breakpoint_directives = 'data-wp-init--overlay="actions.isNavCollapsed"';
}

return '
data-wp-interactive=\'{"namespace":"core/navigation"}\'
data-wp-context=\'' . $nav_element_context . '\'
data-wp-context=\'' . $nav_element_context . '\'
' . $flexible_breakpoint_directives . '
';
}

Expand Down
93 changes: 92 additions & 1 deletion packages/block-library/src/navigation/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const focusableSelectors = [
// capture the clicks, instead of relying on the focusout event.
document.addEventListener( 'click', () => {} );

const { state, actions } = store( 'core/navigation', {
const { state, actions, callbacks } = store( 'core/navigation', {
state: {
get roleAttribute() {
const ctx = getContext();
Expand Down Expand Up @@ -176,7 +176,12 @@ const { state, actions } = store( 'core/navigation', {
ctx.lastFocusableElement =
focusableElements[ focusableElements.length - 1 ];
}
window.addEventListener(
'resize',
callbacks.isNavCollapsed( ref )
);
},

focusFirstElement() {
const { ref } = getElement();
if ( state.isMenuOpen ) {
Expand All @@ -185,5 +190,91 @@ const { state, actions } = store( 'core/navigation', {
focusableElements?.[ 0 ]?.focus();
}
},

isNavCollapsed( ref ) {
//test if the nav items are wrapping before testing if the actual nav is wrapping inside its parent to avoid the recursive function if possible
if (
areItemsWrapping( ref ) === true ||
isNavWrapping( ref ) === true
) {
//console.log( 'is mobile' );
} else {
//console.log( 'is not mobile' );
}
},
},
} );

function areItemsWrapping(
wrapper,
children = wrapper.querySelectorAll( 'li' )
) {
const wrapperDimensions = wrapper.getBoundingClientRect();
//we store an array with the width of each item
const itemsWidths = getItemWidths( children );
let totalWidth = 0;
let isWrapping = false;

//the nav block may have row-gap applied, which is not calculated in getItemWidths
const computedStyle = window.getComputedStyle( wrapper );
const rowGap = parseFloat( computedStyle.rowGap ) || 0;

for ( let i = 0, len = itemsWidths.length; i < len; i++ ) {
totalWidth += itemsWidths[ i ];
if ( rowGap > 0 && i > 0 ) {
totalWidth += rowGap;
}
if ( parseInt( totalWidth ) > parseInt( wrapperDimensions.width ) ) {
isWrapping = true;
}
}
return isWrapping;
}

function isNavWrapping( ref ) {
let isWrapping = false;
//how can we check if the nav element is wrapped inside its parent if we don't know anything about it (the parent)?
//for debugging purposes
const container = getFlexParent( ref );
if ( container !== null ) {
isWrapping = areItemsWrapping(
container,
Array.from(
container.querySelector( 'ul.wp-block-navigation' ).children
)
);
}

return isWrapping;
}

function getFlexParent( elem ) {
if ( elem === document.body ) {
// Base case: Stop recursion once we go all the way to the body to avoid infinite recursion
return null;
}
const parent = elem.parentNode;
const containerStyles = window.getComputedStyle( parent );
const isFlexWrap =
containerStyles.getPropertyValue( 'flex-wrap' ) === 'wrap';
if ( isFlexWrap ) {
return parent;
}
return getFlexParent( parent );
}

function getItemWidths( items ) {
const itemsWidths = [];

items.forEach( function ( item ) {
const style = item.currentStyle || window.getComputedStyle( item );
const itemDimensions = item.getBoundingClientRect();
const width = parseFloat( itemDimensions.width );
const marginLeft = parseFloat( style.marginLeft );
const marginRight = parseFloat( style.marginRight );
const totalWidth = width + marginLeft + marginRight;

itemsWidths.push( totalWidth );
} );
return itemsWidths;
}

0 comments on commit cef2e2c

Please sign in to comment.