Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Style engine: rename at_rule to rules_groups and update test/docs #58922

Merged
merged 5 commits into from
Feb 13, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions packages/style-engine/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,31 @@ $styles = array(
'selector' => '.wp-tomato',
'declarations' => array( 'padding' => '100px' )
),
);

$stylesheet = wp_style_engine_get_stylesheet_from_css_rules(
$styles,
array(
'selector' => '.wp-kumquat',
'context' => 'block-supports', // Indicates that these styles should be stored with block supports CSS.
)
);
print_r( $stylesheet ); // .wp-pumpkin{color:orange}.wp-tomato{color:red;padding:100px}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missed opportunity to use color:tomato here 😄

Copy link
Member Author

@ramonjd ramonjd Feb 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mind blown. I'm updating this later 🤣

```

It's also possible to build simple, nested CSS rules using the `rules_group` key.

```php
$styles = array(
array(
'rules_group' => '@media (min-width: 80rem)',
'selector' => '.wp-carrot',
'declarations' => array( 'color' => 'orange' )
),
array(
'rules_group' => '@media (min-width: 80rem)',
'selector' => '.wp-tomato',
'declarations' => array( 'color' => 'red' )
),
);

$stylesheet = wp_style_engine_get_stylesheet_from_css_rules(
Expand All @@ -138,7 +159,7 @@ $stylesheet = wp_style_engine_get_stylesheet_from_css_rules(
'context' => 'block-supports', // Indicates that these styles should be stored with block supports CSS.
)
);
print_r( $stylesheet ); // .wp-pumpkin,.wp-kumquat{color:orange}.wp-tomato{color:red;padding:100px}
print_r( $stylesheet ); // @media (min-width: 80rem){.wp-carrot{color:orange}}@media (min-width: 80rem){.wp-tomato{color:red;}}
```

### wp_style_engine_get_stylesheet_from_context()
Expand Down
47 changes: 23 additions & 24 deletions packages/style-engine/class-wp-style-engine-css-rule.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,26 +33,25 @@ class WP_Style_Engine_CSS_Rule {
protected $declarations;

/**
* The CSS nested @rule, such as `@media (min-width: 80rem)` or `@layer module`.
* A parent CSS selector in the case of nested CSS, or a CSS nested @rule, such as `@media (min-width: 80rem)` or `@layer module`..
*
* @var string
*/
protected $at_rule;

protected $rules_group;

/**
* Constructor
*
* @param string $selector The CSS selector.
* @param string[]|WP_Style_Engine_CSS_Declarations $declarations An associative array of CSS definitions, e.g., array( "$property" => "$value", "$property" => "$value" ),
* or a WP_Style_Engine_CSS_Declarations object.
* @param string $at_rule A CSS nested @rule, such as `@media (min-width: 80rem)` or `@layer module`.
* @param string $rules_group A parent CSS selector in the case of nested CSS, or a CSS nested @rule, such as `@media (min-width: 80rem)` or `@layer module`.
*
*/
public function __construct( $selector = '', $declarations = array(), $at_rule = '' ) {
public function __construct( $selector = '', $declarations = array(), $rules_group = '' ) {
$this->set_selector( $selector );
$this->add_declarations( $declarations );
$this->set_at_rule( $at_rule );
$this->set_rules_group( $rules_group );
}

/**
Expand Down Expand Up @@ -92,17 +91,26 @@ public function add_declarations( $declarations ) {
}

/**
* Sets the at_rule.
* Sets the rules group.
*
* @param string $at_rule A CSS nested @rule, such as `@media (min-width: 80rem)` or `@layer module`.
* @param string $rules_group A parent CSS selector in the case of nested CSS, or a CSS nested @rule, such as `@media (min-width: 80rem)` or `@layer module`.
*
* @return WP_Style_Engine_CSS_Rule Returns the object to allow chaining of methods.
*/
public function set_at_rule( $at_rule ) {
$this->at_rule = $at_rule;
public function set_rules_group( $rules_group ) {
$this->rules_group = $rules_group;
return $this;
}

/**
* Gets the rules group.
*
* @return string
ramonjd marked this conversation as resolved.
Show resolved Hide resolved
*/
public function get_rules_group() {
return $this->rules_group ?? null;
ramonjd marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Gets the declarations object.
*
Expand All @@ -121,15 +129,6 @@ public function get_selector() {
return $this->selector;
}

/**
* Gets the at_rule.
*
* @return string
*/
public function get_at_rule() {
return $this->at_rule;
}

/**
* Gets the CSS.
*
Expand All @@ -148,16 +147,16 @@ public function get_css( $should_prettify = false, $indent_count = 0 ) {
// Trims any multiple selectors strings.
$selector = $should_prettify ? implode( ',', array_map( 'trim', explode( ',', $this->get_selector() ) ) ) : $this->get_selector();
$selector = $should_prettify ? str_replace( array( ',' ), ",\n", $selector ) : $selector;
$at_rule = $this->get_at_rule();
$has_at_rule = ! empty( $at_rule );
$css_declarations = $this->declarations->get_declarations_string( $should_prettify, $has_at_rule ? $nested_declarations_indent : $declarations_indent );
$rules_group = $this->get_rules_group();
$has_rules_group = ! empty( $rules_group );
$css_declarations = $this->declarations->get_declarations_string( $should_prettify, $has_rules_group ? $nested_declarations_indent : $declarations_indent );

if ( empty( $css_declarations ) ) {
return '';
}

if ( $has_at_rule ) {
$selector = "{$rule_indent}{$at_rule}{$spacer}{{$suffix}{$nested_rule_indent}{$selector}{$spacer}{{$suffix}{$css_declarations}{$suffix}{$nested_rule_indent}}{$suffix}{$rule_indent}}";
if ( $has_rules_group ) {
$selector = "{$rule_indent}{$rules_group}{$spacer}{{$suffix}{$nested_rule_indent}{$selector}{$spacer}{{$suffix}{$css_declarations}{$suffix}{$nested_rule_indent}}{$suffix}{$rule_indent}}";
return $selector;
}

Expand Down
18 changes: 9 additions & 9 deletions packages/style-engine/class-wp-style-engine-css-rules-store.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,25 +109,25 @@ public function get_all_rules() {
* Gets a WP_Style_Engine_CSS_Rule object by its selector.
* If the rule does not exist, it will be created.
*
* @param string $selector The CSS selector.
* @param string $at_rule The CSS nested @rule, such as `@media (min-width: 80rem)` or `@layer module`.
* @param string $selector The CSS selector.
* @param string $rules_group A parent CSS selector in the case of nested CSS, or a CSS nested @rule, such as `@media (min-width: 80rem)` or `@layer module`..
*
* @return WP_Style_Engine_CSS_Rule|void Returns a WP_Style_Engine_CSS_Rule object, or null if the selector is empty.
*/
public function add_rule( $selector, $at_rule = '' ) {
$selector = trim( $selector );
$at_rule = trim( $at_rule );
public function add_rule( $selector, $rules_group = '' ) {
$selector = $selector ? trim( $selector ) : '';
$rules_group = $rules_group ? trim( $rules_group ) : '';

// Bail early if there is no selector.
if ( empty( $selector ) ) {
return;
}

if ( ! empty( $at_rule ) ) {
if ( empty( $this->rules[ "$at_rule $selector" ] ) ) {
$this->rules[ "$at_rule $selector" ] = new WP_Style_Engine_CSS_Rule( $selector, array(), $at_rule );
if ( ! empty( $rules_group ) ) {
if ( empty( $this->rules[ "$rules_group $selector" ] ) ) {
$this->rules[ "$rules_group $selector" ] = new WP_Style_Engine_CSS_Rule( $selector, array(), $rules_group );
}
return $this->rules[ "$at_rule $selector" ];
return $this->rules[ "$rules_group $selector" ];
}

// Create the rule if it doesn't exist.
Expand Down
12 changes: 6 additions & 6 deletions packages/style-engine/class-wp-style-engine-processor.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,20 +65,20 @@ public function add_rules( $css_rules ) {
}

foreach ( $css_rules as $rule ) {
$selector = $rule->get_selector();
$at_rule = $rule->get_at_rule();
$selector = $rule->get_selector();
$rules_group = $rule->get_rules_group();

/**
* If there is an at_rule and it already exists in the css_rules array,
* add the rule to it.
* Otherwise, create a new entry for the at_rule
*/
if ( ! empty( $at_rule ) ) {
if ( isset( $this->css_rules[ "$at_rule $selector" ] ) ) {
$this->css_rules[ "$at_rule $selector" ]->add_declarations( $rule->get_declarations() );
if ( ! empty( $rules_group ) ) {
if ( isset( $this->css_rules[ "$rules_group $selector" ] ) ) {
$this->css_rules[ "$rules_group $selector" ]->add_declarations( $rule->get_declarations() );
continue;
}
$this->css_rules[ "$at_rule $selector" ] = $rule;
$this->css_rules[ "$rules_group $selector" ] = $rule;
continue;
}

Expand Down
5 changes: 3 additions & 2 deletions packages/style-engine/class-wp-style-engine.php
Original file line number Diff line number Diff line change
Expand Up @@ -355,14 +355,15 @@ protected static function is_valid_style_value( $style_value ) {
* @param string $store_name A valid store key.
* @param string $css_selector When a selector is passed, the function will return a full CSS rule `$selector { ...rules }`, otherwise a concatenated string of properties and values.
* @param string[] $css_declarations An associative array of CSS definitions, e.g., array( "$property" => "$value", "$property" => "$value" ).
* @param string $rules_group Optional. A parent CSS selector in the case of nested CSS, or a CSS nested @rule, such as `@media (min-width: 80rem)` or `@layer module`.
*
* @return void.
*/
public static function store_css_rule( $store_name, $css_selector, $css_declarations, $css_at_rule = '' ) {
public static function store_css_rule( $store_name, $css_selector, $css_declarations, $rules_group = '' ) {
if ( empty( $store_name ) || empty( $css_selector ) || empty( $css_declarations ) ) {
return;
}
static::get_store( $store_name )->add_rule( $css_selector, $css_at_rule )->add_declarations( $css_declarations );
static::get_store( $store_name )->add_rule( $css_selector, $rules_group )->add_declarations( $css_declarations );
}

/**
Expand Down
9 changes: 4 additions & 5 deletions packages/style-engine/style-engine.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ function wp_style_engine_get_styles( $block_styles, $options = array() ) {
* Required. A collection of CSS rules.
*
* @type array ...$0 {
* @type string $at_rule A CSS nested @rule, such as `@media (min-width: 80rem)` or `@layer module`.
* @type string $rules_group A parent CSS selector in the case of nested CSS, or a CSS nested @rule, such as `@media (min-width: 80rem)` or `@layer module`.
* @type string $selector A CSS selector.
* @type string[] $declarations An associative array of CSS definitions, e.g., array( "$property" => "$value", "$property" => "$value" ).
* }
Expand Down Expand Up @@ -117,13 +117,12 @@ function wp_style_engine_get_stylesheet_from_css_rules( $css_rules, $options = a
continue;
}

$at_rule = ! empty( $css_rule['at_rule'] ) ? $css_rule['at_rule'] : '';

$rules_group = $css_rule['rules_group'] ?? null;
if ( ! empty( $options['context'] ) ) {
WP_Style_Engine::store_css_rule( $options['context'], $css_rule['selector'], $css_rule['declarations'], $at_rule );
WP_Style_Engine::store_css_rule( $options['context'], $css_rule['selector'], $css_rule['declarations'], $rules_group );
}

$css_rule_objects[] = new WP_Style_Engine_CSS_Rule( $css_rule['selector'], $css_rule['declarations'], $at_rule );
$css_rule_objects[] = new WP_Style_Engine_CSS_Rule( $css_rule['selector'], $css_rule['declarations'], $rules_group );
}

if ( empty( $css_rule_objects ) ) {
Expand Down
16 changes: 16 additions & 0 deletions phpunit/style-engine/class-wp-style-engine-css-rule-test.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,22 @@ public function test_should_instantiate_with_selector_and_rules() {
$this->assertSame( $expected, $css_rule->get_css(), 'Value returned by get_css() does not match expected declarations string.' );
}

/**
* Tests setting and getting a rules group.
*
* @covers ::set_rules_group
* @covers ::get_rules_group
*/
public function test_should_set_rules_group() {
$rule = new WP_Style_Engine_CSS_Rule_Gutenberg( '.heres-johnny', array(), '@layer state' );

$this->assertSame( '@layer state', $rule->get_rules_group(), 'Return value of get_rules_group() does not match value passed to constructor.' );

$rule->set_rules_group( '@layer pony' );

$this->assertSame( '@layer pony', $rule->get_rules_group(), 'Return value of get_rules_group() does not match value passed to set_rules_group().' );
}

/**
* Tests that declaration properties are deduplicated.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,4 +170,20 @@ public function test_should_get_all_rule_objects_for_a_store() {

$this->assertSame( $expected, $new_pizza_store->get_all_rules(), 'Return value for get_all_rules() does not match expectations after adding new rules to store.' );
}

/**
* Tests adding identical selectors.
ramonjd marked this conversation as resolved.
Show resolved Hide resolved
*
* @covers ::add_rule
*/
public function test_should_store_as_concatenated_rules_groups_and_selector() {
$store_one = WP_Style_Engine_CSS_Rules_Store_Gutenberg::get_store( 'one' );
$store_one_rule = $store_one->add_rule( '.tony', '.one' );

$this->assertSame(
'.one .tony',
"{$store_one_rule->get_rules_group()} {$store_one_rule->get_selector()}",
'add_rule() does not return already existing return .one rule.'
ramonjd marked this conversation as resolved.
Show resolved Hide resolved
);
}
}
8 changes: 4 additions & 4 deletions phpunit/style-engine/class-wp-style-engine-processor-test.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public function test_should_return_nested_rules_as_compiled_css() {
'background-color' => 'purple',
)
);
$a_nice_css_rule->set_at_rule( '@media (min-width: 80rem)' );
$a_nice_css_rule->set_rules_group( '@media (min-width: 80rem)' );

$a_nicer_css_rule = new WP_Style_Engine_CSS_Rule_Gutenberg( '.a-nicer-rule' );
$a_nicer_css_rule->add_declarations(
Expand All @@ -68,7 +68,7 @@ public function test_should_return_nested_rules_as_compiled_css() {
'background-color' => 'purple',
)
);
$a_nicer_css_rule->set_at_rule( '@layer nicety' );
$a_nicer_css_rule->set_rules_group( '@layer nicety' );

$a_nice_processor = new WP_Style_Engine_Processor_Gutenberg();
$a_nice_processor->add_rules( array( $a_nice_css_rule, $a_nicer_css_rule ) );
Expand Down Expand Up @@ -143,7 +143,7 @@ public function test_should_return_prettified_nested_css_rules() {
'background-color' => 'orange',
)
);
$a_wonderful_css_rule->set_at_rule( '@media (min-width: 80rem)' );
$a_wonderful_css_rule->set_rules_group( '@media (min-width: 80rem)' );

$a_very_wonderful_css_rule = new WP_Style_Engine_CSS_Rule_Gutenberg( '.a-very_wonderful-rule' );
$a_very_wonderful_css_rule->add_declarations(
Expand All @@ -152,7 +152,7 @@ public function test_should_return_prettified_nested_css_rules() {
'background-color' => 'orange',
)
);
$a_very_wonderful_css_rule->set_at_rule( '@layer wonderfulness' );
$a_very_wonderful_css_rule->set_rules_group( '@layer wonderfulness' );

$a_wonderful_processor = new WP_Style_Engine_Processor_Gutenberg();
$a_wonderful_processor->add_rules( array( $a_wonderful_css_rule, $a_very_wonderful_css_rule ) );
Expand Down
Loading
Loading