@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
@@ -0,0 +1,115 @@
1
+ <?php
2
+ /**
3
+ * Tests the Style Engine CSS Rules Store class.
4
+ *
5
+ * @package Gutenberg
6
+ * @subpackage style-engine
7
+ */
8
+
9
+ require __DIR__ . '/../class-wp-style-engine-css-rules-store.php';
10
+ require __DIR__ . '/../class-wp-style-engine-css-rule.php';
11
+ require __DIR__ . '/../class-wp-style-engine-css-declarations.php';
12
+
13
+ /**
14
+ * Tests for registering, storing and retrieving CSS Rules.
15
+ */
16
+ class WP_Style_Engine_CSS_Rules_Store_Test extends WP_UnitTestCase {
17
+ /**
18
+ * Should create a new store.
19
+ */
20
+ public function test_create_new_store() {
21
+ $new_pancakes_store = WP_Style_Engine_CSS_Rules_Store::get_store( 'pancakes-with-strawberries' );
22
+ $this->assertInstanceOf( 'WP_Style_Engine_CSS_Rules_Store', $new_pancakes_store );
23
+ }
24
+
25
+ /**
26
+ * Should return previously created store when the same selector key is passed.
27
+ */
28
+ public function test_get_store() {
29
+ $new_fish_store = WP_Style_Engine_CSS_Rules_Store::get_store( 'fish-n-chips' );
30
+ $selector = '.haddock';
31
+
32
+ $new_fish_store->add_rule( $selector )->get_selector();
33
+ $this->assertEquals( $selector, $new_fish_store->add_rule( $selector )->get_selector() );
34
+
35
+ $the_same_fish_store = WP_Style_Engine_CSS_Rules_Store::get_store( 'fish-n-chips' );
36
+ $this->assertEquals( $selector, $the_same_fish_store->add_rule( $selector )->get_selector() );
37
+ }
38
+
39
+ /**
40
+ * Should return a stored rule.
41
+ */
42
+ public function test_add_rule() {
43
+ $new_pie_store = WP_Style_Engine_CSS_Rules_Store::get_store( 'meat-pie' );
44
+ $selector = '.wp-block-sauce a:hover';
45
+ $store_rule = $new_pie_store->add_rule( $selector );
46
+ $expected = "$selector {}";
47
+ $this->assertEquals( $expected, $store_rule->get_css() );
48
+
49
+ $pie_declarations = array(
50
+ 'color' => 'brown',
51
+ 'border-color' => 'yellow',
52
+ 'border-radius' => '10rem',
53
+ );
54
+ $css_declarations = new WP_Style_Engine_CSS_Declarations( $pie_declarations );
55
+ $store_rule->add_declarations( $css_declarations );
56
+
57
+ $store_rule = $new_pie_store->add_rule( $selector );
58
+ $expected = "$selector {{$css_declarations->get_declarations_string()}}";
59
+ $this->assertEquals( $expected, $store_rule->get_css() );
60
+ }
61
+
62
+ /**
63
+ * Should return all stored rules.
64
+ */
65
+ public function test_get_all_rules() {
66
+ $new_pizza_store = WP_Style_Engine_CSS_Rules_Store::get_store( 'pizza-with-mozzarella' );
67
+ $selector = '.wp-block-anchovies a:hover';
68
+ $store_rule = $new_pizza_store->add_rule( $selector );
69
+ $expected = array(
70
+ $selector => $store_rule,
71
+ );
72
+
73
+ $this->assertEquals( $expected, $new_pizza_store->get_all_rules() );
74
+
75
+ $pizza_declarations = array(
76
+ 'color' => 'red',
77
+ 'border-color' => 'yellow',
78
+ 'border-radius' => '10rem',
79
+ );
80
+ $css_declarations = new WP_Style_Engine_CSS_Declarations( $pizza_declarations );
81
+ $store_rule->add_declarations( array( $css_declarations ) );
82
+
83
+ $expected = array(
84
+ $selector => $store_rule,
85
+ );
86
+ $this->assertEquals( $expected, $new_pizza_store->get_all_rules() );
87
+
88
+ $new_pizza_declarations = array(
89
+ 'color' => 'red',
90
+ 'border-color' => 'red',
91
+ 'font-size' => '10rem',
92
+ );
93
+ $css_declarations = new WP_Style_Engine_CSS_Declarations( $new_pizza_declarations );
94
+ $store_rule->add_declarations( array( $css_declarations ) );
95
+
96
+ $expected = array(
97
+ $selector => $store_rule,
98
+ );
99
+ $this->assertEquals( $expected, $new_pizza_store->get_all_rules() );
100
+
101
+ $new_selector = '.wp-block-mushroom a:hover';
102
+ $newer_pizza_declarations = array(
103
+ 'padding' => '100px',
104
+ );
105
+ $new_store_rule = $new_pizza_store->add_rule( $new_selector );
106
+ $css_declarations = new WP_Style_Engine_CSS_Declarations( $newer_pizza_declarations );
107
+ $new_store_rule->add_declarations( array( $css_declarations ) );
108
+
109
+ $expected = array(
110
+ $selector => $store_rule,
111
+ $new_selector => $new_store_rule,
112
+ );
113
+ $this->assertEquals( $expected, $new_pizza_store->get_all_rules() );
114
+ }
115
+ }
@@ -0,0 +1,127 @@
1
+ <?php
2
+ /**
3
+ * Tests the Style Engine Renderer class.
4
+ *
5
+ * @package Gutenberg
6
+ * @subpackage style-engine
7
+ */
8
+ require __DIR__ . '/../class-wp-style-engine-css-rules-store.php';
9
+ require __DIR__ . '/../class-wp-style-engine-css-rule.php';
10
+ require __DIR__ . '/../class-wp-style-engine-css-declarations.php';
11
+ require __DIR__ . '/../class-wp-style-engine-processor.php';
12
+
13
+ /**
14
+ * Tests for compiling and rendering styles from a store of CSS rules.
15
+ */
16
+ class WP_Style_Engine_Processor_Test extends WP_UnitTestCase {
17
+ /**
18
+ * Should compile CSS rules from the store.
19
+ */
20
+ public function test_return_store_rules_as_css() {
21
+ $a_nice_store = WP_Style_Engine_CSS_Rules_Store_Gutenberg::get_store( 'nice' );
22
+ $a_nice_renderer = new WP_Style_Engine_Processor_Gutenberg( $a_nice_store );
23
+ $a_nice_store->add_rule( '.a-nice-rule' )->add_declarations(
24
+ array(
25
+ 'color' => 'var(--nice-color)',
26
+ 'background-color' => 'purple',
27
+ )
28
+ );
29
+ $a_nice_store->add_rule( '.a-nicer-rule' )->add_declarations(
30
+ array(
31
+ 'font-family' => 'Nice sans',
32
+ 'font-size' => '1em',
33
+ 'background-color' => 'purple',
34
+ )
35
+ );
36
+
37
+ $this->assertEquals( '.a-nice-rule {color: var(--nice-color); background-color: purple;}.a-nicer-rule {font-family: Nice sans; font-size: 1em; background-color: purple;}', $a_nice_renderer->get_css() );
38
+ }
39
+
40
+ /**
41
+ * Should merge CSS declarations.
42
+ */
43
+ public function test_dedupe_and_merge_css_declarations() {
44
+ $an_excellent_store = WP_Style_Engine_CSS_Rules_Store_Gutenberg::get_store( 'excellent' );
45
+ $an_excellent_renderer = new WP_Style_Engine_Processor_Gutenberg( $an_excellent_store );
46
+ $an_excellent_store->add_rule( '.an-excellent-rule' )->add_declarations(
47
+ array(
48
+ 'color' => 'var(--excellent-color)',
49
+ 'border-style' => 'dotted',
50
+ )
51
+ );
52
+ $an_excellent_store->add_rule( '.an-excellent-rule' )->add_declarations(
53
+ array(
54
+ 'color' => 'var(--excellent-color)',
55
+ 'border-style' => 'dotted',
56
+ 'border-color' => 'brown',
57
+ )
58
+ );
59
+
60
+ $this->assertEquals( '.an-excellent-rule {color: var(--excellent-color); border-style: dotted; border-color: brown;}', $an_excellent_renderer->get_css() );
61
+
62
+ $an_excellent_store->add_rule( '.an-excellent-rule' )->add_declarations(
63
+ array(
64
+ 'color' => 'var(--excellent-color)',
65
+ 'border-style' => 'dashed',
66
+ 'border-width' => '2px',
67
+ )
68
+ );
69
+
70
+ $this->assertEquals( '.an-excellent-rule {color: var(--excellent-color); border-style: dashed; border-color: brown; border-width: 2px;}', $an_excellent_renderer->get_css() );
71
+ }
72
+
73
+ /**
74
+ * Should combine duplicate CSS rules.
75
+ */
76
+ public function test_combine_css_rules() {
77
+ $a_sweet_store = WP_Style_Engine_CSS_Rules_Store_Gutenberg::get_store( 'sweet' );
78
+ $a_sweet_renderer = new WP_Style_Engine_Processor_Gutenberg( $a_sweet_store );
79
+ $a_sweet_store->add_rule( '.a-sweet-rule' )->add_declarations(
80
+ array(
81
+ 'color' => 'var(--sweet-color)',
82
+ 'background-color' => 'purple',
83
+ )
84
+ );
85
+ $a_sweet_store->add_rule( '#an-even-sweeter-rule > marquee' )->add_declarations(
86
+ array(
87
+ 'color' => 'var(--sweet-color)',
88
+ 'background-color' => 'purple',
89
+ )
90
+ );
91
+
92
+ $this->assertEquals( '.a-sweet-rule,#an-even-sweeter-rule > marquee {color: var(--sweet-color); background-color: purple;}', $a_sweet_renderer->get_css() );
93
+ }
94
+
95
+ /**
96
+ * Should combine and store CSS rules.
97
+ */
98
+ public function test_store_combined_css_rules() {
99
+ $a_lovely_store = WP_Style_Engine_CSS_Rules_Store_Gutenberg::get_store( 'lovely' );
100
+ $a_lovely_renderer = new WP_Style_Engine_Processor_Gutenberg( $a_lovely_store );
101
+ $a_lovely_store->add_rule( '.a-lovely-rule' )->add_declarations(
102
+ array(
103
+ 'border-color' => 'purple',
104
+ )
105
+ );
106
+ $a_lovely_store->add_rule( '.a-lovelier-rule' )->add_declarations(
107
+ array(
108
+ 'border-color' => 'purple',
109
+ )
110
+ );
111
+
112
+ $this->assertEquals( '.a-lovely-rule,.a-lovelier-rule {border-color: purple;}', $a_lovely_renderer->get_css() );
113
+
114
+ $a_lovely_store->add_rule( '.a-most-lovely-rule' )->add_declarations(
115
+ array(
116
+ 'border-color' => 'purple',
117
+ )
118
+ );
119
+ $a_lovely_store->add_rule( '.a-perfectly-lovely-rule' )->add_declarations(
120
+ array(
121
+ 'border-color' => 'purple',
122
+ )
123
+ );
124
+
125
+ $this->assertEquals( '.a-lovely-rule,.a-lovelier-rule,.a-most-lovely-rule,.a-perfectly-lovely-rule {border-color: purple;}', $a_lovely_renderer->get_css() );
126
+ }
127
+ }
@@ -6,6 +6,7 @@
6
6
  * @subpackage style-engine
