Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { createHigherOrderComponent } from '@wordpress/compose';
* Internal dependencies
*/
import { useSettings } from '../use-settings';
import useColorSchemePresets from '../colors-gradients/use-color-scheme-presets';

export default createHigherOrderComponent( ( WrappedComponent ) => {
return function WithColorContext( props ) {
Expand All @@ -24,14 +25,18 @@ export default createHigherOrderComponent( ( WrappedComponent ) => {
'color.custom',
'color.defaultPalette'
);
const { presets: currentThemeColors } = useColorSchemePresets(
'palette',
themeColors
);

const _colors = enableDefaultColors
? [
...( themeColors || [] ),
...( currentThemeColors || [] ),
...( defaultColors || [] ),
...( customColors || [] ),
]
: [ ...( themeColors || [] ), ...( customColors || [] ) ];
: [ ...( currentThemeColors || [] ), ...( customColors || [] ) ];

const { colors = _colors, disableCustomColors = ! enableCustomColors } =
props;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/**
* WordPress dependencies
*/
import { useMediaQuery } from '@wordpress/compose';
import { renderHook } from '@testing-library/react';

/**
* Internal dependencies
*/
import { useSettings } from '../../use-settings';
import useColorSchemePresets from '../use-color-scheme-presets';

jest.mock( '@wordpress/compose', () => ( {
...jest.requireActual( '@wordpress/compose' ),
useMediaQuery: jest.fn(),
} ) );

jest.mock( '../../use-settings', () => ( {
useSettings: jest.fn(),
} ) );

const baseColors = [
{ slug: 'base', name: 'Base', color: '#fff' },
{ slug: 'accent', name: 'Accent', color: '#f00' },
];

describe( 'useColorSchemePresets', () => {
beforeEach( () => {
useSettings.mockReset();
useMediaQuery.mockReset();
} );

it( 'returns a complete dark palette for a partial alternative', () => {
useSettings.mockReturnValue( [
undefined,
[
{ slug: 'base', color: '#111' },
{ slug: 'unknown', color: '#f0f' },
],
] );
useMediaQuery.mockImplementation( ( query ) =>
query.includes( 'dark' )
);

const { result } = renderHook( () =>
useColorSchemePresets( 'palette', baseColors )
);

expect( result.current ).toEqual( {
colorScheme: 'dark',
hasColorSchemes: true,
presets: [
{ slug: 'base', name: 'Base', color: '#111' },
{ slug: 'accent', name: 'Accent', color: '#f00' },
],
} );
} );

it( 'uses the base palette when the available scheme does not match', () => {
useSettings.mockReturnValue( [
undefined,
[ { slug: 'base', color: '#111' } ],
] );
useMediaQuery.mockImplementation( ( query ) =>
query.includes( 'light' )
);

const { result } = renderHook( () =>
useColorSchemePresets( 'palette', baseColors )
);

expect( result.current ).toEqual( {
colorScheme: undefined,
hasColorSchemes: true,
presets: baseColors,
} );
} );
} );
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* WordPress dependencies
*/
import { useMediaQuery } from '@wordpress/compose';
import { normalizeColorSchemePresets } from '@wordpress/global-styles-engine';
import { useMemo } from '@wordpress/element';

/**
* Internal dependencies
*/
import { useSettings } from '../use-settings';

/**
* Returns the effective preset list for the current color scheme.
*
* Alternative presets are normalized against the base list by slug. Missing
* alternative values use the base value and unmatched alternative slugs are
* ignored.
*
* @param {'palette'|'gradients'|'duotone'} presetType Color preset type.
* @param {Array} basePresets Complete base presets.
* @return {{ presets: Array, hasColorSchemes: boolean, colorScheme: string|undefined }} Effective presets and scheme metadata.
*/
export default function useColorSchemePresets( presetType, basePresets = [] ) {
const [ lightPresets, darkPresets ] = useSettings(
`color.light.${ presetType }`,
`color.dark.${ presetType }`
);
const prefersLight = useMediaQuery( '(prefers-color-scheme: light)' );
const prefersDark = useMediaQuery( '(prefers-color-scheme: dark)' );

let colorScheme;
let alternativePresets;
if ( prefersDark && darkPresets !== undefined ) {
colorScheme = 'dark';
alternativePresets = darkPresets;
} else if ( prefersLight && lightPresets !== undefined ) {
colorScheme = 'light';
alternativePresets = lightPresets;
}

const presets = useMemo(
() =>
alternativePresets === undefined
? basePresets
: normalizeColorSchemePresets(
basePresets,
alternativePresets
),
[ alternativePresets, basePresets ]
);

return {
presets,
hasColorSchemes:
lightPresets !== undefined || darkPresets !== undefined,
colorScheme,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { _x } from '@wordpress/i18n';
* Internal dependencies
*/
import { useSettings } from '../use-settings';
import useColorSchemePresets from './use-color-scheme-presets';

/**
* Retrieves color and gradient related settings.
Expand Down Expand Up @@ -46,17 +47,24 @@ export default function useMultipleOriginColorsAndGradients() {
disableCustomColors: ! enableCustomColors,
disableCustomGradients: ! enableCustomGradients,
};
const { presets: currentThemeColors, hasColorSchemes } =
useColorSchemePresets( 'palette', themeColors );
const { presets: currentThemeGradients } = useColorSchemePresets(
'gradients',
themeGradients
);
colorGradientSettings.hasColorSchemes = hasColorSchemes;

colorGradientSettings.colors = useMemo( () => {
const result = [];
if ( themeColors && themeColors.length ) {
if ( currentThemeColors && currentThemeColors.length ) {
result.push( {
name: _x(
'Theme',
'Indicates this palette comes from the theme.'
),
slug: 'theme',
colors: themeColors,
colors: currentThemeColors,
} );
}
if (
Expand Down Expand Up @@ -86,21 +94,21 @@ export default function useMultipleOriginColorsAndGradients() {
return result;
}, [
customColors,
themeColors,
currentThemeColors,
defaultColors,
shouldDisplayDefaultColors,
] );

colorGradientSettings.gradients = useMemo( () => {
const result = [];
if ( themeGradients && themeGradients.length ) {
if ( currentThemeGradients && currentThemeGradients.length ) {
result.push( {
name: _x(
'Theme',
'Indicates this palette comes from the theme.'
),
slug: 'theme',
gradients: themeGradients,
gradients: currentThemeGradients,
} );
}
if (
Expand Down Expand Up @@ -130,7 +138,7 @@ export default function useMultipleOriginColorsAndGradients() {
return result;
}, [
customGradients,
themeGradients,
currentThemeGradients,
defaultGradients,
shouldDisplayDefaultGradients,
] );
Expand Down
9 changes: 7 additions & 2 deletions packages/block-editor/src/components/colors/with-colors.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
} from './utils';
import { useSettings } from '../use-settings';
import { unlock } from '../../lock-unlock';
import useColorSchemePresets from '../colors-gradients/use-color-scheme-presets';

const { kebabCase } = unlock( componentsPrivateApis );

Expand Down Expand Up @@ -62,13 +63,17 @@ const withEditorColorPalette = () =>
'color.palette.theme',
'color.palette.default'
);
const { presets: currentThemePalette } = useColorSchemePresets(
'palette',
themePalette
);
const allColors = useMemo(
() => [
...( userPalette || [] ),
...( themePalette || [] ),
...( currentThemePalette || [] ),
...( defaultPalette || [] ),
],
[ userPalette, themePalette, defaultPalette ]
[ userPalette, currentThemePalette, defaultPalette ]
);
return <WrappedComponent { ...props } colors={ allColors } />;
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { useColorsPerOrigin } from './hooks';
import { useToolsPanelDropdownMenuProps } from './utils';
import { setImmutably } from '../../utils/object';
import { useBorderPanelLabel } from '../../hooks/border';
import { extractPresetSlug } from '../../utils/color-values';
import { ShadowPopover, useShadowPresets } from './shadow-panel-components';
import {
getInheritanceProps,
Expand Down Expand Up @@ -111,10 +112,24 @@ export default function BorderPanel( {
} ) {
const colors = useColorsPerOrigin( settings );
const areCustomSolidsEnabled = settings?.color?.custom;
const allColors = useMemo(
() => colors.flatMap( ( { colors: originColors } ) => originColors ),
[ colors ]
);
const decodeValue = useCallback(
( rawValue ) => getValueFromVariable( { settings }, '', rawValue ),
[ settings ]
);
const decodeColorValue = useCallback(
( rawValue ) => {
const slug = extractPresetSlug( rawValue, 'color' );
return (
allColors.find( ( color ) => color.slug === slug )?.color ??
decodeValue( rawValue )
);
},
[ allColors, decodeValue ]
);
// Always keep the layout className (e.g. `single-column`); only the
// inheritance treatment is gated on `showInheritanceLabelIndicators`.
const inheritanceProps = ( isInherited, hasLocalOverride, className ) =>
Expand All @@ -124,9 +139,6 @@ export default function BorderPanel( {
className
);
const encodeColorValue = ( colorValue ) => {
const allColors = colors.flatMap(
( { colors: originColors } ) => originColors
);
const colorObject = allColors.find(
( { color } ) => color === colorValue
);
Expand All @@ -145,17 +157,19 @@ export default function BorderPanel( {
[ 'top', 'right', 'bottom', 'left' ].forEach( ( side ) => {
out[ side ] = {
...out[ side ],
color: decodeValue( out[ side ]?.color ),
color: decodeColorValue( out[ side ]?.color ),
};
} );
return out;
}
return {
...source,
color: source.color ? decodeValue( source.color ) : undefined,
color: source.color
? decodeColorValue( source.color )
: undefined,
};
},
[ decodeValue ]
[ decodeColorValue ]
);
// Local-then-inherited: prefer the user's locally-set border (whether
// flat or split) when defined, otherwise fall back to the inherited
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@ import {
} from '@wordpress/components';
import { __, _x } from '@wordpress/i18n';
import { useCallback, useMemo, useRef } from '@wordpress/element';
import { useMediaQuery } from '@wordpress/compose';
import { reset as resetIcon } from '@wordpress/icons';
import { getValueFromVariable } from '@wordpress/global-styles-engine';
import {
getValueFromVariable,
normalizeColorSchemePresets,
} from '@wordpress/global-styles-engine';

/**
* Internal dependencies
Expand All @@ -49,13 +53,26 @@ function useMultiOriginColorPresets(
settings?.color?.[ presetSetting ]?.theme || EMPTY_ARRAY;
const defaultPresets =
settings?.color?.[ presetSetting ]?.default || EMPTY_ARRAY;
const lightPresets = settings?.color?.light?.[ presetSetting ];
const darkPresets = settings?.color?.dark?.[ presetSetting ];
const prefersLight = useMediaQuery( '(prefers-color-scheme: light)' );
const prefersDark = useMediaQuery( '(prefers-color-scheme: dark)' );
const currentThemePresets = useMemo( () => {
if ( prefersDark && darkPresets !== undefined ) {
return normalizeColorSchemePresets( themePresets, darkPresets );
}
if ( prefersLight && lightPresets !== undefined ) {
return normalizeColorSchemePresets( themePresets, lightPresets );
}
return themePresets;
}, [ darkPresets, lightPresets, prefersDark, prefersLight, themePresets ] );
return useMemo(
() => [
...userPresets,
...themePresets,
...currentThemePresets,
...( disableDefault ? EMPTY_ARRAY : defaultPresets ),
],
[ disableDefault, userPresets, themePresets, defaultPresets ]
[ currentThemePresets, defaultPresets, disableDefault, userPresets ]
);
}

Expand Down Expand Up @@ -189,8 +206,19 @@ export default function FiltersPanel( {
defaultControls = DEFAULT_CONTROLS,
showInheritanceLabelIndicators = ENABLE_GLOBAL_STYLES_INHERITANCE,
} ) {
const decodeValue = ( rawValue ) =>
getValueFromVariable( { settings }, '', rawValue );
const decodeValue = ( rawValue ) => {
const duotonePrefix = 'var:preset|duotone|';
if ( rawValue?.startsWith?.( duotonePrefix ) ) {
const slug = rawValue.slice( duotonePrefix.length );
const preset = duotonePalette.find(
( duotone ) => duotone.slug === slug
);
if ( preset ) {
return preset.colors;
}
}
return getValueFromVariable( { settings }, '', rawValue );
};
// Always keep the layout className (e.g. `single-column`); only the
// inheritance treatment is gated on `showInheritanceLabelIndicators`.
const inheritanceProps = ( isInherited, hasLocalOverride, className ) =>
Expand Down
Loading
Loading