Skip to content

Commit

Permalink
Navigation Block: Add submenu chevron w/ setting (#19601)
Browse files Browse the repository at this point in the history
* Initialize setting in the nav block settings panel

* Add submenu icon

* Register "showSubmenuIcon" attributes

* Add submenu icon to front-end of the page

* Update submenu icon setting description

* Don't use <span> for RichText element

* Isolate NavigationLink icons

* Clean up a little

* Use <span> for NavigationLink contents

* Rename `$level_zero` to `$is_level_zero`

* Add missing spaces

* Update submenu icon selector in style.scss

* Add comment about span-wrapping

* Fix phpcs errors

* Remove unused styles

* Fix failing e2e tests

* Update failing snapshots
  • Loading branch information
WunderBart authored and retrofox committed Jan 21, 2020
1 parent b39e9d9 commit b77d71a
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 67 deletions.
41 changes: 32 additions & 9 deletions packages/block-library/src/navigation-link/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ import {
ExternalLink,
KeyboardShortcuts,
PanelBody,
Path,
Popover,
SVG,
TextareaControl,
TextControl,
ToggleControl,
Expand All @@ -37,12 +35,18 @@ import {
} from '@wordpress/block-editor';
import { Fragment, useState, useEffect } from '@wordpress/element';

/**
* Internal dependencies
*/
import { toolbarSubmenuIcon, itemSubmenuIcon } from './icons';

function NavigationLinkEdit( {
attributes,
hasDescendants,
isSelected,
isParentOfSelectedBlock,
setAttributes,
showSubmenuIcon,
insertLinkBlock,
} ) {
const { label, opensInNewTab, title, url, nofollow, description } = attributes;
Expand Down Expand Up @@ -93,7 +97,7 @@ function NavigationLinkEdit( {
/>
<ToolbarButton
name="submenu"
icon={ <SVG xmlns="http://www.w3.org/2000/svg" width="24" height="24"><Path d="M14 5h8v2h-8zm0 5.5h8v2h-8zm0 5.5h8v2h-8zM2 11.5C2 15.08 4.92 18 8.5 18H9v2l3-3-3-3v2h-.5C6.02 16 4 13.98 4 11.5S6.02 7 8.5 7H12V5H8.5C4.92 5 2 7.92 2 11.5z" /><Path fill="none" d="M0 0h24v24H0z" /></SVG> }
icon={ toolbarSubmenuIcon }
title={ __( 'Add submenu' ) }
onClick={ insertLinkBlock }
/>
Expand Down Expand Up @@ -150,9 +154,10 @@ function NavigationLinkEdit( {
'has-link': !! url,
} ) }
>
<div>
<div className="wp-block-navigation-link__content">
<RichText
className="wp-block-navigation-link__content"
tagName="span"
className="wp-block-navigation-link__label"
value={ label }
onChange={ ( labelValue ) => setAttributes( { label: labelValue } ) }
placeholder={ itemLabelPlaceholder }
Expand All @@ -164,6 +169,11 @@ function NavigationLinkEdit( {
'core/strikethrough',
] }
/>
{ showSubmenuIcon &&
<span className="wp-block-navigation-link__submenu-icon">
{ itemSubmenuIcon }
</span>
}
{ isLinkOpen && (
<Popover position="bottom center">
<LinkControl
Expand Down Expand Up @@ -208,13 +218,26 @@ function NavigationLinkEdit( {

export default compose( [
withSelect( ( select, ownProps ) => {
const { getClientIdsOfDescendants, hasSelectedInnerBlock } = select( 'core/block-editor' );
const {
getBlockName,
getBlockAttributes,
getBlockParents,
getClientIdsOfDescendants,
hasSelectedInnerBlock,
} = select( 'core/block-editor' );
const { clientId } = ownProps;
const rootBlock = getBlockParents( clientId )[ 0 ];
const parentBlock = getBlockParents( clientId, true )[ 0 ];
const rootBlockAttributes = getBlockAttributes( rootBlock );
const hasDescendants = !! getClientIdsOfDescendants( [ clientId ] ).length;
const isLevelZero = getBlockName( parentBlock ) === 'core/navigation';
const showSubmenuIcon = rootBlockAttributes.showSubmenuIcon && isLevelZero && hasDescendants;
const isParentOfSelectedBlock = hasSelectedInnerBlock( clientId, true );

return {
isParentOfSelectedBlock: hasSelectedInnerBlock( clientId, true ),
hasDescendants: !! getClientIdsOfDescendants( [ clientId ] ).length,

isParentOfSelectedBlock,
hasDescendants,
showSubmenuIcon,
};
} ),
withDispatch( ( dispatch, ownProps, registry ) => {
Expand Down
42 changes: 10 additions & 32 deletions packages/block-library/src/navigation-link/editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,6 @@
min-height: $icon-button-size;
}

.wp-block-navigation-link__edit-container {
display: flex;
white-space: nowrap;

// Compensate for navigation link base padding.
margin-left: -$grid-size;

.wp-block-navigation-link__content {
margin-right: $grid-size;

// This should match the padding of the navigation link.
padding: 0 $grid-size;

// This make it look like an input field.
// We may want to not style this at all, but let's try this.
// We don't use the mixins because they increase the size of the input, which doesn't work with PlainText.
box-shadow: inset 0 0 0 1px $dark-gray-200;
transition: box-shadow 0.1s linear;
border-radius: $radius-round-rectangle;
@include reduce-motion("transition");

&:focus {
color: $dark-gray-900;
box-shadow: inset 0 0 0 2px $blue-medium-focus;

// Windows High Contrast mode will show this outline, but not the box-shadow.
outline: 2px solid transparent;
}
}
}

/*
* Adjust Navigation Item.
*/
Expand Down Expand Up @@ -69,10 +38,19 @@
display: block;
}

&.has-link .wp-block-navigation-link__content {
.wp-block-navigation-link__content {
display: flex;
align-items: center;
}

&.has-link .wp-block-navigation-link__label {
text-decoration: underline;
}

.wp-block-navigation-link__submenu-icon {
margin-left: 4px;
}

.block-editor-rich-text__editable.is-selected:not(.keep-placeholder-on-focus):not(:focus) [data-rich-text-placeholder]::after {
display: inline-block;
}
Expand Down
17 changes: 17 additions & 0 deletions packages/block-library/src/navigation-link/icons.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* WordPress dependencies
*/
import { Polygon, Path, SVG } from '@wordpress/components';

export const toolbarSubmenuIcon = (
<SVG xmlns="http://www.w3.org/2000/svg" width="24" height="24">
<Path d="M14 5h8v2h-8zm0 5.5h8v2h-8zm0 5.5h8v2h-8zM2 11.5C2 15.08 4.92 18 8.5 18H9v2l3-3-3-3v2h-.5C6.02 16 4 13.98 4 11.5S6.02 7 8.5 7H12V5H8.5C4.92 5 2 7.92 2 11.5z" />
<Path fill="none" d="M0 0h24v24H0z" />
</SVG>
);

export const itemSubmenuIcon = (
<SVG width="18" height="18" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 18">
<Polygon points="9,13.5 14.7,7.9 13.2,6.5 9,10.7 4.8,6.5 3.3,7.9 " />
</SVG>
);
14 changes: 14 additions & 0 deletions packages/block-library/src/navigation/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
PanelBody,
Placeholder,
Spinner,
ToggleControl,
Toolbar,
ToolbarGroup,
} from '@wordpress/components';
Expand Down Expand Up @@ -216,6 +217,19 @@ function Navigation( {
</PanelBody>
</InspectorControls>
{ InspectorControlsColorPanel }
<InspectorControls>
<PanelBody
title={ __( 'Display Settings' ) }
>
<ToggleControl
checked={ attributes.showSubmenuIcon }
onChange={ ( value ) => {
setAttributes( { showSubmenuIcon: value } );
} }
label={ __( 'Show submenu icon for top-level items' ) }
/>
</PanelBody>
</InspectorControls>
<TextColor>
<BackgroundColor>
<div
Expand Down
48 changes: 37 additions & 11 deletions packages/block-library/src/navigation/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,15 @@ function( $block ) {
return $blocks;
}

/**
* Returns the top-level submenu SVG chevron icon.
*
* @return string
*/
function render_submenu_icon() {
return '<svg width="18" height="18" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 18" role="img" aria-hidden="true" focusable="false"><polygon points="9,13.5 14.7,7.9 13.2,6.5 9,10.7 4.8,6.5 3.3,7.9 "></polygon></svg>';
}

/**
* Renders the `core/navigation` block on server.
*
Expand Down Expand Up @@ -145,21 +154,22 @@ function render_block_navigation( $attributes, $content, $block ) {
'<nav %1$s %2$s>%3$s</nav>',
$class_attribute,
$style_attribute,
build_navigation_html( $block, $colors, $font_sizes )
build_navigation_html( $attributes, $block, $colors, $font_sizes, true )
);
}

/**
* Walks the inner block structure and returns an HTML list for it.
*
* @param array $block The block.
* @param array $colors Contains inline styles and CSS classes to apply to navigation item.
* @param array $font_sizes Contains inline styles and CSS classes to apply to navigation item.
* @param bool $level_zero True whether is main menu (level zero). Otherwise, False.
* @param array $attributes The Navigation block attributes.
* @param array $block The NavigationItem block.
* @param array $colors Contains inline styles and CSS classes to apply to navigation item.
* @param array $font_sizes Contains inline styles and CSS classes to apply to navigation item.
* @param bool $is_level_zero True whether is main menu (level zero). Otherwise, False.
*
* @return string Returns an HTML list from innerBlocks.
*/
function build_navigation_html( $block, $colors, $font_sizes, $level_zero = true ) {
function build_navigation_html( $attributes, $block, $colors, $font_sizes, $is_level_zero = true ) {
$html = '';
$classes = array_merge(
$colors['css_classes'],
Expand All @@ -172,11 +182,12 @@ function build_navigation_html( $block, $colors, $font_sizes, $level_zero = true
: '';

foreach ( (array) $block['innerBlocks'] as $key => $block ) {
$has_submenu = count( (array) $block['innerBlocks'] ) > 0;

$html .= '<li class="wp-block-navigation-link">' .
$html .= '<li class="wp-block-navigation-link' . ( $has_submenu ? ' has-submenu' : '' ) . '">' .
'<a';

if ( $level_zero ) {
if ( $is_level_zero ) {
$html .= $class_attribute . $style_attribute;
}

Expand All @@ -194,7 +205,10 @@ function build_navigation_html( $block, $colors, $font_sizes, $level_zero = true
// End appending HTML attributes to anchor tag.

// Start anchor tag content.
$html .= '>';
$html .= '>' .
// Wrap title with span to isolate it from submenu icon.
'<span class="wp-block-navigation-link__label">';

if ( isset( $block['attrs']['label'] ) ) {
$html .= wp_kses(
$block['attrs']['label'],
Expand All @@ -216,11 +230,19 @@ function build_navigation_html( $block, $colors, $font_sizes, $level_zero = true
)
);
}

$html .= '</span>';

// Append submenu icon to top-level item.
if ( $attributes['showSubmenuIcon'] && $is_level_zero && $has_submenu ) {
$html .= '<span class="wp-block-navigation-link__submenu-icon">' . render_submenu_icon() . '</span>';
}

$html .= '</a>';
// End anchor tag content.

if ( count( (array) $block['innerBlocks'] ) > 0 ) {
$html .= build_navigation_html( $block, $colors, $font_sizes, false );
if ( $has_submenu ) {
$html .= build_navigation_html( $attributes, $block, $colors, $font_sizes, false );
}

$html .= '</li>';
Expand Down Expand Up @@ -264,6 +286,10 @@ function register_block_core_navigation() {
'itemsJustification' => array(
'type' => 'string',
),
'showSubmenuIcon' => array(
'type' => 'boolean',
'default' => false,
),
),

'render_callback' => 'render_block_navigation',
Expand Down
23 changes: 11 additions & 12 deletions packages/block-library/src/navigation/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,12 @@
}
}

// ToDo: move navigation-link styles to navigation-link/style.scss
& > li {

& > a {
display: flex;
align-items: center;
padding-left: 0;

@include break-small {
Expand All @@ -54,6 +57,14 @@
&:last-of-type > a {
padding-right: 0;
}

.wp-block-navigation-link__submenu-icon {
margin-left: 4px;

svg {
fill: currentColor;
}
}
}

// Sub-menus Flyout
Expand Down Expand Up @@ -149,18 +160,6 @@
}
}

// Top-level sub-menu indicators
& .has-sub-menu > a {

&::after {
content: "\00a0\25BC";
display: inline-block;
font-size: 0.6rem;
height: inherit;
width: inherit;
}
}

&.items-justified-left > ul {
justify-content: flex-start;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

exports[`Navigation allows a navigation menu to be created from an empty menu using a mixture of internal and external links 1`] = `
"<!-- wp:navigation -->
<!-- wp:navigation-link {\\"label\\":\\"WP\\",\\"title\\":\\"https://wordpress.org\\",\\"url\\":\\"https://wordpress.org\\"} /-->
<!-- wp:navigation-link {\\"label\\":\\"WP\\",\\"title\\":\\"https://wordpress.org\\",\\"id\\":\\"-1\\",\\"url\\":\\"https://wordpress.org\\"} /-->
<!-- wp:navigation-link {\\"label\\":\\"Get in touch\\",\\"title\\":\\"Contact Us\\",\\"url\\":\\"https://this/is/a/test/url/contact-us\\"} /-->
<!-- wp:navigation-link {\\"label\\":\\"Get in touch\\",\\"title\\":\\"Contact Us\\",\\"id\\":1,\\"url\\":\\"https://this/is/a/test/url/contact-us\\"} /-->
<!-- /wp:navigation -->"
`;

Expand Down
2 changes: 1 addition & 1 deletion packages/e2e-tests/specs/editor/blocks/navigation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ async function updateActiveNavigationLink( { url, label } ) {
}

if ( label ) {
await page.click( '.wp-block-navigation-link__content.is-selected' );
await page.click( '.wp-block-navigation-link__label.is-selected' );

// Ideally this would be `await pressKeyWithModifier( 'primary', 'a' )`
// to select all text like other tests do.
Expand Down

0 comments on commit b77d71a

Please sign in to comment.