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: update terminology and docs #41964

Merged
merged 7 commits into from
Jun 28, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
36 changes: 34 additions & 2 deletions packages/style-engine/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,49 @@ _This package assumes that your code will run in an **ES2015+** environment. If

This Package is considered experimental at the moment. The idea is to have a package used to generate styles based on a style object that is consistent between: backend, frontend, block style object and theme.json.

Currently it's not a package that generates a wp.styleEngine global because it's not ready yet, it's still a bundled package but ultimately, we want it to be so, once the roadmap is finished:
Because this package is experimental and still in development it does not yet generate a `wp.styleEngine` global. To get there, the following tasks need to be completed:

**TODO List:**

- Add style definitions for all the currently supported styles in blocks and theme.json.
- the CSS variable shortcuts for values (for presets...)
- The CSS variable shortcuts for values (for presets...)
- Support generating styles in the frontend. (Ongoing)
- Support generating styles in the backend (block supports and theme.json stylesheet). (Ongoing)
- Refactor all block styles to use the style engine server side. (Ongoing)
- Consolidate global and block style rendering and enqueuing
- Refactor all blocks to consistently use the "style" attribute for all customizations (get rid of the preset specific attributes).

See [Tracking: Add a Style Engine to manage rendering block styles #38167](https://github.com/WordPress/gutenberg/issues/38167)

## Glossary

A guide to the terms and variable names referenced by the Style Engine package.

<dl>
<dt>Block style (Gutenberg internal)</dt>
<dd>An object comprising a block's style attribute that contains a block's style values. E.g., <code>{ spacing: { margin: '10px' }, color: { ... }, ... }</code></dd>
<dt>Global styles (Gutenberg internal)</dt>
<dd>A merged block styles object containing values from a theme's theme.json and user styles settings.</dd>
<dt>CSS declaration or (CSS property declaration)</dt>
<dd>A CSS property paired with a CSS value. E.g., <code>color: pink</code> </dd>
<dt>CSS declarations block</dt>
<dd>A set of CSS declarations usually paired with a CSS selector to create a CSS rule.</dd>
<dt>CSS property</dt>
<dd>Identifiers that describe stylistic, modifiable features of an HTML element. E.g., <code>border</code>, <code>font-size</code>, <code>width</code>...</dd>
<dt>CSS rule</dt>
<dd>A CSS selector followed by a CSS declarations block inside a set of curly braces. Usually found in a CSS stylesheet.</dd>
<dt>CSS selector</dt>
<dd>The first component of a CSS rule, a CSS selector is a pattern of elements, classnames or other terms that define the element to which the rule&rsquo;s CSS definitions apply. E.g., <code>p.my-cool-classname > span</code>. See <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors" target="_blank">MDN CSS selectors article</a>.</dd>
<dt>CSS stylesheet</dt>
<dd>A collection of CSS rules contained within a file or within an <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/style" target="_blank">HTML style tag</a>.</dd>
<dt>CSS value</dt>
<dd>The value of a CSS property. The value determines how the property is modified. E.g., the <code>10vw</code> in <code>height: 10vw</code>.</dd>
<dt>CSS variables (vars) or CSS custom properties</dt>
<dd>Properties, whose values can be reused in other CSS declarations. Set using custom property notation (e.g., <code>--wp--preset--olive: #808000;</code>) and accessed using the <code>var()</code> function (e.g., <code>color: var( --wp--preset--olive );</code>). See <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties" target="_blank">MDN article on CSS custom properties</a>.</dd>
<dt>Inline styles</dt>
<dd>Inline styles are CSS declarations that affect a single HTML element, contained within a style attribute</dd>
</dl>

## Usage

<!-- START TOKEN(Autogenerated API docs) -->
Expand Down
99 changes: 50 additions & 49 deletions packages/style-engine/class-wp-style-engine.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class WP_Style_Engine {
* The value should be a valid CSS property (string) to match the incoming value, e.g., "color" to match var:preset|color|somePresetSlug.
* - property_keys => (array) array of keys whose values represent a valid CSS property, e.g., "margin" or "border".
* - path => (array) a path that accesses the corresponding style value in the block style object.
* - value_func => (string) the name of a function to generate an array of valid CSS rules for a particular style object.
* - value_func => (string) the name of a function to generate a CSS definition array for a particular style object. The output of this function should be `array( "$property" => "$value", ... )`.
*/
const BLOCK_STYLE_DEFINITIONS_METADATA = array(
'color' => array(
Expand Down Expand Up @@ -113,28 +113,28 @@ class WP_Style_Engine {
'path' => array( 'border', 'width' ),
),
'top' => array(
'value_func' => 'static::get_css_individual_property_rules',
'value_func' => 'static::get_individual_property_css_declarations',
'path' => array( 'border', 'top' ),
'css_vars' => array(
'color' => '--wp--preset--color--$slug',
),
),
'right' => array(
'value_func' => 'static::get_css_individual_property_rules',
'value_func' => 'static::get_individual_property_css_declarations',
'path' => array( 'border', 'right' ),
'css_vars' => array(
'color' => '--wp--preset--color--$slug',
),
),
'bottom' => array(
'value_func' => 'static::get_css_individual_property_rules',
'value_func' => 'static::get_individual_property_css_declarations',
'path' => array( 'border', 'bottom' ),
'css_vars' => array(
'color' => '--wp--preset--color--$slug',
),
),
'left' => array(
'value_func' => 'static::get_css_individual_property_rules',
'value_func' => 'static::get_individual_property_css_declarations',
'path' => array( 'border', 'left' ),
'css_vars' => array(
'color' => '--wp--preset--color--$slug',
Expand Down Expand Up @@ -247,7 +247,7 @@ protected static function get_slug_from_preset_value( $style_value, $property_ke
}

/**
* Checks whether an incoming style value is valid.
* Checks whether an incoming block style value is valid.
*
* @param string? $style_value A single css preset value.
*
Expand Down Expand Up @@ -302,25 +302,24 @@ protected static function get_classnames( $style_value, $style_definition ) {
}

/**
* Returns CSS rules based on valid block style values.
* Returns an array of CSS declarations based on valid block style values.
*
* @param array $style_value A single raw style value from the generate() $block_styles array.
* @param array<string> $style_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA.
* @param boolean $should_return_css_vars Whether to try to build and return CSS var values.
*
* @return array An array of CSS rules.
* @return array An array of CSS definitions, e.g., array( "$property" => "$value" ).
*/
protected static function get_css( $style_value, $style_definition, $should_return_css_vars ) {
$rules = array();

protected static function get_css_declarations( $style_value, $style_definition, $should_return_css_vars ) {
if (
isset( $style_definition['value_func'] ) &&
is_callable( $style_definition['value_func'] )
) {
return call_user_func( $style_definition['value_func'], $style_value, $style_definition );
}

$style_properties = $style_definition['property_keys'];
$css_declarations = array();
$style_property_keys = $style_definition['property_keys'];

// Build CSS var values from var:? values, e.g, `var(--wp--css--rule-slug )`
// Check if the value is a CSS preset and there's a corresponding css_var pattern in the style definition.
Expand All @@ -329,35 +328,35 @@ protected static function get_css( $style_value, $style_definition, $should_retu
foreach ( $style_definition['css_vars'] as $css_var_pattern => $property_key ) {
$slug = static::get_slug_from_preset_value( $style_value, $property_key );
if ( $slug ) {
$css_var = strtr(
$css_var = strtr(
$css_var_pattern,
array( '$slug' => $slug )
);
$rules[ $style_properties['default'] ] = "var($css_var)";
$css_declarations[ $style_property_keys['default'] ] = "var($css_var)";
}
}
}
return $rules;
return $css_declarations;
}

// Default rule builder.
// If the input contains an array, assume box model-like properties
// for styles such as margins and padding.
if ( is_array( $style_value ) ) {
foreach ( $style_value as $key => $value ) {
$individual_property = sprintf( $style_properties['individual'], _wp_to_kebab_case( $key ) );
$rules[ $individual_property ] = $value;
$individual_property = sprintf( $style_property_keys['individual'], _wp_to_kebab_case( $key ) );
$css_declarations[ $individual_property ] = $value;
}
} else {
$rules[ $style_properties['default'] ] = $style_value;
$css_declarations[ $style_property_keys['default'] ] = $style_value;
}

return $rules;
return $css_declarations;
}

/**
* Returns an CSS ruleset.
* Styles are bundled based on the instructions in BLOCK_STYLE_DEFINITIONS_METADATA.
* Returns classname and CSS from a block styles object.
* Return values are parsed based on the instructions in BLOCK_STYLE_DEFINITIONS_METADATA.
*
* @param array $block_styles An array of styles from a block's attributes.
* @param array $options array(
Expand All @@ -375,7 +374,7 @@ public function generate( $block_styles, $options ) {
return null;
}

$css_rules = array();
$css_declarations = array();
$classnames = array();
$should_return_css_vars = isset( $options['css_vars'] ) && true === $options['css_vars'];

Expand All @@ -391,36 +390,38 @@ public function generate( $block_styles, $options ) {
continue;
}

$classnames = array_merge( $classnames, static::get_classnames( $style_value, $style_definition ) );
$css_rules = array_merge( $css_rules, static::get_css( $style_value, $style_definition, $should_return_css_vars ) );
$classnames = array_merge( $classnames, static::get_classnames( $style_value, $style_definition ) );
$css_declarations = array_merge( $css_declarations, static::get_css_declarations( $style_value, $style_definition, $should_return_css_vars ) );
}
}

// Build CSS rules output.
$selector = isset( $options['selector'] ) ? $options['selector'] : null;
$css = array();
$styles_output = array();

if ( ! empty( $css_rules ) ) {
// Generate inline style rules.
foreach ( $css_rules as $rule => $value ) {
$filtered_css = esc_html( safecss_filter_attr( "{$rule}: {$value}" ) );
if ( ! empty( $filtered_css ) ) {
$css[] = $filtered_css . ';';
$css_selector = isset( $options['selector'] ) ? $options['selector'] : null;
$filtered_css_declarations = array();

if ( ! empty( $css_declarations ) ) {
// Generate inline style declarations.
foreach ( $css_declarations as $css_property => $css_value ) {
$filtered_css_declaration = esc_html( safecss_filter_attr( "{$css_property}: {$css_value}" ) );
if ( ! empty( $filtered_css_declaration ) ) {
$filtered_css_declarations[] = $filtered_css_declaration . ';';
}
}
}

// The return object.
$styles_output = array();

// Return css, if any.
if ( ! empty( $css ) ) {
if ( ! empty( $filtered_css_declarations ) ) {
// Return an entire rule if there is a selector.
if ( $selector ) {
$style_block = "$selector { ";
$style_block .= implode( ' ', $css );
$style_block .= ' }';
$styles_output['css'] = $style_block;
if ( $css_selector ) {
$css_rule = "$css_selector { ";
$css_rule .= implode( ' ', $filtered_css_declarations );
$css_rule .= ' }';
$styles_output['css'] = $css_rule;
} else {
$styles_output['css'] = implode( ' ', $css );
$styles_output['css'] = implode( ' ', $filtered_css_declarations );
}
}

Expand All @@ -434,7 +435,7 @@ public function generate( $block_styles, $options ) {


/**
* Style value parser that returns a CSS ruleset of style properties for style definition groups
* 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,
Expand All @@ -443,13 +444,13 @@ public function generate( $block_styles, $options ) {
* @param array $style_value A single raw Gutenberg style attributes value for a CSS property.
* @param array $individual_property_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA.
*
* @return array The class name for the added style.
* @return array An array of CSS definitions, e.g., array( "$property" => "$value" ).
*/
protected static function get_css_individual_property_rules( $style_value, $individual_property_definition ) {
$rules = array();
protected static function get_individual_property_css_declarations( $style_value, $individual_property_definition ) {
$css_declarations = array();

if ( ! is_array( $style_value ) || empty( $style_value ) || empty( $individual_property_definition['path'] ) ) {
return $rules;
return $css_declarations;
}

// The first item in $individual_property_definition['path'] array tells us the style property, e.g., "border".
Expand Down Expand Up @@ -477,11 +478,11 @@ protected static function get_css_individual_property_rules( $style_value, $indi
);
$value = "var($css_var)";
}
$individual_css_property = sprintf( $style_definition['property_keys']['individual'], $individual_property_key );
$rules[ $individual_css_property ] = $value;
$individual_css_property = sprintf( $style_definition['property_keys']['individual'], $individual_property_key );
$css_declarations[ $individual_css_property ] = $value;
}
}
return $rules;
return $css_declarations;
}
}

Expand Down