@wordpress/style-engine 0.10.0 → 0.13.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +34 -2
  3. package/build/styles/border/index.js +94 -0
  4. package/build/styles/border/index.js.map +1 -0
  5. package/build/styles/index.js +3 -1
  6. package/build/styles/index.js.map +1 -1
  7. package/build/styles/spacing/margin.js +4 -1
  8. package/build/styles/spacing/margin.js.map +1 -1
  9. package/build/styles/spacing/padding.js +4 -1
  10. package/build/styles/spacing/padding.js.map +1 -1
  11. package/build/styles/utils.js +26 -10
  12. package/build/styles/utils.js.map +1 -1
  13. package/build-module/styles/border/index.js +85 -0
  14. package/build-module/styles/border/index.js.map +1 -0
  15. package/build-module/styles/index.js +2 -1
  16. package/build-module/styles/index.js.map +1 -1
  17. package/build-module/styles/spacing/margin.js +4 -1
  18. package/build-module/styles/spacing/margin.js.map +1 -1
  19. package/build-module/styles/spacing/padding.js +4 -1
  20. package/build-module/styles/spacing/padding.js.map +1 -1
  21. package/build-module/styles/utils.js +25 -11
  22. package/build-module/styles/utils.js.map +1 -1
  23. package/build-types/styles/border/index.d.ts +10 -0
  24. package/build-types/styles/border/index.d.ts.map +1 -0
  25. package/build-types/styles/index.d.ts +3 -7
  26. package/build-types/styles/index.d.ts.map +1 -1
  27. package/build-types/styles/spacing/margin.d.ts.map +1 -1
  28. package/build-types/styles/spacing/padding.d.ts.map +1 -1
  29. package/build-types/styles/utils.d.ts +16 -7
  30. package/build-types/styles/utils.d.ts.map +1 -1
  31. package/build-types/types.d.ts +26 -1
  32. package/build-types/types.d.ts.map +1 -1
  33. package/class-wp-style-engine-css-declarations.php +143 -0
  34. package/class-wp-style-engine-css-rule.php +115 -0
  35. package/class-wp-style-engine-css-rules-store.php +94 -0
  36. package/class-wp-style-engine-processor.php +93 -0
  37. package/class-wp-style-engine.php +109 -99
  38. package/package.json +2 -2
  39. package/phpunit/class-wp-style-engine-css-declarations-test.php +154 -0
  40. package/phpunit/class-wp-style-engine-css-rule-test.php +96 -0
  41. package/phpunit/class-wp-style-engine-css-rules-store-test.php +115 -0
  42. package/phpunit/class-wp-style-engine-processor-test.php +127 -0
  43. package/phpunit/class-wp-style-engine-test.php +159 -23
  44. package/src/styles/border/index.ts +145 -0
  45. package/src/styles/index.ts +7 -1
  46. package/src/styles/spacing/margin.ts +4 -6
  47. package/src/styles/spacing/padding.ts +4 -6
  48. package/src/styles/utils.ts +36 -12
  49. package/src/test/index.js +92 -2
  50. package/src/test/utils.js +12 -0
  51. package/src/types.ts +33 -1
  52. package/tsconfig.tsbuildinfo +1 -1
