Skip to content
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

Improve ThemeJSON handling #545

Merged
merged 5 commits into from
Jul 11, 2023
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
7 changes: 7 additions & 0 deletions .changeset/bright-jokes-learn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@headstartwp/core": patch
---

Fix theme.json handling in `useBlockColors` and `useBlockTypography`.

Thanks @riccardodicurti @dhamibirendra for [the bug report](https://github.com/10up/headstartwp/issues/541).
27 changes: 18 additions & 9 deletions packages/core/src/react/blocks/hooks/useBlockColors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,26 @@ export function useBlockColors(node: Element) {

const defaultColorsSettings = useThemeSetting('color.palette.default', null, []);
const defaultGradientsSettings = useThemeSetting('color.palette.default', null, []);
const themeColorsSettings = useThemeSetting('color.palette.theme', null, []);
const themeGradientsSettings = useThemeSetting('color.palette.theme', null, []);
const userColorsSettings = useThemeSetting('color.palette.user', null, []);
const userGradientsSettings = useThemeSetting('color.palette.user', null, []);

const colorsSettings = useThemeSetting('color.palette', name, []);
const gradientsSettings = useThemeSetting('color.gradients', name, []);
const blockColorsSettings = useThemeSetting('color.palette', name, [], false);
const blockGradientsSettings = useThemeSetting('color.gradients', name, [], false);

const colors = Array.isArray(colorsSettings) ? colorsSettings : colorsSettings?.theme;
const gradients = Array.isArray(gradientsSettings)
? gradientsSettings
: gradientsSettings?.theme ?? [];

const allGradients = [...defaultGradientsSettings, ...gradients];
const allColors = [...defaultColorsSettings, ...colors];
const allGradients = [
...blockGradientsSettings,
...userGradientsSettings,
...themeGradientsSettings,
...defaultGradientsSettings,
];
const allColors = [
...blockColorsSettings,
...userColorsSettings,
...themeColorsSettings,
...defaultColorsSettings,
];

const color: Colors = {
backgroundColorSlug: '',
Expand Down
17 changes: 10 additions & 7 deletions packages/core/src/react/blocks/hooks/useBlockTypography.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ interface BlockTypographyAttributes extends IBlockAttributes {
export function useBlockTypography(node: Element): Typography {
const { name, attributes } = useBlock<BlockTypographyAttributes>(node);
const defaultFontSizesSettings = useThemeSetting('typography.fontSizes.default', null, []);
const fontSizesSettings = useThemeSetting('typography.fontSizes', name, []);
const themeFontSizesSettings = useThemeSetting('typography.fontSizes.default', null, []);
const userFontSizesSettings = useThemeSetting('typography.fontSizes.default', null, []);
const blockFontSizesSettings = useThemeSetting('typography.fontSizes', name, [], false);

const supportsCustomFontSize = !!useThemeSetting('typography.customFontSize', name);
const supportsFontStyle = !!useThemeSetting('typography.fontStyle', name);
const supportsFontWeight = !!useThemeSetting('typography.fontWeight', name);
Expand All @@ -33,12 +36,12 @@ export function useBlockTypography(node: Element): Typography {
const supportsTextDecoration = !!useThemeSetting('typography.textDecoration', name);
const supportsTextTransform = !!useThemeSetting('typography.textTransform', name);

// either use the block settings or try the theme or default one
const fontSizes = Array.isArray(fontSizesSettings)
? fontSizesSettings
: fontSizesSettings?.theme;

const allFontSizes = [...defaultFontSizesSettings, ...fontSizes];
const allFontSizes = [
...blockFontSizesSettings,
...userFontSizesSettings,
...themeFontSizesSettings,
...defaultFontSizesSettings,
];

const fontSizePreset = attributes?.fontSize;

Expand Down
109 changes: 109 additions & 0 deletions packages/core/src/react/provider/__tests__/useThemeSetting.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import * as React from 'react';
import { renderHook } from '@testing-library/react';
import { useThemeSetting } from '../useThemeSetting';
import { ThemeSettingsProvider } from '../ThemeSettingsProvider';

describe('useThemeSetting', () => {
test('it returns default value if no context it set', () => {
const { result } = renderHook(() => useThemeSetting('color.palette', null, []));

expect(result.current).toEqual([]);
});

test('it returns default values if context is set but setting does not exit', () => {
const wrapper = ({ children }) => (
<ThemeSettingsProvider data={{ settings: { color: { background: true } } }}>
{children}
</ThemeSettingsProvider>
);

const { result: result1 } = renderHook(() => useThemeSetting('color.custom', null, false), {
wrapper,
});

expect(result1.current).toBe(false);

const { result: result2 } = renderHook(
() => useThemeSetting('color.background', null, false),
{
wrapper,
},
);

expect(result2.current).toBe(true);

const { result: result3 } = renderHook(
() => useThemeSetting('color.unknown', 'core/button', 'default value'),
{
wrapper,
},
);

expect(result3.current).toBe('default value');
});

test('it returns values from settings', () => {
const defaultPallete = [
{
name: 'Black',
slug: 'black',
color: '#000000',
},
{
name: 'Cyan bluish gray',
slug: 'cyan-bluish-gray',
color: '#abb8c3',
},
];

const blockPallete = [
{
name: 'white',
slug: 'white',
color: '#FFF',
},
];
const wrapper = ({ children }) => (
<ThemeSettingsProvider
data={{
settings: {
color: {
palette: {
// TODO: fix theme json ts types
// @ts-expect-error
default: defaultPallete,
},
},

blocks: {
'core/button': {
color: {
palette: blockPallete,
},
},
},
},
}}
>
{children}
</ThemeSettingsProvider>
);
const { result: result1 } = renderHook(
() => useThemeSetting('color.palette.default', null, []),
{
wrapper,
},
);

expect(result1.current).toMatchObject(defaultPallete);

const { result: result2 } = renderHook(
() => useThemeSetting('color.palette', 'core/button', []),
{
wrapper,
},
);

expect(result2.current).toMatchObject(blockPallete);
});
});
90 changes: 48 additions & 42 deletions packages/core/src/react/provider/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,51 @@ export type StylesPropertiesAndElementsComplete = StylesProperties & {
elements?: StylesElementsPropertiesComplete;
};

export type SettingsColorPreset = {
/**
* Name of the color preset, translatable.
*/
name: string;
/**
* Kebab-case unique identifier for the color preset.
*/
slug: string;
/**
* CSS hex or rgb(a) string.
*/
color: string;
};

export type SettingsGradientPreset = {
/**
* Name of the gradient preset, translatable.
*/
name: string;
/**
* Kebab-case unique identifier for the gradient preset.
*/
slug: string;
/**
* CSS gradient string.
*/
gradient: string;
};

export type SettingsDuotonePreset = {
/**
* Name of the duotone preset, translatable.
*/
name: string;
/**
* Kebab-case unique identifier for the duotone preset.
*/
slug: string;
/**
* List of colors from dark to light.
*/
colors: string[];
};

export interface WpThemeJSON {
/**
* JSON schema URI for theme.json.
Expand Down Expand Up @@ -346,38 +391,12 @@ export interface SettingsProperties {
* Duotone presets for the duotone picker.
* Doesn't generate classes or properties.
*/
duotone?: {
/**
* Name of the duotone preset, translatable.
*/
name: string;
/**
* Kebab-case unique identifier for the duotone preset.
*/
slug: string;
/**
* List of colors from dark to light.
*/
colors: string[];
}[];
duotone?: SettingsDuotonePreset[];
/**
* Gradient presets for the gradient picker.
* Generates a single class (`.has-{slug}-background`) and custom property (`--wp--preset--gradient--{slug}`) per preset value.
*/
gradients?: {
/**
* Name of the gradient preset, translatable.
*/
name: string;
/**
* Kebab-case unique identifier for the gradient preset.
*/
slug: string;
/**
* CSS gradient string.
*/
gradient: string;
}[];
gradients?: SettingsGradientPreset[];
/**
* Allow users to set link colors.
*/
Expand All @@ -386,20 +405,7 @@ export interface SettingsProperties {
* Color palette presets for the color picker.
* Generates three classes (`.has-{slug}-color`, `.has-{slug}-background-color`, and `.has-{slug}-border-color`) and a single custom property (`--wp--preset--color--{slug}`) per preset value.
*/
palette?: {
/**
* Name of the color preset, translatable.
*/
name: string;
/**
* Kebab-case unique identifier for the color preset.
*/
slug: string;
/**
* CSS hex or rgb(a) string.
*/
color: string;
}[];
palette?: SettingsColorPreset[];
/**
* Allow users to set text colors.
*/
Expand Down
8 changes: 8 additions & 0 deletions packages/core/src/react/provider/useThemeSetting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,26 @@ const get = (obj, path, defaultValue: any = undefined) => {
*
* @param path - The path to the setting
* @param blockName - The block name
* @param defaultValue the default value to return
* @param fallbackToGlobalSetting Whether it should fallback to global setting if blockName is passed but setting does not exist
* @returns
*/
export function useThemeSetting(
path: string,
blockName: string | null = '',
defaultValue: any = '',
fallbackToGlobalSetting = true,
) {
const settings = useThemeSettings();

if (blockName && get(settings, `blocks.${blockName}.${path}`)) {
return get(settings, `blocks.${blockName}.${path}`);
}

// if blockName is set but doesn't have the setting and we should not fallback, return the default value only
if (blockName && !fallbackToGlobalSetting) {
return defaultValue;
}

return get(settings, path, defaultValue);
}
Loading