From 652a37d0706ec8c0c735ce72471cf95ff25c883b Mon Sep 17 00:00:00 2001 From: epiqueras Date: Fri, 26 Jul 2019 18:03:48 -0500 Subject: [PATCH 01/15] Block Editor: Implement new colors hook. --- packages/block-editor/README.md | 8 ++ .../src/components/block-edit/context.js | 8 +- .../src/components/block-edit/index.js | 11 ++- .../src/components/colors/index.js | 1 + .../src/components/colors/use-colors.js | 96 +++++++++++++++++++ packages/block-editor/src/components/index.js | 2 +- 6 files changed, 118 insertions(+), 8 deletions(-) create mode 100644 packages/block-editor/src/components/colors/use-colors.js diff --git a/packages/block-editor/README.md b/packages/block-editor/README.md index d9c7818065c0b5..d34ad2d3f87774 100644 --- a/packages/block-editor/README.md +++ b/packages/block-editor/README.md @@ -446,6 +446,14 @@ _Related_ - +# **useBlockEditContext** + +Undocumented declaration. + +# **useColors** + +Undocumented declaration. + # **Warning** Undocumented declaration. diff --git a/packages/block-editor/src/components/block-edit/context.js b/packages/block-editor/src/components/block-edit/context.js index 863cdc3e5d6fa5..3deee618231aa1 100644 --- a/packages/block-editor/src/components/block-edit/context.js +++ b/packages/block-editor/src/components/block-edit/context.js @@ -6,18 +6,22 @@ import { noop } from 'lodash'; /** * WordPress dependencies */ -import { createContext } from '@wordpress/element'; +import { createContext, useContext } from '@wordpress/element'; import { createHigherOrderComponent } from '@wordpress/compose'; -const { Consumer, Provider } = createContext( { +const Context = createContext( { name: '', isSelected: false, focusedElement: null, setFocusedElement: noop, clientId: null, } ); +const { Provider, Consumer } = Context; export { Provider as BlockEditContextProvider }; +export function useBlockEditContext() { + return useContext( Context ); +} /** * A Higher Order Component used to inject BlockEdit context to the diff --git a/packages/block-editor/src/components/block-edit/index.js b/packages/block-editor/src/components/block-edit/index.js index 63c475a50692ff..569864646094d6 100644 --- a/packages/block-editor/src/components/block-edit/index.js +++ b/packages/block-editor/src/components/block-edit/index.js @@ -12,7 +12,7 @@ import { Component } from '@wordpress/element'; * Internal dependencies */ import Edit from './edit'; -import { BlockEditContextProvider } from './context'; +import { BlockEditContextProvider, useBlockEditContext } from './context'; class BlockEdit extends Component { constructor() { @@ -27,13 +27,13 @@ class BlockEdit extends Component { ); } - propsToContext( name, isSelected, clientId, onFocus, onCaretVerticalPositionChange ) { - return { name, isSelected, clientId, onFocus, onCaretVerticalPositionChange }; + propsToContext( name, isSelected, clientId, onFocus, onCaretVerticalPositionChange, attributes, setAttributes ) { + return { name, isSelected, clientId, onFocus, onCaretVerticalPositionChange, attributes, setAttributes }; } render() { - const { name, isSelected, clientId, onFocus, onCaretVerticalPositionChange } = this.props; - const value = this.propsToContext( name, isSelected, clientId, onFocus, onCaretVerticalPositionChange ); + const { name, isSelected, clientId, onFocus, onCaretVerticalPositionChange, attributes, setAttributes } = this.props; + const value = this.propsToContext( name, isSelected, clientId, onFocus, onCaretVerticalPositionChange, attributes, setAttributes ); return ( @@ -44,3 +44,4 @@ class BlockEdit extends Component { } export default BlockEdit; +export { useBlockEditContext }; diff --git a/packages/block-editor/src/components/colors/index.js b/packages/block-editor/src/components/colors/index.js index f6b6fac984db89..d8f46230fd55ad 100644 --- a/packages/block-editor/src/components/colors/index.js +++ b/packages/block-editor/src/components/colors/index.js @@ -7,3 +7,4 @@ export { createCustomColorsHOC, default as withColors, } from './with-colors'; +export { default as useColors } from './use-colors'; diff --git a/packages/block-editor/src/components/colors/use-colors.js b/packages/block-editor/src/components/colors/use-colors.js new file mode 100644 index 00000000000000..a41016e8943999 --- /dev/null +++ b/packages/block-editor/src/components/colors/use-colors.js @@ -0,0 +1,96 @@ +/** + * External dependencies + */ +import memoize from 'memize'; +import { startCase } from 'lodash'; + +/** + * WordPress dependencies + */ +import { Children, cloneElement, useMemo } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import InspectorControls from '../inspector-controls'; +import PanelColorSettings from '../panel-color-settings'; +import { useBlockEditContext } from '../block-edit'; + +const createComponent = memoize( ( attribute, color ) => ( { children } ) => + // Clone children, setting the style attribute from the color configuration, + // if not already set explicitly through props. + Children.map( children, ( child ) => + cloneElement( child, { + style: { [ attribute ]: color, ...child.props.style }, + } ) + ) +); + +const createSetColor = memoize( ( setAttributes, name ) => ( newColor ) => + setAttributes( { [ name ]: newColor } ) +); + +const InspectorControlsColorPanel = ( { title, colorSettings } ) => ( + + + +); + +export default function useColors( + colorConfigs, + deps = [], + panelTitle = __( 'Color Settings' ) +) { + const { attributes, setAttributes } = useBlockEditContext(); + + return useMemo( () => { + const colorSettings = []; + + const components = colorConfigs.reduce( ( acc, colorConfig ) => { + if ( typeof colorConfig === 'string' ) { + colorConfig = { name: colorConfig }; + } + const { + name, // E.g. 'backgroundColor'. + attribute = name, // E.g. 'backgroundColor'. + + panelLabel = startCase( name ), // E.g. 'Background Color'. + componentName = panelLabel.replace( /\s/g, '' ), // E.g. 'BackgroundColor'. + + color = colorConfig.color, + } = { + ...colorConfig, + color: attributes[ colorConfig.name ], + }; + + // We memoize the non-primitives to avoid unnecessary updates + // when they are used as props for other components. + acc[ componentName ] = createComponent( attribute, color ); + acc[ componentName ].color = color; + acc[ componentName ].setColor = createSetColor( setAttributes, name ); + + colorSettings.push( { + value: color, + onChange: acc[ componentName ].setColor, + label: panelLabel, + } ); + + return acc; + }, {} ); + + return { + ...components, + InspectorControlsColorPanel: ( + + ), + }; + }, [ attributes, setAttributes, ...deps ] ); +} diff --git a/packages/block-editor/src/components/index.js b/packages/block-editor/src/components/index.js index 6e9bb592378678..09fbb2d9a18588 100644 --- a/packages/block-editor/src/components/index.js +++ b/packages/block-editor/src/components/index.js @@ -8,7 +8,7 @@ export { default as AlignmentToolbar } from './alignment-toolbar'; export { default as Autocomplete } from './autocomplete'; export { default as BlockAlignmentToolbar } from './block-alignment-toolbar'; export { default as BlockControls } from './block-controls'; -export { default as BlockEdit } from './block-edit'; +export { default as BlockEdit, useBlockEditContext } from './block-edit'; export { default as BlockFormatControls } from './block-format-controls'; export { default as BlockIcon } from './block-icon'; export { default as BlockNavigationDropdown } from './block-navigation/dropdown'; From 5c10afedfba4eed0efb5f0d9fc9562aa4b6b4baa Mon Sep 17 00:00:00 2001 From: epiqueras Date: Fri, 26 Jul 2019 18:07:33 -0500 Subject: [PATCH 02/15] Block Library: Swap usage of the colors HOC with the colors hook in the heading edit component. --- packages/block-library/src/heading/edit.js | 91 +++++++--------------- 1 file changed, 30 insertions(+), 61 deletions(-) diff --git a/packages/block-library/src/heading/edit.js b/packages/block-library/src/heading/edit.js index d500309a0c9aad..885169f64f8919 100644 --- a/packages/block-library/src/heading/edit.js +++ b/packages/block-library/src/heading/edit.js @@ -13,38 +13,14 @@ import HeadingToolbar from './heading-toolbar'; */ import { __ } from '@wordpress/i18n'; import { PanelBody } from '@wordpress/components'; -import { compose } from '@wordpress/compose'; import { createBlock } from '@wordpress/blocks'; import { AlignmentToolbar, BlockControls, InspectorControls, RichText, - withColors, - PanelColorSettings, + useColors, } from '@wordpress/block-editor'; -import { memo } from '@wordpress/element'; - -const HeadingColorUI = memo( - function( { - textColorValue, - setTextColor, - } ) { - return ( - - ); - } -); function HeadingEdit( { attributes, @@ -52,9 +28,9 @@ function HeadingEdit( { mergeBlocks, onReplace, className, - textColor, - setTextColor, } ) { + const { TextColor, InspectorControlsColorPanel } = useColors( [ { name: 'textColor', attribute: 'color' } ], [] ); + const { align, content, level, placeholder } = attributes; const tagName = 'h' + level; @@ -71,43 +47,36 @@ function HeadingEdit( {