7
7
  */
8
8
 
9
+ require __DIR__ . '/../class-wp-style-engine-css-declarations.php';
9
10
  require __DIR__ . '/../class-wp-style-engine.php';
10
11
 
11
12
  /**
@@ -13,12 +14,16 @@ require __DIR__ . '/../class-wp-style-engine.php';
13
14
  */
14
15
  class WP_Style_Engine_Test extends WP_UnitTestCase {
15
16
  /**
16
- * Tests generating styles and classnames based on various manifestations of the $block_styles argument.
17
+ * Tests generating block styles and classnames based on various manifestations of the $block_styles argument.
17
18
  *
18
- * @dataProvider data_generate_styles_fixtures
19
+ * @dataProvider data_generate_block_supports_styles_fixtures
20
+ *
21
+ * @param array $block_styles The incoming block styles object.
22
+ * @param array $options Style engine options.
23
+ * @param string $expected_output The expected output.
19
24
  */
20
- function test_generate_styles( $block_styles, $options, $expected_output ) {
21
- $generated_styles = wp_style_engine_generate( $block_styles, $options );
25
+ public function test_generate_block_supports_styles( $block_styles, $options, $expected_output ) {
26
+ $generated_styles = wp_style_engine_get_block_supports_styles( $block_styles, $options );
22
27
  $this->assertSame( $expected_output, $generated_styles );
23
28
  }
24
29
 
@@ -27,7 +32,7 @@ class WP_Style_Engine_Test extends WP_UnitTestCase {
27
32
  *
28
33
  * @return array
29
34
  */
30
- public function data_generate_styles_fixtures() {
35
+ public function data_generate_block_supports_styles_fixtures() {
31
36
  return array(
32
37
  'default_return_value' => array(
33
38
  'block_styles' => array(),
@@ -82,10 +87,16 @@ class WP_Style_Engine_Test extends WP_UnitTestCase {
82
87
  'style' => 'dotted',
83
88
  ),
84
89
  ),
85
- 'options' => array(),
90
+ 'options' => array( 'convert_vars_to_classnames' => true ),
86
91
  'expected_output' => array(
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',
92
+ 'css' => 'border-style: dotted; border-width: 2rem; padding: 0; margin: 111px;',
93
+ 'declarations' => array(
94
+ 'border-style' => 'dotted',
95
+ 'border-width' => '2rem',
96
+ 'padding' => '0',
97
+ 'margin' => '111px',
98
+ ),
99
+ 'classnames' => 'has-text-color has-texas-flood-color has-border-color has-cool-caramel-border-color',
89
100
  ),
90
101
  ),
91
102
 
@@ -116,7 +127,21 @@ class WP_Style_Engine_Test extends WP_UnitTestCase {
116
127
  ),
117
128
  'options' => null,
118
129
  'expected_output' => array(
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;',
130
+ '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;',
131
+ 'declarations' => array(
132
+ 'border-top-left-radius' => '99px',
133
+ 'border-top-right-radius' => '98px',
134
+ 'border-bottom-left-radius' => '97px',
135
+ 'border-bottom-right-radius' => '96px',
136
+ 'padding-top' => '42px',
137
+ 'padding-left' => '2%',
138
+ 'padding-bottom' => '44px',
139
+ 'padding-right' => '5rem',
140
+ 'margin-top' => '12rem',
141
+ 'margin-left' => '2vh',
142
+ 'margin-bottom' => '2px',
143
+ 'margin-right' => '10em',
144
+ ),
120
145
  ),
121
146
  ),
122
147
 
@@ -135,7 +160,17 @@ class WP_Style_Engine_Test extends WP_UnitTestCase {
135
160
  ),
136
161
  'options' => null,
137
162
  'expected_output' => array(
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;',
163
+ '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;',
164
+ 'declarations' => array(
165
+ 'font-size' => 'clamp(2em, 2vw, 4em)',
166
+ 'font-family' => 'Roboto,Oxygen-Sans,Ubuntu,sans-serif',
167
+ 'font-style' => 'italic',
168
+ 'font-weight' => '800',
169
+ 'line-height' => '1.3',
170
+ 'text-decoration' => 'underline',
171
+ 'text-transform' => 'uppercase',
172
+ 'letter-spacing' => '2',
173
+ ),
139
174
  ),
140
175
  ),
141
176
 
@@ -152,7 +187,13 @@ class WP_Style_Engine_Test extends WP_UnitTestCase {
152
187
  ),
153
188
  'options' => array( 'selector' => '.wp-selector > p' ),
154
189
  'expected_output' => array(
155
- 'css' => '.wp-selector > p { padding-top: 42px; padding-left: 2%; padding-bottom: 44px; padding-right: 5rem; }',
190
+ 'css' => '.wp-selector > p { padding-top: 42px; padding-left: 2%; padding-bottom: 44px; padding-right: 5rem; }',
191
+ 'declarations' => array(
192
+ 'padding-top' => '42px',
193
+ 'padding-left' => '2%',
194
+ 'padding-bottom' => '44px',
195
+ 'padding-right' => '5rem',
196
+ ),
156
197
  ),
157
198
  ),
158
199
 
@@ -164,11 +205,13 @@ class WP_Style_Engine_Test extends WP_UnitTestCase {
164
205
  ),
165
206
  'options' => array(
166
207
  'selector' => '.wp-selector',
167
- 'css_vars' => true,
168
208
  ),
169
209
  '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',
210
+ 'css' => '.wp-selector { color: var(--wp--preset--color--my-little-pony); }',
211
+ 'declarations' => array(
212
+ 'color' => 'var(--wp--preset--color--my-little-pony)',
213
+ ),
214
+ 'classnames' => 'has-text-color has-my-little-pony-color',
172
215
  ),
173
216
  ),
