From 680d1aa4adae9b8d2fa895a30b3dfd48f40837d9 Mon Sep 17 00:00:00 2001 From: Ramon Date: Thu, 10 Mar 2022 15:51:59 +1100 Subject: [PATCH] Layout: use CSS logical properties for margin top and bottom (#38816) * Layout doesn't take into account different writing modes, such as left-to-right, vertical and so on. With CSS logical properties, block and inline margins will apply to the appropriate side depending on the direction of the document flow. This change to the layout margins ensures that margins will adhere to the logic of current flow. For example, margin-block-start (instead of margin-top) will manifest itself as a top margin for `writing-mode: horizontal-tb;` but a right margin for `writing-mode: vertical-rl;`. * Fixing CSS error where I mean to use margin-inline-end for margin-right. Other minor formatting Taking a clumsy stab at compat files so we can load the global styles and settings. * Updated tests and removed var_dumpy * Removing reference to non-existent file after rebasing on top of #38883 Removing `get_stylesheet()` from WP_Theme_JSON_Gutenberg * Removing the CSS logical properties for styles that control horizontal page layout (left and right margins) so that any changes to the writing mode of blocks within wp-site-blocks and block containers still align themselves according to current horizontal rules. --- lib/block-supports/layout.php | 8 +- .../class-wp-theme-json-gutenberg.php | 75 +++++++++++++++++++ packages/block-editor/src/layouts/flow.js | 18 ++--- phpunit/class-wp-theme-json-test.php | 4 +- 4 files changed, 88 insertions(+), 17 deletions(-) diff --git a/lib/block-supports/layout.php b/lib/block-supports/layout.php index 59632f3e2bd16..668ab88a608e0 100644 --- a/lib/block-supports/layout.php +++ b/lib/block-supports/layout.php @@ -62,12 +62,12 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support $style .= "$selector .alignfull { max-width: none; }"; } - $style .= "$selector .alignleft { float: left; margin-right: 2em; margin-left: 0; }"; - $style .= "$selector .alignright { float: right; margin-left: 2em; margin-right: 0; }"; + $style .= "$selector .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }"; + $style .= "$selector .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }"; if ( $has_block_gap_support ) { $gap_style = $gap_value ? $gap_value : 'var( --wp--style--block-gap )'; - $style .= "$selector > * { margin-top: 0; margin-bottom: 0; }"; - $style .= "$selector > * + * { margin-top: $gap_style; margin-bottom: 0; }"; + $style .= "$selector > * { margin-block-start: 0; margin-block-end: 0; }"; + $style .= "$selector > * + * { margin-block-start: $gap_style; margin-block-end: 0; }"; } } elseif ( 'flex' === $layout_type ) { $layout_orientation = isset( $layout['orientation'] ) ? $layout['orientation'] : 'horizontal'; diff --git a/lib/compat/wordpress-6.0/class-wp-theme-json-gutenberg.php b/lib/compat/wordpress-6.0/class-wp-theme-json-gutenberg.php index c68f6fb3d205a..567dfb0cf4027 100644 --- a/lib/compat/wordpress-6.0/class-wp-theme-json-gutenberg.php +++ b/lib/compat/wordpress-6.0/class-wp-theme-json-gutenberg.php @@ -43,6 +43,81 @@ public function get_patterns() { return array(); } + /** + * Converts each style section into a list of rulesets + * containing the block styles to be appended to the stylesheet. + * + * See glossary at https://developer.mozilla.org/en-US/docs/Web/CSS/Syntax + * + * For each section this creates a new ruleset such as: + * + * block-selector { + * style-property-one: value; + * } + * + * @param array $style_nodes Nodes with styles. + * @return string The new stylesheet. + */ + protected function get_block_classes( $style_nodes ) { + $block_rules = ''; + + foreach ( $style_nodes as $metadata ) { + if ( null === $metadata['selector'] ) { + 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 ); + + // 1. Separate the ones who use the general selector + // and the ones who use the duotone selector. + $declarations_duotone = array(); + foreach ( $declarations as $index => $declaration ) { + if ( 'filter' === $declaration['name'] ) { + unset( $declarations[ $index ] ); + $declarations_duotone[] = $declaration; + } + } + + /* + * Reset default browser margin on the root body element. + * This is set on the root selector **before** generating the ruleset + * from the `theme.json`. This is to ensure that if the `theme.json` declares + * `margin` in its `spacing` declaration for the `body` element then these + * user-generated values take precedence in the CSS cascade. + * @link https://github.com/WordPress/gutenberg/issues/36147. + */ + if ( static::ROOT_BLOCK_SELECTOR === $selector ) { + $block_rules .= 'body { margin: 0; }'; + } + + // 2. Generate the rules that use the general selector. + $block_rules .= static::to_ruleset( $selector, $declarations ); + + // 3. Generate the rules that use the duotone selector. + if ( isset( $metadata['duotone'] ) && ! empty( $declarations_duotone ) ) { + $selector_duotone = static::scope_selector( $metadata['selector'], $metadata['duotone'] ); + $block_rules .= static::to_ruleset( $selector_duotone, $declarations_duotone ); + } + + if ( self::ROOT_BLOCK_SELECTOR === $selector ) { + $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; }'; + + $has_block_gap_support = _wp_array_get( $this->theme_json, array( 'settings', 'spacing', 'blockGap' ) ) !== null; + if ( $has_block_gap_support ) { + $block_rules .= '.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }'; + $block_rules .= '.wp-site-blocks > * + * { margin-block-start: var( --wp--style--block-gap ); }'; + } + } + } + + return $block_rules; + } + /** * Returns a valid theme.json for a theme. * Essentially, it flattens the preset data. diff --git a/packages/block-editor/src/layouts/flow.js b/packages/block-editor/src/layouts/flow.js index ae2e9379bdf11..8ef689d7a36d3 100644 --- a/packages/block-editor/src/layouts/flow.js +++ b/packages/block-editor/src/layouts/flow.js @@ -123,11 +123,9 @@ export default { margin-left: auto !important; margin-right: auto !important; } - ${ appendSelectors( selector, '> .alignwide' ) } { max-width: ${ wideSize ?? contentSize }; } - ${ appendSelectors( selector, '> .alignfull' ) } { max-width: none; } @@ -137,26 +135,24 @@ export default { output += ` ${ appendSelectors( selector, '> .alignleft' ) } { float: left; - margin-right: 2em; - margin-left: 0; + margin-inline-start: 0; + margin-inline-end: 2em; } - ${ appendSelectors( selector, '> .alignright' ) } { float: right; - margin-left: 2em; - margin-right: 0; + margin-inline-start: 2em; + margin-inline-end: 0; } - `; if ( hasBlockGapStylesSupport ) { output += ` ${ appendSelectors( selector, '> *' ) } { - margin-top: 0; - margin-bottom: 0; + margin-block-start: 0; + margin-block-end: 0; } ${ appendSelectors( selector, '> * + *' ) } { - margin-top: ${ blockGapValue }; + margin-block-start: ${ blockGapValue }; } `; } diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 09f875fb3b7a0..b138564896cb7 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -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-top: 0; margin-bottom: 0; }.wp-site-blocks > * + * { margin-top: var( --wp--style--block-gap ); }'; + $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 ); }'; $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-top: 0; margin-bottom: 0; }.wp-site-blocks > * + * { margin-top: 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-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() );