@wordpress/style-engine 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2 -0
- package/README.md +4 -4
- package/class-wp-style-engine.php +288 -83
- package/package.json +2 -2
- package/phpunit/class-wp-style-engine-test.php +154 -6
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The Style Engine powering global styles and block customizations.
|
|
4
4
|
|
|
5
|
-
## Installation
|
|
5
|
+
## Installation (JS only)
|
|
6
6
|
|
|
7
7
|
Install the module
|
|
8
8
|
|
|
@@ -22,9 +22,9 @@ Currently it's not a package that generates a wp.styleEngine global because it's
|
|
|
22
22
|
|
|
23
23
|
- Add style definitions for all the currently supported styles in blocks and theme.json.
|
|
24
24
|
- the CSS variable shortcuts for values (for presets...)
|
|
25
|
-
- Support generating styles in the frontend.
|
|
26
|
-
- Support generating styles in the backend (block supports and theme.json stylesheet).
|
|
27
|
-
- Refactor all block styles to use the style engine server side.
|
|
25
|
+
- Support generating styles in the frontend. (Ongoing)
|
|
26
|
+
- Support generating styles in the backend (block supports and theme.json stylesheet). (Ongoing)
|
|
27
|
+
- Refactor all block styles to use the style engine server side. (Ongoing)
|
|
28
28
|
- Refactor all blocks to consistently use the "style" attribute for all customizations (get rid of the preset specific attributes).
|
|
29
29
|
|
|
30
30
|
## Usage
|
|
@@ -34,87 +34,183 @@ class WP_Style_Engine {
|
|
|
34
34
|
* Style definitions that contain the instructions to
|
|
35
35
|
* parse/output valid Gutenberg styles from a block's attributes.
|
|
36
36
|
* For every style definition, the follow properties are valid:
|
|
37
|
-
* - classnames
|
|
38
|
-
* A value of `true` means the classname should be applied always. Otherwise a valid CSS property
|
|
39
|
-
* to match the incoming value, e.g., "color" to match var:preset|color|
|
|
40
|
-
* -
|
|
41
|
-
*
|
|
37
|
+
* - classnames => (array) an array of classnames to be returned for block styles. The key is a classname or pattern.
|
|
38
|
+
* A value of `true` means the classname should be applied always. Otherwise, a valid CSS property (string)
|
|
39
|
+
* to match the incoming value, e.g., "color" to match var:preset|color|somePresetSlug.
|
|
40
|
+
* - css_vars => (array) an array of key value pairs used to generate CSS var values. The key is a CSS var pattern, whose `$slug` fragment will be replaced with a preset slug.
|
|
41
|
+
* The value should be a valid CSS property (string) to match the incoming value, e.g., "color" to match var:preset|color|somePresetSlug.
|
|
42
|
+
* - property_keys => (array) array of keys whose values represent a valid CSS property, e.g., "margin" or "border".
|
|
43
|
+
* - path => (array) a path that accesses the corresponding style value in the block style object.
|
|
44
|
+
* - value_func => (string) the name of a function to generate an array of valid CSS rules for a particular style object.
|
|
42
45
|
*/
|
|
43
46
|
const BLOCK_STYLE_DEFINITIONS_METADATA = array(
|
|
44
47
|
'color' => array(
|
|
45
48
|
'text' => array(
|
|
46
|
-
'
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
'property_keys' => array(
|
|
50
|
+
'default' => 'color',
|
|
51
|
+
),
|
|
52
|
+
'path' => array( 'color', 'text' ),
|
|
53
|
+
'css_vars' => array(
|
|
54
|
+
'--wp--preset--color--$slug' => 'color',
|
|
55
|
+
),
|
|
56
|
+
'classnames' => array(
|
|
57
|
+
'has-text-color' => true,
|
|
58
|
+
'has-$slug-color' => 'color',
|
|
51
59
|
),
|
|
52
60
|
),
|
|
53
61
|
'background' => array(
|
|
54
|
-
'
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
62
|
+
'property_keys' => array(
|
|
63
|
+
'default' => 'background-color',
|
|
64
|
+
),
|
|
65
|
+
'path' => array( 'color', 'background' ),
|
|
66
|
+
'classnames' => array(
|
|
67
|
+
'has-background' => true,
|
|
68
|
+
'has-$slug-background-color' => 'color',
|
|
59
69
|
),
|
|
60
70
|
),
|
|
61
71
|
'gradient' => array(
|
|
62
|
-
'
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
72
|
+
'property_keys' => array(
|
|
73
|
+
'default' => 'background',
|
|
74
|
+
),
|
|
75
|
+
'path' => array( 'color', 'gradient' ),
|
|
76
|
+
'classnames' => array(
|
|
77
|
+
'has-background' => true,
|
|
78
|
+
'has-$slug-gradient-background' => 'gradient',
|
|
79
|
+
),
|
|
80
|
+
),
|
|
81
|
+
),
|
|
82
|
+
'border' => array(
|
|
83
|
+
'color' => array(
|
|
84
|
+
'property_keys' => array(
|
|
85
|
+
'default' => 'border-color',
|
|
86
|
+
'individual' => 'border-%s-color',
|
|
87
|
+
),
|
|
88
|
+
'path' => array( 'border', 'color' ),
|
|
89
|
+
'classnames' => array(
|
|
90
|
+
'has-border-color' => true,
|
|
91
|
+
'has-$slug-border-color' => 'color',
|
|
92
|
+
),
|
|
93
|
+
),
|
|
94
|
+
'radius' => array(
|
|
95
|
+
'property_keys' => array(
|
|
96
|
+
'default' => 'border-radius',
|
|
97
|
+
'individual' => 'border-%s-radius',
|
|
98
|
+
),
|
|
99
|
+
'path' => array( 'border', 'radius' ),
|
|
100
|
+
),
|
|
101
|
+
'style' => array(
|
|
102
|
+
'property_keys' => array(
|
|
103
|
+
'default' => 'border-style',
|
|
104
|
+
'individual' => 'border-%s-style',
|
|
105
|
+
),
|
|
106
|
+
'path' => array( 'border', 'style' ),
|
|
107
|
+
),
|
|
108
|
+
'width' => array(
|
|
109
|
+
'property_keys' => array(
|
|
110
|
+
'default' => 'border-width',
|
|
111
|
+
'individual' => 'border-%s-width',
|
|
112
|
+
),
|
|
113
|
+
'path' => array( 'border', 'width' ),
|
|
114
|
+
),
|
|
115
|
+
'top' => array(
|
|
116
|
+
'value_func' => 'static::get_css_individual_property_rules',
|
|
117
|
+
'path' => array( 'border', 'top' ),
|
|
118
|
+
'css_vars' => array(
|
|
119
|
+
'color' => '--wp--preset--color--$slug',
|
|
120
|
+
),
|
|
121
|
+
),
|
|
122
|
+
'right' => array(
|
|
123
|
+
'value_func' => 'static::get_css_individual_property_rules',
|
|
124
|
+
'path' => array( 'border', 'right' ),
|
|
125
|
+
'css_vars' => array(
|
|
126
|
+
'color' => '--wp--preset--color--$slug',
|
|
127
|
+
),
|
|
128
|
+
),
|
|
129
|
+
'bottom' => array(
|
|
130
|
+
'value_func' => 'static::get_css_individual_property_rules',
|
|
131
|
+
'path' => array( 'border', 'bottom' ),
|
|
132
|
+
'css_vars' => array(
|
|
133
|
+
'color' => '--wp--preset--color--$slug',
|
|
134
|
+
),
|
|
135
|
+
),
|
|
136
|
+
'left' => array(
|
|
137
|
+
'value_func' => 'static::get_css_individual_property_rules',
|
|
138
|
+
'path' => array( 'border', 'left' ),
|
|
139
|
+
'css_vars' => array(
|
|
140
|
+
'color' => '--wp--preset--color--$slug',
|
|
67
141
|
),
|
|
68
142
|
),
|
|
69
143
|
),
|
|
70
144
|
'spacing' => array(
|
|
71
145
|
'padding' => array(
|
|
72
|
-
'
|
|
73
|
-
|
|
146
|
+
'property_keys' => array(
|
|
147
|
+
'default' => 'padding',
|
|
148
|
+
'individual' => 'padding-%s',
|
|
149
|
+
),
|
|
150
|
+
'path' => array( 'spacing', 'padding' ),
|
|
74
151
|
),
|
|
75
152
|
'margin' => array(
|
|
76
|
-
'
|
|
77
|
-
|
|
153
|
+
'property_keys' => array(
|
|
154
|
+
'default' => 'margin',
|
|
155
|
+
'individual' => 'margin-%s',
|
|
156
|
+
),
|
|
157
|
+
'path' => array( 'spacing', 'margin' ),
|
|
78
158
|
),
|
|
79
159
|
),
|
|
80
160
|
'typography' => array(
|
|
81
161
|
'fontSize' => array(
|
|
82
|
-
'
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
162
|
+
'property_keys' => array(
|
|
163
|
+
'default' => 'font-size',
|
|
164
|
+
),
|
|
165
|
+
'path' => array( 'typography', 'fontSize' ),
|
|
166
|
+
'classnames' => array(
|
|
167
|
+
'has-$slug-font-size' => 'font-size',
|
|
86
168
|
),
|
|
87
169
|
),
|
|
88
170
|
'fontFamily' => array(
|
|
89
|
-
'
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
171
|
+
'property_keys' => array(
|
|
172
|
+
'default' => 'font-family',
|
|
173
|
+
),
|
|
174
|
+
'path' => array( 'typography', 'fontFamily' ),
|
|
175
|
+
'classnames' => array(
|
|
176
|
+
'has-$slug-font-family' => 'font-family',
|
|
93
177
|
),
|
|
94
178
|
),
|
|
95
179
|
'fontStyle' => array(
|
|
96
|
-
'
|
|
97
|
-
|
|
180
|
+
'property_keys' => array(
|
|
181
|
+
'default' => 'font-style',
|
|
182
|
+
),
|
|
183
|
+
'path' => array( 'typography', 'fontStyle' ),
|
|
98
184
|
),
|
|
99
185
|
'fontWeight' => array(
|
|
100
|
-
'
|
|
101
|
-
|
|
186
|
+
'property_keys' => array(
|
|
187
|
+
'default' => 'font-weight',
|
|
188
|
+
),
|
|
189
|
+
'path' => array( 'typography', 'fontWeight' ),
|
|
102
190
|
),
|
|
103
191
|
'lineHeight' => array(
|
|
104
|
-
'
|
|
105
|
-
|
|
192
|
+
'property_keys' => array(
|
|
193
|
+
'default' => 'line-height',
|
|
194
|
+
),
|
|
195
|
+
'path' => array( 'typography', 'lineHeight' ),
|
|
106
196
|
),
|
|
107
197
|
'textDecoration' => array(
|
|
108
|
-
'
|
|
109
|
-
|
|
198
|
+
'property_keys' => array(
|
|
199
|
+
'default' => 'text-decoration',
|
|
200
|
+
),
|
|
201
|
+
'path' => array( 'typography', 'textDecoration' ),
|
|
110
202
|
),
|
|
111
203
|
'textTransform' => array(
|
|
112
|
-
'
|
|
113
|
-
|
|
204
|
+
'property_keys' => array(
|
|
205
|
+
'default' => 'text-transform',
|
|
206
|
+
),
|
|
207
|
+
'path' => array( 'typography', 'textTransform' ),
|
|
114
208
|
),
|
|
115
209
|
'letterSpacing' => array(
|
|
116
|
-
'
|
|
117
|
-
|
|
210
|
+
'property_keys' => array(
|
|
211
|
+
'default' => 'letter-spacing',
|
|
212
|
+
),
|
|
213
|
+
'path' => array( 'typography', 'letterSpacing' ),
|
|
118
214
|
),
|
|
119
215
|
),
|
|
120
216
|
);
|
|
@@ -137,8 +233,8 @@ class WP_Style_Engine {
|
|
|
137
233
|
/**
|
|
138
234
|
* Extracts the slug in kebab case from a preset string, e.g., "heavenly-blue" from 'var:preset|color|heavenlyBlue'.
|
|
139
235
|
*
|
|
140
|
-
* @param string $style_value A single css preset value.
|
|
141
|
-
* @param string
|
|
236
|
+
* @param string? $style_value A single css preset value.
|
|
237
|
+
* @param string $property_key The CSS property that is the second element of the preset string. Used for matching.
|
|
142
238
|
*
|
|
143
239
|
* @return string|null The slug, or null if not found.
|
|
144
240
|
*/
|
|
@@ -150,6 +246,25 @@ class WP_Style_Engine {
|
|
|
150
246
|
return null;
|
|
151
247
|
}
|
|
152
248
|
|
|
249
|
+
/**
|
|
250
|
+
* Checks whether an incoming style value is valid.
|
|
251
|
+
*
|
|
252
|
+
* @param string? $style_value A single css preset value.
|
|
253
|
+
*
|
|
254
|
+
* @return boolean
|
|
255
|
+
*/
|
|
256
|
+
protected static function is_valid_style_value( $style_value ) {
|
|
257
|
+
if ( '0' === $style_value ) {
|
|
258
|
+
return true;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if ( empty( $style_value ) ) {
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
|
|
153
268
|
/**
|
|
154
269
|
* Returns classnames, and generates classname(s) from a CSS preset property pattern, e.g., 'var:preset|color|heavenly-blue'.
|
|
155
270
|
*
|
|
@@ -160,6 +275,11 @@ class WP_Style_Engine {
|
|
|
160
275
|
*/
|
|
161
276
|
protected static function get_classnames( $style_value, $style_definition ) {
|
|
162
277
|
$classnames = array();
|
|
278
|
+
|
|
279
|
+
if ( empty( $style_value ) ) {
|
|
280
|
+
return $classnames;
|
|
281
|
+
}
|
|
282
|
+
|
|
163
283
|
if ( ! empty( $style_definition['classnames'] ) ) {
|
|
164
284
|
foreach ( $style_definition['classnames'] as $classname => $property_key ) {
|
|
165
285
|
if ( true === $property_key ) {
|
|
@@ -173,7 +293,7 @@ class WP_Style_Engine {
|
|
|
173
293
|
// One day, if there are no stored schemata, we could allow custom patterns or
|
|
174
294
|
// generate classnames based on other properties
|
|
175
295
|
// such as a path or a value or a prefix passed in options.
|
|
176
|
-
$classnames[] =
|
|
296
|
+
$classnames[] = strtr( $classname, array( '$slug' => $slug ) );
|
|
177
297
|
}
|
|
178
298
|
}
|
|
179
299
|
}
|
|
@@ -186,17 +306,53 @@ class WP_Style_Engine {
|
|
|
186
306
|
*
|
|
187
307
|
* @param array $style_value A single raw style value from the generate() $block_styles array.
|
|
188
308
|
* @param array<string> $style_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA.
|
|
309
|
+
* @param boolean $should_return_css_vars Whether to try to build and return CSS var values.
|
|
189
310
|
*
|
|
190
311
|
* @return array An array of CSS rules.
|
|
191
312
|
*/
|
|
192
|
-
protected static function get_css( $style_value, $style_definition ) {
|
|
193
|
-
|
|
313
|
+
protected static function get_css( $style_value, $style_definition, $should_return_css_vars ) {
|
|
314
|
+
$rules = array();
|
|
315
|
+
|
|
316
|
+
if (
|
|
317
|
+
isset( $style_definition['value_func'] ) &&
|
|
318
|
+
is_callable( $style_definition['value_func'] )
|
|
319
|
+
) {
|
|
320
|
+
return call_user_func( $style_definition['value_func'], $style_value, $style_definition );
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
$style_properties = $style_definition['property_keys'];
|
|
324
|
+
|
|
325
|
+
// Build CSS var values from var:? values, e.g, `var(--wp--css--rule-slug )`
|
|
326
|
+
// Check if the value is a CSS preset and there's a corresponding css_var pattern in the style definition.
|
|
194
327
|
if ( is_string( $style_value ) && strpos( $style_value, 'var:' ) !== false ) {
|
|
195
|
-
|
|
328
|
+
if ( $should_return_css_vars && ! empty( $style_definition['css_vars'] ) ) {
|
|
329
|
+
foreach ( $style_definition['css_vars'] as $css_var_pattern => $property_key ) {
|
|
330
|
+
$slug = static::get_slug_from_preset_value( $style_value, $property_key );
|
|
331
|
+
if ( $slug ) {
|
|
332
|
+
$css_var = strtr(
|
|
333
|
+
$css_var_pattern,
|
|
334
|
+
array( '$slug' => $slug )
|
|
335
|
+
);
|
|
336
|
+
$rules[ $style_properties['default'] ] = "var($css_var)";
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
return $rules;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Default rule builder.
|
|
344
|
+
// If the input contains an array, assume box model-like properties
|
|
345
|
+
// for styles such as margins and padding.
|
|
346
|
+
if ( is_array( $style_value ) ) {
|
|
347
|
+
foreach ( $style_value as $key => $value ) {
|
|
348
|
+
$individual_property = sprintf( $style_properties['individual'], _wp_to_kebab_case( $key ) );
|
|
349
|
+
$rules[ $individual_property ] = $value;
|
|
350
|
+
}
|
|
351
|
+
} else {
|
|
352
|
+
$rules[ $style_properties['default'] ] = $style_value;
|
|
196
353
|
}
|
|
197
354
|
|
|
198
|
-
|
|
199
|
-
return static::get_css_rules( $style_value, $style_definition['property_key'] );
|
|
355
|
+
return $rules;
|
|
200
356
|
}
|
|
201
357
|
|
|
202
358
|
/**
|
|
@@ -204,53 +360,71 @@ class WP_Style_Engine {
|
|
|
204
360
|
* Styles are bundled based on the instructions in BLOCK_STYLE_DEFINITIONS_METADATA.
|
|
205
361
|
*
|
|
206
362
|
* @param array $block_styles An array of styles from a block's attributes.
|
|
363
|
+
* @param array $options array(
|
|
364
|
+
* 'selector' => (string) When a selector is passed, `generate()` will return a full CSS rule `$selector { ...rules }`, otherwise a concatenated string of properties and values.
|
|
365
|
+
* 'css_vars' => (boolean) Whether to covert CSS values to var() values. If `true` the style engine will try to parse var:? values and output var( --wp--preset--* ) rules. Default is `false`.
|
|
366
|
+
* );.
|
|
207
367
|
*
|
|
208
368
|
* @return array|null array(
|
|
209
|
-
* '
|
|
369
|
+
* 'css' => (string) A CSS ruleset formatted to be placed in an HTML `style` attribute or tag. Default is a string of inline styles.
|
|
210
370
|
* 'classnames' => (string) Classnames separated by a space.
|
|
211
371
|
* );
|
|
212
372
|
*/
|
|
213
|
-
public function generate( $block_styles ) {
|
|
373
|
+
public function generate( $block_styles, $options ) {
|
|
214
374
|
if ( empty( $block_styles ) || ! is_array( $block_styles ) ) {
|
|
215
375
|
return null;
|
|
216
376
|
}
|
|
217
377
|
|
|
218
|
-
$css_rules
|
|
219
|
-
$classnames
|
|
220
|
-
$
|
|
378
|
+
$css_rules = array();
|
|
379
|
+
$classnames = array();
|
|
380
|
+
$should_return_css_vars = isset( $options['css_vars'] ) && true === $options['css_vars'];
|
|
221
381
|
|
|
222
382
|
// Collect CSS and classnames.
|
|
223
|
-
foreach ( self::BLOCK_STYLE_DEFINITIONS_METADATA as $
|
|
224
|
-
|
|
383
|
+
foreach ( self::BLOCK_STYLE_DEFINITIONS_METADATA as $definition_group_key => $definition_group_style ) {
|
|
384
|
+
if ( empty( $block_styles[ $definition_group_key ] ) ) {
|
|
385
|
+
continue;
|
|
386
|
+
}
|
|
387
|
+
foreach ( $definition_group_style as $style_definition ) {
|
|
225
388
|
$style_value = _wp_array_get( $block_styles, $style_definition['path'], null );
|
|
226
389
|
|
|
227
|
-
if (
|
|
390
|
+
if ( ! static::is_valid_style_value( $style_value ) ) {
|
|
228
391
|
continue;
|
|
229
392
|
}
|
|
230
393
|
|
|
231
394
|
$classnames = array_merge( $classnames, static::get_classnames( $style_value, $style_definition ) );
|
|
232
|
-
$css_rules = array_merge( $css_rules, static::get_css( $style_value, $style_definition ) );
|
|
395
|
+
$css_rules = array_merge( $css_rules, static::get_css( $style_value, $style_definition, $should_return_css_vars ) );
|
|
233
396
|
}
|
|
234
397
|
}
|
|
235
398
|
|
|
236
399
|
// Build CSS rules output.
|
|
237
|
-
$
|
|
400
|
+
$selector = isset( $options['selector'] ) ? $options['selector'] : null;
|
|
401
|
+
$css = array();
|
|
402
|
+
$styles_output = array();
|
|
403
|
+
|
|
238
404
|
if ( ! empty( $css_rules ) ) {
|
|
239
405
|
// Generate inline style rules.
|
|
240
|
-
// In the future there might be a flag in the option to output
|
|
241
|
-
// inline CSS rules (for HTML style attributes) vs selectors + rules for style tags.
|
|
242
406
|
foreach ( $css_rules as $rule => $value ) {
|
|
243
407
|
$filtered_css = esc_html( safecss_filter_attr( "{$rule}: {$value}" ) );
|
|
244
408
|
if ( ! empty( $filtered_css ) ) {
|
|
245
|
-
$
|
|
409
|
+
$css[] = $filtered_css . ';';
|
|
246
410
|
}
|
|
247
411
|
}
|
|
248
412
|
}
|
|
249
413
|
|
|
250
|
-
|
|
251
|
-
|
|
414
|
+
// Return css, if any.
|
|
415
|
+
if ( ! empty( $css ) ) {
|
|
416
|
+
// Return an entire rule if there is a selector.
|
|
417
|
+
if ( $selector ) {
|
|
418
|
+
$style_block = "$selector { ";
|
|
419
|
+
$style_block .= implode( ' ', $css );
|
|
420
|
+
$style_block .= ' }';
|
|
421
|
+
$styles_output['css'] = $style_block;
|
|
422
|
+
} else {
|
|
423
|
+
$styles_output['css'] = implode( ' ', $css );
|
|
424
|
+
}
|
|
252
425
|
}
|
|
253
426
|
|
|
427
|
+
// Return classnames, if any.
|
|
254
428
|
if ( ! empty( $classnames ) ) {
|
|
255
429
|
$styles_output['classnames'] = implode( ' ', array_unique( $classnames ) );
|
|
256
430
|
}
|
|
@@ -258,32 +432,55 @@ class WP_Style_Engine {
|
|
|
258
432
|
return $styles_output;
|
|
259
433
|
}
|
|
260
434
|
|
|
435
|
+
|
|
261
436
|
/**
|
|
262
|
-
*
|
|
263
|
-
*
|
|
264
|
-
*
|
|
437
|
+
* Style value parser that returns a CSS ruleset of style properties for style definition groups
|
|
438
|
+
* that have keys representing individual style properties, otherwise known as longhand CSS properties.
|
|
439
|
+
* e.g., "$style_property-$individual_feature: $value;", which could represent the following:
|
|
440
|
+
* "border-{top|right|bottom|left}-{color|width|style}: {value};" or,
|
|
441
|
+
* "border-image-{outset|source|width|repeat|slice}: {value};"
|
|
265
442
|
*
|
|
266
|
-
* @param
|
|
267
|
-
* @param
|
|
443
|
+
* @param array $style_value A single raw Gutenberg style attributes value for a CSS property.
|
|
444
|
+
* @param array $individual_property_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA.
|
|
268
445
|
*
|
|
269
446
|
* @return array The class name for the added style.
|
|
270
447
|
*/
|
|
271
|
-
protected static function
|
|
448
|
+
protected static function get_css_individual_property_rules( $style_value, $individual_property_definition ) {
|
|
272
449
|
$rules = array();
|
|
273
450
|
|
|
274
|
-
if ( ! $style_value ) {
|
|
451
|
+
if ( ! is_array( $style_value ) || empty( $style_value ) || empty( $individual_property_definition['path'] ) ) {
|
|
275
452
|
return $rules;
|
|
276
453
|
}
|
|
277
454
|
|
|
278
|
-
//
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
455
|
+
// The first item in $individual_property_definition['path'] array tells us the style property, e.g., "border".
|
|
456
|
+
// We use this to get a corresponding CSS style definition such as "color" or "width" from the same group.
|
|
457
|
+
// The second item in $individual_property_definition['path'] array refers to the individual property marker, e.g., "top".
|
|
458
|
+
$definition_group_key = $individual_property_definition['path'][0];
|
|
459
|
+
$individual_property_key = $individual_property_definition['path'][1];
|
|
460
|
+
|
|
461
|
+
foreach ( $style_value as $css_property => $value ) {
|
|
462
|
+
if ( empty( $value ) ) {
|
|
463
|
+
continue;
|
|
282
464
|
}
|
|
283
|
-
} else {
|
|
284
|
-
$rules[ $style_property ] = $style_value;
|
|
285
|
-
}
|
|
286
465
|
|
|
466
|
+
// Build a path to the individual rules in definitions.
|
|
467
|
+
$style_definition_path = array( $definition_group_key, $css_property );
|
|
468
|
+
$style_definition = _wp_array_get( self::BLOCK_STYLE_DEFINITIONS_METADATA, $style_definition_path, null );
|
|
469
|
+
|
|
470
|
+
if ( $style_definition && isset( $style_definition['property_keys']['individual'] ) ) {
|
|
471
|
+
// Set a CSS var if there is a valid preset value.
|
|
472
|
+
$slug = isset( $individual_property_definition['css_vars'][ $css_property ] ) ? static::get_slug_from_preset_value( $value, $css_property ) : null;
|
|
473
|
+
if ( $slug ) {
|
|
474
|
+
$css_var = strtr(
|
|
475
|
+
$individual_property_definition['css_vars'][ $css_property ],
|
|
476
|
+
array( '$slug' => $slug )
|
|
477
|
+
);
|
|
478
|
+
$value = "var($css_var)";
|
|
479
|
+
}
|
|
480
|
+
$individual_css_property = sprintf( $style_definition['property_keys']['individual'], $individual_property_key );
|
|
481
|
+
$rules[ $individual_css_property ] = $value;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
287
484
|
return $rules;
|
|
288
485
|
}
|
|
289
486
|
}
|
|
@@ -294,17 +491,25 @@ class WP_Style_Engine {
|
|
|
294
491
|
* Returns an CSS ruleset.
|
|
295
492
|
* Styles are bundled based on the instructions in BLOCK_STYLE_DEFINITIONS_METADATA.
|
|
296
493
|
*
|
|
494
|
+
* Example usage:
|
|
495
|
+
*
|
|
496
|
+
* $styles = wp_style_engine_generate( array( 'color' => array( 'text' => '#cccccc' ) ) );
|
|
497
|
+
* // Returns `'color: #cccccc'`.
|
|
498
|
+
*
|
|
499
|
+
* @access public
|
|
500
|
+
*
|
|
297
501
|
* @param array $block_styles An array of styles from a block's attributes.
|
|
502
|
+
* @param array $options An array of options to determine the output.
|
|
298
503
|
*
|
|
299
504
|
* @return array|null array(
|
|
300
505
|
* 'styles' => (string) A CSS ruleset formatted to be placed in an HTML `style` attribute or tag.
|
|
301
506
|
* 'classnames' => (string) Classnames separated by a space.
|
|
302
507
|
* );
|
|
303
508
|
*/
|
|
304
|
-
function wp_style_engine_generate( $block_styles ) {
|
|
509
|
+
function wp_style_engine_generate( $block_styles, $options = array() ) {
|
|
305
510
|
if ( class_exists( 'WP_Style_Engine' ) ) {
|
|
306
511
|
$style_engine = WP_Style_Engine::get_instance();
|
|
307
|
-
return $style_engine->generate( $block_styles );
|
|
512
|
+
return $style_engine->generate( $block_styles, $options );
|
|
308
513
|
}
|
|
309
514
|
return null;
|
|
310
515
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordpress/style-engine",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "WordPress Style engine.",
|
|
5
5
|
"author": "The WordPress Contributors",
|
|
6
6
|
"license": "GPL-2.0-or-later",
|
|
@@ -34,5 +34,5 @@
|
|
|
34
34
|
"publishConfig": {
|
|
35
35
|
"access": "public"
|
|
36
36
|
},
|
|
37
|
-
"gitHead": "
|
|
37
|
+
"gitHead": "48d5f37dfb52d2e77c8eeb662f9874cf141b8c6b"
|
|
38
38
|
}
|
|
@@ -17,8 +17,8 @@ class WP_Style_Engine_Test extends WP_UnitTestCase {
|
|
|
17
17
|
*
|
|
18
18
|
* @dataProvider data_generate_styles_fixtures
|
|
19
19
|
*/
|
|
20
|
-
function test_generate_styles( $block_styles, $expected_output ) {
|
|
21
|
-
$generated_styles = wp_style_engine_generate( $block_styles );
|
|
20
|
+
function test_generate_styles( $block_styles, $options, $expected_output ) {
|
|
21
|
+
$generated_styles = wp_style_engine_generate( $block_styles, $options );
|
|
22
22
|
$this->assertSame( $expected_output, $generated_styles );
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -31,11 +31,13 @@ class WP_Style_Engine_Test extends WP_UnitTestCase {
|
|
|
31
31
|
return array(
|
|
32
32
|
'default_return_value' => array(
|
|
33
33
|
'block_styles' => array(),
|
|
34
|
+
'options' => null,
|
|
34
35
|
'expected_output' => null,
|
|
35
36
|
),
|
|
36
37
|
|
|
37
38
|
'inline_invalid_block_styles_empty' => array(
|
|
38
39
|
'block_styles' => 'hello world!',
|
|
40
|
+
'options' => null,
|
|
39
41
|
'expected_output' => null,
|
|
40
42
|
),
|
|
41
43
|
|
|
@@ -43,6 +45,7 @@ class WP_Style_Engine_Test extends WP_UnitTestCase {
|
|
|
43
45
|
'block_styles' => array(
|
|
44
46
|
'pageBreakAfter' => 'verso',
|
|
45
47
|
),
|
|
48
|
+
'options' => null,
|
|
46
49
|
'expected_output' => array(),
|
|
47
50
|
),
|
|
48
51
|
|
|
@@ -50,6 +53,7 @@ class WP_Style_Engine_Test extends WP_UnitTestCase {
|
|
|
50
53
|
'block_styles' => array(
|
|
51
54
|
'pageBreakAfter' => 'verso',
|
|
52
55
|
),
|
|
56
|
+
'options' => null,
|
|
53
57
|
'expected_output' => array(),
|
|
54
58
|
),
|
|
55
59
|
|
|
@@ -59,6 +63,7 @@ class WP_Style_Engine_Test extends WP_UnitTestCase {
|
|
|
59
63
|
'gap' => '1000vw',
|
|
60
64
|
),
|
|
61
65
|
),
|
|
66
|
+
'options' => null,
|
|
62
67
|
'expected_output' => array(),
|
|
63
68
|
),
|
|
64
69
|
|
|
@@ -68,12 +73,19 @@ class WP_Style_Engine_Test extends WP_UnitTestCase {
|
|
|
68
73
|
'text' => 'var:preset|color|texas-flood',
|
|
69
74
|
),
|
|
70
75
|
'spacing' => array(
|
|
71
|
-
'margin'
|
|
76
|
+
'margin' => '111px',
|
|
77
|
+
'padding' => '0',
|
|
78
|
+
),
|
|
79
|
+
'border' => array(
|
|
80
|
+
'color' => 'var:preset|color|cool-caramel',
|
|
81
|
+
'width' => '2rem',
|
|
82
|
+
'style' => 'dotted',
|
|
72
83
|
),
|
|
73
84
|
),
|
|
85
|
+
'options' => array(),
|
|
74
86
|
'expected_output' => array(
|
|
75
|
-
'css' => 'margin: 111px;',
|
|
76
|
-
'classnames' => 'has-text-color has-texas-flood-color',
|
|
87
|
+
'css' => 'border-style: dotted; border-width: 2rem; padding: 0; margin: 111px;',
|
|
88
|
+
'classnames' => 'has-text-color has-texas-flood-color has-border-color has-cool-caramel-border-color',
|
|
77
89
|
),
|
|
78
90
|
),
|
|
79
91
|
|
|
@@ -93,9 +105,18 @@ class WP_Style_Engine_Test extends WP_UnitTestCase {
|
|
|
93
105
|
'right' => '10em',
|
|
94
106
|
),
|
|
95
107
|
),
|
|
108
|
+
'border' => array(
|
|
109
|
+
'radius' => array(
|
|
110
|
+
'topLeft' => '99px',
|
|
111
|
+
'topRight' => '98px',
|
|
112
|
+
'bottomLeft' => '97px',
|
|
113
|
+
'bottomRight' => '96px',
|
|
114
|
+
),
|
|
115
|
+
),
|
|
96
116
|
),
|
|
117
|
+
'options' => null,
|
|
97
118
|
'expected_output' => array(
|
|
98
|
-
'css' => 'padding-top: 42px; padding-left: 2%; padding-bottom: 44px; padding-right: 5rem; margin-top: 12rem; margin-left: 2vh; margin-bottom: 2px; margin-right: 10em;',
|
|
119
|
+
'css' => 'border-top-left-radius: 99px; border-top-right-radius: 98px; border-bottom-left-radius: 97px; border-bottom-right-radius: 96px; padding-top: 42px; padding-left: 2%; padding-bottom: 44px; padding-right: 5rem; margin-top: 12rem; margin-left: 2vh; margin-bottom: 2px; margin-right: 10em;',
|
|
99
120
|
),
|
|
100
121
|
),
|
|
101
122
|
|
|
@@ -112,10 +133,57 @@ class WP_Style_Engine_Test extends WP_UnitTestCase {
|
|
|
112
133
|
'letterSpacing' => '2',
|
|
113
134
|
),
|
|
114
135
|
),
|
|
136
|
+
'options' => null,
|
|
115
137
|
'expected_output' => array(
|
|
116
138
|
'css' => 'font-family: Roboto,Oxygen-Sans,Ubuntu,sans-serif; font-style: italic; font-weight: 800; line-height: 1.3; text-decoration: underline; text-transform: uppercase; letter-spacing: 2;',
|
|
117
139
|
),
|
|
118
140
|
),
|
|
141
|
+
|
|
142
|
+
'style_block_with_selector' => array(
|
|
143
|
+
'block_styles' => array(
|
|
144
|
+
'spacing' => array(
|
|
145
|
+
'padding' => array(
|
|
146
|
+
'top' => '42px',
|
|
147
|
+
'left' => '2%',
|
|
148
|
+
'bottom' => '44px',
|
|
149
|
+
'right' => '5rem',
|
|
150
|
+
),
|
|
151
|
+
),
|
|
152
|
+
),
|
|
153
|
+
'options' => array( 'selector' => '.wp-selector > p' ),
|
|
154
|
+
'expected_output' => array(
|
|
155
|
+
'css' => '.wp-selector > p { padding-top: 42px; padding-left: 2%; padding-bottom: 44px; padding-right: 5rem; }',
|
|
156
|
+
),
|
|
157
|
+
),
|
|
158
|
+
|
|
159
|
+
'elements_with_css_var_value' => array(
|
|
160
|
+
'block_styles' => array(
|
|
161
|
+
'color' => array(
|
|
162
|
+
'text' => 'var:preset|color|my-little-pony',
|
|
163
|
+
),
|
|
164
|
+
),
|
|
165
|
+
'options' => array(
|
|
166
|
+
'selector' => '.wp-selector',
|
|
167
|
+
'css_vars' => true,
|
|
168
|
+
),
|
|
169
|
+
'expected_output' => array(
|
|
170
|
+
'css' => '.wp-selector { color: var(--wp--preset--color--my-little-pony); }',
|
|
171
|
+
'classnames' => 'has-text-color has-my-little-pony-color',
|
|
172
|
+
),
|
|
173
|
+
),
|
|
174
|
+
|
|
175
|
+
'elements_with_invalid_preset_style_property' => array(
|
|
176
|
+
'block_styles' => array(
|
|
177
|
+
'color' => array(
|
|
178
|
+
'text' => 'var:preset|invalid_property|my-little-pony',
|
|
179
|
+
),
|
|
180
|
+
),
|
|
181
|
+
'options' => array( 'selector' => '.wp-selector' ),
|
|
182
|
+
'expected_output' => array(
|
|
183
|
+
'classnames' => 'has-text-color',
|
|
184
|
+
),
|
|
185
|
+
),
|
|
186
|
+
|
|
119
187
|
'valid_classnames_deduped' => array(
|
|
120
188
|
'block_styles' => array(
|
|
121
189
|
'color' => array(
|
|
@@ -128,10 +196,25 @@ class WP_Style_Engine_Test extends WP_UnitTestCase {
|
|
|
128
196
|
'fontFamily' => 'var:preset|font-family|totally-awesome',
|
|
129
197
|
),
|
|
130
198
|
),
|
|
199
|
+
'options' => array(),
|
|
131
200
|
'expected_output' => array(
|
|
132
201
|
'classnames' => 'has-text-color has-copper-socks-color has-background has-splendid-carrot-background-color has-like-wow-dude-gradient-background has-fantastic-font-size has-totally-awesome-font-family',
|
|
133
202
|
),
|
|
134
203
|
),
|
|
204
|
+
|
|
205
|
+
'valid_classnames_and_css_vars' => array(
|
|
206
|
+
'block_styles' => array(
|
|
207
|
+
'color' => array(
|
|
208
|
+
'text' => 'var:preset|color|teal-independents',
|
|
209
|
+
),
|
|
210
|
+
),
|
|
211
|
+
'options' => array( 'css_vars' => true ),
|
|
212
|
+
'expected_output' => array(
|
|
213
|
+
'css' => 'color: var(--wp--preset--color--teal-independents);',
|
|
214
|
+
'classnames' => 'has-text-color has-teal-independents-color',
|
|
215
|
+
),
|
|
216
|
+
),
|
|
217
|
+
|
|
135
218
|
'valid_classnames_with_null_style_values' => array(
|
|
136
219
|
'block_styles' => array(
|
|
137
220
|
'color' => array(
|
|
@@ -139,11 +222,13 @@ class WP_Style_Engine_Test extends WP_UnitTestCase {
|
|
|
139
222
|
'background' => null,
|
|
140
223
|
),
|
|
141
224
|
),
|
|
225
|
+
'options' => array(),
|
|
142
226
|
'expected_output' => array(
|
|
143
227
|
'css' => 'color: #fff;',
|
|
144
228
|
'classnames' => 'has-text-color',
|
|
145
229
|
),
|
|
146
230
|
),
|
|
231
|
+
|
|
147
232
|
'invalid_classnames_preset_value' => array(
|
|
148
233
|
'block_styles' => array(
|
|
149
234
|
'color' => array(
|
|
@@ -155,10 +240,12 @@ class WP_Style_Engine_Test extends WP_UnitTestCase {
|
|
|
155
240
|
'padding' => 'var:preset|spacing|padding',
|
|
156
241
|
),
|
|
157
242
|
),
|
|
243
|
+
'options' => array(),
|
|
158
244
|
'expected_output' => array(
|
|
159
245
|
'classnames' => 'has-text-color has-background',
|
|
160
246
|
),
|
|
161
247
|
),
|
|
248
|
+
|
|
162
249
|
'invalid_classnames_options' => array(
|
|
163
250
|
'block_styles' => array(
|
|
164
251
|
'typography' => array(
|
|
@@ -170,8 +257,69 @@ class WP_Style_Engine_Test extends WP_UnitTestCase {
|
|
|
170
257
|
),
|
|
171
258
|
),
|
|
172
259
|
),
|
|
260
|
+
'options' => array(),
|
|
173
261
|
'expected_output' => array(),
|
|
174
262
|
),
|
|
263
|
+
|
|
264
|
+
'inline_valid_box_model_style_with_sides' => array(
|
|
265
|
+
'block_styles' => array(
|
|
266
|
+
'border' => array(
|
|
267
|
+
'top' => array(
|
|
268
|
+
'color' => '#fe1',
|
|
269
|
+
'width' => '1.5rem',
|
|
270
|
+
'style' => 'dashed',
|
|
271
|
+
),
|
|
272
|
+
'right' => array(
|
|
273
|
+
'color' => '#fe2',
|
|
274
|
+
'width' => '1.4rem',
|
|
275
|
+
'style' => 'solid',
|
|
276
|
+
),
|
|
277
|
+
'bottom' => array(
|
|
278
|
+
'color' => '#fe3',
|
|
279
|
+
'width' => '1.3rem',
|
|
280
|
+
),
|
|
281
|
+
'left' => array(
|
|
282
|
+
'color' => 'var:preset|color|swampy-yellow',
|
|
283
|
+
'width' => '0.5rem',
|
|
284
|
+
'style' => 'dotted',
|
|
285
|
+
),
|
|
286
|
+
),
|
|
287
|
+
),
|
|
288
|
+
'options' => array(),
|
|
289
|
+
'expected_output' => array(
|
|
290
|
+
'css' => 'border-top-color: #fe1; border-top-width: 1.5rem; border-top-style: dashed; border-right-color: #fe2; border-right-width: 1.4rem; border-right-style: solid; border-bottom-color: #fe3; border-bottom-width: 1.3rem; border-left-color: var(--wp--preset--color--swampy-yellow); border-left-width: 0.5rem; border-left-style: dotted;',
|
|
291
|
+
),
|
|
292
|
+
),
|
|
293
|
+
|
|
294
|
+
'inline_invalid_box_model_style_with_sides' => array(
|
|
295
|
+
'block_styles' => array(
|
|
296
|
+
'border' => array(
|
|
297
|
+
'top' => array(
|
|
298
|
+
'top' => '#fe1',
|
|
299
|
+
'right' => '1.5rem',
|
|
300
|
+
'cheese' => 'dashed',
|
|
301
|
+
),
|
|
302
|
+
'right' => array(
|
|
303
|
+
'right' => '#fe2',
|
|
304
|
+
'top' => '1.4rem',
|
|
305
|
+
'bacon' => 'solid',
|
|
306
|
+
),
|
|
307
|
+
'bottom' => array(
|
|
308
|
+
'color' => 'var:preset|color|terrible-lizard',
|
|
309
|
+
'bottom' => '1.3rem',
|
|
310
|
+
),
|
|
311
|
+
'left' => array(
|
|
312
|
+
'left' => null,
|
|
313
|
+
'width' => null,
|
|
314
|
+
'top' => 'dotted',
|
|
315
|
+
),
|
|
316
|
+
),
|
|
317
|
+
),
|
|
318
|
+
'options' => array(),
|
|
319
|
+
'expected_output' => array(
|
|
320
|
+
'css' => 'border-bottom-color: var(--wp--preset--color--terrible-lizard);',
|
|
321
|
+
),
|
|
322
|
+
),
|
|
175
323
|
);
|
|
176
324
|
}
|
|
177
325
|
}
|