174
217
 
@@ -196,7 +239,7 @@ class WP_Style_Engine_Test extends WP_UnitTestCase {
196
239
  'fontFamily' => 'var:preset|font-family|totally-awesome',
197
240
  ),
198
241
  ),
199
- 'options' => array(),
242
+ 'options' => array( 'convert_vars_to_classnames' => true ),
200
243
  'expected_output' => array(
201
244
  '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',
202
245
  ),
@@ -208,10 +251,13 @@ class WP_Style_Engine_Test extends WP_UnitTestCase {
208
251
  'text' => 'var:preset|color|teal-independents',
209
252
  ),
210
253
  ),
211
- 'options' => array( 'css_vars' => true ),
254
+ 'options' => array(),
212
255
  'expected_output' => array(
213
- 'css' => 'color: var(--wp--preset--color--teal-independents);',
214
- 'classnames' => 'has-text-color has-teal-independents-color',
256
+ 'css' => 'color: var(--wp--preset--color--teal-independents);',
257
+ 'declarations' => array(
258
+ 'color' => 'var(--wp--preset--color--teal-independents)',
259
+ ),
260
+ 'classnames' => 'has-text-color has-teal-independents-color',
215
261
  ),
216
262
  ),
217
263
 
@@ -224,8 +270,11 @@ class WP_Style_Engine_Test extends WP_UnitTestCase {
224
270
  ),
