Skip to content

Commit 0f2a437

Browse files
t-hamanontsekouras
authored andcommitted
ColorPalette: Ensure text label contrast checking works with CSS variables (#47373)
* ColorPalette: Ensure text label contrast checking works with CSS variables * use `useEffect` to get normalized color value * Update changelog * Try to detect actual color from rgba * Use function to get the composite background color * Rewrite useEffect with useCallback * Don't consider transparent color * Don't use ref, simplify normalizeColorValue() function * Add JSDoc * Add unit tests * Refactor unit tests * Refactor unit test
1 parent 79a9bbd commit 0f2a437

File tree

4 files changed

+46
-13
lines changed

4 files changed

+46
-13
lines changed

packages/components/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## Unreleased
44

5+
### Enhancements
6+
7+
- `ColorPalette`: ensure text label contrast checking works with CSS variables ([#47373](https://github.com/WordPress/gutenberg/pull/47373)).
8+
59
### Internal
610

711
- `NavigatorButton`: Reuse `Button` types ([47754](https://github.com/WordPress/gutenberg/pull/47754)).

packages/components/src/color-palette/index.tsx

+13-5
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import a11yPlugin from 'colord/plugins/a11y';
1010
* WordPress dependencies
1111
*/
1212
import { __, sprintf } from '@wordpress/i18n';
13-
import { useCallback, useRef, useMemo, forwardRef } from '@wordpress/element';
13+
import { useCallback, useMemo, useState, forwardRef } from '@wordpress/element';
1414

1515
/**
1616
* Internal dependencies
@@ -174,7 +174,6 @@ function UnforwardedColorPalette(
174174
props: WordPressComponentProps< ColorPaletteProps, 'div' >,
175175
forwardedRef: ForwardedRef< any >
176176
) {
177-
const customColorPaletteRef = useRef< HTMLElement | null >( null );
178177
const {
179178
clearable = true,
180179
colors = [],
@@ -185,8 +184,17 @@ function UnforwardedColorPalette(
185184
__experimentalIsRenderedInSidebar = false,
186185
...otherProps
187186
} = props;
187+
const [ normalizedColorValue, setNormalizedColorValue ] = useState( value );
188+
188189
const clearColor = useCallback( () => onChange( undefined ), [ onChange ] );
189190

191+
const customColorPaletteCallbackRef = useCallback(
192+
( node: HTMLElement | null ) => {
193+
setNormalizedColorValue( normalizeColorValue( value, node ) );
194+
},
195+
[ value ]
196+
);
197+
190198
const hasMultipleColorOrigins = isMultiplePaletteArray( colors );
191199
const buttonLabelName = useMemo(
192200
() =>
@@ -201,14 +209,14 @@ function UnforwardedColorPalette(
201209
const renderCustomColorPicker = () => (
202210
<DropdownContentWrapper paddingSize="none">
203211
<ColorPicker
204-
color={ normalizeColorValue( value, customColorPaletteRef ) }
212+
color={ normalizedColorValue }
205213
onChange={ ( color ) => onChange( color ) }
206214
enableAlpha={ enableAlpha }
207215
/>
208216
</DropdownContentWrapper>
209217
);
210218

211-
const colordColor = colord( value ?? '' );
219+
const colordColor = colord( normalizedColorValue ?? '' );
212220

213221
const valueWithoutLeadingHash = value?.startsWith( '#' )
214222
? value.substring( 1 )
@@ -246,7 +254,7 @@ function UnforwardedColorPalette(
246254
renderToggle={ ( { isOpen, onToggle } ) => (
247255
<Flex
248256
as={ 'button' }
249-
ref={ customColorPaletteRef }
257+
ref={ customColorPaletteCallbackRef }
250258
justify="space-between"
251259
align="flex-start"
252260
className="components-color-palette__custom-color"

packages/components/src/color-palette/test/utils.ts

+17-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import {
55
extractColorNameFromCurrentValue,
66
showTransparentBackground,
7+
normalizeColorValue,
78
} from '../utils';
89

910
describe( 'ColorPalette: Utils', () => {
@@ -32,11 +33,26 @@ describe( 'ColorPalette: Utils', () => {
3233
expect( showTransparentBackground( 'transparent' ) ).toBe( true );
3334
expect( showTransparentBackground( '#75757500' ) ).toBe( true );
3435
} );
35-
3636
test( 'should return false for non-transparent colors', () => {
3737
expect( showTransparentBackground( '#FFF' ) ).toBe( false );
3838
expect( showTransparentBackground( '#757575' ) ).toBe( false );
3939
expect( showTransparentBackground( '#f5f5f524' ) ).toBe( false ); // 0.14 alpha.
4040
} );
4141
} );
42+
43+
describe( 'normalizeColorValue', () => {
44+
test( 'should return the value as is if the color value is not a CSS variable', () => {
45+
const element = document.createElement( 'div' );
46+
expect( normalizeColorValue( '#ff0000', element ) ).toBe(
47+
'#ff0000'
48+
);
49+
} );
50+
test( 'should return the background color computed from a element if the color value is a CSS variable', () => {
51+
const element = document.createElement( 'div' );
52+
element.style.backgroundColor = '#ff0000';
53+
expect( normalizeColorValue( 'var(--red)', element ) ).toBe(
54+
'#ff0000'
55+
);
56+
} );
57+
} );
4258
} );

packages/components/src/color-palette/utils.ts

+12-7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
/**
22
* External dependencies
33
*/
4-
import type { RefObject } from 'react';
54
import { colord, extend } from 'colord';
65
import namesPlugin from 'colord/plugins/names';
76
import a11yPlugin from 'colord/plugins/a11y';
@@ -76,21 +75,27 @@ export const isMultiplePaletteArray = (
7675
);
7776
};
7877

78+
/**
79+
* Transform a CSS variable used as background color into the color value itself.
80+
*
81+
* @param value The color value that may be a CSS variable.
82+
* @param element The element for which to get the computed style.
83+
* @return The background color value computed from a element.
84+
*/
7985
export const normalizeColorValue = (
8086
value: string | undefined,
81-
ref: RefObject< HTMLElement > | null
87+
element: HTMLElement | null
8288
) => {
8389
const currentValueIsCssVariable = /^var\(/.test( value ?? '' );
8490

85-
if ( ! currentValueIsCssVariable || ! ref?.current ) {
91+
if ( ! currentValueIsCssVariable || element === null ) {
8692
return value;
8793
}
8894

89-
const { ownerDocument } = ref.current;
95+
const { ownerDocument } = element;
9096
const { defaultView } = ownerDocument;
91-
const computedBackgroundColor = defaultView?.getComputedStyle(
92-
ref.current
93-
).backgroundColor;
97+
const computedBackgroundColor =
98+
defaultView?.getComputedStyle( element ).backgroundColor;
9499

95100
return computedBackgroundColor
96101
? colord( computedBackgroundColor ).toHex()

0 commit comments

Comments
 (0)