diff --git a/docs/manifest.json b/docs/manifest.json
index 3ab1908240867..c5deaa3b4b3f0 100644
--- a/docs/manifest.json
+++ b/docs/manifest.json
@@ -1745,6 +1745,12 @@
"markdown_source": "../packages/shortcode/README.md",
"parent": "packages"
},
+ {
+ "title": "@wordpress/style-engine",
+ "slug": "packages-style-engine",
+ "markdown_source": "../packages/style-engine/README.md",
+ "parent": "packages"
+ },
{
"title": "@wordpress/stylelint-config",
"slug": "packages-stylelint-config",
diff --git a/package-lock.json b/package-lock.json
index 0c3802a1fab78..d6a88a9e466f8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15744,6 +15744,7 @@
"@wordpress/notices": "file:packages/notices",
"@wordpress/rich-text": "file:packages/rich-text",
"@wordpress/shortcode": "file:packages/shortcode",
+ "@wordpress/style-engine": "file:packages/style-engine",
"@wordpress/token-list": "file:packages/token-list",
"@wordpress/url": "file:packages/url",
"@wordpress/warning": "file:packages/warning",
@@ -16215,6 +16216,7 @@
"@wordpress/notices": "file:packages/notices",
"@wordpress/plugins": "file:packages/plugins",
"@wordpress/reusable-blocks": "file:packages/reusable-blocks",
+ "@wordpress/style-engine": "file:packages/style-engine",
"@wordpress/url": "file:packages/url",
"@wordpress/viewport": "file:packages/viewport",
"classnames": "^2.3.1",
@@ -16911,6 +16913,13 @@
"memize": "^1.1.0"
}
},
+ "@wordpress/style-engine": {
+ "version": "file:packages/style-engine",
+ "requires": {
+ "@babel/runtime": "^7.16.0",
+ "lodash": "^4.17.21"
+ }
+ },
"@wordpress/stylelint-config": {
"version": "file:packages/stylelint-config",
"dev": true,
diff --git a/package.json b/package.json
index ab2f863cc4530..6895168e5a3bc 100755
--- a/package.json
+++ b/package.json
@@ -76,6 +76,7 @@
"@wordpress/rich-text": "file:packages/rich-text",
"@wordpress/server-side-render": "file:packages/server-side-render",
"@wordpress/shortcode": "file:packages/shortcode",
+ "@wordpress/style-engine": "file:packages/style-engine",
"@wordpress/token-list": "file:packages/token-list",
"@wordpress/url": "file:packages/url",
"@wordpress/viewport": "file:packages/viewport",
diff --git a/packages/block-editor/package.json b/packages/block-editor/package.json
index c8d527323e527..ee27b0305da0a 100644
--- a/packages/block-editor/package.json
+++ b/packages/block-editor/package.json
@@ -53,6 +53,7 @@
"@wordpress/notices": "file:../notices",
"@wordpress/rich-text": "file:../rich-text",
"@wordpress/shortcode": "file:../shortcode",
+ "@wordpress/style-engine": "file:../style-engine",
"@wordpress/token-list": "file:../token-list",
"@wordpress/url": "file:../url",
"@wordpress/warning": "file:../warning",
diff --git a/packages/block-editor/src/hooks/style.js b/packages/block-editor/src/hooks/style.js
index 5882d5275937b..c6f0ee91a2f2b 100644
--- a/packages/block-editor/src/hooks/style.js
+++ b/packages/block-editor/src/hooks/style.js
@@ -27,6 +27,7 @@ import {
__EXPERIMENTAL_ELEMENTS as ELEMENTS,
} from '@wordpress/blocks';
import { createHigherOrderComponent, useInstanceId } from '@wordpress/compose';
+import { getCSSRules } from '@wordpress/style-engine';
/**
* Internal dependencies
@@ -85,21 +86,35 @@ export function getInlineStyles( styles = {} ) {
// option and backwards compatibility for border radius support.
const styleValue = get( styles, path );
- if ( !! subPaths && ! isString( styleValue ) ) {
- Object.entries( subPaths ).forEach( ( entry ) => {
- const [ name, subPath ] = entry;
- const value = get( styleValue, [ subPath ] );
-
- if ( value ) {
- output[ name ] = compileStyleValue( value );
- }
- } );
- } else if ( ! ignoredStyles.includes( path.join( '.' ) ) ) {
- output[ propKey ] = compileStyleValue( get( styles, path ) );
+ if ( ! STYLE_PROPERTY[ propKey ].useEngine ) {
+ if ( !! subPaths && ! isString( styleValue ) ) {
+ Object.entries( subPaths ).forEach( ( entry ) => {
+ const [ name, subPath ] = entry;
+ const value = get( styleValue, [ subPath ] );
+
+ if ( value ) {
+ output[ name ] = compileStyleValue( value );
+ }
+ } );
+ } else if ( ! ignoredStyles.includes( path.join( '.' ) ) ) {
+ output[ propKey ] = compileStyleValue(
+ get( styles, path )
+ );
+ }
}
}
} );
+ // 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( styles, { selector: 'self' } );
+ extraRules.forEach( ( rule ) => {
+ if ( rule.selector !== 'self' ) {
+ throw "This style can't be added as inline style";
+ }
+ output[ rule.key ] = rule.value;
+ } );
+
return output;
}
diff --git a/packages/blocks/src/api/constants.js b/packages/blocks/src/api/constants.js
index 674caea6af4c9..a237402e143f9 100644
--- a/packages/blocks/src/api/constants.js
+++ b/packages/blocks/src/api/constants.js
@@ -99,6 +99,7 @@ export const __EXPERIMENTAL_STYLE_PROPERTY = {
paddingBottom: 'bottom',
paddingLeft: 'left',
},
+ useEngine: true,
},
textDecoration: {
value: [ 'typography', 'textDecoration' ],
diff --git a/packages/dependency-extraction-webpack-plugin/lib/util.js b/packages/dependency-extraction-webpack-plugin/lib/util.js
index a22837af6a72e..87d67f8dbd68f 100644
--- a/packages/dependency-extraction-webpack-plugin/lib/util.js
+++ b/packages/dependency-extraction-webpack-plugin/lib/util.js
@@ -1,5 +1,9 @@
const WORDPRESS_NAMESPACE = '@wordpress/';
-const BUNDLED_PACKAGES = [ '@wordpress/icons', '@wordpress/interface' ];
+const BUNDLED_PACKAGES = [
+ '@wordpress/icons',
+ '@wordpress/interface',
+ '@wordpress/style-engine',
+];
/**
* Default request to global transformation
diff --git a/packages/edit-site/package.json b/packages/edit-site/package.json
index 698f6234e0bae..23b01517c6f6b 100644
--- a/packages/edit-site/package.json
+++ b/packages/edit-site/package.json
@@ -50,6 +50,7 @@
"@wordpress/notices": "file:../notices",
"@wordpress/plugins": "file:../plugins",
"@wordpress/reusable-blocks": "file:../reusable-blocks",
+ "@wordpress/style-engine": "file:../style-engine",
"@wordpress/url": "file:../url",
"@wordpress/viewport": "file:../viewport",
"classnames": "^2.3.1",
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 b3ca7bd9ba016..72ed5a5afe32e 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
@@ -23,6 +23,7 @@ import {
getBlockTypes,
} from '@wordpress/blocks';
import { useEffect, useState, useContext } from '@wordpress/element';
+import { getCSSRules } from '@wordpress/style-engine';
/**
* Internal dependencies
@@ -146,11 +147,11 @@ function flattenTree( input = {}, prefix, token ) {
* @return {Array} An array of style declarations.
*/
function getStylesDeclarations( blockStyles = {} ) {
- return reduce(
+ const output = reduce(
STYLE_PROPERTY,
- ( declarations, { value, properties }, key ) => {
+ ( declarations, { value, properties, useEngine }, key ) => {
const pathToValue = value;
- if ( first( pathToValue ) === 'elements' ) {
+ if ( first( pathToValue ) === 'elements' || useEngine ) {
return declarations;
}
@@ -188,6 +189,21 @@ function getStylesDeclarations( blockStyles = {} ) {
},
[]
);
+
+ // 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, { selector: 'self' } );
+ extraRules.forEach( ( rule ) => {
+ if ( rule.selector !== 'self' ) {
+ throw "This style can't be added as inline style";
+ }
+ const cssProperty = rule.key.startsWith( '--' )
+ ? rule.key
+ : kebabCase( rule.key );
+ output.push( `${ cssProperty }: ${ compileStyleValue( rule.value ) }` );
+ } );
+
+ return output;
}
export const getNodesWithStyles = ( tree, blockSelectors ) => {
diff --git a/packages/style-engine/.npmrc b/packages/style-engine/.npmrc
new file mode 100644
index 0000000000000..43c97e719a5a8
--- /dev/null
+++ b/packages/style-engine/.npmrc
@@ -0,0 +1 @@
+package-lock=false
diff --git a/packages/style-engine/CHANGELOG.md b/packages/style-engine/CHANGELOG.md
new file mode 100644
index 0000000000000..6367d4fc4b6ce
--- /dev/null
+++ b/packages/style-engine/CHANGELOG.md
@@ -0,0 +1,7 @@
+
+
+## Unreleased
+
+### New Feature
+
+- Added initial version of the style engine ([#37978](https://github.com/WordPress/gutenberg/pull/37978)).
diff --git a/packages/style-engine/README.md b/packages/style-engine/README.md
new file mode 100644
index 0000000000000..612097cc49735
--- /dev/null
+++ b/packages/style-engine/README.md
@@ -0,0 +1,62 @@
+# Style Engine
+
+The Style Engine powering global styles and block customizations.
+
+## Installation
+
+Install the module
+
+```bash
+npm install @wordpress/style-engine --save
+```
+
+_This package assumes that your code will run in an **ES2015+** environment. If you're using an environment that has limited or no support for such language features and APIs, you should include [the polyfill shipped in `@wordpress/babel-preset-default`](https://github.com/WordPress/gutenberg/tree/HEAD/packages/babel-preset-default#polyfill) in your code._
+
+## Important
+
+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:
+
+**TODO List:**
+
+- Add style definitions for all the currently supported styles in blocks and theme.json.
+- the CSS variable shortcuts for values (for presets...)
+- Support generating styles in the frontend.
+- Support generating styles in the backend (block supports and theme.json stylesheet).
+- Refactor all block styles to use the style engine server side.
+- Refactor all blocks to consistently use the "style" attribute for all customizations (get rid of the preset specific attributes).
+
+## Usage
+
+
+
+### generate
+
+Generates a stylesheet for a given style object and selector.
+
+_Parameters_
+
+- _style_ `Style`: Style object.
+- _options_ `StyleOptions`: Options object with settings to adjust how the styles are generated.
+
+_Returns_
+
+- `string`: generated stylesheet.
+
+### getCSSRules
+
+Returns a JSON representation of the generated CSS rules.
+
+_Parameters_
+
+- _style_ `Style`: Style object.
+- _options_ `StyleOptions`: Options object with settings to adjust how the styles are generated.
+
+_Returns_
+
+- `GeneratedCSSRule[]`: generated styles.
+
+
+
+