Skip to content

Commit

Permalink
DuotonePicker, DuotoneSwatch: Convert to TypeScript (#49060)
Browse files Browse the repository at this point in the history
* Rename index.tsx

* Add types for DuotoneSwatch

* Add more types

* Add main JSDoc

* Move ColorListPicker into duotone-picker folder

* Convert stories

* Add changelog

* Fix style imports

* ColorListPicker: Tweak types

* Add code comment

* Improve TODO comment

* Fix typo

* Move changelog
  • Loading branch information
mirka authored Mar 21, 2023
1 parent b468691 commit 04c579c
Show file tree
Hide file tree
Showing 14 changed files with 177 additions and 40 deletions.
4 changes: 4 additions & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@

- `InputControl`: Fix misaligned textarea input control ([#49116](https://github.com/WordPress/gutenberg/pull/49116)).

### Internal

- `DuotonePicker`, `DuotoneSwatch`: Convert to TypeScript ([#49060](https://github.com/WordPress/gutenberg/pull/49060)).

## 23.6.0 (2023-03-15)

### Enhancements
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import { swatch } from '@wordpress/icons';
/**
* Internal dependencies
*/
import Button from '../button';
import ColorPalette from '../color-palette';
import ColorIndicator from '../color-indicator';
import Icon from '../icon';
import { HStack } from '../h-stack';
import Button from '../../button';
import ColorPalette from '../../color-palette';
import ColorIndicator from '../../color-indicator';
import Icon from '../../icon';
import { HStack } from '../../h-stack';
import type { ColorListPickerProps, ColorOptionProps } from './types';

function ColorOption( {
Expand Down Expand Up @@ -75,7 +75,8 @@ function ColorListPicker( {
disableCustomColors={ disableCustomColors }
enableAlpha={ enableAlpha }
onChange={ ( newColor ) => {
const newColors = value.slice();
const newColors: ( string | undefined )[] =
value.slice();
newColors[ index ] = newColor;
onChange( newColors );
} }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { CSSProperties } from 'react';

export type ColorListPickerProps = {
/**
* A list of predifened colors. Each color is an object with a `name` and a
* A list of predefined colors. Each color is an object with a `name` and a
* `color` value.
* The `name` is a string used to identify the color in the UI.
* The `color` is a valid CSS color string.
Expand All @@ -21,7 +21,7 @@ export type ColorListPickerProps = {
/**
* An array containing the currently selected colors.
*/
value?: Array< string | undefined >;
value?: Array< string >;
/**
* Controls whether the custom color picker is displayed.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ import {

const PLACEHOLDER_VALUES = [ '#333', '#CCC' ];

export default function CustomDuotoneBar( { value, onChange } ) {
export default function CustomDuotoneBar( {
value,
onChange,
}: {
value?: string[];
onChange: ( value?: string[] ) => void;
} ) {
const hasGradient = !! value;
const values = hasGradient ? value : PLACEHOLDER_VALUES;
const background = getGradientFromCSSColors( values );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,48 @@ import { __, sprintf } from '@wordpress/i18n';
/**
* Internal dependencies
*/
import ColorListPicker from '../color-list-picker';
import ColorListPicker from './color-list-picker';
import CircularOptionPicker from '../circular-option-picker';
import { VStack } from '../v-stack';

import CustomDuotoneBar from './custom-duotone-bar';
import { getDefaultColors, getGradientFromCSSColors } from './utils';
import { Spacer } from '../spacer';
import type { DuotonePickerProps } from './types';

/**
* ```jsx
* import { DuotonePicker, DuotoneSwatch } from '@wordpress/components';
* import { useState } from '@wordpress/element';
*
* const DUOTONE_PALETTE = [
* { colors: [ '#8c00b7', '#fcff41' ], name: 'Purple and yellow', slug: 'purple-yellow' },
* { colors: [ '#000097', '#ff4747' ], name: 'Blue and red', slug: 'blue-red' },
* ];
*
* const COLOR_PALETTE = [
* { color: '#ff4747', name: 'Red', slug: 'red' },
* { color: '#fcff41', name: 'Yellow', slug: 'yellow' },
* { color: '#000097', name: 'Blue', slug: 'blue' },
* { color: '#8c00b7', name: 'Purple', slug: 'purple' },
* ];
*
* const Example = () => {
* const [ duotone, setDuotone ] = useState( [ '#000000', '#ffffff' ] );
* return (
* <>
* <DuotonePicker
* duotonePalette={ DUOTONE_PALETTE }
* colorPalette={ COLOR_PALETTE }
* value={ duotone }
* onChange={ setDuotone }
* />
* <DuotoneSwatch values={ duotone } />
* </>
* );
* };
* ```
*/
function DuotonePicker( {
clearable = true,
unsetable = true,
Expand All @@ -29,7 +63,7 @@ function DuotonePicker( {
disableCustomDuotone,
value,
onChange,
} ) {
}: DuotonePickerProps ) {
const [ defaultDark, defaultLight ] = useMemo(
() => getDefaultColors( colorPalette ),
[ colorPalette ]
Expand Down Expand Up @@ -125,6 +159,9 @@ function DuotonePicker( {
newColors.length >= 2
? newColors
: undefined;
// @ts-expect-error TODO: The color arrays for a DuotonePicker should be a tuple of two colors,
// but it's currently typed as a string[].
// See also https://github.com/WordPress/gutenberg/pull/49060#discussion_r1136951035
onChange( newValue );
} }
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import { swatch } from '@wordpress/icons';
import ColorIndicator from '../color-indicator';
import Icon from '../icon';
import { getGradientFromCSSColors } from './utils';
import type { DuotoneSwatchProps } from './types';

function DuotoneSwatch( { values } ) {
function DuotoneSwatch( { values }: DuotoneSwatchProps ) {
return values ? (
<ColorIndicator
colorValue={ getGradientFromCSSColors( values, '135deg' ) }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/**
* External dependencies
*/
import type { ComponentMeta, ComponentStory } from '@storybook/react';

/**
* WordPress dependencies
*/
Expand All @@ -6,23 +11,22 @@ import { useState } from '@wordpress/element';
/**
* Internal dependencies
*/
import { DuotonePicker } from '../';
import { DuotonePicker } from '..';
import type { DuotonePickerProps } from '../types';

export default {
const meta: ComponentMeta< typeof DuotonePicker > = {
title: 'Components/DuotonePicker',
component: DuotonePicker,
argTypes: {
clearable: { control: { type: 'boolean' } },
disableCustomColors: { control: { type: 'boolean' } },
disableCustomDuotone: { control: { type: 'boolean' } },
onChange: { action: 'onChange' },
unsetable: { control: { type: 'boolean' } },
value: { control: { type: null } },
},
parameters: {
controls: { expanded: true },
docs: { source: { state: 'open' } },
},
};
export default meta;

const DUOTONE_PALETTE = [
{
Expand All @@ -44,8 +48,11 @@ const COLOR_PALETTE = [
{ color: '#8c00b7', name: 'Purple', slug: 'purple' },
];

const Template = ( { onChange, ...args } ) => {
const [ value, setValue ] = useState();
const Template: ComponentStory< typeof DuotonePicker > = ( {
onChange,
...args
} ) => {
const [ value, setValue ] = useState< DuotonePickerProps[ 'value' ] >();

return (
<DuotonePicker
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
/**
* External dependencies
*/
import type { ComponentMeta, ComponentStory } from '@storybook/react';

/**
* Internal dependencies
*/
import { DuotoneSwatch } from '../';
import { DuotoneSwatch } from '..';

export default {
const meta: ComponentMeta< typeof DuotoneSwatch > = {
title: 'Components/DuotoneSwatch',
component: DuotoneSwatch,
parameters: {
controls: { expanded: true },
docs: { source: { state: 'open' } },
},
};
export default meta;

const Template = ( args ) => {
const Template: ComponentStory< typeof DuotoneSwatch > = ( args ) => {
return <DuotoneSwatch { ...args } />;
};

Expand Down
61 changes: 61 additions & 0 deletions packages/components/src/duotone-picker/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
export type DuotonePickerProps = {
/**
* Whether there should be a button to clear the duotone value.
*
* @default true
*/
clearable?: boolean;
/**
* Whether there should be an `unset` option.
*
* @default true
*/
unsetable?: boolean;
/**
* Array of color presets of the form `{ color: '#000000', name: 'Black', slug: 'black' }`.
*/
colorPalette: Color[];
/**
* Array of duotone presets of the form `{ colors: [ '#000000', '#ffffff' ], name: 'Grayscale', slug: 'grayscale' }`.
*/
duotonePalette: DuotoneColor[];
/**
* Whether custom colors should be disabled.
*
* @default false
*/
disableCustomColors?: boolean;
/**
* Whether custom duotone values should be disabled.
*
* @default false
*/
disableCustomDuotone?: boolean;
/**
* An array of colors for the duotone effect.
*/
value?: string[] | 'unset';
/**
* Callback which is called when the duotone colors change.
*/
onChange: ( value: DuotonePickerProps[ 'value' ] | undefined ) => void;
};

type Color = {
color: string;
name: string;
slug: string;
};

type DuotoneColor = {
colors: string[];
name: string;
slug: string;
};

export type DuotoneSwatchProps = {
/**
* An array of colors to show or `null` to show the placeholder swatch icon.
*/
values?: string[] | null;
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
import { colord, extend } from 'colord';
import namesPlugin from 'colord/plugins/names';

/**
* Internal dependencies
*/
import type { DuotonePickerProps } from './types';

extend( [ namesPlugin ] );

/**
Expand All @@ -18,11 +23,13 @@ extend( [ namesPlugin ] );
/**
* Calculate the brightest and darkest values from a color palette.
*
* @param {Object[]} palette Color palette for the theme.
* @param palette Color palette for the theme.
*
* @return {string[]} Tuple of the darkest color and brightest color.
* @return Tuple of the darkest color and brightest color.
*/
export function getDefaultColors( palette ) {
export function getDefaultColors(
palette: DuotonePickerProps[ 'colorPalette' ]
) {
// A default dark and light color are required.
if ( ! palette || palette.length < 2 ) return [ '#000', '#fff' ];

Expand All @@ -38,20 +45,26 @@ export function getDefaultColors( palette ) {
current.brightness >= max.brightness ? current : max,
];
},
[ { brightness: 1 }, { brightness: 0 } ]
[
{ brightness: 1, color: '' },
{ brightness: 0, color: '' },
]
)
.map( ( { color } ) => color );
}

/**
* Generate a duotone gradient from a list of colors.
*
* @param {string[]} colors CSS color strings.
* @param {string} angle CSS gradient angle.
* @param colors CSS color strings.
* @param angle CSS gradient angle.
*
* @return {string} CSS gradient string for the duotone swatch.
* @return CSS gradient string for the duotone swatch.
*/
export function getGradientFromCSSColors( colors = [], angle = '90deg' ) {
export function getGradientFromCSSColors(
colors: string[] = [],
angle = '90deg'
) {
const l = 100 / colors.length;

const stops = colors
Expand All @@ -64,11 +77,11 @@ export function getGradientFromCSSColors( colors = [], angle = '90deg' ) {
/**
* Convert a color array to an array of color stops.
*
* @param {string[]} colors CSS colors array
* @param colors CSS colors array
*
* @return {Object[]} Color stop information.
* @return Color stop information.
*/
export function getColorStopsFromColors( colors ) {
export function getColorStopsFromColors( colors: string[] ) {
return colors.map( ( color, i ) => ( {
position: ( i * 100 ) / ( colors.length - 1 ),
color,
Expand All @@ -78,10 +91,12 @@ export function getColorStopsFromColors( colors ) {
/**
* Convert a color stop array to an array colors.
*
* @param {Object[]} colorStops Color stop information.
* @param colorStops Color stop information.
*
* @return {string[]} CSS colors array.
* @return CSS colors array.
*/
export function getColorsFromColorStops( colorStops = [] ) {
export function getColorsFromColorStops(
colorStops: { position: number; color: string }[] = []
) {
return colorStops.map( ( { color } ) => color );
}
Loading

1 comment on commit 04c579c

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flaky tests detected in 04c579c.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/4478707343
📝 Reported issues:

Please sign in to comment.