From a25fe283d964cddbb68e1ee231dd34ef69d19df7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dami=C3=A1n=20Su=C3=A1rez?= Date: Tue, 22 Oct 2019 20:08:25 -0300 Subject: [PATCH] navigation-menu: Implement colors selector button. (#17832) Summary block-editor: expose ColorPaletteControl component navigation-menu: improve colors-selector component navigation-menu: compose withColors navigation-menu: render colors selector in bar navigation-menu: propagate withColor props navigation-menu: apply theme styles to selection navigation-item: populate styles to nav item navigation-menu: apply inline styles and CSS classes --- packages/block-editor/README.md | 4 + packages/block-editor/src/components/index.js | 1 + .../src/navigation-menu-item/edit.js | 13 +- .../src/navigation-menu-item/editor.scss | 13 +- .../navigation-menu/block-colors-selector.js | 95 ++++++++++++++ .../block-library/src/navigation-menu/edit.js | 111 ++++++++++++---- .../src/navigation-menu/editor.scss | 85 +++++++++++- .../src/navigation-menu/index.php | 124 +++++++++++++++++- 8 files changed, 407 insertions(+), 39 deletions(-) create mode 100644 packages/block-library/src/navigation-menu/block-colors-selector.js diff --git a/packages/block-editor/README.md b/packages/block-editor/README.md index d9c7818065c0b5..86ffa7887d2daf 100644 --- a/packages/block-editor/README.md +++ b/packages/block-editor/README.md @@ -171,6 +171,10 @@ _Related_ Undocumented declaration. +# **ColorPaletteControl** + +Undocumented declaration. + # **ContrastChecker** Undocumented declaration. diff --git a/packages/block-editor/src/components/index.js b/packages/block-editor/src/components/index.js index 6e9bb592378678..a31f3829ca360c 100644 --- a/packages/block-editor/src/components/index.js +++ b/packages/block-editor/src/components/index.js @@ -16,6 +16,7 @@ export { default as __experimentalBlockNavigationList } from './block-navigation export { default as BlockVerticalAlignmentToolbar } from './block-vertical-alignment-toolbar'; export { default as ButtonBlockerAppender } from './button-block-appender'; export { default as ColorPalette } from './color-palette'; +export { default as ColorPaletteControl } from './color-palette/control'; export { default as ContrastChecker } from './contrast-checker'; export { default as __experimentalGradientPicker } from './gradient-picker'; export { default as __experimentalGradientPickerControl } from './gradient-picker/control'; diff --git a/packages/block-library/src/navigation-menu-item/edit.js b/packages/block-library/src/navigation-menu-item/edit.js index f4e456321347c6..90a80f41e2f696 100644 --- a/packages/block-library/src/navigation-menu-item/edit.js +++ b/packages/block-library/src/navigation-menu-item/edit.js @@ -2,6 +2,7 @@ * External dependencies */ import { invoke } from 'lodash'; +import classnames from 'classnames'; /** * WordPress dependencies @@ -84,8 +85,11 @@ function NavigationMenuItemEdit( { ); } else { - content = attributes.label; + content =
+ { attributes.label } +
; } + return ( @@ -138,7 +142,12 @@ function NavigationMenuItemEdit( { /> -
+
{ content } { ( isSelected || isParentOfSelectedBlock ) && +
+
+ Aa +
+
; + +/** + * Renders the Colors Selector Toolbar with the icon button. + * + * @param {Object} style - Colors style object. + * @return {*} React toggle button component. + */ +const renderToggleComponent = ( style ) => ( { onToggle, isOpen } ) => { + const openOnArrowDown = ( event ) => { + if ( ! isOpen && event.keyCode === DOWN ) { + event.preventDefault(); + event.stopPropagation(); + onToggle(); + } + }; + + return ( + + } + /> + + ); +}; + +const renderContent = ( { backgroundColor, textColor, onColorChange = noop } ) => ( () => { + const setColor = ( attr ) => ( value ) => onColorChange( { attr, value } ); + + return ( + <> +
+ +
+ +
+ +
+ + + + ); +} ); + +export default ( { style, className, ...colorControlProps } ) => + ; diff --git a/packages/block-library/src/navigation-menu/edit.js b/packages/block-library/src/navigation-menu/edit.js index 5b4ad5ce475f9a..3fc18a43b2259a 100644 --- a/packages/block-library/src/navigation-menu/edit.js +++ b/packages/block-library/src/navigation-menu/edit.js @@ -1,3 +1,8 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + /** * WordPress dependencies */ @@ -9,6 +14,7 @@ import { InnerBlocks, InspectorControls, BlockControls, + withColors, } from '@wordpress/block-editor'; import { withSelect } from '@wordpress/data'; import { @@ -17,12 +23,15 @@ import { Spinner, Toolbar, } from '@wordpress/components'; +import { compose } from '@wordpress/compose'; + import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ import useBlockNavigator from './use-block-navigator'; +import BlockColorsStyleSelector from './block-colors-selector'; function NavigationMenu( { attributes, @@ -30,6 +39,10 @@ function NavigationMenu( { clientId, pages, isRequesting, + backgroundColor, + textColor, + setBackgroundColor, + setTextColor, } ) { const { navigatorToolbarButton, navigatorModal } = useBlockNavigator( clientId ); const defaultMenuItems = useMemo( @@ -38,20 +51,71 @@ function NavigationMenu( { return null; } return pages.map( ( page ) => { - return [ 'core/navigation-menu-item', - { label: page.title.rendered, destination: page.permalink_template }, - ]; + return [ 'core/navigation-menu-item', { label: page.title.rendered, destination: page.permalink_template } ]; } ); }, [ pages ] ); + const navigationMenuStyles = {}; + if ( textColor.color ) { + navigationMenuStyles[ '--color-menu-link' ] = textColor.color; + } + + if ( backgroundColor.color ) { + navigationMenuStyles[ '--background-color-menu-link' ] = backgroundColor.color; + } + + const navigationMenuClasses = classnames( + 'wp-block-navigation-menu', { + 'has-text-color': textColor.color, + 'has-background-color': backgroundColor.color, + } + ); + + /** + * Set the color type according to the given values. + * It propagate the color values into the attributes object. + * Both `backgroundColorValue` and `textColorValue` are + * using the apply inline styles. + * + * @param {Object} colorsData Arguments passed by BlockColorsStyleSelector onColorChange. + * @param {string} colorsData.attr Color attribute. + * @param {boolean} colorsData.value Color attribute value. + */ + const setColorType = ( { attr, value } ) => { + switch ( attr ) { + case 'backgroundColor': + setBackgroundColor( value ); + setAttributes( { backgroundColorValue: value } ); + break; + + case 'textColor': + setTextColor( value ); + setAttributes( { textColorValue: value } ); + break; + } + }; + + // Set/Unset colors CSS classes. + setAttributes( { + backgroundColorCSSClass: backgroundColor.class ? backgroundColor.class : null, + textColorCSSClass: textColor.class ? textColor.class : null, + } ); + return ( { navigatorToolbarButton } + { navigatorModal } @@ -60,18 +124,15 @@ function NavigationMenu( { > { - setAttributes( { automaticallyAdd } ); - } } + onChange={ ( automaticallyAdd ) => setAttributes( { automaticallyAdd } ) } label={ __( 'Automatically add new pages' ) } help={ __( 'Automatically add new top level pages to this menu.' ) } /> -
- { isRequesting && - - } + +
+ { isRequesting && } { pages && { - const { getEntityRecords } = select( 'core' ); - const { isResolving } = select( 'core/data' ); - const filterDefaultPages = { - parent: 0, - order: 'asc', - orderby: 'id', - }; - return { - pages: getEntityRecords( 'postType', 'page', filterDefaultPages ), - isRequesting: isResolving( 'core', 'getEntityRecords', [ 'postType', 'page', filterDefaultPages ] ), - }; -} )( NavigationMenu ); - +export default compose( [ + withColors( { backgroundColor: 'background-color', textColor: 'color' } ), + withSelect( ( select ) => { + const { getEntityRecords } = select( 'core' ); + const { isResolving } = select( 'core/data' ); + const filterDefaultPages = { + parent: 0, + order: 'asc', + orderby: 'id', + }; + return { + pages: getEntityRecords( 'postType', 'page', filterDefaultPages ), + isRequesting: isResolving( 'core', 'getEntityRecords', [ 'postType', 'page', filterDefaultPages ] ), + }; + } ), +] )( NavigationMenu ); diff --git a/packages/block-library/src/navigation-menu/editor.scss b/packages/block-library/src/navigation-menu/editor.scss index 2238b2fae8dd7c..a92f72eb5c1704 100644 --- a/packages/block-library/src/navigation-menu/editor.scss +++ b/packages/block-library/src/navigation-menu/editor.scss @@ -12,7 +12,90 @@ } .wp-block-navigation-menu-item { - .wp-block-navigation-menu-item { + .wp-block-navigation-menu-item__link { margin-left: $grid-size-large; } } + +/** + * Colors Selector component + */ +$colors-selector-size: 22px; +.block-library-colors-selector { + width: auto; + + // Toolbar colors-selector button. + .block-library-colors-selector__toggle { + display: block; + margin: 0 auto; + padding: 3px; + width: auto; + } + + // Button container. + .block-library-colors-selector__icon-container { + width: 42px; + height: 30px; + position: relative; + margin: 0 auto; + padding: 3px; + display: flex; + align-items: center; + border-radius: 4px; + + // Add the button arrow. + &::after { + @include dropdown-arrow(); + } + + // Styling button states. + &:focus, + &:hover { + color: $dark-gray-500; + box-shadow: inset 0 0 0 1px $dark-gray-500, inset 0 0 0 2px #fff; + } + } + + // colors-selector - selection status. + .block-library-colors-selector__state-selection { + font-size: 11px; + font-style: normal; + font-family: inherit; + font-weight: 600; + + border-radius: $colors-selector-size / 2; + box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2); + + width: $colors-selector-size; + min-width: $colors-selector-size; + height: $colors-selector-size; + min-height: $colors-selector-size; + line-height: ($colors-selector-size - 2); + + background-color: var(--background-color-menu-link); + color: var(--color-menu-link); + } + + &:not(.has-background-color) .block-library-colors-selector__state-selection { + background-image: linear-gradient(135deg, rgba(0, 0, 0, 0.08) 25%, transparent 25%, transparent 50%, rgba(0, 0, 0, 0.08) 50%, rgba(0, 0, 0, 0.08) 75%, transparent 75%, transparent 100%); + background-size: 12px 12px; + } +} + +// Colors Selector Popover. +$color-control-label-height: 20px; +.block-library-colors-selector__popover { + .color-palette-controller-container { + padding: 16px; + } + + .components-base-control__label { + height: $color-control-label-height; + line-height: $color-control-label-height; + } + + .component-color-indicator { + float: right; + margin-top: 2px; + } +} diff --git a/packages/block-library/src/navigation-menu/index.php b/packages/block-library/src/navigation-menu/index.php index ba6348bd66e1b6..c797a65fdfc10c 100644 --- a/packages/block-library/src/navigation-menu/index.php +++ b/packages/block-library/src/navigation-menu/index.php @@ -5,6 +5,56 @@ * @package gutenberg */ +/** + * Build an array with CSS classes and inline styles defining the colors + * which will be applied to the navigation menu markup in the front-end. + * + * @param array $attributes NavigationMenu block attributes. + * @return array Colors CSS classes and inline styles. + */ +function build_css_colors( $attributes ) { + // CSS classes. + $colors = array( + 'bg_css_classes' => '', + 'bg_inline_styles' => '', + 'text_css_classes' => '', + 'text_inline_styles' => '', + ); + + // Background color. + // Background color - has text color. + if ( array_key_exists( 'backgroundColor', $attributes ) ) { + $colors['bg_css_classes'] .= ' has-background-color'; + } + + // Background color - add custom CSS class. + if ( array_key_exists( 'backgroundColorCSSClass', $attributes ) ) { + $colors['bg_css_classes'] .= " {$attributes['backgroundColorCSSClass']}"; + + } elseif ( array_key_exists( 'customBackgroundColor', $attributes ) ) { + // Background color - or add inline `background-color` style. + $colors['bg_inline_styles'] = ' style="background-color: ' . esc_attr( $attributes['customBackgroundColor'] ) . ';"'; + } + + // Text color. + // Text color - has text color. + if ( array_key_exists( 'textColor', $attributes ) ) { + $colors['text_css_classes'] .= ' has-text-color'; + } + // Text color - add custom CSS class. + if ( array_key_exists( 'textColorCSSClass', $attributes ) ) { + $colors['text_css_classes'] .= " {$attributes['textColorCSSClass']}"; + + } elseif ( array_key_exists( 'customTextColor', $attributes ) ) { + // Text color - or add inline `color` style. + $colors['text_inline_styles'] = ' style="color: ' . esc_attr( $attributes['customTextColor'] ) . ';"'; + } + + $colors['bg_css_classes'] = esc_attr( trim( $colors['bg_css_classes'] ) ); + $colors['text_css_classes'] = esc_attr( trim( $colors['text_css_classes'] ) ); + + return $colors; +} /** * Renders the `core/navigation-menu` block on server. * @@ -15,20 +65,43 @@ * @return string Returns the post content with the legacy widget added. */ function render_block_navigation_menu( $attributes, $content, $block ) { - return ''; + // Inline computed colors. + $comp_inline_styles = ''; + if ( array_key_exists( 'backgroundColorValue', $attributes ) ) { + $comp_inline_styles .= ' background-color: ' . esc_attr( $attributes['backgroundColorValue'] ) . ';'; + } + + if ( array_key_exists( 'textColorValue', $attributes ) ) { + $comp_inline_styles .= ' color: ' . esc_attr( $attributes['textColorValue'] ) . ';'; + } + $comp_inline_styles = ! empty( $comp_inline_styles ) + ? ' style="' . esc_attr( trim( $comp_inline_styles ) ) . '"' + : ''; + + $colors = build_css_colors( $attributes ); + + return "'; } /** * Walks the inner block structure and returns an HTML list for it. * - * @param array $block The block. + * @param array $block The block. + * @param array $colors Contains inline styles and CSS classes to apply to menu item. * * @return string Returns an HTML list from innerBlocks. */ -function build_navigation_menu_html( $block ) { +function build_navigation_menu_html( $block, $colors ) { $html = ''; foreach ( (array) $block['innerBlocks'] as $key => $menu_item ) { - $html .= '
  • ' . + ' 0 ) { - $html .= build_navigation_menu_html( $menu_item ); + $html .= build_navigation_menu_html( $menu_item, $colors ); } $html .= '
  • '; @@ -54,18 +127,57 @@ function build_navigation_menu_html( $block ) { * Register the navigation menu block. * * @uses render_block_navigation_menu() + * @throws WP_Error An WP_Error exception parsing the block definition. */ function register_block_core_navigation_menu() { + register_block_type( 'core/navigation-menu', array( 'category' => 'layout', 'attributes' => array( - 'automaticallyAdd' => array( + 'className' => array( + 'type' => 'string', + ), + + 'automaticallyAdd' => array( 'type' => 'boolean', 'default' => false, ), + + 'backgroundColor' => array( + 'type' => 'string', + ), + + 'textColor' => array( + 'type' => 'string', + ), + + 'backgroundColorValue' => array( + 'type' => 'string', + ), + + 'textColorValue' => array( + 'type' => 'string', + ), + + 'customBackgroundColor' => array( + 'type' => 'string', + ), + + 'customTextColor' => array( + 'type' => 'string', + ), + + 'backgroundColorCSSClass' => array( + 'type' => 'string', + ), + + 'textColorCSSClass' => array( + 'type' => 'string', + ), ), + 'render_callback' => 'render_block_navigation_menu', ) );