{ __( 'Level' ) }

setAttributes( { level: newLevel } ) } /> - - setAttributes( { content: value } ) } - onMerge={ mergeBlocks } - onSplit={ ( value ) => { - if ( ! value ) { - return createBlock( 'core/paragraph' ); - } + { InspectorControlsColorPanel } + + setAttributes( { content: value } ) } + onMerge={ mergeBlocks } + onSplit={ ( value ) => { + if ( ! value ) { + return createBlock( 'core/paragraph' ); + } - return createBlock( 'core/heading', { - ...attributes, - content: value, - } ); - } } - onReplace={ onReplace } - onRemove={ () => onReplace( [] ) } - className={ classnames( className, { - [ `has-text-align-${ align }` ]: align, - 'has-text-color': textColor.color, - [ textColor.class ]: textColor.class, - } ) } - placeholder={ placeholder || __( 'Write heading…' ) } - style={ { - color: textColor.color, - } } - /> + return createBlock( 'core/heading', { + ...attributes, + content: value, + } ); + } } + onReplace={ onReplace } + onRemove={ () => onReplace( [] ) } + className={ classnames( className, { + [ `has-text-align-${ align }` ]: align, + 'has-text-color': TextColor.color, + } ) } + placeholder={ placeholder || __( 'Write heading…' ) } + /> + ); } -export default compose( [ - withColors( 'backgroundColor', { textColor: 'color' } ), -] )( HeadingEdit ); +export default HeadingEdit; From ead8a389a67620cf3a5af673b7779513e2e96964 Mon Sep 17 00:00:00 2001 From: epiqueras Date: Mon, 29 Jul 2019 11:23:03 -0400 Subject: [PATCH 03/15] Use Colors: Add 'has-x-color' class names. --- packages/block-editor/src/components/colors/use-colors.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/colors/use-colors.js b/packages/block-editor/src/components/colors/use-colors.js index a41016e8943999..2e5076de2a95d1 100644 --- a/packages/block-editor/src/components/colors/use-colors.js +++ b/packages/block-editor/src/components/colors/use-colors.js @@ -2,7 +2,7 @@ * External dependencies */ import memoize from 'memize'; -import { startCase } from 'lodash'; +import { kebabCase, startCase } from 'lodash'; /** * WordPress dependencies @@ -22,6 +22,9 @@ const createComponent = memoize( ( attribute, color ) => ( { children } ) => // if not already set explicitly through props. Children.map( children, ( child ) => cloneElement( child, { + className: color ? + `${ child.props.className } has-${ kebabCase( attribute ) }` : + child.props.className, style: { [ attribute ]: color, ...child.props.style }, } ) ) From 7809eaf4b4b4270f009da6df3f5c5a7007d6a914 Mon Sep 17 00:00:00 2001 From: epiqueras Date: Mon, 29 Jul 2019 11:41:41 -0400 Subject: [PATCH 04/15] Use Colors: Avoid memory leaks by making caches limited in size, and tied to hook instances. --- .../src/components/colors/use-colors.js | 47 +++++++++++-------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/packages/block-editor/src/components/colors/use-colors.js b/packages/block-editor/src/components/colors/use-colors.js index 2e5076de2a95d1..d16a5b66f5d680 100644 --- a/packages/block-editor/src/components/colors/use-colors.js +++ b/packages/block-editor/src/components/colors/use-colors.js @@ -7,8 +7,8 @@ import { kebabCase, startCase } from 'lodash'; /** * WordPress dependencies */ -import { Children, cloneElement, useMemo } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; +import { useMemo, Children, cloneElement } from '@wordpress/element'; /** * Internal dependencies @@ -17,23 +17,6 @@ import InspectorControls from '../inspector-controls'; import PanelColorSettings from '../panel-color-settings'; import { useBlockEditContext } from '../block-edit'; -const createComponent = memoize( ( attribute, color ) => ( { children } ) => - // Clone children, setting the style attribute from the color configuration, - // if not already set explicitly through props. - Children.map( children, ( child ) => - cloneElement( child, { - className: color ? - `${ child.props.className } has-${ kebabCase( attribute ) }` : - child.props.className, - style: { [ attribute ]: color, ...child.props.style }, - } ) - ) -); - -const createSetColor = memoize( ( setAttributes, name ) => ( newColor ) => - setAttributes( { [ name ]: newColor } ) -); - const InspectorControlsColorPanel = ( { title, colorSettings } ) => ( + memoize( + ( attribute, color ) => ( { children } ) => + // Clone children, setting the style attribute from the color configuration, + // if not already set explicitly through props. + Children.map( children, ( child ) => + cloneElement( child, { + className: color ? + `${ child.props.className } has-${ kebabCase( attribute ) }` : + child.props.className, + style: { [ attribute ]: color, ...child.props.style }, + } ) + ), + { maxSize: colorConfigs.length } + ), + [ colorConfigs.length ] + ); + const createSetColor = useMemo( + () => + memoize( ( name ) => ( newColor ) => setAttributes( { [ name ]: newColor } ), { + maxSize: colorConfigs.length, + } ), + [ setAttributes, colorConfigs.length ] + ); + return useMemo( () => { const colorSettings = []; @@ -75,7 +84,7 @@ export default function useColors( // when they are used as props for other components. acc[ componentName ] = createComponent( attribute, color ); acc[ componentName ].color = color; - acc[ componentName ].setColor = createSetColor( setAttributes, name ); + acc[ componentName ].setColor = createSetColor( name ); colorSettings.push( { value: color, From ee203c8a5f2077188e66dd21dcd859d5b3dd7338 Mon Sep 17 00:00:00 2001 From: epiqueras Date: Mon, 29 Jul 2019 12:21:33 -0400 Subject: [PATCH 05/15] Use Colors: Support children and optional contrast checking in the color panel. --- .../src/components/colors/use-colors.js | 33 ++++++++++++++++--- packages/block-library/src/heading/edit.js | 8 ++++- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/packages/block-editor/src/components/colors/use-colors.js b/packages/block-editor/src/components/colors/use-colors.js index d16a5b66f5d680..78632114be6bd0 100644 --- a/packages/block-editor/src/components/colors/use-colors.js +++ b/packages/block-editor/src/components/colors/use-colors.js @@ -15,22 +15,43 @@ import { useMemo, Children, cloneElement } from '@wordpress/element'; */ import InspectorControls from '../inspector-controls'; import PanelColorSettings from '../panel-color-settings'; +import ContrastChecker from '../contrast-checker'; import { useBlockEditContext } from '../block-edit'; -const InspectorControlsColorPanel = ( { title, colorSettings } ) => ( +const InspectorControlsColorPanel = ( { + title, + colorSettings, + contrastCheckerProps, + components, + panelChildren, +} ) => ( + > + { contrastCheckerProps && + components.map( ( Component ) => ( + + ) ) } + { typeof panelChildren === 'function' ? + panelChildren( components ) : + panelChildren } + ); export default function useColors( colorConfigs, - deps = [], - panelTitle = __( 'Color Settings' ) + { panelTitle = __( 'Color Settings' ), contrastCheckerProps, panelChildren } = { + panelTitle: __( 'Color Settings' ), + }, + deps = [] ) { const { attributes, setAttributes } = useBlockEditContext(); @@ -83,6 +104,7 @@ export default function useColors( // We memoize the non-primitives to avoid unnecessary updates // when they are used as props for other components. acc[ componentName ] = createComponent( attribute, color ); + acc[ componentName ].displayName = componentName; acc[ componentName ].color = color; acc[ componentName ].setColor = createSetColor( name ); @@ -101,6 +123,9 @@ export default function useColors( ), }; diff --git a/packages/block-library/src/heading/edit.js b/packages/block-library/src/heading/edit.js index 885169f64f8919..5dbce739987fba 100644 --- a/packages/block-library/src/heading/edit.js +++ b/packages/block-library/src/heading/edit.js @@ -29,7 +29,13 @@ function HeadingEdit( { onReplace, className, } ) { - const { TextColor, InspectorControlsColorPanel } = useColors( [ { name: 'textColor', attribute: 'color' } ], [] ); + const { TextColor, InspectorControlsColorPanel } = useColors( + [ { name: 'textColor', attribute: 'color' } ], + { + contrastCheckerProps: { backgroundColor: 'white', isLargeText: true }, + }, + [] + ); const { align, content, level, placeholder } = attributes; const tagName = 'h' + level; From 3316f3be4c0354f92a4ad3eea932ae00ccd87d8a Mon Sep 17 00:00:00 2001 From: epiqueras Date: Mon, 29 Jul 2019 12:31:40 -0400 Subject: [PATCH 06/15] Use Colors: Expose colors panel without inspector slot/fill wrapper. --- .../src/components/colors/use-colors.js | 57 ++++++++++--------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/packages/block-editor/src/components/colors/use-colors.js b/packages/block-editor/src/components/colors/use-colors.js index 78632114be6bd0..56375e102ce818 100644 --- a/packages/block-editor/src/components/colors/use-colors.js +++ b/packages/block-editor/src/components/colors/use-colors.js @@ -13,36 +13,39 @@ import { useMemo, Children, cloneElement } from '@wordpress/element'; /** * Internal dependencies */ -import InspectorControls from '../inspector-controls'; import PanelColorSettings from '../panel-color-settings'; import ContrastChecker from '../contrast-checker'; +import InspectorControls from '../inspector-controls'; import { useBlockEditContext } from '../block-edit'; -const InspectorControlsColorPanel = ( { +const ColorPanel = ( { title, colorSettings, contrastCheckerProps, components, panelChildren, } ) => ( + + { contrastCheckerProps && + components.map( ( Component ) => ( + + ) ) } + { typeof panelChildren === 'function' ? + panelChildren( components ) : + panelChildren } + +); +const InspectorControlsColorPanel = ( props ) => ( - - { contrastCheckerProps && - components.map( ( Component ) => ( - - ) ) } - { typeof panelChildren === 'function' ? - panelChildren( components ) : - panelChildren } - + ); @@ -117,16 +120,18 @@ export default function useColors( return acc; }, {} ); + const colorPanelProps = { + title: panelTitle, + colorSettings, + contrastCheckerProps, + components: Object.values( components ), + panelChildren, + }; return { ...components, + ColorPanel: , InspectorControlsColorPanel: ( - + ), }; }, [ attributes, setAttributes, ...deps ] ); From 9dcbb9f7674ab6ae106bb4bf59944d81b8ac961f Mon Sep 17 00:00:00 2001 From: epiqueras Date: Mon, 29 Jul 2019 12:46:36 -0400 Subject: [PATCH 07/15] Use Colors: Mark hook as experimental. --- packages/block-editor/README.md | 4 ---- packages/block-editor/src/components/colors/index.js | 2 +- packages/block-editor/src/components/colors/use-colors.js | 2 +- packages/block-library/src/heading/edit.js | 4 ++-- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/block-editor/README.md b/packages/block-editor/README.md index d34ad2d3f87774..002e45eafb2a49 100644 --- a/packages/block-editor/README.md +++ b/packages/block-editor/README.md @@ -450,10 +450,6 @@ _Related_ Undocumented declaration. -# **useColors** - -Undocumented declaration. - # **Warning** Undocumented declaration. diff --git a/packages/block-editor/src/components/colors/index.js b/packages/block-editor/src/components/colors/index.js index d8f46230fd55ad..cadb34a8c9aa37 100644 --- a/packages/block-editor/src/components/colors/index.js +++ b/packages/block-editor/src/components/colors/index.js @@ -7,4 +7,4 @@ export { createCustomColorsHOC, default as withColors, } from './with-colors'; -export { default as useColors } from './use-colors'; +export { default as __experimentalUseColors } from './use-colors'; diff --git a/packages/block-editor/src/components/colors/use-colors.js b/packages/block-editor/src/components/colors/use-colors.js index 56375e102ce818..a1013209f045fc 100644 --- a/packages/block-editor/src/components/colors/use-colors.js +++ b/packages/block-editor/src/components/colors/use-colors.js @@ -49,7 +49,7 @@ const InspectorControlsColorPanel = ( props ) => ( ); -export default function useColors( +export default function __experimentalUseColors( colorConfigs, { panelTitle = __( 'Color Settings' ), contrastCheckerProps, panelChildren } = { panelTitle: __( 'Color Settings' ), diff --git a/packages/block-library/src/heading/edit.js b/packages/block-library/src/heading/edit.js index 5dbce739987fba..85e7c55a2e8437 100644 --- a/packages/block-library/src/heading/edit.js +++ b/packages/block-library/src/heading/edit.js @@ -19,7 +19,7 @@ import { BlockControls, InspectorControls, RichText, - useColors, + __experimentalUseColors, } from '@wordpress/block-editor'; function HeadingEdit( { @@ -29,7 +29,7 @@ function HeadingEdit( { onReplace, className, } ) { - const { TextColor, InspectorControlsColorPanel } = useColors( + const { TextColor, InspectorControlsColorPanel } = __experimentalUseColors( [ { name: 'textColor', attribute: 'color' } ], { contrastCheckerProps: { backgroundColor: 'white', isLargeText: true }, From 86efb0111ec3f81189ff886263c37138a12a578c Mon Sep 17 00:00:00 2001 From: epiqueras Date: Mon, 29 Jul 2019 13:36:33 -0400 Subject: [PATCH 08/15] Use Colors: Support custom colors. --- .../src/components/colors/use-colors.js | 36 ++++++++++++++----- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/packages/block-editor/src/components/colors/use-colors.js b/packages/block-editor/src/components/colors/use-colors.js index a1013209f045fc..948499375497a9 100644 --- a/packages/block-editor/src/components/colors/use-colors.js +++ b/packages/block-editor/src/components/colors/use-colors.js @@ -21,6 +21,7 @@ import { useBlockEditContext } from '../block-edit'; const ColorPanel = ( { title, colorSettings, + colorPanelProps, contrastCheckerProps, components, panelChildren, @@ -29,6 +30,7 @@ const ColorPanel = ( { title={ title } initialOpen={ false } colorSettings={ colorSettings } + { ...colorPanelProps } > { contrastCheckerProps && components.map( ( Component ) => ( @@ -51,7 +53,12 @@ const InspectorControlsColorPanel = ( props ) => ( export default function __experimentalUseColors( colorConfigs, - { panelTitle = __( 'Color Settings' ), contrastCheckerProps, panelChildren } = { + { + panelTitle = __( 'Color Settings' ), + colorPanelProps, + contrastCheckerProps, + panelChildren, + } = { panelTitle: __( 'Color Settings' ), }, deps = [] @@ -99,6 +106,7 @@ export default function __experimentalUseColors( componentName = panelLabel.replace( /\s/g, '' ), // E.g. 'BackgroundColor'. color = colorConfig.color, + colors, } = { ...colorConfig, color: attributes[ colorConfig.name ], @@ -111,27 +119,37 @@ export default function __experimentalUseColors( acc[ componentName ].color = color; acc[ componentName ].setColor = createSetColor( name ); - colorSettings.push( { - value: color, - onChange: acc[ componentName ].setColor, - label: panelLabel, - } ); + const newSettingIndex = + colorSettings.push( { + value: color, + onChange: acc[ componentName ].setColor, + label: panelLabel, + colors, + } ) - 1; + // These settings will be spread over the `colors` in + // `colorPanelProps`, so we need to unset the key here, + // if not set to an actual value, to avoid overwriting + // an actual value in `colorPanelProps`. + if ( ! colors ) { + delete colorSettings[ newSettingIndex ].colors; + } return acc; }, {} ); - const colorPanelProps = { + const wrappedColorPanelProps = { title: panelTitle, colorSettings, + colorPanelProps, contrastCheckerProps, components: Object.values( components ), panelChildren, }; return { ...components, - ColorPanel: , + ColorPanel: , InspectorControlsColorPanel: ( - + ), }; }, [ attributes, setAttributes, ...deps ] ); From 69865ddd252be9ea9c853174dbdc48ddf7b88c21 Mon Sep 17 00:00:00 2001 From: epiqueras Date: Mon, 21 Oct 2019 13:05:14 -0700 Subject: [PATCH 09/15] Block Edit: Remove extra context values and use selectors/actions instead. --- .../src/components/block-edit/index.js | 8 ++++---- .../src/components/colors/use-colors.js | 19 +++++++++++++++++-- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/packages/block-editor/src/components/block-edit/index.js b/packages/block-editor/src/components/block-edit/index.js index 569864646094d6..403a5cd87898e3 100644 --- a/packages/block-editor/src/components/block-edit/index.js +++ b/packages/block-editor/src/components/block-edit/index.js @@ -27,13 +27,13 @@ class BlockEdit extends Component { ); } - propsToContext( name, isSelected, clientId, onFocus, onCaretVerticalPositionChange, attributes, setAttributes ) { - return { name, isSelected, clientId, onFocus, onCaretVerticalPositionChange, attributes, setAttributes }; + propsToContext( name, isSelected, clientId, onFocus, onCaretVerticalPositionChange ) { + return { name, isSelected, clientId, onFocus, onCaretVerticalPositionChange }; } render() { - const { name, isSelected, clientId, onFocus, onCaretVerticalPositionChange, attributes, setAttributes } = this.props; - const value = this.propsToContext( name, isSelected, clientId, onFocus, onCaretVerticalPositionChange, attributes, setAttributes ); + const { name, isSelected, clientId, onFocus, onCaretVerticalPositionChange } = this.props; + const value = this.propsToContext( name, isSelected, clientId, onFocus, onCaretVerticalPositionChange ); return ( diff --git a/packages/block-editor/src/components/colors/use-colors.js b/packages/block-editor/src/components/colors/use-colors.js index 948499375497a9..76db7e2cc7703e 100644 --- a/packages/block-editor/src/components/colors/use-colors.js +++ b/packages/block-editor/src/components/colors/use-colors.js @@ -8,7 +8,13 @@ import { kebabCase, startCase } from 'lodash'; * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { useMemo, Children, cloneElement } from '@wordpress/element'; +import { useSelect, useDispatch } from '@wordpress/data'; +import { + useCallback, + useMemo, + Children, + cloneElement, +} from '@wordpress/element'; /** * Internal dependencies @@ -63,7 +69,16 @@ export default function __experimentalUseColors( }, deps = [] ) { - const { attributes, setAttributes } = useBlockEditContext(); + const { clientId } = useBlockEditContext(); + const attributes = useSelect( + ( select ) => select( 'core/block-editor' ).getBlockAttributes( clientId ), + [ clientId ] + ); + const { updateBlockAttributes } = useDispatch( 'core/block-editor' ); + const setAttributes = useCallback( + ( newAttributes ) => updateBlockAttributes( clientId, newAttributes ), + [ updateBlockAttributes, clientId ] + ); const createComponent = useMemo( () => From b3d600eb433bada926ab0871b56c2e3ef57f3c6f Mon Sep 17 00:00:00 2001 From: epiqueras Date: Tue, 22 Oct 2019 11:57:35 -0700 Subject: [PATCH 10/15] Heading: Remove unnecessary color class and set text color on save. --- packages/block-library/src/heading/edit.js | 1 - packages/block-library/src/heading/save.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/block-library/src/heading/edit.js b/packages/block-library/src/heading/edit.js index 85e7c55a2e8437..611eca7879c733 100644 --- a/packages/block-library/src/heading/edit.js +++ b/packages/block-library/src/heading/edit.js @@ -76,7 +76,6 @@ function HeadingEdit( { onRemove={ () => onReplace( [] ) } className={ classnames( className, { [ `has-text-align-${ align }` ]: align, - 'has-text-color': TextColor.color, } ) } placeholder={ placeholder || __( 'Write heading…' ) } /> diff --git a/packages/block-library/src/heading/save.js b/packages/block-library/src/heading/save.js index e8ace3129a6edc..82bfda56b3af49 100644 --- a/packages/block-library/src/heading/save.js +++ b/packages/block-library/src/heading/save.js @@ -34,7 +34,7 @@ export default function save( { attributes } ) { className={ className ? className : undefined } tagName={ tagName } style={ { - color: textClass ? undefined : customTextColor, + color: textColor, } } value={ content } /> From 81c60f0ac0eef907826df326bc56a416d943cffd Mon Sep 17 00:00:00 2001 From: epiqueras Date: Tue, 22 Oct 2019 17:09:11 -0700 Subject: [PATCH 11/15] Use Colors: Add custom/preset color logic. --- .../src/components/colors/use-colors.js | 70 ++++++++++++++----- packages/block-library/src/heading/save.js | 2 +- 2 files changed, 53 insertions(+), 19 deletions(-) diff --git a/packages/block-editor/src/components/colors/use-colors.js b/packages/block-editor/src/components/colors/use-colors.js index 76db7e2cc7703e..f3e80c5993d6d9 100644 --- a/packages/block-editor/src/components/colors/use-colors.js +++ b/packages/block-editor/src/components/colors/use-colors.js @@ -2,7 +2,7 @@ * External dependencies */ import memoize from 'memize'; -import { kebabCase, startCase } from 'lodash'; +import { kebabCase, camelCase, startCase } from 'lodash'; /** * WordPress dependencies @@ -70,8 +70,14 @@ export default function __experimentalUseColors( deps = [] ) { const { clientId } = useBlockEditContext(); - const attributes = useSelect( - ( select ) => select( 'core/block-editor' ).getBlockAttributes( clientId ), + const { attributes, settingsColors } = useSelect( + ( select ) => { + const { getBlockAttributes, getSettings } = select( 'core/block-editor' ); + return { + attributes: getBlockAttributes( clientId ), + settingsColors: getSettings().colors, + }; + }, [ clientId ] ); const { updateBlockAttributes } = useDispatch( 'core/block-editor' ); @@ -83,26 +89,48 @@ export default function __experimentalUseColors( const createComponent = useMemo( () => memoize( - ( attribute, color ) => ( { children } ) => + ( attribute, color, colorValue, customColor ) => ( { children } ) => // Clone children, setting the style attribute from the color configuration, // if not already set explicitly through props. - Children.map( children, ( child ) => - cloneElement( child, { - className: color ? - `${ child.props.className } has-${ kebabCase( attribute ) }` : - child.props.className, - style: { [ attribute ]: color, ...child.props.style }, - } ) - ), + Children.map( children, ( child ) => { + let className = child.props.className; + let style = child.props.style; + if ( color ) { + className = `${ child.props.className } has-${ kebabCase( + color + ) }-${ kebabCase( attribute ) }`; + style = { [ attribute ]: colorValue, ...child.props.style }; + } else if ( customColor ) { + className = `${ child.props.className } has-${ kebabCase( attribute ) }`; + style = { [ attribute ]: customColor, ...child.props.style }; + } + return cloneElement( child, { + className, + style, + } ); + } ), { maxSize: colorConfigs.length } ), [ colorConfigs.length ] ); const createSetColor = useMemo( () => - memoize( ( name ) => ( newColor ) => setAttributes( { [ name ]: newColor } ), { - maxSize: colorConfigs.length, - } ), + memoize( + ( name, colors ) => ( newColor ) => { + const color = colors.find( ( _color ) => _color.color === newColor ); + setAttributes( { + [ color ? camelCase( `custom ${ name }` ) : name ]: undefined, + } ); + setAttributes( { + [ color ? name : camelCase( `custom ${ name }` ) ]: color ? + color.slug : + newColor, + } ); + }, + { + maxSize: colorConfigs.length, + } + ), [ setAttributes, colorConfigs.length ] ); @@ -121,7 +149,7 @@ export default function __experimentalUseColors( componentName = panelLabel.replace( /\s/g, '' ), // E.g. 'BackgroundColor'. color = colorConfig.color, - colors, + colors = settingsColors, } = { ...colorConfig, color: attributes[ colorConfig.name ], @@ -129,10 +157,16 @@ export default function __experimentalUseColors( // We memoize the non-primitives to avoid unnecessary updates // when they are used as props for other components. - acc[ componentName ] = createComponent( attribute, color ); + const _color = colors.find( ( __color ) => __color.slug === color ); + acc[ componentName ] = createComponent( + attribute, + color, + _color && _color.color, + attributes[ camelCase( `custom ${ name }` ) ] + ); acc[ componentName ].displayName = componentName; acc[ componentName ].color = color; - acc[ componentName ].setColor = createSetColor( name ); + acc[ componentName ].setColor = createSetColor( name, colors ); const newSettingIndex = colorSettings.push( { diff --git a/packages/block-library/src/heading/save.js b/packages/block-library/src/heading/save.js index 82bfda56b3af49..e8ace3129a6edc 100644 --- a/packages/block-library/src/heading/save.js +++ b/packages/block-library/src/heading/save.js @@ -34,7 +34,7 @@ export default function save( { attributes } ) { className={ className ? className : undefined } tagName={ tagName } style={ { - color: textColor, + color: textClass ? undefined : customTextColor, } } value={ content } /> From 25053b5c11bfe663940b1646517be8a2baeb47e6 Mon Sep 17 00:00:00 2001 From: epiqueras Date: Thu, 24 Oct 2019 15:32:06 -0700 Subject: [PATCH 12/15] Use Colors: Fix panel bugs. --- packages/block-editor/src/components/colors/use-colors.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/block-editor/src/components/colors/use-colors.js b/packages/block-editor/src/components/colors/use-colors.js index f3e80c5993d6d9..5b73dfc7c1370d 100644 --- a/packages/block-editor/src/components/colors/use-colors.js +++ b/packages/block-editor/src/components/colors/use-colors.js @@ -39,10 +39,10 @@ const ColorPanel = ( { { ...colorPanelProps } > { contrastCheckerProps && - components.map( ( Component ) => ( + components.map( ( Component, index ) => ( ) ) } @@ -170,7 +170,9 @@ export default function __experimentalUseColors( const newSettingIndex = colorSettings.push( { - value: color, + value: _color ? + _color.color : + attributes[ camelCase( `custom ${ name }` ) ], onChange: acc[ componentName ].setColor, label: panelLabel, colors, From fa6c34f39759297b9b8898028fa46815e133c5e0 Mon Sep 17 00:00:00 2001 From: epiqueras Date: Thu, 24 Oct 2019 15:32:36 -0700 Subject: [PATCH 13/15] Heading Block: Detect actual background color for contrast checking. --- packages/block-library/src/heading/edit.js | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/packages/block-library/src/heading/edit.js b/packages/block-library/src/heading/edit.js index 611eca7879c733..28550322edbfa9 100644 --- a/packages/block-library/src/heading/edit.js +++ b/packages/block-library/src/heading/edit.js @@ -12,7 +12,7 @@ import HeadingToolbar from './heading-toolbar'; * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { PanelBody } from '@wordpress/components'; +import { PanelBody, withFallbackStyles } from '@wordpress/components'; import { createBlock } from '@wordpress/blocks'; import { AlignmentToolbar, @@ -22,7 +22,13 @@ import { __experimentalUseColors, } from '@wordpress/block-editor'; +/** + * Browser dependencies + */ +const { getComputedStyle } = window; + function HeadingEdit( { + backgroundColor, attributes, setAttributes, mergeBlocks, @@ -32,7 +38,7 @@ function HeadingEdit( { const { TextColor, InspectorControlsColorPanel } = __experimentalUseColors( [ { name: 'textColor', attribute: 'color' } ], { - contrastCheckerProps: { backgroundColor: 'white', isLargeText: true }, + contrastCheckerProps: { backgroundColor, isLargeText: true }, }, [] ); @@ -84,4 +90,11 @@ function HeadingEdit( { ); } -export default HeadingEdit; +export default withFallbackStyles( ( node ) => { + let backgroundColor = getComputedStyle( node ).backgroundColor; + while ( backgroundColor === 'rgba(0, 0, 0, 0)' && node.parentNode ) { + node = node.parentNode; + backgroundColor = getComputedStyle( node ).backgroundColor; + } + return { backgroundColor }; +} )( HeadingEdit ); From da24e6c4e2b57564e0478866a85ac400c0cfb9c9 Mon Sep 17 00:00:00 2001 From: epiqueras Date: Fri, 25 Oct 2019 11:57:13 -0700 Subject: [PATCH 14/15] Block Edit: Add new export to native file. --- packages/block-editor/src/components/index.native.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/index.native.js b/packages/block-editor/src/components/index.native.js index b278e29d4555a9..ba4a477253f341 100644 --- a/packages/block-editor/src/components/index.native.js +++ b/packages/block-editor/src/components/index.native.js @@ -1,6 +1,6 @@ // Block Creation Components export { default as BlockControls } from './block-controls'; -export { default as BlockEdit } from './block-edit'; +export { default as BlockEdit, useBlockEditContext } from './block-edit'; export { default as BlockFormatControls } from './block-format-controls'; export { default as BlockIcon } from './block-icon'; export { default as BlockVerticalAlignmentToolbar } from './block-vertical-alignment-toolbar'; From 90990cea119c6bc1db984008c9d15e14c09b1d2d Mon Sep 17 00:00:00 2001 From: epiqueras Date: Fri, 25 Oct 2019 11:59:05 -0700 Subject: [PATCH 15/15] Use Colors: Change CSS "attribute" to "property". --- .../src/components/colors/use-colors.js | 16 ++++++++-------- packages/block-library/src/heading/edit.js | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/block-editor/src/components/colors/use-colors.js b/packages/block-editor/src/components/colors/use-colors.js index 5b73dfc7c1370d..ee3f37c8b00bf7 100644 --- a/packages/block-editor/src/components/colors/use-colors.js +++ b/packages/block-editor/src/components/colors/use-colors.js @@ -89,8 +89,8 @@ export default function __experimentalUseColors( const createComponent = useMemo( () => memoize( - ( attribute, color, colorValue, customColor ) => ( { children } ) => - // Clone children, setting the style attribute from the color configuration, + ( property, color, colorValue, customColor ) => ( { children } ) => + // Clone children, setting the style property from the color configuration, // if not already set explicitly through props. Children.map( children, ( child ) => { let className = child.props.className; @@ -98,11 +98,11 @@ export default function __experimentalUseColors( if ( color ) { className = `${ child.props.className } has-${ kebabCase( color - ) }-${ kebabCase( attribute ) }`; - style = { [ attribute ]: colorValue, ...child.props.style }; + ) }-${ kebabCase( property ) }`; + style = { [ property ]: colorValue, ...child.props.style }; } else if ( customColor ) { - className = `${ child.props.className } has-${ kebabCase( attribute ) }`; - style = { [ attribute ]: customColor, ...child.props.style }; + className = `${ child.props.className } has-${ kebabCase( property ) }`; + style = { [ property ]: customColor, ...child.props.style }; } return cloneElement( child, { className, @@ -143,7 +143,7 @@ export default function __experimentalUseColors( } const { name, // E.g. 'backgroundColor'. - attribute = name, // E.g. 'backgroundColor'. + property = name, // E.g. 'backgroundColor'. panelLabel = startCase( name ), // E.g. 'Background Color'. componentName = panelLabel.replace( /\s/g, '' ), // E.g. 'BackgroundColor'. @@ -159,7 +159,7 @@ export default function __experimentalUseColors( // when they are used as props for other components. const _color = colors.find( ( __color ) => __color.slug === color ); acc[ componentName ] = createComponent( - attribute, + property, color, _color && _color.color, attributes[ camelCase( `custom ${ name }` ) ] diff --git a/packages/block-library/src/heading/edit.js b/packages/block-library/src/heading/edit.js index 28550322edbfa9..241a327bb42c1a 100644 --- a/packages/block-library/src/heading/edit.js +++ b/packages/block-library/src/heading/edit.js @@ -36,7 +36,7 @@ function HeadingEdit( { className, } ) { const { TextColor, InspectorControlsColorPanel } = __experimentalUseColors( - [ { name: 'textColor', attribute: 'color' } ], + [ { name: 'textColor', property: 'color' } ], { contrastCheckerProps: { backgroundColor, isLargeText: true }, },