diff --git a/packages/block-editor/src/components/duotone-control/index.js b/packages/block-editor/src/components/duotone-control/index.js index d27e6863fe0dfd..fdfbefc4723094 100644 --- a/packages/block-editor/src/components/duotone-control/index.js +++ b/packages/block-editor/src/components/duotone-control/index.js @@ -16,6 +16,7 @@ import { Icon, filter } from '@wordpress/icons'; function DuotoneControl( { colorPalette, duotonePalette, + duotonePaletteByOrigin, disableCustomColors, disableCustomDuotone, value, @@ -67,6 +68,7 @@ function DuotoneControl( { { label={ __( 'Color' ) } className="color-block-support-panel__inner-wrapper" /> + [ ...userPresets, @@ -81,6 +83,33 @@ function useMultiOriginPresets( { presetSetting, defaultSetting } ) { ); } +function useGroupedPresets( { presetSetting, defaultSetting } ) { + const disableDefault = ! useSetting( defaultSetting ); + const userPresets = + useSetting( `${ presetSetting }.custom` ) || EMPTY_ARRAY; + const themePresets = + useSetting( `${ presetSetting }.theme` ) || EMPTY_ARRAY; + const defaultPresets = + useSetting( `${ presetSetting }.default` ) || EMPTY_ARRAY; + + return useMemo( () => { + return [ + { + name: 'User', + palettes: userPresets, + }, + { + name: 'Theme', + palettes: themePresets, + }, + { + name: 'Default', + palettes: disableDefault ? EMPTY_ARRAY : defaultPresets, + }, + ]; + }, [ disableDefault, userPresets, themePresets, defaultPresets ] ); +} + export function getColorsFromDuotonePreset( duotone, duotonePalette ) { if ( ! duotone ) { return; @@ -114,6 +143,10 @@ function DuotonePanel( { attributes, setAttributes } ) { presetSetting: 'color.duotone', defaultSetting: 'color.defaultDuotone', } ); + const duotonePaletteByOrigin = useGroupedPresets( { + presetSetting: 'color.duotone', + defaultSetting: 'color.defaultDuotone', + } ); const colorPalette = useMultiOriginPresets( { presetSetting: 'color.palette', defaultSetting: 'color.defaultPalette', @@ -132,30 +165,59 @@ function DuotonePanel( { attributes, setAttributes } ) { : duotoneStyle; return ( - - { - const maybePreset = getDuotonePresetFromColors( - newDuotone, - duotonePalette - ); - - const newStyle = { - ...style, - color: { - ...style?.color, - duotone: maybePreset ?? newDuotone, // use preset or fallback to custom colors. - }, - }; - setAttributes( { style: newStyle } ); - } } - /> - + <> + + { + const maybePreset = getDuotonePresetFromColors( + newDuotone, + duotonePalette + ); + + const newStyle = { + ...style, + color: { + ...style?.color, + duotone: maybePreset ?? newDuotone, // use preset or fallback to custom colors. + }, + }; + setAttributes( { style: newStyle } ); + } } + /> + + + { + const maybePreset = getDuotonePresetFromColors( + newDuotone, + duotonePalette + ); + + const newStyle = { + ...style, + color: { + ...style?.color, + duotone: maybePreset ?? newDuotone, // use preset or fallback to custom colors. + }, + }; + setAttributes( { style: newStyle } ); + } } + /> + + ); } diff --git a/packages/components/src/duotone-picker/duotone-picker.tsx b/packages/components/src/duotone-picker/duotone-picker.tsx index 2daacb15c9159c..663ebde0ac3c6c 100644 --- a/packages/components/src/duotone-picker/duotone-picker.tsx +++ b/packages/components/src/duotone-picker/duotone-picker.tsx @@ -12,6 +12,7 @@ import { __, sprintf } from '@wordpress/i18n'; /** * Internal dependencies */ +import { ColorHeading } from '../color-palette/styles'; import ColorListPicker from './color-list-picker'; import CircularOptionPicker from '../circular-option-picker'; import { VStack } from '../v-stack'; @@ -19,72 +20,15 @@ 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'; +import type { + DuotonePickerProps, + SinglePaletteProps, + MultiplePalettesProps, + paletteOptionsProps, +} 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 ( - * <> - * - * - * - * ); - * }; - * ``` - */ -function DuotonePicker( { - clearable = true, - unsetable = true, - colorPalette, - duotonePalette, - disableCustomColors, - disableCustomDuotone, - value, - onChange, -}: DuotonePickerProps ) { - const [ defaultDark, defaultLight ] = useMemo( - () => getDefaultColors( colorPalette ), - [ colorPalette ] - ); - - const isUnset = value === 'unset'; - - const unsetOption = ( - { - onChange( isUnset ? undefined : 'unset' ); - } } - /> - ); - - const options = duotonePalette.map( ( { colors, slug, name } ) => { +function paletteOptions( { palette, value, onChange }: paletteOptionsProps ) { + return palette.map( ( { colors, slug, name } ) => { const style = { background: getGradientFromCSSColors( colors, '135deg' ), color: 'transparent', @@ -119,6 +63,27 @@ function DuotonePicker( { /> ); } ); +} + +function SinglePalette( { + defaultDark, + defaultLight, + clearable, + unsetable, + colorPalette, + duotonePalette, + disableCustomColors, + disableCustomDuotone, + value, + unsetOption, + onChange, +}: SinglePaletteProps ) { + const colorValue = value && value !== 'unset' ? value : undefined; + const options = paletteOptions( { + palette: duotonePalette, + value, + onChange, + } ); return ( { ! disableCustomColors && ! disableCustomDuotone && ( ) } @@ -145,7 +110,7 @@ function DuotonePicker( { { @@ -172,4 +137,154 @@ function DuotonePicker( { ); } +function MultiplePalettes( { + defaultDark, + defaultLight, + unsetable, + colorPalette, + duotonePaletteByOrigin, + disableCustomColors, + disableCustomDuotone, + value, + unsetOption, + onChange, +}: MultiplePalettesProps ) { + if ( ! duotonePaletteByOrigin ) { + return null; + } + + const paletteProps = { + defaultDark, + defaultLight, + clearable: false, + unsetable, + colorPalette, + disableCustomColors, + disableCustomDuotone, + value, + unsetOption, + onChange, + }; + + return ( + <> + { duotonePaletteByOrigin + .filter( ( { palettes } ) => palettes.length > 0 ) + .map( ( { name, palettes }, index, array ) => { + if ( index > 0 ) { + paletteProps.unsetable = false; + } + if ( index === array.length - 1 ) { + paletteProps.clearable = true; + } + return ( + + { name } + + + ); + } ) } + + ); +} + +/** + * ```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 ( + * <> + * + * + * + * ); + * }; + * ``` + */ +function DuotonePicker( { + clearable = true, + unsetable = true, + colorPalette, + duotonePalette, + duotonePaletteByOrigin, + disableCustomColors, + disableCustomDuotone, + value, + onChange, +}: DuotonePickerProps ) { + const [ defaultDark, defaultLight ] = useMemo( + () => getDefaultColors( colorPalette ), + [ colorPalette ] + ); + + const isUnset = value === 'unset'; + + const unsetOption = ( + { + onChange( isUnset ? undefined : 'unset' ); + } } + /> + ); + + const paletteCommonProps = { + defaultDark, + defaultLight, + unsetable, + colorPalette, + disableCustomColors, + disableCustomDuotone, + value, + unsetOption, + onChange, + }; + + return ( + <> + { duotonePaletteByOrigin ? ( + <> + + + ) : ( + + ) } + + ); +} + export default DuotonePicker; diff --git a/packages/components/src/duotone-picker/types.ts b/packages/components/src/duotone-picker/types.ts index 3d5927675f542f..18bb5607a9bcf4 100644 --- a/packages/components/src/duotone-picker/types.ts +++ b/packages/components/src/duotone-picker/types.ts @@ -19,6 +19,10 @@ export type DuotonePickerProps = { * Array of duotone presets of the form `{ colors: [ '#000000', '#ffffff' ], name: 'Grayscale', slug: 'grayscale' }`. */ duotonePalette: DuotoneColor[]; + /** + * Array of duotone presets of the form `{ colors: [ '#000000', '#ffffff' ], name: 'Grayscale', slug: 'grayscale' } grouped by origin`. + */ + duotonePaletteByOrigin?: duotonePaletteByOrigin; /** * Whether custom colors should be disabled. * @@ -47,6 +51,11 @@ type Color = { slug: string; }; +type duotonePaletteByOrigin = Array< { + name: string; + palettes: DuotoneColor[]; +} >; + type DuotoneColor = { colors: string[]; name: string; @@ -59,3 +68,36 @@ export type DuotoneSwatchProps = { */ values?: string[] | null; }; + +export type SinglePaletteProps = { + defaultDark: string; + defaultLight: string; + unsetable?: boolean; + colorPalette: Color[]; + disableCustomColors?: boolean; + disableCustomDuotone?: boolean; + value?: string[] | 'unset'; + unsetOption: React.ReactElement; + onChange: ( value: DuotonePickerProps[ 'value' ] | undefined ) => void; + clearable?: boolean; + duotonePalette: DuotoneColor[]; +}; + +export type MultiplePalettesProps = { + defaultDark: string; + defaultLight: string; + unsetable?: boolean; + colorPalette: Color[]; + disableCustomColors?: boolean; + disableCustomDuotone?: boolean; + value?: string[] | 'unset'; + unsetOption: React.ReactElement; + onChange: ( value: DuotonePickerProps[ 'value' ] | undefined ) => void; + duotonePaletteByOrigin: duotonePaletteByOrigin; +}; + +export type paletteOptionsProps = { + palette: DuotoneColor[]; + value?: string[] | 'unset'; + onChange: ( value: DuotonePickerProps[ 'value' ] | undefined ) => void; +};