Skip to content

Commit

Permalink
Try extracting Navigation Link rendering from the Navigation Block (#…
Browse files Browse the repository at this point in the history
…21075)

* Extract Navigation Link block rendering from Navigation

Move code around with TODOs where needed

Migrate away from block.json

Filter out empty blocks

Minor tweaks

Add navigation link to core dynamic block types

Temporarily comment out code in nav-link block that is coupled to nav block

Minor fixes

Actually render the inner blocks

This is probably fine

Render nav link inner blocks in a <ul>

Make the Show Submenu Icon feature work using CSS

Ensure default attributes work correctly on nav and nav link blocks

Fix has-submenu-icon classname application in render function

Make color styles inherit

Move navigation link styles to the navigation link style.scss

Fix & being used in base level style

Remove TODO that has now been TODONE

Fix PHP linting

Update navigation link snapshot test

Fix PHP doc block comments

Co-Authored-By: Robert Anderson <[email protected]>

* Render navigation-link from block.json

* Migrate some navigation-link styles from navigation

* Fix copy/pasted function name

* Navigation: Use render_callback instead of render_block hook

* Navigation: Use block context when rendering a Link

* Navigation: Remove core/ prefix from context attribute names

* Navigation: Remove .has-submenu-icon

* Navigation: Fix failing integration test

* Navigation: Fix submenu icon appearance

Co-authored-by: Robert Anderson <[email protected]>
  • Loading branch information
