Editor: Introduce spacing presets in global style properties.

This changeset is part of the Gutenberg changes merged into WP 6.1. It adds spacing presets support in global style properties.

Follow-up to [54211].

Props glendaviesnz, andrewserong, costdev, audrasjb, mukesh27.
See #56467.


git-svn-id: https://develop.svn.wordpress.org/trunk@54272 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Jb Audras
2022-09-21 11:41:44 +00:00
parent 6c6a6747a0
commit 30de259b07
5 changed files with 543 additions and 6 deletions

View File

@@ -488,7 +488,7 @@ function get_block_editor_settings( array $custom_settings, $block_editor_contex
unset( $editor_settings['__experimentalFeatures']['spacing']['padding'] );
}
if ( isset( $editor_settings['__experimentalFeatures']['spacing']['customSpacingSize'] ) ) {
$editor_settings['disableCustomSpacingSizes'] = ! $editor_ettings['__experimentalFeatures']['spacing']['customSpacingSize'];
$editor_settings['disableCustomSpacingSizes'] = ! $editor_settings['__experimentalFeatures']['spacing']['customSpacingSize'];
unset( $editor_settings['__experimentalFeatures']['spacing']['customSpacingSize'] );
}

View File

@@ -470,7 +470,7 @@ class WP_Theme_JSON_Resolver {
* @since 5.8.0
* @since 5.9.0 Added user data, removed the `$settings` parameter,
* added the `$origin` parameter.
* @since 6.1.0 Added block data.
* @since 6.1.0 Added block data and generation of spacingSizes array.
*
* @param string $origin Optional. To what level should we merge data.
* Valid values are 'theme' or 'custom'. Default 'custom'.
@@ -490,6 +490,9 @@ class WP_Theme_JSON_Resolver {
$result->merge( static::get_user_data() );
}
// Generate the default spacingSizes array based on the merged spacingScale settings.
$result->set_spacing_sizes();
return $result;
}

View File

