Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Try using popover API for navigation block (WIP) #68755

Draft
wants to merge 13 commits into
base: trunk
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 38 additions & 28 deletions packages/block-library/src/navigation/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -492,31 +492,19 @@
$toggle_aria_label_close = $should_display_icon_label ? 'aria-label="' . __( 'Close menu' ) . '"' : ''; // Close button label.

// Add Interactivity API directives to the markup if needed.
$open_button_directives = '';
$responsive_container_directives = '';
$responsive_dialog_directives = '';
$close_button_directives = '';
if ( $is_interactive ) {
$open_button_directives = '
data-wp-on-async--click="actions.openMenuOnClick"
data-wp-on--keydown="actions.handleMenuKeydown"
';
$responsive_container_directives = '
data-wp-class--has-modal-open="state.isMenuOpen"
data-wp-class--is-menu-open="state.isMenuOpen"
data-wp-watch="callbacks.initMenu"
data-wp-on--toggle="actions.handleToggle"
data-wp-on--keydown="actions.handleMenuKeydown"
data-wp-on-async--focusout="actions.handleMenuFocusout"
tabindex="-1"
data-wp-watch="callbacks.setModal"
';
$responsive_dialog_directives = '
data-wp-bind--aria-modal="state.ariaModal"
data-wp-bind--aria-label="state.ariaLabel"
data-wp-bind--role="state.roleAttribute"
';
$close_button_directives = '
data-wp-on-async--click="actions.closeMenuOnClick"
';
$responsive_container_content_directives = '
data-wp-watch="callbacks.focusFirstElement"
';
Expand All @@ -525,12 +513,12 @@
$overlay_inline_styles = esc_attr( safecss_filter_attr( $colors['overlay_inline_styles'] ) );

return sprintf(
'<button aria-haspopup="dialog" %3$s class="%6$s" %10$s>%8$s</button>
<div class="%5$s" %7$s id="%1$s" %11$s>
'<button popovertarget="%1$s" aria-haspopup="dialog" %3$s class="%6$s">%8$s</button>
<div popover="auto" class="%5$s" %7$s id="%1$s" %10$s>
<div class="wp-block-navigation__responsive-close" tabindex="-1">
<div class="wp-block-navigation__responsive-dialog" %12$s>
<button %4$s class="wp-block-navigation__responsive-container-close" %13$s>%9$s</button>
<div class="wp-block-navigation__responsive-container-content" %14$s id="%1$s-content">
<div class="wp-block-navigation__responsive-dialog" %11$s>
<button popovertarget="%1$s" %4$s class="wp-block-navigation__responsive-container-close">%9$s</button>
<div class="wp-block-navigation__responsive-container-content" %12$s id="%1$s-content">
%2$s
</div>
</div>
Expand All @@ -545,10 +533,8 @@
( ! empty( $overlay_inline_styles ) ) ? "style=\"$overlay_inline_styles\"" : '',
$toggle_button_content,
$toggle_close_button_content,
$open_button_directives,
$responsive_container_directives,
$responsive_dialog_directives,
$close_button_directives,
$responsive_container_content_directives
);
}
Expand Down Expand Up @@ -811,18 +797,24 @@
* @return string Submenu markup with the directives injected.
*/
function block_core_navigation_add_directives_to_submenu( $tags, $block_attributes ) {
static $unique_id_counter = 0;

while ( $tags->next_tag(
array(
'tag_name' => 'LI',
'class_name' => 'has-child',
)
) ) {
$unique_id_counter++;

Check warning on line 808 in packages/block-library/src/navigation/index.php

View workflow job for this annotation

GitHub Actions / PHP coding standards

Stand-alone post-increment statement found. Use pre-increment instead: ++$unique_id_counter.
$anchor_name = "wp-block-navigation-submenu-container-{$unique_id_counter}";

// Add directives to the parent `<li>`.
$tags->set_attribute( 'data-wp-interactive', 'core/navigation' );
$tags->set_attribute( 'data-wp-context', '{ "submenuOpenedBy": { "click": false, "hover": false, "focus": false }, "type": "submenu", "modal": null }' );
$tags->set_attribute( 'data-wp-watch', 'callbacks.initMenu' );
$tags->set_attribute( 'data-wp-on--focusout', 'actions.handleMenuFocusout' );
$tags->set_attribute( 'data-wp-on--keydown', 'actions.handleMenuKeydown' );
// TODO: Check if this is intended. Before this was on the submenu container, but then caused it to never open from focus alone.
$tags->set_attribute( 'data-wp-on--focusin', 'actions.openMenuOnFocus' );
$tags->set_attribute( 'data-wp-on--focusout', 'actions.closeMenuOnFocus' );
$tags->set_attribute( 'style', "anchor-name: --{$anchor_name};" );

// This is a fix for Safari. Without it, Safari doesn't change the active
// element when the user clicks on a button. It can be removed once we add
Expand All @@ -842,9 +834,8 @@
'class_name' => 'wp-block-navigation-submenu__toggle',
)
) ) {
$tags->set_attribute( 'data-wp-on-async--click', 'actions.toggleMenuOnClick' );
$tags->set_attribute( 'data-wp-bind--aria-expanded', 'state.isMenuOpen' );
// The `aria-expanded` attribute for SSR is already added in the submenu block.
// Set bookmark to amend the submenu toggle based on the submenu container below.
$tags->set_bookmark( 'nav-submenu-toggle' );
}
// Add directives to the submenu.
if ( $tags->next_tag(
Expand All @@ -853,7 +844,26 @@
'class_name' => 'wp-block-navigation__submenu-container',
)
) ) {
$tags->set_attribute( 'data-wp-on-async--focus', 'actions.openMenuOnFocus' );
$id = $tags->get_attribute( 'id' );
if ( ! $id ) {
$id = $anchor_name;
$tags->set_attribute( 'id', $id );
}
// TODO: `popover=hint` is not supported yet, but eventually it should be used if the menu opens on hover.
$tags->set_attribute( 'popover', /* isset( $block_attributes['openSubmenusOnClick'] ) && $block_attributes['openSubmenusOnClick'] ? 'auto' : 'hint' */ 'auto' );
$tags->set_attribute( 'data-wp-on--toggle', 'actions.handleToggle' );
$tags->set_attribute( 'data-wp-watch', 'callbacks.setModal' );
$tags->set_attribute( 'style', "position-anchor: --{$anchor_name};" );

// Set the ID of the submenu container as `popovertarget` on its submenu button if present.
$tags->set_bookmark( 'nav-submenu-container' );
if ( $tags->seek( 'nav-submenu-toggle' ) ) {
$tags->set_attribute( 'popovertarget', $id );
$tags->remove_attribute( 'aria-expanded' ); // Unnecessary when using `popovertarget`.
}
$tags->seek( 'nav-submenu-container' );
$tags->release_bookmark( 'nav-submenu-toggle' );
$tags->release_bookmark( 'nav-submenu-container' );
}

