diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 06650771ce1ba8..8ce5c10ccf8fde 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Enhancements + +- `ColorPalette`: ensure text label contrast checking works with CSS variables ([#47373](https://github.com/WordPress/gutenberg/pull/47373)). + ### Internal - `NavigatorButton`: Reuse `Button` types ([47754](https://github.com/WordPress/gutenberg/pull/47754)). diff --git a/packages/components/src/color-palette/index.tsx b/packages/components/src/color-palette/index.tsx index c967703141ea34..b72a611747b40f 100644 --- a/packages/components/src/color-palette/index.tsx +++ b/packages/components/src/color-palette/index.tsx @@ -10,7 +10,7 @@ import a11yPlugin from 'colord/plugins/a11y'; * WordPress dependencies */ import { __, sprintf } from '@wordpress/i18n'; -import { useCallback, useRef, useMemo, forwardRef } from '@wordpress/element'; +import { useCallback, useMemo, useState, forwardRef } from '@wordpress/element'; /** * Internal dependencies @@ -174,7 +174,6 @@ function UnforwardedColorPalette( props: WordPressComponentProps< ColorPaletteProps, 'div' >, forwardedRef: ForwardedRef< any > ) { - const customColorPaletteRef = useRef< HTMLElement | null >( null ); const { clearable = true, colors = [], @@ -185,8 +184,17 @@ function UnforwardedColorPalette( __experimentalIsRenderedInSidebar = false, ...otherProps } = props; + const [ normalizedColorValue, setNormalizedColorValue ] = useState( value ); + const clearColor = useCallback( () => onChange( undefined ), [ onChange ] ); + const customColorPaletteCallbackRef = useCallback( + ( node: HTMLElement | null ) => { + setNormalizedColorValue( normalizeColorValue( value, node ) ); + }, + [ value ] + ); + const hasMultipleColorOrigins = isMultiplePaletteArray( colors ); const buttonLabelName = useMemo( () => @@ -201,14 +209,14 @@ function UnforwardedColorPalette( const renderCustomColorPicker = () => ( onChange( color ) } enableAlpha={ enableAlpha } /> ); - const colordColor = colord( value ?? '' ); + const colordColor = colord( normalizedColorValue ?? '' ); const valueWithoutLeadingHash = value?.startsWith( '#' ) ? value.substring( 1 ) @@ -246,7 +254,7 @@ function UnforwardedColorPalette( renderToggle={ ( { isOpen, onToggle } ) => ( { @@ -32,11 +33,26 @@ describe( 'ColorPalette: Utils', () => { expect( showTransparentBackground( 'transparent' ) ).toBe( true ); expect( showTransparentBackground( '#75757500' ) ).toBe( true ); } ); - test( 'should return false for non-transparent colors', () => { expect( showTransparentBackground( '#FFF' ) ).toBe( false ); expect( showTransparentBackground( '#757575' ) ).toBe( false ); expect( showTransparentBackground( '#f5f5f524' ) ).toBe( false ); // 0.14 alpha. } ); } ); + + describe( 'normalizeColorValue', () => { + test( 'should return the value as is if the color value is not a CSS variable', () => { + const element = document.createElement( 'div' ); + expect( normalizeColorValue( '#ff0000', element ) ).toBe( + '#ff0000' + ); + } ); + test( 'should return the background color computed from a element if the color value is a CSS variable', () => { + const element = document.createElement( 'div' ); + element.style.backgroundColor = '#ff0000'; + expect( normalizeColorValue( 'var(--red)', element ) ).toBe( + '#ff0000' + ); + } ); + } ); } ); diff --git a/packages/components/src/color-palette/utils.ts b/packages/components/src/color-palette/utils.ts index 8a70d25a701e99..1ef7f308d01230 100644 --- a/packages/components/src/color-palette/utils.ts +++ b/packages/components/src/color-palette/utils.ts @@ -1,7 +1,6 @@ /** * External dependencies */ -import type { RefObject } from 'react'; import { colord, extend } from 'colord'; import namesPlugin from 'colord/plugins/names'; import a11yPlugin from 'colord/plugins/a11y'; @@ -76,21 +75,27 @@ export const isMultiplePaletteArray = ( ); }; +/** + * Transform a CSS variable used as background color into the color value itself. + * + * @param value The color value that may be a CSS variable. + * @param element The element for which to get the computed style. + * @return The background color value computed from a element. + */ export const normalizeColorValue = ( value: string | undefined, - ref: RefObject< HTMLElement > | null + element: HTMLElement | null ) => { const currentValueIsCssVariable = /^var\(/.test( value ?? '' ); - if ( ! currentValueIsCssVariable || ! ref?.current ) { + if ( ! currentValueIsCssVariable || element === null ) { return value; } - const { ownerDocument } = ref.current; + const { ownerDocument } = element; const { defaultView } = ownerDocument; - const computedBackgroundColor = defaultView?.getComputedStyle( - ref.current - ).backgroundColor; + const computedBackgroundColor = + defaultView?.getComputedStyle( element ).backgroundColor; return computedBackgroundColor ? colord( computedBackgroundColor ).toHex()