From 5901eaa8b699ed1bbde4353769da0142f6c16b5d Mon Sep 17 00:00:00 2001 From: ramonjd Date: Thu, 17 Mar 2022 17:13:32 +1100 Subject: [PATCH 01/24] Initial commit --- lib/block-supports/typography.php | 47 ++++++++ .../wordpress-6.0/class-wp-theme-json-6-0.php | 108 ++++++++++++++++++ 2 files changed, 155 insertions(+) diff --git a/lib/block-supports/typography.php b/lib/block-supports/typography.php index 00ea2b17ac178e..fe6cc3f4c337aa 100644 --- a/lib/block-supports/typography.php +++ b/lib/block-supports/typography.php @@ -222,6 +222,53 @@ function gutenberg_typography_get_css_variable_inline_style( $attributes, $featu return sprintf( '%s:var(--wp--preset--%s--%s);', $css_property, $css_property, $slug ); } +function gutenberg_get_typography_font_size_value( $preset ) { + // This is where we'll keep options I guess. + // Comment out to show how things work. + $typography_settings = gutenberg_get_global_settings( array( 'typography' ) ); + +// if ( ! isset( $typography_settings['fluid'] ) ) { +// return $preset['size']; +// } + + // Should be defined by theme.json, maybe take from layout? + $minimum_viewport_width = 640 / 16; // rem for now. 1200(px) / 16 to get rem. + $maximum_viewport_width = 1600 / 16; // Ditto. + + /* + Up next; + - Challenge: looping through fontSizes and calculating clamp functions for every size relies preferably on rem/px or unitless values. + - Apply this to custom font-size values. + */ + + // Matches rem or unitless values only. + $pattern = '/^(\d*\.?\d+)(rem|px)?$/'; + preg_match_all( $pattern, $preset['size'], $matches ); + + if ( isset( $matches[1][0] ) ) { + $base_value = intval( $matches[1][0] ); + + if ( isset( $matches[2][0] ) && 'px' === $matches[2][0] ) { + // Calculate rem to px. + + $base_value = $base_value / 16; + } + + $minimum_font_size = $base_value * 1; // A min value should ideally be coming from theme.json. + $maximum_font_size = $base_value * 1.5; // Ditto on the max. + $factor = ( 1 / ( $maximum_viewport_width - $minimum_viewport_width ) ) * ( $maximum_font_size - $minimum_font_size ); + $calc_rem = $minimum_font_size - ( $minimum_viewport_width * $factor ); + $calc_vw = 100 * $factor; + $min = min( $minimum_font_size, $maximum_font_size ); + $max = max( $minimum_font_size, $maximum_font_size ); + + return "clamp({$min}rem, {$calc_rem}rem + {$calc_vw}vw, {$max}rem)"; + + } else { + return $preset['size']; + } +} + // Register the block support. WP_Block_Supports::get_instance()->register( 'typography', diff --git a/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php b/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php index 878ac30c1b2c7d..bd13946c899cce 100644 --- a/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php +++ b/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php @@ -169,6 +169,114 @@ class WP_Theme_JSON_6_0 extends WP_Theme_JSON { ), ); + /** + * Presets are a set of values that serve + * to bootstrap some styles: colors, font sizes, etc. + * + * They are a unkeyed array of values such as: + * + * ```php + * array( + * array( + * 'slug' => 'unique-name-within-the-set', + * 'name' => 'Name for the UI', + * => 'value' + * ), + * ) + * ``` + * + * This contains the necessary metadata to process them: + * + * - path => Where to find the preset within the settings section. + * - prevent_override => Whether a theme preset with the same slug as a default preset + * should not override it or the path to a setting for the same + * When defaults. + * The relationship between whether to override the defaults + * and whether the defaults are enabled is inverse: + * - If defaults are enabled => theme presets should not be overriden + * - If defaults are disabled => theme presets should be overriden + * For example, a theme sets defaultPalette to false, + * making the default palette hidden from the user. + * In that case, we want all the theme presets to be present, + * so they should override the defaults by setting this false. + * - value_key => the key that represents the value + * - value_func => optionally, instead of value_key, a function to generate + * the value that takes a preset as an argument + * (either value_key or value_func should be present) + * - css_vars => template string to use in generating the CSS Custom Property. + * Example output: "--wp--preset--duotone--blue: " will generate as many CSS Custom Properties as presets defined + * substituting the $slug for the slug's value for each preset value. + * - classes => array containing a structure with the classes to + * generate for the presets, where for each array item + * the key is the class name and the value the property name. + * The "$slug" substring will be replaced by the slug of each preset. + * For example: + * 'classes' => array( + * '.has-$slug-color' => 'color', + * '.has-$slug-background-color' => 'background-color', + * '.has-$slug-border-color' => 'border-color', + * ) + * - properties => array of CSS properties to be used by kses to + * validate the content of each preset + * by means of the remove_insecure_properties method. + */ + const PRESETS_METADATA = array( + array( + 'path' => array( 'color', 'palette' ), + 'prevent_override' => array( 'color', 'defaultPalette' ), + 'use_default_presets' => array( 'color', 'defaultPalette' ), + 'use_default_names' => false, + 'value_key' => 'color', + 'css_vars' => '--wp--preset--color--$slug', + 'classes' => array( + '.has-$slug-color' => 'color', + '.has-$slug-background-color' => 'background-color', + '.has-$slug-border-color' => 'border-color', + ), + 'properties' => array( 'color', 'background-color', 'border-color' ), + ), + array( + 'path' => array( 'color', 'gradients' ), + 'prevent_override' => array( 'color', 'defaultGradients' ), + 'use_default_presets' => array( 'color', 'defaultGradients' ), + 'use_default_names' => false, + 'value_key' => 'gradient', + 'css_vars' => '--wp--preset--gradient--$slug', + 'classes' => array( '.has-$slug-gradient-background' => 'background' ), + 'properties' => array( 'background' ), + ), + array( + 'path' => array( 'color', 'duotone' ), + 'prevent_override' => array( 'color', 'defaultDuotone' ), + 'use_default_presets' => array( 'color', 'defaultDuotone' ), + 'use_default_names' => false, + 'value_func' => 'gutenberg_get_duotone_filter_property', + 'css_vars' => '--wp--preset--duotone--$slug', + 'classes' => array(), + 'properties' => array( 'filter' ), + ), + array( + 'path' => array( 'typography', 'fontSizes' ), + 'prevent_override' => false, + 'use_default_presets' => true, + 'use_default_names' => true, + 'value_func' => 'gutenberg_get_typography_font_size_value', + 'css_vars' => '--wp--preset--font-size--$slug', + 'classes' => array( '.has-$slug-font-size' => 'font-size' ), + 'properties' => array( 'font-size' ), + ), + array( + 'path' => array( 'typography', 'fontFamilies' ), + 'prevent_override' => false, + 'use_default_presets' => true, + 'use_default_names' => false, + 'value_key' => 'fontFamily', + 'css_vars' => '--wp--preset--font-family--$slug', + 'classes' => array( '.has-$slug-font-family' => 'font-family' ), + 'properties' => array( 'font-family' ), + ), + ); + /** * The top-level keys a theme.json can have. * From 7cb5b0908f7d068bfd7aacbfad11b9cdfc914406 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Thu, 17 Mar 2022 17:16:54 +1100 Subject: [PATCH 02/24] Enabling fluid type in theme.json Only allowing rem and px --- lib/block-supports/typography.php | 78 +++++++++++++------ .../wordpress-6.0/class-wp-theme-json-6-0.php | 53 +++++++++++++ schemas/json/theme.json | 14 ++++ 3 files changed, 121 insertions(+), 24 deletions(-) diff --git a/lib/block-supports/typography.php b/lib/block-supports/typography.php index fe6cc3f4c337aa..3596d74d1f6f70 100644 --- a/lib/block-supports/typography.php +++ b/lib/block-supports/typography.php @@ -222,40 +222,71 @@ function gutenberg_typography_get_css_variable_inline_style( $attributes, $featu return sprintf( '%s:var(--wp--preset--%s--%s);', $css_property, $css_property, $slug ); } +/** + * Returns a font-size value based on a given font-size preset. If typography.fluid is enabled it will calculate clamp values. + * + * @param array $preset Duotone preset value as seen in theme.json. + * @return string Font-size value. + */ function gutenberg_get_typography_font_size_value( $preset ) { - // This is where we'll keep options I guess. - // Comment out to show how things work. $typography_settings = gutenberg_get_global_settings( array( 'typography' ) ); -// if ( ! isset( $typography_settings['fluid'] ) ) { -// return $preset['size']; -// } - - // Should be defined by theme.json, maybe take from layout? - $minimum_viewport_width = 640 / 16; // rem for now. 1200(px) / 16 to get rem. - $maximum_viewport_width = 1600 / 16; // Ditto. + // This is where we'll keep options I guess. + if ( ! isset( $typography_settings['fluid'] ) ) { + return $preset['size']; + } - /* - Up next; - - Challenge: looping through fontSizes and calculating clamp functions for every size relies preferably on rem/px or unitless values. - - Apply this to custom font-size values. - */ + // Up for discussion. + $default_unit = 'rem'; + $default_minimum_viewport_width = '1600px'; + $default_maximum_viewport_width = '650px'; - // Matches rem or unitless values only. + // Matches rem or px values only. $pattern = '/^(\d*\.?\d+)(rem|px)?$/'; - preg_match_all( $pattern, $preset['size'], $matches ); + // Could we also take these from layout? contentSize and wideSize? + $minimum_viewport_width = isset( $typography_settings['minViewportWidth'] ) ? $typography_settings['minViewportWidth'] : $default_minimum_viewport_width; + $minimum_viewport_width_unit = $default_unit; + $maximum_viewport_width = isset( $typography_settings['maxViewportWidth'] ) ? $typography_settings['maxViewportWidth'] : $default_maximum_viewport_width; + $maximum_viewport_width_unit = $default_unit; + + // Minimum viewport size. + preg_match_all( $pattern, $minimum_viewport_width, $minimum_viewport_width_matches ); + if ( isset( $minimum_viewport_width_matches[1][0] ) ) { + $minimum_viewport_width = intval( $minimum_viewport_width_matches[1][0] ); + $minimum_viewport_width_unit = isset( $minimum_viewport_width_matches[2][0] ) ? $minimum_viewport_width_matches[2][0] : $minimum_viewport_width_unit; + if ( 'px' === $minimum_viewport_width_unit ) { + // Default is rem so we convert px to rem. + $minimum_viewport_width = $minimum_viewport_width / 16; + } + } - if ( isset( $matches[1][0] ) ) { - $base_value = intval( $matches[1][0] ); + // Maximum viewport size. + preg_match_all( $pattern, $maximum_viewport_width, $maximum_viewport_width_matches ); + if ( isset( $maximum_viewport_width_matches[1][0] ) ) { + $maximum_viewport_width = intval( $maximum_viewport_width_matches[1][0] ); + $maximum_viewport_width_unit = isset( $maximum_viewport_width_matches[2][0] ) ? $maximum_viewport_width_matches[2][0] : $maximum_viewport_width_unit; + if ( 'px' === $maximum_viewport_width_unit ) { + // Default is rem so we convert px to rem. + $maximum_viewport_width = $maximum_viewport_width / 16; + } + } - if ( isset( $matches[2][0] ) && 'px' === $matches[2][0] ) { - // Calculate rem to px. + // Font sizes. + preg_match_all( $pattern, $preset['size'], $size_matches ); + if ( isset( $size_matches[1][0] ) ) { + $base_size_value = $size_matches[1][0]; - $base_value = $base_value / 16; + if ( isset( $size_matches[2][0] ) && 'px' === $size_matches[2][0] ) { + // Default is rem so we convert px to rem. + $base_size_value = $base_size_value / 16; } - $minimum_font_size = $base_value * 1; // A min value should ideally be coming from theme.json. - $maximum_font_size = $base_value * 1.5; // Ditto on the max. + // How can we offer control over this? + // Maybe typography.fluid.{min|max}FontSizeFactor. + // Or picking the first and last sizes in the fontSizes array? + // Another option is here to accept fontSizes[0]['min'] and fontSizes[0]['max'] from a preset item. + $minimum_font_size = $base_size_value * 0.9; + $maximum_font_size = $base_size_value * 1.75; $factor = ( 1 / ( $maximum_viewport_width - $minimum_viewport_width ) ) * ( $maximum_font_size - $minimum_font_size ); $calc_rem = $minimum_font_size - ( $minimum_viewport_width * $factor ); $calc_vw = 100 * $factor; @@ -263,7 +294,6 @@ function gutenberg_get_typography_font_size_value( $preset ) { $max = max( $minimum_font_size, $maximum_font_size ); return "clamp({$min}rem, {$calc_rem}rem + {$calc_vw}vw, {$max}rem)"; - } else { return $preset['size']; } diff --git a/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php b/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php index bd13946c899cce..a86310f473af64 100644 --- a/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php +++ b/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php @@ -397,6 +397,59 @@ class WP_Theme_JSON_6_0 extends WP_Theme_JSON { ), ); + /** + * The valid properties under the settings key. + * + * @var array + */ + const VALID_SETTINGS = array( + 'appearanceTools' => null, + 'border' => array( + 'color' => null, + 'radius' => null, + 'style' => null, + 'width' => null, + ), + 'color' => array( + 'background' => null, + 'custom' => null, + 'customDuotone' => null, + 'customGradient' => null, + 'defaultDuotone' => null, + 'defaultGradients' => null, + 'defaultPalette' => null, + 'duotone' => null, + 'gradients' => null, + 'link' => null, + 'palette' => null, + 'text' => null, + ), + 'custom' => null, + 'layout' => array( + 'contentSize' => null, + 'wideSize' => null, + ), + 'spacing' => array( + 'blockGap' => null, + 'margin' => null, + 'padding' => null, + 'units' => null, + ), + 'typography' => array( + 'customFontSize' => null, + 'dropCap' => null, + 'fontFamilies' => null, + 'fontSizes' => null, + 'fontStyle' => null, + 'fontWeight' => null, + 'fluid' => null, + 'letterSpacing' => null, + 'lineHeight' => null, + 'textDecoration' => null, + 'textTransform' => null, + ), + ); + /** * Returns the current theme's wanted patterns(slugs) to be * registered from Pattern Directory. diff --git a/schemas/json/theme.json b/schemas/json/theme.json index c699cd78424b90..bf5fa1d7089019 100644 --- a/schemas/json/theme.json +++ b/schemas/json/theme.json @@ -316,6 +316,20 @@ "type": "boolean", "default": true }, + "fluid": { + "description": "Enables fluid typography and allows users to set global fluid typography parameters.", + "type": "object", + "properties": { + "maxViewportWidth": { + "description": "Allow users to set custom a max viewport width.", + "type": "string" + }, + "minViewportWidth": { + "description": "Allow users to set custom a min viewport width.", + "type": "string" + } + } + }, "letterSpacing": { "description": "Allow users to set custom letter spacing.", "type": "boolean", From 6b96585f4061c1e0fde4637084135bdd3c7c0655 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Mon, 21 Mar 2022 13:17:07 +1100 Subject: [PATCH 03/24] Alternative calculation for fluid type --- lib/block-supports/typography.php | 128 ++++++++++-------- .../wordpress-6.0/class-wp-theme-json-6-0.php | 2 +- 2 files changed, 72 insertions(+), 58 deletions(-) diff --git a/lib/block-supports/typography.php b/lib/block-supports/typography.php index 3596d74d1f6f70..befa6ac75c7eb1 100644 --- a/lib/block-supports/typography.php +++ b/lib/block-supports/typography.php @@ -222,6 +222,42 @@ function gutenberg_typography_get_css_variable_inline_style( $attributes, $featu return sprintf( '%s:var(--wp--preset--%s--%s);', $css_property, $css_property, $slug ); } +/** + * Checks a string for a px or rem value and returns an array consisting of `'value'` and `'unit'`, e.g., [ '42', 'rem' ]. + * + * @param string $raw_value Raw size value from theme.json. + * @param string $preferred_unit Whether to coerce the value to rem or px. Default `'rem'`. + * @return array An array consisting of `'value'` and `'unit'`, e.g., [ '42', 'rem' ] + */ +function gutenberg_get_typography_value_and_unit( $raw_value, $preferred_unit = 'rem' ) { + $pattern = '/^(\d*\.?\d+)(rem|px){1,1}$/'; + + preg_match( $pattern, $raw_value, $matches ); + + // We need a number value and a px or rem unit. + if ( ! isset( $matches[1] ) && isset( $matches[2] ) ) { + return null; + } + + $value = $matches[1]; + $unit = $matches[2]; + + if ( 'rem' === $preferred_unit && 'px' === $unit ) { + // Preferred is rem so we convert px to rem. + $value = $value / 16; + } + + if ( 'px' === $preferred_unit && 'rem' === $unit ) { + // Preferred is px so we convert rem to px. + $value = $value * 16; + } + + return array( + 'value' => $value, + 'unit' => $unit, + ); +} + /** * Returns a font-size value based on a given font-size preset. If typography.fluid is enabled it will calculate clamp values. * @@ -232,71 +268,49 @@ function gutenberg_get_typography_font_size_value( $preset ) { $typography_settings = gutenberg_get_global_settings( array( 'typography' ) ); // This is where we'll keep options I guess. - if ( ! isset( $typography_settings['fluid'] ) ) { + if ( ! isset( $typography_settings['responsive'] ) ) { return $preset['size']; } - // Up for discussion. - $default_unit = 'rem'; - $default_minimum_viewport_width = '1600px'; - $default_maximum_viewport_width = '650px'; - - // Matches rem or px values only. - $pattern = '/^(\d*\.?\d+)(rem|px)?$/'; - // Could we also take these from layout? contentSize and wideSize? - $minimum_viewport_width = isset( $typography_settings['minViewportWidth'] ) ? $typography_settings['minViewportWidth'] : $default_minimum_viewport_width; - $minimum_viewport_width_unit = $default_unit; - $maximum_viewport_width = isset( $typography_settings['maxViewportWidth'] ) ? $typography_settings['maxViewportWidth'] : $default_maximum_viewport_width; - $maximum_viewport_width_unit = $default_unit; - - // Minimum viewport size. - preg_match_all( $pattern, $minimum_viewport_width, $minimum_viewport_width_matches ); - if ( isset( $minimum_viewport_width_matches[1][0] ) ) { - $minimum_viewport_width = intval( $minimum_viewport_width_matches[1][0] ); - $minimum_viewport_width_unit = isset( $minimum_viewport_width_matches[2][0] ) ? $minimum_viewport_width_matches[2][0] : $minimum_viewport_width_unit; - if ( 'px' === $minimum_viewport_width_unit ) { - // Default is rem so we convert px to rem. - $minimum_viewport_width = $minimum_viewport_width / 16; - } - } + $responsive_settings = $typography_settings['responsive']; - // Maximum viewport size. - preg_match_all( $pattern, $maximum_viewport_width, $maximum_viewport_width_matches ); - if ( isset( $maximum_viewport_width_matches[1][0] ) ) { - $maximum_viewport_width = intval( $maximum_viewport_width_matches[1][0] ); - $maximum_viewport_width_unit = isset( $maximum_viewport_width_matches[2][0] ) ? $maximum_viewport_width_matches[2][0] : $maximum_viewport_width_unit; - if ( 'px' === $maximum_viewport_width_unit ) { - // Default is rem so we convert px to rem. - $maximum_viewport_width = $maximum_viewport_width / 16; - } - } + // Defaults. + // Up for discussion. + // We expect these to be in `px`. + $default_minimum_viewport_width = '1600px'; + $default_maximum_viewport_width = '650px'; + $default_minimum_font_size_factor = 0.75; + $default_maximum_font_size_factor = 1.5; // Font sizes. - preg_match_all( $pattern, $preset['size'], $size_matches ); - if ( isset( $size_matches[1][0] ) ) { - $base_size_value = $size_matches[1][0]; - - if ( isset( $size_matches[2][0] ) && 'px' === $size_matches[2][0] ) { - // Default is rem so we convert px to rem. - $base_size_value = $base_size_value / 16; - } - - // How can we offer control over this? - // Maybe typography.fluid.{min|max}FontSizeFactor. - // Or picking the first and last sizes in the fontSizes array? - // Another option is here to accept fontSizes[0]['min'] and fontSizes[0]['max'] from a preset item. - $minimum_font_size = $base_size_value * 0.9; - $maximum_font_size = $base_size_value * 1.75; - $factor = ( 1 / ( $maximum_viewport_width - $minimum_viewport_width ) ) * ( $maximum_font_size - $minimum_font_size ); - $calc_rem = $minimum_font_size - ( $minimum_viewport_width * $factor ); - $calc_vw = 100 * $factor; - $min = min( $minimum_font_size, $maximum_font_size ); - $max = max( $minimum_font_size, $maximum_font_size ); - - return "clamp({$min}rem, {$calc_rem}rem + {$calc_vw}vw, {$max}rem)"; - } else { + $preferred_size = gutenberg_get_typography_value_and_unit( $preset['size'] ); + + if ( empty( $preferred_size ) ) { return $preset['size']; } + + $preferred_unit = $preferred_size['unit']; + $maximum_font_size_raw = isset( $preset['max'] ) ? $preset['max'] : $preferred_size['value'] * $default_minimum_font_size_factor . $preferred_unit; + $minimum_font_size_raw = isset( $preset['min'] ) ? $preset['min'] : $preferred_size['value'] * $default_maximum_font_size_factor . $preferred_unit; + $maximum_font_size = gutenberg_get_typography_value_and_unit( $maximum_font_size_raw, $preferred_unit )['value']; + $minimum_font_size = gutenberg_get_typography_value_and_unit( $minimum_font_size_raw, $preferred_unit )['value']; + + // Viewport widths. + // Could we also take these from layout? contentSize and wideSize? + $maximum_viewport_width_raw = isset( $responsive_settings['maxViewportWidth'] ) ? $responsive_settings['maxViewportWidth'] : $default_maximum_viewport_width; + $minimum_viewport_width_raw = isset( $responsive_settings['minViewportWidth'] ) ? $responsive_settings['minViewportWidth'] : $default_minimum_viewport_width; + $maximum_viewport_width = gutenberg_get_typography_value_and_unit( $maximum_viewport_width_raw, $preferred_unit )['value']; + $minimum_viewport_width = gutenberg_get_typography_value_and_unit( $minimum_viewport_width_raw, $preferred_unit )['value']; + + // Calculate fluid font size. + $rise = $maximum_font_size - $minimum_font_size; + $run = $maximum_viewport_width - $minimum_viewport_width; + $slope = $rise / $run; + $max_font_size_calc = "calc($maximum_font_size * 1{$preferred_unit})"; + $min_font_size_calc = "calc($minimum_font_size * 1{$preferred_unit})"; + $fluid_font_size = "calc($slope * (100vw - calc($minimum_viewport_width * 1{$preferred_unit})) + $min_font_size_calc)"; + + return "clamp($min_font_size_calc, $fluid_font_size, $max_font_size_calc);"; } // Register the block support. diff --git a/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php b/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php index a86310f473af64..8bcb1e93e00c4e 100644 --- a/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php +++ b/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php @@ -442,9 +442,9 @@ class WP_Theme_JSON_6_0 extends WP_Theme_JSON { 'fontSizes' => null, 'fontStyle' => null, 'fontWeight' => null, - 'fluid' => null, 'letterSpacing' => null, 'lineHeight' => null, + 'responsive' => null, 'textDecoration' => null, 'textTransform' => null, ), From 1182f269f2b0f9807cdc2d4f1e05c02e37ae1650 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Tue, 22 Mar 2022 21:49:50 +1100 Subject: [PATCH 04/24] Implementing new algorithm using max and mix viewport widths --- lib/block-supports/typography.php | 84 ++++++++++--------- .../wordpress-6.0/class-wp-theme-json-6-0.php | 2 +- 2 files changed, 44 insertions(+), 42 deletions(-) diff --git a/lib/block-supports/typography.php b/lib/block-supports/typography.php index befa6ac75c7eb1..47b6508594b99f 100644 --- a/lib/block-supports/typography.php +++ b/lib/block-supports/typography.php @@ -223,14 +223,17 @@ function gutenberg_typography_get_css_variable_inline_style( $attributes, $featu } /** - * Checks a string for a px or rem value and returns an array consisting of `'value'` and `'unit'`, e.g., [ '42', 'rem' ]. + * Checks a string for a unit and value and returns an array consisting of `'value'` and `'unit'`, e.g., [ '42', 'rem' ]. * - * @param string $raw_value Raw size value from theme.json. - * @param string $preferred_unit Whether to coerce the value to rem or px. Default `'rem'`. - * @return array An array consisting of `'value'` and `'unit'`, e.g., [ '42', 'rem' ] + * @param string $raw_value Raw size value from theme.json. + * @param string $coerce_to Coerce the value to rem or px. Default `'rem'`. + * @param number $root_font_size_value Value of root font size for rem|em <-> px conversion. + * @param array $acceptable_units An array of font size units. + * @return array An array consisting of `'value'` and `'unit'`, e.g., [ '42', 'rem' ] */ -function gutenberg_get_typography_value_and_unit( $raw_value, $preferred_unit = 'rem' ) { - $pattern = '/^(\d*\.?\d+)(rem|px){1,1}$/'; +function gutenberg_get_typography_value_and_unit( $raw_value, $coerce_to = 'rem', $root_font_size_value = 16, $acceptable_units = array( 'rem', 'px', 'em' ) ) { + $acceptable_units_group = implode( '|', $acceptable_units ); + $pattern = '/^(\d*\.?\d+)(' . $acceptable_units_group . '){1,1}$/'; preg_match( $pattern, $raw_value, $matches ); @@ -242,14 +245,13 @@ function gutenberg_get_typography_value_and_unit( $raw_value, $preferred_unit = $value = $matches[1]; $unit = $matches[2]; - if ( 'rem' === $preferred_unit && 'px' === $unit ) { - // Preferred is rem so we convert px to rem. - $value = $value / 16; + // Default browser font size. Later we could inject some JS to compute this `getComputedStyle( document.querySelector( "html" ) ).fontSize`. + if ( 'px' === $coerce_to && ( 'em' === $unit || 'rem' === $unit ) ) { + $value = $value * $root_font_size_value; } - if ( 'px' === $preferred_unit && 'rem' === $unit ) { - // Preferred is px so we convert rem to px. - $value = $value * 16; + if ( 'px' === $unit && ( 'em' === $coerce_to || 'rem' === $coerce_to ) ) { + $value = $value / $root_font_size_value; } return array( @@ -268,49 +270,49 @@ function gutenberg_get_typography_font_size_value( $preset ) { $typography_settings = gutenberg_get_global_settings( array( 'typography' ) ); // This is where we'll keep options I guess. - if ( ! isset( $typography_settings['responsive'] ) ) { + if ( ! isset( $typography_settings['fluid'] ) ) { return $preset['size']; } - $responsive_settings = $typography_settings['responsive']; + $fluid_settings = $typography_settings['fluid']; - // Defaults. - // Up for discussion. - // We expect these to be in `px`. - $default_minimum_viewport_width = '1600px'; - $default_maximum_viewport_width = '650px'; + $default_maximum_viewport_width_px = '1900px'; + $default_minimum_viewport_width_px = '800px'; + // Used to compute min and max font sizes. + // We could also use values directly from fontSize items, e.g., fontSizes[n]['maxSize'] and fontSizes[n]['minSize']. $default_minimum_font_size_factor = 0.75; - $default_maximum_font_size_factor = 1.5; + $default_maximum_font_size_factor = 1; // Font sizes. - $preferred_size = gutenberg_get_typography_value_and_unit( $preset['size'] ); + $relative_font_size = gutenberg_get_typography_value_and_unit( $preset['size'] ); - if ( empty( $preferred_size ) ) { + if ( empty( $relative_font_size ) ) { return $preset['size']; } - $preferred_unit = $preferred_size['unit']; - $maximum_font_size_raw = isset( $preset['max'] ) ? $preset['max'] : $preferred_size['value'] * $default_minimum_font_size_factor . $preferred_unit; - $minimum_font_size_raw = isset( $preset['min'] ) ? $preset['min'] : $preferred_size['value'] * $default_maximum_font_size_factor . $preferred_unit; - $maximum_font_size = gutenberg_get_typography_value_and_unit( $maximum_font_size_raw, $preferred_unit )['value']; - $minimum_font_size = gutenberg_get_typography_value_and_unit( $minimum_font_size_raw, $preferred_unit )['value']; + // We need to get the unit to "normalize" rem/em and px. + $relative_font_size_unit = $relative_font_size['unit']; + $maximum_font_size_raw = ( $relative_font_size['value'] * $default_maximum_font_size_factor ) . $relative_font_size_unit; + $minimum_font_size_raw = ( $relative_font_size['value'] * $default_minimum_font_size_factor ) . $relative_font_size_unit; + $maximum_font_size = gutenberg_get_typography_value_and_unit( $maximum_font_size_raw, $relative_font_size_unit ); + $minimum_font_size = gutenberg_get_typography_value_and_unit( $minimum_font_size_raw, $relative_font_size_unit ); + $minimum_font_size_rem = gutenberg_get_typography_value_and_unit( $minimum_font_size_raw, 'rem' ); // Viewport widths. // Could we also take these from layout? contentSize and wideSize? - $maximum_viewport_width_raw = isset( $responsive_settings['maxViewportWidth'] ) ? $responsive_settings['maxViewportWidth'] : $default_maximum_viewport_width; - $minimum_viewport_width_raw = isset( $responsive_settings['minViewportWidth'] ) ? $responsive_settings['minViewportWidth'] : $default_minimum_viewport_width; - $maximum_viewport_width = gutenberg_get_typography_value_and_unit( $maximum_viewport_width_raw, $preferred_unit )['value']; - $minimum_viewport_width = gutenberg_get_typography_value_and_unit( $minimum_viewport_width_raw, $preferred_unit )['value']; - - // Calculate fluid font size. - $rise = $maximum_font_size - $minimum_font_size; - $run = $maximum_viewport_width - $minimum_viewport_width; - $slope = $rise / $run; - $max_font_size_calc = "calc($maximum_font_size * 1{$preferred_unit})"; - $min_font_size_calc = "calc($minimum_font_size * 1{$preferred_unit})"; - $fluid_font_size = "calc($slope * (100vw - calc($minimum_viewport_width * 1{$preferred_unit})) + $min_font_size_calc)"; - - return "clamp($min_font_size_calc, $fluid_font_size, $max_font_size_calc);"; + $maximum_viewport_width_raw = isset( $fluid_settings['maxViewportWidth'] ) ? $fluid_settings['maxViewportWidth'] : $default_maximum_viewport_width_px; + $minimum_viewport_width_raw = isset( $fluid_settings['minViewportWidth'] ) ? $fluid_settings['minViewportWidth'] : $default_minimum_viewport_width_px; + $maximum_viewport_width = gutenberg_get_typography_value_and_unit( $maximum_viewport_width_raw, $relative_font_size_unit ); + $minimum_viewport_width = gutenberg_get_typography_value_and_unit( $minimum_viewport_width_raw, $relative_font_size_unit ); + + // Build CSS rule. + // Borrowed from https://websemantics.uk/tools/responsive-font-calculator/. + $view_port_width_offset = ( $minimum_viewport_width['value'] / 100 ) . $relative_font_size_unit; + $linear_factor = 100 * ( ( $maximum_font_size['value'] - $minimum_font_size['value'] ) / ( $maximum_viewport_width['value'] - $minimum_viewport_width['value'] ) ); + $fluid_target_font_size = 'calc(' . implode( '', $minimum_font_size_rem ) . " + ((1vw - $view_port_width_offset) * $linear_factor))"; + $minimum_font_size = implode( '', $minimum_font_size ); + $maximum_font_size = implode( '', $maximum_font_size ); + return "clamp($minimum_font_size, $fluid_target_font_size, $maximum_font_size)"; } // Register the block support. diff --git a/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php b/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php index 8bcb1e93e00c4e..09aef875f52e40 100644 --- a/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php +++ b/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php @@ -438,13 +438,13 @@ class WP_Theme_JSON_6_0 extends WP_Theme_JSON { 'typography' => array( 'customFontSize' => null, 'dropCap' => null, + 'fluid' => null, 'fontFamilies' => null, 'fontSizes' => null, 'fontStyle' => null, 'fontWeight' => null, 'letterSpacing' => null, 'lineHeight' => null, - 'responsive' => null, 'textDecoration' => null, 'textTransform' => null, ), From 3998a1df33a8d9a08eea1d787a6fa28256b6dbe8 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Wed, 23 Mar 2022 14:17:12 +1100 Subject: [PATCH 05/24] Refactoring the method to accept a `maxSize` --- lib/block-supports/typography.php | 54 ++++++++++++++++--------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/lib/block-supports/typography.php b/lib/block-supports/typography.php index 47b6508594b99f..c9abcf3a8355ba 100644 --- a/lib/block-supports/typography.php +++ b/lib/block-supports/typography.php @@ -269,50 +269,52 @@ function gutenberg_get_typography_value_and_unit( $raw_value, $coerce_to = 'rem' function gutenberg_get_typography_font_size_value( $preset ) { $typography_settings = gutenberg_get_global_settings( array( 'typography' ) ); - // This is where we'll keep options I guess. if ( ! isset( $typography_settings['fluid'] ) ) { return $preset['size']; } + // Font sizes. + // $preset['size'] acts as the minimum size of the font. + $minimum_font_size = gutenberg_get_typography_value_and_unit( $preset['size'] ); + + // If the minimum fontsize isn't successfully parsed, + // or there's no defined `maxSize` skip the font. + // Defining a `maxSize` provides a way for theme.json to specify which + // font-sizes receive the clamp treatment. + if ( empty( $minimum_font_size || isset( $preset['maxSize'] ) ) ) { + return $preset['size']; + } + + // Fluid typography general settings. $fluid_settings = $typography_settings['fluid']; + // Set some defaults for the case that `"fluid": true,`. $default_maximum_viewport_width_px = '1900px'; $default_minimum_viewport_width_px = '800px'; - // Used to compute min and max font sizes. - // We could also use values directly from fontSize items, e.g., fontSizes[n]['maxSize'] and fontSizes[n]['minSize']. - $default_minimum_font_size_factor = 0.75; - $default_maximum_font_size_factor = 1; - // Font sizes. - $relative_font_size = gutenberg_get_typography_value_and_unit( $preset['size'] ); - - if ( empty( $relative_font_size ) ) { - return $preset['size']; - } + // Use rem for accessible fluid target font scaling. + $minimum_font_size_rem = gutenberg_get_typography_value_and_unit( $preset['size'], 'rem' ); // We need to get the unit to "normalize" rem/em and px. - $relative_font_size_unit = $relative_font_size['unit']; - $maximum_font_size_raw = ( $relative_font_size['value'] * $default_maximum_font_size_factor ) . $relative_font_size_unit; - $minimum_font_size_raw = ( $relative_font_size['value'] * $default_minimum_font_size_factor ) . $relative_font_size_unit; - $maximum_font_size = gutenberg_get_typography_value_and_unit( $maximum_font_size_raw, $relative_font_size_unit ); - $minimum_font_size = gutenberg_get_typography_value_and_unit( $minimum_font_size_raw, $relative_font_size_unit ); - $minimum_font_size_rem = gutenberg_get_typography_value_and_unit( $minimum_font_size_raw, 'rem' ); - - // Viewport widths. - // Could we also take these from layout? contentSize and wideSize? + $font_size_unit = $minimum_font_size['unit']; + + // Grab the maximum font size and normalize it so we can use the value for calculations. + $maximum_font_size = gutenberg_get_typography_value_and_unit( $preset['maxSize'], $font_size_unit ); + + // Viewport widths defined for fluid typography. $maximum_viewport_width_raw = isset( $fluid_settings['maxViewportWidth'] ) ? $fluid_settings['maxViewportWidth'] : $default_maximum_viewport_width_px; $minimum_viewport_width_raw = isset( $fluid_settings['minViewportWidth'] ) ? $fluid_settings['minViewportWidth'] : $default_minimum_viewport_width_px; - $maximum_viewport_width = gutenberg_get_typography_value_and_unit( $maximum_viewport_width_raw, $relative_font_size_unit ); - $minimum_viewport_width = gutenberg_get_typography_value_and_unit( $minimum_viewport_width_raw, $relative_font_size_unit ); + $maximum_viewport_width = gutenberg_get_typography_value_and_unit( $maximum_viewport_width_raw, $font_size_unit ); + $minimum_viewport_width = gutenberg_get_typography_value_and_unit( $minimum_viewport_width_raw, $font_size_unit ); // Build CSS rule. // Borrowed from https://websemantics.uk/tools/responsive-font-calculator/. - $view_port_width_offset = ( $minimum_viewport_width['value'] / 100 ) . $relative_font_size_unit; + $view_port_width_offset = round( $minimum_viewport_width['value'] / 100, 3 ) . $font_size_unit; $linear_factor = 100 * ( ( $maximum_font_size['value'] - $minimum_font_size['value'] ) / ( $maximum_viewport_width['value'] - $minimum_viewport_width['value'] ) ); + $linear_factor = round( $linear_factor, 3 ); $fluid_target_font_size = 'calc(' . implode( '', $minimum_font_size_rem ) . " + ((1vw - $view_port_width_offset) * $linear_factor))"; - $minimum_font_size = implode( '', $minimum_font_size ); - $maximum_font_size = implode( '', $maximum_font_size ); - return "clamp($minimum_font_size, $fluid_target_font_size, $maximum_font_size)"; + + return "clamp({$preset['size']}, $fluid_target_font_size, {$preset['maxSize']})"; } // Register the block support. From 82caf169aff4b1a09f6b7d657b94a680878f6ba5 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Wed, 23 Mar 2022 19:32:17 +1100 Subject: [PATCH 06/24] The linter of doom! Testing out a new model that allows all values to be custom, with a fallback clamp implementation. --- lib/block-supports/typography.php | 127 ++++++++++++++++++++++-------- 1 file changed, 93 insertions(+), 34 deletions(-) diff --git a/lib/block-supports/typography.php b/lib/block-supports/typography.php index c9abcf3a8355ba..dec5411c685377 100644 --- a/lib/block-supports/typography.php +++ b/lib/block-supports/typography.php @@ -274,47 +274,106 @@ function gutenberg_get_typography_font_size_value( $preset ) { } // Font sizes. - // $preset['size'] acts as the minimum size of the font. - $minimum_font_size = gutenberg_get_typography_value_and_unit( $preset['size'] ); - - // If the minimum fontsize isn't successfully parsed, - // or there's no defined `maxSize` skip the font. - // Defining a `maxSize` provides a way for theme.json to specify which - // font-sizes receive the clamp treatment. - if ( empty( $minimum_font_size || isset( $preset['maxSize'] ) ) ) { + $fluid_font_size_settings = isset( $preset['fluidSize'] ) ? $preset['fluidSize'] : null; + + if ( ! $fluid_font_size_settings ) { return $preset['size']; } - // Fluid typography general settings. - $fluid_settings = $typography_settings['fluid']; - - // Set some defaults for the case that `"fluid": true,`. - $default_maximum_viewport_width_px = '1900px'; - $default_minimum_viewport_width_px = '800px'; - - // Use rem for accessible fluid target font scaling. - $minimum_font_size_rem = gutenberg_get_typography_value_and_unit( $preset['size'], 'rem' ); - - // We need to get the unit to "normalize" rem/em and px. - $font_size_unit = $minimum_font_size['unit']; + $minimum_font_size_raw = isset( $fluid_font_size_settings['minSize'] ) ? $fluid_font_size_settings['minSize'] : null; + $maximum_font_size_raw = isset( $fluid_font_size_settings['maxSize'] ) ? $fluid_font_size_settings['maxSize'] : null; + $fluid_formula = isset( $fluid_font_size_settings['fluidFormula'] ) ? $fluid_font_size_settings['fluidFormula'] : null; - // Grab the maximum font size and normalize it so we can use the value for calculations. - $maximum_font_size = gutenberg_get_typography_value_and_unit( $preset['maxSize'], $font_size_unit ); + // Fluid typography general settings. + // Gutenberg's internal implementation. + // If a minimum and maximum viewport width is set, let's try to use it. + $fluid_settings = $typography_settings['fluid']; + $maximum_viewport_width_raw = isset( $fluid_settings['maxViewportWidth'] ) ? $fluid_settings['maxViewportWidth'] : null; + $minimum_viewport_width_raw = isset( $fluid_settings['minViewportWidth'] ) ? $fluid_settings['minViewportWidth'] : null; + + // Expect all required variables except formula to trigger internal clamp() implementation based on min/max viewport width. + + /* + "fluid": { + "maxViewportWidth": "1600px", + "minViewportWidth": "768px" + }, + "fontSizes": [ + { + "size": "5.25rem", + "fluidSize": { + "minSize": "5.25rem", + "maxSize": "9rem" + }, + "slug": "colossal", + "name": "Colossal" + } + */ + if ( $minimum_viewport_width_raw && $maximum_viewport_width_raw && $minimum_font_size_raw && $maximum_font_size_raw && ! $fluid_formula ) { + // In order to do fluid calculations, we need a "preferred" unit so the base values have the same ratio. + // We need to get the unit to "normalize" rem/em and px. + $preferred_font_size = gutenberg_get_typography_value_and_unit( $preset['size'] ); + $font_size_unit = $preferred_font_size['unit']; + $minimum_font_size = gutenberg_get_typography_value_and_unit( $minimum_font_size_raw ); + // Grab the maximum font size and normalize it in order to use the value for calculations. + $maximum_font_size = gutenberg_get_typography_value_and_unit( $maximum_font_size_raw, $font_size_unit ); + // Use rem for accessible fluid target font scaling. + $minimum_font_size_rem = gutenberg_get_typography_value_and_unit( $minimum_font_size, 'rem' ); + + // Viewport widths defined for fluid typography. Normalize units. + $maximum_viewport_width = gutenberg_get_typography_value_and_unit( $maximum_viewport_width_raw, $font_size_unit ); + $minimum_viewport_width = gutenberg_get_typography_value_and_unit( $minimum_viewport_width_raw, $font_size_unit ); + + // Build CSS rule. + // Borrowed from https://websemantics.uk/tools/responsive-font-calculator/. + $view_port_width_offset = round( $minimum_viewport_width['value'] / 100, 3 ) . $font_size_unit; + $linear_factor = 100 * ( ( $maximum_font_size['value'] - $minimum_font_size['value'] ) / ( $maximum_viewport_width['value'] - $minimum_viewport_width['value'] ) ); + $linear_factor = round( $linear_factor, 3 ); + $fluid_target_font_size = 'calc(' . implode( '', $minimum_font_size_rem ) . " + ((1vw - $view_port_width_offset) * $linear_factor))"; + + return "clamp({$minimum_font_size_raw}, $fluid_target_font_size, {$maximum_font_size_raw})"; + } - // Viewport widths defined for fluid typography. - $maximum_viewport_width_raw = isset( $fluid_settings['maxViewportWidth'] ) ? $fluid_settings['maxViewportWidth'] : $default_maximum_viewport_width_px; - $minimum_viewport_width_raw = isset( $fluid_settings['minViewportWidth'] ) ? $fluid_settings['minViewportWidth'] : $default_minimum_viewport_width_px; - $maximum_viewport_width = gutenberg_get_typography_value_and_unit( $maximum_viewport_width_raw, $font_size_unit ); - $minimum_viewport_width = gutenberg_get_typography_value_and_unit( $minimum_viewport_width_raw, $font_size_unit ); + // If there's no min or max viewport, use custom implementation. + // min, max sizes and fluid formula? Use clamp(). + + /* + "fluid": true, + "fontSizes": [ + { + "size": "2rem", + "fluidSize": { + "minSize": "2rem", + "fluidFormula": "calc(2.5 / 100 * 100vw)", + "maxSize": "2.5rem" + }, + "slug": "large", + "name": "Large" + }, + */ + if ( $fluid_formula && $minimum_font_size_raw && $maximum_font_size_raw ) { + return "clamp($minimum_font_size_raw, $fluid_formula, $maximum_font_size_raw)"; + } - // Build CSS rule. - // Borrowed from https://websemantics.uk/tools/responsive-font-calculator/. - $view_port_width_offset = round( $minimum_viewport_width['value'] / 100, 3 ) . $font_size_unit; - $linear_factor = 100 * ( ( $maximum_font_size['value'] - $minimum_font_size['value'] ) / ( $maximum_viewport_width['value'] - $minimum_viewport_width['value'] ) ); - $linear_factor = round( $linear_factor, 3 ); - $fluid_target_font_size = 'calc(' . implode( '', $minimum_font_size_rem ) . " + ((1vw - $view_port_width_offset) * $linear_factor))"; + // Use a custom formula. Could be clamp(), could be anything. + + /* + "fluid": true, + "fontSizes": [ + { + "size": "3.7rem", + "fluidSize": { + "fluidFormula": "calc(3.7rem * 1px + 2 * 1vw)" + }, + "slug": "huge", + "name": "Huge" + }, + */ + if ( $fluid_formula && ! $minimum_font_size_raw && ! $maximum_font_size_raw ) { + return $fluid_formula; + } - return "clamp({$preset['size']}, $fluid_target_font_size, {$preset['maxSize']})"; + return $preset['size']; } // Register the block support. From 3b7c42d84fd18767296414a68326d655fc277358 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Tue, 29 Mar 2022 10:42:56 +1100 Subject: [PATCH 07/24] Extracting internal implementation. --- lib/block-supports/typography.php | 78 +++++++++++++++++-------------- 1 file changed, 44 insertions(+), 34 deletions(-) diff --git a/lib/block-supports/typography.php b/lib/block-supports/typography.php index dec5411c685377..35fb80d5261eaf 100644 --- a/lib/block-supports/typography.php +++ b/lib/block-supports/typography.php @@ -231,7 +231,7 @@ function gutenberg_typography_get_css_variable_inline_style( $attributes, $featu * @param array $acceptable_units An array of font size units. * @return array An array consisting of `'value'` and `'unit'`, e.g., [ '42', 'rem' ] */ -function gutenberg_get_typography_value_and_unit( $raw_value, $coerce_to = 'rem', $root_font_size_value = 16, $acceptable_units = array( 'rem', 'px', 'em' ) ) { +function gutenberg_get_typography_value_and_unit( $raw_value, $coerce_to = '', $root_font_size_value = 16, $acceptable_units = array( 'rem', 'px', 'em' ) ) { $acceptable_units_group = implode( '|', $acceptable_units ); $pattern = '/^(\d*\.?\d+)(' . $acceptable_units_group . '){1,1}$/'; @@ -248,10 +248,12 @@ function gutenberg_get_typography_value_and_unit( $raw_value, $coerce_to = 'rem' // Default browser font size. Later we could inject some JS to compute this `getComputedStyle( document.querySelector( "html" ) ).fontSize`. if ( 'px' === $coerce_to && ( 'em' === $unit || 'rem' === $unit ) ) { $value = $value * $root_font_size_value; + $unit = $coerce_to; } if ( 'px' === $unit && ( 'em' === $coerce_to || 'rem' === $coerce_to ) ) { $value = $value / $root_font_size_value; + $unit = $coerce_to; } return array( @@ -261,9 +263,41 @@ function gutenberg_get_typography_value_and_unit( $raw_value, $coerce_to = 'rem' } /** - * Returns a font-size value based on a given font-size preset. If typography.fluid is enabled it will calculate clamp values. + * Internal implementation of clamp() based on available min/max viewport width, and min/max font sizes.. * - * @param array $preset Duotone preset value as seen in theme.json. + * @param array $fluid_settings Possible values: array( 'minViewportWidth' => string, 'maxViewportWidth' => string ). + * @param string $minimum_font_size_raw Minimumn font size for any clamp() calculation. + * @param string $maximum_font_size_raw Maximumn font size for any clamp() calculation. + * @return string A font-size value using clamp(). + */ +function gutenberg_get_computed_typography_clamp_value( $fluid_settings, $minimum_font_size_raw, $maximum_font_size_raw ) { + $minimum_font_size = gutenberg_get_typography_value_and_unit( $minimum_font_size_raw ); + // We get a 'preferred' unit to keep units across the calc as consistent as possible. + $font_size_unit = $minimum_font_size['unit']; + + // Grab the maximum font size and normalize it in order to use the value for calculations. + $maximum_font_size = gutenberg_get_typography_value_and_unit( $maximum_font_size_raw, $font_size_unit ); + // Use rem for accessible fluid target font scaling. + $minimum_font_size_rem = gutenberg_get_typography_value_and_unit( $minimum_font_size_raw, 'rem' ); + + // Viewport widths defined for fluid typography. Normalize units. + $maximum_viewport_width = gutenberg_get_typography_value_and_unit( $fluid_settings['maxViewportWidth'], $font_size_unit ); + $minimum_viewport_width = gutenberg_get_typography_value_and_unit( $fluid_settings['minViewportWidth'], $font_size_unit ); + + // Build CSS rule. + // Borrowed from https://websemantics.uk/tools/responsive-font-calculator/. + $view_port_width_offset = round( $minimum_viewport_width['value'] / 100, 3 ) . $font_size_unit; + $linear_factor = 100 * ( ( $maximum_font_size['value'] - $minimum_font_size['value'] ) / ( $maximum_viewport_width['value'] - $minimum_viewport_width['value'] ) ); + $linear_factor = round( $linear_factor, 3 ); + $fluid_target_font_size = 'calc(' . implode( '', $minimum_font_size_rem ) . " + ((1vw - $view_port_width_offset) * $linear_factor))"; + + return "clamp({$minimum_font_size_raw}, $fluid_target_font_size, {$maximum_font_size_raw})"; +} + +/** + * Returns a font-size value based on a given font-size preset. If typography.fluid is enabled it will try to return a fluid string. + * + * @param array $preset fontSizes preset value as seen in theme.json. * @return string Font-size value. */ function gutenberg_get_typography_font_size_value( $preset ) { @@ -273,6 +307,8 @@ function gutenberg_get_typography_font_size_value( $preset ) { return $preset['size']; } + $fluid_settings = $typography_settings['fluid']; + // Font sizes. $fluid_font_size_settings = isset( $preset['fluidSize'] ) ? $preset['fluidSize'] : null; @@ -283,15 +319,9 @@ function gutenberg_get_typography_font_size_value( $preset ) { $minimum_font_size_raw = isset( $fluid_font_size_settings['minSize'] ) ? $fluid_font_size_settings['minSize'] : null; $maximum_font_size_raw = isset( $fluid_font_size_settings['maxSize'] ) ? $fluid_font_size_settings['maxSize'] : null; $fluid_formula = isset( $fluid_font_size_settings['fluidFormula'] ) ? $fluid_font_size_settings['fluidFormula'] : null; + $viewport_widths_set = isset( $fluid_settings['minViewportWidth'] ) && isset( $fluid_settings['maxViewportWidth'] ); - // Fluid typography general settings. // Gutenberg's internal implementation. - // If a minimum and maximum viewport width is set, let's try to use it. - $fluid_settings = $typography_settings['fluid']; - $maximum_viewport_width_raw = isset( $fluid_settings['maxViewportWidth'] ) ? $fluid_settings['maxViewportWidth'] : null; - $minimum_viewport_width_raw = isset( $fluid_settings['minViewportWidth'] ) ? $fluid_settings['minViewportWidth'] : null; - - // Expect all required variables except formula to trigger internal clamp() implementation based on min/max viewport width. /* "fluid": { @@ -309,32 +339,12 @@ function gutenberg_get_typography_font_size_value( $preset ) { "name": "Colossal" } */ - if ( $minimum_viewport_width_raw && $maximum_viewport_width_raw && $minimum_font_size_raw && $maximum_font_size_raw && ! $fluid_formula ) { - // In order to do fluid calculations, we need a "preferred" unit so the base values have the same ratio. - // We need to get the unit to "normalize" rem/em and px. - $preferred_font_size = gutenberg_get_typography_value_and_unit( $preset['size'] ); - $font_size_unit = $preferred_font_size['unit']; - $minimum_font_size = gutenberg_get_typography_value_and_unit( $minimum_font_size_raw ); - // Grab the maximum font size and normalize it in order to use the value for calculations. - $maximum_font_size = gutenberg_get_typography_value_and_unit( $maximum_font_size_raw, $font_size_unit ); - // Use rem for accessible fluid target font scaling. - $minimum_font_size_rem = gutenberg_get_typography_value_and_unit( $minimum_font_size, 'rem' ); - - // Viewport widths defined for fluid typography. Normalize units. - $maximum_viewport_width = gutenberg_get_typography_value_and_unit( $maximum_viewport_width_raw, $font_size_unit ); - $minimum_viewport_width = gutenberg_get_typography_value_and_unit( $minimum_viewport_width_raw, $font_size_unit ); - - // Build CSS rule. - // Borrowed from https://websemantics.uk/tools/responsive-font-calculator/. - $view_port_width_offset = round( $minimum_viewport_width['value'] / 100, 3 ) . $font_size_unit; - $linear_factor = 100 * ( ( $maximum_font_size['value'] - $minimum_font_size['value'] ) / ( $maximum_viewport_width['value'] - $minimum_viewport_width['value'] ) ); - $linear_factor = round( $linear_factor, 3 ); - $fluid_target_font_size = 'calc(' . implode( '', $minimum_font_size_rem ) . " + ((1vw - $view_port_width_offset) * $linear_factor))"; - - return "clamp({$minimum_font_size_raw}, $fluid_target_font_size, {$maximum_font_size_raw})"; + // Expect all required variables except formula to trigger internal clamp() implementation based on min/max viewport width. + if ( ! $fluid_formula && $minimum_font_size_raw && $maximum_font_size_raw && $viewport_widths_set ) { + return gutenberg_get_computed_typography_clamp_value( $fluid_settings, $minimum_font_size_raw, $maximum_font_size_raw ); } - // If there's no min or max viewport, use custom implementation. + // If there are min or max viewport widths, use custom implementation if values available. // min, max sizes and fluid formula? Use clamp(). /* From 9efbd8bbbb4fe32e55f06efa251a10e29bf8904b Mon Sep 17 00:00:00 2001 From: ramonjd Date: Wed, 27 Apr 2022 09:13:42 +1000 Subject: [PATCH 08/24] Added missing doc comment for fluid prop in theme.json --- docs/reference-guides/theme-json-reference/theme-json-living.md | 1 + 1 file changed, 1 insertion(+) 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 57fac0b7e95432..09fdeadbb3757f 100644 --- a/docs/reference-guides/theme-json-reference/theme-json-living.md +++ b/docs/reference-guides/theme-json-reference/theme-json-living.md @@ -98,6 +98,7 @@ Settings related to typography. | customFontSize | boolean | true | | | fontStyle | boolean | true | | | fontWeight | boolean | true | | +| fluid | object | | | | letterSpacing | boolean | true | | | lineHeight | boolean | false | | | textDecoration | boolean | true | | From f2d1668c91bce09b085d58c44f2c1fdde46945e8 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Thu, 28 Apr 2022 06:32:56 +1000 Subject: [PATCH 09/24] Remove dupe presets --- .../wordpress-6.0/class-wp-theme-json-6-0.php | 108 ------------------ 1 file changed, 108 deletions(-) diff --git a/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php b/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php index 09aef875f52e40..3bd39e357160d0 100644 --- a/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php +++ b/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php @@ -169,114 +169,6 @@ class WP_Theme_JSON_6_0 extends WP_Theme_JSON { ), ); - /** - * Presets are a set of values that serve - * to bootstrap some styles: colors, font sizes, etc. - * - * They are a unkeyed array of values such as: - * - * ```php - * array( - * array( - * 'slug' => 'unique-name-within-the-set', - * 'name' => 'Name for the UI', - * => 'value' - * ), - * ) - * ``` - * - * This contains the necessary metadata to process them: - * - * - path => Where to find the preset within the settings section. - * - prevent_override => Whether a theme preset with the same slug as a default preset - * should not override it or the path to a setting for the same - * When defaults. - * The relationship between whether to override the defaults - * and whether the defaults are enabled is inverse: - * - If defaults are enabled => theme presets should not be overriden - * - If defaults are disabled => theme presets should be overriden - * For example, a theme sets defaultPalette to false, - * making the default palette hidden from the user. - * In that case, we want all the theme presets to be present, - * so they should override the defaults by setting this false. - * - value_key => the key that represents the value - * - value_func => optionally, instead of value_key, a function to generate - * the value that takes a preset as an argument - * (either value_key or value_func should be present) - * - css_vars => template string to use in generating the CSS Custom Property. - * Example output: "--wp--preset--duotone--blue: " will generate as many CSS Custom Properties as presets defined - * substituting the $slug for the slug's value for each preset value. - * - classes => array containing a structure with the classes to - * generate for the presets, where for each array item - * the key is the class name and the value the property name. - * The "$slug" substring will be replaced by the slug of each preset. - * For example: - * 'classes' => array( - * '.has-$slug-color' => 'color', - * '.has-$slug-background-color' => 'background-color', - * '.has-$slug-border-color' => 'border-color', - * ) - * - properties => array of CSS properties to be used by kses to - * validate the content of each preset - * by means of the remove_insecure_properties method. - */ - const PRESETS_METADATA = array( - array( - 'path' => array( 'color', 'palette' ), - 'prevent_override' => array( 'color', 'defaultPalette' ), - 'use_default_presets' => array( 'color', 'defaultPalette' ), - 'use_default_names' => false, - 'value_key' => 'color', - 'css_vars' => '--wp--preset--color--$slug', - 'classes' => array( - '.has-$slug-color' => 'color', - '.has-$slug-background-color' => 'background-color', - '.has-$slug-border-color' => 'border-color', - ), - 'properties' => array( 'color', 'background-color', 'border-color' ), - ), - array( - 'path' => array( 'color', 'gradients' ), - 'prevent_override' => array( 'color', 'defaultGradients' ), - 'use_default_presets' => array( 'color', 'defaultGradients' ), - 'use_default_names' => false, - 'value_key' => 'gradient', - 'css_vars' => '--wp--preset--gradient--$slug', - 'classes' => array( '.has-$slug-gradient-background' => 'background' ), - 'properties' => array( 'background' ), - ), - array( - 'path' => array( 'color', 'duotone' ), - 'prevent_override' => array( 'color', 'defaultDuotone' ), - 'use_default_presets' => array( 'color', 'defaultDuotone' ), - 'use_default_names' => false, - 'value_func' => 'gutenberg_get_duotone_filter_property', - 'css_vars' => '--wp--preset--duotone--$slug', - 'classes' => array(), - 'properties' => array( 'filter' ), - ), - array( - 'path' => array( 'typography', 'fontSizes' ), - 'prevent_override' => false, - 'use_default_presets' => true, - 'use_default_names' => true, - 'value_func' => 'gutenberg_get_typography_font_size_value', - 'css_vars' => '--wp--preset--font-size--$slug', - 'classes' => array( '.has-$slug-font-size' => 'font-size' ), - 'properties' => array( 'font-size' ), - ), - array( - 'path' => array( 'typography', 'fontFamilies' ), - 'prevent_override' => false, - 'use_default_presets' => true, - 'use_default_names' => false, - 'value_key' => 'fontFamily', - 'css_vars' => '--wp--preset--font-family--$slug', - 'classes' => array( '.has-$slug-font-family' => 'font-family' ), - 'properties' => array( 'font-family' ), - ), - ); - /** * The top-level keys a theme.json can have. * From 15403eb6146de091228f748539aa367114ae36ee Mon Sep 17 00:00:00 2001 From: ramonjd Date: Thu, 28 Apr 2022 06:42:03 +1000 Subject: [PATCH 10/24] Remove dupe settings --- .../wordpress-6.0/class-wp-theme-json-6-0.php | 53 ------------------- 1 file changed, 53 deletions(-) diff --git a/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php b/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php index 3bd39e357160d0..878ac30c1b2c7d 100644 --- a/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php +++ b/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php @@ -289,59 +289,6 @@ class WP_Theme_JSON_6_0 extends WP_Theme_JSON { ), ); - /** - * The valid properties under the settings key. - * - * @var array - */ - const VALID_SETTINGS = array( - 'appearanceTools' => null, - 'border' => array( - 'color' => null, - 'radius' => null, - 'style' => null, - 'width' => null, - ), - 'color' => array( - 'background' => null, - 'custom' => null, - 'customDuotone' => null, - 'customGradient' => null, - 'defaultDuotone' => null, - 'defaultGradients' => null, - 'defaultPalette' => null, - 'duotone' => null, - 'gradients' => null, - 'link' => null, - 'palette' => null, - 'text' => null, - ), - 'custom' => null, - 'layout' => array( - 'contentSize' => null, - 'wideSize' => null, - ), - 'spacing' => array( - 'blockGap' => null, - 'margin' => null, - 'padding' => null, - 'units' => null, - ), - 'typography' => array( - 'customFontSize' => null, - 'dropCap' => null, - 'fluid' => null, - 'fontFamilies' => null, - 'fontSizes' => null, - 'fontStyle' => null, - 'fontWeight' => null, - 'letterSpacing' => null, - 'lineHeight' => null, - 'textDecoration' => null, - 'textTransform' => null, - ), - ); - /** * Returns the current theme's wanted patterns(slugs) to be * registered from Pattern Directory. From 912b80e2ff197fc971f87e72d2feb268fc749cd6 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Fri, 29 Apr 2022 11:22:24 +1000 Subject: [PATCH 11/24] Creating new compat file for 6.1 --- .../class-wp-theme-json-gutenberg.php | 172 ++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 lib/compat/wordpress-6.1/class-wp-theme-json-gutenberg.php diff --git a/lib/compat/wordpress-6.1/class-wp-theme-json-gutenberg.php b/lib/compat/wordpress-6.1/class-wp-theme-json-gutenberg.php new file mode 100644 index 00000000000000..d0decf35f6aac8 --- /dev/null +++ b/lib/compat/wordpress-6.1/class-wp-theme-json-gutenberg.php @@ -0,0 +1,172 @@ + 'unique-name-within-the-set', + * 'name' => 'Name for the UI', + * => 'value' + * ), + * ) + * ``` + * + * This contains the necessary metadata to process them: + * + * - path => Where to find the preset within the settings section. + * - prevent_override => Disables override of default presets by theme presets. + * The relationship between whether to override the defaults + * and whether the defaults are enabled is inverse: + * - If defaults are enabled => theme presets should not be overriden + * - If defaults are disabled => theme presets should be overriden + * For example, a theme sets defaultPalette to false, + * making the default palette hidden from the user. + * In that case, we want all the theme presets to be present, + * so they should override the defaults by setting this false. + * - use_default_names => whether to use the default names + * - value_key => the key that represents the value + * - value_func => optionally, instead of value_key, a function to generate + * the value that takes a preset as an argument + * (either value_key or value_func should be present) + * - css_vars => template string to use in generating the CSS Custom Property. + * Example output: "--wp--preset--duotone--blue: " will generate as many CSS Custom Properties as presets defined + * substituting the $slug for the slug's value for each preset value. + * - classes => array containing a structure with the classes to + * generate for the presets, where for each array item + * the key is the class name and the value the property name. + * The "$slug" substring will be replaced by the slug of each preset. + * For example: + * 'classes' => array( + * '.has-$slug-color' => 'color', + * '.has-$slug-background-color' => 'background-color', + * '.has-$slug-border-color' => 'border-color', + * ) + * - properties => array of CSS properties to be used by kses to + * validate the content of each preset + * by means of the remove_insecure_properties method. + */ + const PRESETS_METADATA = array( + array( + 'path' => array( 'color', 'palette' ), + 'prevent_override' => array( 'color', 'defaultPalette' ), + 'use_default_names' => false, + 'value_key' => 'color', + 'css_vars' => '--wp--preset--color--$slug', + 'classes' => array( + '.has-$slug-color' => 'color', + '.has-$slug-background-color' => 'background-color', + '.has-$slug-border-color' => 'border-color', + ), + 'properties' => array( 'color', 'background-color', 'border-color' ), + ), + array( + 'path' => array( 'color', 'gradients' ), + 'prevent_override' => array( 'color', 'defaultGradients' ), + 'use_default_names' => false, + 'value_key' => 'gradient', + 'css_vars' => '--wp--preset--gradient--$slug', + 'classes' => array( '.has-$slug-gradient-background' => 'background' ), + 'properties' => array( 'background' ), + ), + array( + 'path' => array( 'color', 'duotone' ), + 'prevent_override' => array( 'color', 'defaultDuotone' ), + 'use_default_names' => false, + 'value_func' => 'gutenberg_get_duotone_filter_property', + 'css_vars' => '--wp--preset--duotone--$slug', + 'classes' => array(), + 'properties' => array( 'filter' ), + ), + array( + 'path' => array( 'typography', 'fontSizes' ), + 'prevent_override' => false, + 'use_default_names' => true, + 'value_func' => 'gutenberg_get_typography_font_size_value', + 'css_vars' => '--wp--preset--font-size--$slug', + 'classes' => array( '.has-$slug-font-size' => 'font-size' ), + 'properties' => array( 'font-size' ), + ), + array( + 'path' => array( 'typography', 'fontFamilies' ), + 'prevent_override' => false, + 'use_default_names' => false, + 'value_key' => 'fontFamily', + 'css_vars' => '--wp--preset--font-family--$slug', + 'classes' => array( '.has-$slug-font-family' => 'font-family' ), + 'properties' => array( 'font-family' ), + ), + ); + + /** + * The valid properties under the settings key. + * + * @var array + */ + const VALID_SETTINGS = array( + 'appearanceTools' => null, + 'border' => array( + 'color' => null, + 'radius' => null, + 'style' => null, + 'width' => null, + ), + 'color' => array( + 'background' => null, + 'custom' => null, + 'customDuotone' => null, + 'customGradient' => null, + 'defaultDuotone' => null, + 'defaultGradients' => null, + 'defaultPalette' => null, + 'duotone' => null, + 'gradients' => null, + 'link' => null, + 'palette' => null, + 'text' => null, + ), + 'custom' => null, + 'layout' => array( + 'contentSize' => null, + 'wideSize' => null, + ), + 'spacing' => array( + 'blockGap' => null, + 'margin' => null, + 'padding' => null, + 'units' => null, + ), + 'typography' => array( + 'fluid' => null, + 'customFontSize' => null, + 'dropCap' => null, + 'fontFamilies' => null, + 'fontSizes' => null, + 'fontStyle' => null, + 'fontWeight' => null, + 'letterSpacing' => null, + 'lineHeight' => null, + 'textDecoration' => null, + 'textTransform' => null, + ), + ); +} From 69168ba747be61ebec704bdad44ea0c9b65f9c99 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Fri, 29 Apr 2022 14:31:14 +1000 Subject: [PATCH 12/24] Created fallback for min and max viewport widths Returning `min()` CSS rule where there's only a maximum font size Returning `max()` CSS rule where there's only a minimum font size Removing `fluidFormula` as a property and related logic --- lib/block-supports/typography.php | 147 ++++++++++----------- phpunit/block-supports/typography-test.php | 2 +- schemas/json/theme.json | 22 ++- 3 files changed, 87 insertions(+), 84 deletions(-) diff --git a/lib/block-supports/typography.php b/lib/block-supports/typography.php index 35fb80d5261eaf..08efee58b38e0d 100644 --- a/lib/block-supports/typography.php +++ b/lib/block-supports/typography.php @@ -270,28 +270,61 @@ function gutenberg_get_typography_value_and_unit( $raw_value, $coerce_to = '', $ * @param string $maximum_font_size_raw Maximumn font size for any clamp() calculation. * @return string A font-size value using clamp(). */ -function gutenberg_get_computed_typography_clamp_value( $fluid_settings, $minimum_font_size_raw, $maximum_font_size_raw ) { - $minimum_font_size = gutenberg_get_typography_value_and_unit( $minimum_font_size_raw ); - // We get a 'preferred' unit to keep units across the calc as consistent as possible. - $font_size_unit = $minimum_font_size['unit']; - - // Grab the maximum font size and normalize it in order to use the value for calculations. - $maximum_font_size = gutenberg_get_typography_value_and_unit( $maximum_font_size_raw, $font_size_unit ); - // Use rem for accessible fluid target font scaling. - $minimum_font_size_rem = gutenberg_get_typography_value_and_unit( $minimum_font_size_raw, 'rem' ); - - // Viewport widths defined for fluid typography. Normalize units. - $maximum_viewport_width = gutenberg_get_typography_value_and_unit( $fluid_settings['maxViewportWidth'], $font_size_unit ); - $minimum_viewport_width = gutenberg_get_typography_value_and_unit( $fluid_settings['minViewportWidth'], $font_size_unit ); - - // Build CSS rule. - // Borrowed from https://websemantics.uk/tools/responsive-font-calculator/. - $view_port_width_offset = round( $minimum_viewport_width['value'] / 100, 3 ) . $font_size_unit; - $linear_factor = 100 * ( ( $maximum_font_size['value'] - $minimum_font_size['value'] ) / ( $maximum_viewport_width['value'] - $minimum_viewport_width['value'] ) ); - $linear_factor = round( $linear_factor, 3 ); - $fluid_target_font_size = 'calc(' . implode( '', $minimum_font_size_rem ) . " + ((1vw - $view_port_width_offset) * $linear_factor))"; - - return "clamp({$minimum_font_size_raw}, $fluid_target_font_size, {$maximum_font_size_raw})"; +function gutenberg_get_computed_fluid_typography_value( $fluid_settings, $minimum_font_size_raw, $maximum_font_size_raw ) { + // Min and max viewport widths. + $default_maximum_viewport_width = '1600px'; + $default_minimum_viewport_width = '768px'; + $maximum_viewport_width_raw = isset( $fluid_settings['max'] ) ? $fluid_settings['max'] : $default_maximum_viewport_width; + $minimum_viewport_width_raw = isset( $fluid_settings['min'] ) ? $fluid_settings['min'] : $default_minimum_viewport_width; + + // If min, max and viewport sizes are there, do `clamp()` + if ( $minimum_font_size_raw && $maximum_font_size_raw ) { + $minimum_font_size = gutenberg_get_typography_value_and_unit( $minimum_font_size_raw ); + // We get a 'preferred' unit to keep units across the calc as consistent as possible. + $font_size_unit = $minimum_font_size['unit']; + + // Grab the maximum font size and normalize it in order to use the value for calculations. + $maximum_font_size = gutenberg_get_typography_value_and_unit( $maximum_font_size_raw, $font_size_unit ); + // Use rem for accessible fluid target font scaling. + $minimum_font_size_rem = gutenberg_get_typography_value_and_unit( $minimum_font_size_raw, 'rem' ); + + // Viewport widths defined for fluid typography. Normalize units. + $maximum_viewport_width = gutenberg_get_typography_value_and_unit( $maximum_viewport_width_raw, $font_size_unit ); + $minimum_viewport_width = gutenberg_get_typography_value_and_unit( $minimum_viewport_width_raw, $font_size_unit ); + + // Build CSS rule. + // Borrowed from https://websemantics.uk/tools/responsive-font-calculator/. + $view_port_width_offset = round( $minimum_viewport_width['value'] / 100, 3 ) . $font_size_unit; + $linear_factor = 100 * ( ( $maximum_font_size['value'] - $minimum_font_size['value'] ) / ( $maximum_viewport_width['value'] - $minimum_viewport_width['value'] ) ); + $linear_factor = round( $linear_factor, 3 ); + $fluid_target_font_size = 'calc(' . implode( '', $minimum_font_size_rem ) . " + ((1vw - $view_port_width_offset) * $linear_factor))"; + + return "clamp($minimum_font_size_raw, $fluid_target_font_size, $maximum_font_size_raw)"; + } + + if ( $minimum_font_size_raw ) { + // Coerce units for ratio calculation. + $minimum_font_size = gutenberg_get_typography_value_and_unit( $minimum_font_size_raw, 'rem' ); + $minimum_viewport_width = gutenberg_get_typography_value_and_unit( $minimum_viewport_width_raw, 'rem' ); + // Ratio of mmin_font_size / min_viewport + $min_ratio = ( $minimum_font_size['value'] / $minimum_viewport_width['value'] ) * 100; + $min_size = implode( '', $minimum_font_size ); + // The font-size will be set at $min_size, unless the computed value of calc($min_ratio * 1vw) is greater than that of $min_size, + // in which case it will be set to that value instead. + return "max($min_size, calc($min_ratio * 1vw))"; + } + + if ( $maximum_font_size_raw ) { + // Coerce units for ratio calculation. + $maximum_font_size = gutenberg_get_typography_value_and_unit( $maximum_font_size_raw, 'rem' ); + $maximum_viewport_width = gutenberg_get_typography_value_and_unit( $maximum_viewport_width_raw, 'rem' ); + // Ratio of max_font_size / max_viewport. + $max_ratio = ( $maximum_font_size['value'] / $maximum_viewport_width['value'] ) * 100; + $max_size = implode( '', $maximum_font_size ); + // The font-size will be set at $max_size, unless the result of calc($max_ratio * 1vw) is less than $max_size, + // in which case it will be set to that value instead. + return "min($max_size, calc($max_ratio * 1vw))"; + } } /** @@ -301,86 +334,42 @@ function gutenberg_get_computed_typography_clamp_value( $fluid_settings, $minimu * @return string Font-size value. */ function gutenberg_get_typography_font_size_value( $preset ) { - $typography_settings = gutenberg_get_global_settings( array( 'typography' ) ); - - if ( ! isset( $typography_settings['fluid'] ) ) { - return $preset['size']; - } - - $fluid_settings = $typography_settings['fluid']; - // Font sizes. $fluid_font_size_settings = isset( $preset['fluidSize'] ) ? $preset['fluidSize'] : null; + // if ( ! $fluid_font_size_settings ) { return $preset['size']; } - $minimum_font_size_raw = isset( $fluid_font_size_settings['minSize'] ) ? $fluid_font_size_settings['minSize'] : null; - $maximum_font_size_raw = isset( $fluid_font_size_settings['maxSize'] ) ? $fluid_font_size_settings['maxSize'] : null; - $fluid_formula = isset( $fluid_font_size_settings['fluidFormula'] ) ? $fluid_font_size_settings['fluidFormula'] : null; - $viewport_widths_set = isset( $fluid_settings['minViewportWidth'] ) && isset( $fluid_settings['maxViewportWidth'] ); + $minimum_font_size_raw = isset( $fluid_font_size_settings['min'] ) ? $fluid_font_size_settings['min'] : null; + $maximum_font_size_raw = isset( $fluid_font_size_settings['max'] ) ? $fluid_font_size_settings['max'] : null; + + // Grab fluid setting, if any. + $typography_settings = gutenberg_get_global_settings( array( 'typography' ) ); + $fluid_settings = isset( $typography_settings['fluid'] ) ? $typography_settings['fluid'] : null; // Gutenberg's internal implementation. /* "fluid": { - "maxViewportWidth": "1600px", - "minViewportWidth": "768px" + "max": "1600px", + "min": "768px" }, "fontSizes": [ { "size": "5.25rem", "fluidSize": { - "minSize": "5.25rem", - "maxSize": "9rem" + "min": "5.25rem", + "max": "9rem" }, "slug": "colossal", "name": "Colossal" } */ // Expect all required variables except formula to trigger internal clamp() implementation based on min/max viewport width. - if ( ! $fluid_formula && $minimum_font_size_raw && $maximum_font_size_raw && $viewport_widths_set ) { - return gutenberg_get_computed_typography_clamp_value( $fluid_settings, $minimum_font_size_raw, $maximum_font_size_raw ); - } - - // If there are min or max viewport widths, use custom implementation if values available. - // min, max sizes and fluid formula? Use clamp(). - - /* - "fluid": true, - "fontSizes": [ - { - "size": "2rem", - "fluidSize": { - "minSize": "2rem", - "fluidFormula": "calc(2.5 / 100 * 100vw)", - "maxSize": "2.5rem" - }, - "slug": "large", - "name": "Large" - }, - */ - if ( $fluid_formula && $minimum_font_size_raw && $maximum_font_size_raw ) { - return "clamp($minimum_font_size_raw, $fluid_formula, $maximum_font_size_raw)"; - } - - // Use a custom formula. Could be clamp(), could be anything. - - /* - "fluid": true, - "fontSizes": [ - { - "size": "3.7rem", - "fluidSize": { - "fluidFormula": "calc(3.7rem * 1px + 2 * 1vw)" - }, - "slug": "huge", - "name": "Huge" - }, - */ - if ( $fluid_formula && ! $minimum_font_size_raw && ! $maximum_font_size_raw ) { - return $fluid_formula; + if ( $minimum_font_size_raw || $maximum_font_size_raw ) { + return gutenberg_get_computed_fluid_typography_value( $fluid_settings, $minimum_font_size_raw, $maximum_font_size_raw ); } return $preset['size']; diff --git a/phpunit/block-supports/typography-test.php b/phpunit/block-supports/typography-test.php index bc5655ebb69856..8efd5add463ac8 100644 --- a/phpunit/block-supports/typography-test.php +++ b/phpunit/block-supports/typography-test.php @@ -122,7 +122,7 @@ function test_typography_with_skipped_serialization_block_supports() { } function test_letter_spacing_with_individual_skipped_serialization_block_supports() { - $this->test_block_name = 'test/letter-spacing-with-individua-skipped-serialization-block-supports'; + $this->test_block_name = 'test/letter-spacing-with-individual-skipped-serialization-block-supports'; register_block_type( $this->test_block_name, array( diff --git a/schemas/json/theme.json b/schemas/json/theme.json index bf5fa1d7089019..734c849cd99043 100644 --- a/schemas/json/theme.json +++ b/schemas/json/theme.json @@ -320,12 +320,12 @@ "description": "Enables fluid typography and allows users to set global fluid typography parameters.", "type": "object", "properties": { - "maxViewportWidth": { - "description": "Allow users to set custom a max viewport width.", + "max": { + "description": "Allow users to set custom a max viewport width in px, rem or em.", "type": "string" }, - "minViewportWidth": { - "description": "Allow users to set custom a min viewport width.", + "min": { + "description": "Allow users to set custom a min viewport width in px, rem or em.", "type": "string" } } @@ -372,6 +372,20 @@ "size": { "description": "CSS font-size value, including units.", "type": "string" + }, + "fluidSize": { + "type": "object", + "properties": { + "min": { + "description": "A min font size for fluid font size calculations in px, rem or em.", + "type": "string" + }, + "max": { + "description": "A max font size for fluid font size calculations in px, rem or em.", + "type": "string" + } + }, + "additionalProperties": false } }, "additionalProperties": false From fed9f2fca1fcddc2145c7acff015e3fc551fb93a Mon Sep 17 00:00:00 2001 From: ramonjd Date: Fri, 29 Apr 2022 15:53:31 +1000 Subject: [PATCH 13/24] Checking for valid units Adding tests Docs --- .../theme-json-reference/theme-json-living.md | 2 +- lib/block-supports/typography.php | 85 +++++++++++-------- phpunit/block-supports/typography-test.php | 77 +++++++++++++++++ 3 files changed, 127 insertions(+), 37 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 09fdeadbb3757f..949863ee189253 100644 --- a/docs/reference-guides/theme-json-reference/theme-json-living.md +++ b/docs/reference-guides/theme-json-reference/theme-json-living.md @@ -104,7 +104,7 @@ Settings related to typography. | textDecoration | boolean | true | | | textTransform | boolean | true | | | dropCap | boolean | true | | -| fontSizes | array | | name, size, slug | +| fontSizes | array | | fluidSize, name, size, slug | | fontFamilies | array | | fontFace, fontFamily, name, slug | --- diff --git a/lib/block-supports/typography.php b/lib/block-supports/typography.php index 08efee58b38e0d..dc86ce78d0cad5 100644 --- a/lib/block-supports/typography.php +++ b/lib/block-supports/typography.php @@ -223,7 +223,9 @@ function gutenberg_typography_get_css_variable_inline_style( $attributes, $featu } /** - * Checks a string for a unit and value and returns an array consisting of `'value'` and `'unit'`, e.g., [ '42', 'rem' ]. + * Internal method that checks a string for a unit and value and returns an array consisting of `'value'` and `'unit'`, e.g., [ '42', 'rem' ]. + * + * @access private * * @param string $raw_value Raw size value from theme.json. * @param string $coerce_to Coerce the value to rem or px. Default `'rem'`. @@ -232,13 +234,17 @@ function gutenberg_typography_get_css_variable_inline_style( $attributes, $featu * @return array An array consisting of `'value'` and `'unit'`, e.g., [ '42', 'rem' ] */ function gutenberg_get_typography_value_and_unit( $raw_value, $coerce_to = '', $root_font_size_value = 16, $acceptable_units = array( 'rem', 'px', 'em' ) ) { + if ( empty( $raw_value ) ) { + return null; + } + $acceptable_units_group = implode( '|', $acceptable_units ); $pattern = '/^(\d*\.?\d+)(' . $acceptable_units_group . '){1,1}$/'; preg_match( $pattern, $raw_value, $matches ); // We need a number value and a px or rem unit. - if ( ! isset( $matches[1] ) && isset( $matches[2] ) ) { + if ( ! isset( $matches[1] ) || ! isset( $matches[2] ) ) { return null; } @@ -263,28 +269,36 @@ function gutenberg_get_typography_value_and_unit( $raw_value, $coerce_to = '', $ } /** - * Internal implementation of clamp() based on available min/max viewport width, and min/max font sizes.. + * Internal implementation of clamp() based on available min/max viewport width, and min/max font sizes. + * + * @access private * * @param array $fluid_settings Possible values: array( 'minViewportWidth' => string, 'maxViewportWidth' => string ). * @param string $minimum_font_size_raw Minimumn font size for any clamp() calculation. * @param string $maximum_font_size_raw Maximumn font size for any clamp() calculation. - * @return string A font-size value using clamp(). + * @return string|null A font-size value using clamp(). */ function gutenberg_get_computed_fluid_typography_value( $fluid_settings, $minimum_font_size_raw, $maximum_font_size_raw ) { // Min and max viewport widths. $default_maximum_viewport_width = '1600px'; $default_minimum_viewport_width = '768px'; - $maximum_viewport_width_raw = isset( $fluid_settings['max'] ) ? $fluid_settings['max'] : $default_maximum_viewport_width; + $maximum_viewport_width_raw = isset( $fluid_settings['max'] ) ? $fluid_settings['max'] : $default_maximum_viewport_width; $minimum_viewport_width_raw = isset( $fluid_settings['min'] ) ? $fluid_settings['min'] : $default_minimum_viewport_width; - // If min, max and viewport sizes are there, do `clamp()` - if ( $minimum_font_size_raw && $maximum_font_size_raw ) { + // If min, max and viewport sizes are there, do `clamp()`. + if ( $minimum_font_size_raw && $maximum_font_size_raw ) { $minimum_font_size = gutenberg_get_typography_value_and_unit( $minimum_font_size_raw ); // We get a 'preferred' unit to keep units across the calc as consistent as possible. $font_size_unit = $minimum_font_size['unit']; // Grab the maximum font size and normalize it in order to use the value for calculations. $maximum_font_size = gutenberg_get_typography_value_and_unit( $maximum_font_size_raw, $font_size_unit ); + + // Protect against unsupported units. + if ( ! $maximum_font_size || ! $minimum_font_size ) { + return null; + } + // Use rem for accessible fluid target font scaling. $minimum_font_size_rem = gutenberg_get_typography_value_and_unit( $minimum_font_size_raw, 'rem' ); @@ -300,15 +314,22 @@ function gutenberg_get_computed_fluid_typography_value( $fluid_settings, $minimu $fluid_target_font_size = 'calc(' . implode( '', $minimum_font_size_rem ) . " + ((1vw - $view_port_width_offset) * $linear_factor))"; return "clamp($minimum_font_size_raw, $fluid_target_font_size, $maximum_font_size_raw)"; - } + } if ( $minimum_font_size_raw ) { // Coerce units for ratio calculation. $minimum_font_size = gutenberg_get_typography_value_and_unit( $minimum_font_size_raw, 'rem' ); $minimum_viewport_width = gutenberg_get_typography_value_and_unit( $minimum_viewport_width_raw, 'rem' ); - // Ratio of mmin_font_size / min_viewport - $min_ratio = ( $minimum_font_size['value'] / $minimum_viewport_width['value'] ) * 100; - $min_size = implode( '', $minimum_font_size ); + + // Protect against unsupported units. + if ( ! $minimum_font_size || ! $minimum_viewport_width ) { + return null; + } + + // Ratio of min_font_size / min_viewport. + $min_ratio = round( ( $minimum_font_size['value'] / $minimum_viewport_width['value'] ) * 100, 3 ); + $min_size = implode( '', $minimum_font_size ); + // The font-size will be set at $min_size, unless the computed value of calc($min_ratio * 1vw) is greater than that of $min_size, // in which case it will be set to that value instead. return "max($min_size, calc($min_ratio * 1vw))"; @@ -318,17 +339,25 @@ function gutenberg_get_computed_fluid_typography_value( $fluid_settings, $minimu // Coerce units for ratio calculation. $maximum_font_size = gutenberg_get_typography_value_and_unit( $maximum_font_size_raw, 'rem' ); $maximum_viewport_width = gutenberg_get_typography_value_and_unit( $maximum_viewport_width_raw, 'rem' ); + + // Protect against unsupported units. + if ( ! $maximum_viewport_width || ! $maximum_font_size ) { + return null; + } + // Ratio of max_font_size / max_viewport. - $max_ratio = ( $maximum_font_size['value'] / $maximum_viewport_width['value'] ) * 100; - $max_size = implode( '', $maximum_font_size ); + $max_ratio = round( ( $maximum_font_size['value'] / $maximum_viewport_width['value'] ) * 100, 3 ); + $max_size = implode( '', $maximum_font_size ); + // The font-size will be set at $max_size, unless the result of calc($max_ratio * 1vw) is less than $max_size, - // in which case it will be set to that value instead. + // in which case it will be set to that value instead. return "min($max_size, calc($max_ratio * 1vw))"; } } /** - * Returns a font-size value based on a given font-size preset. If typography.fluid is enabled it will try to return a fluid string. + * Returns a font-size value based on a given font-size preset. + * Takes into account fluid typography parameters and attempts to return a css formula depending on available, valid values. * * @param array $preset fontSizes preset value as seen in theme.json. * @return string Font-size value. @@ -337,7 +366,6 @@ function gutenberg_get_typography_font_size_value( $preset ) { // Font sizes. $fluid_font_size_settings = isset( $preset['fluidSize'] ) ? $preset['fluidSize'] : null; - // if ( ! $fluid_font_size_settings ) { return $preset['size']; } @@ -349,27 +377,12 @@ function gutenberg_get_typography_font_size_value( $preset ) { $typography_settings = gutenberg_get_global_settings( array( 'typography' ) ); $fluid_settings = isset( $typography_settings['fluid'] ) ? $typography_settings['fluid'] : null; - // Gutenberg's internal implementation. - - /* - "fluid": { - "max": "1600px", - "min": "768px" - }, - "fontSizes": [ - { - "size": "5.25rem", - "fluidSize": { - "min": "5.25rem", - "max": "9rem" - }, - "slug": "colossal", - "name": "Colossal" - } - */ - // Expect all required variables except formula to trigger internal clamp() implementation based on min/max viewport width. if ( $minimum_font_size_raw || $maximum_font_size_raw ) { - return gutenberg_get_computed_fluid_typography_value( $fluid_settings, $minimum_font_size_raw, $maximum_font_size_raw ); + $fluid_font_size_value = gutenberg_get_computed_fluid_typography_value( $fluid_settings, $minimum_font_size_raw, $maximum_font_size_raw ); + + if ( ! empty( $fluid_font_size_value ) ) { + return $fluid_font_size_value; + } } return $preset['size']; diff --git a/phpunit/block-supports/typography-test.php b/phpunit/block-supports/typography-test.php index 8efd5add463ac8..7bbe8bef5b92b1 100644 --- a/phpunit/block-supports/typography-test.php +++ b/phpunit/block-supports/typography-test.php @@ -207,4 +207,81 @@ function test_font_family_with_class() { $this->assertSame( $expected, $actual ); } + + /** + * Tests generating font size values, including fluid formulae, from fontSizes preset. + * + * @dataProvider data_generate_font_size_preset_fixtures + */ + function test_gutenberg_get_typography_font_size_value( $font_size_preset, $expected_output ) { + $actual = gutenberg_get_typography_font_size_value( $font_size_preset ); + + $this->assertSame( $expected_output, $actual ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_generate_font_size_preset_fixtures() { + return array( + 'default_return_value' => array( + 'font_size_preset' => array( + 'size' => '28px', + ), + 'expected_output' => '28px', + ), + + 'default_return_value_with_no_valid_fluid_values' => array( + 'font_size_preset' => array( + 'size' => '28px', + 'fluidSize' => array(), + ), + 'expected_output' => '28px', + ), + + 'default_return_size_with_invalid_fluid_units' => array( + 'font_size_preset' => array( + 'size' => '10em', + 'fluidSize' => array( + 'min' => '20vw', + 'max' => '50%', + ), + ), + 'expected_output' => '10em', + ), + + 'default_return_fluid_clamp_value' => array( + 'font_size_preset' => array( + 'size' => '28px', + 'fluidSize' => array( + 'min' => '20px', + 'max' => '50rem', + ), + ), + 'expected_output' => 'clamp(20px, calc(1.25rem + ((1vw - 7.68px) * 93.75)), 50rem)', + ), + + 'default_return_fluid_min_value' => array( + 'font_size_preset' => array( + 'size' => '28px', + 'fluidSize' => array( + 'min' => '2.6rem', + ), + ), + 'expected_output' => 'max(2.6rem, calc(5.417 * 1vw))', + ), + + 'default_return_fluid_max_value' => array( + 'font_size_preset' => array( + 'size' => '28px', + 'fluidSize' => array( + 'max' => '80px', + ), + ), + 'expected_output' => 'min(5rem, calc(5 * 1vw))', + ), + ); + } } From dd25039b17546e1afbe4a6bf253e5e3572afe607 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Mon, 2 May 2022 10:40:39 +1000 Subject: [PATCH 14/24] Looking in layout settings for viewport width fallbacks --- lib/block-supports/typography.php | 55 +++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/lib/block-supports/typography.php b/lib/block-supports/typography.php index dc86ce78d0cad5..789c0acfea0ad9 100644 --- a/lib/block-supports/typography.php +++ b/lib/block-supports/typography.php @@ -273,22 +273,20 @@ function gutenberg_get_typography_value_and_unit( $raw_value, $coerce_to = '', $ * * @access private * - * @param array $fluid_settings Possible values: array( 'minViewportWidth' => string, 'maxViewportWidth' => string ). - * @param string $minimum_font_size_raw Minimumn font size for any clamp() calculation. - * @param string $maximum_font_size_raw Maximumn font size for any clamp() calculation. + * @param string $minimum_viewport_width_raw Minimum viewport size from which type will have fluidity. + * @param string $maximum_viewport_width_raw Maximum size up to which type will have fluidity. + * @param string $minimum_font_size_raw Minimum font size for any clamp() calculation. + * @param string $maximum_font_size_raw Maximum font size for any clamp() calculation. * @return string|null A font-size value using clamp(). */ -function gutenberg_get_computed_fluid_typography_value( $fluid_settings, $minimum_font_size_raw, $maximum_font_size_raw ) { - // Min and max viewport widths. - $default_maximum_viewport_width = '1600px'; - $default_minimum_viewport_width = '768px'; - $maximum_viewport_width_raw = isset( $fluid_settings['max'] ) ? $fluid_settings['max'] : $default_maximum_viewport_width; - $minimum_viewport_width_raw = isset( $fluid_settings['min'] ) ? $fluid_settings['min'] : $default_minimum_viewport_width; +function gutenberg_get_computed_fluid_typography_value( $minimum_viewport_width_raw, $maximum_viewport_width_raw, $minimum_font_size_raw, $maximum_font_size_raw ) { - // If min, max and viewport sizes are there, do `clamp()`. + // Min, max and viewport sizes are there: `clamp()`. if ( $minimum_font_size_raw && $maximum_font_size_raw ) { $minimum_font_size = gutenberg_get_typography_value_and_unit( $minimum_font_size_raw ); - // We get a 'preferred' unit to keep units across the calc as consistent as possible. + + // We get a 'preferred' unit to keep units consistent when calculating. + // Otherwise the result will not be accurate. $font_size_unit = $minimum_font_size['unit']; // Grab the maximum font size and normalize it in order to use the value for calculations. @@ -316,6 +314,7 @@ function gutenberg_get_computed_fluid_typography_value( $fluid_settings, $minimu return "clamp($minimum_font_size_raw, $fluid_target_font_size, $maximum_font_size_raw)"; } + // Only min font size is available: max(). if ( $minimum_font_size_raw ) { // Coerce units for ratio calculation. $minimum_font_size = gutenberg_get_typography_value_and_unit( $minimum_font_size_raw, 'rem' ); @@ -335,6 +334,7 @@ function gutenberg_get_computed_fluid_typography_value( $fluid_settings, $minimu return "max($min_size, calc($min_ratio * 1vw))"; } + // Only min font size is available: min(). if ( $maximum_font_size_raw ) { // Coerce units for ratio calculation. $maximum_font_size = gutenberg_get_typography_value_and_unit( $maximum_font_size_raw, 'rem' ); @@ -370,15 +370,44 @@ function gutenberg_get_typography_font_size_value( $preset ) { return $preset['size']; } + // Default viewport widths. + $default_maximum_viewport_width = '1600px'; + $default_minimum_viewport_width = '768px'; + $maximum_viewport_width_raw = null; + $minimum_viewport_width_raw = null; + + // Grab fluid font sizes. $minimum_font_size_raw = isset( $fluid_font_size_settings['min'] ) ? $fluid_font_size_settings['min'] : null; $maximum_font_size_raw = isset( $fluid_font_size_settings['max'] ) ? $fluid_font_size_settings['max'] : null; - // Grab fluid setting, if any. + // Grab fluid settings, if any. $typography_settings = gutenberg_get_global_settings( array( 'typography' ) ); $fluid_settings = isset( $typography_settings['fluid'] ) ? $typography_settings['fluid'] : null; + if ( isset( $fluid_settings['max'] ) ) { + $maximum_viewport_width_raw = $fluid_settings['max']; + } + + if ( isset( $fluid_settings['min'] ) ) { + $minimum_viewport_width_raw = $fluid_settings['min']; + } + + // Apply viewport width fallbacks. + // First from "layout.contentSize" for min width and "layout.wideSize" for max width. + // Then from the hardcoded defaults. + if ( ! $maximum_viewport_width_raw || ! $minimum_viewport_width_raw ) { + $layout_settings = gutenberg_get_global_settings( array( 'layout' ) ); + if ( ! $maximum_viewport_width_raw ) { + $maximum_viewport_width_raw = isset( $layout_settings['wideSize'] ) ? $layout_settings['wideSize'] : $default_maximum_viewport_width; + } + + if ( ! $minimum_viewport_width_raw ) { + $minimum_viewport_width_raw = isset( $layout_settings['contentSize'] ) ? $layout_settings['contentSize'] : $default_minimum_viewport_width; + } + } + // We need at least one fluid font size to return a valid formula. if ( $minimum_font_size_raw || $maximum_font_size_raw ) { - $fluid_font_size_value = gutenberg_get_computed_fluid_typography_value( $fluid_settings, $minimum_font_size_raw, $maximum_font_size_raw ); + $fluid_font_size_value = gutenberg_get_computed_fluid_typography_value( $minimum_viewport_width_raw, $maximum_viewport_width_raw, $minimum_font_size_raw, $maximum_font_size_raw ); if ( ! empty( $fluid_font_size_value ) ) { return $fluid_font_size_value; From aa6763814f237bf3d5ca8f572a17b350745eda90 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Mon, 16 May 2022 12:10:35 +1000 Subject: [PATCH 15/24] Post-rebase file shuffling. Renaming properties to `__experimental*` --- lib/block-supports/typography.php | 4 +- .../wordpress-6.1/class-wp-theme-json-6-1.php | 155 ++++++++++++++++ .../class-wp-theme-json-gutenberg.php | 172 ------------------ 3 files changed, 157 insertions(+), 174 deletions(-) delete mode 100644 lib/compat/wordpress-6.1/class-wp-theme-json-gutenberg.php diff --git a/lib/block-supports/typography.php b/lib/block-supports/typography.php index 789c0acfea0ad9..cded5d00359050 100644 --- a/lib/block-supports/typography.php +++ b/lib/block-supports/typography.php @@ -314,7 +314,7 @@ function gutenberg_get_computed_fluid_typography_value( $minimum_viewport_width_ return "clamp($minimum_font_size_raw, $fluid_target_font_size, $maximum_font_size_raw)"; } - // Only min font size is available: max(). + // Only minimum font size is available: max(). if ( $minimum_font_size_raw ) { // Coerce units for ratio calculation. $minimum_font_size = gutenberg_get_typography_value_and_unit( $minimum_font_size_raw, 'rem' ); @@ -334,7 +334,7 @@ function gutenberg_get_computed_fluid_typography_value( $minimum_viewport_width_ return "max($min_size, calc($min_ratio * 1vw))"; } - // Only min font size is available: min(). + // Only maximum font size is available: min(). if ( $maximum_font_size_raw ) { // Coerce units for ratio calculation. $maximum_font_size = gutenberg_get_typography_value_and_unit( $maximum_font_size_raw, 'rem' ); diff --git a/lib/compat/wordpress-6.1/class-wp-theme-json-6-1.php b/lib/compat/wordpress-6.1/class-wp-theme-json-6-1.php index 5fc0dd1223ba62..88d2be013a0534 100644 --- a/lib/compat/wordpress-6.1/class-wp-theme-json-6-1.php +++ b/lib/compat/wordpress-6.1/class-wp-theme-json-6-1.php @@ -126,6 +126,161 @@ public static function get_element_class_name( $element ) { return array_key_exists( $element, static::__EXPERIMENTAL_ELEMENT_CLASS_NAMES ) ? static::__EXPERIMENTAL_ELEMENT_CLASS_NAMES[ $element ] : ''; } + /** + * Presets are a set of values that serve + * to bootstrap some styles: colors, font sizes, etc. + * + * They are a unkeyed array of values such as: + * + * ```php + * array( + * array( + * 'slug' => 'unique-name-within-the-set', + * 'name' => 'Name for the UI', + * => 'value' + * ), + * ) + * ``` + * + * This contains the necessary metadata to process them: + * + * - path => Where to find the preset within the settings section. + * - prevent_override => Disables override of default presets by theme presets. + * The relationship between whether to override the defaults + * and whether the defaults are enabled is inverse: + * - If defaults are enabled => theme presets should not be overriden + * - If defaults are disabled => theme presets should be overriden + * For example, a theme sets defaultPalette to false, + * making the default palette hidden from the user. + * In that case, we want all the theme presets to be present, + * so they should override the defaults by setting this false. + * - use_default_names => whether to use the default names + * - value_key => the key that represents the value + * - value_func => optionally, instead of value_key, a function to generate + * the value that takes a preset as an argument + * (either value_key or value_func should be present) + * - css_vars => template string to use in generating the CSS Custom Property. + * Example output: "--wp--preset--duotone--blue: " will generate as many CSS Custom Properties as presets defined + * substituting the $slug for the slug's value for each preset value. + * - classes => array containing a structure with the classes to + * generate for the presets, where for each array item + * the key is the class name and the value the property name. + * The "$slug" substring will be replaced by the slug of each preset. + * For example: + * 'classes' => array( + * '.has-$slug-color' => 'color', + * '.has-$slug-background-color' => 'background-color', + * '.has-$slug-border-color' => 'border-color', + * ) + * - properties => array of CSS properties to be used by kses to + * validate the content of each preset + * by means of the remove_insecure_properties method. + */ + const PRESETS_METADATA = array( + array( + 'path' => array( 'color', 'palette' ), + 'prevent_override' => array( 'color', 'defaultPalette' ), + 'use_default_names' => false, + 'value_key' => 'color', + 'css_vars' => '--wp--preset--color--$slug', + 'classes' => array( + '.has-$slug-color' => 'color', + '.has-$slug-background-color' => 'background-color', + '.has-$slug-border-color' => 'border-color', + ), + 'properties' => array( 'color', 'background-color', 'border-color' ), + ), + array( + 'path' => array( 'color', 'gradients' ), + 'prevent_override' => array( 'color', 'defaultGradients' ), + 'use_default_names' => false, + 'value_key' => 'gradient', + 'css_vars' => '--wp--preset--gradient--$slug', + 'classes' => array( '.has-$slug-gradient-background' => 'background' ), + 'properties' => array( 'background' ), + ), + array( + 'path' => array( 'color', 'duotone' ), + 'prevent_override' => array( 'color', 'defaultDuotone' ), + 'use_default_names' => false, + 'value_func' => 'gutenberg_get_duotone_filter_property', + 'css_vars' => '--wp--preset--duotone--$slug', + 'classes' => array(), + 'properties' => array( 'filter' ), + ), + array( + 'path' => array( 'typography', 'fontSizes' ), + 'prevent_override' => false, + 'use_default_names' => true, + 'value_func' => 'gutenberg_get_typography_font_size_value', + 'css_vars' => '--wp--preset--font-size--$slug', + 'classes' => array( '.has-$slug-font-size' => 'font-size' ), + 'properties' => array( 'font-size' ), + ), + array( + 'path' => array( 'typography', 'fontFamilies' ), + 'prevent_override' => false, + 'use_default_names' => false, + 'value_key' => 'fontFamily', + 'css_vars' => '--wp--preset--font-family--$slug', + 'classes' => array( '.has-$slug-font-family' => 'font-family' ), + 'properties' => array( 'font-family' ), + ), + ); + + /** + * The valid properties under the settings key. + * + * @var array + */ + const VALID_SETTINGS = array( + 'appearanceTools' => null, + 'border' => array( + 'color' => null, + 'radius' => null, + 'style' => null, + 'width' => null, + ), + 'color' => array( + 'background' => null, + 'custom' => null, + 'customDuotone' => null, + 'customGradient' => null, + 'defaultDuotone' => null, + 'defaultGradients' => null, + 'defaultPalette' => null, + 'duotone' => null, + 'gradients' => null, + 'link' => null, + 'palette' => null, + 'text' => null, + ), + 'custom' => null, + 'layout' => array( + 'contentSize' => null, + 'wideSize' => null, + ), + 'spacing' => array( + 'blockGap' => null, + 'margin' => null, + 'padding' => null, + 'units' => null, + ), + 'typography' => array( + 'fluid' => null, + 'customFontSize' => null, + 'dropCap' => null, + 'fontFamilies' => null, + 'fontSizes' => null, + 'fontStyle' => null, + 'fontWeight' => null, + 'letterSpacing' => null, + 'lineHeight' => null, + 'textDecoration' => null, + 'textTransform' => null, + ), + ); + /** * Sanitizes the input according to the schemas. * diff --git a/lib/compat/wordpress-6.1/class-wp-theme-json-gutenberg.php b/lib/compat/wordpress-6.1/class-wp-theme-json-gutenberg.php deleted file mode 100644 index d0decf35f6aac8..00000000000000 --- a/lib/compat/wordpress-6.1/class-wp-theme-json-gutenberg.php +++ /dev/null @@ -1,172 +0,0 @@ - 'unique-name-within-the-set', - * 'name' => 'Name for the UI', - * => 'value' - * ), - * ) - * ``` - * - * This contains the necessary metadata to process them: - * - * - path => Where to find the preset within the settings section. - * - prevent_override => Disables override of default presets by theme presets. - * The relationship between whether to override the defaults - * and whether the defaults are enabled is inverse: - * - If defaults are enabled => theme presets should not be overriden - * - If defaults are disabled => theme presets should be overriden - * For example, a theme sets defaultPalette to false, - * making the default palette hidden from the user. - * In that case, we want all the theme presets to be present, - * so they should override the defaults by setting this false. - * - use_default_names => whether to use the default names - * - value_key => the key that represents the value - * - value_func => optionally, instead of value_key, a function to generate - * the value that takes a preset as an argument - * (either value_key or value_func should be present) - * - css_vars => template string to use in generating the CSS Custom Property. - * Example output: "--wp--preset--duotone--blue: " will generate as many CSS Custom Properties as presets defined - * substituting the $slug for the slug's value for each preset value. - * - classes => array containing a structure with the classes to - * generate for the presets, where for each array item - * the key is the class name and the value the property name. - * The "$slug" substring will be replaced by the slug of each preset. - * For example: - * 'classes' => array( - * '.has-$slug-color' => 'color', - * '.has-$slug-background-color' => 'background-color', - * '.has-$slug-border-color' => 'border-color', - * ) - * - properties => array of CSS properties to be used by kses to - * validate the content of each preset - * by means of the remove_insecure_properties method. - */ - const PRESETS_METADATA = array( - array( - 'path' => array( 'color', 'palette' ), - 'prevent_override' => array( 'color', 'defaultPalette' ), - 'use_default_names' => false, - 'value_key' => 'color', - 'css_vars' => '--wp--preset--color--$slug', - 'classes' => array( - '.has-$slug-color' => 'color', - '.has-$slug-background-color' => 'background-color', - '.has-$slug-border-color' => 'border-color', - ), - 'properties' => array( 'color', 'background-color', 'border-color' ), - ), - array( - 'path' => array( 'color', 'gradients' ), - 'prevent_override' => array( 'color', 'defaultGradients' ), - 'use_default_names' => false, - 'value_key' => 'gradient', - 'css_vars' => '--wp--preset--gradient--$slug', - 'classes' => array( '.has-$slug-gradient-background' => 'background' ), - 'properties' => array( 'background' ), - ), - array( - 'path' => array( 'color', 'duotone' ), - 'prevent_override' => array( 'color', 'defaultDuotone' ), - 'use_default_names' => false, - 'value_func' => 'gutenberg_get_duotone_filter_property', - 'css_vars' => '--wp--preset--duotone--$slug', - 'classes' => array(), - 'properties' => array( 'filter' ), - ), - array( - 'path' => array( 'typography', 'fontSizes' ), - 'prevent_override' => false, - 'use_default_names' => true, - 'value_func' => 'gutenberg_get_typography_font_size_value', - 'css_vars' => '--wp--preset--font-size--$slug', - 'classes' => array( '.has-$slug-font-size' => 'font-size' ), - 'properties' => array( 'font-size' ), - ), - array( - 'path' => array( 'typography', 'fontFamilies' ), - 'prevent_override' => false, - 'use_default_names' => false, - 'value_key' => 'fontFamily', - 'css_vars' => '--wp--preset--font-family--$slug', - 'classes' => array( '.has-$slug-font-family' => 'font-family' ), - 'properties' => array( 'font-family' ), - ), - ); - - /** - * The valid properties under the settings key. - * - * @var array - */ - const VALID_SETTINGS = array( - 'appearanceTools' => null, - 'border' => array( - 'color' => null, - 'radius' => null, - 'style' => null, - 'width' => null, - ), - 'color' => array( - 'background' => null, - 'custom' => null, - 'customDuotone' => null, - 'customGradient' => null, - 'defaultDuotone' => null, - 'defaultGradients' => null, - 'defaultPalette' => null, - 'duotone' => null, - 'gradients' => null, - 'link' => null, - 'palette' => null, - 'text' => null, - ), - 'custom' => null, - 'layout' => array( - 'contentSize' => null, - 'wideSize' => null, - ), - 'spacing' => array( - 'blockGap' => null, - 'margin' => null, - 'padding' => null, - 'units' => null, - ), - 'typography' => array( - 'fluid' => null, - 'customFontSize' => null, - 'dropCap' => null, - 'fontFamilies' => null, - 'fontSizes' => null, - 'fontStyle' => null, - 'fontWeight' => null, - 'letterSpacing' => null, - 'lineHeight' => null, - 'textDecoration' => null, - 'textTransform' => null, - ), - ); -} From 930482975b8504b6614dfff59ec758c3f4089e6b Mon Sep 17 00:00:00 2001 From: ramonjd Date: Thu, 26 May 2022 13:57:51 +1000 Subject: [PATCH 16/24] Update CHANGELOG.md --- schemas/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/schemas/CHANGELOG.md b/schemas/CHANGELOG.md index e04ce921cdfdc4..51d33d49707c27 100644 --- a/schemas/CHANGELOG.md +++ b/schemas/CHANGELOG.md @@ -2,4 +2,7 @@ ## Unreleased +- Add new properties `settings.typography.fluid` and `settings.typography.fontSizes[n].fluidSize` to theme.json to enable fluid typography ([#39529](https://github.com/WordPress/gutenberg/pull/39529)). + + Initial release. From e74b07bfc7f33b7f2d48ed3da5a47eb428519676 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Fri, 27 May 2022 18:26:53 +1000 Subject: [PATCH 17/24] min(), max() and clamp() automatically parse mathematic expressions so removing calc() props @wongjn --- lib/block-supports/typography.php | 10 +++++----- phpunit/block-supports/typography-test.php | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/block-supports/typography.php b/lib/block-supports/typography.php index cded5d00359050..8ac8fc9b6cfa8c 100644 --- a/lib/block-supports/typography.php +++ b/lib/block-supports/typography.php @@ -309,7 +309,7 @@ function gutenberg_get_computed_fluid_typography_value( $minimum_viewport_width_ $view_port_width_offset = round( $minimum_viewport_width['value'] / 100, 3 ) . $font_size_unit; $linear_factor = 100 * ( ( $maximum_font_size['value'] - $minimum_font_size['value'] ) / ( $maximum_viewport_width['value'] - $minimum_viewport_width['value'] ) ); $linear_factor = round( $linear_factor, 3 ); - $fluid_target_font_size = 'calc(' . implode( '', $minimum_font_size_rem ) . " + ((1vw - $view_port_width_offset) * $linear_factor))"; + $fluid_target_font_size = implode( '', $minimum_font_size_rem ) . " + ((1vw - $view_port_width_offset) * $linear_factor)"; return "clamp($minimum_font_size_raw, $fluid_target_font_size, $maximum_font_size_raw)"; } @@ -329,9 +329,9 @@ function gutenberg_get_computed_fluid_typography_value( $minimum_viewport_width_ $min_ratio = round( ( $minimum_font_size['value'] / $minimum_viewport_width['value'] ) * 100, 3 ); $min_size = implode( '', $minimum_font_size ); - // The font-size will be set at $min_size, unless the computed value of calc($min_ratio * 1vw) is greater than that of $min_size, + // The font-size will be set at $min_size, unless the computed value of $min_ratio * 1vw is greater than that of $min_size, // in which case it will be set to that value instead. - return "max($min_size, calc($min_ratio * 1vw))"; + return "max($min_size, $min_ratio * 1vw)"; } // Only maximum font size is available: min(). @@ -349,9 +349,9 @@ function gutenberg_get_computed_fluid_typography_value( $minimum_viewport_width_ $max_ratio = round( ( $maximum_font_size['value'] / $maximum_viewport_width['value'] ) * 100, 3 ); $max_size = implode( '', $maximum_font_size ); - // The font-size will be set at $max_size, unless the result of calc($max_ratio * 1vw) is less than $max_size, + // The font-size will be set at $max_size, unless the result of $max_ratio * 1vw is less than $max_size, // in which case it will be set to that value instead. - return "min($max_size, calc($max_ratio * 1vw))"; + return "min($max_size, $max_ratio * 1vw)"; } } diff --git a/phpunit/block-supports/typography-test.php b/phpunit/block-supports/typography-test.php index 7bbe8bef5b92b1..4dc2eefb1180c2 100644 --- a/phpunit/block-supports/typography-test.php +++ b/phpunit/block-supports/typography-test.php @@ -260,7 +260,7 @@ public function data_generate_font_size_preset_fixtures() { 'max' => '50rem', ), ), - 'expected_output' => 'clamp(20px, calc(1.25rem + ((1vw - 7.68px) * 93.75)), 50rem)', + 'expected_output' => 'clamp(20px, 1.25rem + ((1vw - 7.68px) * 93.75), 50rem)', ), 'default_return_fluid_min_value' => array( @@ -270,7 +270,7 @@ public function data_generate_font_size_preset_fixtures() { 'min' => '2.6rem', ), ), - 'expected_output' => 'max(2.6rem, calc(5.417 * 1vw))', + 'expected_output' => 'max(2.6rem, 5.417 * 1vw)', ), 'default_return_fluid_max_value' => array( @@ -280,7 +280,7 @@ public function data_generate_font_size_preset_fixtures() { 'max' => '80px', ), ), - 'expected_output' => 'min(5rem, calc(5 * 1vw))', + 'expected_output' => 'min(5rem, 5 * 1vw)', ), ); } From 00c51d1eacd4ac4afa532a190c257724b55411ae Mon Sep 17 00:00:00 2001 From: ramonjd Date: Fri, 17 Jun 2022 16:37:15 +1000 Subject: [PATCH 18/24] We're now supporting passing single values to the fluid type calculator, and returning clamp values based on a set of defaults: minFontSizeFactor, maxFontSizeFactor and scaleFactor. So that themes can opt-in to the system, typography.fluid should be true, in which case default values will be used, or an object of viewport width, minFontSizeFactor, maxFontSizeFactor and scaleFactor. The values in fontSizes will take precedence, then, if they're not there, we'll calculate a min and max font size based on the scale value. The calculations for min() and max() have been removed since we'll always have a min and max font size value. This means we're returning a clamp() value always. I think that's okay as it also removes any unexpected side effects. --- lib/block-supports/typography.php | 159 +++++++++------------ phpunit/block-supports/typography-test.php | 40 +++--- 2 files changed, 91 insertions(+), 108 deletions(-) diff --git a/lib/block-supports/typography.php b/lib/block-supports/typography.php index 8ac8fc9b6cfa8c..9d4b11ba4bbba0 100644 --- a/lib/block-supports/typography.php +++ b/lib/block-supports/typography.php @@ -277,118 +277,98 @@ function gutenberg_get_typography_value_and_unit( $raw_value, $coerce_to = '', $ * @param string $maximum_viewport_width_raw Maximum size up to which type will have fluidity. * @param string $minimum_font_size_raw Minimum font size for any clamp() calculation. * @param string $maximum_font_size_raw Maximum font size for any clamp() calculation. + * @param number $scale_factor A scale factor to determine how fast a font scales within boundaries. * @return string|null A font-size value using clamp(). */ -function gutenberg_get_computed_fluid_typography_value( $minimum_viewport_width_raw, $maximum_viewport_width_raw, $minimum_font_size_raw, $maximum_font_size_raw ) { +function gutenberg_get_computed_fluid_typography_value( $minimum_viewport_width_raw, $maximum_viewport_width_raw, $minimum_font_size_raw, $maximum_font_size_raw, $scale_factor ) { + $minimum_font_size = gutenberg_get_typography_value_and_unit( $minimum_font_size_raw ); - // Min, max and viewport sizes are there: `clamp()`. - if ( $minimum_font_size_raw && $maximum_font_size_raw ) { - $minimum_font_size = gutenberg_get_typography_value_and_unit( $minimum_font_size_raw ); + // We get a 'preferred' unit to keep units consistent when calculating. + // Otherwise the result will not be accurate. + $font_size_unit = $minimum_font_size['unit']; - // We get a 'preferred' unit to keep units consistent when calculating. - // Otherwise the result will not be accurate. - $font_size_unit = $minimum_font_size['unit']; + // Grab the maximum font size and normalize it in order to use the value for calculations. + $maximum_font_size = gutenberg_get_typography_value_and_unit( $maximum_font_size_raw, $font_size_unit ); - // Grab the maximum font size and normalize it in order to use the value for calculations. - $maximum_font_size = gutenberg_get_typography_value_and_unit( $maximum_font_size_raw, $font_size_unit ); - - // Protect against unsupported units. - if ( ! $maximum_font_size || ! $minimum_font_size ) { - return null; - } - - // Use rem for accessible fluid target font scaling. - $minimum_font_size_rem = gutenberg_get_typography_value_and_unit( $minimum_font_size_raw, 'rem' ); - - // Viewport widths defined for fluid typography. Normalize units. - $maximum_viewport_width = gutenberg_get_typography_value_and_unit( $maximum_viewport_width_raw, $font_size_unit ); - $minimum_viewport_width = gutenberg_get_typography_value_and_unit( $minimum_viewport_width_raw, $font_size_unit ); - - // Build CSS rule. - // Borrowed from https://websemantics.uk/tools/responsive-font-calculator/. - $view_port_width_offset = round( $minimum_viewport_width['value'] / 100, 3 ) . $font_size_unit; - $linear_factor = 100 * ( ( $maximum_font_size['value'] - $minimum_font_size['value'] ) / ( $maximum_viewport_width['value'] - $minimum_viewport_width['value'] ) ); - $linear_factor = round( $linear_factor, 3 ); - $fluid_target_font_size = implode( '', $minimum_font_size_rem ) . " + ((1vw - $view_port_width_offset) * $linear_factor)"; - - return "clamp($minimum_font_size_raw, $fluid_target_font_size, $maximum_font_size_raw)"; - } - - // Only minimum font size is available: max(). - if ( $minimum_font_size_raw ) { - // Coerce units for ratio calculation. - $minimum_font_size = gutenberg_get_typography_value_and_unit( $minimum_font_size_raw, 'rem' ); - $minimum_viewport_width = gutenberg_get_typography_value_and_unit( $minimum_viewport_width_raw, 'rem' ); - - // Protect against unsupported units. - if ( ! $minimum_font_size || ! $minimum_viewport_width ) { - return null; - } - - // Ratio of min_font_size / min_viewport. - $min_ratio = round( ( $minimum_font_size['value'] / $minimum_viewport_width['value'] ) * 100, 3 ); - $min_size = implode( '', $minimum_font_size ); - - // The font-size will be set at $min_size, unless the computed value of $min_ratio * 1vw is greater than that of $min_size, - // in which case it will be set to that value instead. - return "max($min_size, $min_ratio * 1vw)"; + // Protect against unsupported units. + if ( ! $maximum_font_size || ! $minimum_font_size ) { + return null; } - // Only maximum font size is available: min(). - if ( $maximum_font_size_raw ) { - // Coerce units for ratio calculation. - $maximum_font_size = gutenberg_get_typography_value_and_unit( $maximum_font_size_raw, 'rem' ); - $maximum_viewport_width = gutenberg_get_typography_value_and_unit( $maximum_viewport_width_raw, 'rem' ); + // Use rem for accessible fluid target font scaling. + $minimum_font_size_rem = gutenberg_get_typography_value_and_unit( $minimum_font_size_raw, 'rem' ); - // Protect against unsupported units. - if ( ! $maximum_viewport_width || ! $maximum_font_size ) { - return null; - } + // Viewport widths defined for fluid typography. Normalize units. + $maximum_viewport_width = gutenberg_get_typography_value_and_unit( $maximum_viewport_width_raw, $font_size_unit ); + $minimum_viewport_width = gutenberg_get_typography_value_and_unit( $minimum_viewport_width_raw, $font_size_unit ); - // Ratio of max_font_size / max_viewport. - $max_ratio = round( ( $maximum_font_size['value'] / $maximum_viewport_width['value'] ) * 100, 3 ); - $max_size = implode( '', $maximum_font_size ); + // Build CSS rule. + // Borrowed from https://websemantics.uk/tools/responsive-font-calculator/. + $view_port_width_offset = round( $minimum_viewport_width['value'] / 100, 3 ) . $font_size_unit; + $linear_factor = 100 * ( ( $maximum_font_size['value'] - $minimum_font_size['value'] ) / ( $maximum_viewport_width['value'] - $minimum_viewport_width['value'] ) ); + $linear_factor = round( $linear_factor, 3 ) * $scale_factor; + $fluid_target_font_size = implode( '', $minimum_font_size_rem ) . " + ((1vw - $view_port_width_offset) * $linear_factor)"; - // The font-size will be set at $max_size, unless the result of $max_ratio * 1vw is less than $max_size, - // in which case it will be set to that value instead. - return "min($max_size, $max_ratio * 1vw)"; - } + return "clamp($minimum_font_size_raw, $fluid_target_font_size, $maximum_font_size_raw)"; } /** * Returns a font-size value based on a given font-size preset. * Takes into account fluid typography parameters and attempts to return a css formula depending on available, valid values. * - * @param array $preset fontSizes preset value as seen in theme.json. - * @return string Font-size value. + * @param array $preset fontSizes preset value as seen in theme.json. + * @param boolean $should_use_fluid_typography An override to switch fluid typography "on". + * @return string Font-size value. */ -function gutenberg_get_typography_font_size_value( $preset ) { - // Font sizes. - $fluid_font_size_settings = isset( $preset['fluidSize'] ) ? $preset['fluidSize'] : null; +function gutenberg_get_typography_font_size_value( $preset, $should_use_fluid_typography = false ) { + // Check if fluid font sizes are activated. + $typography_settings = gutenberg_get_global_settings( array( 'typography' ) ); + $fluid_settings = isset( $typography_settings['fluid'] ) ? $typography_settings['fluid'] : $should_use_fluid_typography; - if ( ! $fluid_font_size_settings ) { + if ( ! $fluid_settings ) { return $preset['size']; } - // Default viewport widths. - $default_maximum_viewport_width = '1600px'; - $default_minimum_viewport_width = '768px'; - $maximum_viewport_width_raw = null; - $minimum_viewport_width_raw = null; + // Defaults. + $default_maximum_viewport_width = '1600px'; + $default_minimum_viewport_width = '768px'; + $default_minimum_font_size_factor = isset( $fluid_settings['minFontSizeFactor'] ) && is_numeric( $fluid_settings['minFontSizeFactor'] ) ? $fluid_settings['minFontSizeFactor'] : 0.75; + $default_maximum_font_size_factor = isset( $fluid_settings['maxFontSizeFactor'] ) && is_numeric( $fluid_settings['minFontSizeFactor'] ) ? $fluid_settings['maxFontSizeFactor'] : 2; + $default_scale_factor = isset( $fluid_settings['scaleFactor'] ) && is_numeric( $fluid_settings['scaleFactor'] ) ? $fluid_settings['scaleFactor'] : 1; + $maximum_viewport_width_raw = null; + $minimum_viewport_width_raw = null; + + // Font sizes. + $fluid_font_size_settings = isset( $preset['fluidSize'] ) ? $preset['fluidSize'] : null; - // Grab fluid font sizes. + // Try to grab explicit min and max fluid font sizes. $minimum_font_size_raw = isset( $fluid_font_size_settings['min'] ) ? $fluid_font_size_settings['min'] : null; $maximum_font_size_raw = isset( $fluid_font_size_settings['max'] ) ? $fluid_font_size_settings['max'] : null; - // Grab fluid settings, if any. - $typography_settings = gutenberg_get_global_settings( array( 'typography' ) ); - $fluid_settings = isset( $typography_settings['fluid'] ) ? $typography_settings['fluid'] : null; - if ( isset( $fluid_settings['max'] ) ) { - $maximum_viewport_width_raw = $fluid_settings['max']; + // Font sizes. + $preferred_size = gutenberg_get_typography_value_and_unit( $preset['size'] ); + + // Protect against unsupported units. + if ( empty( $preferred_size['unit'] ) ) { + return $preset['size']; + } + + // If no fluid min or max font sizes are available, create some using min/max font size factors. + if ( ! $minimum_font_size_raw ) { + $minimum_font_size_raw = ( $preferred_size['value'] * $default_minimum_font_size_factor ) . $preferred_size['unit']; + } + + if ( ! $maximum_font_size_raw ) { + $maximum_font_size_raw = ( $preferred_size['value'] * $default_maximum_font_size_factor ) . $preferred_size['unit']; + } + + // Set min and max viewport sizes, if any. + if ( isset( $fluid_settings['maxViewPortWidth'] ) ) { + $maximum_viewport_width_raw = $fluid_settings['maxViewPortWidth']; } - if ( isset( $fluid_settings['min'] ) ) { - $minimum_viewport_width_raw = $fluid_settings['min']; + if ( isset( $fluid_settings['minViewPortWidth'] ) ) { + $minimum_viewport_width_raw = $fluid_settings['minViewPortWidth']; } // Apply viewport width fallbacks. @@ -405,13 +385,10 @@ function gutenberg_get_typography_font_size_value( $preset ) { } } - // We need at least one fluid font size to return a valid formula. - if ( $minimum_font_size_raw || $maximum_font_size_raw ) { - $fluid_font_size_value = gutenberg_get_computed_fluid_typography_value( $minimum_viewport_width_raw, $maximum_viewport_width_raw, $minimum_font_size_raw, $maximum_font_size_raw ); + $fluid_font_size_value = gutenberg_get_computed_fluid_typography_value( $minimum_viewport_width_raw, $maximum_viewport_width_raw, $minimum_font_size_raw, $maximum_font_size_raw, $default_scale_factor ); - if ( ! empty( $fluid_font_size_value ) ) { - return $fluid_font_size_value; - } + if ( ! empty( $fluid_font_size_value ) ) { + return $fluid_font_size_value; } return $preset['size']; diff --git a/phpunit/block-supports/typography-test.php b/phpunit/block-supports/typography-test.php index 4dc2eefb1180c2..3694d4558dca97 100644 --- a/phpunit/block-supports/typography-test.php +++ b/phpunit/block-supports/typography-test.php @@ -213,8 +213,8 @@ function test_font_family_with_class() { * * @dataProvider data_generate_font_size_preset_fixtures */ - function test_gutenberg_get_typography_font_size_value( $font_size_preset, $expected_output ) { - $actual = gutenberg_get_typography_font_size_value( $font_size_preset ); + function test_gutenberg_get_typography_font_size_value( $font_size_preset, $should_use_fluid_typography, $expected_output ) { + $actual = gutenberg_get_typography_font_size_value( $font_size_preset, $should_use_fluid_typography ); $this->assertSame( $expected_output, $actual ); } @@ -227,60 +227,66 @@ function test_gutenberg_get_typography_font_size_value( $font_size_preset, $expe public function data_generate_font_size_preset_fixtures() { return array( 'default_return_value' => array( - 'font_size_preset' => array( + 'font_size_preset' => array( 'size' => '28px', ), - 'expected_output' => '28px', + 'should_use_fluid_typography' => false, + 'expected_output' => '28px', ), - 'default_return_value_with_no_valid_fluid_values' => array( - 'font_size_preset' => array( + 'default_return_default_fluid_values_with_empty_fluidSize' => array( + 'font_size_preset' => array( 'size' => '28px', 'fluidSize' => array(), ), - 'expected_output' => '28px', + 'should_use_fluid_typography' => true, + 'expected_output' => 'clamp(21px, 1.3125rem + ((1vw - 7.68px) * 4.207), 56px)', ), 'default_return_size_with_invalid_fluid_units' => array( - 'font_size_preset' => array( + 'font_size_preset' => array( 'size' => '10em', 'fluidSize' => array( 'min' => '20vw', 'max' => '50%', ), ), - 'expected_output' => '10em', + 'should_use_fluid_typography' => true, + 'expected_output' => '10em', ), 'default_return_fluid_clamp_value' => array( - 'font_size_preset' => array( + 'font_size_preset' => array( 'size' => '28px', 'fluidSize' => array( 'min' => '20px', 'max' => '50rem', ), ), - 'expected_output' => 'clamp(20px, 1.25rem + ((1vw - 7.68px) * 93.75), 50rem)', + 'should_use_fluid_typography' => true, + 'expected_output' => 'clamp(20px, 1.25rem + ((1vw - 7.68px) * 93.75), 50rem)', ), - 'default_return_fluid_min_value' => array( - 'font_size_preset' => array( + 'default_return_clamp_value_with_default_fluid_max_value' => array( + 'font_size_preset' => array( 'size' => '28px', 'fluidSize' => array( 'min' => '2.6rem', ), ), - 'expected_output' => 'max(2.6rem, 5.417 * 1vw)', + 'should_use_fluid_typography' => true, + 'expected_output' => 'clamp(2.6rem, 2.6rem + ((1vw - 0.48rem) * 1.731), 56px)', ), - 'default_return_fluid_max_value' => array( - 'font_size_preset' => array( + 'default_return_clamp_value_with_default_fluid_min_value' => array( + 'font_size_preset' => array( 'size' => '28px', 'fluidSize' => array( 'max' => '80px', ), ), - 'expected_output' => 'min(5rem, 5 * 1vw)', + 'should_use_fluid_typography' => true, + 'expected_output' => 'clamp(21px, 1.3125rem + ((1vw - 7.68px) * 7.091), 80px)', ), ); } From eea3aebb1ab4de6fa300bd24bfb1f7afa3b8051e Mon Sep 17 00:00:00 2001 From: ramonjd Date: Fri, 24 Jun 2022 15:07:52 +1000 Subject: [PATCH 19/24] Refactoring function signatures to pass options array instead of multiple args. --- lib/block-supports/typography.php | 80 +++++++++++++++++++++++-------- 1 file changed, 61 insertions(+), 19 deletions(-) diff --git a/lib/block-supports/typography.php b/lib/block-supports/typography.php index 9d4b11ba4bbba0..6c09f8abf21232 100644 --- a/lib/block-supports/typography.php +++ b/lib/block-supports/typography.php @@ -227,16 +227,21 @@ function gutenberg_typography_get_css_variable_inline_style( $attributes, $featu * * @access private * - * @param string $raw_value Raw size value from theme.json. - * @param string $coerce_to Coerce the value to rem or px. Default `'rem'`. - * @param number $root_font_size_value Value of root font size for rem|em <-> px conversion. - * @param array $acceptable_units An array of font size units. - * @return array An array consisting of `'value'` and `'unit'`, e.g., [ '42', 'rem' ] + * @param string $raw_value Raw size value from theme.json. + * @param array $options array( + * 'coerce_to' => (string) Coerce the value to rem or px. Default `'rem'`. + * 'root_size_value' => (number) Value of root font size for rem|em <-> px conversion. Default `16`. + * 'acceptable_units' => (array) An array of font size units. Default `[ 'rem', 'px', 'em' ]`; + * );. + * @return array An array consisting of `'value'` and `'unit'`, e.g., [ '42', 'rem' ] */ -function gutenberg_get_typography_value_and_unit( $raw_value, $coerce_to = '', $root_font_size_value = 16, $acceptable_units = array( 'rem', 'px', 'em' ) ) { +function gutenberg_get_typography_value_and_unit( $raw_value, $options = array() ) { if ( empty( $raw_value ) ) { return null; } + $coerce_to = isset( $options['coerce_to'] ) ? $options['coerce_to'] : ''; + $root_font_size_value = isset( $options['root_size_value'] ) ? $options['root_size_value'] : 16; + $acceptable_units = isset( $options['acceptable_units'] ) ? $options['acceptable_units'] : array( 'rem', 'px', 'em' ); $acceptable_units_group = implode( '|', $acceptable_units ); $pattern = '/^(\d*\.?\d+)(' . $acceptable_units_group . '){1,1}$/'; @@ -273,22 +278,36 @@ function gutenberg_get_typography_value_and_unit( $raw_value, $coerce_to = '', $ * * @access private * - * @param string $minimum_viewport_width_raw Minimum viewport size from which type will have fluidity. - * @param string $maximum_viewport_width_raw Maximum size up to which type will have fluidity. - * @param string $minimum_font_size_raw Minimum font size for any clamp() calculation. - * @param string $maximum_font_size_raw Maximum font size for any clamp() calculation. - * @param number $scale_factor A scale factor to determine how fast a font scales within boundaries. + * @param array $args array( + * 'maximum_viewport_width' => (string) Maximum size up to which type will have fluidity. + * 'minimum_viewport_width' => (string) Minimum viewport size from which type will have fluidity. + * 'maximum_font_size' => (string) Maximum font size for any clamp() calculation. + * 'minimum_font_size' => (string) Minimum font size for any clamp() calculation. + * 'scale_factor' => (number) A scale factor to determine how fast a font scales within boundaries. + * );. * @return string|null A font-size value using clamp(). */ -function gutenberg_get_computed_fluid_typography_value( $minimum_viewport_width_raw, $maximum_viewport_width_raw, $minimum_font_size_raw, $maximum_font_size_raw, $scale_factor ) { +function gutenberg_get_computed_fluid_typography_value( $args = array() ) { + $maximum_viewport_width_raw = isset( $args['maximum_viewport_width'] ) ? $args['maximum_viewport_width'] : null; + $minimum_viewport_width_raw = isset( $args['minimum_viewport_width'] ) ? $args['minimum_viewport_width'] : null; + $maximum_font_size_raw = isset( $args['maximum_font_size'] ) ? $args['maximum_font_size'] : null; + $minimum_font_size_raw = isset( $args['minimum_font_size'] ) ? $args['minimum_font_size'] : null; + $scale_factor = isset( $args['scale_factor'] ) ? $args['scale_factor'] : null; + + // Grab the minimum font size and normalize it in order to use the value for calculations. $minimum_font_size = gutenberg_get_typography_value_and_unit( $minimum_font_size_raw ); - // We get a 'preferred' unit to keep units consistent when calculating. - // Otherwise the result will not be accurate. + // We get a 'preferred' unit to keep units consistent when calculating, + // otherwise the result will not be accurate. $font_size_unit = $minimum_font_size['unit']; // Grab the maximum font size and normalize it in order to use the value for calculations. - $maximum_font_size = gutenberg_get_typography_value_and_unit( $maximum_font_size_raw, $font_size_unit ); + $maximum_font_size = gutenberg_get_typography_value_and_unit( + $maximum_font_size_raw, + array( + 'coerce_to' => $font_size_unit, + ) + ); // Protect against unsupported units. if ( ! $maximum_font_size || ! $minimum_font_size ) { @@ -296,11 +315,26 @@ function gutenberg_get_computed_fluid_typography_value( $minimum_viewport_width_ } // Use rem for accessible fluid target font scaling. - $minimum_font_size_rem = gutenberg_get_typography_value_and_unit( $minimum_font_size_raw, 'rem' ); + $minimum_font_size_rem = gutenberg_get_typography_value_and_unit( + $minimum_font_size_raw, + array( + 'coerce_to' => 'rem', + ) + ); // Viewport widths defined for fluid typography. Normalize units. - $maximum_viewport_width = gutenberg_get_typography_value_and_unit( $maximum_viewport_width_raw, $font_size_unit ); - $minimum_viewport_width = gutenberg_get_typography_value_and_unit( $minimum_viewport_width_raw, $font_size_unit ); + $maximum_viewport_width = gutenberg_get_typography_value_and_unit( + $maximum_viewport_width_raw, + array( + 'coerce_to' => $font_size_unit, + ) + ); + $minimum_viewport_width = gutenberg_get_typography_value_and_unit( + $minimum_viewport_width_raw, + array( + 'coerce_to' => $font_size_unit, + ) + ); // Build CSS rule. // Borrowed from https://websemantics.uk/tools/responsive-font-calculator/. @@ -385,7 +419,15 @@ function gutenberg_get_typography_font_size_value( $preset, $should_use_fluid_ty } } - $fluid_font_size_value = gutenberg_get_computed_fluid_typography_value( $minimum_viewport_width_raw, $maximum_viewport_width_raw, $minimum_font_size_raw, $maximum_font_size_raw, $default_scale_factor ); + $fluid_font_size_value = gutenberg_get_computed_fluid_typography_value( + array( + 'minimum_viewport_width' => $minimum_viewport_width_raw, + 'maximum_viewport_width' => $maximum_viewport_width_raw, + 'minimum_font_size' => $minimum_font_size_raw, + 'maximum_font_size' => $maximum_font_size_raw, + 'scale_factor' => $default_scale_factor, + ) + ); if ( ! empty( $fluid_font_size_value ) ) { return $fluid_font_size_value; From 15b5bee6bb529c5d58fdb70d905f912a209ab8d7 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Fri, 24 Jun 2022 15:25:41 +1000 Subject: [PATCH 20/24] Merge default args in gutenberg_get_typography_value_and_unit using wp_parse_args --- lib/block-supports/typography.php | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/lib/block-supports/typography.php b/lib/block-supports/typography.php index 6c09f8abf21232..e765ce0b68d08b 100644 --- a/lib/block-supports/typography.php +++ b/lib/block-supports/typography.php @@ -239,11 +239,16 @@ function gutenberg_get_typography_value_and_unit( $raw_value, $options = array() if ( empty( $raw_value ) ) { return null; } - $coerce_to = isset( $options['coerce_to'] ) ? $options['coerce_to'] : ''; - $root_font_size_value = isset( $options['root_size_value'] ) ? $options['root_size_value'] : 16; - $acceptable_units = isset( $options['acceptable_units'] ) ? $options['acceptable_units'] : array( 'rem', 'px', 'em' ); - $acceptable_units_group = implode( '|', $acceptable_units ); + $defaults = array( + 'coerce_to' => '', + 'root_size_value' => 16, + 'acceptable_units' => array( 'rem', 'px', 'em' ), + ); + + $options = wp_parse_args( $options, $defaults ); + + $acceptable_units_group = implode( '|', $options['acceptable_units'] ); $pattern = '/^(\d*\.?\d+)(' . $acceptable_units_group . '){1,1}$/'; preg_match( $pattern, $raw_value, $matches ); @@ -257,14 +262,14 @@ function gutenberg_get_typography_value_and_unit( $raw_value, $options = array() $unit = $matches[2]; // Default browser font size. Later we could inject some JS to compute this `getComputedStyle( document.querySelector( "html" ) ).fontSize`. - if ( 'px' === $coerce_to && ( 'em' === $unit || 'rem' === $unit ) ) { - $value = $value * $root_font_size_value; - $unit = $coerce_to; + if ( 'px' === $options['coerce_to'] && ( 'em' === $unit || 'rem' === $unit ) ) { + $value = $value * $options['root_size_value']; + $unit = $options['coerce_to']; } - if ( 'px' === $unit && ( 'em' === $coerce_to || 'rem' === $coerce_to ) ) { - $value = $value / $root_font_size_value; - $unit = $coerce_to; + if ( 'px' === $unit && ( 'em' === $options['coerce_to'] || 'rem' === $options['coerce_to'] ) ) { + $value = $value / $options['root_size_value']; + $unit = $options['coerce_to']; } return array( From 62beef54b04fb62eacf9786bc260fc0d601e6a42 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Thu, 14 Jul 2022 09:54:57 +1000 Subject: [PATCH 21/24] Fix merge conflicts with trunk. Updated JSON schema. --- lib/block-supports/typography.php | 2 +- .../wordpress-6.1/class-wp-theme-json-6-1.php | 158 +----------------- schemas/json/theme.json | 20 ++- 3 files changed, 19 insertions(+), 161 deletions(-) diff --git a/lib/block-supports/typography.php b/lib/block-supports/typography.php index e765ce0b68d08b..1776abb62d5aa6 100644 --- a/lib/block-supports/typography.php +++ b/lib/block-supports/typography.php @@ -304,7 +304,7 @@ function gutenberg_get_computed_fluid_typography_value( $args = array() ) { // We get a 'preferred' unit to keep units consistent when calculating, // otherwise the result will not be accurate. - $font_size_unit = $minimum_font_size['unit']; + $font_size_unit = isset( $minimum_font_size['unit'] ) ? $minimum_font_size['unit'] : 'rem'; // Grab the maximum font size and normalize it in order to use the value for calculations. $maximum_font_size = gutenberg_get_typography_value_and_unit( diff --git a/lib/compat/wordpress-6.1/class-wp-theme-json-6-1.php b/lib/compat/wordpress-6.1/class-wp-theme-json-6-1.php index 88d2be013a0534..1679e87c5a8a92 100644 --- a/lib/compat/wordpress-6.1/class-wp-theme-json-6-1.php +++ b/lib/compat/wordpress-6.1/class-wp-theme-json-6-1.php @@ -126,161 +126,6 @@ public static function get_element_class_name( $element ) { return array_key_exists( $element, static::__EXPERIMENTAL_ELEMENT_CLASS_NAMES ) ? static::__EXPERIMENTAL_ELEMENT_CLASS_NAMES[ $element ] : ''; } - /** - * Presets are a set of values that serve - * to bootstrap some styles: colors, font sizes, etc. - * - * They are a unkeyed array of values such as: - * - * ```php - * array( - * array( - * 'slug' => 'unique-name-within-the-set', - * 'name' => 'Name for the UI', - * => 'value' - * ), - * ) - * ``` - * - * This contains the necessary metadata to process them: - * - * - path => Where to find the preset within the settings section. - * - prevent_override => Disables override of default presets by theme presets. - * The relationship between whether to override the defaults - * and whether the defaults are enabled is inverse: - * - If defaults are enabled => theme presets should not be overriden - * - If defaults are disabled => theme presets should be overriden - * For example, a theme sets defaultPalette to false, - * making the default palette hidden from the user. - * In that case, we want all the theme presets to be present, - * so they should override the defaults by setting this false. - * - use_default_names => whether to use the default names - * - value_key => the key that represents the value - * - value_func => optionally, instead of value_key, a function to generate - * the value that takes a preset as an argument - * (either value_key or value_func should be present) - * - css_vars => template string to use in generating the CSS Custom Property. - * Example output: "--wp--preset--duotone--blue: " will generate as many CSS Custom Properties as presets defined - * substituting the $slug for the slug's value for each preset value. - * - classes => array containing a structure with the classes to - * generate for the presets, where for each array item - * the key is the class name and the value the property name. - * The "$slug" substring will be replaced by the slug of each preset. - * For example: - * 'classes' => array( - * '.has-$slug-color' => 'color', - * '.has-$slug-background-color' => 'background-color', - * '.has-$slug-border-color' => 'border-color', - * ) - * - properties => array of CSS properties to be used by kses to - * validate the content of each preset - * by means of the remove_insecure_properties method. - */ - const PRESETS_METADATA = array( - array( - 'path' => array( 'color', 'palette' ), - 'prevent_override' => array( 'color', 'defaultPalette' ), - 'use_default_names' => false, - 'value_key' => 'color', - 'css_vars' => '--wp--preset--color--$slug', - 'classes' => array( - '.has-$slug-color' => 'color', - '.has-$slug-background-color' => 'background-color', - '.has-$slug-border-color' => 'border-color', - ), - 'properties' => array( 'color', 'background-color', 'border-color' ), - ), - array( - 'path' => array( 'color', 'gradients' ), - 'prevent_override' => array( 'color', 'defaultGradients' ), - 'use_default_names' => false, - 'value_key' => 'gradient', - 'css_vars' => '--wp--preset--gradient--$slug', - 'classes' => array( '.has-$slug-gradient-background' => 'background' ), - 'properties' => array( 'background' ), - ), - array( - 'path' => array( 'color', 'duotone' ), - 'prevent_override' => array( 'color', 'defaultDuotone' ), - 'use_default_names' => false, - 'value_func' => 'gutenberg_get_duotone_filter_property', - 'css_vars' => '--wp--preset--duotone--$slug', - 'classes' => array(), - 'properties' => array( 'filter' ), - ), - array( - 'path' => array( 'typography', 'fontSizes' ), - 'prevent_override' => false, - 'use_default_names' => true, - 'value_func' => 'gutenberg_get_typography_font_size_value', - 'css_vars' => '--wp--preset--font-size--$slug', - 'classes' => array( '.has-$slug-font-size' => 'font-size' ), - 'properties' => array( 'font-size' ), - ), - array( - 'path' => array( 'typography', 'fontFamilies' ), - 'prevent_override' => false, - 'use_default_names' => false, - 'value_key' => 'fontFamily', - 'css_vars' => '--wp--preset--font-family--$slug', - 'classes' => array( '.has-$slug-font-family' => 'font-family' ), - 'properties' => array( 'font-family' ), - ), - ); - - /** - * The valid properties under the settings key. - * - * @var array - */ - const VALID_SETTINGS = array( - 'appearanceTools' => null, - 'border' => array( - 'color' => null, - 'radius' => null, - 'style' => null, - 'width' => null, - ), - 'color' => array( - 'background' => null, - 'custom' => null, - 'customDuotone' => null, - 'customGradient' => null, - 'defaultDuotone' => null, - 'defaultGradients' => null, - 'defaultPalette' => null, - 'duotone' => null, - 'gradients' => null, - 'link' => null, - 'palette' => null, - 'text' => null, - ), - 'custom' => null, - 'layout' => array( - 'contentSize' => null, - 'wideSize' => null, - ), - 'spacing' => array( - 'blockGap' => null, - 'margin' => null, - 'padding' => null, - 'units' => null, - ), - 'typography' => array( - 'fluid' => null, - 'customFontSize' => null, - 'dropCap' => null, - 'fontFamilies' => null, - 'fontSizes' => null, - 'fontStyle' => null, - 'fontWeight' => null, - 'letterSpacing' => null, - 'lineHeight' => null, - 'textDecoration' => null, - 'textTransform' => null, - ), - ); - /** * Sanitizes the input according to the schemas. * @@ -1206,7 +1051,7 @@ protected static function get_property_value( $styles, $path, $theme_json = null 'path' => array( 'typography', 'fontSizes' ), 'prevent_override' => false, 'use_default_names' => true, - 'value_key' => 'size', + 'value_func' => 'gutenberg_get_typography_font_size_value', 'css_vars' => '--wp--preset--font-size--$slug', 'classes' => array( '.has-$slug-font-size' => 'font-size' ), 'properties' => array( 'font-size' ), @@ -1284,6 +1129,7 @@ protected static function get_property_value( $styles, $path, $theme_json = null 'units' => null, ), 'typography' => array( + 'fluid' => null, 'customFontSize' => null, 'dropCap' => null, 'fontFamilies' => null, diff --git a/schemas/json/theme.json b/schemas/json/theme.json index 734c849cd99043..33d88d4ca179e3 100644 --- a/schemas/json/theme.json +++ b/schemas/json/theme.json @@ -320,13 +320,25 @@ "description": "Enables fluid typography and allows users to set global fluid typography parameters.", "type": "object", "properties": { - "max": { - "description": "Allow users to set custom a max viewport width in px, rem or em.", + "maxViewPortWidth": { + "description": "Allow users to set custom a max viewport width in px, rem or em, used to set the maximum size boundary of a fluid font.", "type": "string" }, - "min": { - "description": "Allow users to set custom a min viewport width in px, rem or em.", + "minViewPortWidth": { + "description": "Allow users to set custom a min viewport width in px, rem or em, used to set the minimum size boundary of a fluid font", "type": "string" + }, + "minFontSizeFactor": { + "description": "Used to calculate a minimum font size from a single size value, where `fluidSize.min` is not set.", + "type": "number" + }, + "maxFontSizeFactor": { + "description": "Used to calculate a maximum font size from a single size value, where `fluidSize.max` is not set.", + "type": "number" + }, + "scaleFactor": { + "description": "Determines the rate of font size change between the minimum and maximum font sizes. The higher the value the faster the change.", + "type": "number" } } }, From edeaca7068196f8960453965fe7fa64632d573ef Mon Sep 17 00:00:00 2001 From: ramonjd Date: Fri, 15 Jul 2022 09:41:33 +1000 Subject: [PATCH 22/24] - add to settings > fluid would be a boolean true to enable the feature. - remove content settings as fallbacks - rename fluidSize to fluid in the typography settings for each font. - unit tests --- lib/block-supports/typography.php | 45 +++++---------------- phpunit/block-supports/typography-test.php | 46 +++++++++++++--------- schemas/json/theme.json | 28 ++----------- 3 files changed, 40 insertions(+), 79 deletions(-) diff --git a/lib/block-supports/typography.php b/lib/block-supports/typography.php index 1776abb62d5aa6..dc800d9fb47252 100644 --- a/lib/block-supports/typography.php +++ b/lib/block-supports/typography.php @@ -356,29 +356,27 @@ function gutenberg_get_computed_fluid_typography_value( $args = array() ) { * Takes into account fluid typography parameters and attempts to return a css formula depending on available, valid values. * * @param array $preset fontSizes preset value as seen in theme.json. - * @param boolean $should_use_fluid_typography An override to switch fluid typography "on". + * @param boolean $should_use_fluid_typography An override to switch fluid typography "on". Can be used for unit testing. * @return string Font-size value. */ function gutenberg_get_typography_font_size_value( $preset, $should_use_fluid_typography = false ) { // Check if fluid font sizes are activated. - $typography_settings = gutenberg_get_global_settings( array( 'typography' ) ); - $fluid_settings = isset( $typography_settings['fluid'] ) ? $typography_settings['fluid'] : $should_use_fluid_typography; + $typography_settings = gutenberg_get_global_settings( array( 'typography' ) ); + $should_use_fluid_typography = isset( $typography_settings['fluid'] ) && true === $typography_settings['fluid'] ? true : $should_use_fluid_typography; - if ( ! $fluid_settings ) { + if ( ! $should_use_fluid_typography ) { return $preset['size']; } // Defaults. $default_maximum_viewport_width = '1600px'; $default_minimum_viewport_width = '768px'; - $default_minimum_font_size_factor = isset( $fluid_settings['minFontSizeFactor'] ) && is_numeric( $fluid_settings['minFontSizeFactor'] ) ? $fluid_settings['minFontSizeFactor'] : 0.75; - $default_maximum_font_size_factor = isset( $fluid_settings['maxFontSizeFactor'] ) && is_numeric( $fluid_settings['minFontSizeFactor'] ) ? $fluid_settings['maxFontSizeFactor'] : 2; - $default_scale_factor = isset( $fluid_settings['scaleFactor'] ) && is_numeric( $fluid_settings['scaleFactor'] ) ? $fluid_settings['scaleFactor'] : 1; - $maximum_viewport_width_raw = null; - $minimum_viewport_width_raw = null; + $default_minimum_font_size_factor = 0.75; + $default_maximum_font_size_factor = 1.5; + $default_scale_factor = 1; // Font sizes. - $fluid_font_size_settings = isset( $preset['fluidSize'] ) ? $preset['fluidSize'] : null; + $fluid_font_size_settings = isset( $preset['fluid'] ) ? $preset['fluid'] : null; // Try to grab explicit min and max fluid font sizes. $minimum_font_size_raw = isset( $fluid_font_size_settings['min'] ) ? $fluid_font_size_settings['min'] : null; @@ -401,33 +399,10 @@ function gutenberg_get_typography_font_size_value( $preset, $should_use_fluid_ty $maximum_font_size_raw = ( $preferred_size['value'] * $default_maximum_font_size_factor ) . $preferred_size['unit']; } - // Set min and max viewport sizes, if any. - if ( isset( $fluid_settings['maxViewPortWidth'] ) ) { - $maximum_viewport_width_raw = $fluid_settings['maxViewPortWidth']; - } - - if ( isset( $fluid_settings['minViewPortWidth'] ) ) { - $minimum_viewport_width_raw = $fluid_settings['minViewPortWidth']; - } - - // Apply viewport width fallbacks. - // First from "layout.contentSize" for min width and "layout.wideSize" for max width. - // Then from the hardcoded defaults. - if ( ! $maximum_viewport_width_raw || ! $minimum_viewport_width_raw ) { - $layout_settings = gutenberg_get_global_settings( array( 'layout' ) ); - if ( ! $maximum_viewport_width_raw ) { - $maximum_viewport_width_raw = isset( $layout_settings['wideSize'] ) ? $layout_settings['wideSize'] : $default_maximum_viewport_width; - } - - if ( ! $minimum_viewport_width_raw ) { - $minimum_viewport_width_raw = isset( $layout_settings['contentSize'] ) ? $layout_settings['contentSize'] : $default_minimum_viewport_width; - } - } - $fluid_font_size_value = gutenberg_get_computed_fluid_typography_value( array( - 'minimum_viewport_width' => $minimum_viewport_width_raw, - 'maximum_viewport_width' => $maximum_viewport_width_raw, + 'minimum_viewport_width' => $default_maximum_viewport_width, + 'maximum_viewport_width' => $default_minimum_viewport_width, 'minimum_font_size' => $minimum_font_size_raw, 'maximum_font_size' => $maximum_font_size_raw, 'scale_factor' => $default_scale_factor, diff --git a/phpunit/block-supports/typography-test.php b/phpunit/block-supports/typography-test.php index 3694d4558dca97..71d68ca2d9fd3c 100644 --- a/phpunit/block-supports/typography-test.php +++ b/phpunit/block-supports/typography-test.php @@ -226,7 +226,7 @@ function test_gutenberg_get_typography_font_size_value( $font_size_preset, $shou */ public function data_generate_font_size_preset_fixtures() { return array( - 'default_return_value' => array( + 'default_return_value' => array( 'font_size_preset' => array( 'size' => '28px', ), @@ -234,19 +234,27 @@ public function data_generate_font_size_preset_fixtures() { 'expected_output' => '28px', ), - 'default_return_default_fluid_values_with_empty_fluidSize' => array( + 'return_fluid_value' => array( 'font_size_preset' => array( - 'size' => '28px', - 'fluidSize' => array(), + 'size' => '1.75rem', ), 'should_use_fluid_typography' => true, - 'expected_output' => 'clamp(21px, 1.3125rem + ((1vw - 7.68px) * 4.207), 56px)', + 'expected_output' => 'clamp(1.3125rem, 1.3125rem + ((1vw - 1rem) * -2.524), 2.625rem)', ), - 'default_return_size_with_invalid_fluid_units' => array( + 'return_default_fluid_values_with_empty_fluidSize' => array( 'font_size_preset' => array( - 'size' => '10em', - 'fluidSize' => array( + 'size' => '28px', + 'fluid' => array(), + ), + 'should_use_fluid_typography' => true, + 'expected_output' => 'clamp(21px, 1.3125rem + ((1vw - 16px) * -2.524), 42px)', + ), + + 'return_size_with_invalid_fluid_units' => array( + 'font_size_preset' => array( + 'size' => '10em', + 'fluid' => array( 'min' => '20vw', 'max' => '50%', ), @@ -255,38 +263,38 @@ public function data_generate_font_size_preset_fixtures() { 'expected_output' => '10em', ), - 'default_return_fluid_clamp_value' => array( + 'return_fluid_clamp_value' => array( 'font_size_preset' => array( - 'size' => '28px', - 'fluidSize' => array( + 'size' => '28px', + 'fluid' => array( 'min' => '20px', 'max' => '50rem', ), ), 'should_use_fluid_typography' => true, - 'expected_output' => 'clamp(20px, 1.25rem + ((1vw - 7.68px) * 93.75), 50rem)', + 'expected_output' => 'clamp(20px, 1.25rem + ((1vw - 16px) * -93.75), 50rem)', ), - 'default_return_clamp_value_with_default_fluid_max_value' => array( + 'return_clamp_value_with_default_fluid_max_value' => array( 'font_size_preset' => array( - 'size' => '28px', - 'fluidSize' => array( + 'size' => '28px', + 'fluid' => array( 'min' => '2.6rem', ), ), 'should_use_fluid_typography' => true, - 'expected_output' => 'clamp(2.6rem, 2.6rem + ((1vw - 0.48rem) * 1.731), 56px)', + 'expected_output' => 'clamp(2.6rem, 2.6rem + ((1vw - 1rem) * -0.048), 42px)', ), 'default_return_clamp_value_with_default_fluid_min_value' => array( 'font_size_preset' => array( - 'size' => '28px', - 'fluidSize' => array( + 'size' => '28px', + 'fluid' => array( 'max' => '80px', ), ), 'should_use_fluid_typography' => true, - 'expected_output' => 'clamp(21px, 1.3125rem + ((1vw - 7.68px) * 7.091), 80px)', + 'expected_output' => 'clamp(21px, 1.3125rem + ((1vw - 16px) * -7.091), 80px)', ), ); } diff --git a/schemas/json/theme.json b/schemas/json/theme.json index 33d88d4ca179e3..a218947b92f4a4 100644 --- a/schemas/json/theme.json +++ b/schemas/json/theme.json @@ -317,30 +317,8 @@ "default": true }, "fluid": { - "description": "Enables fluid typography and allows users to set global fluid typography parameters.", - "type": "object", - "properties": { - "maxViewPortWidth": { - "description": "Allow users to set custom a max viewport width in px, rem or em, used to set the maximum size boundary of a fluid font.", - "type": "string" - }, - "minViewPortWidth": { - "description": "Allow users to set custom a min viewport width in px, rem or em, used to set the minimum size boundary of a fluid font", - "type": "string" - }, - "minFontSizeFactor": { - "description": "Used to calculate a minimum font size from a single size value, where `fluidSize.min` is not set.", - "type": "number" - }, - "maxFontSizeFactor": { - "description": "Used to calculate a maximum font size from a single size value, where `fluidSize.max` is not set.", - "type": "number" - }, - "scaleFactor": { - "description": "Determines the rate of font size change between the minimum and maximum font sizes. The higher the value the faster the change.", - "type": "number" - } - } + "description": "Opts into fluid typography.", + "type": "boolean" }, "letterSpacing": { "description": "Allow users to set custom letter spacing.", @@ -385,7 +363,7 @@ "description": "CSS font-size value, including units.", "type": "string" }, - "fluidSize": { + "fluid": { "type": "object", "properties": { "min": { From ded379d2d92beb7f9b0ea74f1dd78c1848376820 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Fri, 15 Jul 2022 10:17:16 +1000 Subject: [PATCH 23/24] - update docs --- .../theme-json-reference/theme-json-living.md | 4 ++-- 1 file changed, 2 insertions(+), 2 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 949863ee189253..fdbf14d6b9379b 100644 --- a/docs/reference-guides/theme-json-reference/theme-json-living.md +++ b/docs/reference-guides/theme-json-reference/theme-json-living.md @@ -98,13 +98,13 @@ Settings related to typography. | customFontSize | boolean | true | | | fontStyle | boolean | true | | | fontWeight | boolean | true | | -| fluid | object | | | +| fluid | boolean | | | | letterSpacing | boolean | true | | | lineHeight | boolean | false | | | textDecoration | boolean | true | | | textTransform | boolean | true | | | dropCap | boolean | true | | -| fontSizes | array | | fluidSize, name, size, slug | +| fontSizes | array | | fluid, name, size, slug | | fontFamilies | array | | fontFace, fontFamily, name, slug | --- From 62fa6f8ad87f3f37144aa581c8f18faeec80c181 Mon Sep 17 00:00:00 2001 From: Ben Dwyer Date: Fri, 15 Jul 2022 08:25:14 +0200 Subject: [PATCH 24/24] reverse min/max viewport width Updated tests --- lib/block-supports/typography.php | 4 ++-- phpunit/block-supports/typography-test.php | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/block-supports/typography.php b/lib/block-supports/typography.php index dc800d9fb47252..382b897fefcf87 100644 --- a/lib/block-supports/typography.php +++ b/lib/block-supports/typography.php @@ -401,8 +401,8 @@ function gutenberg_get_typography_font_size_value( $preset, $should_use_fluid_ty $fluid_font_size_value = gutenberg_get_computed_fluid_typography_value( array( - 'minimum_viewport_width' => $default_maximum_viewport_width, - 'maximum_viewport_width' => $default_minimum_viewport_width, + 'minimum_viewport_width' => $default_minimum_viewport_width, + 'maximum_viewport_width' => $default_maximum_viewport_width, 'minimum_font_size' => $minimum_font_size_raw, 'maximum_font_size' => $maximum_font_size_raw, 'scale_factor' => $default_scale_factor, diff --git a/phpunit/block-supports/typography-test.php b/phpunit/block-supports/typography-test.php index 71d68ca2d9fd3c..956acd40f3c308 100644 --- a/phpunit/block-supports/typography-test.php +++ b/phpunit/block-supports/typography-test.php @@ -239,7 +239,7 @@ public function data_generate_font_size_preset_fixtures() { 'size' => '1.75rem', ), 'should_use_fluid_typography' => true, - 'expected_output' => 'clamp(1.3125rem, 1.3125rem + ((1vw - 1rem) * -2.524), 2.625rem)', + 'expected_output' => 'clamp(1.3125rem, 1.3125rem + ((1vw - 0.48rem) * 2.524), 2.625rem)', ), 'return_default_fluid_values_with_empty_fluidSize' => array( @@ -248,7 +248,7 @@ public function data_generate_font_size_preset_fixtures() { 'fluid' => array(), ), 'should_use_fluid_typography' => true, - 'expected_output' => 'clamp(21px, 1.3125rem + ((1vw - 16px) * -2.524), 42px)', + 'expected_output' => 'clamp(21px, 1.3125rem + ((1vw - 7.68px) * 2.524), 42px)', ), 'return_size_with_invalid_fluid_units' => array( @@ -272,7 +272,7 @@ public function data_generate_font_size_preset_fixtures() { ), ), 'should_use_fluid_typography' => true, - 'expected_output' => 'clamp(20px, 1.25rem + ((1vw - 16px) * -93.75), 50rem)', + 'expected_output' => 'clamp(20px, 1.25rem + ((1vw - 7.68px) * 93.75), 50rem)', ), 'return_clamp_value_with_default_fluid_max_value' => array( @@ -283,7 +283,7 @@ public function data_generate_font_size_preset_fixtures() { ), ), 'should_use_fluid_typography' => true, - 'expected_output' => 'clamp(2.6rem, 2.6rem + ((1vw - 1rem) * -0.048), 42px)', + 'expected_output' => 'clamp(2.6rem, 2.6rem + ((1vw - 0.48rem) * 0.048), 42px)', ), 'default_return_clamp_value_with_default_fluid_min_value' => array( @@ -294,7 +294,7 @@ public function data_generate_font_size_preset_fixtures() { ), ), 'should_use_fluid_typography' => true, - 'expected_output' => 'clamp(21px, 1.3125rem + ((1vw - 16px) * -7.091), 80px)', + 'expected_output' => 'clamp(21px, 1.3125rem + ((1vw - 7.68px) * 7.091), 80px)', ), ); }