diff --git a/lib/block-supports/layout.php b/lib/block-supports/layout.php index e239ed023bd62..e6e3663b82318 100644 --- a/lib/block-supports/layout.php +++ b/lib/block-supports/layout.php @@ -30,6 +30,7 @@ function gutenberg_register_layout_support( $block_type ) { * * @param string $selector CSS selector. * @param array $layout Layout object. The one that is passed has already checked the existence of default block layout. + * @param array|null $padding Padding applied to the current block. * @param boolean $has_block_gap_support Whether the theme has support for the block gap. * @param string $gap_value The block gap value to apply. * @param boolean $should_skip_gap_serialization Whether to skip applying the user-defined value set in the editor. @@ -37,7 +38,7 @@ function gutenberg_register_layout_support( $block_type ) { * * @return string CSS style. */ -function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support = false, $gap_value = null, $should_skip_gap_serialization = false, $fallback_gap_value = '0.5em' ) { +function gutenberg_get_layout_style( $selector, $layout, $padding, $has_block_gap_support = false, $gap_value = null, $should_skip_gap_serialization = false, $fallback_gap_value = '0.5em' ) { $layout_type = isset( $layout['type'] ) ? $layout['type'] : 'default'; $style = ''; @@ -54,14 +55,37 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support $wide_max_width_value = wp_strip_all_tags( explode( ';', $wide_max_width_value )[0] ); if ( $content_size || $wide_size ) { - $style = "$selector > :where(:not(.alignleft):not(.alignright)) {"; + // Add a .wp-container-default-layout so this only applies to lower level default layouts, not the top level + $style = ".wp-container-default-layout $selector {"; + // Using important here to override the inline padding that could be potentially + // applied using the custom padding control before the layout inheritance is applied. + $style .= sprintf( + 'padding: %s %s %s %s !important', + isset( $padding['top'] ) ? $padding['top'] : 0, + isset( $padding['right'] ) ? $padding['right'] : 0, + isset( $padding['bottom'] ) ? $padding['bottom'] : 0, + isset( $padding['left'] ) ? $padding['left'] : 0 + ); + $style .= '}'; + $style .= "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull)) {"; $style .= 'max-width: ' . esc_html( $all_max_width_value ) . ';'; $style .= 'margin-left: auto !important;'; $style .= 'margin-right: auto !important;'; $style .= '}'; $style .= "$selector > .alignwide { max-width: " . esc_html( $wide_max_width_value ) . ';}'; - $style .= "$selector .alignfull { max-width: none; }"; + // Add a .wp-container-default-layout so this only applies to lower level default layouts, not the top level// Add a .wp-container-default-layout so this only applies to lower level default layouts, not the top level. + $style .= ".wp-container-default-layout $selector > .alignfull {"; + $style .= 'max-width: none;'; + $style .= isset( $padding['left'] ) ? sprintf( 'margin-left: calc( -1 * %s ) !important;', $padding['left'] ) : ''; + $style .= isset( $padding['right'] ) ? sprintf( 'margin-right: calc( -1 * %s ) !important;', $padding['right'] ) : ''; + $style .= '}'; + + // Add padding to full wide blocks that inherit default layout, so the content doesn't touch the edges. + $style .= "$selector > .alignfull {"; + $style .= isset( $padding['left'] ) ? sprintf( 'padding-left: %s !important;', $padding['left'] ) : ''; + $style .= isset( $padding['right'] ) ? sprintf( 'padding-right: %s !important;', $padding['right'] ) : ''; + $style .= '}'; } $style .= "$selector > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }"; @@ -159,9 +183,12 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { if ( ! $support_layout ) { return $block_content; } - + $class_name = wp_unique_id( 'wp-container-' ); + $selector = '.' . $class_name; $block_gap = gutenberg_get_global_settings( array( 'spacing', 'blockGap' ) ); $default_layout = gutenberg_get_global_settings( array( 'layout' ) ); + $default_padding = gutenberg_get_global_styles( array( 'spacing', 'padding' ) ); + $padding = _wp_array_get( $block, array( 'attrs', 'style', 'spacing', 'padding' ), null ); $has_block_gap_support = isset( $block_gap ) ? null !== $block_gap : false; $default_block_layout = _wp_array_get( $block_type->supports, array( '__experimentalLayout', 'default' ), array() ); $used_layout = isset( $block['attrs']['layout'] ) ? $block['attrs']['layout'] : $default_block_layout; @@ -169,12 +196,15 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { if ( ! $default_layout ) { return $block_content; } - $used_layout = $default_layout; + $class_name .= ' wp-container-default-layout'; + $selector .= '.wp-container-default-layout'; + $used_layout = $default_layout; + //TODO - can we allow padding from the block settings? + $padding = isset( $default_padding ) ? $default_padding : null; } $class_names = array(); - $container_class = wp_unique_id( 'wp-container-' ); - $class_names[] = $container_class; + $class_names[] = $class_name; // The following section was added to reintroduce a small set of layout classnames that were // removed in the 5.9 release (https://github.com/WordPress/gutenberg/issues/38719). It is @@ -193,6 +223,7 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { } $gap_value = _wp_array_get( $block, array( 'attrs', 'style', 'spacing', 'blockGap' ) ); + // Skip if gap value contains unsupported characters. // Regex for CSS value borrowed from `safecss_filter_attr`, and used here // because we only want to match against the value, not the CSS attribute. @@ -209,7 +240,7 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { // If a block's block.json skips serialization for spacing or spacing.blockGap, // don't apply the user-defined value to the styles. $should_skip_gap_serialization = gutenberg_should_skip_block_supports_serialization( $block_type, 'spacing', 'blockGap' ); - $style = gutenberg_get_layout_style( ".$container_class", $used_layout, $has_block_gap_support, $gap_value, $should_skip_gap_serialization, $fallback_gap_value ); + $style = gutenberg_get_layout_style( $selector, $used_layout, $padding, $has_block_gap_support, $gap_value, $should_skip_gap_serialization, $fallback_gap_value ); // This assumes the hook only applies to blocks with a single wrapper. // I think this is a reasonable limitation for that particular hook. $content = preg_replace( diff --git a/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php b/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php index 77d731b9d4544..73c204513faee 100644 --- a/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php +++ b/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php @@ -22,49 +22,54 @@ class WP_Theme_JSON_6_0 extends WP_Theme_JSON_5_9 { * path to the value in theme.json & block attributes. */ const PROPERTIES_METADATA = array( - 'background' => array( 'color', 'gradient' ), - 'background-color' => array( 'color', 'background' ), - 'border-radius' => array( 'border', 'radius' ), - 'border-top-left-radius' => array( 'border', 'radius', 'topLeft' ), - 'border-top-right-radius' => array( 'border', 'radius', 'topRight' ), - 'border-bottom-left-radius' => array( 'border', 'radius', 'bottomLeft' ), - 'border-bottom-right-radius' => array( 'border', 'radius', 'bottomRight' ), - 'border-color' => array( 'border', 'color' ), - 'border-width' => array( 'border', 'width' ), - 'border-style' => array( 'border', 'style' ), - 'border-top-color' => array( 'border', 'top', 'color' ), - 'border-top-width' => array( 'border', 'top', 'width' ), - 'border-top-style' => array( 'border', 'top', 'style' ), - 'border-right-color' => array( 'border', 'right', 'color' ), - 'border-right-width' => array( 'border', 'right', 'width' ), - 'border-right-style' => array( 'border', 'right', 'style' ), - 'border-bottom-color' => array( 'border', 'bottom', 'color' ), - 'border-bottom-width' => array( 'border', 'bottom', 'width' ), - 'border-bottom-style' => array( 'border', 'bottom', 'style' ), - 'border-left-color' => array( 'border', 'left', 'color' ), - 'border-left-width' => array( 'border', 'left', 'width' ), - 'border-left-style' => array( 'border', 'left', 'style' ), - 'color' => array( 'color', 'text' ), - 'font-family' => array( 'typography', 'fontFamily' ), - 'font-size' => array( 'typography', 'fontSize' ), - 'font-style' => array( 'typography', 'fontStyle' ), - 'font-weight' => array( 'typography', 'fontWeight' ), - 'letter-spacing' => array( 'typography', 'letterSpacing' ), - 'line-height' => array( 'typography', 'lineHeight' ), - 'margin' => array( 'spacing', 'margin' ), - 'margin-top' => array( 'spacing', 'margin', 'top' ), - 'margin-right' => array( 'spacing', 'margin', 'right' ), - 'margin-bottom' => array( 'spacing', 'margin', 'bottom' ), - 'margin-left' => array( 'spacing', 'margin', 'left' ), - 'padding' => array( 'spacing', 'padding' ), - 'padding-top' => array( 'spacing', 'padding', 'top' ), - 'padding-right' => array( 'spacing', 'padding', 'right' ), - 'padding-bottom' => array( 'spacing', 'padding', 'bottom' ), - 'padding-left' => array( 'spacing', 'padding', 'left' ), - '--wp--style--block-gap' => array( 'spacing', 'blockGap' ), - 'text-decoration' => array( 'typography', 'textDecoration' ), - 'text-transform' => array( 'typography', 'textTransform' ), - 'filter' => array( 'filter', 'duotone' ), + 'background' => array( 'color', 'gradient' ), + 'background-color' => array( 'color', 'background' ), + 'border-radius' => array( 'border', 'radius' ), + 'border-top-left-radius' => array( 'border', 'radius', 'topLeft' ), + 'border-top-right-radius' => array( 'border', 'radius', 'topRight' ), + 'border-bottom-left-radius' => array( 'border', 'radius', 'bottomLeft' ), + 'border-bottom-right-radius' => array( 'border', 'radius', 'bottomRight' ), + 'border-color' => array( 'border', 'color' ), + 'border-width' => array( 'border', 'width' ), + 'border-style' => array( 'border', 'style' ), + 'border-top-color' => array( 'border', 'top', 'color' ), + 'border-top-width' => array( 'border', 'top', 'width' ), + 'border-top-style' => array( 'border', 'top', 'style' ), + 'border-right-color' => array( 'border', 'right', 'color' ), + 'border-right-width' => array( 'border', 'right', 'width' ), + 'border-right-style' => array( 'border', 'right', 'style' ), + 'border-bottom-color' => array( 'border', 'bottom', 'color' ), + 'border-bottom-width' => array( 'border', 'bottom', 'width' ), + 'border-bottom-style' => array( 'border', 'bottom', 'style' ), + 'border-left-color' => array( 'border', 'left', 'color' ), + 'border-left-width' => array( 'border', 'left', 'width' ), + 'border-left-style' => array( 'border', 'left', 'style' ), + 'color' => array( 'color', 'text' ), + 'font-family' => array( 'typography', 'fontFamily' ), + 'font-size' => array( 'typography', 'fontSize' ), + 'font-style' => array( 'typography', 'fontStyle' ), + 'font-weight' => array( 'typography', 'fontWeight' ), + 'letter-spacing' => array( 'typography', 'letterSpacing' ), + 'line-height' => array( 'typography', 'lineHeight' ), + 'margin' => array( 'spacing', 'margin' ), + 'margin-top' => array( 'spacing', 'margin', 'top' ), + 'margin-right' => array( 'spacing', 'margin', 'right' ), + 'margin-bottom' => array( 'spacing', 'margin', 'bottom' ), + 'margin-left' => array( 'spacing', 'margin', 'left' ), + 'padding' => array( 'spacing', 'padding' ), + 'padding-top' => array( 'spacing', 'padding', 'top' ), + 'padding-right' => array( 'spacing', 'padding', 'right' ), + 'padding-bottom' => array( 'spacing', 'padding', 'bottom' ), + 'padding-left' => array( 'spacing', 'padding', 'left' ), + '--wp--style--root--padding' => array( 'spacing', 'padding' ), + '--wp--style--root--padding-top' => array( 'spacing', 'padding', 'top' ), + '--wp--style--root--padding-right' => array( 'spacing', 'padding', 'right' ), + '--wp--style--root--padding-bottom' => array( 'spacing', 'padding', 'bottom' ), + '--wp--style--root--padding-left' => array( 'spacing', 'padding', 'left' ), + '--wp--style--block-gap' => array( 'spacing', 'blockGap' ), + 'text-decoration' => array( 'typography', 'textDecoration' ), + 'text-transform' => array( 'typography', 'textTransform' ), + 'filter' => array( 'filter', 'duotone' ), ); /** @@ -202,14 +207,15 @@ class WP_Theme_JSON_6_0 extends WP_Theme_JSON_5_9 { * @var array */ const VALID_SETTINGS = array( - 'appearanceTools' => null, - 'border' => array( + 'appearanceTools' => null, + 'useRootVariables' => null, + 'border' => array( 'color' => null, 'radius' => null, 'style' => null, 'width' => null, ), - 'color' => array( + 'color' => array( 'background' => null, 'custom' => null, 'customDuotone' => null, @@ -223,18 +229,19 @@ class WP_Theme_JSON_6_0 extends WP_Theme_JSON_5_9 { 'palette' => null, 'text' => null, ), - 'custom' => null, - 'layout' => array( + 'custom' => null, + 'layout' => array( 'contentSize' => null, 'wideSize' => null, + 'padding' => null, ), - 'spacing' => array( + 'spacing' => array( 'blockGap' => null, 'margin' => null, 'padding' => null, 'units' => null, ), - 'typography' => array( + 'typography' => array( 'customFontSize' => null, 'dropCap' => null, 'fontFamilies' => null, @@ -325,10 +332,11 @@ protected function get_block_classes( $style_nodes ) { continue; } - $node = _wp_array_get( $this->theme_json, $metadata['path'], array() ); - $selector = $metadata['selector']; - $settings = _wp_array_get( $this->theme_json, array( 'settings' ) ); - $declarations = static::compute_style_properties( $node, $settings ); + $use_root_vars = _wp_array_get( $this->theme_json, array( 'settings', 'useRootVariables' ), array() ); + $node = _wp_array_get( $this->theme_json, $metadata['path'], array() ); + $selector = $metadata['selector']; + $settings = _wp_array_get( $this->theme_json, array( 'settings' ) ); + $declarations = static::compute_style_properties( $node, $settings, null, $selector, $use_root_vars ); // 1. Separate the ones who use the general selector // and the ones who use the duotone selector. @@ -362,6 +370,18 @@ protected function get_block_classes( $style_nodes ) { } if ( static::ROOT_BLOCK_SELECTOR === $selector ) { + if ( $use_root_vars ) { + $block_rules .= '.wp-site-blocks { padding-top: var(--wp--style--root--padding-top); padding-bottom: var(--wp--style--root--padding-bottom); }'; + $block_rules .= '.wp-site-blocks > * { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }'; + + // This will be overridden by children who inherit default layout. + $block_rules .= '.wp-site-blocks .alignfull { margin-right: calc(var(--wp--style--root--padding-right) * -1); margin-left: calc(var(--wp--style--root--padding-left) * -1); width: auto;}'; + + // Alignfull blocks in the block editor that are direct children of post content should also get negative margins. + if ( is_callable( 'get_current_screen' ) && get_current_screen()->is_block_editor() ) { + $block_rules .= '.is-root-container .alignfull { margin-right: calc(var(--wp--style--root--padding-right) * -1); margin-left: calc(var(--wp--style--root--padding-left) * -1); width: auto; }'; + } + } $block_rules .= '.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }'; $block_rules .= '.wp-site-blocks > .alignright { float: right; margin-left: 2em; }'; $block_rules .= '.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; @@ -529,6 +549,143 @@ protected static function get_metadata_boolean( $data, $path, $default = false ) return $default; } + /** + * Given a styles array, it extracts the style properties + * and adds them to the $declarations array following the format: + * + * ```php + * array( + * 'name' => 'property_name', + * 'value' => 'property_value, + * ) + * ``` + * + * @param array $styles Styles to process. + * @param array $settings Theme settings. + * @param array $properties Properties metadata. + * @param string $selector Selector for styles. + * @param boolean $use_root_vars Whether to use root variables. + * @return array Returns the modified $declarations. + */ + protected static function compute_style_properties( $styles, $settings = array(), $properties = null, $selector = null, $use_root_vars = null ) { + if ( null === $properties ) { + $properties = static::PROPERTIES_METADATA; + } + + $declarations = array(); + $root_variable_duplicates = array(); + + if ( empty( $styles ) ) { + return $declarations; + } + + foreach ( $properties as $css_property => $value_path ) { + $value = static::get_property_value( $styles, $value_path ); + + if ( strpos( $css_property, '--wp--style--root--' ) === 0 && static::ROOT_BLOCK_SELECTOR !== $selector ) { + continue; + } + + if ( strpos( $css_property, '--wp--style--root--' ) === 0 && $use_root_vars ) { + $root_variable_duplicates[] = substr( $css_property, strlen( '--wp--style--root--' ) ); + } + + // Root padding requires special logic to split shorthand values. + if ( '--wp--style--root--padding' === $css_property && is_string( $value ) ) { + + $shorthand_top = '0'; + $shorthand_right = '0'; + $shorthand_bottom = '0'; + $shorthand_left = '0'; + + $separate_values = explode( ' ', $value ); + + switch ( count( $separate_values ) ) { + case 1: + $shorthand_top = $separate_values[0]; + $shorthand_right = $separate_values[0]; + $shorthand_bottom = $separate_values[0]; + $shorthand_left = $separate_values[0]; + break; + case 2: + $shorthand_top = $separate_values[0]; + $shorthand_right = $separate_values[1]; + $shorthand_bottom = $separate_values[0]; + $shorthand_left = $separate_values[1]; + break; + case 3: + $shorthand_top = $separate_values[0]; + $shorthand_right = $separate_values[1]; + $shorthand_bottom = $separate_values[2]; + $shorthand_left = $separate_values[1]; + break; + case 4: + $shorthand_top = $separate_values[0]; + $shorthand_right = $separate_values[1]; + $shorthand_bottom = $separate_values[2]; + $shorthand_left = $separate_values[3]; + break; + } + + $all_properties = array( + array( + 'name' => '--wp--style--root--padding-top', + 'value' => $shorthand_top, + ), + array( + 'name' => '--wp--style--root--padding-right', + 'value' => $shorthand_right, + ), + array( + 'name' => '--wp--style--root--padding-bottom', + 'value' => $shorthand_bottom, + ), + array( + 'name' => '--wp--style--root--padding-left', + 'value' => $shorthand_left, + ), + ); + + $declarations = array_merge( $declarations, $all_properties ); + + continue; + } + + // Look up protected properties, keyed by value path. + // Skip protected properties that are explicitly set to `null`. + if ( is_array( $value_path ) ) { + $path_string = implode( '.', $value_path ); + if ( + array_key_exists( $path_string, static::PROTECTED_PROPERTIES ) && + _wp_array_get( $settings, static::PROTECTED_PROPERTIES[ $path_string ], null ) === null + ) { + continue; + } + } + + // Skip if empty and not "0" or value represents array of longhand values. + $has_missing_value = empty( $value ) && ! is_numeric( $value ); + if ( $has_missing_value || is_array( $value ) ) { + continue; + } + + $declarations[] = array( + 'name' => $css_property, + 'value' => $value, + ); + } + + // If a variable value is added to the root, the corresponding property should be removed. + foreach ( $root_variable_duplicates as $duplicate ) { + $discard = array_search( $duplicate, array_column( $declarations, 'name' ), true ); + if ( $discard ) { + array_splice( $declarations, $discard, 1 ); + } + } + + return $declarations; + } + /** * Returns a valid theme.json as provided by a theme. * diff --git a/lib/compat/wordpress-6.0/class-wp-theme-json-resolver-6-0.php b/lib/compat/wordpress-6.0/class-wp-theme-json-resolver-6-0.php index cc6aa688493de..11c20951d7faf 100644 --- a/lib/compat/wordpress-6.0/class-wp-theme-json-resolver-6-0.php +++ b/lib/compat/wordpress-6.0/class-wp-theme-json-resolver-6-0.php @@ -16,6 +16,7 @@ * @access private */ class WP_Theme_JSON_Resolver_6_0 extends WP_Theme_JSON_Resolver_5_9 { + /** * Given a theme.json structure modifies it in place * to update certain values by its translated strings diff --git a/lib/compat/wordpress-6.0/theme.json b/lib/compat/wordpress-6.0/theme.json index 7691aa4a64e6a..631201a70063c 100644 --- a/lib/compat/wordpress-6.0/theme.json +++ b/lib/compat/wordpress-6.0/theme.json @@ -2,6 +2,7 @@ "version": 2, "settings": { "appearanceTools": false, + "useRootVariables": false, "border": { "color": false, "radius": false, @@ -240,6 +241,14 @@ } }, "styles": { - "spacing": { "blockGap": "24px" } + "spacing": { + "blockGap": "24px", + "padding": { + "top": "var(--wp--style--block-gap)", + "right": "var(--wp--style--block-gap)", + "bottom": "var(--wp--style--block-gap)", + "left": "var(--wp--style--block-gap)" + } + } } } diff --git a/lib/compat/wordpress-6.1/class-wp-theme-json-6-1.php b/lib/compat/wordpress-6.1/class-wp-theme-json-6-1.php index d093480e924e4..1ceebf837b183 100644 --- a/lib/compat/wordpress-6.1/class-wp-theme-json-6-1.php +++ b/lib/compat/wordpress-6.1/class-wp-theme-json-6-1.php @@ -486,6 +486,12 @@ public function get_styles_for_block( $block_metadata ) { $block_rules = ''; + $use_root_vars = _wp_array_get( $this->theme_json, array( 'settings', 'useRootVariables' ), array() ); + $node = _wp_array_get( $this->theme_json, $block_metadata['path'], array() ); + $selector = $block_metadata['selector']; + $settings = _wp_array_get( $this->theme_json, array( 'settings' ) ); + $declarations = static::compute_style_properties( $node, $settings, null, null, $selector, $use_root_vars ); + // 1. Separate the ones who use the general selector // and the ones who use the duotone selector. $declarations_duotone = array(); @@ -518,6 +524,19 @@ public function get_styles_for_block( $block_metadata ) { } if ( static::ROOT_BLOCK_SELECTOR === $selector ) { + if ( $use_root_vars ) { + $block_rules .= '.wp-site-blocks { padding-top: var(--wp--style--root--padding-top); padding-bottom: var(--wp--style--root--padding-bottom); }'; + $block_rules .= '.wp-site-blocks > * { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }'; + + // This will be overridden by children who inherit default layout. + $block_rules .= '.wp-site-blocks .alignfull { margin-right: calc(var(--wp--style--root--padding-right) * -1); margin-left: calc(var(--wp--style--root--padding-left) * -1); width: auto;}'; + + // Alignfull blocks in the block editor that are direct children of post content should also get negative margins. + if ( is_callable( 'get_current_screen' ) && get_current_screen()->is_block_editor() ) { + $block_rules .= '.is-root-container .alignfull { margin-right: calc(var(--wp--style--root--padding-right) * -1); margin-left: calc(var(--wp--style--root--padding-left) * -1); width: auto; }'; + } + } + $block_rules .= '.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }'; $block_rules .= '.wp-site-blocks > .alignright { float: right; margin-left: 2em; }'; $block_rules .= '.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; @@ -571,18 +590,21 @@ protected function get_block_classes( $style_nodes ) { * ) * ``` * - * @param array $styles Styles to process. - * @param array $settings Theme settings. - * @param array $properties Properties metadata. - * @param array $theme_json Theme JSON array. - * @return array Returns the modified $declarations. + * @param array $styles Styles to process. + * @param array $settings Theme settings. + * @param array $properties Properties metadata. + * @param array $theme_json Theme JSON array. + * @param string $selector Selector for styles. + * @param boolean $use_root_vars Whether to use root. + * @return array Returns the modified $declarations. */ - protected static function compute_style_properties( $styles, $settings = array(), $properties = null, $theme_json = null ) { + protected static function compute_style_properties( $styles, $settings = array(), $properties = null, $theme_json = null, $selector = null, $use_root_vars = null ) { if ( null === $properties ) { $properties = static::PROPERTIES_METADATA; } - $declarations = array(); + $declarations = array(); + $root_variable_duplicates = array(); if ( empty( $styles ) ) { return $declarations; } @@ -590,6 +612,75 @@ protected static function compute_style_properties( $styles, $settings = array() foreach ( $properties as $css_property => $value_path ) { $value = static::get_property_value( $styles, $value_path, $theme_json ); + if ( strpos( $css_property, '--wp--style--root--' ) === 0 && static::ROOT_BLOCK_SELECTOR !== $selector ) { + continue; + } + + if ( strpos( $css_property, '--wp--style--root--' ) === 0 && $use_root_vars ) { + $root_variable_duplicates[] = substr( $css_property, strlen( '--wp--style--root--' ) ); + } + + // Root padding requires special logic to split shorthand values. + if ( '--wp--style--root--padding' === $css_property && is_string( $value ) ) { + + $shorthand_top = '0'; + $shorthand_right = '0'; + $shorthand_bottom = '0'; + $shorthand_left = '0'; + + $separate_values = explode( ' ', $value ); + + switch ( count( $separate_values ) ) { + case 1: + $shorthand_top = $separate_values[0]; + $shorthand_right = $separate_values[0]; + $shorthand_bottom = $separate_values[0]; + $shorthand_left = $separate_values[0]; + break; + case 2: + $shorthand_top = $separate_values[0]; + $shorthand_right = $separate_values[1]; + $shorthand_bottom = $separate_values[0]; + $shorthand_left = $separate_values[1]; + break; + case 3: + $shorthand_top = $separate_values[0]; + $shorthand_right = $separate_values[1]; + $shorthand_bottom = $separate_values[2]; + $shorthand_left = $separate_values[1]; + break; + case 4: + $shorthand_top = $separate_values[0]; + $shorthand_right = $separate_values[1]; + $shorthand_bottom = $separate_values[2]; + $shorthand_left = $separate_values[3]; + break; + } + + $all_properties = array( + array( + 'name' => '--wp--style--root--padding-top', + 'value' => $shorthand_top, + ), + array( + 'name' => '--wp--style--root--padding-right', + 'value' => $shorthand_right, + ), + array( + 'name' => '--wp--style--root--padding-bottom', + 'value' => $shorthand_bottom, + ), + array( + 'name' => '--wp--style--root--padding-left', + 'value' => $shorthand_left, + ), + ); + + $declarations = array_merge( $declarations, $all_properties ); + + continue; + } + // Look up protected properties, keyed by value path. // Skip protected properties that are explicitly set to `null`. if ( is_array( $value_path ) ) { @@ -614,6 +705,14 @@ protected static function compute_style_properties( $styles, $settings = array() ); } + // If a variable value is added to the root, the corresponding property should be removed. + foreach ( $root_variable_duplicates as $duplicate ) { + $discard = array_search( $duplicate, array_column( $declarations, 'name' ), true ); + if ( $discard ) { + array_splice( $declarations, $discard, 1 ); + } + } + return $declarations; } diff --git a/packages/block-editor/src/components/block-list/style.scss b/packages/block-editor/src/components/block-list/style.scss index 7b78148328aec..51156e4b3af90 100644 --- a/packages/block-editor/src/components/block-list/style.scss +++ b/packages/block-editor/src/components/block-list/style.scss @@ -308,6 +308,22 @@ } } +// Active entity spotlight. +// Disable if focus mode is active. +.is-root-container:not(.is-focus-mode) .block-editor-block-list__block.has-active-entity { + opacity: 0.5; + transition: opacity 0.1s linear; + @include reduce-motion("transition"); + + &.is-active-entity, + &.has-child-selected, + &:not(.has-child-selected) .block-editor-block-list__block, + &.is-active-entity .block-editor-block-list__block, + .is-active-entity .block-editor-block-list__block { + opacity: 1; + } +} + .wp-block[data-align="left"] > *, .wp-block[data-align="right"] > *, .wp-block.alignleft, diff --git a/packages/block-editor/src/hooks/layout.js b/packages/block-editor/src/hooks/layout.js index c5072200869ed..eeb01a45f5b51 100644 --- a/packages/block-editor/src/hooks/layout.js +++ b/packages/block-editor/src/hooks/layout.js @@ -2,7 +2,7 @@ * External dependencies */ import classnames from 'classnames'; -import { has, kebabCase } from 'lodash'; +import { has, get, kebabCase } from 'lodash'; /** * WordPress dependencies @@ -77,23 +77,14 @@ function getLayoutClasses( attributes ) { function LayoutPanel( { setAttributes, attributes, name: blockName } ) { const { layout } = attributes; - const defaultThemeLayout = useSetting( 'layout' ); - const themeSupportsLayout = useSelect( ( select ) => { - const { getSettings } = select( blockEditorStore ); - return getSettings().supportsLayout; - }, [] ); - const layoutBlockSupport = getBlockSupport( - blockName, - layoutBlockSupportKey, - {} - ); + const { supportsFlowLayout, config } = useLayout( blockName ); const { allowSwitching, allowEditing = true, allowInheriting = true, default: defaultBlockLayout, - } = layoutBlockSupport; + } = config; if ( ! allowEditing ) { return null; @@ -104,18 +95,14 @@ function LayoutPanel( { setAttributes, attributes, name: blockName } ) { // and that the default / flow layout type is in use, as this is the only one that supports inheritance. const showInheritToggle = !! ( allowInheriting && - !! defaultThemeLayout && + !! supportsFlowLayout && ( ! layout?.type || layout?.type === 'default' || layout?.inherit ) ); const usedLayout = layout || defaultBlockLayout || {}; const { inherit = false, type = 'default' } = usedLayout; - /** - * `themeSupportsLayout` is only relevant to the `default/flow` - * layout and it should not be taken into account when other - * `layout` types are used. - */ - if ( type === 'default' && ! themeSupportsLayout ) { + + if ( type === 'default' && ! supportsFlowLayout ) { return null; } const layoutType = getLayoutType( type ); @@ -163,7 +150,7 @@ function LayoutPanel( { setAttributes, attributes, name: blockName } ) { ) } @@ -172,7 +159,7 @@ function LayoutPanel( { setAttributes, attributes, name: blockName } ) { ) } @@ -197,6 +184,26 @@ function LayoutTypeSwitcher( { type, onChange } ) { ); } +export function useLayout( blockName ) { + const defaultThemeLayout = useSetting( 'layout' ); + const themeSupportsLayout = useSelect( ( select ) => { + const { getSettings } = select( blockEditorStore ); + return getSettings().supportsLayout; + }, [] ); + + const layoutBlockSupport = getBlockSupport( + blockName, + layoutBlockSupportKey, + {} + ); + + return { + supportsFlowLayout: themeSupportsLayout, + defaultLayout: defaultThemeLayout, + config: layoutBlockSupport, + }; +} + /** * Filters registered block settings, extending attributes to include `layout`. * @@ -276,6 +283,9 @@ export const withLayoutStyles = createHigherOrderComponent( }, layoutClasses ); + const padding = layout?.inherit + ? usedLayout?.padding + : get( attributes, [ 'style', 'spacing', 'padding' ] ); return ( <> @@ -286,6 +296,7 @@ export const withLayoutStyles = createHigherOrderComponent( blockName={ name } selector={ `.wp-container-${ id }` } layout={ usedLayout } + padding={ padding } style={ attributes?.style } />, element diff --git a/packages/block-editor/src/hooks/padding.js b/packages/block-editor/src/hooks/padding.js index 02a371db0d6a3..495ea70570e59 100644 --- a/packages/block-editor/src/hooks/padding.js +++ b/packages/block-editor/src/hooks/padding.js @@ -28,6 +28,7 @@ import { } from './dimensions'; import { cleanEmptyObject } from './utils'; import BlockPopover from '../components/block-popover'; +import { useLayout } from './layout'; /** * Determines if there is padding support. @@ -80,11 +81,19 @@ export function resetPadding( { attributes = {}, setAttributes } ) { * * @return {boolean} Whether padding setting is disabled. */ -export function useIsPaddingDisabled( { name: blockName } = {} ) { +export function useIsPaddingDisabled( { name: blockName, attributes } = {} ) { + const { supportsFlowLayout, config } = useLayout( blockName ); + const hasInheritedLayout = + supportsFlowLayout && !! config && attributes?.layout?.inherit; const isDisabled = ! useSetting( 'spacing.padding' ); const isInvalid = ! useIsDimensionsSupportValid( blockName, 'padding' ); - return ! hasPaddingSupport( blockName ) || isDisabled || isInvalid; + return ( + ! hasPaddingSupport( blockName ) || + hasInheritedLayout || + isDisabled || + isInvalid + ); } /** diff --git a/packages/block-editor/src/hooks/style.js b/packages/block-editor/src/hooks/style.js index 400ebd0a84263..fd4c4fdc8b9fa 100644 --- a/packages/block-editor/src/hooks/style.js +++ b/packages/block-editor/src/hooks/style.js @@ -68,6 +68,9 @@ export function getInlineStyles( styles = {} ) { const ignoredStyles = [ 'spacing.blockGap' ]; const output = {}; Object.keys( STYLE_PROPERTY ).forEach( ( propKey ) => { + if ( STYLE_PROPERTY[ propKey ].rootOnly ) { + return; + } const path = STYLE_PROPERTY[ propKey ].value; const subPaths = STYLE_PROPERTY[ propKey ].properties; // Ignore styles on elements because they are handled on the server. diff --git a/packages/block-editor/src/layouts/flow.js b/packages/block-editor/src/layouts/flow.js index 82851cb015075..4c263ea4daf21 100644 --- a/packages/block-editor/src/layouts/flow.js +++ b/packages/block-editor/src/layouts/flow.js @@ -112,6 +112,7 @@ export default { layout = {}, style, blockName, + padding, } ) { const { contentSize, wideSize } = layout; const blockGapSupport = useSetting( 'spacing.blockGap' ); @@ -126,13 +127,20 @@ export default { ! shouldSkipSerialization( blockName, 'spacing', 'blockGap' ) ? blockGapStyleValue?.top : 'var( --wp--style--block-gap )'; + // Using important here for the padding to override the inline padding that could be potentially + // applied using the custom padding control before the layout inheritance is applied. let output = !! contentSize || !! wideSize ? ` + ${ appendSelectors( selector ) } { + padding: ${ padding?.top || 0 } ${ padding?.right || 0 } ${ + padding?.bottom || 0 + } ${ padding?.left || 0 } !important; + } ${ appendSelectors( selector, - '> :where(:not(.alignleft):not(.alignright))' + '> :where(:not(.alignleft):not(.alignright):not(.alignfull))' ) } { max-width: ${ contentSize ?? wideSize }; margin-left: auto !important; @@ -143,6 +151,16 @@ export default { } ${ appendSelectors( selector, '> .alignfull' ) } { max-width: none; + ${ + padding?.left + ? `margin-left: calc( -1 * ${ padding?.left } ) !important;` + : '' + } + ${ + padding?.right + ? `margin-right: calc( -1 * ${ padding?.right } ) !important;` + : '' + } } ` : ''; diff --git a/packages/blocks/src/api/constants.js b/packages/blocks/src/api/constants.js index b7e9d11524ac7..ee2e1f8a0d8cb 100644 --- a/packages/blocks/src/api/constants.js +++ b/packages/blocks/src/api/constants.js @@ -203,6 +203,17 @@ export const __EXPERIMENTAL_STYLE_PROPERTY = { value: [ 'spacing', 'blockGap' ], support: [ 'spacing', 'blockGap' ], }, + '--wp--style--root--padding': { + value: [ 'spacing', 'padding' ], + support: [ 'spacing', 'padding' ], + properties: { + '--wp--style--root--padding-top': 'top', + '--wp--style--root--padding-right': 'right', + '--wp--style--root--padding-bottom': 'bottom', + '--wp--style--root--padding-left': 'left', + }, + rootOnly: true, + }, }; export const __EXPERIMENTAL_ELEMENTS = { diff --git a/packages/edit-post/src/components/visual-editor/index.js b/packages/edit-post/src/components/visual-editor/index.js index b5a2b0a4a4b97..a0ef01533a92e 100644 --- a/packages/edit-post/src/components/visual-editor/index.js +++ b/packages/edit-post/src/components/visual-editor/index.js @@ -198,6 +198,14 @@ export default function VisualEditor( { styles } ) { titleRef?.current?.focus(); }, [ isWelcomeGuideVisible, isCleanNewPost ] ); + const padding = useMemo( () => { + if ( isTemplateMode || ! themeSupportsLayout ) { + return undefined; + } + + return defaultLayout?.padding; + } ); + return ( ) } { ! isTemplateMode && ( diff --git a/packages/edit-site/src/components/global-styles/test/use-global-styles-output.js b/packages/edit-site/src/components/global-styles/test/use-global-styles-output.js index 10e1d533e025b..1ea6261e6d3d1 100644 --- a/packages/edit-site/src/components/global-styles/test/use-global-styles-output.js +++ b/packages/edit-site/src/components/global-styles/test/use-global-styles-output.js @@ -443,10 +443,7 @@ describe( 'global styles renderer', () => { }; expect( toStyles( tree, blockSelectors ) ).toEqual( - 'body {margin: 0;}' + - 'body{background-color: red;margin: 10px;padding: 10px;}h1{font-size: 42px;}a{color: blue;}a:hover{color: orange;}a:focus{color: orange;}.wp-block-group{margin-top: 10px;margin-right: 20px;margin-bottom: 30px;margin-left: 40px;padding-top: 11px;padding-right: 22px;padding-bottom: 33px;padding-left: 44px;}h1,h2,h3,h4,h5,h6{color: orange;}h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{color: hotpink;}h1 a:hover,h2 a:hover,h3 a:hover,h4 a:hover,h5 a:hover,h6 a:hover{color: red;}h1 a:focus,h2 a:focus,h3 a:focus,h4 a:focus,h5 a:focus,h6 a:focus{color: red;}' + - '.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }' + - '.has-white-color{color: var(--wp--preset--color--white) !important;}.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}.has-black-color{color: var(--wp--preset--color--black) !important;}.has-black-background-color{background-color: var(--wp--preset--color--black) !important;}.has-black-border-color{border-color: var(--wp--preset--color--black) !important;}h1.has-blue-color,h2.has-blue-color,h3.has-blue-color,h4.has-blue-color,h5.has-blue-color,h6.has-blue-color{color: var(--wp--preset--color--blue) !important;}h1.has-blue-background-color,h2.has-blue-background-color,h3.has-blue-background-color,h4.has-blue-background-color,h5.has-blue-background-color,h6.has-blue-background-color{background-color: var(--wp--preset--color--blue) !important;}h1.has-blue-border-color,h2.has-blue-border-color,h3.has-blue-border-color,h4.has-blue-border-color,h5.has-blue-border-color,h6.has-blue-border-color{border-color: var(--wp--preset--color--blue) !important;}' + '.wp-site-blocks > * { margin-top: 0; margin-bottom: 0; }.wp-site-blocks > * + * { margin-top: var( --wp--style--block-gap ); }body{background-color: red;--wp--style--root--padding-top: 10px;--wp--style--root--padding-right: 10px;--wp--style--root--padding-bottom: 10px;--wp--style--root--padding-left: 10px;margin: 10px;padding: 10px;}h1{font-size: 42px;}.wp-block-group{margin-top: 10px;margin-right: 20px;margin-bottom: 30px;margin-left: 40px;padding-top: 11px;padding-right: 22px;padding-bottom: 33px;padding-left: 44px;}h1,h2,h3,h4,h5,h6{color: orange;}h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{color: hotpink;}.has-white-color{color: var(--wp--preset--color--white) !important;}.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}.has-black-color{color: var(--wp--preset--color--black) !important;}.has-black-background-color{background-color: var(--wp--preset--color--black) !important;}.has-black-border-color{border-color: var(--wp--preset--color--black) !important;}h1.has-blue-color,h2.has-blue-color,h3.has-blue-color,h4.has-blue-color,h5.has-blue-color,h6.has-blue-color{color: var(--wp--preset--color--blue) !important;}h1.has-blue-background-color,h2.has-blue-background-color,h3.has-blue-background-color,h4.has-blue-background-color,h5.has-blue-background-color,h6.has-blue-background-color{background-color: var(--wp--preset--color--blue) !important;}h1.has-blue-border-color,h2.has-blue-border-color,h3.has-blue-border-color,h4.has-blue-border-color,h5.has-blue-border-color,h6.has-blue-border-color{border-color: var(--wp--preset--color--blue) !important;}' ); } ); } ); diff --git a/packages/edit-site/src/components/global-styles/use-global-styles-output.js b/packages/edit-site/src/components/global-styles/use-global-styles-output.js index 9a8ad4f54282b..4b1a1df822393 100644 --- a/packages/edit-site/src/components/global-styles/use-global-styles-output.js +++ b/packages/edit-site/src/components/global-styles/use-global-styles-output.js @@ -170,14 +170,21 @@ function flattenTree( input = {}, prefix, token ) { /** * Transform given style tree into a set of style declarations. * - * @param {Object} blockStyles Block styles. + * @param {Object} blockStyles Block styles. * + * @param {string} selector The selector these declarations should attach to. + * + * @param {boolean} useRootVars Whether to use CSS custom properties in root selector. * @return {Array} An array of style declarations. */ -function getStylesDeclarations( blockStyles = {} ) { +function getStylesDeclarations( blockStyles = {}, selector = '', useRootVars ) { + const isRoot = ROOT_BLOCK_SELECTOR === selector; const output = reduce( STYLE_PROPERTY, - ( declarations, { value, properties, useEngine }, key ) => { + ( declarations, { value, properties, useEngine, rootOnly }, key ) => { + if ( rootOnly && ! isRoot ) { + return declarations; + } const pathToValue = value; if ( first( pathToValue ) === 'elements' || useEngine ) { return declarations; @@ -194,14 +201,63 @@ function getStylesDeclarations( blockStyles = {} ) { // for sub-properties that don't have any value. return; } - - const cssProperty = kebabCase( name ); + const cssProperty = name.startsWith( '--' ) + ? name + : kebabCase( name ); declarations.push( `${ cssProperty }: ${ compileStyleValue( get( styleValue, [ prop ] ) ) }` ); } ); + } else if ( !! properties && isString( styleValue ) && rootOnly ) { + const separateValues = styleValue.split( ' ' ); + + const sortedBoxValues = { + top: '0', + right: '0', + bottom: '0', + left: '0', + }; + + switch ( separateValues.length ) { + case 1: + sortedBoxValues.top = separateValues[ 0 ]; + sortedBoxValues.right = separateValues[ 0 ]; + sortedBoxValues.bottom = separateValues[ 0 ]; + sortedBoxValues.left = separateValues[ 0 ]; + break; + case 2: + sortedBoxValues.top = separateValues[ 0 ]; + sortedBoxValues.right = separateValues[ 1 ]; + sortedBoxValues.bottom = separateValues[ 0 ]; + sortedBoxValues.left = separateValues[ 1 ]; + break; + case 3: + sortedBoxValues.top = separateValues[ 0 ]; + sortedBoxValues.right = separateValues[ 1 ]; + sortedBoxValues.bottom = separateValues[ 2 ]; + sortedBoxValues.left = separateValues[ 1 ]; + break; + case 4: + sortedBoxValues.top = separateValues[ 0 ]; + sortedBoxValues.right = separateValues[ 1 ]; + sortedBoxValues.bottom = separateValues[ 2 ]; + sortedBoxValues.left = separateValues[ 3 ]; + break; + } + + Object.entries( properties ).forEach( ( entry ) => { + const [ name, prop ] = entry; + const cssProperty = name.startsWith( '--' ) + ? name + : kebabCase( name ); + declarations.push( + `${ cssProperty }: ${ compileStyleValue( + get( sortedBoxValues, [ prop ] ) + ) }` + ); + } ); } else if ( get( blockStyles, pathToValue, false ) ) { const cssProperty = key.startsWith( '--' ) ? key @@ -218,6 +274,10 @@ function getStylesDeclarations( blockStyles = {} ) { [] ); + if ( isRoot && useRootVars ) { + return output; + } + // The goal is to move everything to server side generated engine styles // This is temporary as we absorb more and more styles into the engine. const extraRules = getCSSRules( blockStyles ); @@ -367,6 +427,7 @@ export const toCustomProperties = ( tree, blockSelectors ) => { export const toStyles = ( tree, blockSelectors, hasBlockGapSupport ) => { const nodesWithStyles = getNodesWithStyles( tree, blockSelectors ); const nodesWithSettings = getNodesWithSettings( tree, blockSelectors ); + const useRootVars = tree?.settings?.useRootVariables; /* * Reset default browser margin on the root body element. @@ -377,6 +438,11 @@ export const toStyles = ( tree, blockSelectors, hasBlockGapSupport ) => { * @link https://github.com/WordPress/gutenberg/issues/36147. */ let ruleset = 'body {margin: 0;}'; + if ( useRootVars ) { + ruleset = + 'body { margin: 0; padding-right: 0; padding-left: 0; padding-top: var(--wp--style--root--padding-top); padding-bottom: var(--wp--style--root--padding-bottom) } .wp-site-blocks > * { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); } }'; + } + nodesWithStyles.forEach( ( { selector, duotoneSelector, styles } ) => { const duotoneStyles = {}; if ( styles?.filter ) { @@ -396,7 +462,12 @@ export const toStyles = ( tree, blockSelectors, hasBlockGapSupport ) => { } // Process the remaning block styles (they use either normal block class or __experimentalSelector). - const declarations = getStylesDeclarations( styles ); + const declarations = getStylesDeclarations( + styles, + selector, + useRootVars + ); + if ( declarations?.length ) { ruleset = ruleset + `${ selector }{${ declarations.join( ';' ) };}`; } diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index ed5b867e77534..6129acc0df258 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -351,7 +351,7 @@ function test_get_stylesheet_support_for_shorthand_and_longhand_values() { ) ); - $styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-block-group{border-radius: 10px;margin: 1em;padding: 24px;}.wp-block-image{border-top-left-radius: 10px;border-bottom-right-radius: 1em;margin-bottom: 30px;padding-top: 15px;}'; + $styles = 'body { margin: 0; }body{--wp--style--root--padding-top: ;--wp--style--root--padding-right: ;--wp--style--root--padding-bottom: ;--wp--style--root--padding-left: ;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-block-group{border-radius: 10px;margin: 1em;padding: 24px;}.wp-block-image{border-top-left-radius: 10px;border-bottom-right-radius: 1em;margin-bottom: 30px;padding-top: 15px;}'; $this->assertEquals( $styles, $theme_json->get_stylesheet() ); $this->assertEquals( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) ); } @@ -380,7 +380,7 @@ function test_get_stylesheet_skips_disabled_protected_properties() { ) ); - $expected = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; + $expected = 'body { margin: 0; }body{--wp--style--root--padding-top: ;--wp--style--root--padding-right: ;--wp--style--root--padding-bottom: ;--wp--style--root--padding-left: ;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; $this->assertEquals( $expected, $theme_json->get_stylesheet() ); $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); } @@ -402,7 +402,7 @@ function test_get_stylesheet_renders_enabled_protected_properties() { ) ); - $expected = 'body { margin: 0; }body{--wp--style--block-gap: 1em;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }.wp-site-blocks > * + * { margin-block-start: var( --wp--style--block-gap ); }'; + $expected = 'body { margin: 0; }body{--wp--style--root--padding-top: ;--wp--style--root--padding-right: ;--wp--style--root--padding-bottom: ;--wp--style--root--padding-left: ;--wp--style--block-gap: 1em;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }.wp-site-blocks > * + * { margin-block-start: var( --wp--style--block-gap ); }'; $this->assertEquals( $expected, $theme_json->get_stylesheet() ); $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); } @@ -528,7 +528,7 @@ function test_get_stylesheet() { ); $variables = 'body{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}.wp-block-group{--wp--custom--base-font: 16;--wp--custom--line-height--small: 1.2;--wp--custom--line-height--medium: 1.4;--wp--custom--line-height--large: 1.8;}'; - $styles = 'body { margin: 0; }body{color: var(--wp--preset--color--grey);}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }.wp-site-blocks > * + * { margin-block-start: var( --wp--style--block-gap ); }a{background-color: #333;color: #111;}.wp-block-group{border-radius: 10px;padding: 24px;}.wp-block-group a{color: #111;}h1,h2,h3,h4,h5,h6{color: #123456;}h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{background-color: #333;color: #111;font-size: 60px;}.wp-block-post-date{color: #123456;}.wp-block-post-date a{background-color: #777;color: #555;}.wp-block-image{border-top-left-radius: 10px;border-bottom-right-radius: 1em;margin-bottom: 30px;}'; + $styles = 'body { margin: 0; }body{color: var(--wp--preset--color--grey);--wp--style--root--padding-top: ;--wp--style--root--padding-right: ;--wp--style--root--padding-bottom: ;--wp--style--root--padding-left: ;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }.wp-site-blocks > * + * { margin-block-start: var( --wp--style--block-gap ); }a{background-color: #333;color: #111;}.wp-block-group{border-radius: 10px;padding: 24px;}.wp-block-group a{color: #111;}h1,h2,h3,h4,h5,h6{color: #123456;}h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{background-color: #333;color: #111;font-size: 60px;}.wp-block-post-date{color: #123456;}.wp-block-post-date a{background-color: #777;color: #555;}.wp-block-image{border-top-left-radius: 10px;border-bottom-right-radius: 1em;margin-bottom: 30px;}'; $presets = '.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}.has-small-font-family{font-family: var(--wp--preset--font-family--small) !important;}.has-big-font-family{font-family: var(--wp--preset--font-family--big) !important;}'; $all = $variables . $styles . $presets; $this->assertEquals( $all, $theme_json->get_stylesheet() ); @@ -594,7 +594,7 @@ function test_get_stylesheet_preset_rules_come_after_block_rules() { ) ); - $styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-block-group{color: red;}'; + $styles = 'body { margin: 0; }body{--wp--style--root--padding-top: ;--wp--style--root--padding-right: ;--wp--style--root--padding-bottom: ;--wp--style--root--padding-left: ;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-block-group{color: red;}'; $presets = '.wp-block-group.has-grey-color{color: var(--wp--preset--color--grey) !important;}.wp-block-group.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.wp-block-group.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}'; $variables = '.wp-block-group{--wp--preset--color--grey: grey;}'; $all = $variables . $styles . $presets; @@ -680,7 +680,7 @@ public function test_get_stylesheet_preset_values_are_marked_as_important() { ); $this->assertEquals( - 'body{--wp--preset--color--grey: grey;}body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }p{background-color: blue;color: red;font-size: 12px;line-height: 1.3;}.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}', + 'body{--wp--preset--color--grey: grey;}body { margin: 0; }body{--wp--style--root--padding-top: ;--wp--style--root--padding-right: ;--wp--style--root--padding-bottom: ;--wp--style--root--padding-left: ;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }p{background-color: blue;color: red;font-size: 12px;line-height: 1.3;}.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}', $theme_json->get_stylesheet() ); }