// Iterate through subitems if exist.
Expand Down
101 changes: 41 additions & 60 deletions packages/block-library/src/navigation/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,12 @@ $navigation-icon-size: 24px;
background-color: inherit;
color: inherit;
position: absolute;
z-index: 2;
margin: 0;
padding: 0;
right: auto;
left: anchor(left);
top: anchor(bottom);
bottom: auto;
display: flex;
flex-direction: column;
align-items: normal;
Expand All @@ -171,11 +176,23 @@ $navigation-icon-size: 24px;
}
visibility: hidden;

// Submenu indentation when there's no background.
margin-left: -1px; // Border width.

// Don't take up space when the menu is collapsed.
width: 0;
height: 0;
overflow: hidden; // Overflow is necessary to set, otherwise submenu items will take up space.

&:popover-open {
visibility: visible;
overflow: visible;
opacity: 1;
width: auto;
height: auto;
min-width: 200px;
}

// Submenu items.
> .wp-block-navigation-item {
> .wp-block-navigation-item__content {
Expand All @@ -195,16 +212,11 @@ $navigation-icon-size: 24px;
margin: 0;
}

// Submenu indentation when there's no background.
left: -1px; // Border width.
top: 100%;

// Indentation for all submenus.
// Nested submenus sit to the left on large breakpoints.
// On smaller breakpoints, they open vertically, accordion-style.
@include break-medium {
.wp-block-navigation__submenu-container {
left: 100%;
top: -1px; // Border width.

// Prevent the menu from disappearing when the mouse is over the gap
Expand All @@ -230,50 +242,17 @@ $navigation-icon-size: 24px;
}
}
}

// Custom menu items.
// Show submenus on hover unless they open on click.
&:not(.open-on-click):hover > .wp-block-navigation__submenu-container {
visibility: visible;
overflow: visible;
opacity: 1;
width: auto;
height: auto;
min-width: 200px;
}

// Keep submenus open when focus is within.
&:not(.open-on-click):not(.open-on-hover-click):focus-within > .wp-block-navigation__submenu-container {
visibility: visible;
overflow: visible;
opacity: 1;
width: auto;
height: auto;
min-width: 200px;
}

// Show submenus on click.
.wp-block-navigation-submenu__toggle[aria-expanded="true"] ~ .wp-block-navigation__submenu-container {
visibility: visible;
overflow: visible;
opacity: 1;
width: auto;
height: auto;
min-width: 200px;
}
}