225
271
  'options' => array(),
226
272
  'expected_output' => array(
227
- 'css' => 'color: #fff;',
228
- 'classnames' => 'has-text-color',
273
+ 'css' => 'color: #fff;',
274
+ 'declarations' => array(
275
+ 'color' => '#fff',
276
+ ),
277
+ 'classnames' => 'has-text-color',
229
278
  ),
230
279
  ),
231
280
 
@@ -240,12 +289,83 @@ class WP_Style_Engine_Test extends WP_UnitTestCase {
240
289
  'padding' => 'var:preset|spacing|padding',
241
290
  ),
242
291
  ),
243
- 'options' => array(),
292
+ 'options' => array( 'convert_vars_to_classnames' => true ),
244
293
  'expected_output' => array(
245
294
  'classnames' => 'has-text-color has-background',
246
295
  ),
247
296
  ),
248
297
 
298
+ 'valid_spacing_single_preset_values' => array(
299
+ 'block_styles' => array(
300
+ 'spacing' => array(
301
+ 'margin' => 'var:preset|spacing|10',
302
+ 'padding' => 'var:preset|spacing|20',
303
+ ),
304
+ ),
305
+ 'options' => array(),
306
+ 'expected_output' => array(
307
+ 'css' => 'padding: var(--wp--preset--spacing--20); margin: var(--wp--preset--spacing--10);',
308
+ 'declarations' => array(
309
+ 'padding' => 'var(--wp--preset--spacing--20)',
310
+ 'margin' => 'var(--wp--preset--spacing--10)',
311
+ ),
312
+ ),
313
+ ),
314
+
315
+ 'valid_spacing_multi_preset_values' => array(
316
+ 'block_styles' => array(
317
+ 'spacing' => array(
318
+ 'margin' => array(
319
+ 'left' => 'var:preset|spacing|10',
320
+ 'right' => 'var:preset|spacing|20',
321
+ 'top' => '1rem',
322
+ 'bottom' => '1rem',
323
+ ),
324
+ 'padding' => array(
325
+ 'left' => 'var:preset|spacing|30',
326
+ 'right' => 'var:preset|spacing|40',
327
+ 'top' => '14px',
328
+ 'bottom' => '14px',
329
+ ),
330
+ ),
331
+ ),
332
+ 'options' => array(),
333
+ 'expected_output' => array(
334
+ 'css' => 'padding-left: var(--wp--preset--spacing--30); padding-right: var(--wp--preset--spacing--40); padding-top: 14px; padding-bottom: 14px; margin-left: var(--wp--preset--spacing--10); margin-right: var(--wp--preset--spacing--20); margin-top: 1rem; margin-bottom: 1rem;',
335
+ 'declarations' => array(
336
+ 'padding-left' => 'var(--wp--preset--spacing--30)',
337
+ 'padding-right' => 'var(--wp--preset--spacing--40)',
338
+ 'padding-top' => '14px',
339
+ 'padding-bottom' => '14px',
340
+ 'margin-left' => 'var(--wp--preset--spacing--10)',
341
+ 'margin-right' => 'var(--wp--preset--spacing--20)',
342
+ 'margin-top' => '1rem',
343
+ 'margin-bottom' => '1rem',
344
+ ),
345
+ ),
346
+ ),
347
+
348
+ 'invalid_spacing_multi_preset_values' => array(
349
+ 'block_styles' => array(
350
+ 'spacing' => array(
351
+ 'margin' => array(
352
+ 'left' => 'var:preset|spaceman|10',
353
+ 'right' => 'var:preset|spaceman|20',
354
+ 'top' => '1rem',
355
+ 'bottom' => '0',
356
+ ),
357
+ ),
358
+ ),
359
+ 'options' => array(),
360
+ 'expected_output' => array(
361
+ 'css' => 'margin-top: 1rem; margin-bottom: 0;',
362
+ 'declarations' => array(
363
+ 'margin-top' => '1rem',
364
+ 'margin-bottom' => '0',
365
+ ),
366
+ ),
367
+ ),
368
+
249
369
  'invalid_classnames_options' => array(
250
370
  'block_styles' => array(
251
371
  'typography' => array(
@@ -287,7 +407,20 @@ class WP_Style_Engine_Test extends WP_UnitTestCase {
287
407
  ),
288
408
  'options' => array(),
289
409
  '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;',
410
+ '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;',
411
+ 'declarations' => array(
412
+ 'border-top-color' => '#fe1',
413
+ 'border-top-width' => '1.5rem',
414
+ 'border-top-style' => 'dashed',
415
+ 'border-right-color' => '#fe2',
416
+ 'border-right-width' => '1.4rem',
417
+ 'border-right-style' => 'solid',
418
+ 'border-bottom-color' => '#fe3',
419
+ 'border-bottom-width' => '1.3rem',
420
+ 'border-left-color' => 'var(--wp--preset--color--swampy-yellow)',
421
+ 'border-left-width' => '0.5rem',
422
+ 'border-left-style' => 'dotted',
423
+ ),
291
424
  ),
292
425
  ),
293
426
 
@@ -317,7 +450,10 @@ class WP_Style_Engine_Test extends WP_UnitTestCase {
317
450
  ),
318
451
  'options' => array(),
319
452
  'expected_output' => array(
320
- 'css' => 'border-bottom-color: var(--wp--preset--color--terrible-lizard);',
453
+ 'css' => 'border-bottom-color: var(--wp--preset--color--terrible-lizard);',
454
+ 'declarations' => array(
455
+ 'border-bottom-color' => 'var(--wp--preset--color--terrible-lizard)',
456
+ ),
321
457
  ),
322
458
  ),
