From cae2c6744c249df04e0ada7142dbfcfbed926db4 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 8 Apr 2020 13:36:49 +0100 Subject: [PATCH 1/2] Add the possibility to support gradients using the experimental color support flag --- packages/block-editor/README.md | 26 ++++ .../src/components/gradients/index.js | 19 ++- .../block-editor/src/hooks/color-panel.js | 13 +- packages/block-editor/src/hooks/color.js | 142 +++++++++++++++--- packages/block-editor/src/hooks/style.js | 1 + 5 files changed, 170 insertions(+), 31 deletions(-) diff --git a/packages/block-editor/README.md b/packages/block-editor/README.md index af1b5428dcf09a..820137bd973fa8 100644 --- a/packages/block-editor/README.md +++ b/packages/block-editor/README.md @@ -317,6 +317,32 @@ _Returns_ - `Object`: Font size object. +# **getGradientSlugByValue** + +Retrieves the gradient slug per slug. + +_Parameters_ + +- _gradients_ `Array`: Gradient Palette +- _value_ `string`: Gradient value + +_Returns_ + +- `string`: Gradient slug. + +# **getGradientValueBySlug** + +Retrieves the gradient value per slug. + +_Parameters_ + +- _gradients_ `Array`: Gradient Palette +- _slug_ `string`: Gradient slug + +_Returns_ + +- `string`: Gradient value. + # **InnerBlocks** _Related_ diff --git a/packages/block-editor/src/components/gradients/index.js b/packages/block-editor/src/components/gradients/index.js index 988ca37da2cfe3..8e5efdb3b0704e 100644 --- a/packages/block-editor/src/components/gradients/index.js +++ b/packages/block-editor/src/components/gradients/index.js @@ -21,7 +21,15 @@ export function __experimentalGetGradientClass( gradientSlug ) { return `has-${ gradientSlug }-gradient-background`; } -function getGradientValueBySlug( gradients, slug ) { +/** + * Retrieves the gradient value per slug. + * + * @param {Array} gradients Gradient Palette + * @param {string} slug Gradient slug + * + * @return {string} Gradient value. + */ +export function getGradientValueBySlug( gradients, slug ) { const gradient = find( gradients, [ 'slug', slug ] ); return gradient && gradient.gradient; } @@ -34,7 +42,14 @@ export function __experimentalGetGradientObjectByGradientValue( return gradient; } -function getGradientSlugByValue( gradients, value ) { +/** + * Retrieves the gradient slug per slug. + * + * @param {Array} gradients Gradient Palette + * @param {string} value Gradient value + * @return {string} Gradient slug. + */ +export function getGradientSlugByValue( gradients, value ) { const gradient = __experimentalGetGradientObjectByGradientValue( gradients, value diff --git a/packages/block-editor/src/hooks/color-panel.js b/packages/block-editor/src/hooks/color-panel.js index 5a39737f6a6ecc..66545c1b11fb98 100644 --- a/packages/block-editor/src/hooks/color-panel.js +++ b/packages/block-editor/src/hooks/color-panel.js @@ -7,12 +7,12 @@ import { useState, useEffect } from '@wordpress/element'; /** * Internal dependencies */ -import PanelColorSettings from '../components/panel-color-settings'; +import PanelColorGradientSettings from '../components/colors-gradients/panel-color-gradient-settings'; import ContrastChecker from '../components/contrast-checker'; import InspectorControls from '../components/inspector-controls'; import { getBlockDOMNode } from '../utils/dom'; -export default function ColorPanel( { colorSettings, clientId } ) { +export default function ColorPanel( { settings, clientId } ) { const { getComputedStyle, Node } = window; const [ detectedBackgroundColor, setDetectedBackgroundColor ] = useState(); @@ -20,6 +20,9 @@ export default function ColorPanel( { colorSettings, clientId } ) { useEffect( () => { const colorsDetectionElement = getBlockDOMNode( clientId ); + if ( ! colorsDetectionElement ) { + return; + } setDetectedColor( getComputedStyle( colorsDetectionElement ).color ); let backgroundColorNode = colorsDetectionElement; @@ -40,16 +43,16 @@ export default function ColorPanel( { colorSettings, clientId } ) { return ( - - + ); } diff --git a/packages/block-editor/src/hooks/color.js b/packages/block-editor/src/hooks/color.js index 5e6cff33d41b14..6ea9ea958b7cef 100644 --- a/packages/block-editor/src/hooks/color.js +++ b/packages/block-editor/src/hooks/color.js @@ -2,14 +2,16 @@ * External dependencies */ import classnames from 'classnames'; +import { isObject } from 'lodash'; /** * WordPress dependencies */ import { addFilter } from '@wordpress/hooks'; -import { hasBlockSupport } from '@wordpress/blocks'; +import { hasBlockSupport, getBlockSupport } from '@wordpress/blocks'; import { __ } from '@wordpress/i18n'; import { useSelect } from '@wordpress/data'; +import { useRef, useEffect } from '@wordpress/element'; /** * Internal dependencies @@ -19,11 +21,25 @@ import { getColorObjectByColorValue, getColorObjectByAttributeValues, } from '../components/colors'; +import { + __experimentalGetGradientClass, + getGradientValueBySlug, + getGradientSlugByValue, +} from '../components/gradients'; import { cleanEmptyObject } from './utils'; import ColorPanel from './color-panel'; export const COLOR_SUPPORT_KEY = '__experimentalColor'; +const hasColorSupport = ( blockType ) => + hasBlockSupport( blockType, COLOR_SUPPORT_KEY ); + +const hasGradientSupport = ( blockType ) => { + const colorSupport = getBlockSupport( blockType, COLOR_SUPPORT_KEY ); + + return isObject( colorSupport ) && !! colorSupport.gradients; +}; + /** * Filters registered block settings, extending attributes to include * `backgroundColor` and `textColor` attribute. @@ -32,7 +48,7 @@ export const COLOR_SUPPORT_KEY = '__experimentalColor'; * @return {Object} Filtered block settings */ function addAttributes( settings ) { - if ( ! hasBlockSupport( settings, COLOR_SUPPORT_KEY ) ) { + if ( ! hasColorSupport( settings ) ) { return settings; } @@ -52,6 +68,14 @@ function addAttributes( settings ) { } ); } + if ( hasGradientSupport( settings ) && ! settings.attributes.gradient ) { + Object.assign( settings.attributes, { + gradient: { + type: 'string', + }, + } ); + } + return settings; } @@ -64,25 +88,35 @@ function addAttributes( settings ) { * @return {Object} Filtered props applied to save element */ export function addSaveProps( props, blockType, attributes ) { - if ( ! hasBlockSupport( blockType, COLOR_SUPPORT_KEY ) ) { + if ( ! hasColorSupport( blockType ) ) { return props; } + const hasGradient = hasGradientSupport( blockType ); + // I'd have prefered to avoid the "style" attribute usage here - const { backgroundColor, textColor, style } = attributes; + const { backgroundColor, textColor, gradient, style } = attributes; const backgroundClass = getColorClassName( 'background-color', backgroundColor ); + const gradientClass = __experimentalGetGradientClass( gradient ); const textClass = getColorClassName( 'color', textColor ); const newClassName = classnames( props.className, - backgroundClass, textClass, + gradientClass, { + // Don't apply the background class if there's a custom gradient + [ backgroundClass ]: + ( ! hasGradient || ! style?.color?.gradient ) && + !! backgroundClass, 'has-text-color': textColor || style?.color?.text, - 'has-background': backgroundColor || style?.color?.background, + 'has-background': + backgroundColor || + style?.color?.background || + ( hasGradient && ( gradient || style?.color?.gradient ) ), } ); props.className = newClassName ? newClassName : undefined; @@ -98,7 +132,7 @@ export function addSaveProps( props, blockType, attributes ) { * @return {Object} Filtered block settings */ export function addEditProps( settings ) { - if ( ! hasBlockSupport( settings, COLOR_SUPPORT_KEY ) ) { + if ( ! hasColorSupport( settings ) ) { return settings; } const existingGetEditWrapperProps = settings.getEditWrapperProps; @@ -121,43 +155,100 @@ export function addEditProps( settings ) { * @return {WPElement} Color edit element. */ export function ColorEdit( props ) { - const { name: blockName } = props; - const colors = useSelect( ( select ) => { - return select( 'core/block-editor' ).getSettings().colors; + const { name: blockName, attributes } = props; + const { colors, gradients } = useSelect( ( select ) => { + return select( 'core/block-editor' ).getSettings(); }, [] ); + // Shouldn't be needed but right now the ColorGradientsPanel + // can trigger both onChangeColor and onChangeBackground + // synchronously causing our two callbacks to override changes + // from each other. + const localAttributes = useRef( attributes ); + useEffect( () => { + localAttributes.current = attributes; + }, [ attributes ] ); - if ( ! hasBlockSupport( blockName, COLOR_SUPPORT_KEY ) ) { + if ( ! hasColorSupport( blockName ) ) { return null; } - const { style, textColor, backgroundColor } = props.attributes; + + const hasGradient = hasGradientSupport( blockName ); + + const { style, textColor, backgroundColor, gradient } = attributes; + let gradientValue; + if ( hasGradient && gradient ) { + gradientValue = getGradientValueBySlug( gradients, gradient ); + } else if ( hasGradient ) { + gradientValue = style?.color?.gradient; + } const onChangeColor = ( name ) => ( value ) => { const colorObject = getColorObjectByColorValue( colors, value ); const attributeName = name + 'Color'; const newStyle = { - ...style, + ...localAttributes.current.style, color: { - ...style?.color, + ...localAttributes.current?.style?.color, [ name ]: colorObject?.slug ? undefined : value, }, }; + const newNamedColor = colorObject?.slug ? colorObject.slug : undefined; - props.setAttributes( { + const newAttributes = { style: cleanEmptyObject( newStyle ), [ attributeName ]: newNamedColor, - } ); + }; + + props.setAttributes( newAttributes ); + localAttributes.current = { + ...localAttributes.current, + ...newAttributes, + }; + }; + + const onChangeGradient = ( value ) => { + const slug = getGradientSlugByValue( gradients, value ); + let newAttributes; + if ( slug ) { + const newStyle = { + ...localAttributes.current?.style, + color: { + ...localAttributes.current?.style?.color, + gradient: undefined, + }, + }; + newAttributes = { + style: cleanEmptyObject( newStyle ), + gradient: slug, + }; + } else { + const newStyle = { + ...localAttributes.current?.style, + color: { + ...localAttributes.current?.style?.color, + gradient: value, + }, + }; + newAttributes = { + style: cleanEmptyObject( newStyle ), + gradient: undefined, + }; + } + props.setAttributes( newAttributes ); + localAttributes.current = { + ...localAttributes.current, + ...newAttributes, + }; }; return ( diff --git a/packages/block-editor/src/hooks/style.js b/packages/block-editor/src/hooks/style.js index c4639da55fb8b2..8858982f456c52 100644 --- a/packages/block-editor/src/hooks/style.js +++ b/packages/block-editor/src/hooks/style.js @@ -44,6 +44,7 @@ export function getInlineStyles( styles = {} ) { const mappings = { lineHeight: [ 'typography', 'lineHeight' ], fontSize: [ 'typography', 'fontSize' ], + background: [ 'color', 'gradient' ], backgroundColor: [ 'color', 'background' ], color: [ 'color', 'text' ], }; From 8d0231eff99e2385e35fc293cc651974ebb4ec19 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 8 Apr 2020 13:46:38 +0100 Subject: [PATCH 2/2] Disable contrast checking when gradients are applied --- .../block-editor/src/hooks/color-panel.js | 20 ++++++++++++++----- packages/block-editor/src/hooks/color.js | 1 + 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/block-editor/src/hooks/color-panel.js b/packages/block-editor/src/hooks/color-panel.js index 66545c1b11fb98..553a59eca0c3e2 100644 --- a/packages/block-editor/src/hooks/color-panel.js +++ b/packages/block-editor/src/hooks/color-panel.js @@ -12,13 +12,21 @@ import ContrastChecker from '../components/contrast-checker'; import InspectorControls from '../components/inspector-controls'; import { getBlockDOMNode } from '../utils/dom'; -export default function ColorPanel( { settings, clientId } ) { +export default function ColorPanel( { + settings, + clientId, + enableContrastChecking = true, +} ) { const { getComputedStyle, Node } = window; const [ detectedBackgroundColor, setDetectedBackgroundColor ] = useState(); const [ detectedColor, setDetectedColor ] = useState(); useEffect( () => { + if ( ! enableContrastChecking ) { + return; + } + const colorsDetectionElement = getBlockDOMNode( clientId ); if ( ! colorsDetectionElement ) { return; @@ -48,10 +56,12 @@ export default function ColorPanel( { settings, clientId } ) { initialOpen={ false } settings={ settings } > - + { enableContrastChecking && ( + + ) } ); diff --git a/packages/block-editor/src/hooks/color.js b/packages/block-editor/src/hooks/color.js index 6ea9ea958b7cef..c196a521b39061 100644 --- a/packages/block-editor/src/hooks/color.js +++ b/packages/block-editor/src/hooks/color.js @@ -243,6 +243,7 @@ export function ColorEdit( props ) { return (