From f0b30b5ffb12491639fd650cb8968a82dbcc32fe Mon Sep 17 00:00:00 2001 From: ramonjd Date: Thu, 9 Jun 2022 17:09:21 +1000 Subject: [PATCH 01/14] Initial commit. --- .../style-engine/class-wp-style-engine.php | 121 ++++++++++++++++-- .../phpunit/class-wp-style-engine-test.php | 54 +++++++- 2 files changed, 159 insertions(+), 16 deletions(-) diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index a1961241047213..cd4d0e3e6ae6c0 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -141,6 +141,19 @@ class WP_Style_Engine { ), ), ), + 'elements' => array( + 'link' => array( + 'path' => array( 'elements', 'link' ), + 'value_func' => 'static::get_elements_rules', + 'selector' => 'a', + 'states' => array( + 'hover' => array( + 'path' => array( 'elements', 'link', 'states', 'hover' ), + 'selector' => 'a:hover', + ), + ), + ), + ), 'spacing' => array( 'padding' => array( 'property_keys' => array( @@ -306,21 +319,21 @@ protected static function get_classnames( $style_value, $style_definition ) { * * @param array $style_value A single raw style value from the generate() $block_styles array. * @param array $style_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA. - * @param boolean $should_return_css_vars Whether to try to build and return CSS var values. + * @param array $options The options array passed to $this->generate(). * * @return array An array of CSS rules. */ - protected static function get_css( $style_value, $style_definition, $should_return_css_vars ) { - $rules = array(); - + protected static function get_css( $style_value, $style_definition, $options ) { if ( isset( $style_definition['value_func'] ) && is_callable( $style_definition['value_func'] ) ) { - return call_user_func( $style_definition['value_func'], $style_value, $style_definition ); + return call_user_func( $style_definition['value_func'], $style_value, $style_definition, $options ); } - $style_properties = $style_definition['property_keys']; + $rules = array(); + $style_properties = $style_definition['property_keys']; + $should_return_css_vars = isset( $options['css_vars'] ) && true === $options['css_vars']; // Build CSS var values from var:? values, e.g, `var(--wp--css--rule-slug )` // Check if the value is a CSS preset and there's a corresponding css_var pattern in the style definition. @@ -363,6 +376,7 @@ protected static function get_css( $style_value, $style_definition, $should_retu * @param array $options array( * 'selector' => (string) When a selector is passed, `generate()` will return a full CSS rule `$selector { ...rules }`, otherwise a concatenated string of properties and values. * 'css_vars' => (boolean) Whether to covert CSS values to var() values. If `true` the style engine will try to parse var:? values and output var( --wp--preset--* ) rules. Default is `false`. + * 'css_vars' => (boolean) Whether to covert CSS values to var() values. If `true` the style engine will try to parse var:? values and output var( --wp--preset--* ) rules. Default is `false`. * );. * * @return array|null array( @@ -375,16 +389,23 @@ public function generate( $block_styles, $options ) { return null; } - $css_rules = array(); - $classnames = array(); - $should_return_css_vars = isset( $options['css_vars'] ) && true === $options['css_vars']; + $css_rules = array(); + $classnames = array(); + + // Elements are a special case: we need to define styles on a per-element basis using the element's selector. + // And we also need to combine selectors. + if ( array_key_exists( 'elements', $block_styles ) ) { + return static::generate_elements_rules_output( $block_styles, $options ); + } // Collect CSS and classnames. - foreach ( self::BLOCK_STYLE_DEFINITIONS_METADATA as $definition_group_key => $definition_group_style ) { - if ( empty( $block_styles[ $definition_group_key ] ) ) { + foreach ( self::BLOCK_STYLE_DEFINITIONS_METADATA as $definition_group_key => $definition_group_definitions ) { + // Do we know about this CSS top-level key? + if ( ! array_key_exists( $definition_group_key, $block_styles ) ) { continue; } - foreach ( $definition_group_style as $style_definition ) { + + foreach ( $definition_group_definitions as $style_definition ) { $style_value = _wp_array_get( $block_styles, $style_definition['path'], null ); if ( ! static::is_valid_style_value( $style_value ) ) { @@ -392,7 +413,7 @@ public function generate( $block_styles, $options ) { } $classnames = array_merge( $classnames, static::get_classnames( $style_value, $style_definition ) ); - $css_rules = array_merge( $css_rules, static::get_css( $style_value, $style_definition, $should_return_css_vars ) ); + $css_rules = array_merge( $css_rules, static::get_css( $style_value, $style_definition, $options ) ); } } @@ -448,7 +469,7 @@ public function generate( $block_styles, $options ) { protected static function get_css_individual_property_rules( $style_value, $individual_property_definition ) { $rules = array(); - if ( ! is_array( $style_value ) || empty( $style_value ) || empty( $individual_property_definition['path'] ) ) { + if ( ! is_array( $style_value ) || ! static::is_valid_style_value( $style_value ) || empty( $individual_property_definition['path'] ) ) { return $rules; } @@ -483,6 +504,78 @@ protected static function get_css_individual_property_rules( $style_value, $indi } return $rules; } + + /** + * Returns an CSS ruleset specifically for elements. + * Styles are bundled based on the instructions in BLOCK_STYLE_DEFINITIONS_METADATA. + * + * @param array $element_styles An array of elements, each of which contain styles from a block's attributes. + * @param array $options array( + * 'selector' => (string) When a selector is passed, `generate()` will return a full CSS rule `$selector { ...rules }`, otherwise a concatenated string of properties and values. + * 'css_vars' => (boolean) Whether to covert CSS values to var() values. If `true` the style engine will try to parse var:? values and output var( --wp--preset--* ) rules. Default is `false`. + * 'css_vars' => (boolean) Whether to covert CSS values to var() values. If `true` the style engine will try to parse var:? values and output var( --wp--preset--* ) rules. Default is `false`. + * );. + * + * @return array|null array( + * 'css' => (string) A CSS ruleset formatted to be placed in an HTML `style` attribute or tag. Default is a string of inline styles. + * ); + */ + protected static function generate_elements_rules_output( $element_styles, $options = array() ) { + $css_output = array(); + + foreach ( self::BLOCK_STYLE_DEFINITIONS_METADATA['elements'] as $elements_group_key => $element_definition ) { + $block_styles = _wp_array_get( $element_styles, $element_definition['path'], null ); + + if ( empty( $block_styles ) ) { + continue; + } + + $element_options = array_merge( + $options, + array( + 'selector' => isset( $options['selector'] ) ? "{$options['selector']} {$element_definition['selector']}" : $element_definition['selector'], + ) + ); + + $generated_elements_styles = wp_style_engine_generate( $block_styles, $element_options ); + + if ( isset( $generated_elements_styles['css'] ) ) { + $css_output[] = $generated_elements_styles['css']; + } + + // States. + if ( array_key_exists( 'states', $element_definition ) ) { + foreach ( $element_definition['states'] as $state_group_key => $state_definition ) { + $state_styles = _wp_array_get( $element_styles, $state_definition['path'], null ); + + if ( empty( $state_styles ) ) { + continue; + } + + $state_options = array_merge( + $options, + array( + 'selector' => isset( $options['selector'] ) ? "{$options['selector']} {$state_definition['selector']}" : $state_definition['selector'], + ) + ); + + $generated_state_styles = wp_style_engine_generate( $state_styles, $state_options ); + + if ( isset( $generated_state_styles['css'] ) ) { + $css_output[] = $generated_state_styles['css']; + } + } + } + } + + if ( ! empty( $css_output ) ) { + return array( + 'css' => implode( ' ', $css_output ), + ); + } + + return $css_output; + } } /** diff --git a/packages/style-engine/phpunit/class-wp-style-engine-test.php b/packages/style-engine/phpunit/class-wp-style-engine-test.php index e8274e85425fa3..b875a649ff9d03 100644 --- a/packages/style-engine/phpunit/class-wp-style-engine-test.php +++ b/packages/style-engine/phpunit/class-wp-style-engine-test.php @@ -156,7 +156,7 @@ public function data_generate_styles_fixtures() { ), ), - 'elements_with_css_var_value' => array( + 'with_valid_css_value_preset_style_property' => array( 'block_styles' => array( 'color' => array( 'text' => 'var:preset|color|my-little-pony', @@ -172,7 +172,7 @@ public function data_generate_styles_fixtures() { ), ), - 'elements_with_invalid_preset_style_property' => array( + 'with_invalid_css_value_preset_style_property' => array( 'block_styles' => array( 'color' => array( 'text' => 'var:preset|invalid_property|my-little-pony', @@ -320,6 +320,56 @@ public function data_generate_styles_fixtures() { 'css' => 'border-bottom-color: var(--wp--preset--color--terrible-lizard);', ), ), + + 'elements_and_element_states_default' => array( + 'block_styles' => array( + 'elements' => array( + 'link' => array( + 'color' => array( + 'text' => '#fff', + 'background' => '#000', + ), + 'states' => array( + 'hover' => array( + 'color' => array( + 'text' => '#000', + 'background' => '#fff', + ), + ), + ), + ), + ), + ), + 'options' => array(), + 'expected_output' => array( + 'css' => 'a { color: #fff; background-color: #000; } a:hover { color: #000; background-color: #fff; }', + ), + ), + + 'elements_and_element_states_with_selector' => array( + 'block_styles' => array( + 'elements' => array( + 'link' => array( + 'color' => array( + 'text' => '#fff', + 'background' => '#000', + ), + 'states' => array( + 'hover' => array( + 'color' => array( + 'text' => '#000', + 'background' => '#fff', + ), + ), + ), + ), + ), + ), + 'options' => array( 'selector' => '.la-sinistra' ), + 'expected_output' => array( + 'css' => '.la-sinistra a { color: #fff; background-color: #000; } .la-sinistra a:hover { color: #000; background-color: #fff; }', + ), + ), ); } } From 127bc767d7fc0c868a15ca424bc2fe91ab1265fa Mon Sep 17 00:00:00 2001 From: ramonjd Date: Thu, 9 Jun 2022 17:39:15 +1000 Subject: [PATCH 02/14] Lint and other stuff zzzz --- packages/style-engine/class-wp-style-engine.php | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index cd4d0e3e6ae6c0..1c887abd18cca3 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -376,7 +376,6 @@ protected static function get_css( $style_value, $style_definition, $options ) { * @param array $options array( * 'selector' => (string) When a selector is passed, `generate()` will return a full CSS rule `$selector { ...rules }`, otherwise a concatenated string of properties and values. * 'css_vars' => (boolean) Whether to covert CSS values to var() values. If `true` the style engine will try to parse var:? values and output var( --wp--preset--* ) rules. Default is `false`. - * 'css_vars' => (boolean) Whether to covert CSS values to var() values. If `true` the style engine will try to parse var:? values and output var( --wp--preset--* ) rules. Default is `false`. * );. * * @return array|null array( @@ -506,14 +505,12 @@ protected static function get_css_individual_property_rules( $style_value, $indi } /** - * Returns an CSS ruleset specifically for elements. - * Styles are bundled based on the instructions in BLOCK_STYLE_DEFINITIONS_METADATA. + * Returns an CSS ruleset specifically for elements and their states. + * Styles are bundled based on the instructions in BLOCK_STYLE_DEFINITIONS_METADATA['elements']. * * @param array $element_styles An array of elements, each of which contain styles from a block's attributes. * @param array $options array( * 'selector' => (string) When a selector is passed, `generate()` will return a full CSS rule `$selector { ...rules }`, otherwise a concatenated string of properties and values. - * 'css_vars' => (boolean) Whether to covert CSS values to var() values. If `true` the style engine will try to parse var:? values and output var( --wp--preset--* ) rules. Default is `false`. - * 'css_vars' => (boolean) Whether to covert CSS values to var() values. If `true` the style engine will try to parse var:? values and output var( --wp--preset--* ) rules. Default is `false`. * );. * * @return array|null array( @@ -523,7 +520,7 @@ protected static function get_css_individual_property_rules( $style_value, $indi protected static function generate_elements_rules_output( $element_styles, $options = array() ) { $css_output = array(); - foreach ( self::BLOCK_STYLE_DEFINITIONS_METADATA['elements'] as $elements_group_key => $element_definition ) { + foreach ( self::BLOCK_STYLE_DEFINITIONS_METADATA['elements'] as $element_definition ) { $block_styles = _wp_array_get( $element_styles, $element_definition['path'], null ); if ( empty( $block_styles ) ) { @@ -537,7 +534,7 @@ protected static function generate_elements_rules_output( $element_styles, $opti ) ); - $generated_elements_styles = wp_style_engine_generate( $block_styles, $element_options ); + $generated_elements_styles = self::get_instance()->generate( $block_styles, $element_options ); if ( isset( $generated_elements_styles['css'] ) ) { $css_output[] = $generated_elements_styles['css']; @@ -545,7 +542,7 @@ protected static function generate_elements_rules_output( $element_styles, $opti // States. if ( array_key_exists( 'states', $element_definition ) ) { - foreach ( $element_definition['states'] as $state_group_key => $state_definition ) { + foreach ( $element_definition['states'] as $state_definition ) { $state_styles = _wp_array_get( $element_styles, $state_definition['path'], null ); if ( empty( $state_styles ) ) { @@ -559,7 +556,7 @@ protected static function generate_elements_rules_output( $element_styles, $opti ) ); - $generated_state_styles = wp_style_engine_generate( $state_styles, $state_options ); + $generated_state_styles = self::get_instance()->generate( $state_styles, $state_options ); if ( isset( $generated_state_styles['css'] ) ) { $css_output[] = $generated_state_styles['css']; From 4ced1d56808acd749273135546e4b4aaf7ec931c Mon Sep 17 00:00:00 2001 From: ramonjd Date: Thu, 9 Jun 2022 20:00:47 +1000 Subject: [PATCH 03/14] Removed unused `value_func` --- packages/style-engine/class-wp-style-engine.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index 1c887abd18cca3..12efa1f18c678b 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -143,10 +143,9 @@ class WP_Style_Engine { ), 'elements' => array( 'link' => array( - 'path' => array( 'elements', 'link' ), - 'value_func' => 'static::get_elements_rules', - 'selector' => 'a', - 'states' => array( + 'path' => array( 'elements', 'link' ), + 'selector' => 'a', + 'states' => array( 'hover' => array( 'path' => array( 'elements', 'link', 'states', 'hover' ), 'selector' => 'a:hover', From caeade2630f69940ebb19d47b1bd02298d55eb45 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Fri, 10 Jun 2022 09:43:50 +1000 Subject: [PATCH 04/14] Testing adding button element and transition states. Do not merge! This commit has highlighted the need to possibly allow certain CSS props via safecss_filter_attr --- .../style-engine/class-wp-style-engine.php | 36 +++++-- .../phpunit/class-wp-style-engine-test.php | 99 ++++++++++++------- 2 files changed, 95 insertions(+), 40 deletions(-) diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index 12efa1f18c678b..8d11af8a691a7b 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -63,6 +63,9 @@ class WP_Style_Engine { 'default' => 'background-color', ), 'path' => array( 'color', 'background' ), + 'css_vars' => array( + '--wp--preset--color--$slug' => 'color', + ), 'classnames' => array( 'has-background' => true, 'has-$slug-background-color' => 'color', @@ -141,8 +144,16 @@ class WP_Style_Engine { ), ), ), + 'effects' => array( + 'transition' => array( + 'property_keys' => array( + 'default' => 'transition', + ), + 'path' => array( 'effects', 'transition' ), + ), + ), 'elements' => array( - 'link' => array( + 'link' => array( 'path' => array( 'elements', 'link' ), 'selector' => 'a', 'states' => array( @@ -152,6 +163,16 @@ class WP_Style_Engine { ), ), ), + 'button' => array( + 'path' => array( 'elements', 'button' ), + 'selector' => 'button', + 'states' => array( + 'hover' => array( + 'path' => array( 'elements', 'button', 'states', 'hover' ), + 'selector' => 'button:hover', + ), + ), + ), ), 'spacing' => array( 'padding' => array( @@ -393,7 +414,7 @@ public function generate( $block_styles, $options ) { // Elements are a special case: we need to define styles on a per-element basis using the element's selector. // And we also need to combine selectors. if ( array_key_exists( 'elements', $block_styles ) ) { - return static::generate_elements_rules_output( $block_styles, $options ); + return static::generate_elements_styles( $block_styles, $options ); } // Collect CSS and classnames. @@ -423,7 +444,10 @@ public function generate( $block_styles, $options ) { if ( ! empty( $css_rules ) ) { // Generate inline style rules. foreach ( $css_rules as $rule => $value ) { - $filtered_css = esc_html( safecss_filter_attr( "{$rule}: {$value}" ) ); + // $filtered_css = esc_html( safecss_filter_attr( "{$rule}: {$value}" ) ); + // @TODO disabling escaping only for this test. + // The `transition` property is filtered out otherwise. + $filtered_css = "{$rule}: {$value}"; if ( ! empty( $filtered_css ) ) { $css[] = $filtered_css . ';'; } @@ -512,11 +536,11 @@ protected static function get_css_individual_property_rules( $style_value, $indi * 'selector' => (string) When a selector is passed, `generate()` will return a full CSS rule `$selector { ...rules }`, otherwise a concatenated string of properties and values. * );. * - * @return array|null array( - * 'css' => (string) A CSS ruleset formatted to be placed in an HTML `style` attribute or tag. Default is a string of inline styles. + * @return array array( + * 'css' => (string) A CSS ruleset formatted to be placed in an HTML `style` attribute or tag. Default is a string of inline styles. * ); */ - protected static function generate_elements_rules_output( $element_styles, $options = array() ) { + protected static function generate_elements_styles( $element_styles, $options = array() ) { $css_output = array(); foreach ( self::BLOCK_STYLE_DEFINITIONS_METADATA['elements'] as $element_definition ) { diff --git a/packages/style-engine/phpunit/class-wp-style-engine-test.php b/packages/style-engine/phpunit/class-wp-style-engine-test.php index b875a649ff9d03..0f45db84a130f4 100644 --- a/packages/style-engine/phpunit/class-wp-style-engine-test.php +++ b/packages/style-engine/phpunit/class-wp-style-engine-test.php @@ -119,25 +119,25 @@ public function data_generate_styles_fixtures() { 'css' => 'border-top-left-radius: 99px; border-top-right-radius: 98px; border-bottom-left-radius: 97px; border-bottom-right-radius: 96px; padding-top: 42px; padding-left: 2%; padding-bottom: 44px; padding-right: 5rem; margin-top: 12rem; margin-left: 2vh; margin-bottom: 2px; margin-right: 10em;', ), ), - - 'inline_valid_typography_style' => array( - 'block_styles' => array( - 'typography' => array( - 'fontSize' => 'clamp(2em, 2vw, 4em)', - 'fontFamily' => 'Roboto,Oxygen-Sans,Ubuntu,sans-serif', - 'fontStyle' => 'italic', - 'fontWeight' => '800', - 'lineHeight' => '1.3', - 'textDecoration' => 'underline', - 'textTransform' => 'uppercase', - 'letterSpacing' => '2', - ), - ), - 'options' => null, - 'expected_output' => array( - 'css' => 'font-family: Roboto,Oxygen-Sans,Ubuntu,sans-serif; font-style: italic; font-weight: 800; line-height: 1.3; text-decoration: underline; text-transform: uppercase; letter-spacing: 2;', - ), - ), +// @TODO failing because we removed the safecss_filter_attr() to test this branch. +// 'inline_valid_typography_style' => array( +// 'block_styles' => array( +// 'typography' => array( +// 'fontSize' => 'clamp(2em, 2vw, 4em)', +// 'fontFamily' => 'Roboto,Oxygen-Sans,Ubuntu,sans-serif', +// 'fontStyle' => 'italic', +// 'fontWeight' => '800', +// 'lineHeight' => '1.3', +// 'textDecoration' => 'underline', +// 'textTransform' => 'uppercase', +// 'letterSpacing' => '2', +// ), +// ), +// 'options' => null, +// 'expected_output' => array( +// 'css' => 'font-family: Roboto,Oxygen-Sans,Ubuntu,sans-serif; font-style: italic; font-weight: 800; line-height: 1.3; text-decoration: underline; text-transform: uppercase; letter-spacing: 2;', +// ), +// ), 'style_block_with_selector' => array( 'block_styles' => array( @@ -245,21 +245,21 @@ public function data_generate_styles_fixtures() { 'classnames' => 'has-text-color has-background', ), ), - - 'invalid_classnames_options' => array( - 'block_styles' => array( - 'typography' => array( - 'fontSize' => array( - 'tomodachi' => 'friends', - ), - 'fontFamily' => array( - 'oishii' => 'tasty', - ), - ), - ), - 'options' => array(), - 'expected_output' => array(), - ), +// @TODO failing because we removed the safecss_filter_attr() to test this branch. +// 'invalid_classnames_options' => array( +// 'block_styles' => array( +// 'typography' => array( +// 'fontSize' => array( +// 'tomodachi' => 'friends', +// ), +// 'fontFamily' => array( +// 'oishii' => 'tasty', +// ), +// ), +// ), +// 'options' => array(), +// 'expected_output' => array(), +// ), 'inline_valid_box_model_style_with_sides' => array( 'block_styles' => array( @@ -370,6 +370,37 @@ public function data_generate_styles_fixtures() { 'css' => '.la-sinistra a { color: #fff; background-color: #000; } .la-sinistra a:hover { color: #000; background-color: #fff; }', ), ), + + 'elements_and_element_states_with_css_vars_and_transitions' => array( + 'block_styles' => array( + 'elements' => array( + 'button' => array( + 'color' => array( + 'text' => 'var:preset|color|roastbeef', + 'background' => '#000', + ), + 'effects' => array( + 'transition' => 'all 0.5s ease-out', + ), + 'states' => array( + 'hover' => array( + 'color' => array( + 'text' => 'var:preset|color|pineapple', + 'background' => 'var:preset|color|goldenrod', + ), + ), + ), + ), + ), + ), + 'options' => array( + 'selector' => '.der-beste-button', + 'css_vars' => true, + ), + 'expected_output' => array( + 'css' => '.der-beste-button button { color: var(--wp--preset--color--roastbeef); background-color: #000; transition: all 0.5s ease-out; } .der-beste-button button:hover { color: var(--wp--preset--color--pineapple); background-color: var(--wp--preset--color--goldenrod); }', + ), + ), ); } } From a741faeb87d7359656a696b43ce16d79c5678fe9 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 10 Jun 2022 14:08:58 +0100 Subject: [PATCH 05/14] Add support for focus for links and disabled for buttons --- packages/style-engine/class-wp-style-engine.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index 8d11af8a691a7b..7534f8c7e68b18 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -161,6 +161,10 @@ class WP_Style_Engine { 'path' => array( 'elements', 'link', 'states', 'hover' ), 'selector' => 'a:hover', ), + 'focus' => array( + 'path' => array( 'elements', 'link', 'states', 'focus' ), + 'selector' => 'a:focus', + ), ), ), 'button' => array( @@ -171,6 +175,10 @@ class WP_Style_Engine { 'path' => array( 'elements', 'button', 'states', 'hover' ), 'selector' => 'button:hover', ), + 'disabled' => array( + 'path' => array( 'elements', 'button', 'states', 'disabled' ), + 'selector' => 'button:disabled', + ), ), ), ), @@ -444,10 +452,8 @@ public function generate( $block_styles, $options ) { if ( ! empty( $css_rules ) ) { // Generate inline style rules. foreach ( $css_rules as $rule => $value ) { - // $filtered_css = esc_html( safecss_filter_attr( "{$rule}: {$value}" ) ); - // @TODO disabling escaping only for this test. - // The `transition` property is filtered out otherwise. - $filtered_css = "{$rule}: {$value}"; + $filtered_css = esc_html( safecss_filter_attr( "{$rule}: {$value}" ) ); + if ( ! empty( $filtered_css ) ) { $css[] = $filtered_css . ';'; } @@ -626,3 +632,6 @@ function wp_style_engine_generate( $block_styles, $options = array() ) { } return null; } + + + From 2608e32ea72c7a0949025aa42762bfd033d96d90 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 10 Jun 2022 14:09:16 +0100 Subject: [PATCH 06/14] Update tests to assert on focus and disabled state styles --- .../phpunit/class-wp-style-engine-test.php | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/style-engine/phpunit/class-wp-style-engine-test.php b/packages/style-engine/phpunit/class-wp-style-engine-test.php index 0f45db84a130f4..801b3564a1c89e 100644 --- a/packages/style-engine/phpunit/class-wp-style-engine-test.php +++ b/packages/style-engine/phpunit/class-wp-style-engine-test.php @@ -361,13 +361,33 @@ public function data_generate_styles_fixtures() { 'background' => '#fff', ), ), + 'focus' => array( + 'color' => array( + 'text' => '#000', + 'background' => '#fff', + ), + ), + ), + ), + 'button' => array( + 'color' => array( + 'text' => '#fff', + 'background' => '#000', + ), + 'states' => array( + 'disabled' => array( + 'color' => array( + 'text' => '#999', + 'background' => '#fff', + ), + ), ), ), ), ), 'options' => array( 'selector' => '.la-sinistra' ), 'expected_output' => array( - 'css' => '.la-sinistra a { color: #fff; background-color: #000; } .la-sinistra a:hover { color: #000; background-color: #fff; }', + 'css' => '.la-sinistra a { color: #fff; background-color: #000; } .la-sinistra a:hover { color: #000; background-color: #fff; } .la-sinistra a:focus { color: #000; background-color: #fff; } .la-sinistra button { color: #fff; background-color: #000; } .la-sinistra button:disabled { color: #999; background-color: #fff; }', ), ), From 862ef25b79f98a356f92c43dceb906bcb698affe Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 10 Jun 2022 14:22:43 +0100 Subject: [PATCH 07/14] DRY up by dynamically generating state definitions --- .../style-engine/class-wp-style-engine.php | 32 +++++++------------ 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index 7534f8c7e68b18..82a60a629b58e1 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -156,30 +156,12 @@ class WP_Style_Engine { 'link' => array( 'path' => array( 'elements', 'link' ), 'selector' => 'a', - 'states' => array( - 'hover' => array( - 'path' => array( 'elements', 'link', 'states', 'hover' ), - 'selector' => 'a:hover', - ), - 'focus' => array( - 'path' => array( 'elements', 'link', 'states', 'focus' ), - 'selector' => 'a:focus', - ), - ), + 'states' => array( 'hover', 'focus' ), ), 'button' => array( 'path' => array( 'elements', 'button' ), 'selector' => 'button', - 'states' => array( - 'hover' => array( - 'path' => array( 'elements', 'button', 'states', 'hover' ), - 'selector' => 'button:hover', - ), - 'disabled' => array( - 'path' => array( 'elements', 'button', 'states', 'disabled' ), - 'selector' => 'button:disabled', - ), - ), + 'states' => array( 'hover', 'focus', 'disabled' ), ), ), 'spacing' => array( @@ -571,7 +553,15 @@ protected static function generate_elements_styles( $element_styles, $options = // States. if ( array_key_exists( 'states', $element_definition ) ) { - foreach ( $element_definition['states'] as $state_definition ) { + foreach ( $element_definition['states'] as $the_state ) { + + // Dynamically generate the state definitions based on the state keys provided. + $state_definition = array( + 'path' => array_merge( $element_definition['path'], array( 'states', $the_state ) ), + 'selector' => "{$element_definition['selector']}:{$the_state}", + + ); + $state_styles = _wp_array_get( $element_styles, $state_definition['path'], null ); if ( empty( $state_styles ) ) { From 94e3a7897ffbeaee428bda03e193ab0d985cecef Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 10 Jun 2022 14:29:22 +0100 Subject: [PATCH 08/14] Hack: Filter safe CSS rules to enable transition --- lib/load.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/load.php b/lib/load.php index 0791c511518fc3..aa67455551aee4 100644 --- a/lib/load.php +++ b/lib/load.php @@ -151,6 +151,14 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/demo.php'; require __DIR__ . '/experiments-page.php'; +add_filter( + 'safe_style_css', + function( $safe_rules ) { + $safe_rules[] = 'transition'; + return $safe_rules; + } +); + // Copied package PHP files. if ( file_exists( __DIR__ . '/../build/style-engine/class-wp-style-engine-gutenberg.php' ) ) { require_once __DIR__ . '/../build/style-engine/class-wp-style-engine-gutenberg.php'; @@ -166,3 +174,4 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/block-supports/spacing.php'; require __DIR__ . '/block-supports/dimensions.php'; require __DIR__ . '/block-supports/duotone.php'; + From f98e4c83ec710ae843b75f9700fe368cc0ca48d2 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Tue, 14 Jun 2022 15:10:40 +0100 Subject: [PATCH 09/14] Update data model to remove the states key --- .../style-engine/class-wp-style-engine.php | 48 ++--- .../phpunit/class-wp-style-engine-test.php | 200 +++++++++--------- 2 files changed, 120 insertions(+), 128 deletions(-) diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index 82a60a629b58e1..7254157efa8818 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -156,12 +156,12 @@ class WP_Style_Engine { 'link' => array( 'path' => array( 'elements', 'link' ), 'selector' => 'a', - 'states' => array( 'hover', 'focus' ), + 'states' => array( ':hover', ':focus' ), ), 'button' => array( 'path' => array( 'elements', 'button' ), 'selector' => 'button', - 'states' => array( 'hover', 'focus', 'disabled' ), + 'states' => array( ':hover', ':focus', ':disabled' ), ), ), 'spacing' => array( @@ -551,37 +551,37 @@ protected static function generate_elements_styles( $element_styles, $options = $css_output[] = $generated_elements_styles['css']; } - // States. - if ( array_key_exists( 'states', $element_definition ) ) { - foreach ( $element_definition['states'] as $the_state ) { - // Dynamically generate the state definitions based on the state keys provided. - $state_definition = array( - 'path' => array_merge( $element_definition['path'], array( 'states', $the_state ) ), - 'selector' => "{$element_definition['selector']}:{$the_state}", + // States. + foreach ( $element_definition['states'] as $state_pseudo_selector ) { - ); + // Dynamically generate the state definitions based on the hard coded + // "allow list" of psuedo selectors for the given element. + $state_definition = array( + 'path' => array_merge( $element_definition['path'], array( $state_pseudo_selector ) ), + 'selector' => $element_definition['selector'] . $state_pseudo_selector, + ); - $state_styles = _wp_array_get( $element_styles, $state_definition['path'], null ); + $state_styles = _wp_array_get( $element_styles, $state_definition['path'], null ); - if ( empty( $state_styles ) ) { - continue; - } + if ( empty( $state_styles ) ) { + continue; + } - $state_options = array_merge( - $options, - array( - 'selector' => isset( $options['selector'] ) ? "{$options['selector']} {$state_definition['selector']}" : $state_definition['selector'], - ) - ); + $state_options = array_merge( + $options, + array( + 'selector' => isset( $options['selector'] ) ? "{$options['selector']} {$state_definition['selector']}" : $state_definition['selector'], + ) + ); - $generated_state_styles = self::get_instance()->generate( $state_styles, $state_options ); + $generated_state_styles = self::get_instance()->generate( $state_styles, $state_options ); - if ( isset( $generated_state_styles['css'] ) ) { - $css_output[] = $generated_state_styles['css']; - } + if ( isset( $generated_state_styles['css'] ) ) { + $css_output[] = $generated_state_styles['css']; } } + } if ( ! empty( $css_output ) ) { diff --git a/packages/style-engine/phpunit/class-wp-style-engine-test.php b/packages/style-engine/phpunit/class-wp-style-engine-test.php index 801b3564a1c89e..9878e02dc918f2 100644 --- a/packages/style-engine/phpunit/class-wp-style-engine-test.php +++ b/packages/style-engine/phpunit/class-wp-style-engine-test.php @@ -119,42 +119,42 @@ public function data_generate_styles_fixtures() { 'css' => 'border-top-left-radius: 99px; border-top-right-radius: 98px; border-bottom-left-radius: 97px; border-bottom-right-radius: 96px; padding-top: 42px; padding-left: 2%; padding-bottom: 44px; padding-right: 5rem; margin-top: 12rem; margin-left: 2vh; margin-bottom: 2px; margin-right: 10em;', ), ), -// @TODO failing because we removed the safecss_filter_attr() to test this branch. -// 'inline_valid_typography_style' => array( -// 'block_styles' => array( -// 'typography' => array( -// 'fontSize' => 'clamp(2em, 2vw, 4em)', -// 'fontFamily' => 'Roboto,Oxygen-Sans,Ubuntu,sans-serif', -// 'fontStyle' => 'italic', -// 'fontWeight' => '800', -// 'lineHeight' => '1.3', -// 'textDecoration' => 'underline', -// 'textTransform' => 'uppercase', -// 'letterSpacing' => '2', -// ), -// ), -// 'options' => null, -// 'expected_output' => array( -// 'css' => 'font-family: Roboto,Oxygen-Sans,Ubuntu,sans-serif; font-style: italic; font-weight: 800; line-height: 1.3; text-decoration: underline; text-transform: uppercase; letter-spacing: 2;', -// ), -// ), + // @TODO failing because we removed the safecss_filter_attr() to test this branch. + // 'inline_valid_typography_style' => array( + // 'block_styles' => array( + // 'typography' => array( + // 'fontSize' => 'clamp(2em, 2vw, 4em)', + // 'fontFamily' => 'Roboto,Oxygen-Sans,Ubuntu,sans-serif', + // 'fontStyle' => 'italic', + // 'fontWeight' => '800', + // 'lineHeight' => '1.3', + // 'textDecoration' => 'underline', + // 'textTransform' => 'uppercase', + // 'letterSpacing' => '2', + // ), + // ), + // 'options' => null, + // 'expected_output' => array( + // 'css' => 'font-family: Roboto,Oxygen-Sans,Ubuntu,sans-serif; font-style: italic; font-weight: 800; line-height: 1.3; text-decoration: underline; text-transform: uppercase; letter-spacing: 2;', + // ), + // ), - 'style_block_with_selector' => array( - 'block_styles' => array( - 'spacing' => array( - 'padding' => array( - 'top' => '42px', - 'left' => '2%', - 'bottom' => '44px', - 'right' => '5rem', + 'style_block_with_selector' => array( + 'block_styles' => array( + 'spacing' => array( + 'padding' => array( + 'top' => '42px', + 'left' => '2%', + 'bottom' => '44px', + 'right' => '5rem', + ), ), ), + 'options' => array( 'selector' => '.wp-selector > p' ), + 'expected_output' => array( + 'css' => '.wp-selector > p { padding-top: 42px; padding-left: 2%; padding-bottom: 44px; padding-right: 5rem; }', + ), ), - 'options' => array( 'selector' => '.wp-selector > p' ), - 'expected_output' => array( - 'css' => '.wp-selector > p { padding-top: 42px; padding-left: 2%; padding-bottom: 44px; padding-right: 5rem; }', - ), - ), 'with_valid_css_value_preset_style_property' => array( 'block_styles' => array( @@ -245,51 +245,51 @@ public function data_generate_styles_fixtures() { 'classnames' => 'has-text-color has-background', ), ), -// @TODO failing because we removed the safecss_filter_attr() to test this branch. -// 'invalid_classnames_options' => array( -// 'block_styles' => array( -// 'typography' => array( -// 'fontSize' => array( -// 'tomodachi' => 'friends', -// ), -// 'fontFamily' => array( -// 'oishii' => 'tasty', -// ), -// ), -// ), -// 'options' => array(), -// 'expected_output' => array(), -// ), + // @TODO failing because we removed the safecss_filter_attr() to test this branch. + // 'invalid_classnames_options' => array( + // 'block_styles' => array( + // 'typography' => array( + // 'fontSize' => array( + // 'tomodachi' => 'friends', + // ), + // 'fontFamily' => array( + // 'oishii' => 'tasty', + // ), + // ), + // ), + // 'options' => array(), + // 'expected_output' => array(), + // ), - 'inline_valid_box_model_style_with_sides' => array( - 'block_styles' => array( - 'border' => array( - 'top' => array( - 'color' => '#fe1', - 'width' => '1.5rem', - 'style' => 'dashed', - ), - 'right' => array( - 'color' => '#fe2', - 'width' => '1.4rem', - 'style' => 'solid', - ), - 'bottom' => array( - 'color' => '#fe3', - 'width' => '1.3rem', - ), - 'left' => array( - 'color' => 'var:preset|color|swampy-yellow', - 'width' => '0.5rem', - 'style' => 'dotted', + 'inline_valid_box_model_style_with_sides' => array( + 'block_styles' => array( + 'border' => array( + 'top' => array( + 'color' => '#fe1', + 'width' => '1.5rem', + 'style' => 'dashed', + ), + 'right' => array( + 'color' => '#fe2', + 'width' => '1.4rem', + 'style' => 'solid', + ), + 'bottom' => array( + 'color' => '#fe3', + 'width' => '1.3rem', + ), + 'left' => array( + 'color' => 'var:preset|color|swampy-yellow', + 'width' => '0.5rem', + 'style' => 'dotted', + ), ), ), + 'options' => array(), + 'expected_output' => array( + 'css' => 'border-top-color: #fe1; border-top-width: 1.5rem; border-top-style: dashed; border-right-color: #fe2; border-right-width: 1.4rem; border-right-style: solid; border-bottom-color: #fe3; border-bottom-width: 1.3rem; border-left-color: var(--wp--preset--color--swampy-yellow); border-left-width: 0.5rem; border-left-style: dotted;', + ), ), - 'options' => array(), - 'expected_output' => array( - 'css' => 'border-top-color: #fe1; border-top-width: 1.5rem; border-top-style: dashed; border-right-color: #fe2; border-right-width: 1.4rem; border-right-style: solid; border-bottom-color: #fe3; border-bottom-width: 1.3rem; border-left-color: var(--wp--preset--color--swampy-yellow); border-left-width: 0.5rem; border-left-style: dotted;', - ), - ), 'inline_invalid_box_model_style_with_sides' => array( 'block_styles' => array( @@ -329,12 +329,10 @@ public function data_generate_styles_fixtures() { 'text' => '#fff', 'background' => '#000', ), - 'states' => array( - 'hover' => array( - 'color' => array( - 'text' => '#000', - 'background' => '#fff', - ), + ':hover' => array( + 'color' => array( + 'text' => '#000', + 'background' => '#fff', ), ), ), @@ -349,37 +347,33 @@ public function data_generate_styles_fixtures() { 'elements_and_element_states_with_selector' => array( 'block_styles' => array( 'elements' => array( - 'link' => array( + 'link' => array( 'color' => array( 'text' => '#fff', 'background' => '#000', ), - 'states' => array( - 'hover' => array( - 'color' => array( - 'text' => '#000', - 'background' => '#fff', - ), + ':hover' => array( + 'color' => array( + 'text' => '#000', + 'background' => '#fff', ), - 'focus' => array( - 'color' => array( - 'text' => '#000', - 'background' => '#fff', - ), + ), + ':focus' => array( + 'color' => array( + 'text' => '#000', + 'background' => '#fff', ), ), ), 'button' => array( - 'color' => array( + 'color' => array( 'text' => '#fff', 'background' => '#000', ), - 'states' => array( - 'disabled' => array( - 'color' => array( - 'text' => '#999', - 'background' => '#fff', - ), + ':disabled' => array( + 'color' => array( + 'text' => '#999', + 'background' => '#fff', ), ), ), @@ -402,12 +396,10 @@ public function data_generate_styles_fixtures() { 'effects' => array( 'transition' => 'all 0.5s ease-out', ), - 'states' => array( - 'hover' => array( - 'color' => array( - 'text' => 'var:preset|color|pineapple', - 'background' => 'var:preset|color|goldenrod', - ), + ':hover' => array( + 'color' => array( + 'text' => 'var:preset|color|pineapple', + 'background' => 'var:preset|color|goldenrod', ), ), ), From 9448577fb7e2249433078fdab4ba2ac738eba5c2 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Tue, 14 Jun 2022 15:14:54 +0100 Subject: [PATCH 10/14] Simplify: remove transitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let’s tackle this in a separate PR --- lib/load.php | 8 -------- packages/style-engine/class-wp-style-engine.php | 8 -------- .../style-engine/phpunit/class-wp-style-engine-test.php | 9 +++------ 3 files changed, 3 insertions(+), 22 deletions(-) diff --git a/lib/load.php b/lib/load.php index aa67455551aee4..3d6d782eae15bf 100644 --- a/lib/load.php +++ b/lib/load.php @@ -151,14 +151,6 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/demo.php'; require __DIR__ . '/experiments-page.php'; -add_filter( - 'safe_style_css', - function( $safe_rules ) { - $safe_rules[] = 'transition'; - return $safe_rules; - } -); - // Copied package PHP files. if ( file_exists( __DIR__ . '/../build/style-engine/class-wp-style-engine-gutenberg.php' ) ) { require_once __DIR__ . '/../build/style-engine/class-wp-style-engine-gutenberg.php'; diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index 7254157efa8818..5bf2abbe3287a9 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -144,14 +144,6 @@ class WP_Style_Engine { ), ), ), - 'effects' => array( - 'transition' => array( - 'property_keys' => array( - 'default' => 'transition', - ), - 'path' => array( 'effects', 'transition' ), - ), - ), 'elements' => array( 'link' => array( 'path' => array( 'elements', 'link' ), diff --git a/packages/style-engine/phpunit/class-wp-style-engine-test.php b/packages/style-engine/phpunit/class-wp-style-engine-test.php index 9878e02dc918f2..fc7e1ee67be495 100644 --- a/packages/style-engine/phpunit/class-wp-style-engine-test.php +++ b/packages/style-engine/phpunit/class-wp-style-engine-test.php @@ -385,7 +385,7 @@ public function data_generate_styles_fixtures() { ), ), - 'elements_and_element_states_with_css_vars_and_transitions' => array( + 'elements_and_element_states_with_css_vars' => array( 'block_styles' => array( 'elements' => array( 'button' => array( @@ -393,10 +393,7 @@ public function data_generate_styles_fixtures() { 'text' => 'var:preset|color|roastbeef', 'background' => '#000', ), - 'effects' => array( - 'transition' => 'all 0.5s ease-out', - ), - ':hover' => array( + ':hover' => array( 'color' => array( 'text' => 'var:preset|color|pineapple', 'background' => 'var:preset|color|goldenrod', @@ -410,7 +407,7 @@ public function data_generate_styles_fixtures() { 'css_vars' => true, ), 'expected_output' => array( - 'css' => '.der-beste-button button { color: var(--wp--preset--color--roastbeef); background-color: #000; transition: all 0.5s ease-out; } .der-beste-button button:hover { color: var(--wp--preset--color--pineapple); background-color: var(--wp--preset--color--goldenrod); }', + 'css' => '.der-beste-button button { color: var(--wp--preset--color--roastbeef); background-color: #000; } .der-beste-button button:hover { color: var(--wp--preset--color--pineapple); background-color: var(--wp--preset--color--goldenrod); }', ), ), ); From a0037a031e4b4dd2b6c1493ddfc30b6728017413 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Tue, 14 Jun 2022 15:25:20 +0100 Subject: [PATCH 11/14] Remove everything that is not a link with :hover Initial version should only support :hover on link. We can iteratively add support for more functionality once the elements API is upgraded. --- .../style-engine/class-wp-style-engine.php | 49 ++++++------ .../phpunit/class-wp-style-engine-test.php | 74 ++++++++++++++----- 2 files changed, 82 insertions(+), 41 deletions(-) diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index 5bf2abbe3287a9..0c170a11b13158 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -148,12 +148,11 @@ class WP_Style_Engine { 'link' => array( 'path' => array( 'elements', 'link' ), 'selector' => 'a', - 'states' => array( ':hover', ':focus' ), + 'states' => array( ':hover' ), ), 'button' => array( 'path' => array( 'elements', 'button' ), 'selector' => 'button', - 'states' => array( ':hover', ':focus', ':disabled' ), ), ), 'spacing' => array( @@ -543,37 +542,39 @@ protected static function generate_elements_styles( $element_styles, $options = $css_output[] = $generated_elements_styles['css']; } + // Handle states if the given element supports pseudo selector "states" + // in its allow list. + if ( ! empty( $element_definition['states'] ) ) { - // States. - foreach ( $element_definition['states'] as $state_pseudo_selector ) { + foreach ( $element_definition['states'] as $state_pseudo_selector ) { - // Dynamically generate the state definitions based on the hard coded - // "allow list" of psuedo selectors for the given element. - $state_definition = array( - 'path' => array_merge( $element_definition['path'], array( $state_pseudo_selector ) ), - 'selector' => $element_definition['selector'] . $state_pseudo_selector, - ); + // Dynamically generate the state definitions based on the hard coded + // "allow list" of psuedo selectors for the given element. + $state_definition = array( + 'path' => array_merge( $element_definition['path'], array( $state_pseudo_selector ) ), + 'selector' => $element_definition['selector'] . $state_pseudo_selector, + ); - $state_styles = _wp_array_get( $element_styles, $state_definition['path'], null ); + $state_styles = _wp_array_get( $element_styles, $state_definition['path'], null ); - if ( empty( $state_styles ) ) { - continue; - } + if ( empty( $state_styles ) ) { + continue; + } - $state_options = array_merge( - $options, - array( - 'selector' => isset( $options['selector'] ) ? "{$options['selector']} {$state_definition['selector']}" : $state_definition['selector'], - ) - ); + $state_options = array_merge( + $options, + array( + 'selector' => isset( $options['selector'] ) ? "{$options['selector']} {$state_definition['selector']}" : $state_definition['selector'], + ) + ); - $generated_state_styles = self::get_instance()->generate( $state_styles, $state_options ); + $generated_state_styles = self::get_instance()->generate( $state_styles, $state_options ); - if ( isset( $generated_state_styles['css'] ) ) { - $css_output[] = $generated_state_styles['css']; + if ( isset( $generated_state_styles['css'] ) ) { + $css_output[] = $generated_state_styles['css']; + } } } - } if ( ! empty( $css_output ) ) { diff --git a/packages/style-engine/phpunit/class-wp-style-engine-test.php b/packages/style-engine/phpunit/class-wp-style-engine-test.php index fc7e1ee67be495..e1bf4e5518dec4 100644 --- a/packages/style-engine/phpunit/class-wp-style-engine-test.php +++ b/packages/style-engine/phpunit/class-wp-style-engine-test.php @@ -347,7 +347,7 @@ public function data_generate_styles_fixtures() { 'elements_and_element_states_with_selector' => array( 'block_styles' => array( 'elements' => array( - 'link' => array( + 'link' => array( 'color' => array( 'text' => '#fff', 'background' => '#000', @@ -365,51 +365,91 @@ public function data_generate_styles_fixtures() { ), ), ), - 'button' => array( - 'color' => array( + ), + ), + 'options' => array( 'selector' => '.la-sinistra' ), + 'expected_output' => array( + 'css' => '.la-sinistra a { color: #fff; background-color: #000; } .la-sinistra a:hover { color: #000; background-color: #fff; }', + ), + ), + + 'elements_and_element_states_with_css_vars' => array( + 'block_styles' => array( + 'elements' => array( + 'link' => array( + 'color' => array( + 'text' => 'var:preset|color|roastbeef', + 'background' => '#000', + ), + ':hover' => array( + 'color' => array( + 'text' => 'var:preset|color|pineapple', + 'background' => 'var:preset|color|goldenrod', + ), + ), + ), + ), + ), + 'options' => array( + 'selector' => '.der-beste-link', + 'css_vars' => true, + ), + 'expected_output' => array( + 'css' => '.der-beste-link a { color: var(--wp--preset--color--roastbeef); background-color: #000; } .der-beste-link a:hover { color: var(--wp--preset--color--pineapple); background-color: var(--wp--preset--color--goldenrod); }', + ), + ), + + 'elements_and_unsupported_element_states' => array( + 'block_styles' => array( + 'elements' => array( + 'link' => array( + 'color' => array( 'text' => '#fff', 'background' => '#000', ), - ':disabled' => array( + // Not a supported pseudo selector (yet!) + ':focus' => array( 'color' => array( - 'text' => '#999', + 'text' => '#000', 'background' => '#fff', ), ), ), ), ), - 'options' => array( 'selector' => '.la-sinistra' ), + 'options' => array(), 'expected_output' => array( - 'css' => '.la-sinistra a { color: #fff; background-color: #000; } .la-sinistra a:hover { color: #000; background-color: #fff; } .la-sinistra a:focus { color: #000; background-color: #fff; } .la-sinistra button { color: #fff; background-color: #000; } .la-sinistra button:disabled { color: #999; background-color: #fff; }', + // Should not contain the `:focus` rule. + 'css' => 'a { color: #fff; background-color: #000; }', ), ), - 'elements_and_element_states_with_css_vars' => array( + 'unsupported_elements_with_states' => array( 'block_styles' => array( 'elements' => array( + // Only `link` has state support at this time. 'button' => array( - 'color' => array( - 'text' => 'var:preset|color|roastbeef', + 'color' => array( + 'text' => '#fff', 'background' => '#000', ), ':hover' => array( + // Should be ignored. 'color' => array( - 'text' => 'var:preset|color|pineapple', - 'background' => 'var:preset|color|goldenrod', + 'text' => '#000', + 'background' => '#fff', ), ), ), ), ), - 'options' => array( - 'selector' => '.der-beste-button', - 'css_vars' => true, - ), + 'options' => array(), 'expected_output' => array( - 'css' => '.der-beste-button button { color: var(--wp--preset--color--roastbeef); background-color: #000; } .der-beste-button button:hover { color: var(--wp--preset--color--pineapple); background-color: var(--wp--preset--color--goldenrod); }', + // Should not contain the `:hover` rule. + 'css' => 'button { color: #fff; background-color: #000; }', ), ), + ); } } From 66a0276c649b7d8fe1aac6f5977df7c466bc679e Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Tue, 14 Jun 2022 15:27:31 +0100 Subject: [PATCH 12/14] Remove changes to file --- lib/load.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/load.php b/lib/load.php index 3d6d782eae15bf..0791c511518fc3 100644 --- a/lib/load.php +++ b/lib/load.php @@ -166,4 +166,3 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/block-supports/spacing.php'; require __DIR__ . '/block-supports/dimensions.php'; require __DIR__ . '/block-supports/duotone.php'; - From 037b9236636f777120fc23e623f536cf8d18973e Mon Sep 17 00:00:00 2001 From: ramonjd Date: Wed, 15 Jun 2022 11:10:07 +1000 Subject: [PATCH 13/14] Remove button element from definition list. Reinstated tests A bit of tidying up. --- .../style-engine/class-wp-style-engine.php | 27 +-- .../phpunit/class-wp-style-engine-test.php | 173 ++++++++---------- 2 files changed, 80 insertions(+), 120 deletions(-) diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index 0c170a11b13158..d3eaef4784ec47 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -145,15 +145,11 @@ class WP_Style_Engine { ), ), 'elements' => array( - 'link' => array( + 'link' => array( 'path' => array( 'elements', 'link' ), 'selector' => 'a', 'states' => array( ':hover' ), ), - 'button' => array( - 'path' => array( 'elements', 'button' ), - 'selector' => 'button', - ), ), 'spacing' => array( 'padding' => array( @@ -542,29 +538,20 @@ protected static function generate_elements_styles( $element_styles, $options = $css_output[] = $generated_elements_styles['css']; } - // Handle states if the given element supports pseudo selector "states" - // in its allow list. if ( ! empty( $element_definition['states'] ) ) { - - foreach ( $element_definition['states'] as $state_pseudo_selector ) { - - // Dynamically generate the state definitions based on the hard coded - // "allow list" of psuedo selectors for the given element. - $state_definition = array( - 'path' => array_merge( $element_definition['path'], array( $state_pseudo_selector ) ), - 'selector' => $element_definition['selector'] . $state_pseudo_selector, - ); - - $state_styles = _wp_array_get( $element_styles, $state_definition['path'], null ); + foreach ( $element_definition['states'] as $state_selector ) { + // Try to fetch "state" styles in the incoming element's style object. + $state_styles = _wp_array_get( $element_styles, array_merge( $element_definition['path'], array( $state_selector ) ), null ); if ( empty( $state_styles ) ) { continue; } - $state_options = array_merge( + $element_state_selector = "{$element_definition['selector']}$state_selector"; + $state_options = array_merge( $options, array( - 'selector' => isset( $options['selector'] ) ? "{$options['selector']} {$state_definition['selector']}" : $state_definition['selector'], + 'selector' => isset( $options['selector'] ) ? "{$options['selector']} $element_state_selector" : $element_state_selector, ) ); diff --git a/packages/style-engine/phpunit/class-wp-style-engine-test.php b/packages/style-engine/phpunit/class-wp-style-engine-test.php index e1bf4e5518dec4..0f39ffc11f7117 100644 --- a/packages/style-engine/phpunit/class-wp-style-engine-test.php +++ b/packages/style-engine/phpunit/class-wp-style-engine-test.php @@ -119,42 +119,42 @@ public function data_generate_styles_fixtures() { 'css' => 'border-top-left-radius: 99px; border-top-right-radius: 98px; border-bottom-left-radius: 97px; border-bottom-right-radius: 96px; padding-top: 42px; padding-left: 2%; padding-bottom: 44px; padding-right: 5rem; margin-top: 12rem; margin-left: 2vh; margin-bottom: 2px; margin-right: 10em;', ), ), - // @TODO failing because we removed the safecss_filter_attr() to test this branch. - // 'inline_valid_typography_style' => array( - // 'block_styles' => array( - // 'typography' => array( - // 'fontSize' => 'clamp(2em, 2vw, 4em)', - // 'fontFamily' => 'Roboto,Oxygen-Sans,Ubuntu,sans-serif', - // 'fontStyle' => 'italic', - // 'fontWeight' => '800', - // 'lineHeight' => '1.3', - // 'textDecoration' => 'underline', - // 'textTransform' => 'uppercase', - // 'letterSpacing' => '2', - // ), - // ), - // 'options' => null, - // 'expected_output' => array( - // 'css' => 'font-family: Roboto,Oxygen-Sans,Ubuntu,sans-serif; font-style: italic; font-weight: 800; line-height: 1.3; text-decoration: underline; text-transform: uppercase; letter-spacing: 2;', - // ), - // ), - 'style_block_with_selector' => array( - 'block_styles' => array( - 'spacing' => array( - 'padding' => array( - 'top' => '42px', - 'left' => '2%', - 'bottom' => '44px', - 'right' => '5rem', - ), - ), + 'inline_valid_typography_style' => array( + 'block_styles' => array( + 'typography' => array( + 'fontSize' => 'clamp(2em, 2vw, 4em)', + 'fontFamily' => 'Roboto,Oxygen-Sans,Ubuntu,sans-serif', + 'fontStyle' => 'italic', + 'fontWeight' => '800', + 'lineHeight' => '1.3', + 'textDecoration' => 'underline', + 'textTransform' => 'uppercase', + 'letterSpacing' => '2', ), - 'options' => array( 'selector' => '.wp-selector > p' ), - 'expected_output' => array( - 'css' => '.wp-selector > p { padding-top: 42px; padding-left: 2%; padding-bottom: 44px; padding-right: 5rem; }', + ), + 'options' => null, + 'expected_output' => array( + 'css' => 'font-family: Roboto,Oxygen-Sans,Ubuntu,sans-serif; font-style: italic; font-weight: 800; line-height: 1.3; text-decoration: underline; text-transform: uppercase; letter-spacing: 2;', + ), + ), + + 'style_block_with_selector' => array( + 'block_styles' => array( + 'spacing' => array( + 'padding' => array( + 'top' => '42px', + 'left' => '2%', + 'bottom' => '44px', + 'right' => '5rem', + ), ), ), + 'options' => array( 'selector' => '.wp-selector > p' ), + 'expected_output' => array( + 'css' => '.wp-selector > p { padding-top: 42px; padding-left: 2%; padding-bottom: 44px; padding-right: 5rem; }', + ), + ), 'with_valid_css_value_preset_style_property' => array( 'block_styles' => array( @@ -245,51 +245,51 @@ public function data_generate_styles_fixtures() { 'classnames' => 'has-text-color has-background', ), ), - // @TODO failing because we removed the safecss_filter_attr() to test this branch. - // 'invalid_classnames_options' => array( - // 'block_styles' => array( - // 'typography' => array( - // 'fontSize' => array( - // 'tomodachi' => 'friends', - // ), - // 'fontFamily' => array( - // 'oishii' => 'tasty', - // ), - // ), - // ), - // 'options' => array(), - // 'expected_output' => array(), - // ), - 'inline_valid_box_model_style_with_sides' => array( - 'block_styles' => array( - 'border' => array( - 'top' => array( - 'color' => '#fe1', - 'width' => '1.5rem', - 'style' => 'dashed', - ), - 'right' => array( - 'color' => '#fe2', - 'width' => '1.4rem', - 'style' => 'solid', - ), - 'bottom' => array( - 'color' => '#fe3', - 'width' => '1.3rem', - ), - 'left' => array( - 'color' => 'var:preset|color|swampy-yellow', - 'width' => '0.5rem', - 'style' => 'dotted', - ), + 'invalid_classnames_options' => array( + 'block_styles' => array( + 'typography' => array( + 'fontSize' => array( + 'tomodachi' => 'friends', + ), + 'fontFamily' => array( + 'oishii' => 'tasty', ), ), - 'options' => array(), - 'expected_output' => array( - 'css' => 'border-top-color: #fe1; border-top-width: 1.5rem; border-top-style: dashed; border-right-color: #fe2; border-right-width: 1.4rem; border-right-style: solid; border-bottom-color: #fe3; border-bottom-width: 1.3rem; border-left-color: var(--wp--preset--color--swampy-yellow); border-left-width: 0.5rem; border-left-style: dotted;', + ), + 'options' => array(), + 'expected_output' => array(), + ), + + 'inline_valid_box_model_style_with_sides' => array( + 'block_styles' => array( + 'border' => array( + 'top' => array( + 'color' => '#fe1', + 'width' => '1.5rem', + 'style' => 'dashed', + ), + 'right' => array( + 'color' => '#fe2', + 'width' => '1.4rem', + 'style' => 'solid', + ), + 'bottom' => array( + 'color' => '#fe3', + 'width' => '1.3rem', + ), + 'left' => array( + 'color' => 'var:preset|color|swampy-yellow', + 'width' => '0.5rem', + 'style' => 'dotted', + ), ), ), + 'options' => array(), + 'expected_output' => array( + 'css' => 'border-top-color: #fe1; border-top-width: 1.5rem; border-top-style: dashed; border-right-color: #fe2; border-right-width: 1.4rem; border-right-style: solid; border-bottom-color: #fe3; border-bottom-width: 1.3rem; border-left-color: var(--wp--preset--color--swampy-yellow); border-left-width: 0.5rem; border-left-style: dotted;', + ), + ), 'inline_invalid_box_model_style_with_sides' => array( 'block_styles' => array( @@ -407,7 +407,7 @@ public function data_generate_styles_fixtures() { 'text' => '#fff', 'background' => '#000', ), - // Not a supported pseudo selector (yet!) + // Not a supported pseudo selector (yet!). ':focus' => array( 'color' => array( 'text' => '#000', @@ -423,33 +423,6 @@ public function data_generate_styles_fixtures() { 'css' => 'a { color: #fff; background-color: #000; }', ), ), - - 'unsupported_elements_with_states' => array( - 'block_styles' => array( - 'elements' => array( - // Only `link` has state support at this time. - 'button' => array( - 'color' => array( - 'text' => '#fff', - 'background' => '#000', - ), - ':hover' => array( - // Should be ignored. - 'color' => array( - 'text' => '#000', - 'background' => '#fff', - ), - ), - ), - ), - ), - 'options' => array(), - 'expected_output' => array( - // Should not contain the `:hover` rule. - 'css' => 'button { color: #fff; background-color: #000; }', - ), - ), - ); } } From 99d836f58dc5af117bd0790b3c77d492d9a9b75f Mon Sep 17 00:00:00 2001 From: ramonjd Date: Wed, 15 Jun 2022 11:50:26 +1000 Subject: [PATCH 14/14] Updating elements to account for the fact that the style engine controls which elements we support. --- lib/block-supports/elements.php | 41 +++++++++++++-------------------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/lib/block-supports/elements.php b/lib/block-supports/elements.php index 9230fd48b1c102..3b7fe7001b5dcc 100644 --- a/lib/block-supports/elements.php +++ b/lib/block-supports/elements.php @@ -87,35 +87,26 @@ function gutenberg_render_elements_support( $block_content, $block ) { * @return null */ function gutenberg_render_elements_support_styles( $pre_render, $block ) { - $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] ); - $element_block_styles = isset( $block['attrs']['style']['elements'] ) ? $block['attrs']['style']['elements'] : null; - - /* - * For now we only care about link color. - * This code in the future when we have a public API - * should take advantage of WP_Theme_JSON_Gutenberg::compute_style_properties - * and work for any element and style. - */ + $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] ); + $element_block_styles = isset( $block['attrs']['style']['elements'] ) ? $block['attrs']['style']['elements'] : null; $skip_link_color_serialization = gutenberg_should_skip_block_supports_serialization( $block_type, 'color', 'link' ); - if ( $skip_link_color_serialization ) { + if ( empty( $element_block_styles ) || $skip_link_color_serialization ) { return null; } - $class_name = gutenberg_get_elements_class_name( $block ); - $link_block_styles = isset( $element_block_styles['link'] ) ? $element_block_styles['link'] : null; - - if ( $link_block_styles ) { - $styles = gutenberg_style_engine_generate( - $link_block_styles, - array( - 'selector' => ".$class_name a", - 'css_vars' => true, - ) - ); - - if ( ! empty( $styles['css'] ) ) { - gutenberg_enqueue_block_support_styles( $styles['css'] ); - } + $class_name = '.' . gutenberg_get_elements_class_name( $block ); + $styles = gutenberg_style_engine_generate( + array( + 'elements' => $element_block_styles, + ), + array( + 'selector' => $class_name, + 'css_vars' => true, + ) + ); + + if ( ! empty( $styles['css'] ) ) { + gutenberg_enqueue_block_support_styles( $styles['css'] ); } return null;