// Submenu indentation when there's a background.
.wp-block-navigation.has-background
.has-child
.wp-block-navigation__submenu-container {
left: 0;
top: 100%;
margin-left: 0;

// There's no border on submenus when there are backgrounds.
@include break-medium {
.wp-block-navigation__submenu-container {
left: 100%;
top: 0;
}
}
Expand Down Expand Up @@ -384,7 +363,7 @@ button.wp-block-navigation-item__content {
// First submenu.
.wp-block-navigation__submenu-container {
left: auto;
right: 0;
right: anchor(right);

// Nested submenus.
// On smaller breakpoints, nested menus open downwards.
Expand Down Expand Up @@ -466,12 +445,12 @@ button.wp-block-navigation-item__content {
}
}
.wp-block-navigation__responsive-container {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100vh;
box-sizing: border-box;

// Low specificity so that themes can override.
& :where(.wp-block-navigation-item a) {
Expand All @@ -486,9 +465,15 @@ button.wp-block-navigation-item__content {
align-items: var(--navigation-layout-align, initial);
}

&[popover] {
margin: 0;
padding: 0;
border: 0;
}

// If the responsive wrapper is present but overlay is not open,
// overlay styles shouldn't apply.
&:not(.is-menu-open.is-menu-open) {
&:not(:popover-open) {
color: inherit !important;
background-color: inherit !important;
}
Expand All @@ -498,7 +483,7 @@ button.wp-block-navigation-item__content {
// Inherit as much as we can regarding colors, fonts, sizes,
// but otherwise provide a baseline.
// In a future version, we can explore more customizability.
&.is-menu-open {
&:popover-open {
display: flex; // Needs to be set to override "none".
flex-direction: column;
background-color: inherit;
Expand All @@ -518,9 +503,6 @@ button.wp-block-navigation-item__content {
// Allow modal to scroll.
overflow: auto;

// Give it a z-index just higher than the adminbar.
z-index: 100000;

.wp-block-navigation__responsive-container-content {
// Add padding above to accommodate close button.
padding-top: calc(2rem + #{ $navigation-icon-size });
Expand Down Expand Up @@ -612,11 +594,11 @@ button.wp-block-navigation-item__content {

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

.wp-block-navigation__responsive-container-close {
Expand All @@ -625,7 +607,7 @@ button.wp-block-navigation-item__content {
}
}

&.is-menu-open {
&:popover-open {
// Override breakpoint-inherited submenu rules.
.wp-block-navigation__submenu-container.wp-block-navigation__submenu-container.wp-block-navigation__submenu-container.wp-block-navigation__submenu-container {
left: 0;
Expand All @@ -636,12 +618,12 @@ button.wp-block-navigation-item__content {

// Default menu background and font color.
.wp-block-navigation:not(.has-background)
.wp-block-navigation__responsive-container.is-menu-open {
.wp-block-navigation__responsive-container:popover-open {
background-color: #fff;
}

.wp-block-navigation:not(.has-text-color)
.wp-block-navigation__responsive-container.is-menu-open {
.wp-block-navigation__responsive-container:popover-open {
color: #000;
}

Expand Down Expand Up @@ -697,7 +679,6 @@ button.wp-block-navigation-item__content {
position: absolute;
top: 0;
right: 0;
z-index: 2; // Needs to be above the modal z index itself.

// When set to collapse into a text button, it should inherit the parent font.
// This needs specificity to override inherited properties by the button element and component.
Expand Down Expand Up @@ -728,9 +709,9 @@ button.wp-block-navigation-item__content {
}
}

.is-menu-open .wp-block-navigation__responsive-close,
.is-menu-open .wp-block-navigation__responsive-dialog,
.is-menu-open .wp-block-navigation__responsive-container-content {
.wp-block-navigation__responsive-container:popover-open .wp-block-navigation__responsive-close,
.wp-block-navigation__responsive-container:popover-open .wp-block-navigation__responsive-dialog,
.wp-block-navigation__responsive-container:popover-open .wp-block-navigation__responsive-container-content {
box-sizing: border-box;
}

Expand All @@ -739,8 +720,8 @@ button.wp-block-navigation-item__content {
}

// Adjust open dialog top margin when admin-bar is visible.
// Needs to be scoped to .is-menu-open, or it will shift the position of any other navigations that may be present.
.has-modal-open .admin-bar .is-menu-open .wp-block-navigation__responsive-dialog {
// Needs to be scoped to :popover-open, or it will shift the position of any other navigations that may be present.
.has-modal-open .admin-bar .wp-block-navigation__responsive-container:popover-open .wp-block-navigation__responsive-dialog {
margin-top: $admin-bar-height-big;

// Handle smaller admin-bar.
Expand Down
Loading
Loading