talldan and noisysocks authored Jul 3, 2020
1 parent 0db58dd commit 55d7f85
Show file tree
Hide file tree
Showing 8 changed files with 384 additions and 275 deletions.
1 change: 1 addition & 0 deletions lib/blocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ function gutenberg_reregister_core_block_types() {
'latest-posts.php' => 'core/latest-posts',
'legacy-widget.php' => 'core/legacy-widget',
'navigation.php' => 'core/navigation',
'navigation-link.php' => 'core/navigation-link',
'rss.php' => 'core/rss',
'search.php' => 'core/search',
'shortcode.php' => 'core/shortcode',
Expand Down
9 changes: 9 additions & 0 deletions packages/block-library/src/navigation-link/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@
"type": "string"
}
},
"usesContext": [
"textColor",
"customTextColor",
"backgroundColor",
"customBackgroundColor",
"fontSize",
"customFontSize",
"showSubmenuIcon"
],
"supports": {
"reusable": false,
"html": false,
Expand Down
214 changes: 214 additions & 0 deletions packages/block-library/src/navigation-link/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
<?php
/**
* Server-side rendering of the `core/navigation-link` block.
*
* @package gutenberg
*/

/**
* Build an array with CSS classes and inline styles defining the colors
* which will be applied to the navigation markup in the front-end.
*
* @param array $context Navigation block context.
* @return array Colors CSS classes and inline styles.
*/
function block_core_navigation_link_build_css_colors( $context ) {
$colors = array(
'css_classes' => array(),
'inline_styles' => '',
);

// Text color.
$has_named_text_color = array_key_exists( 'textColor', $context );
$has_custom_text_color = array_key_exists( 'customTextColor', $context );

// If has text color.
if ( $has_custom_text_color || $has_named_text_color ) {
// Add has-text-color class.
$colors['css_classes'][] = 'has-text-color';
}

if ( $has_named_text_color ) {
// Add the color class.
$colors['css_classes'][] = sprintf( 'has-%s-color', $context['textColor'] );
} elseif ( $has_custom_text_color ) {
// Add the custom color inline style.
$colors['inline_styles'] .= sprintf( 'color: %s;', $context['customTextColor'] );
}

// Background color.
$has_named_background_color = array_key_exists( 'backgroundColor', $context );
$has_custom_background_color = array_key_exists( 'customBackgroundColor', $context );

// If has background color.
if ( $has_custom_background_color || $has_named_background_color ) {
// Add has-background class.
$colors['css_classes'][] = 'has-background';
}

if ( $has_named_background_color ) {
// Add the background-color class.
$colors['css_classes'][] = sprintf( 'has-%s-background-color', $context['backgroundColor'] );
} elseif ( $has_custom_background_color ) {
// Add the custom background-color inline style.
$colors['inline_styles'] .= sprintf( 'background-color: %s;', $context['customBackgroundColor'] );
}

return $colors;
}

/**
* Build an array with CSS classes and inline styles defining the font sizes
* which will be applied to the navigation markup in the front-end.
*
* @param array $context Navigation block context.
* @return array Font size CSS classes and inline styles.
*/
function block_core_navigation_link_build_css_font_sizes( $context ) {
// CSS classes.
$font_sizes = array(
'css_classes' => array(),
'inline_styles' => '',
);

$has_named_font_size = array_key_exists( 'fontSize', $context );
$has_custom_font_size = array_key_exists( 'customFontSize', $context );

if ( $has_named_font_size ) {
// Add the font size class.
$font_sizes['css_classes'][] = sprintf( 'has-%s-font-size', $context['fontSize'] );
} elseif ( $has_custom_font_size ) {
// Add the custom font size inline style.
$font_sizes['inline_styles'] = sprintf( 'font-size: %spx;', $context['customFontSize'] );
}

return $font_sizes;
}

/**
* Returns the top-level submenu SVG chevron icon.
*
* @return string
*/
function block_core_navigation_link_render_submenu_icon() {
return '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" transform="rotate(90)"><path d="M8 5v14l11-7z"/><path d="M0 0h24v24H0z" fill="none"/></svg>';
}

/**
* Renders the `core/navigation-link` block.
*
* @param array $attributes The block attributes.
* @param array $content The saved content.
* @param array $block The parsed block.
*
* @return string Returns the post content with the legacy widget added.
*/
function render_block_core_navigation_link( $attributes, $content, $block ) {
// Don't render the block's subtree if it has no label.
if ( empty( $attributes['label'] ) ) {
return '';
}

$colors = block_core_navigation_link_build_css_colors( $block->context );
$font_sizes = block_core_navigation_link_build_css_font_sizes( $block->context );
$classes = array_merge(
$colors['css_classes'],
$font_sizes['css_classes']
);
$classes[] = 'wp-block-navigation-link';
$style_attribute = ( $colors['inline_styles'] || $font_sizes['inline_styles'] );

$css_classes = trim( implode( ' ', $classes ) );
$has_submenu = count( $block->inner_blocks ) > 0;
$is_active = ! empty( $attributes['id'] ) && ( get_the_ID() === $attributes['id'] );

$class_name = ! empty( $attributes['className'] ) ? implode( ' ', (array) $attributes['className'] ) : false;

if ( false !== $class_name ) {
$css_classes .= ' ' . $class_name;
};

$html = '<li class="' . esc_attr( $css_classes . ( $has_submenu ? ' has-child' : '' ) ) .
( $is_active ? ' current-menu-item' : '' ) . '"' . $style_attribute . '>' .
'<a class="wp-block-navigation-link__content"';

// Start appending HTML attributes to anchor tag.
if ( isset( $attributes['url'] ) ) {
$html .= ' href="' . esc_url( $attributes['url'] ) . '"';
}

if ( isset( $attributes['opensInNewTab'] ) && true === $attributes['opensInNewTab'] ) {
$html .= ' target="_blank" ';
}
// End appending HTML attributes to anchor tag.

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

if ( isset( $attributes['label'] ) ) {
$html .= wp_kses(
$attributes['label'],
array(
'code' => array(),
'em' => array(),
'img' => array(
'scale' => array(),
'class' => array(),
'style' => array(),
'src' => array(),
'alt' => array(),
),
's' => array(),
'span' => array(
'style' => array(),
),
'strong' => array(),
)
);
}

$html .= '</span>';

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

if ( $block->context['showSubmenuIcon'] && $has_submenu ) {
// The submenu icon can be hidden by a CSS rule on the Navigation Block.
$html .= '<span class="wp-block-navigation-link__submenu-icon">' . block_core_navigation_link_render_submenu_icon() . '</span>';
}

if ( $has_submenu ) {
$inner_blocks_html = '';
foreach ( $block->inner_blocks as $inner_block ) {
$inner_blocks_html .= $inner_block->render();
}

// TODO - classname is wrong!
$html .= sprintf(
'<ul class="wp-block-navigation__container">%s</ul>',
$inner_blocks_html
);
}

$html .= '</li>';

return $html;
}

/**
* Register the navigation link block.
*
* @uses render_block_core_navigation()
* @throws WP_Error An WP_Error exception parsing the block definition.
*/
function register_block_core_navigation_link() {
register_block_type_from_metadata(
__DIR__ . '/navigation-link',
array(
'render_callback' => 'render_block_core_navigation_link',
)
);
}
add_action( 'init', 'register_block_core_navigation_link' );
135 changes: 135 additions & 0 deletions packages/block-library/src/navigation-link/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
.wp-block-navigation-link {
display: flex;
align-items: center;
position: relative;
margin: 0;

.wp-block-navigation__container:empty {
display: none;
}
}

.wp-block-navigation__container {
// Reset the default list styles
list-style: none;
margin: 0;
padding-left: 0;

// Horizontal layout
display: flex;
flex-wrap: wrap;

// Vertical layout

.is-vertical & {
display: block;
}
}

// Styles for submenu flyout
.has-child {
$navigation-vertical-padding: $grid-unit-10 * 0.75;
.wp-block-navigation__container {
border: $border-width solid rgba(0, 0, 0, 0.15);
background-color: inherit;
color: inherit;
position: absolute;
left: 0;
top: 100%;
width: fit-content;
z-index: 1;
opacity: 0;
transition: opacity 0.1s linear;
visibility: hidden;

> .wp-block-navigation-link {
> .wp-block-navigation-link__content {
flex-grow: 1;
}
> .wp-block-navigation-link__submenu-icon {
padding-right: $grid-unit-10;
}
}

@include break-medium {
left: $grid-unit-30;

// Nested submenus sit to the left on large breakpoints
.wp-block-navigation__container {
left: 100%;
top: -1px;

// Prevent the menu from disappearing when the mouse is over the gap
&::before {
content: "";
position: absolute;
right: 100%;
height: 100%;
display: block;
width: $grid-unit-10;
background: transparent;
}
}

.wp-block-navigation-link__submenu-icon svg {
transform: rotate(0);
}
}
}
// Separating out hover and focus-within so hover works again on IE: https://davidwalsh.name/css-focus-within#comment-513401
// We will need to replace focus-within with a JS solution for IE keyboard support.
&:hover {
cursor: pointer;

> .wp-block-navigation__container {
visibility: visible;
opacity: 1;
display: flex;
flex-direction: column;
}
}

&:focus-within {
cursor: pointer;

> .wp-block-navigation__container {
visibility: visible;
opacity: 1;
display: flex;
flex-direction: column;
}
}
}

// All links
.wp-block-navigation-link__content {
text-decoration: none;
padding: $grid-unit-10 $grid-unit-10 * 2;

+ .wp-block-navigation-link__content {
padding-top: 0;
}
.has-text-color & {
color: inherit;
}
}

.wp-block-navigation-link__label {
font-family: $default-font;

word-break: normal;
overflow-wrap: break-word;
}

.wp-block-navigation-link__submenu-icon {
height: inherit;
padding: $grid-unit-10 * 0.75 $grid-unit-10 * 2;

svg {
fill: currentColor;

@include break-medium {
transform: rotate(90deg);
}
}
}
9 changes: 9 additions & 0 deletions packages/block-library/src/navigation/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@
"default": true
}
},
"providesContext": {
"textColor": "textColor",
"customTextColor": "customTextColor",
"backgroundColor": "backgroundColor",
"customBackgroundColor": "customBackgroundColor",
"fontSize": "fontSize",
"customFontSize": "customFontSize",
"showSubmenuIcon": "showSubmenuIcon"
},
"supports": {
"align": [
"wide",
Expand Down
Loading

0 comments on commit 55d7f85

Please sign in to comment.