Skip to content

Commit

Permalink
Use Colors: Enhance contrast checking API. (#18237)
Browse files Browse the repository at this point in the history
* Use Colors: Enhance contrast checking API.

* Use Colors: Re-detect background color when attributes change.

* Use Colors: Only re-detect background color when color attributes change.

* Use Colors: Allow specifying a query selector for the background color detector to start searching from.

* Use Colors: Only create background detector when needed.
  • Loading branch information
epiqueras authored Nov 15, 2019
1 parent 9c34fc9 commit 808097c
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 49 deletions.
134 changes: 102 additions & 32 deletions packages/block-editor/src/components/colors/use-colors.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@
*/
import memoize from 'memize';
import classnames from 'classnames';
import {
camelCase,
kebabCase,
map,
startCase,
} from 'lodash';
import { map, kebabCase, camelCase, startCase } from 'lodash';

/**
* WordPress dependencies
Expand All @@ -20,7 +15,9 @@ import {
useMemo,
Children,
cloneElement,
useRef,
} from '@wordpress/element';
import { withFallbackStyles } from '@wordpress/components';

/**
* Internal dependencies
Expand All @@ -30,13 +27,28 @@ import ContrastChecker from '../contrast-checker';
import InspectorControls from '../inspector-controls';
import { useBlockEditContext } from '../block-edit';

/**
* Browser dependencies
*/
const { getComputedStyle } = window;

const DEFAULT_COLORS = [];

const resolveContrastCheckerColor = ( color, colorSettings, detectedColor ) => {
if ( typeof color === 'function' ) {
return color( colorSettings );
} else if ( color === true ) {
return detectedColor;
}
return color;
};

const ColorPanel = ( {
title,
colorSettings,
colorPanelProps,
contrastCheckerProps,
components,
contrastCheckers,
detectedBackgroundColor,
panelChildren,
} ) => (
<PanelColorSettings
Expand All @@ -45,16 +57,46 @@ const ColorPanel = ( {
colorSettings={ Object.values( colorSettings ) }
{ ...colorPanelProps }
>
{ contrastCheckerProps &&
map( components, ( ( Component, key ) => (
<ContrastChecker
key={ key }
textColor={ colorSettings[ key ].value }
{ ...contrastCheckerProps }
/>
) ) ) }
{ contrastCheckers &&
( Array.isArray( contrastCheckers ) ?
contrastCheckers.map( ( { backgroundColor, textColor, ...rest } ) => {
backgroundColor = resolveContrastCheckerColor(
backgroundColor,
colorSettings,
detectedBackgroundColor
);
textColor = resolveContrastCheckerColor( textColor, colorSettings );
return (
<ContrastChecker
key={ `${ backgroundColor }-${ textColor }` }
backgroundColor={ backgroundColor }
textColor={ textColor }
{ ...rest }
/>
);
} ) :
map( colorSettings, ( { value } ) => {
let { backgroundColor, textColor } = contrastCheckers;
backgroundColor = resolveContrastCheckerColor(
backgroundColor || value,
colorSettings,
detectedBackgroundColor
);
textColor = resolveContrastCheckerColor(
textColor || value,
colorSettings
);
return (
<ContrastChecker
{ ...contrastCheckers }
key={ `${ backgroundColor }-${ textColor }` }
backgroundColor={ backgroundColor }
textColor={ textColor }
/>
);
} ) ) }
{ typeof panelChildren === 'function' ?
panelChildren( components ) :
panelChildren( colorSettings ) :
panelChildren }
</PanelColorSettings>
);
Expand All @@ -69,7 +111,7 @@ export default function __experimentalUseColors(
{
panelTitle = __( 'Color Settings' ),
colorPanelProps,
contrastCheckerProps,
contrastCheckers,
panelChildren,
} = {
panelTitle: __( 'Color Settings' ),
Expand Down Expand Up @@ -113,14 +155,10 @@ export default function __experimentalUseColors(
}

return cloneElement( child, {
className: classnames(
componentClassName,
child.props.className,
{
[ `has-${ kebabCase( color ) }-${ kebabCase( property ) }` ]: color,
[ className || `has-${ kebabCase( name ) }` ]: color || customColor,
}
),
className: classnames( componentClassName, child.props.className, {
[ `has-${ kebabCase( color ) }-${ kebabCase( property ) }` ]: color,
[ className || `has-${ kebabCase( name ) }` ]: color || customColor,
} ),
style: {
...colorStyle,
...componentStyle,
Expand Down Expand Up @@ -153,6 +191,39 @@ export default function __experimentalUseColors(
[ setAttributes, colorConfigs.length ]
);

const detectedBackgroundColorRef = useRef();
const BackgroundColorDetector = useMemo(
() =>
contrastCheckers &&
( Array.isArray( contrastCheckers ) ?
contrastCheckers.some(
( { backgroundColor } ) => backgroundColor === true
) :
contrastCheckers.backgroundColor === true ) &&
withFallbackStyles( ( node, { querySelector } ) => {
if ( querySelector ) {
node = node.parentNode.querySelector( querySelector );
}
let backgroundColor = getComputedStyle( node ).backgroundColor;
while ( backgroundColor === 'rgba(0, 0, 0, 0)' && node.parentNode ) {
node = node.parentNode;
backgroundColor = getComputedStyle( node ).backgroundColor;
}
detectedBackgroundColorRef.current = backgroundColor;
return { backgroundColor };
} )( () => <></> ),
[
colorConfigs.reduce(
( acc, colorConfig ) =>
`${ acc } | ${ attributes[ colorConfig.name ] } | ${
attributes[ camelCase( `custom ${ colorConfig.name }` ) ]
}`,
''
),
...deps,
]
);

return useMemo( () => {
const colorSettings = {};

Expand Down Expand Up @@ -191,9 +262,7 @@ export default function __experimentalUseColors(
acc[ componentName ].setColor = createSetColor( name, colors );

colorSettings[ componentName ] = {
value: _color ?
_color.color :
attributes[ camelCase( `custom ${ name }` ) ],
value: _color ? _color.color : attributes[ camelCase( `custom ${ name }` ) ],
onChange: acc[ componentName ].setColor,
label: panelLabel,
colors,
Expand All @@ -213,8 +282,8 @@ export default function __experimentalUseColors(
title: panelTitle,
colorSettings,
colorPanelProps,
contrastCheckerProps,
components,
contrastCheckers,
detectedBackgroundColor: detectedBackgroundColorRef.current,
panelChildren,
};
return {
Expand All @@ -223,6 +292,7 @@ export default function __experimentalUseColors(
InspectorControlsColorPanel: (
<InspectorControlsColorPanel { ...wrappedColorPanelProps } />
),
BackgroundColorDetector,
};
}, [ attributes, setAttributes, ...deps ] );
}, [ attributes, setAttributes, detectedBackgroundColorRef.current, ...deps ] );
}
22 changes: 5 additions & 17 deletions packages/block-library/src/heading/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import HeadingToolbar from './heading-toolbar';
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { PanelBody, withFallbackStyles } from '@wordpress/components';
import { PanelBody } from '@wordpress/components';
import { createBlock } from '@wordpress/blocks';
import {
AlignmentToolbar,
Expand All @@ -22,23 +22,17 @@ import {
__experimentalUseColors,
} from '@wordpress/block-editor';

/**
* Browser dependencies
*/
const { getComputedStyle } = window;

function HeadingEdit( {
backgroundColor,
attributes,
setAttributes,
mergeBlocks,
onReplace,
className,
} ) {
const { TextColor, InspectorControlsColorPanel } = __experimentalUseColors(
const { TextColor, InspectorControlsColorPanel, BackgroundColorDetector } = __experimentalUseColors(
[ { name: 'textColor', property: 'color' } ],
{
contrastCheckerProps: { backgroundColor, isLargeText: true },
contrastCheckers: { backgroundColor: true },
},
[]
);
Expand All @@ -62,6 +56,7 @@ function HeadingEdit( {
</InspectorControls>
{ InspectorControlsColorPanel }
<TextColor>
<BackgroundColorDetector querySelector='[contenteditable="true"]' />
<RichText
identifier="content"
tagName={ tagName }
Expand Down Expand Up @@ -90,11 +85,4 @@ function 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 );
export default HeadingEdit;

0 comments on commit 808097c

Please sign in to comment.