323
459
  );
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import type {
5
+ BorderIndividualStyles,
6
+ BorderIndividualProperty,
7
+ GeneratedCSSRule,
8
+ Style,
9
+ StyleDefinition,
10
+ StyleOptions,
11
+ } from '../../types';
12
+ import { generateRule, generateBoxRules, upperFirst } from '../utils';
13
+
14
+ const color = {
15
+ name: 'color',
16
+ generate: (
17
+ style: Style,
18
+ options: StyleOptions,
19
+ path: string[] = [ 'border', 'color' ],
20
+ ruleKey: string = 'borderColor'
21
+ ): GeneratedCSSRule[] => {
22
+ return generateRule( style, options, path, ruleKey );
23
+ },
24
+ };
25
+
26
+ const radius = {
27
+ name: 'radius',
28
+ generate: ( style: Style, options: StyleOptions ): GeneratedCSSRule[] => {
29
+ return generateBoxRules(
30
+ style,
31
+ options,
32
+ [ 'border', 'radius' ],
33
+ {
34
+ default: 'borderRadius',
35
+ individual: 'border%sRadius',
36
+ },
37
+ [ 'topLeft', 'topRight', 'bottomLeft', 'bottomRight' ]
38
+ );
39
+ },
40
+ };
41
+
42
+ const borderStyle = {
43
+ name: 'style',
44
+ generate: (
45
+ style: Style,
46
+ options: StyleOptions,
47
+ path: string[] = [ 'border', 'style' ],
48
+ ruleKey: string = 'borderStyle'
49
+ ): GeneratedCSSRule[] => {
50
+ return generateRule( style, options, path, ruleKey );
51
+ },
52
+ };
53
+
54
+ const width = {
55
+ name: 'width',
56
+ generate: (
57
+ style: Style,
58
+ options: StyleOptions,
59
+ path: string[] = [ 'border', 'width' ],
60
+ ruleKey: string = 'borderWidth'
61
+ ): GeneratedCSSRule[] => {
62
+ return generateRule( style, options, path, ruleKey );
63
+ },
64
+ };
65
+
66
+ const borderDefinitionsWithIndividualStyles: StyleDefinition[] = [
67
+ color,
68
+ borderStyle,
69
+ width,
70
+ ];
71
+
72
+ /**
73
+ * Returns a curried generator function with the individual border property ('top' | 'right' | 'bottom' | 'left') baked in.
74
+ *
75
+ * @param individualProperty Individual border property ('top' | 'right' | 'bottom' | 'left').
76
+ *
77
+ * @return StyleDefinition[ 'generate' ]
78
+ */
79
+ const createBorderGenerateFunction =
80
+ ( individualProperty: BorderIndividualProperty ) =>
81
+ ( style: Style, options: StyleOptions ) => {
82
+ const styleValue:
83
+ | BorderIndividualStyles< typeof individualProperty >
84
+ | undefined = style?.border?.[ individualProperty ];
85
+
86
+ if ( ! styleValue ) {
87
+ return [];
88
+ }
89
+
90
+ return borderDefinitionsWithIndividualStyles.reduce(
91
+ (
92
+ acc: GeneratedCSSRule[],
93
+ borderDefinition: StyleDefinition
94
+ ): GeneratedCSSRule[] => {
95
+ const key = borderDefinition.name;
96
+ if (
97
+ styleValue.hasOwnProperty( key ) &&
98
+ typeof borderDefinition.generate === 'function'
99
+ ) {
100
+ const ruleKey = `border${ upperFirst(
101
+ individualProperty
102
+ ) }${ upperFirst( key ) }`;
103
+ acc.push(
104
+ ...borderDefinition.generate(
105
+ style,
106
+ options,
107
+ [ 'border', individualProperty, key ],
108
+ ruleKey
109
+ )
110
+ );
111
+ }
112
+ return acc;
113
+ },
114
+ []
115
+ );
116
+ };
117
+
118
+ const borderTop = {
119
+ name: 'borderTop',
120
+ generate: createBorderGenerateFunction( 'top' ),
121
+ };
122
+
123
+ const borderRight = {
124
+ name: 'borderRight',
125
+ generate: createBorderGenerateFunction( 'right' ),
126
+ };
127
+
128
+ const borderBottom = {
129
+ name: 'borderBottom',
130
+ generate: createBorderGenerateFunction( 'bottom' ),
131
+ };
132
+
133
+ const borderLeft = {
134
+ name: 'borderLeft',
135
+ generate: createBorderGenerateFunction( 'left' ),
136
+ };
137
+
138
+ export default [
139
+ ...borderDefinitionsWithIndividualStyles,
140
+ radius,
141
+ borderTop,
142
+ borderRight,
143
+ borderBottom,
144
+ borderLeft,
145
+ ];
@@ -1,8 +1,14 @@
1
1
  /**
2
2
  * Internal dependencies
3
3
  */
4
+ import border from './border';
4
5
  import color from './color';
5
6
  import spacing from './spacing';
6
7
  import typography from './typography';
7
8
 
8
- export const styleDefinitions = [ ...color, ...spacing, ...typography ];
9
+ export const styleDefinitions = [
10
+ ...border,
11
+ ...color,
12
+ ...spacing,
13
+ ...typography,
14
+ ];