Skip to content

Commit

Permalink
Experimenting with cascade layers
Browse files Browse the repository at this point in the history
  • Loading branch information
ramonjd committed Jun 27, 2022
1 parent 42f4436 commit c72366e
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 37 deletions.
4 changes: 0 additions & 4 deletions lib/block-supports/elements.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,6 @@ function gutenberg_render_elements_support_styles( $pre_render, $block ) {
'layer' => 'block-supports',
)
);

// if ( ! empty( $styles['css'] ) ) {
// gutenberg_enqueue_block_support_styles( $styles['css'] );
// }
}

return null;
Expand Down
88 changes: 66 additions & 22 deletions packages/style-engine/class-wp-style-engine-renderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class WP_Style_Engine_Renderer {
*/
public static function render_registered_block_supports_styles() {
$style_engine = WP_Style_Engine::get_instance();
$block_support_styles = $style_engine->get_registered_styles( 'block-supports' );
$block_support_styles = $style_engine->get_registered_styles();

if ( empty( $block_support_styles ) ) {
return;
Expand All @@ -39,7 +39,7 @@ public static function render_registered_block_supports_styles() {
$output = '';

foreach ( $block_support_styles as $selector => $css_definitions ) {
$output .= self::generate_css_rule( $selector, $css_definitions, true );
$output .= self::generate_css_rule( $selector, $css_definitions, array( 'prettify' => true ) );
}

echo "<style>\n$output</style>\n";
Expand Down Expand Up @@ -79,46 +79,89 @@ public static function generate_inline_property_declarations( $css_definitions )
}

/**
* Creates a string consisting of a CSS rule
* Creates a string consisting of a CSS rule.
*
* @param string $selector A CSS selector, e.g., `.some-class-name`.
* @param array $css_definitions An collection of CSS definitions `[ [ 'color' => 'red' ] ]`.
* @param boolean $should_prettify Whether to print spaces and carriage returns.
* @param string $selector A CSS selector, e.g., `.some-class-name`.
* @param array $css_definitions An collection of CSS definitions `[ [ 'color' => 'red' ] ]`.
* @param array $options array(
* 'prettify' => (boolean) Whether to add carriage returns and indenting.
* 'indent' => (number) The number of tab indents to apply to the rule. Applies if `prettify` is `true`.
* );.
*
* @return string A CSS rule, e.g. `'.some-selector { color: red; font-size:12px }'`
*/
public static function generate_css_rule( $selector, $css_definitions, $should_prettify = false ) {
public static function generate_css_rule( $selector, $css_definitions, $options = array() ) {
$css_rule_block = '';

if ( ! $selector || empty( $css_definitions ) ) {
return $css_rule_block;
}

$css_rule_block = $should_prettify ? "$selector {\n" : "$selector { ";
$defaults = array(
'prettify' => false,
'indent' => 0,
);
$options = wp_parse_args( $options, $defaults );
$indent = str_repeat( "\t", $options['indent'] );
$css_rule_block = $options['prettify'] ? "$indent$selector {\n" : "$selector { ";

foreach ( $css_definitions as $definition => $value ) {
$filtered_css = self::sanitize_property_declaration( "{$definition}: {$value}" );
if ( ! empty( $filtered_css ) ) {
if ( $should_prettify ) {
$css_rule_block .= "\t$filtered_css;\n";
if ( $options['prettify'] ) {
$css_rule_block .= "\t$indent$filtered_css;\n";
} else {
$css_rule_block .= $filtered_css . ';';
}
}
}
$css_rule_block .= $should_prettify ? "}\n" : ' }';
$css_rule_block .= $options['prettify'] ? "$indent}\n" : ' }';
return $css_rule_block;
}

// @TODO The following method takes over the work of enqueuing block support styles for now.
// Later we'd want to identify which styles we're rendering, e.g., is this a global styles ruleset,
// so we can create appropriate "layers" / control specificity.
// We could create separate blocks for each layer, e.g.,
// wp_register_style( 'global-styles-layer', false, array(), true, true );
// wp_add_inline_style( 'global-styles-layer', $styles );
// wp_enqueue_style( 'global-styles-layer' );
// Or build them and print them all out in one.
// Just how, I don't know right now :D.
// @TODO Using cascade layers should be opt-in.
/**
* Builds layers and styles rules from registered layers and styles for output.
*/
public static function enqueue_cascade_layers() {
$style_engine = WP_Style_Engine::get_instance();
$registered_layers = $style_engine->get_registered_styles();

if ( empty( $registered_layers ) ) {
return;
}

$layer_output = array();
$styles_output = '';

foreach ( $style_engine::STYLE_LAYERS as $layer_name ) {
if ( ! isset( $registered_layers[ $layer_name ] ) || empty( $registered_layers[ $layer_name ] ) ) {
continue;
}

$layer_output[] = $layer_name;
$styles_output .= "@layer {$layer_name} {\n";

foreach ( $registered_layers[ $layer_name ] as $selector => $css_definitions ) {
$styles_output .= self::generate_css_rule(
$selector,
$css_definitions,
array(
'prettify' => true,
'indent' => 1,
)
);
}
$styles_output .= '}';
}

if ( ! empty( $styles_output ) ) {
$layer_output = '@layer ' . implode( ', ', $layer_output ) . ";\n";
wp_register_style( 'wp-styles-layers', false, array(), true, true );
wp_add_inline_style( 'wp-styles-layers', $layer_output . $styles_output );
wp_enqueue_style( 'wp-styles-layers' );
}
}

/**
* Taken from gutenberg_enqueue_block_support_styles()
Expand All @@ -135,14 +178,15 @@ public static function generate_css_rule( $selector, $css_definitions, $should_p
*
* @param int $priority To set the priority for the add_action.
*/
public static function enqueue_block_support_styles( $priority = 10 ) {
public static function enqueue_registered_styles( $priority = 10 ) {
$action_hook_name = 'wp_footer';
if ( wp_is_block_theme() ) {
$action_hook_name = 'wp_head';
}
add_action( 'wp_enqueue_scripts', array( __CLASS__, 'enqueue_cascade_layers' ) );
add_action(
$action_hook_name,
array( __CLASS__, 'render_registered_block_supports_styles' ),
array( __CLASS__, 'enqueue_cascade_layers' ),
$priority
);
}
Expand Down
10 changes: 6 additions & 4 deletions packages/style-engine/class-wp-style-engine-store.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,23 +43,25 @@ public function __construct( $layers = array() ) {
* @param string $layer Unique key for a layer.
* @param string $key Unique key for a $style_data object.
* @param array $style_data Associative array of style information.
* @return void
* @return boolean Whether registration was successful.
*/
public function register( $layer, $key, $style_data ) {
if ( empty( $layer ) || empty( $key ) || empty( $style_data ) ) {
return;
return false;
}

if ( isset( $this->registered_styles[ $layer ][ $key ] ) ) {
$style_data = array_unique( array_merge( $this->registered_styles[ $layer ][ $key ], $style_data ) );
}
$this->registered_styles[ $layer ][ $key ] = $style_data;
return true;
}

/**
* Retrieves style data from the store.
* Retrieves style data from the store. If neither $layer nor $key are provided,
* this method will return everything in the store.
*
* @param string $layer Unique key for a layer.
* @param string $layer Optional unique key for a layer to return all styles for a layer.
* @param string $key Optional unique key for a $style_data object to return a single style object.
*
* @return array Registered styles
Expand Down
15 changes: 8 additions & 7 deletions packages/style-engine/class-wp-style-engine.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
/**
* WP_Style_Engine
*
* Singleton.
* Generates classnames and block styles.
*
* @package Gutenberg
Expand Down Expand Up @@ -39,8 +40,11 @@ class WP_Style_Engine {

/**
* An ordered list of style layers from least specific to most specific.
* The layers loosely represent a cascade layer system.
* The layers loosely represent a cascade layer system. See: https://developer.mozilla.org/en-US/docs/Web/CSS/@layer
* The layer name will also be the key to retrieve the corresponding styles from the store.
* Using a "store" for each layer of the style hierarchy, one can control the order in which they're rendered.
*
* @TODO are static, named layers dynamic enough? Or should we define numerically according specificity? E.g., @wp-layer-1?
*/
const STYLE_LAYERS = array(
'block-supports', // User-defined block-level overrides.
Expand Down Expand Up @@ -235,12 +239,9 @@ class WP_Style_Engine {
* Gather internals.
*/
public function __construct() {
// @TODO not sure where to instantiate stuff or whether to dependency inject yet.
// The hope is to have several "stores" for each layer of the style hierarchy.
// This is so we can control the order in which we render.
// Each store might have a unique way to render on the frontend, maybe not.
// @TODO not sure where keep as singleton or whether to dependency inject yet.
$this->styles_store = new WP_Style_Engine_Store( self::STYLE_LAYERS );
WP_Style_Engine_Renderer::enqueue_block_support_styles();
WP_Style_Engine_Renderer::enqueue_registered_styles();
}

/**
Expand Down Expand Up @@ -280,7 +281,7 @@ public function register_styles( $layer, $key, $style_data ) {
* @param string $layer Unique key for a layer.
* @return array All registered block support styles.
*/
public function get_registered_styles( $layer ) {
public function get_registered_styles( $layer = null ) {
return $this->styles_store->get( $layer );
}

Expand Down

0 comments on commit c72366e

Please sign in to comment.