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 24a5845381bfd..65f7f54892b22 100644 --- a/docs/reference-guides/theme-json-reference/theme-json-living.md +++ b/docs/reference-guides/theme-json-reference/theme-json-living.md @@ -176,6 +176,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 9311001f2edd1..33d1ca6851d1b 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -155,7 +155,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', @@ -410,19 +410,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 671dd50227852..3605a7fc1fe67 100644 --- a/lib/theme.json +++ b/lib/theme.json @@ -235,6 +235,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 356ff4dce57a9..66f01a431adc0 100644 --- a/packages/block-editor/src/components/global-styles/hooks.js +++ b/packages/block-editor/src/components/global-styles/hooks.js @@ -63,6 +63,7 @@ const VALID_SETTINGS = [ 'spacing.units', 'typography.fluid', 'typography.customFontSize', + 'typography.defaultFontSizes', 'typography.dropCap', 'typography.fontFamilies', 'typography.fontSizes', @@ -235,6 +236,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 103b1e63b75b5..3c67350c77dcb 100644 --- a/packages/block-editor/src/components/global-styles/typography-panel.js +++ b/packages/block-editor/src/components/global-styles/typography-panel.js @@ -8,7 +8,7 @@ import { __experimentalToolsPanelItem as ToolsPanelItem, } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import { useCallback } from '@wordpress/element'; +import { useCallback, useMemo } from '@wordpress/element'; /** * Internal dependencies @@ -22,7 +22,7 @@ import TextTransformControl from '../text-transform-control'; import TextDecorationControl from '../text-decoration-control'; import WritingModeControl from '../writing-mode-control'; import { getValueFromVariable } from './utils'; -import { setImmutably } from '../../utils/object'; +import { setImmutably, uniqByProperty } from '../../utils/object'; const MIN_TEXT_COLUMNS = 1; const MAX_TEXT_COLUMNS = 6; @@ -51,10 +51,10 @@ export function useHasTypographyPanel( settings ) { ); } -function useHasFontSizeControl( settings ) { +function useHasFontSizeControl( mergedSettings ) { return ( - hasMergedOrigins( settings?.typography?.fontSizes ) || - settings?.typography?.customFontSize + mergedSettings?.typography?.fontSizes?.length || + mergedSettings?.typography?.customFontSize ); } @@ -100,18 +100,6 @@ 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; -} - function TypographyToolsPanel( { resetAllFilter, onChange, @@ -147,6 +135,39 @@ const DEFAULT_CONTROLS = { textColumns: true, }; +function useMergedSettings( parentSettings ) { + return useMemo( () => { + const updatedSettings = { ...parentSettings }; + + // Remove default font sizes if disabled. + if ( + updatedSettings?.typography?.defaultFontSizes === false && + updatedSettings?.typography?.fontSizes?.default + ) { + updatedSettings.typography = { + ...updatedSettings.typography, + fontSizes: { + custom: updatedSettings.typography.fontSizes.custom, + theme: updatedSettings.typography.fontSizes.theme, + }, + }; + } + + // Merge origins and remove duplicates. + if ( updatedSettings?.typography?.fontSizes ) { + updatedSettings.typography.fontSizes = mergeOrigins( + updatedSettings.typography.fontSizes + ); + updatedSettings.typography.fontSizes = uniqByProperty( + updatedSettings.typography.fontSizes, + 'slug' + ); + } + + return updatedSettings; + }, [ parentSettings ] ); +} + export default function TypographyPanel( { as: Wrapper = TypographyToolsPanel, value, @@ -159,6 +180,8 @@ export default function TypographyPanel( { const decodeValue = ( rawValue ) => getValueFromVariable( { settings }, '', rawValue ); + const mergedSettings = useMergedSettings( settings ); + // Font Family const hasFontFamilyEnabled = useHasFontFamilyControl( settings ); const fontFamilies = settings?.typography?.fontFamilies; @@ -182,9 +205,9 @@ export default function TypographyPanel( { const resetFontFamily = () => setFontFamily( undefined ); // Font Size - const hasFontSizeEnabled = useHasFontSizeControl( settings ); - const disableCustomFontSizes = ! settings?.typography?.customFontSize; - const mergedFontSizes = getUniqueFontSizesBySlug( settings ); + const hasFontSizeEnabled = useHasFontSizeControl( mergedSettings ); + const disableCustomFontSizes = ! mergedSettings?.typography?.customFontSize; + const fontSizes = mergedSettings?.typography?.fontSizes; const fontSize = decodeValue( inheritedValue?.typography?.fontSize ); const setFontSize = ( newValue, metadata ) => { @@ -367,7 +390,7 @@ export default function TypographyPanel( { { } ); 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 782e59794a5d1..ae59f289bd6c5 100644 --- a/schemas/json/theme.json +++ b/schemas/json/theme.json @@ -484,6 +484,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",