@@ -164,6 +164,24 @@ class WP_Theme_JSON {
'classes' => array( '.has-$slug-font-family' => 'font-family' ),
'properties' => array( 'font-family' ),
),
array(
'path' => array( 'spacing', 'spacingSizes' ),
'prevent_override' => false,
'use_default_names' => true,
'value_key' => 'size',
'css_vars' => '--wp--preset--spacing--$slug',
'classes' => array(),
'properties' => array( 'padding', 'margin' ),
),
array(
'path' => array( 'spacing', 'spacingScale' ),
'prevent_override' => false,
'use_default_names' => true,
'value_key' => 'size',
'css_vars' => '--wp--preset--spacing--$slug',
'classes' => array(),
'properties' => array( 'padding', 'margin' ),
),
);
/**
@@ -307,10 +325,13 @@ class WP_Theme_JSON {
'wideSize' => null,
),
'spacing' => array(
'blockGap' => null,
'margin' => null,
'padding' => null,
'units' => null,
'customSpacingSize' => null,
'spacingSizes' => null,
'spacingScale' => null,
'blockGap' => null,
'margin' => null,
'padding' => null,
'units' => null,
),
'typography' => array(
'customFontSize' => null,
@@ -2890,4 +2911,122 @@ class WP_Theme_JSON {
return $output;
}
/**
* Sets the spacingSizes array based on the spacingScale values from theme.json.
*
* @since 6.1.0
*
* @return null|void
*/
public function set_spacing_sizes() {
$spacing_scale = _wp_array_get( $this->theme_json, array( 'settings', 'spacing', 'spacingScale' ), array() );
if ( ! is_numeric( $spacing_scale['steps'] )
|| ! isset( $spacing_scale['mediumStep'] )
|| ! isset( $spacing_scale['unit'] )
|| ! isset( $spacing_scale['operator'] )
|| ! isset( $spacing_scale['increment'] )
|| ! isset( $spacing_scale['steps'] )
|| ! is_numeric( $spacing_scale['increment'] )
|| ! is_numeric( $spacing_scale['mediumStep'] )
|| ( '+' !== $spacing_scale['operator'] && '*' !== $spacing_scale['operator'] ) ) {
if ( ! empty( $spacing_scale ) ) {
trigger_error( __( 'Some of the theme.json settings.spacing.spacingScale values are invalid' ), E_USER_NOTICE );
}
return null;
}
// If theme authors want to prevent the generation of the core spacing scale they can set their theme.json spacingScale.steps to 0.
if ( 0 === $spacing_scale['steps'] ) {
return null;
}
$unit = '%' === $spacing_scale['unit'] ? '%' : sanitize_title( $spacing_scale['unit'] );
$current_step = $spacing_scale['mediumStep'];
$steps_mid_point = round( $spacing_scale['steps'] / 2, 0 );
$x_small_count = null;
$below_sizes = array();
$slug = 40;
$remainder = 0;
for ( $below_midpoint_count = $steps_mid_point - 1; $spacing_scale['steps'] > 1 && $slug > 0 && $below_midpoint_count > 0; $below_midpoint_count-- ) {
if ( '+' === $spacing_scale['operator'] ) {
$current_step -= $spacing_scale['increment'];
} elseif ( $spacing_scale['increment'] > 1 ) {
$current_step /= $spacing_scale['increment'];
} else {
$current_step *= $spacing_scale['increment'];
}
if ( $current_step <= 0 ) {
$remainder = $below_midpoint_count;
break;
}
$below_sizes[] = array(
/* translators: %s: Digit to indicate multiple of sizing, eg. 2X-Small. */
'name' => $below_midpoint_count === $steps_mid_point - 1 ? __( 'Small' ) : sprintf( __( '%sX-Small' ), (string) $x_small_count ),
'slug' => (string) $slug,
'size' => round( $current_step, 2 ) . $unit,
);
if ( $below_midpoint_count === $steps_mid_point - 2 ) {
$x_small_count = 2;
}
if ( $below_midpoint_count < $steps_mid_point - 2 ) {
$x_small_count++;
}
$slug -= 10;
}
$below_sizes = array_reverse( $below_sizes );
$below_sizes[] = array(
'name' => __( 'Medium' ),
'slug' => '50',
'size' => $spacing_scale['mediumStep'] . $unit,
);
$current_step = $spacing_scale['mediumStep'];
$x_large_count = null;
$above_sizes = array();
$slug = 60;
$steps_above = ( $spacing_scale['steps'] - $steps_mid_point ) + $remainder;
for ( $above_midpoint_count = 0; $above_midpoint_count < $steps_above; $above_midpoint_count++ ) {
$current_step = '+' === $spacing_scale['operator']
? $current_step + $spacing_scale['increment']
: ( $spacing_scale['increment'] >= 1 ? $current_step * $spacing_scale['increment'] : $current_step / $spacing_scale['increment'] );
$above_sizes[] = array(
/* translators: %s: Digit to indicate multiple of sizing, eg. 2X-Large. */
'name' => 0 === $above_midpoint_count ? __( 'Large' ) : sprintf( __( '%sX-Large' ), (string) $x_large_count ),
'slug' => (string) $slug,
'size' => round( $current_step, 2 ) . $unit,
);
if ( 1 === $above_midpoint_count ) {
$x_large_count = 2;
}
if ( $above_midpoint_count > 1 ) {
$x_large_count++;
}
$slug += 10;
}
$spacing_sizes = array_merge( $below_sizes, $above_sizes );
// If there are 7 or less steps in the scale revert to numbers for labels instead of t-shirt sizes.
if ( $spacing_scale['steps'] <= 7 ) {
for ( $spacing_sizes_count = 0; $spacing_sizes_count < count( $spacing_sizes ); $spacing_sizes_count++ ) {
$spacing_sizes[ $spacing_sizes_count ]['name'] = (string) ( $spacing_sizes_count + 1 );
}
}
_wp_array_set( $this->theme_json, array( 'settings', 'spacing', 'spacingSizes', 'default' ), $spacing_sizes );
}
}

View File

@@ -30,6 +30,13 @@
}
]
},
"spacing": {
"spacingSizes": [
{
"name": "Space size name"
}
]
},
"blocks": {
"*": {
"typography": {
@@ -55,6 +62,13 @@
"name": "Gradient name"
}
]
},
"spacing": {
"spacingSizes": [
{
"name": "Space size name"
}
]
}
}
}

View File

