From a533269eb95dc643b49da32c093c1e71b5335277 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Mon, 27 Jun 2022 11:50:24 +0300 Subject: [PATCH 1/5] Move defining style definitions meta to block-supports --- lib/block-supports/background.php | 19 ++ lib/block-supports/border.php | 66 +++++ lib/block-supports/colors.php | 51 ++++ lib/block-supports/dimensions.php | 16 ++ lib/block-supports/shadow.php | 15 + lib/block-supports/spacing.php | 26 ++ lib/block-supports/typography.php | 73 +++++ .../style-engine/class-wp-style-engine.php | 272 +++--------------- 8 files changed, 298 insertions(+), 240 deletions(-) diff --git a/lib/block-supports/background.php b/lib/block-supports/background.php index a32ee72fd90c6d..d096cbefb79a97 100644 --- a/lib/block-supports/background.php +++ b/lib/block-supports/background.php @@ -101,3 +101,22 @@ function gutenberg_render_background_support( $block_content, $block ) { ); add_filter( 'render_block', 'gutenberg_render_background_support', 10, 2 ); + +WP_Style_Engine_Gutenberg::register_block_style_definitions_metadata( + 'background', + array( + 'backgroundImage' => array( + 'property_keys' => array( + 'default' => 'background-image', + ), + 'value_func' => array( self::class, 'get_url_or_value_css_declaration' ), + 'path' => array( 'background', 'backgroundImage' ), + ), + 'backgroundSize' => array( + 'property_keys' => array( + 'default' => 'background-size', + ), + 'path' => array( 'background', 'backgroundSize' ), + ), + ) +); diff --git a/lib/block-supports/border.php b/lib/block-supports/border.php index 1a54371d082e17..d4b59c0385fc0c 100644 --- a/lib/block-supports/border.php +++ b/lib/block-supports/border.php @@ -162,3 +162,69 @@ function gutenberg_has_border_feature_support( $block_type, $feature, $default_v 'apply' => 'gutenberg_apply_border_support', ) ); + +WP_Style_Engine_Gutenberg::register_block_style_definitions_metadata( + 'border', + array( + 'color' => array( + 'property_keys' => array( + 'default' => 'border-color', + 'individual' => 'border-%s-color', + ), + 'path' => array( 'border', 'color' ), + 'classnames' => array( + 'has-border-color' => true, + 'has-$slug-border-color' => 'color', + ), + ), + 'radius' => array( + 'property_keys' => array( + 'default' => 'border-radius', + 'individual' => 'border-%s-radius', + ), + 'path' => array( 'border', 'radius' ), + ), + 'style' => array( + 'property_keys' => array( + 'default' => 'border-style', + 'individual' => 'border-%s-style', + ), + 'path' => array( 'border', 'style' ), + ), + 'width' => array( + 'property_keys' => array( + 'default' => 'border-width', + 'individual' => 'border-%s-width', + ), + 'path' => array( 'border', 'width' ), + ), + 'top' => array( + 'value_func' => array( self::class, 'get_individual_property_css_declarations' ), + 'path' => array( 'border', 'top' ), + 'css_vars' => array( + 'color' => '--wp--preset--color--$slug', + ), + ), + 'right' => array( + 'value_func' => array( self::class, 'get_individual_property_css_declarations' ), + 'path' => array( 'border', 'right' ), + 'css_vars' => array( + 'color' => '--wp--preset--color--$slug', + ), + ), + 'bottom' => array( + 'value_func' => array( self::class, 'get_individual_property_css_declarations' ), + 'path' => array( 'border', 'bottom' ), + 'css_vars' => array( + 'color' => '--wp--preset--color--$slug', + ), + ), + 'left' => array( + 'value_func' => array( self::class, 'get_individual_property_css_declarations' ), + 'path' => array( 'border', 'left' ), + 'css_vars' => array( + 'color' => '--wp--preset--color--$slug', + ), + ), + ) +); diff --git a/lib/block-supports/colors.php b/lib/block-supports/colors.php index 6919f58c067e4a..3186c91a095b6f 100644 --- a/lib/block-supports/colors.php +++ b/lib/block-supports/colors.php @@ -135,3 +135,54 @@ function gutenberg_apply_colors_support( $block_type, $block_attributes ) { 'apply' => 'gutenberg_apply_colors_support', ) ); + +WP_Style_Engine_Gutenberg::register_block_style_definitions_metadata( + 'color.text', + array( + 'property_keys' => array( + 'default' => 'color', + ), + 'path' => array( 'color', 'text' ), + 'css_vars' => array( + 'color' => '--wp--preset--color--$slug', + ), + 'classnames' => array( + 'has-text-color' => true, + 'has-$slug-color' => 'color', + ), + ) +); + +WP_Style_Engine_Gutenberg::register_block_style_definitions_metadata( + 'color.background', + array( + 'property_keys' => array( + 'default' => 'background-color', + ), + 'path' => array( 'color', 'background' ), + 'css_vars' => array( + 'color' => '--wp--preset--color--$slug', + ), + 'classnames' => array( + 'has-background' => true, + 'has-$slug-background-color' => 'color', + ), + ) +); + +WP_Style_Engine_Gutenberg::register_block_style_definitions_metadata( + 'color.gradient', + array( + 'property_keys' => array( + 'default' => 'background', + ), + 'css_vars' => array( + 'gradient' => '--wp--preset--gradient--$slug', + ), + 'path' => array( 'color', 'gradient' ), + 'classnames' => array( + 'has-background' => true, + 'has-$slug-gradient-background' => 'gradient', + ), + ) +); diff --git a/lib/block-supports/dimensions.php b/lib/block-supports/dimensions.php index 1ef43133c2cdfb..5f3d1503c60549 100644 --- a/lib/block-supports/dimensions.php +++ b/lib/block-supports/dimensions.php @@ -82,3 +82,19 @@ function gutenberg_apply_dimensions_support( $block_type, $block_attributes ) { 'apply' => 'gutenberg_apply_dimensions_support', ) ); + + +WP_Style_Engine_Gutenberg::register_block_style_definitions_metadata( + 'dimensions', + array( + 'minHeight' => array( + 'property_keys' => array( + 'default' => 'min-height', + ), + 'path' => array( 'dimensions', 'minHeight' ), + 'css_vars' => array( + 'spacing' => '--wp--preset--spacing--$slug', + ), + ), + ) +); diff --git a/lib/block-supports/shadow.php b/lib/block-supports/shadow.php index 4a28c98b79325d..69ba9b93e84527 100644 --- a/lib/block-supports/shadow.php +++ b/lib/block-supports/shadow.php @@ -75,3 +75,18 @@ function gutenberg_apply_shadow_support( $block_type, $block_attributes ) { 'apply' => 'gutenberg_apply_shadow_support', ) ); + +WP_Style_Engine_Gutenberg::register_block_style_definitions_metadata( + 'shadow', + array( + 'shadow' => array( + 'property_keys' => array( + 'default' => 'box-shadow', + ), + 'path' => array( 'shadow' ), + 'css_vars' => array( + 'shadow' => '--wp--preset--shadow--$slug', + ), + ), + ) +); diff --git a/lib/block-supports/spacing.php b/lib/block-supports/spacing.php index 86e6c750185a56..08d82ff061e50c 100644 --- a/lib/block-supports/spacing.php +++ b/lib/block-supports/spacing.php @@ -81,3 +81,29 @@ function gutenberg_apply_spacing_support( $block_type, $block_attributes ) { 'apply' => 'gutenberg_apply_spacing_support', ) ); + +WP_Style_Engine_Gutenberg::register_block_style_definitions_metadata( + 'spacing', + array( + 'padding' => array( + 'property_keys' => array( + 'default' => 'padding', + 'individual' => 'padding-%s', + ), + 'path' => array( 'spacing', 'padding' ), + 'css_vars' => array( + 'spacing' => '--wp--preset--spacing--$slug', + ), + ), + 'margin' => array( + 'property_keys' => array( + 'default' => 'margin', + 'individual' => 'margin-%s', + ), + 'path' => array( 'spacing', 'margin' ), + 'css_vars' => array( + 'spacing' => '--wp--preset--spacing--$slug', + ), + ), + ) +); diff --git a/lib/block-supports/typography.php b/lib/block-supports/typography.php index 5c051ee05cc2c2..d1cb4b7c52a904 100644 --- a/lib/block-supports/typography.php +++ b/lib/block-supports/typography.php @@ -580,3 +580,76 @@ function gutenberg_get_typography_font_size_value( $preset, $should_use_fluid_ty remove_filter( 'render_block', 'wp_render_typography_support' ); } add_filter( 'render_block', 'gutenberg_render_typography_support', 10, 2 ); + + +WP_Style_Engine_Gutenberg::register_block_style_definitions_metadata( + 'typography', + array( + 'fontSize' => array( + 'property_keys' => array( + 'default' => 'font-size', + ), + 'path' => array( 'typography', 'fontSize' ), + 'classnames' => array( + 'has-$slug-font-size' => 'font-size', + ), + ), + 'fontFamily' => array( + 'property_keys' => array( + 'default' => 'font-family', + ), + 'path' => array( 'typography', 'fontFamily' ), + 'classnames' => array( + 'has-$slug-font-family' => 'font-family', + ), + ), + 'fontStyle' => array( + 'property_keys' => array( + 'default' => 'font-style', + ), + 'path' => array( 'typography', 'fontStyle' ), + ), + 'fontWeight' => array( + 'property_keys' => array( + 'default' => 'font-weight', + ), + 'path' => array( 'typography', 'fontWeight' ), + ), + 'lineHeight' => array( + 'property_keys' => array( + 'default' => 'line-height', + ), + 'path' => array( 'typography', 'lineHeight' ), + ), + 'textColumns' => array( + 'property_keys' => array( + 'default' => 'column-count', + ), + 'path' => array( 'typography', 'textColumns' ), + ), + 'textDecoration' => array( + 'property_keys' => array( + 'default' => 'text-decoration', + ), + 'path' => array( 'typography', 'textDecoration' ), + ), + 'textTransform' => array( + 'property_keys' => array( + 'default' => 'text-transform', + ), + 'path' => array( 'typography', 'textTransform' ), + ), + 'letterSpacing' => array( + 'property_keys' => array( + 'default' => 'letter-spacing', + ), + 'path' => array( 'typography', 'letterSpacing' ), + ), + 'writingMode' => array( + 'property_keys' => array( + 'default' => 'writing-mode', + ), + 'path' => array( 'typography', 'writingMode' ), + ), + ) +); diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index a8935fc5ef14b2..517b7473983ee2 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -42,238 +42,29 @@ final class WP_Style_Engine { * * @var array */ - const BLOCK_STYLE_DEFINITIONS_METADATA = array( - 'background' => array( - 'backgroundImage' => array( - 'property_keys' => array( - 'default' => 'background-image', - ), - 'value_func' => array( self::class, 'get_url_or_value_css_declaration' ), - 'path' => array( 'background', 'backgroundImage' ), - ), - 'backgroundSize' => array( - 'property_keys' => array( - 'default' => 'background-size', - ), - 'path' => array( 'background', 'backgroundSize' ), - ), - ), - 'color' => array( - 'text' => array( - 'property_keys' => array( - 'default' => 'color', - ), - 'path' => array( 'color', 'text' ), - 'css_vars' => array( - 'color' => '--wp--preset--color--$slug', - ), - 'classnames' => array( - 'has-text-color' => true, - 'has-$slug-color' => 'color', - ), - ), - 'background' => array( - 'property_keys' => array( - 'default' => 'background-color', - ), - 'path' => array( 'color', 'background' ), - 'css_vars' => array( - 'color' => '--wp--preset--color--$slug', - ), - 'classnames' => array( - 'has-background' => true, - 'has-$slug-background-color' => 'color', - ), - ), - 'gradient' => array( - 'property_keys' => array( - 'default' => 'background', - ), - 'css_vars' => array( - 'gradient' => '--wp--preset--gradient--$slug', - ), - 'path' => array( 'color', 'gradient' ), - 'classnames' => array( - 'has-background' => true, - 'has-$slug-gradient-background' => 'gradient', - ), - ), - ), - 'border' => array( - 'color' => array( - 'property_keys' => array( - 'default' => 'border-color', - 'individual' => 'border-%s-color', - ), - 'path' => array( 'border', 'color' ), - 'classnames' => array( - 'has-border-color' => true, - 'has-$slug-border-color' => 'color', - ), - ), - 'radius' => array( - 'property_keys' => array( - 'default' => 'border-radius', - 'individual' => 'border-%s-radius', - ), - 'path' => array( 'border', 'radius' ), - ), - 'style' => array( - 'property_keys' => array( - 'default' => 'border-style', - 'individual' => 'border-%s-style', - ), - 'path' => array( 'border', 'style' ), - ), - 'width' => array( - 'property_keys' => array( - 'default' => 'border-width', - 'individual' => 'border-%s-width', - ), - 'path' => array( 'border', 'width' ), - ), - 'top' => array( - 'value_func' => array( self::class, 'get_individual_property_css_declarations' ), - 'path' => array( 'border', 'top' ), - 'css_vars' => array( - 'color' => '--wp--preset--color--$slug', - ), - ), - 'right' => array( - 'value_func' => array( self::class, 'get_individual_property_css_declarations' ), - 'path' => array( 'border', 'right' ), - 'css_vars' => array( - 'color' => '--wp--preset--color--$slug', - ), - ), - 'bottom' => array( - 'value_func' => array( self::class, 'get_individual_property_css_declarations' ), - 'path' => array( 'border', 'bottom' ), - 'css_vars' => array( - 'color' => '--wp--preset--color--$slug', - ), - ), - 'left' => array( - 'value_func' => array( self::class, 'get_individual_property_css_declarations' ), - 'path' => array( 'border', 'left' ), - 'css_vars' => array( - 'color' => '--wp--preset--color--$slug', - ), - ), - ), - 'shadow' => array( - 'shadow' => array( - 'property_keys' => array( - 'default' => 'box-shadow', - ), - 'path' => array( 'shadow' ), - 'css_vars' => array( - 'shadow' => '--wp--preset--shadow--$slug', - ), - ), - ), - 'dimensions' => array( - 'minHeight' => array( - 'property_keys' => array( - 'default' => 'min-height', - ), - 'path' => array( 'dimensions', 'minHeight' ), - 'css_vars' => array( - 'spacing' => '--wp--preset--spacing--$slug', - ), - ), - ), - 'spacing' => array( - 'padding' => array( - 'property_keys' => array( - 'default' => 'padding', - 'individual' => 'padding-%s', - ), - 'path' => array( 'spacing', 'padding' ), - 'css_vars' => array( - 'spacing' => '--wp--preset--spacing--$slug', - ), - ), - 'margin' => array( - 'property_keys' => array( - 'default' => 'margin', - 'individual' => 'margin-%s', - ), - 'path' => array( 'spacing', 'margin' ), - 'css_vars' => array( - 'spacing' => '--wp--preset--spacing--$slug', - ), - ), - ), - 'typography' => array( - 'fontSize' => array( - 'property_keys' => array( - 'default' => 'font-size', - ), - 'path' => array( 'typography', 'fontSize' ), - 'classnames' => array( - 'has-$slug-font-size' => 'font-size', - ), - ), - 'fontFamily' => array( - 'property_keys' => array( - 'default' => 'font-family', - ), - 'path' => array( 'typography', 'fontFamily' ), - 'classnames' => array( - 'has-$slug-font-family' => 'font-family', - ), - ), - 'fontStyle' => array( - 'property_keys' => array( - 'default' => 'font-style', - ), - 'path' => array( 'typography', 'fontStyle' ), - ), - 'fontWeight' => array( - 'property_keys' => array( - 'default' => 'font-weight', - ), - 'path' => array( 'typography', 'fontWeight' ), - ), - 'lineHeight' => array( - 'property_keys' => array( - 'default' => 'line-height', - ), - 'path' => array( 'typography', 'lineHeight' ), - ), - 'textColumns' => array( - 'property_keys' => array( - 'default' => 'column-count', - ), - 'path' => array( 'typography', 'textColumns' ), - ), - 'textDecoration' => array( - 'property_keys' => array( - 'default' => 'text-decoration', - ), - 'path' => array( 'typography', 'textDecoration' ), - ), - 'textTransform' => array( - 'property_keys' => array( - 'default' => 'text-transform', - ), - 'path' => array( 'typography', 'textTransform' ), - ), - 'letterSpacing' => array( - 'property_keys' => array( - 'default' => 'letter-spacing', - ), - 'path' => array( 'typography', 'letterSpacing' ), - ), - 'writingMode' => array( - 'property_keys' => array( - 'default' => 'writing-mode', - ), - 'path' => array( 'typography', 'writingMode' ), - ), - ), - ); + private static $block_style_definition_metadata = array(); + + /** + * Registers a style definition metadata for a defined path. + * Adds the data to self::$block_style_definition_metadata. + * + * @param string $path The path to the style definition, in a dot-annotation format (e.g., "border.color"). + * @param array $meta The style definition metadata. + */ + public static function register_block_style_definitions_metadata( $path = '', $meta = array() ) { + $result = array(); + $keys = explode( '.', $path ); + $keys = array_reverse( $keys ); + $value = $meta; + foreach ( $keys as $key ) { + // Wrap value with key over each iteration. + $value = array( + $key => $value, + ); + $result = array_merge_recursive( $result, $value ); + } + static::$block_style_definition_metadata = array_merge_recursive( static::$block_style_definition_metadata, $result ); + } /** * Util: Extracts the slug in kebab case from a preset string, e.g., "heavenly-blue" from 'var:preset|color|heavenlyBlue'. @@ -353,7 +144,7 @@ public static function get_store( $store_name ) { /** * Returns classnames and CSS based on the values in a styles object. - * Return values are parsed based on the instructions in BLOCK_STYLE_DEFINITIONS_METADATA. + * Return values are parsed based on the instructions in static::$block_style_definition_metadata. * * @since 6.1.0 * @@ -381,7 +172,7 @@ public static function parse_block_styles( $block_styles, $options ) { } // Collect CSS and classnames. - foreach ( static::BLOCK_STYLE_DEFINITIONS_METADATA as $definition_group_key => $definition_group_style ) { + foreach ( static::$block_style_definition_metadata as $definition_group_key => $definition_group_style ) { if ( empty( $block_styles[ $definition_group_key ] ) ) { continue; } @@ -404,7 +195,7 @@ public static function parse_block_styles( $block_styles, $options ) { * Returns classnames, and generates classname(s) from a CSS preset property pattern, e.g., '`var:preset||`'. * * @param array $style_value A single raw style value or css preset property from the $block_styles array. - * @param array $style_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA. + * @param array $style_definition A single style definition from static::$block_style_definition_metadata. * * @return array|string[] An array of CSS classnames, or empty array. */ @@ -424,7 +215,7 @@ protected static function get_classnames( $style_value, $style_definition ) { if ( $slug ) { /* - * Right now we expect a classname pattern to be stored in BLOCK_STYLE_DEFINITIONS_METADATA. + * Right now we expect a classname pattern to be stored in static::$block_style_definition_metadata. * One day, if there are no stored schemata, we could allow custom patterns or * generate classnames based on other properties * such as a path or a value or a prefix passed in options. @@ -443,7 +234,7 @@ protected static function get_classnames( $style_value, $style_definition ) { * @since 6.1.0 * * @param array $style_value A single raw style value from $block_styles array. - * @param array $style_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA. + * @param array $style_definition A single style definition from static::$block_style_definition_metadata. * @param array $options { * Optional. An array of options. Default empty array. * @@ -513,7 +304,8 @@ protected static function get_css_declarations( $style_value, $style_definition, * "border-image-{outset|source|width|repeat|slice}: {value};" * * @param array $style_value A single raw style value from $block_styles array. - * @param array $individual_property_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA representing an individual property of a CSS property, e.g., 'top' in 'border-top'. + * @param array $individual_property_definition A single style definition from static::$block_style_definition_metadata, + * representing an individual property of a CSS property, e.g., 'top' in 'border-top'. * @param array $options { * Optional. An array of options. Default empty array. * @@ -544,7 +336,7 @@ protected static function get_individual_property_css_declarations( $style_value // Build a path to the individual rules in definitions. $style_definition_path = array( $definition_group_key, $css_property ); - $style_definition = _wp_array_get( static::BLOCK_STYLE_DEFINITIONS_METADATA, $style_definition_path, null ); + $style_definition = _wp_array_get( static::$block_style_definition_metadata, $style_definition_path, null ); if ( $style_definition && isset( $style_definition['property_keys']['individual'] ) ) { // Set a CSS var if there is a valid preset value. @@ -565,7 +357,7 @@ protected static function get_individual_property_css_declarations( $style_value * e.g., array( 'background-image' => "url( '...' )" ). * * @param array $style_value A single raw style value from $block_styles array. - * @param array $style_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA. + * @param array $style_definition A single style definition from static::$block_style_definition_metadata. * * @return string[] An associative array of CSS definitions, e.g., array( "$property" => "$value", "$property" => "$value" ). */ From f7e77e77873137b787c942d672e623ef2065dc8e Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Tue, 26 Sep 2023 09:38:06 +0300 Subject: [PATCH 2/5] copy-paste omission --- lib/block-supports/background.php | 2 +- lib/block-supports/border.php | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/block-supports/background.php b/lib/block-supports/background.php index d096cbefb79a97..90fee333f37c64 100644 --- a/lib/block-supports/background.php +++ b/lib/block-supports/background.php @@ -109,7 +109,7 @@ function gutenberg_render_background_support( $block_content, $block ) { 'property_keys' => array( 'default' => 'background-image', ), - 'value_func' => array( self::class, 'get_url_or_value_css_declaration' ), + 'value_func' => array( 'WP_Style_Engine_Gutenberg', 'get_url_or_value_css_declaration' ), 'path' => array( 'background', 'backgroundImage' ), ), 'backgroundSize' => array( diff --git a/lib/block-supports/border.php b/lib/block-supports/border.php index d4b59c0385fc0c..494c229833ce72 100644 --- a/lib/block-supports/border.php +++ b/lib/block-supports/border.php @@ -199,28 +199,28 @@ function gutenberg_has_border_feature_support( $block_type, $feature, $default_v 'path' => array( 'border', 'width' ), ), 'top' => array( - 'value_func' => array( self::class, 'get_individual_property_css_declarations' ), + 'value_func' => array( 'WP_Style_Engine_Gutenberg', 'get_individual_property_css_declarations' ), 'path' => array( 'border', 'top' ), 'css_vars' => array( 'color' => '--wp--preset--color--$slug', ), ), 'right' => array( - 'value_func' => array( self::class, 'get_individual_property_css_declarations' ), + 'value_func' => array( 'WP_Style_Engine_Gutenberg', 'get_individual_property_css_declarations' ), 'path' => array( 'border', 'right' ), 'css_vars' => array( 'color' => '--wp--preset--color--$slug', ), ), 'bottom' => array( - 'value_func' => array( self::class, 'get_individual_property_css_declarations' ), + 'value_func' => array( 'WP_Style_Engine_Gutenberg', 'get_individual_property_css_declarations' ), 'path' => array( 'border', 'bottom' ), 'css_vars' => array( 'color' => '--wp--preset--color--$slug', ), ), 'left' => array( - 'value_func' => array( self::class, 'get_individual_property_css_declarations' ), + 'value_func' => array( 'WP_Style_Engine_Gutenberg', 'get_individual_property_css_declarations' ), 'path' => array( 'border', 'left' ), 'css_vars' => array( 'color' => '--wp--preset--color--$slug', From 42b17dfa7ca895425fceafd55623d8a782a38225 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Tue, 26 Sep 2023 09:51:23 +0300 Subject: [PATCH 3/5] Move methods to their respective block-supports --- lib/block-supports/background.php | 37 +++++++- lib/block-supports/border.php | 62 ++++++++++++- .../style-engine/class-wp-style-engine.php | 93 +------------------ 3 files changed, 96 insertions(+), 96 deletions(-) diff --git a/lib/block-supports/background.php b/lib/block-supports/background.php index 90fee333f37c64..09e7e3e8ad56ea 100644 --- a/lib/block-supports/background.php +++ b/lib/block-supports/background.php @@ -92,6 +92,41 @@ function gutenberg_render_background_support( $block_content, $block ) { return $block_content; } +/** + * Style value parser that constructs a CSS definition array comprising a single CSS property and value. + * If the provided value is an array containing a `url` property, the function will return a CSS definition array + * with a single property and value, with `url` escaped and injected into a CSS `url()` function, + * e.g., array( 'background-image' => "url( '...' )" ). + * + * @param array $style_value A single raw style value from $block_styles array. + * @param array $style_definition A single style definition from static::$block_style_definition_metadata. + * + * @return string[] An associative array of CSS definitions, e.g., array( "$property" => "$value", "$property" => "$value" ). + */ +function _gutenberg_block_supports_get_url_or_value_css_declaration( $style_value, $style_definition ) { + if ( empty( $style_value ) ) { + return array(); + } + + $css_declarations = array(); + + if ( isset( $style_definition['property_keys']['default'] ) ) { + $value = null; + + if ( ! empty( $style_value['url'] ) ) { + $value = "url('" . $style_value['url'] . "')"; + } elseif ( is_string( $style_value ) ) { + $value = $style_value; + } + + if ( null !== $value ) { + $css_declarations[ $style_definition['property_keys']['default'] ] = $value; + } + } + + return $css_declarations; +} + // Register the block support. WP_Block_Supports::get_instance()->register( 'background', @@ -109,7 +144,7 @@ function gutenberg_render_background_support( $block_content, $block ) { 'property_keys' => array( 'default' => 'background-image', ), - 'value_func' => array( 'WP_Style_Engine_Gutenberg', 'get_url_or_value_css_declaration' ), + 'value_func' => '_gutenberg_block_supports_get_url_or_value_css_declaration', 'path' => array( 'background', 'backgroundImage' ), ), 'backgroundSize' => array( diff --git a/lib/block-supports/border.php b/lib/block-supports/border.php index 494c229833ce72..5cb6cbd1ef6853 100644 --- a/lib/block-supports/border.php +++ b/lib/block-supports/border.php @@ -154,6 +154,60 @@ function gutenberg_has_border_feature_support( $block_type, $feature, $default_v return block_has_support( $block_type, array( '__experimentalBorder', $feature ), $default_value ); } +/** + * Style value parser that returns a CSS definition array comprising style properties + * that have keys representing individual style properties, otherwise known as longhand CSS properties. + * e.g., "$style_property-$individual_feature: $value;", which could represent the following: + * "border-{top|right|bottom|left}-{color|width|style}: {value};" or, + * "border-image-{outset|source|width|repeat|slice}: {value};" + * + * @param array $style_value A single raw style value from $block_styles array. + * @param array $individual_property_definition A single style definition from static::$block_style_definition_metadata, + * representing an individual property of a CSS property, e.g., 'top' in 'border-top'. + * @param array $options { + * Optional. An array of options. Default empty array. + * + * @type bool $convert_vars_to_classnames Whether to skip converting incoming CSS var patterns, e.g., `var:preset||`, to var( --wp--preset--* ) values. Default `false`. + * } + * + * @return string[] An associative array of CSS definitions, e.g., array( "$property" => "$value", "$property" => "$value" ). + */ +function _gutenberg_block_supports_get_individual_property_css_declarations( $style_value, $individual_property_definition, $options = array() ) { + if ( ! is_array( $style_value ) || empty( $style_value ) || empty( $individual_property_definition['path'] ) ) { + return array(); + } + + /* + * The first item in $individual_property_definition['path'] array tells us the style property, e.g., "border". + * We use this to get a corresponding CSS style definition such as "color" or "width" from the same group. + * The second item in $individual_property_definition['path'] array refers to the individual property marker, e.g., "top". + */ + $definition_group_key = $individual_property_definition['path'][0]; + $individual_property_key = $individual_property_definition['path'][1]; + $should_skip_css_vars = isset( $options['convert_vars_to_classnames'] ) && true === $options['convert_vars_to_classnames']; + $css_declarations = array(); + + foreach ( $style_value as $css_property => $value ) { + if ( empty( $value ) ) { + continue; + } + + // Build a path to the individual rules in definitions. + $style_definition_path = array( $definition_group_key, $css_property ); + $style_definition = _wp_array_get( WP_Style_Engine_Gutenberg::$block_style_definition_metadata, $style_definition_path, null ); + + if ( $style_definition && isset( $style_definition['property_keys']['individual'] ) ) { + // Set a CSS var if there is a valid preset value. + if ( is_string( $value ) && str_contains( $value, 'var:' ) && ! $should_skip_css_vars && ! empty( $individual_property_definition['css_vars'] ) ) { + $value = WP_Style_Engine_Gutenberg::get_css_var_value( $value, $individual_property_definition['css_vars'] ); + } + $individual_css_property = sprintf( $style_definition['property_keys']['individual'], $individual_property_key ); + $css_declarations[ $individual_css_property ] = $value; + } + } + return $css_declarations; +} + // Register the block support. WP_Block_Supports::get_instance()->register( 'border', @@ -199,28 +253,28 @@ function gutenberg_has_border_feature_support( $block_type, $feature, $default_v 'path' => array( 'border', 'width' ), ), 'top' => array( - 'value_func' => array( 'WP_Style_Engine_Gutenberg', 'get_individual_property_css_declarations' ), + 'value_func' => '_gutenberg_block_supports_get_individual_property_css_declarations', 'path' => array( 'border', 'top' ), 'css_vars' => array( 'color' => '--wp--preset--color--$slug', ), ), 'right' => array( - 'value_func' => array( 'WP_Style_Engine_Gutenberg', 'get_individual_property_css_declarations' ), + 'value_func' => '_gutenberg_block_supports_get_individual_property_css_declarations', 'path' => array( 'border', 'right' ), 'css_vars' => array( 'color' => '--wp--preset--color--$slug', ), ), 'bottom' => array( - 'value_func' => array( 'WP_Style_Engine_Gutenberg', 'get_individual_property_css_declarations' ), + 'value_func' => '_gutenberg_block_supports_get_individual_property_css_declarations', 'path' => array( 'border', 'bottom' ), 'css_vars' => array( 'color' => '--wp--preset--color--$slug', ), ), 'left' => array( - 'value_func' => array( 'WP_Style_Engine_Gutenberg', 'get_individual_property_css_declarations' ), + 'value_func' => '_gutenberg_block_supports_get_individual_property_css_declarations', 'path' => array( 'border', 'left' ), 'css_vars' => array( 'color' => '--wp--preset--color--$slug', diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index 517b7473983ee2..69a34f157630f4 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -42,7 +42,7 @@ final class WP_Style_Engine { * * @var array */ - private static $block_style_definition_metadata = array(); + public static $block_style_definition_metadata = array(); /** * Registers a style definition metadata for a defined path. @@ -90,7 +90,7 @@ protected static function get_slug_from_preset_value( $style_value, $property_ke * * @return string The css var, or an empty string if no match for slug found. */ - protected static function get_css_var_value( $style_value, $css_vars ) { + public static function get_css_var_value( $style_value, $css_vars ) { foreach ( $css_vars as $property_key => $css_var_pattern ) { $slug = static::get_slug_from_preset_value( $style_value, $property_key ); if ( static::is_valid_style_value( $slug ) ) { @@ -296,95 +296,6 @@ protected static function get_css_declarations( $style_value, $style_definition, return $css_declarations; } - /** - * Style value parser that returns a CSS definition array comprising style properties - * that have keys representing individual style properties, otherwise known as longhand CSS properties. - * e.g., "$style_property-$individual_feature: $value;", which could represent the following: - * "border-{top|right|bottom|left}-{color|width|style}: {value};" or, - * "border-image-{outset|source|width|repeat|slice}: {value};" - * - * @param array $style_value A single raw style value from $block_styles array. - * @param array $individual_property_definition A single style definition from static::$block_style_definition_metadata, - * representing an individual property of a CSS property, e.g., 'top' in 'border-top'. - * @param array $options { - * Optional. An array of options. Default empty array. - * - * @type bool $convert_vars_to_classnames Whether to skip converting incoming CSS var patterns, e.g., `var:preset||`, to var( --wp--preset--* ) values. Default `false`. - * } - * - * @return string[] An associative array of CSS definitions, e.g., array( "$property" => "$value", "$property" => "$value" ). - */ - protected static function get_individual_property_css_declarations( $style_value, $individual_property_definition, $options = array() ) { - if ( ! is_array( $style_value ) || empty( $style_value ) || empty( $individual_property_definition['path'] ) ) { - return array(); - } - - /* - * The first item in $individual_property_definition['path'] array tells us the style property, e.g., "border". - * We use this to get a corresponding CSS style definition such as "color" or "width" from the same group. - * The second item in $individual_property_definition['path'] array refers to the individual property marker, e.g., "top". - */ - $definition_group_key = $individual_property_definition['path'][0]; - $individual_property_key = $individual_property_definition['path'][1]; - $should_skip_css_vars = isset( $options['convert_vars_to_classnames'] ) && true === $options['convert_vars_to_classnames']; - $css_declarations = array(); - - foreach ( $style_value as $css_property => $value ) { - if ( empty( $value ) ) { - continue; - } - - // Build a path to the individual rules in definitions. - $style_definition_path = array( $definition_group_key, $css_property ); - $style_definition = _wp_array_get( static::$block_style_definition_metadata, $style_definition_path, null ); - - if ( $style_definition && isset( $style_definition['property_keys']['individual'] ) ) { - // Set a CSS var if there is a valid preset value. - if ( is_string( $value ) && str_contains( $value, 'var:' ) && ! $should_skip_css_vars && ! empty( $individual_property_definition['css_vars'] ) ) { - $value = static::get_css_var_value( $value, $individual_property_definition['css_vars'] ); - } - $individual_css_property = sprintf( $style_definition['property_keys']['individual'], $individual_property_key ); - $css_declarations[ $individual_css_property ] = $value; - } - } - return $css_declarations; - } - - /** - * Style value parser that constructs a CSS definition array comprising a single CSS property and value. - * If the provided value is an array containing a `url` property, the function will return a CSS definition array - * with a single property and value, with `url` escaped and injected into a CSS `url()` function, - * e.g., array( 'background-image' => "url( '...' )" ). - * - * @param array $style_value A single raw style value from $block_styles array. - * @param array $style_definition A single style definition from static::$block_style_definition_metadata. - * - * @return string[] An associative array of CSS definitions, e.g., array( "$property" => "$value", "$property" => "$value" ). - */ - protected static function get_url_or_value_css_declaration( $style_value, $style_definition ) { - if ( empty( $style_value ) ) { - return array(); - } - - $css_declarations = array(); - - if ( isset( $style_definition['property_keys']['default'] ) ) { - $value = null; - - if ( ! empty( $style_value['url'] ) ) { - $value = "url('" . $style_value['url'] . "')"; - } elseif ( is_string( $style_value ) ) { - $value = $style_value; - } - - if ( null !== $value ) { - $css_declarations[ $style_definition['property_keys']['default'] ] = $value; - } - } - - return $css_declarations; - } - /** * Returns compiled CSS from css_declarations. * From 41572797eccc8efd61546c7c7d3319dbe239f4e5 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Tue, 26 Sep 2023 09:51:23 +0300 Subject: [PATCH 4/5] Revert "Move methods to their respective block-supports" This reverts commit 42b17dfa7ca895425fceafd55623d8a782a38225. --- lib/block-supports/background.php | 37 +------- lib/block-supports/border.php | 62 +------------ .../style-engine/class-wp-style-engine.php | 93 ++++++++++++++++++- 3 files changed, 96 insertions(+), 96 deletions(-) diff --git a/lib/block-supports/background.php b/lib/block-supports/background.php index 09e7e3e8ad56ea..90fee333f37c64 100644 --- a/lib/block-supports/background.php +++ b/lib/block-supports/background.php @@ -92,41 +92,6 @@ function gutenberg_render_background_support( $block_content, $block ) { return $block_content; } -/** - * Style value parser that constructs a CSS definition array comprising a single CSS property and value. - * If the provided value is an array containing a `url` property, the function will return a CSS definition array - * with a single property and value, with `url` escaped and injected into a CSS `url()` function, - * e.g., array( 'background-image' => "url( '...' )" ). - * - * @param array $style_value A single raw style value from $block_styles array. - * @param array $style_definition A single style definition from static::$block_style_definition_metadata. - * - * @return string[] An associative array of CSS definitions, e.g., array( "$property" => "$value", "$property" => "$value" ). - */ -function _gutenberg_block_supports_get_url_or_value_css_declaration( $style_value, $style_definition ) { - if ( empty( $style_value ) ) { - return array(); - } - - $css_declarations = array(); - - if ( isset( $style_definition['property_keys']['default'] ) ) { - $value = null; - - if ( ! empty( $style_value['url'] ) ) { - $value = "url('" . $style_value['url'] . "')"; - } elseif ( is_string( $style_value ) ) { - $value = $style_value; - } - - if ( null !== $value ) { - $css_declarations[ $style_definition['property_keys']['default'] ] = $value; - } - } - - return $css_declarations; -} - // Register the block support. WP_Block_Supports::get_instance()->register( 'background', @@ -144,7 +109,7 @@ function _gutenberg_block_supports_get_url_or_value_css_declaration( $style_valu 'property_keys' => array( 'default' => 'background-image', ), - 'value_func' => '_gutenberg_block_supports_get_url_or_value_css_declaration', + 'value_func' => array( 'WP_Style_Engine_Gutenberg', 'get_url_or_value_css_declaration' ), 'path' => array( 'background', 'backgroundImage' ), ), 'backgroundSize' => array( diff --git a/lib/block-supports/border.php b/lib/block-supports/border.php index 5cb6cbd1ef6853..494c229833ce72 100644 --- a/lib/block-supports/border.php +++ b/lib/block-supports/border.php @@ -154,60 +154,6 @@ function gutenberg_has_border_feature_support( $block_type, $feature, $default_v return block_has_support( $block_type, array( '__experimentalBorder', $feature ), $default_value ); } -/** - * Style value parser that returns a CSS definition array comprising style properties - * that have keys representing individual style properties, otherwise known as longhand CSS properties. - * e.g., "$style_property-$individual_feature: $value;", which could represent the following: - * "border-{top|right|bottom|left}-{color|width|style}: {value};" or, - * "border-image-{outset|source|width|repeat|slice}: {value};" - * - * @param array $style_value A single raw style value from $block_styles array. - * @param array $individual_property_definition A single style definition from static::$block_style_definition_metadata, - * representing an individual property of a CSS property, e.g., 'top' in 'border-top'. - * @param array $options { - * Optional. An array of options. Default empty array. - * - * @type bool $convert_vars_to_classnames Whether to skip converting incoming CSS var patterns, e.g., `var:preset||`, to var( --wp--preset--* ) values. Default `false`. - * } - * - * @return string[] An associative array of CSS definitions, e.g., array( "$property" => "$value", "$property" => "$value" ). - */ -function _gutenberg_block_supports_get_individual_property_css_declarations( $style_value, $individual_property_definition, $options = array() ) { - if ( ! is_array( $style_value ) || empty( $style_value ) || empty( $individual_property_definition['path'] ) ) { - return array(); - } - - /* - * The first item in $individual_property_definition['path'] array tells us the style property, e.g., "border". - * We use this to get a corresponding CSS style definition such as "color" or "width" from the same group. - * The second item in $individual_property_definition['path'] array refers to the individual property marker, e.g., "top". - */ - $definition_group_key = $individual_property_definition['path'][0]; - $individual_property_key = $individual_property_definition['path'][1]; - $should_skip_css_vars = isset( $options['convert_vars_to_classnames'] ) && true === $options['convert_vars_to_classnames']; - $css_declarations = array(); - - foreach ( $style_value as $css_property => $value ) { - if ( empty( $value ) ) { - continue; - } - - // Build a path to the individual rules in definitions. - $style_definition_path = array( $definition_group_key, $css_property ); - $style_definition = _wp_array_get( WP_Style_Engine_Gutenberg::$block_style_definition_metadata, $style_definition_path, null ); - - if ( $style_definition && isset( $style_definition['property_keys']['individual'] ) ) { - // Set a CSS var if there is a valid preset value. - if ( is_string( $value ) && str_contains( $value, 'var:' ) && ! $should_skip_css_vars && ! empty( $individual_property_definition['css_vars'] ) ) { - $value = WP_Style_Engine_Gutenberg::get_css_var_value( $value, $individual_property_definition['css_vars'] ); - } - $individual_css_property = sprintf( $style_definition['property_keys']['individual'], $individual_property_key ); - $css_declarations[ $individual_css_property ] = $value; - } - } - return $css_declarations; -} - // Register the block support. WP_Block_Supports::get_instance()->register( 'border', @@ -253,28 +199,28 @@ function _gutenberg_block_supports_get_individual_property_css_declarations( $st 'path' => array( 'border', 'width' ), ), 'top' => array( - 'value_func' => '_gutenberg_block_supports_get_individual_property_css_declarations', + 'value_func' => array( 'WP_Style_Engine_Gutenberg', 'get_individual_property_css_declarations' ), 'path' => array( 'border', 'top' ), 'css_vars' => array( 'color' => '--wp--preset--color--$slug', ), ), 'right' => array( - 'value_func' => '_gutenberg_block_supports_get_individual_property_css_declarations', + 'value_func' => array( 'WP_Style_Engine_Gutenberg', 'get_individual_property_css_declarations' ), 'path' => array( 'border', 'right' ), 'css_vars' => array( 'color' => '--wp--preset--color--$slug', ), ), 'bottom' => array( - 'value_func' => '_gutenberg_block_supports_get_individual_property_css_declarations', + 'value_func' => array( 'WP_Style_Engine_Gutenberg', 'get_individual_property_css_declarations' ), 'path' => array( 'border', 'bottom' ), 'css_vars' => array( 'color' => '--wp--preset--color--$slug', ), ), 'left' => array( - 'value_func' => '_gutenberg_block_supports_get_individual_property_css_declarations', + 'value_func' => array( 'WP_Style_Engine_Gutenberg', 'get_individual_property_css_declarations' ), 'path' => array( 'border', 'left' ), 'css_vars' => array( 'color' => '--wp--preset--color--$slug', diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index 69a34f157630f4..517b7473983ee2 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -42,7 +42,7 @@ final class WP_Style_Engine { * * @var array */ - public static $block_style_definition_metadata = array(); + private static $block_style_definition_metadata = array(); /** * Registers a style definition metadata for a defined path. @@ -90,7 +90,7 @@ protected static function get_slug_from_preset_value( $style_value, $property_ke * * @return string The css var, or an empty string if no match for slug found. */ - public static function get_css_var_value( $style_value, $css_vars ) { + protected static function get_css_var_value( $style_value, $css_vars ) { foreach ( $css_vars as $property_key => $css_var_pattern ) { $slug = static::get_slug_from_preset_value( $style_value, $property_key ); if ( static::is_valid_style_value( $slug ) ) { @@ -296,6 +296,95 @@ protected static function get_css_declarations( $style_value, $style_definition, return $css_declarations; } + /** + * Style value parser that returns a CSS definition array comprising style properties + * that have keys representing individual style properties, otherwise known as longhand CSS properties. + * e.g., "$style_property-$individual_feature: $value;", which could represent the following: + * "border-{top|right|bottom|left}-{color|width|style}: {value};" or, + * "border-image-{outset|source|width|repeat|slice}: {value};" + * + * @param array $style_value A single raw style value from $block_styles array. + * @param array $individual_property_definition A single style definition from static::$block_style_definition_metadata, + * representing an individual property of a CSS property, e.g., 'top' in 'border-top'. + * @param array $options { + * Optional. An array of options. Default empty array. + * + * @type bool $convert_vars_to_classnames Whether to skip converting incoming CSS var patterns, e.g., `var:preset||`, to var( --wp--preset--* ) values. Default `false`. + * } + * + * @return string[] An associative array of CSS definitions, e.g., array( "$property" => "$value", "$property" => "$value" ). + */ + protected static function get_individual_property_css_declarations( $style_value, $individual_property_definition, $options = array() ) { + if ( ! is_array( $style_value ) || empty( $style_value ) || empty( $individual_property_definition['path'] ) ) { + return array(); + } + + /* + * The first item in $individual_property_definition['path'] array tells us the style property, e.g., "border". + * We use this to get a corresponding CSS style definition such as "color" or "width" from the same group. + * The second item in $individual_property_definition['path'] array refers to the individual property marker, e.g., "top". + */ + $definition_group_key = $individual_property_definition['path'][0]; + $individual_property_key = $individual_property_definition['path'][1]; + $should_skip_css_vars = isset( $options['convert_vars_to_classnames'] ) && true === $options['convert_vars_to_classnames']; + $css_declarations = array(); + + foreach ( $style_value as $css_property => $value ) { + if ( empty( $value ) ) { + continue; + } + + // Build a path to the individual rules in definitions. + $style_definition_path = array( $definition_group_key, $css_property ); + $style_definition = _wp_array_get( static::$block_style_definition_metadata, $style_definition_path, null ); + + if ( $style_definition && isset( $style_definition['property_keys']['individual'] ) ) { + // Set a CSS var if there is a valid preset value. + if ( is_string( $value ) && str_contains( $value, 'var:' ) && ! $should_skip_css_vars && ! empty( $individual_property_definition['css_vars'] ) ) { + $value = static::get_css_var_value( $value, $individual_property_definition['css_vars'] ); + } + $individual_css_property = sprintf( $style_definition['property_keys']['individual'], $individual_property_key ); + $css_declarations[ $individual_css_property ] = $value; + } + } + return $css_declarations; + } + + /** + * Style value parser that constructs a CSS definition array comprising a single CSS property and value. + * If the provided value is an array containing a `url` property, the function will return a CSS definition array + * with a single property and value, with `url` escaped and injected into a CSS `url()` function, + * e.g., array( 'background-image' => "url( '...' )" ). + * + * @param array $style_value A single raw style value from $block_styles array. + * @param array $style_definition A single style definition from static::$block_style_definition_metadata. + * + * @return string[] An associative array of CSS definitions, e.g., array( "$property" => "$value", "$property" => "$value" ). + */ + protected static function get_url_or_value_css_declaration( $style_value, $style_definition ) { + if ( empty( $style_value ) ) { + return array(); + } + + $css_declarations = array(); + + if ( isset( $style_definition['property_keys']['default'] ) ) { + $value = null; + + if ( ! empty( $style_value['url'] ) ) { + $value = "url('" . $style_value['url'] . "')"; + } elseif ( is_string( $style_value ) ) { + $value = $style_value; + } + + if ( null !== $value ) { + $css_declarations[ $style_definition['property_keys']['default'] ] = $value; + } + } + + return $css_declarations; + } + /** * Returns compiled CSS from css_declarations. * From 8b89b3a24248e6728b8c8eb8ee061a4f5e084bb8 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Tue, 26 Sep 2023 10:34:05 +0300 Subject: [PATCH 5/5] make methods public --- packages/style-engine/class-wp-style-engine.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index 517b7473983ee2..aad62cfd0e4dff 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -314,7 +314,7 @@ protected static function get_css_declarations( $style_value, $style_definition, * * @return string[] An associative array of CSS definitions, e.g., array( "$property" => "$value", "$property" => "$value" ). */ - protected static function get_individual_property_css_declarations( $style_value, $individual_property_definition, $options = array() ) { + public static function get_individual_property_css_declarations( $style_value, $individual_property_definition, $options = array() ) { if ( ! is_array( $style_value ) || empty( $style_value ) || empty( $individual_property_definition['path'] ) ) { return array(); } @@ -361,7 +361,7 @@ protected static function get_individual_property_css_declarations( $style_value * * @return string[] An associative array of CSS definitions, e.g., array( "$property" => "$value", "$property" => "$value" ). */ - protected static function get_url_or_value_css_declaration( $style_value, $style_definition ) { + public static function get_url_or_value_css_declaration( $style_value, $style_definition ) { if ( empty( $style_value ) ) { return array(); }