@@ -41,7 +41,7 @@ class WP_Style_Engine {
41
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
42
  * - property_keys => (array) array of keys whose values represent a valid CSS property, e.g., "margin" or "border".
43
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.
44
+ * - 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", ... )`.
45
45
  */
46
46
  const BLOCK_STYLE_DEFINITIONS_METADATA = array(
47
47
  'color' => array(
@@ -51,7 +51,7 @@ class WP_Style_Engine {
51
51
  ),
52
52
  'path' => array( 'color', 'text' ),
53
53
  'css_vars' => array(
54
- '--wp--preset--color--$slug' => 'color',
54
+ 'color' => '--wp--preset--color--$slug',
55
55
  ),
56
56
  'classnames' => array(
57
57
  'has-text-color' => true,
@@ -113,28 +113,28 @@ class WP_Style_Engine {
113
113
  'path' => array( 'border', 'width' ),
114
114
  ),
115
115
  'top' => array(
116
- 'value_func' => 'static::get_css_individual_property_rules',
116
+ 'value_func' => 'static::get_individual_property_css_declarations',
117
117
  'path' => array( 'border', 'top' ),
118
118
  'css_vars' => array(
119
119
  'color' => '--wp--preset--color--$slug',
120
120
  ),
121
121
  ),
122
122
  'right' => array(
123
- 'value_func' => 'static::get_css_individual_property_rules',
123
+ 'value_func' => 'static::get_individual_property_css_declarations',
124
124
  'path' => array( 'border', 'right' ),
125
125
  'css_vars' => array(
126
126
  'color' => '--wp--preset--color--$slug',
127
127
  ),
128
128
  ),
129
129
  'bottom' => array(
130
- 'value_func' => 'static::get_css_individual_property_rules',
130
+ 'value_func' => 'static::get_individual_property_css_declarations',
131
131
  'path' => array( 'border', 'bottom' ),
132
132
  'css_vars' => array(
133
133
  'color' => '--wp--preset--color--$slug',
134
134
  ),
135
135
  ),
136
136
  'left' => array(
137
- 'value_func' => 'static::get_css_individual_property_rules',
137
+ 'value_func' => 'static::get_individual_property_css_declarations',
138
138
  'path' => array( 'border', 'left' ),
139
139
  'css_vars' => array(
140
140
  'color' => '--wp--preset--color--$slug',
@@ -148,6 +148,9 @@ class WP_Style_Engine {
148
148
  'individual' => 'padding-%s',
149
149
  ),
150
150
  'path' => array( 'spacing', 'padding' ),
151
+ 'css_vars' => array(
152
+ 'spacing' => '--wp--preset--spacing--$slug',
153
+ ),
151
154
  ),
152
155
  'margin' => array(
153
156
  'property_keys' => array(
@@ -155,6 +158,9 @@ class WP_Style_Engine {
155
158
  'individual' => 'margin-%s',
156
159
  ),
157
160
  'path' => array( 'spacing', 'margin' ),
161
+ 'css_vars' => array(
162
+ 'spacing' => '--wp--preset--spacing--$slug',
163
+ ),
158
164
  ),
159
165
  ),
160
166
  'typography' => array(
@@ -223,11 +229,11 @@ class WP_Style_Engine {
223
229
  * @return WP_Style_Engine The main instance.
224
230
  */
225
231
  public static function get_instance() {
226
- if ( null === self::$instance ) {
227
- self::$instance = new self();
232
+ if ( null === static::$instance ) {
233
+ static::$instance = new static();
228
234
  }
229
235
 
230
- return self::$instance;
236
+ return static::$instance;
231
237
  }
232
238
 
233
239
  /**
@@ -247,7 +253,29 @@ class WP_Style_Engine {
247
253
  }
248
254
 
249
255
  /**
250
- * Checks whether an incoming style value is valid.
256
+ * Generates a css var string, eg var(--wp--preset--color--background) from a preset string, eg. `var:preset|space|50`.
257
+ *
258
+ * @param string $style_value A single css preset value.
259
+ * @param array $css_vars The css var patterns used to generate the var string.
260
+ *
261
+ * @return string|null The css var, or null if no match for slug found.
262
+ */
263
+ protected static function get_css_var_value( $style_value, $css_vars ) {
264
+ foreach ( $css_vars as $property_key => $css_var_pattern ) {
265
+ $slug = static::get_slug_from_preset_value( $style_value, $property_key );
266
+ if ( $slug ) {
267
+ $var = strtr(
268
+ $css_var_pattern,
269
+ array( '$slug' => $slug )
270
+ );
271
+ return "var($var)";
272
+ }
273
+ }
274
+ return null;
275
+ }
276
+
277
+ /**
278
+ * Checks whether an incoming block style value is valid.
251
279
  *
252
280
  * @param string? $style_value A single css preset value.
253
281
  *
@@ -302,42 +330,35 @@ class WP_Style_Engine {
302
330
  }
303
331
 
304
332
  /**
305
- * Returns CSS rules based on valid block style values.
333
+ * Returns an array of CSS declarations based on valid block style values.
306
334
  *
307
- * @param array $style_value A single raw style value from the generate() $block_styles array.
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.
335
+ * @param array $style_value A single raw style value from the generate() $block_styles array.
336
+ * @param array<string> $style_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA.
337
+ * @param boolean $should_skip_css_vars Whether to skip compiling CSS var values.
310
338
  *
311
- * @return array An array of CSS rules.
339
+ * @return array An array of CSS definitions, e.g., array( "$property" => "$value" ).
312
340
  */
313
- protected static function get_css( $style_value, $style_definition, $should_return_css_vars ) {
314
- $rules = array();
315
-
341
+ protected static function get_css_declarations( $style_value, $style_definition, $should_skip_css_vars = false ) {
316
342
  if (
317
343
  isset( $style_definition['value_func'] ) &&
318
344
  is_callable( $style_definition['value_func'] )
319
345
  ) {
320
- return call_user_func( $style_definition['value_func'], $style_value, $style_definition );
346
+ return call_user_func( $style_definition['value_func'], $style_value, $style_definition, $should_skip_css_vars );
321
347
  }
322
348
 
323
- $style_properties = $style_definition['property_keys'];
349
+ $css_declarations = array();
350
+ $style_property_keys = $style_definition['property_keys'];
324
351
 
325
352
  // Build CSS var values from var:? values, e.g, `var(--wp--css--rule-slug )`
326
353
  // Check if the value is a CSS preset and there's a corresponding css_var pattern in the style definition.
327
354
  if ( is_string( $style_value ) && strpos( $style_value, 'var:' ) !== false ) {
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
- }
355
+ if ( ! $should_skip_css_vars && ! empty( $style_definition['css_vars'] ) ) {
356
+ $css_var = static::get_css_var_value( $style_value, $style_definition['css_vars'] );
357
+ if ( $css_var ) {
358
+ $css_declarations[ $style_property_keys['default'] ] = $css_var;
338
359
  }
339
360
  }
340
- return $rules;
361
+ return $css_declarations;
341
362
  }
342
363
 
343
364
  // Default rule builder.
@@ -345,24 +366,29 @@ class WP_Style_Engine {
345
366
  // for styles such as margins and padding.
346
367
  if ( is_array( $style_value ) ) {
347
368
  foreach ( $style_value as $key => $value ) {
348
- $individual_property = sprintf( $style_properties['individual'], _wp_to_kebab_case( $key ) );
349
- $rules[ $individual_property ] = $value;
369
+ if ( is_string( $value ) && strpos( $value, 'var:' ) !== false && ! $should_skip_css_vars && ! empty( $style_definition['css_vars'] ) ) {
370
+ $value = static::get_css_var_value( $value, $style_definition['css_vars'] );
371
+ }
372
+ $individual_property = sprintf( $style_property_keys['individual'], _wp_to_kebab_case( $key ) );
373
+ if ( $individual_property && static::is_valid_style_value( $value ) ) {
374
+ $css_declarations[ $individual_property ] = $value;
375
+ }
350
376
  }
351
377
  } else {
352
- $rules[ $style_properties['default'] ] = $style_value;
378
+ $css_declarations[ $style_property_keys['default'] ] = $style_value;
353
379
  }
354
380
 
355
- return $rules;
381
+ return $css_declarations;
356
382
  }
357
383
 
358
384
  /**
359
- * Returns an CSS ruleset.
360
- * Styles are bundled based on the instructions in BLOCK_STYLE_DEFINITIONS_METADATA.
385
+ * Returns classnames and CSS based on the values in a block attributes.styles object.
386
+ * Return values are parsed based on the instructions in BLOCK_STYLE_DEFINITIONS_METADATA.
361
387
  *
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`.
388
+ * @param array $block_styles Styles from a block's attributes object.
389
+ * @param array $options array(
390
+ * 'selector' => (string) When a selector is passed, `generate()` will return a full CSS rule `$selector { ...rules }`, otherwise a concatenated string of properties and values.
391
+ * 'convert_vars_to_classnames' => (boolean) Whether to skip converting CSS var:? values to var( --wp--preset--* ) values. Default is `false`.
366
392
  * );.
367
393
  *
368
394
  * @return array|null array(
@@ -370,17 +396,17 @@ class WP_Style_Engine {
370
396
  * 'classnames' => (string) Classnames separated by a space.
371
397
  * );
372
398
  */
373
- public function generate( $block_styles, $options ) {
399
+ public function get_block_supports_styles( $block_styles, $options ) {
374
400
  if ( empty( $block_styles ) || ! is_array( $block_styles ) ) {
375
401
  return null;
376
402
  }
377
403
 
378
- $css_rules = array();
379
- $classnames = array();
380
- $should_return_css_vars = isset( $options['css_vars'] ) && true === $options['css_vars'];
404
+ $css_declarations = array();
405
+ $classnames = array();
406
+ $should_skip_css_vars = isset( $options['convert_vars_to_classnames'] ) && true === $options['convert_vars_to_classnames'];
381
407
 
382
408
  // Collect CSS and classnames.
383
- foreach ( self::BLOCK_STYLE_DEFINITIONS_METADATA as $definition_group_key => $definition_group_style ) {
409
+ foreach ( static::BLOCK_STYLE_DEFINITIONS_METADATA as $definition_group_key => $definition_group_style ) {
384
410
  if ( empty( $block_styles[ $definition_group_key ] ) ) {
385
411
  continue;
386
412
  }
@@ -391,36 +417,26 @@ class WP_Style_Engine {
391
417
  continue;
392
418
  }
393
419
 
394
- $classnames = array_merge( $classnames, static::get_classnames( $style_value, $style_definition ) );
395
- $css_rules = array_merge( $css_rules, static::get_css( $style_value, $style_definition, $should_return_css_vars ) );
420
+ $classnames = array_merge( $classnames, static::get_classnames( $style_value, $style_definition ) );
421
+ $css_declarations = array_merge( $css_declarations, static::get_css_declarations( $style_value, $style_definition, $should_skip_css_vars ) );
396
422
  }
397
423
  }
398
424
 
399
425
  // Build CSS rules output.
400
- $selector = isset( $options['selector'] ) ? $options['selector'] : null;
401
- $css = array();
402
- $styles_output = array();
426
+ $css_selector = isset( $options['selector'] ) ? $options['selector'] : null;
427
+ $css_declarations = new WP_Style_Engine_CSS_Declarations( $css_declarations );
403
428
 
404
- if ( ! empty( $css_rules ) ) {
405
- // Generate inline style rules.
406
- foreach ( $css_rules as $rule => $value ) {
407
- $filtered_css = esc_html( safecss_filter_attr( "{$rule}: {$value}" ) );
408
- if ( ! empty( $filtered_css ) ) {
409
- $css[] = $filtered_css . ';';
410
- }
411
- }
412
- }
429
+ // The return object.
430
+ $styles_output = array();
431
+ $css = $css_declarations->get_declarations_string();
413
432
 
414
433
  // Return css, if any.
415
434
  if ( ! empty( $css ) ) {
435
+ $styles_output['css'] = $css;
436
+ $styles_output['declarations'] = $css_declarations->get_declarations();
416
437
  // 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 );
438
+ if ( $css_selector ) {
439
+ $styles_output['css'] = $css_selector . ' { ' . $css . ' }';
424
440
  }
425
441
  }
426
442
 
@@ -432,24 +448,24 @@ class WP_Style_Engine {
432
448
  return $styles_output;
433
449
  }
434
450
 
435
-
436
451
  /**
437
- * Style value parser that returns a CSS ruleset of style properties for style definition groups
452
+ * Style value parser that returns a CSS definition array comprising style properties
438
453
  * that have keys representing individual style properties, otherwise known as longhand CSS properties.
439
454
  * e.g., "$style_property-$individual_feature: $value;", which could represent the following:
440
455
  * "border-{top|right|bottom|left}-{color|width|style}: {value};" or,
441
456
  * "border-image-{outset|source|width|repeat|slice}: {value};"
442
457
  *
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.
458
+ * @param array $style_value A single raw Gutenberg style attributes value for a CSS property.
459
+ * @param array $individual_property_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA.
460
+ * @param boolean $should_skip_css_vars Whether to skip compiling CSS var values.
445
461
  *
446
- * @return array The class name for the added style.
462
+ * @return array An array of CSS definitions, e.g., array( "$property" => "$value" ).
447
463
  */
448
- protected static function get_css_individual_property_rules( $style_value, $individual_property_definition ) {
449
- $rules = array();
464
+ protected static function get_individual_property_css_declarations( $style_value, $individual_property_definition, $should_skip_css_vars ) {
465
+ $css_declarations = array();
450
466
 
451
467
  if ( ! is_array( $style_value ) || empty( $style_value ) || empty( $individual_property_definition['path'] ) ) {
452
- return $rules;
468
+ return $css_declarations;
453
469
  }
454
470
 
455
471
  // The first item in $individual_property_definition['path'] array tells us the style property, e.g., "border".
@@ -465,51 +481,45 @@ class WP_Style_Engine {
465
481
 
466
482
  // Build a path to the individual rules in definitions.
467
483
  $style_definition_path = array( $definition_group_key, $css_property );
468
- $style_definition = _wp_array_get( self::BLOCK_STYLE_DEFINITIONS_METADATA, $style_definition_path, null );
484
+ $style_definition = _wp_array_get( static::BLOCK_STYLE_DEFINITIONS_METADATA, $style_definition_path, null );
469
485
 
470
486
  if ( $style_definition && isset( $style_definition['property_keys']['individual'] ) ) {
471
487
  // 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)";
488
+ if ( is_string( $value ) && strpos( $value, 'var:' ) !== false && ! $should_skip_css_vars && ! empty( $individual_property_definition['css_vars'] ) ) {
489
+ $value = static::get_css_var_value( $value, $individual_property_definition['css_vars'] );
479
490
  }
480
- $individual_css_property = sprintf( $style_definition['property_keys']['individual'], $individual_property_key );
481
- $rules[ $individual_css_property ] = $value;
491
+ $individual_css_property = sprintf( $style_definition['property_keys']['individual'], $individual_property_key );
492
+ $css_declarations[ $individual_css_property ] = $value;
482
493
  }
483
494
  }
484
- return $rules;
495
+ return $css_declarations;
485
496
  }
486
497
  }
487
498
 
488
499
  /**
489
- * Global public interface method to WP_Style_Engine->generate.
490
- *
491
- * Returns an CSS ruleset.
492
- * Styles are bundled based on the instructions in BLOCK_STYLE_DEFINITIONS_METADATA.
500
+ * Global public interface method to WP_Style_Engine->get_block_supports_styles to generate block styles from a single block style object.
501
+ * See: https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/
493
502
  *
494
503
  * Example usage:
495
504
  *
496
- * $styles = wp_style_engine_generate( array( 'color' => array( 'text' => '#cccccc' ) ) );
497
- * // Returns `'color: #cccccc'`.
505
+ * $styles = wp_style_engine_get_block_supports_styles( array( 'color' => array( 'text' => '#cccccc' ) ) );
506
+ * // Returns `array( 'css' => 'color: #cccccc', 'declarations' => array( 'color' => '#cccccc' ), 'classnames' => 'has-color' )`.
498
507
  *
499
508
  * @access public
500
509
  *
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.
510
+ * @param array $block_styles The value of a block's attributes.style.
511
+ * @param array<string> $options An array of options to determine the output.
503
512
  *
504
- * @return array|null array(
505
- * 'styles' => (string) A CSS ruleset formatted to be placed in an HTML `style` attribute or tag.
506
- * 'classnames' => (string) Classnames separated by a space.
513
+ * @return array<string>|null array(
514
+ * 'css' => (string) A CSS ruleset or declarations block formatted to be placed in an HTML `style` attribute or tag.
515
+ * 'declarations' => (array) An array of property/value pairs representing parsed CSS declarations.
516
+ * 'classnames' => (string) Classnames separated by a space.
507
517
  * );
508
518
  */
509
- function wp_style_engine_generate( $block_styles, $options = array() ) {
519
+ function wp_style_engine_get_block_supports_styles( $block_styles, $options = array() ) {
510
520
  if ( class_exists( 'WP_Style_Engine' ) ) {
511
521
  $style_engine = WP_Style_Engine::get_instance();
512
- return $style_engine->generate( $block_styles, $options );
522
+ return $style_engine->get_block_supports_styles( $block_styles, $options );
513
523
  }
514
524
  return null;
515
525
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/style-engine",
3
- "version": "0.10.0",
3
+ "version": "0.13.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": "48d5f37dfb52d2e77c8eeb662f9874cf141b8c6b"
37
+ "gitHead": "0315dbc240cb2aa146d7c1bafd251f004b88300e"
38
38
  }
@@ -0,0 +1,154 @@
1
+ <?php
2
+ /**
3
+ * Tests the Style Engine CSS declarations class.
4
+ *
5
+ * @package Gutenberg
6
+ * @subpackage style-engine
7
+ */
8
+
9
+ require __DIR__ . '/../class-wp-style-engine-css-declarations.php';
10
+
11
+ /**
12
+ * Tests for registering, storing and generating CSS declarations.
13
+ */
14
+ class WP_Style_Engine_CSS_Declarations_Test extends WP_UnitTestCase {
15
+ /**
16
+ * Should set declarations on instantiation.
17
+ */
18
+ public function test_instantiate_with_declarations() {
19
+ $input_declarations = array(
20
+ 'margin-top' => '10px',
21
+ 'font-size' => '2rem',
22
+ );
23
+ $css_declarations = new WP_Style_Engine_CSS_Declarations( $input_declarations );
24
+ $this->assertSame( $input_declarations, $css_declarations->get_declarations() );
25
+ }
26
+
27
+ /**
28
+ * Should add declarations.
29
+ */
30
+ public function test_add_declarations() {
31
+ $input_declarations = array(
32
+ 'padding' => '20px',
33
+ 'color' => 'var(--wp--preset--elbow-patches)',
34
+ );
35
+ $css_declarations = new WP_Style_Engine_CSS_Declarations();
36
+ $css_declarations->add_declarations( $input_declarations );
37
+ $this->assertSame( $input_declarations, $css_declarations->get_declarations() );
38
+ }
39
+
40
+ /**
41
+ * Should add declarations.
42
+ */
43
+ public function test_add_a_single_declaration() {
44
+ $input_declarations = array(
45
+ 'border-width' => '1%',
46
+ 'background-color' => 'var(--wp--preset--english-mustard)',
47
+ );
48
+ $css_declarations = new WP_Style_Engine_CSS_Declarations( $input_declarations );
49
+ $extra_declaration = array(
50
+ 'letter-spacing' => '1.5px',
51
+ );
52
+ $css_declarations->add_declarations( $extra_declaration );
53
+ $this->assertSame( array_merge( $input_declarations, $extra_declaration ), $css_declarations->get_declarations() );
54
+ }
55
+
56
+ /**
57
+ * Should sanitize properties before storing.
58
+ */
59
+ public function test_sanitize_properties() {
60
+ $input_declarations = array(
61
+ '^--wp--style--sleepy-potato$' => '40px',
62
+ '<background-//color>' => 'var(--wp--preset--english-mustard)',
63
+ );
64
+ $css_declarations = new WP_Style_Engine_CSS_Declarations( $input_declarations );
65
+
66
+ $this->assertSame(
67
+ array(
68
+ '--wp--style--sleepy-potato' => '40px',
69
+ 'background-color' => 'var(--wp--preset--english-mustard)',
70
+ ),
71
+ $css_declarations->get_declarations()
72
+ );
73
+ }
74
+
75
+ /**
76
+ * Should compile css declarations into a css declarations block string.
77
+ */
78
+ public function test_generate_css_declarations_string() {
79
+ $input_declarations = array(
80
+ 'color' => 'red',
81
+ 'border-top-left-radius' => '99px',
82
+ 'text-decoration' => 'underline',
83
+ );
84
+ $css_declarations = new WP_Style_Engine_CSS_Declarations( $input_declarations );
85
+
86
+ $this->assertSame(
87
+ 'color: red; border-top-left-radius: 99px; text-decoration: underline;',
88
+ $css_declarations->get_declarations_string()
89
+ );
90
+ }
91
+
92
+ /**
93
+ * Should escape values and run the CSS through safecss_filter_attr.
94
+ */
95
+ public function test_remove_unsafe_properties_and_values() {
96
+ $input_declarations = array(
97
+ 'color' => '<red/>',
98
+ 'margin-right' => '10em',
99
+ 'potato' => 'uppercase',
100
+ );
101
+ $css_declarations = new WP_Style_Engine_CSS_Declarations( $input_declarations );
102
+
103
+ $this->assertSame(
104
+ 'color: &lt;red/&gt;; margin-right: 10em;',
105
+ $css_declarations->get_declarations_string()
106
+ );
107
+ }
108
+
109
+ /**
110
+ * Should remove a declaration
111
+ */
112
+ public function test_remove_declaration() {
113
+ $input_declarations = array(
114
+ 'color' => 'tomato',
115
+ 'margin' => '10em 10em 20em 1px',
116
+ 'font-family' => 'Happy Font serif',
117
+ );
118
+ $css_declarations = new WP_Style_Engine_CSS_Declarations( $input_declarations );
119
+
120
+ $this->assertSame(
121
+ 'color: tomato; margin: 10em 10em 20em 1px; font-family: Happy Font serif;',
122
+ $css_declarations->get_declarations_string()
123
+ );
124
+
125
+ $css_declarations->remove_declaration( 'color' );
126
+ $this->assertSame(
127
+ 'margin: 10em 10em 20em 1px; font-family: Happy Font serif;',
128
+ $css_declarations->get_declarations_string()
129
+ );
130
+ }
131
+
132
+ /**
133
+ * Should remove declarations
134
+ */
135
+ public function test_remove_declarations() {
136
+ $input_declarations = array(
137
+ 'color' => 'cucumber',
138
+ 'margin' => '10em 10em 20em 1px',
139
+ 'font-family' => 'Happy Font serif',
140
+ );
141
+ $css_declarations = new WP_Style_Engine_CSS_Declarations( $input_declarations );
142
+
143
+ $this->assertSame(
144
+ 'color: cucumber; margin: 10em 10em 20em 1px; font-family: Happy Font serif;',
145
+ $css_declarations->get_declarations_string()
146
+ );
147
+
148
+ $css_declarations->remove_declarations( array( 'color', 'margin' ) );
149
+ $this->assertSame(
150
+ 'font-family: Happy Font serif;',
151
+ $css_declarations->get_declarations_string()
152
+ );
153
+ }
154
+ }
@@ -0,0 +1,96 @@
1
+ <?php
2
+ /**
3
+ * Tests the Style Engine CSS Rule class.
4
+ *
5
+ * @package Gutenberg
6
+ * @subpackage style-engine
7
+ */
8
+
9
+ require __DIR__ . '/../class-wp-style-engine-css-rule.php';
10
+ require __DIR__ . '/../class-wp-style-engine-css-declarations.php';
11
+
12
+ /**
13
+ * Tests for registering, storing and generating CSS declarations.
14
+ */
15
+ class WP_Style_Engine_CSS_Rule_Test extends WP_UnitTestCase {
16
+ /**
17
+ * Should set declarations on instantiation.
18
+ */
19
+ public function test_instantiate_with_selector_and_rules() {
20
+ $selector = '.law-and-order';
21
+ $input_declarations = array(
22
+ 'margin-top' => '10px',
23
+ 'font-size' => '2rem',
24
+ );
25
+ $css_declarations = new WP_Style_Engine_CSS_Declarations( $input_declarations );
26
+ $css_rule = new WP_Style_Engine_CSS_Rule( $selector, $css_declarations );
27
+
28
+ $this->assertSame( $selector, $css_rule->get_selector() );
29
+
30
+ $expected = "$selector {{$css_declarations->get_declarations_string()}}";
31
+ $this->assertSame( $expected, $css_rule->get_css() );
32
+ }
33
+
34
+ /**
35
+ * Test dedupe declaration properties.
36
+ */
37
+ public function test_dedupe_properties_in_rules() {
38
+ $selector = '.taggart';
39
+ $first_declaration = array(
40
+ 'font-size' => '2rem',
41
+ );
42
+ $overwrite_first_declaration = array(
43
+ 'font-size' => '4px',
44
+ );
45
+ $css_rule = new WP_Style_Engine_CSS_Rule( $selector, $first_declaration );
46
+ $css_rule->add_declarations( new WP_Style_Engine_CSS_Declarations( $overwrite_first_declaration ) );
47
+
48
+ $expected = '.taggart {font-size: 4px;}';
49
+ $this->assertSame( $expected, $css_rule->get_css() );
50
+ }
51
+
52
+ /**
53
+ * Should set selector and rules on instantiation.
54
+ */
55
+ public function test_add_declarations() {
56
+ // Declarations using a WP_Style_Engine_CSS_Declarations object.
57
+ $some_css_declarations = new WP_Style_Engine_CSS_Declarations( array( 'margin-top' => '10px' ) );
58
+ // Declarations using a property => value array.
59
+ $some_more_css_declarations = array( 'font-size' => '1rem' );
60
+ $css_rule = new WP_Style_Engine_CSS_Rule( '.hill-street-blues', $some_css_declarations );
61
+ $css_rule->add_declarations( $some_more_css_declarations );
62
+
63
+ $expected = '.hill-street-blues {margin-top: 10px; font-size: 1rem;}';
64
+ $this->assertSame( $expected, $css_rule->get_css() );
65
+ }
66
+
67
+ /**
68
+ * Should set selector and rules on instantiation.
69
+ */
70
+ public function test_set_selector() {
71
+ $selector = '.taggart';
72
+ $css_rule = new WP_Style_Engine_CSS_Rule( $selector );
73
+
74
+ $this->assertSame( $selector, $css_rule->get_selector() );
75
+
76
+ $css_rule->set_selector( '.law-and-order' );
77
+
78
+ $this->assertSame( '.law-and-order', $css_rule->get_selector() );
79
+ }
80
+
81
+ /**
82
+ * Should set selector and rules on instantiation.
83
+ */
84
+ public function test_get_css() {
85
+ $selector = '.chips';
86
+ $input_declarations = array(
87
+ 'margin-top' => '10px',
88
+ 'font-size' => '2rem',
89
+ );
90
+ $css_declarations = new WP_Style_Engine_CSS_Declarations( $input_declarations );
91
+ $css_rule = new WP_Style_Engine_CSS_Rule( $selector, $css_declarations );
92
+ $expected = "$selector {{$css_declarations->get_declarations_string()}}";
93
+
94
+ $this->assertSame( $expected, $css_rule->get_css() );
95
+ }
96
+ }