@@ -3493,4 +3493,385 @@ class Tests_Theme_wpThemeJson extends WP_UnitTestCase {
$style_rules = $theme_json->get_styles_for_block( $metadata );
$this->assertSame( $expected, $root_rules . $style_rules );
}
/**
* Tests generating the spacing presets array based on the spacing scale provided.
*
* @ticket 56467
*
* @dataProvider data_generate_spacing_scale_fixtures
*
* @param array $spacing_scale Example spacing scale definitions from the data provider.
* @param array $expected_output Expected output from data provider.
*/
function test_should_set_spacing_sizes( $spacing_scale, $expected_output ) {
$theme_json = new WP_Theme_JSON(
array(
'version' => 2,
'settings' => array(
'spacing' => array(
'spacingScale' => $spacing_scale,
),
),
)
);
$theme_json->set_spacing_sizes();
$this->assertSame( $expected_output, _wp_array_get( $theme_json->get_raw_data(), array( 'settings', 'spacing', 'spacingSizes', 'default' ) ) );
}
/**
* Data provider for spacing scale tests.
*
* @ticket 56467
*
* @return array
*/
function data_generate_spacing_scale_fixtures() {
return array(
'only one value when single step in spacing scale' => array(
'spacing_scale' => array(
'operator' => '+',
'increment' => 1.5,
'steps' => 1,
'mediumStep' => 4,
'unit' => 'rem',
),
'expected_output' => array(
array(
'name' => '1',
'slug' => '50',
'size' => '4rem',
),
),
),
'one step above medium when two steps in spacing scale' => array(
'spacing_scale' => array(
'operator' => '+',
'increment' => 1.5,
'steps' => 2,
'mediumStep' => 4,
'unit' => 'rem',
),
'expected_output' => array(
array(
'name' => '1',
'slug' => '50',
'size' => '4rem',
),
array(
'name' => '2',
'slug' => '60',
'size' => '5.5rem',
),
),
),
'one step above medium and one below when three steps in spacing scale' => array(
'spacing_scale' => array(
'operator' => '+',
'increment' => 1.5,
'steps' => 3,
'mediumStep' => 4,
'unit' => 'rem',
),
'expected_output' => array(
array(
'name' => '1',
'slug' => '40',
'size' => '2.5rem',
),
array(
'name' => '2',
'slug' => '50',
'size' => '4rem',
),
array(
'name' => '3',
'slug' => '60',
'size' => '5.5rem',
),
),
),
'extra step added above medium when an even number of steps > 2 specified' => array(
'spacing_scale' => array(
'operator' => '+',
'increment' => 1.5,
'steps' => 4,
'mediumStep' => 4,
'unit' => 'rem',
),
'expected_output' => array(
array(
'name' => '1',
'slug' => '40',
'size' => '2.5rem',
),
array(
'name' => '2',
'slug' => '50',
'size' => '4rem',
),
array(
'name' => '3',
'slug' => '60',
'size' => '5.5rem',
),
array(
'name' => '4',
'slug' => '70',
'size' => '7rem',
),
),
),
'extra steps above medium if bottom end will go below zero' => array(
'spacing_scale' => array(
'operator' => '+',
'increment' => 2.5,
'steps' => 5,
'mediumStep' => 5,
'unit' => 'rem',
),
'expected_output' => array(
array(
'name' => '1',
'slug' => '40',
'size' => '2.5rem',
),
array(
'name' => '2',
'slug' => '50',
'size' => '5rem',
),
array(
'name' => '3',
'slug' => '60',
'size' => '7.5rem',
),
array(
'name' => '4',
'slug' => '70',
'size' => '10rem',
),
array(
'name' => '5',
'slug' => '80',
'size' => '12.5rem',
),
),
),
'multiplier correctly calculated above and below medium' => array(
'spacing_scale' => array(
'operator' => '*',
'increment' => 1.5,
'steps' => 5,
'mediumStep' => 1.5,
'unit' => 'rem',
),
'expected_output' => array(
array(
'name' => '1',
'slug' => '30',
'size' => '0.67rem',
),
array(
'name' => '2',
'slug' => '40',
'size' => '1rem',
),
array(
'name' => '3',
'slug' => '50',
'size' => '1.5rem',
),
array(
'name' => '4',
'slug' => '60',
'size' => '2.25rem',
),
array(
'name' => '5',
'slug' => '70',
'size' => '3.38rem',
),
),
),
'increment < 1 combined showing * operator acting as divisor above and below medium' => array(
'spacing_scale' => array(
'operator' => '*',
'increment' => 0.25,
'steps' => 5,
'mediumStep' => 1.5,
'unit' => 'rem',
),
'expected_output' => array(
array(
'name' => '1',
'slug' => '30',
'size' => '0.09rem',
),
array(
'name' => '2',
'slug' => '40',
'size' => '0.38rem',
),
array(
'name' => '3',
'slug' => '50',
'size' => '1.5rem',
),
array(
'name' => '4',
'slug' => '60',
'size' => '6rem',
),
array(
'name' => '5',
'slug' => '70',
'size' => '24rem',
),
),
),
't-shirt sizing used if more than 7 steps in scale' => array(
'spacing_scale' => array(
'operator' => '*',
'increment' => 1.5,
'steps' => 8,
'mediumStep' => 1.5,
'unit' => 'rem',
),
'expected_output' => array(
array(
'name' => '2X-Small',
'slug' => '20',
'size' => '0.44rem',
),
array(
'name' => 'X-Small',
'slug' => '30',
'size' => '0.67rem',
),
array(
'name' => 'Small',
'slug' => '40',
'size' => '1rem',
),
array(
'name' => 'Medium',
'slug' => '50',
'size' => '1.5rem',
),
array(
'name' => 'Large',
'slug' => '60',
'size' => '2.25rem',
),
array(
'name' => 'X-Large',
'slug' => '70',
'size' => '3.38rem',
),
array(
'name' => '2X-Large',
'slug' => '80',
'size' => '5.06rem',
),
array(
'name' => '3X-Large',
'slug' => '90',
'size' => '7.59rem',
),
),
),
);
}
/**
* Tests generating the spacing presets array based on the spacing scale provided.
*
* @ticket 56467
*
* @dataProvider data_set_spacing_sizes_when_invalid
*
* @param array $spacing_scale Example spacing scale definitions from the data provider.
* @param array $expected_output Expected output from data provider.
*/
public function test_set_spacing_sizes_should_detect_invalid_spacing_scale( $spacing_scale, $expected_output ) {
$this->expectNotice();
$this->expectNoticeMessage( 'Some of the theme.json settings.spacing.spacingScale values are invalid' );
$theme_json = new WP_Theme_JSON(
array(
'version' => 2,
'settings' => array(
'spacing' => array(
'spacingScale' => $spacing_scale,
),
),
)
);
$theme_json->set_spacing_sizes();
$this->assertSame( $expected_output, _wp_array_get( $theme_json->get_raw_data(), array( 'settings', 'spacing', 'spacingSizes', 'default' ) ) );
}
/**
* Data provider for spacing scale tests.
*
* @ticket 56467
*
* @return array
*/
function data_set_spacing_sizes_when_invalid() {
return array(
'missing operator value' => array(
'spacing_scale' => array(
'operator' => '',
'increment' => 1.5,
'steps' => 1,
'mediumStep' => 4,
'unit' => 'rem',
),
'expected_output' => null,
),
'non numeric increment' => array(
'spacing_scale' => array(
'operator' => '+',
'increment' => 'add two to previous value',
'steps' => 1,
'mediumStep' => 4,
'unit' => 'rem',
),
'expected_output' => null,
),
'non numeric steps' => array(
'spacing_scale' => array(
'operator' => '+',
'increment' => 1.5,
'steps' => 'spiral staircase preferred',
'mediumStep' => 4,
'unit' => 'rem',
),
'expected_output' => null,
),
'non numeric medium step' => array(
'spacing_scale' => array(
'operator' => '+',
'increment' => 1.5,
'steps' => 5,
'mediumStep' => 'That which is just right',
'unit' => 'rem',
),
'expected_output' => null,
),
'missing unit value' => array(
'spacing_scale' => array(
'operator' => '+',
'increment' => 1.5,
'steps' => 5,
'mediumStep' => 4,
),
'expected_output' => null,
),
);
}
}