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()