-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ColorPalette, BorderControl, GradientPicker: refine types and logic around single vs multiple palettes #47384
Changes from all commits
4db74c8
b212fe7
5e172cd
c24be5b
715da3e
03acd11
726764d
7f1cd2a
280513e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,22 +24,24 @@ import { useBorderControlDropdown } from './hook'; | |
import { StyledLabel } from '../../base-control/styles/base-control-styles'; | ||
import DropdownContentWrapper from '../../dropdown/dropdown-content-wrapper'; | ||
|
||
import type { ColorObject, PaletteObject } from '../../color-palette/types'; | ||
import type { ColorObject } from '../../color-palette/types'; | ||
import { isMultiplePaletteArray } from '../../color-palette/utils'; | ||
import type { DropdownProps as DropdownComponentProps } from '../../dropdown/types'; | ||
import type { ColorProps, DropdownProps } from '../types'; | ||
|
||
const getColorObject = ( | ||
colorValue: CSSProperties[ 'borderColor' ], | ||
colors: ColorProps[ 'colors' ] | undefined | ||
) => { | ||
if ( ! colorValue || ! colors || colors.length === 0 ) { | ||
if ( ! colorValue || ! colors ) { | ||
return; | ||
} | ||
|
||
if ( ( colors as PaletteObject[] )[ 0 ].colors !== undefined ) { | ||
if ( isMultiplePaletteArray( colors ) ) { | ||
// Multiple origins | ||
let matchedColor; | ||
|
||
( colors as PaletteObject[] ).some( ( origin ) => | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since |
||
colors.some( ( origin ) => | ||
origin.colors.some( ( color ) => { | ||
if ( color.color === colorValue ) { | ||
matchedColor = color; | ||
|
@@ -53,9 +55,8 @@ const getColorObject = ( | |
return matchedColor; | ||
} | ||
|
||
return ( colors as ColorObject[] ).find( | ||
( color ) => color.color === colorValue | ||
); | ||
// Single origin | ||
return colors.find( ( color ) => color.color === colorValue ); | ||
}; | ||
|
||
const getToggleAriaLabel = ( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import type { ForwardedRef, RefObject } from 'react'; | ||
import type { ForwardedRef } from 'react'; | ||
import { colord, extend } from 'colord'; | ||
import namesPlugin from 'colord/plugins/names'; | ||
import a11yPlugin from 'colord/plugins/a11y'; | ||
|
@@ -33,6 +33,12 @@ import type { | |
} from './types'; | ||
import type { WordPressComponentProps } from '../ui/context'; | ||
import type { DropdownProps } from '../dropdown/types'; | ||
import { | ||
extractColorNameFromCurrentValue, | ||
isMultiplePaletteArray, | ||
normalizeColorValue, | ||
showTransparentBackground, | ||
} from './utils'; | ||
|
||
extend( [ namesPlugin, a11yPlugin ] ); | ||
|
||
|
@@ -164,77 +170,6 @@ export function CustomColorPickerDropdown( { | |
); | ||
} | ||
|
||
export const extractColorNameFromCurrentValue = ( | ||
currentValue?: ColorPaletteProps[ 'value' ], | ||
colors: ColorPaletteProps[ 'colors' ] = [], | ||
showMultiplePalettes: boolean = false | ||
) => { | ||
if ( ! currentValue ) { | ||
return ''; | ||
} | ||
|
||
const currentValueIsCssVariable = /^var\(/.test( currentValue ); | ||
const normalizedCurrentValue = currentValueIsCssVariable | ||
? currentValue | ||
: colord( currentValue ).toHex(); | ||
|
||
// Normalize format of `colors` to simplify the following loop | ||
type normalizedPaletteObject = { colors: ColorObject[] }; | ||
const colorPalettes: normalizedPaletteObject[] = showMultiplePalettes | ||
? ( colors as PaletteObject[] ) | ||
: [ { colors: colors as ColorObject[] } ]; | ||
for ( const { colors: paletteColors } of colorPalettes ) { | ||
for ( const { name: colorName, color: colorValue } of paletteColors ) { | ||
const normalizedColorValue = currentValueIsCssVariable | ||
? colorValue | ||
: colord( colorValue ).toHex(); | ||
|
||
if ( normalizedCurrentValue === normalizedColorValue ) { | ||
return colorName; | ||
} | ||
} | ||
} | ||
|
||
// translators: shown when the user has picked a custom color (i.e not in the palette of colors). | ||
return __( 'Custom' ); | ||
}; | ||
|
||
export const showTransparentBackground = ( currentValue?: string ) => { | ||
if ( typeof currentValue === 'undefined' ) { | ||
return true; | ||
} | ||
return colord( currentValue ).alpha() === 0; | ||
}; | ||
|
||
const areColorsMultiplePalette = ( | ||
colors: NonNullable< ColorPaletteProps[ 'colors' ] > | ||
): colors is PaletteObject[] => { | ||
return colors.every( ( colorObj ) => | ||
Array.isArray( ( colorObj as PaletteObject ).colors ) | ||
); | ||
}; | ||
|
||
const normalizeColorValue = ( | ||
value: string | undefined, | ||
ref: RefObject< HTMLElement > | null | ||
) => { | ||
const currentValueIsCssVariable = /^var\(/.test( value ?? '' ); | ||
|
||
if ( ! currentValueIsCssVariable || ! ref?.current ) { | ||
return value; | ||
} | ||
|
||
const { ownerDocument } = ref.current; | ||
const { defaultView } = ownerDocument; | ||
const computedBackgroundColor = defaultView?.getComputedStyle( | ||
ref.current | ||
).backgroundColor; | ||
|
||
return computedBackgroundColor | ||
? colord( computedBackgroundColor ).toHex() | ||
: value; | ||
}; | ||
|
||
function UnforwardedColorPalette( | ||
props: WordPressComponentProps< ColorPaletteProps, 'div' >, | ||
forwardedRef: ForwardedRef< any > | ||
|
@@ -252,9 +187,7 @@ function UnforwardedColorPalette( | |
} = props; | ||
const clearColor = useCallback( () => onChange( undefined ), [ onChange ] ); | ||
|
||
const hasMultipleColorOrigins = | ||
colors.length > 0 && | ||
( colors as PaletteObject[] )[ 0 ].colors !== undefined; | ||
const hasMultipleColorOrigins = isMultiplePaletteArray( colors ); | ||
const buttonLabelName = useMemo( | ||
() => | ||
extractColorNameFromCurrentValue( | ||
|
@@ -265,18 +198,6 @@ function UnforwardedColorPalette( | |
[ value, colors, hasMultipleColorOrigins ] | ||
); | ||
|
||
// Make sure that the `colors` array has a valid format. | ||
if ( | ||
colors.length > 0 && | ||
hasMultipleColorOrigins !== areColorsMultiplePalette( colors ) | ||
) { | ||
// eslint-disable-next-line no-console | ||
console.warn( | ||
'wp.components.ColorPalette: please specify a valid format for the `colors` prop. ' | ||
); | ||
return null; | ||
} | ||
|
||
Comment on lines
-268
to
-279
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This check isn't necessary anymore, because its goal was to check that the |
||
const renderCustomColorPicker = () => ( | ||
<DropdownContentWrapper paddingSize="none"> | ||
<ColorPicker | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -55,7 +55,7 @@ export type ColorPaletteProps = Pick< PaletteProps, 'onChange' > & { | |
* | ||
* @default [] | ||
*/ | ||
colors?: ( PaletteObject | ColorObject )[]; | ||
colors?: PaletteObject[] | ColorObject[]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This change is to reflect that the |
||
/** | ||
* Whether to allow the user to pick a custom color on top of the predefined | ||
* choices (defined via the `colors` prop). | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import type { RefObject } from 'react'; | ||
import { colord, extend } from 'colord'; | ||
import namesPlugin from 'colord/plugins/names'; | ||
import a11yPlugin from 'colord/plugins/a11y'; | ||
|
||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { __ } from '@wordpress/i18n'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import type { ColorObject, ColorPaletteProps, PaletteObject } from './types'; | ||
|
||
extend( [ namesPlugin, a11yPlugin ] ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had to add |
||
|
||
export const extractColorNameFromCurrentValue = ( | ||
currentValue?: ColorPaletteProps[ 'value' ], | ||
colors: ColorPaletteProps[ 'colors' ] = [], | ||
showMultiplePalettes: boolean = false | ||
) => { | ||
if ( ! currentValue ) { | ||
return ''; | ||
} | ||
|
||
const currentValueIsCssVariable = /^var\(/.test( currentValue ); | ||
const normalizedCurrentValue = currentValueIsCssVariable | ||
? currentValue | ||
: colord( currentValue ).toHex(); | ||
|
||
// Normalize format of `colors` to simplify the following loop | ||
type normalizedPaletteObject = { colors: ColorObject[] }; | ||
const colorPalettes: normalizedPaletteObject[] = showMultiplePalettes | ||
? ( colors as PaletteObject[] ) | ||
: [ { colors: colors as ColorObject[] } ]; | ||
for ( const { colors: paletteColors } of colorPalettes ) { | ||
for ( const { name: colorName, color: colorValue } of paletteColors ) { | ||
const normalizedColorValue = currentValueIsCssVariable | ||
? colorValue | ||
: colord( colorValue ).toHex(); | ||
|
||
if ( normalizedCurrentValue === normalizedColorValue ) { | ||
return colorName; | ||
} | ||
} | ||
} | ||
|
||
// translators: shown when the user has picked a custom color (i.e not in the palette of colors). | ||
return __( 'Custom' ); | ||
}; | ||
|
||
export const showTransparentBackground = ( currentValue?: string ) => { | ||
if ( typeof currentValue === 'undefined' ) { | ||
return true; | ||
} | ||
return colord( currentValue ).alpha() === 0; | ||
}; | ||
|
||
// The PaletteObject type has a `colors` property (an array of ColorObject), | ||
// while the ColorObject type has a `color` property (the CSS color value). | ||
export const isMultiplePaletteObject = ( | ||
obj: PaletteObject | ColorObject | ||
): obj is PaletteObject => | ||
Array.isArray( ( obj as PaletteObject ).colors ) && ! ( 'color' in obj ); | ||
|
||
export const isMultiplePaletteArray = ( | ||
arr: ( PaletteObject | ColorObject )[] | ||
): arr is PaletteObject[] => { | ||
return ( | ||
arr.length > 0 && | ||
arr.every( ( colorObj ) => isMultiplePaletteObject( colorObj ) ) | ||
); | ||
}; | ||
Comment on lines
+63
to
+77
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the only part that changes in this file. The rest of the lines are a simple copy/paste from |
||
|
||
export const normalizeColorValue = ( | ||
value: string | undefined, | ||
ref: RefObject< HTMLElement > | null | ||
) => { | ||
const currentValueIsCssVariable = /^var\(/.test( value ?? '' ); | ||
|
||
if ( ! currentValueIsCssVariable || ! ref?.current ) { | ||
return value; | ||
} | ||
|
||
const { ownerDocument } = ref.current; | ||
const { defaultView } = ownerDocument; | ||
const computedBackgroundColor = defaultView?.getComputedStyle( | ||
ref.current | ||
).backgroundColor; | ||
|
||
return computedBackgroundColor | ||
? colord( computedBackgroundColor ).toHex() | ||
: value; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,6 +14,18 @@ import { VStack } from '../v-stack'; | |
import { ColorHeading } from '../color-palette/styles'; | ||
import { Spacer } from '../spacer'; | ||
|
||
// The Multiple Origin Gradients have a `gradients` property (an array of | ||
// gradient objects), while Single Origin ones have a `gradient` property. | ||
const isMultipleOriginObject = ( obj ) => | ||
Array.isArray( obj.gradients ) && ! ( 'gradient' in obj ); | ||
|
||
const isMultipleOriginArray = ( arr ) => { | ||
return ( | ||
arr.length > 0 && | ||
arr.every( ( gradientObj ) => isMultipleOriginObject( gradientObj ) ) | ||
); | ||
}; | ||
|
||
function SingleOrigin( { | ||
className, | ||
clearGradient, | ||
|
@@ -105,10 +117,9 @@ export default function GradientPicker( { | |
() => onChange( undefined ), | ||
[ onChange ] | ||
); | ||
const Component = | ||
gradients?.length && gradients[ 0 ].gradients | ||
? MultipleOrigin | ||
: SingleOrigin; | ||
const Component = isMultipleOriginArray( gradients ) | ||
? MultipleOrigin | ||
: SingleOrigin; | ||
Comment on lines
-108
to
+122
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Applied the same logic used for |
||
|
||
if ( ! __nextHasNoMargin ) { | ||
deprecated( 'Outer margin styles for wp.components.GradientPicker', { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This check is now embedded in
isMultiplePaletteArray