From 117e69c48362a70d5240b82b868c99ef2ddd02a5 Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Thu, 11 Jan 2024 05:05:15 -0600 Subject: [PATCH] Add defaultFontSizes option to theme.json (#56661) * Add defaultFontSizes option for theme.json * Fix defaultFontSizes causing errors when missing * Simplify useMergedSettings * Simplify more * Remove the memo because it's probably fine * Try ignoring how overrides are handled in the dropdown * Minor performance improvement using reverse instead of toReversed * Link to a new issue with a more complete description * Refactor hack into its own funtion --- .../theme-json-reference/theme-json-living.md | 1 + lib/class-wp-theme-json-gutenberg.php | 29 +++++----- lib/theme.json | 1 + .../src/components/global-styles/hooks.js | 2 + .../global-styles/typography-panel.js | 58 ++++++++++++++----- packages/block-editor/src/hooks/utils.js | 20 +++++-- packages/block-editor/src/utils/object.js | 16 +++++ schemas/json/theme.json | 5 ++ 8 files changed, 101 insertions(+), 31 deletions(-) diff --git a/docs/reference-guides/theme-json-reference/theme-json-living.md b/docs/reference-guides/theme-json-reference/theme-json-living.md index c58b8b3239f33e..d9389597b89da2 100644 --- a/docs/reference-guides/theme-json-reference/theme-json-living.md +++ b/docs/reference-guides/theme-json-reference/theme-json-living.md @@ -177,6 +177,7 @@ Settings related to typography. | Property | Type | Default | Props | | --- | --- | --- |--- | +| defaultFontSizes | boolean | true | | | customFontSize | boolean | true | | | fontStyle | boolean | true | | | fontWeight | boolean | true | | diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index 0d2520ff9682a4..7c75a3de8d46f6 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -151,7 +151,7 @@ class WP_Theme_JSON_Gutenberg { ), array( 'path' => array( 'typography', 'fontSizes' ), - 'prevent_override' => false, + 'prevent_override' => array( 'typography', 'defaultFontSizes' ), 'use_default_names' => true, 'value_func' => 'gutenberg_get_typography_font_size_value', 'css_vars' => '--wp--preset--font-size--$slug', @@ -409,19 +409,20 @@ class WP_Theme_JSON_Gutenberg { 'defaultPresets' => null, ), 'typography' => array( - 'fluid' => null, - 'customFontSize' => null, - 'dropCap' => null, - 'fontFamilies' => null, - 'fontSizes' => null, - 'fontStyle' => null, - 'fontWeight' => null, - 'letterSpacing' => null, - 'lineHeight' => null, - 'textColumns' => null, - 'textDecoration' => null, - 'textTransform' => null, - 'writingMode' => null, + 'fluid' => null, + 'customFontSize' => null, + 'defaultFontSizes' => null, + 'dropCap' => null, + 'fontFamilies' => null, + 'fontSizes' => null, + 'fontStyle' => null, + 'fontWeight' => null, + 'letterSpacing' => null, + 'lineHeight' => null, + 'textColumns' => null, + 'textDecoration' => null, + 'textTransform' => null, + 'writingMode' => null, ), ); diff --git a/lib/theme.json b/lib/theme.json index c2ed7fdca39ed5..b7bc3cb89e60f2 100644 --- a/lib/theme.json +++ b/lib/theme.json @@ -236,6 +236,7 @@ }, "typography": { "customFontSize": true, + "defaultFontSizes": true, "dropCap": true, "fontSizes": [ { diff --git a/packages/block-editor/src/components/global-styles/hooks.js b/packages/block-editor/src/components/global-styles/hooks.js index 6be5481a633daa..7c5cf4cbf3e0fa 100644 --- a/packages/block-editor/src/components/global-styles/hooks.js +++ b/packages/block-editor/src/components/global-styles/hooks.js @@ -67,6 +67,7 @@ const VALID_SETTINGS = [ 'spacing.units', 'typography.fluid', 'typography.customFontSize', + 'typography.defaultFontSizes', 'typography.dropCap', 'typography.fontFamilies', 'typography.fontSizes', @@ -239,6 +240,7 @@ export function useSettingsForBlockElement( ...updatedSettings.typography, fontSizes: {}, customFontSize: false, + defaultFontSizes: false, }; } diff --git a/packages/block-editor/src/components/global-styles/typography-panel.js b/packages/block-editor/src/components/global-styles/typography-panel.js index e689d84c83c981..79c1d271f4e0a3 100644 --- a/packages/block-editor/src/components/global-styles/typography-panel.js +++ b/packages/block-editor/src/components/global-styles/typography-panel.js @@ -22,7 +22,7 @@ import TextTransformControl from '../text-transform-control'; import TextDecorationControl from '../text-decoration-control'; import WritingModeControl from '../writing-mode-control'; import { getValueFromVariable, TOOLSPANEL_DROPDOWNMENU_PROPS } from './utils'; -import { setImmutably } from '../../utils/object'; +import { setImmutably, uniqByProperty } from '../../utils/object'; const MIN_TEXT_COLUMNS = 1; const MAX_TEXT_COLUMNS = 6; @@ -53,7 +53,10 @@ export function useHasTypographyPanel( settings ) { function useHasFontSizeControl( settings ) { return ( - hasMergedOrigins( settings?.typography?.fontSizes ) || + ( settings?.typography?.defaultFontSizes !== false && + settings?.typography?.fontSizes?.default?.length ) || + settings?.typography?.fontSizes?.theme?.length || + settings?.typography?.fontSizes?.custom?.length || settings?.typography?.customFontSize ); } @@ -100,16 +103,45 @@ function useHasTextColumnsControl( settings ) { return settings?.typography?.textColumns; } -function getUniqueFontSizesBySlug( settings ) { - const fontSizes = settings?.typography?.fontSizes; - const mergedFontSizes = fontSizes ? mergeOrigins( fontSizes ) : []; - const uniqueSizes = []; - for ( const currentSize of mergedFontSizes ) { - if ( ! uniqueSizes.some( ( { slug } ) => slug === currentSize.slug ) ) { - uniqueSizes.push( currentSize ); - } - } - return uniqueSizes; +/** + * TODO: The reversing and filtering of default font sizes is a hack so the + * dropdown UI matches what is generated in the global styles CSS stylesheet. + * + * This is a temporary solution until #57733 is resolved. At which point, + * the mergedFontSizes would just need to be the concatenated array of all + * presets or a custom dropdown with sections for each. + * + * @see {@link https://github.com/WordPress/gutenberg/issues/57733} + * + * @param {Object} settings The global styles settings. + * + * @return {Array} The merged font sizes. + */ +function getMergedFontSizes( settings ) { + // The font size presets are merged in reverse order so that the duplicates + // that may defined later in the array have higher priority to match the CSS. + const mergedFontSizesAll = uniqByProperty( + [ + settings?.typography?.fontSizes?.custom, + settings?.typography?.fontSizes?.theme, + settings?.typography?.fontSizes?.default, + ].flatMap( ( presets ) => presets?.toReversed() ?? [] ), + 'slug' + ).reverse(); + + // Default presets exist in the global styles CSS no matter the setting, so + // filtering them out in the UI has to be done after merging. + const mergedFontSizes = + settings?.typography?.defaultFontSizes === false + ? mergedFontSizesAll.filter( + ( { slug } ) => + ! [ 'small', 'medium', 'large', 'x-large' ].includes( + slug + ) + ) + : mergedFontSizesAll; + + return mergedFontSizes; } function TypographyToolsPanel( { @@ -185,7 +217,7 @@ export default function TypographyPanel( { // Font Size const hasFontSizeEnabled = useHasFontSizeControl( settings ); const disableCustomFontSizes = ! settings?.typography?.customFontSize; - const mergedFontSizes = getUniqueFontSizesBySlug( settings ); + const mergedFontSizes = getMergedFontSizes( settings ); const fontSize = decodeValue( inheritedValue?.typography?.fontSize ); const setFontSize = ( newValue, metadata ) => { diff --git a/packages/block-editor/src/hooks/utils.js b/packages/block-editor/src/hooks/utils.js index 2f7a8f3a81f19d..f13963933e5225 100644 --- a/packages/block-editor/src/hooks/utils.js +++ b/packages/block-editor/src/hooks/utils.js @@ -177,7 +177,10 @@ export function useBlockSettings( name, parentLayout ) { backgroundImage, backgroundSize, fontFamilies, - fontSizes, + userFontSizes, + themeFontSizes, + defaultFontSizes, + defaultFontSizesEnabled, customFontSize, fontStyle, fontWeight, @@ -224,7 +227,10 @@ export function useBlockSettings( name, parentLayout ) { 'background.backgroundImage', 'background.backgroundSize', 'typography.fontFamilies', - 'typography.fontSizes', + 'typography.fontSizes.custom', + 'typography.fontSizes.theme', + 'typography.fontSizes.default', + 'typography.defaultFontSizes', 'typography.customFontSize', 'typography.fontStyle', 'typography.fontWeight', @@ -308,9 +314,12 @@ export function useBlockSettings( name, parentLayout ) { custom: fontFamilies, }, fontSizes: { - custom: fontSizes, + custom: userFontSizes, + theme: themeFontSizes, + default: defaultFontSizes, }, customFontSize, + defaultFontSizes: defaultFontSizesEnabled, fontStyle, fontWeight, lineHeight, @@ -347,7 +356,10 @@ export function useBlockSettings( name, parentLayout ) { backgroundImage, backgroundSize, fontFamilies, - fontSizes, + userFontSizes, + themeFontSizes, + defaultFontSizes, + defaultFontSizesEnabled, customFontSize, fontStyle, fontWeight, diff --git a/packages/block-editor/src/utils/object.js b/packages/block-editor/src/utils/object.js index 8f6c82a9c3991e..c78fe0e656dfef 100644 --- a/packages/block-editor/src/utils/object.js +++ b/packages/block-editor/src/utils/object.js @@ -49,3 +49,19 @@ export const getValueFromObjectPath = ( object, path, defaultValue ) => { } ); return value ?? defaultValue; }; + +/** + * Helper util to filter out objects with duplicate values for a given property. + * + * @param {Object[]} array Array of objects to filter. + * @param {string} property Property to filter unique values by. + * + * @return {Object[]} Array of objects with unique values for the specified property. + */ +export function uniqByProperty( array, property ) { + const seen = new Set(); + return array.filter( ( item ) => { + const value = item[ property ]; + return seen.has( value ) ? false : seen.add( value ); + } ); +} diff --git a/schemas/json/theme.json b/schemas/json/theme.json index 8ec1de58478b8d..64e32b4da9df88 100644 --- a/schemas/json/theme.json +++ b/schemas/json/theme.json @@ -489,6 +489,11 @@ "description": "Settings related to typography.", "type": "object", "properties": { + "defaultFontSizes": { + "description": "Allow users to choose font sizes from the default font size presets.", + "type": "boolean", + "default": true + }, "customFontSize": { "description": "Allow users to set custom font sizes.", "type": "boolean",