Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

### Bug Fix

- Fixed error thrown in `ColorPicker` when used in controlled state in color gradients ([#36941](https://github.com/WordPress/gutenberg/pull/36941)).
- Updated readme to include default value introduced in fix for unexpected movements in the `ColorPicker` ([#35670](https://github.com/WordPress/gutenberg/pull/35670)).
- Replaced hardcoded blue in `ColorPicker` with UI theme color ([#36153](https://github.com/WordPress/gutenberg/pull/36153)).

### Experimental
Expand Down
24 changes: 13 additions & 11 deletions packages/components/src/color-picker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,32 +22,34 @@ function Example() {

## Props

### `color`

**Type**: `string`
### `color`: `string`

The current color value to display in the picker. Must be a hex or hex8 string.

### `onChange`
- Required: No

**Type**: `(hex8Color: string) => void`
### `onChange`: `(hex8Color: string) => void`

Fired when the color changes. Always passes a hex8 color string.

### `enableAlpha`
- Required: No

**Type**: `boolean`
### `enableAlpha`: `boolean`

Defaults to `false`. When `true` the color picker will display the alpha channel both in the bottom inputs as well as in the color picker itself.

### `defaultValue`
- Required: No
- Default: `false`

**Type**: `string | undefined`
### `defaultValue`: `string | undefined`

An optional default value to use for the color picker.

### `copyFormat`
- Required: No
- Default: `'#fff'`

**Type**: `'hex' | 'hsl' | 'rgb' | undefined`
### `copyFormat`: `'hex' | 'hsl' | 'rgb' | undefined`

The format to copy when clicking the displayed color format.

- Required: No
20 changes: 15 additions & 5 deletions packages/components/src/color-picker/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import namesPlugin from 'colord/plugins/names';
*/
import { useState, useMemo } from '@wordpress/element';
import { settings } from '@wordpress/icons';
import { useDebounce } from '@wordpress/compose';
import { __ } from '@wordpress/i18n';

/**
Expand All @@ -32,6 +33,7 @@ import {
import { ColorDisplay } from './color-display';
import { ColorInput } from './color-input';
import { Picker } from './picker';
import { useControlledValue } from '../utils/hooks';

import type { ColorType } from './types';

Expand All @@ -57,23 +59,31 @@ const ColorPicker = (
) => {
const {
enableAlpha = false,
color,
color: colorProp,
onChange,
defaultValue = '#fff',
copyFormat,
...divProps
} = useContextSystem( props, 'ColorPicker' );

// Use a safe default value for the color and remove the possibility of `undefined`.
const [ color, setColor ] = useControlledValue( {
onChange,
value: colorProp,
defaultValue,
} );

const safeColordColor = useMemo( () => {
return color ? colord( color ) : colord( defaultValue );
}, [ color, defaultValue ] );
return colord( color );
}, [ color ] );

const debouncedSetColor = useDebounce( setColor );

const handleChange = useCallback(
( nextValue: Colord ) => {
onChange( nextValue.toHex() );
debouncedSetColor( nextValue.toHex() );
},
[ onChange ]
[ debouncedSetColor ]
);

const [ showInputs, setShowInputs ] = useState< boolean >( false );
Expand Down
15 changes: 15 additions & 0 deletions packages/components/src/color-picker/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ function moveReactColorfulSlider( sliderElement, from, to ) {
fireEvent( sliderElement, new FakeMouseEvent( 'mousemove', to ) );
}

const sleep = ( ms ) => {
const promise = new Promise( ( resolve ) => setTimeout( resolve, ms ) );
jest.advanceTimersByTime( ms + 1 );
return promise;
};

const hslaMatcher = expect.objectContaining( {
h: expect.any( Number ),
s: expect.any( Number ),
Expand Down Expand Up @@ -87,6 +93,9 @@ describe( 'ColorPicker', () => {
{ pageX: 10, pageY: 10 }
);

// `onChange` is debounced so we need to sleep for at least 1ms before checking that onChange was called
await sleep( 1 );

expect( onChangeComplete ).toHaveBeenCalledWith(
legacyColorMatcher
);
Expand All @@ -108,6 +117,9 @@ describe( 'ColorPicker', () => {
{ pageX: 10, pageY: 10 }
);

// `onChange` is debounced so we need to sleep for at least 1ms before checking that onChange was called
await sleep( 1 );

expect( onChange ).toHaveBeenCalledWith(
expect.stringMatching( /^#([a-fA-F0-9]{8})$/ )
);
Expand Down Expand Up @@ -138,6 +150,9 @@ describe( 'ColorPicker', () => {
{ pageX: 10, pageY: 10 }
);

// `onChange` is debounced so we need to sleep for at least 1ms before checking that onChange was called
await sleep( 1 );

expect( onChange ).toHaveBeenCalledWith(
expect.stringMatching( /^#([a-fA-F0-9]{6})$/ )
);
Expand Down