@stylexjs/babel-plugin 0.1.0-beta.1

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.
@@ -0,0 +1,551 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ jest.autoMockOff();
11
+
12
+ const { transformSync } = require('@babel/core');
13
+ const flowPlugin = require('@babel/plugin-syntax-flow');
14
+ const stylexPlugin = require('../src/index');
15
+
16
+ function transform(source, opts = {}) {
17
+ return transformSync(source, {
18
+ filename: opts.filename,
19
+ parserOpts: {
20
+ flow: {
21
+ all: true,
22
+ },
23
+ },
24
+ plugins: [flowPlugin, [stylexPlugin, opts]],
25
+ }).code;
26
+ }
27
+
28
+ describe('@stylexjs/babel-plugin', () => {
29
+ describe('[transform] stylex.create()', () => {
30
+ test('transforms style object', () => {
31
+ expect(
32
+ transform(`
33
+ import stylex from 'stylex';
34
+ const styles = stylex.create({
35
+ default: {
36
+ backgroundColor: 'red',
37
+ color: 'blue',
38
+ }
39
+ });
40
+ `)
41
+ ).toMatchInlineSnapshot(`
42
+ "import stylex from 'stylex';
43
+ stylex.inject(".xrkmrrc{background-color:red}", 1);
44
+ stylex.inject(".xju2f9n{color:blue}", 1);"
45
+ `);
46
+ });
47
+
48
+ test('transforms style object with custom propety', () => {
49
+ expect(
50
+ transform(`
51
+ import stylex from 'stylex';
52
+ const styles = stylex.create({
53
+ default: {
54
+ '--background-color': 'red',
55
+ }
56
+ });
57
+ `)
58
+ ).toMatchInlineSnapshot(`
59
+ "import stylex from 'stylex';
60
+ stylex.inject(".xgau0yw{--background-color:red}", 1);"
61
+ `);
62
+ });
63
+
64
+ test('transforms style object with custom propety as value', () => {
65
+ expect(
66
+ transform(`
67
+ import stylex from 'stylex';
68
+ const styles = stylex.create({
69
+ default: {
70
+ '--final-color': 'var(--background-color)',
71
+ }
72
+ });
73
+ `)
74
+ ).toMatchInlineSnapshot(`
75
+ "import stylex from 'stylex';
76
+ stylex.inject(".x13tgbkp{--final-color:var(--background-color)}", 1);"
77
+ `);
78
+ });
79
+
80
+ test('transforms multiple namespaces', () => {
81
+ expect(
82
+ transform(`
83
+ import stylex from 'stylex';
84
+ const styles = stylex.create({
85
+ default: {
86
+ backgroundColor: 'red',
87
+ },
88
+ default2: {
89
+ color: 'blue',
90
+ },
91
+ });
92
+ `)
93
+ ).toMatchInlineSnapshot(`
94
+ "import stylex from 'stylex';
95
+ stylex.inject(".xrkmrrc{background-color:red}", 1);
96
+ stylex.inject(".xju2f9n{color:blue}", 1);"
97
+ `);
98
+ });
99
+
100
+ test('does not transform attr() value', () => {
101
+ expect(
102
+ transform(`
103
+ import stylex from 'stylex';
104
+ const styles = stylex.create({
105
+ default: {
106
+ content: 'attr(some-attribute)',
107
+ },
108
+ });
109
+ `)
110
+ ).toMatchInlineSnapshot(`
111
+ "import stylex from 'stylex';
112
+ stylex.inject(".xd71okc{content:attr(some-attribute)}", 1);"
113
+ `);
114
+ });
115
+
116
+ test('transforms nested pseudo-class to CSS', () => {
117
+ expect(
118
+ transform(`
119
+ import stylex from 'stylex';
120
+ const styles = stylex.create({
121
+ default: {
122
+ ':hover': {
123
+ backgroundColor: 'red',
124
+ color: 'blue',
125
+ },
126
+ },
127
+ });
128
+ `)
129
+ ).toMatchInlineSnapshot(`
130
+ "import stylex from 'stylex';
131
+ stylex.inject(".x1gykpug:hover{background-color:red}", 8);
132
+ stylex.inject(".x17z2mba:hover{color:blue}", 8);"
133
+ `);
134
+ });
135
+
136
+ test('transforms array values as fallbacks', () => {
137
+ expect(
138
+ transform(`
139
+ import stylex from 'stylex';
140
+ const styles = stylex.create({
141
+ default: {
142
+ position: ['sticky', 'fixed']
143
+ },
144
+ });
145
+ `)
146
+ ).toMatchInlineSnapshot(`
147
+ "import stylex from 'stylex';
148
+ stylex.inject(".x1ruww2u{position:sticky;position:fixed}", 1);"
149
+ `);
150
+ });
151
+
152
+ // TODO: add more vendor-prefixed properties and values
153
+ test('transforms properties requiring vendor prefixes', () => {
154
+ expect(
155
+ transform(`
156
+ import stylex from 'stylex';
157
+ const styles = stylex.create({
158
+ default: {
159
+ userSelect: 'none',
160
+ },
161
+ });
162
+ `)
163
+ ).toMatchInlineSnapshot(`
164
+ "import stylex from 'stylex';
165
+ stylex.inject(".x87ps6o{user-select:none}", 1);"
166
+ `);
167
+ });
168
+
169
+ // Legacy, short?
170
+ test('tranforms valid shorthands', () => {
171
+ expect(
172
+ transform(`
173
+ import stylex from 'stylex';
174
+ const styles = stylex.create({
175
+ default: {
176
+ overflow: 'hidden',
177
+ borderStyle: 'dashed',
178
+ borderWidth: 1
179
+ }
180
+ });
181
+ `)
182
+ ).toMatchInlineSnapshot(`
183
+ "import stylex from 'stylex';
184
+ stylex.inject(".x6ikm8r{overflow-x:hidden}", 1);
185
+ stylex.inject(".x10wlt62{overflow-y:hidden}", 1);
186
+ stylex.inject(".xlya59e{border-top-style:dashed}", 1);
187
+ stylex.inject(".x157eodl{border-right-style:dashed}", 1, ".x157eodl{border-left-style:dashed}");
188
+ stylex.inject(".xpvcztv{border-bottom-style:dashed}", 1);
189
+ stylex.inject(".x1q04ism{border-left-style:dashed}", 1, ".x1q04ism{border-right-style:dashed}");
190
+ stylex.inject(".x178xt8z{border-top-width:1px}", 1);
191
+ stylex.inject(".xm81vs4{border-right-width:1px}", 1, ".xm81vs4{border-left-width:1px}");
192
+ stylex.inject(".xso031l{border-bottom-width:1px}", 1);
193
+ stylex.inject(".xy80clv{border-left-width:1px}", 1, ".xy80clv{border-right-width:1px}");"
194
+ `);
195
+ });
196
+
197
+ test('preserves imported object spread', () => {
198
+ expect(
199
+ transform(`
200
+ import stylex from 'stylex';
201
+ export const styles = stylex.create({
202
+ foo: {
203
+ ...(importedStyles.foo: XStyle<>)
204
+ }
205
+ });
206
+ `)
207
+ ).toMatchInlineSnapshot(`
208
+ "import stylex from 'stylex';
209
+ stylex.inject(".x1k9kg1j{include(imported-styles.foo):include(importedStyles.foo)}", 1);
210
+ export const styles = {
211
+ foo: {
212
+ ...importedStyles.foo
213
+ }
214
+ };"
215
+ `);
216
+ });
217
+
218
+ test('Uses stylex.include correctly with Identifiers', () => {
219
+ expect(
220
+ transform(`
221
+ import {create, include} from 'stylex';
222
+ export const styles = create({
223
+ foo: {
224
+ ...include(importedStyles)
225
+ }
226
+ });
227
+ `)
228
+ ).toMatchInlineSnapshot(`
229
+ "import { create, include } from 'stylex';
230
+ export const styles = {
231
+ foo: {
232
+ ...importedStyles
233
+ }
234
+ };"
235
+ `);
236
+ });
237
+
238
+ test('Uses stylex.include correctly with MemberExpressions', () => {
239
+ expect(
240
+ transform(`
241
+ import stylex from 'stylex';
242
+ export const styles = stylex.create({
243
+ foo: {
244
+ ...stylex.include(importedStyles.foo)
245
+ }
246
+ });
247
+ `)
248
+ ).toMatchInlineSnapshot(`
249
+ "import stylex from 'stylex';
250
+ export const styles = {
251
+ foo: {
252
+ ...importedStyles.foo
253
+ }
254
+ };"
255
+ `);
256
+ });
257
+
258
+ test('Uses stylex.firstThatWorks correctly', () => {
259
+ expect(
260
+ transform(`
261
+ export const styles = stylex.create({
262
+ foo: {
263
+ position: stylex.firstThatWorks('sticky', 'fixed'),
264
+ }
265
+ });
266
+ `)
267
+ ).toMatchInlineSnapshot(`
268
+ "export const styles = stylex.create({
269
+ foo: {
270
+ position: stylex.firstThatWorks('sticky', 'fixed')
271
+ }
272
+ });"
273
+ `);
274
+ });
275
+
276
+ test('transforms complex property values containing custom properties variables', () => {
277
+ expect(
278
+ transform(`
279
+ import stylex from 'stylex';
280
+ const styles = stylex.create({
281
+ default: {
282
+ boxShadow: '0px 2px 4px var(--shadow-1)',
283
+ }
284
+ });
285
+ `)
286
+ ).toMatchInlineSnapshot(`
287
+ "import stylex from 'stylex';
288
+ stylex.inject(".xxnfx33{box-shadow:0 2px 4px var(--shadow-1)}", 1);"
289
+ `);
290
+ });
291
+
292
+ describe('pseudo-classes', () => {
293
+ // TODO: this should either fail or guarantee an insertion order relative to valid pseudo-classes
294
+ test('transforms invalid pseudo-class', () => {
295
+ expect(
296
+ transform(`
297
+ import stylex from 'stylex';
298
+ const styles = stylex.create({
299
+ default: {
300
+ ':invalpwdijad': {
301
+ backgroundColor: 'red',
302
+ color: 'blue',
303
+ },
304
+ },
305
+ });
306
+ `)
307
+ ).toMatchInlineSnapshot(`
308
+ "import stylex from 'stylex';
309
+ stylex.inject(".x19iys6w:invalpwdijad{background-color:red}", 2);
310
+ stylex.inject(".x5z3o4w:invalpwdijad{color:blue}", 2);"
311
+ `);
312
+ });
313
+
314
+ test('transforms valid pseudo-classes in order', () => {
315
+ expect(
316
+ transform(`
317
+ import stylex from 'stylex';
318
+ const styles = stylex.create({
319
+ default: {
320
+ ':hover': {
321
+ color: 'blue',
322
+ },
323
+ ':active': {
324
+ color: 'red',
325
+ },
326
+ ':focus': {
327
+ color: 'yellow',
328
+ },
329
+ ':nth-child(2n)': {
330
+ color: 'purple'
331
+ }
332
+ },
333
+ });
334
+ `)
335
+ ).toMatchInlineSnapshot(`
336
+ "import stylex from 'stylex';
337
+ stylex.inject(".x17z2mba:hover{color:blue}", 8);
338
+ stylex.inject(".x96fq8s:active{color:red}", 10);
339
+ stylex.inject(".x1wvtd7d:focus{color:yellow}", 9);
340
+ stylex.inject(".x126ychx:nth-child(2n){color:purple}", 6);"
341
+ `);
342
+ });
343
+
344
+ test('transforms pseudo-class with array value as fallbacks', () => {
345
+ expect(
346
+ transform(`
347
+ import stylex from 'stylex';
348
+ const styles = stylex.create({
349
+ default: {
350
+ ':hover': {
351
+ position: ['sticky', 'fixed'],
352
+ }
353
+ },
354
+ });
355
+ `)
356
+ ).toMatchInlineSnapshot(`
357
+ "import stylex from 'stylex';
358
+ stylex.inject(".x1nxcus0:hover{position:sticky;position:fixed}", 8);"
359
+ `);
360
+ });
361
+ });
362
+
363
+ // TODO: more unsupported pseudo-classes
364
+ describe('pseudo-elements', () => {
365
+ test('transforms ::before and ::after', () => {
366
+ expect(
367
+ transform(`
368
+ import stylex from 'stylex';
369
+ const styles = stylex.create({
370
+ foo: {
371
+ '::before': {
372
+ color: 'red'
373
+ },
374
+ '::after': {
375
+ color: 'blue'
376
+ },
377
+ },
378
+ });
379
+ `)
380
+ ).toMatchInlineSnapshot(`
381
+ "import stylex from 'stylex';
382
+ stylex.inject(".x16oeupf::before{color:red}", 2);
383
+ stylex.inject(".xdaarc3::after{color:blue}", 2);"
384
+ `);
385
+ });
386
+
387
+ test('transforms ::placeholder', () => {
388
+ expect(
389
+ transform(`
390
+ import stylex from 'stylex';
391
+ const styles = stylex.create({
392
+ foo: {
393
+ '::placeholder': {
394
+ color: 'gray',
395
+ },
396
+ },
397
+ });
398
+ `)
399
+ ).toMatchInlineSnapshot(`
400
+ "import stylex from 'stylex';
401
+ stylex.inject(".x6yu8oj::placeholder{color:gray}", 12);"
402
+ `);
403
+ });
404
+
405
+ test('transforms ::thumb', () => {
406
+ expect(
407
+ transform(`
408
+ import stylex from 'stylex';
409
+ const styles = stylex.create({
410
+ foo: {
411
+ '::thumb': {
412
+ width: 16,
413
+ },
414
+ },
415
+ });
416
+ `)
417
+ ).toMatchInlineSnapshot(`
418
+ "import stylex from 'stylex';
419
+ stylex.inject(".x1en94km::-webkit-slider-thumb, .x1en94km::-moz-range-thumb, .x1en94km::-ms-thumb{width:16px}", 13);"
420
+ `);
421
+ });
422
+ });
423
+
424
+ describe('queries', () => {
425
+ test('transforms media queries', () => {
426
+ expect(
427
+ transform(`
428
+ import stylex from 'stylex';
429
+ const styles = stylex.create({
430
+ default: {
431
+ backgroundColor: 'red',
432
+ '@media (min-width: 1000px)': {
433
+ backgroundColor: 'blue',
434
+ },
435
+ '@media (min-width: 2000px)': {
436
+ backgroundColor: 'purple',
437
+ },
438
+ },
439
+ });
440
+ `)
441
+ ).toMatchInlineSnapshot(`
442
+ "import stylex from 'stylex';
443
+ stylex.inject(".xrkmrrc{background-color:red}", 1);
444
+ stylex.inject("@media (min-width: 1000px){.xc445zv.xc445zv{background-color:blue}}", 2);
445
+ stylex.inject("@media (min-width: 2000px){.x1ssfqz5.x1ssfqz5{background-color:purple}}", 2);"
446
+ `);
447
+ });
448
+
449
+ test('transforms supports queries', () => {
450
+ expect(
451
+ transform(`
452
+ import stylex from 'stylex';
453
+ const styles = stylex.create({
454
+ default: {
455
+ backgroundColor: 'red',
456
+ '@supports (hover: hover)': {
457
+ backgroundColor: 'blue',
458
+ },
459
+ '@supports not (hover: hover)': {
460
+ backgroundColor: 'purple',
461
+ },
462
+ },
463
+ });
464
+
465
+ `)
466
+ ).toMatchInlineSnapshot(`
467
+ "import stylex from 'stylex';
468
+ stylex.inject(".xrkmrrc{background-color:red}", 1);
469
+ stylex.inject("@supports (hover: hover){.x6m3b6q.x6m3b6q{background-color:blue}}", 2);
470
+ stylex.inject("@supports not (hover: hover){.x6um648.x6um648{background-color:purple}}", 2);"
471
+ `);
472
+ });
473
+ });
474
+
475
+ test('[legacy] auto-expands shorthands', () => {
476
+ expect(
477
+ transform(`
478
+ import stylex from 'stylex';
479
+ const borderRadius = 2;
480
+ const styles = stylex.create({
481
+ default: {
482
+ margin: 'calc((100% - 50px) * 0.5) 20px 0',
483
+ },
484
+ error: {
485
+ borderColor: 'red blue',
486
+ borderStyle: 'dashed',
487
+ borderWidth: '0 0 2px 0',
488
+ },
489
+ root: {
490
+ border: '1px solid var(--divider)',
491
+ borderRadius: borderRadius * 2,
492
+ borderBottom: '5px solid red',
493
+ },
494
+ short: {
495
+ padding: 'calc((100% - 50px) * 0.5) var(--rightpadding, 20px)',
496
+ paddingTop: 0,
497
+ },
498
+ valid: {
499
+ borderColor: 'green',
500
+ borderStyle: 'solid',
501
+ borderWidth: 1,
502
+ }
503
+ });
504
+ `)
505
+ ).toMatchInlineSnapshot(`
506
+ "import stylex from 'stylex';
507
+ const borderRadius = 2;
508
+ stylex.inject(".xxsse2n{margin-top:calc((100% - 50px) * .5)}", 1);
509
+ stylex.inject(".x1h5jrl4{margin-right:20px}", 1, ".x1h5jrl4{margin-left:20px}");
510
+ stylex.inject(".xat24cr{margin-bottom:0}", 1);
511
+ stylex.inject(".xmn8rco{margin-left:20px}", 1, ".xmn8rco{margin-right:20px}");
512
+ stylex.inject(".x1uu1fcu{border-top-color:red}", 1);
513
+ stylex.inject(".xkwlhv9{border-right-color:blue}", 1, ".xkwlhv9{border-left-color:blue}");
514
+ stylex.inject(".xud65wk{border-bottom-color:red}", 1);
515
+ stylex.inject(".x1z0yhbn{border-left-color:blue}", 1, ".x1z0yhbn{border-right-color:blue}");
516
+ stylex.inject(".xlya59e{border-top-style:dashed}", 1);
517
+ stylex.inject(".x157eodl{border-right-style:dashed}", 1, ".x157eodl{border-left-style:dashed}");
518
+ stylex.inject(".xpvcztv{border-bottom-style:dashed}", 1);
519
+ stylex.inject(".x1q04ism{border-left-style:dashed}", 1, ".x1q04ism{border-right-style:dashed}");
520
+ stylex.inject(".x972fbf{border-top-width:0}", 1);
521
+ stylex.inject(".xcfux6l{border-right-width:0}", 1, ".xcfux6l{border-left-width:0}");
522
+ stylex.inject(".xlxy82{border-bottom-width:2px}", 1);
523
+ stylex.inject(".xm0m39n{border-left-width:0}", 1, ".xm0m39n{border-right-width:0}");
524
+ stylex.inject(".x1n2xptk{border-top:1px solid var(--divider)}", 1);
525
+ stylex.inject(".xkbpzyx{border-right:1px solid var(--divider)}", 1, ".xkbpzyx{border-left:1px solid var(--divider)}");
526
+ stylex.inject(".xdwpb5{border-bottom:5px solid red}", 1);
527
+ stylex.inject(".x1rr5fae{border-left:1px solid var(--divider)}", 1, ".x1rr5fae{border-right:1px solid var(--divider)}");
528
+ stylex.inject(".x1lcm9me{border-top-left-radius:4px}", 1, ".x1lcm9me{border-top-right-radius:4px}");
529
+ stylex.inject(".x1yr5g0i{border-top-right-radius:4px}", 1, ".x1yr5g0i{border-top-left-radius:4px}");
530
+ stylex.inject(".xrt01vj{border-bottom-right-radius:4px}", 1, ".xrt01vj{border-bottom-left-radius:4px}");
531
+ stylex.inject(".x10y3i5r{border-bottom-left-radius:4px}", 1, ".x10y3i5r{border-bottom-right-radius:4px}");
532
+ stylex.inject(".xexx8yu{padding-top:0}", 1);
533
+ stylex.inject(".xcrpjku{padding-right:var(--rightpadding,20px)}", 1, ".xcrpjku{padding-left:var(--rightpadding,20px)}");
534
+ stylex.inject(".x18xuxqe{padding-bottom:calc((100% - 50px) * .5)}", 1);
535
+ stylex.inject(".xyv1419{padding-left:var(--rightpadding,20px)}", 1, ".xyv1419{padding-right:var(--rightpadding,20px)}");
536
+ stylex.inject(".xb9njkq{border-top-color:green}", 1);
537
+ stylex.inject(".x1plg3iu{border-right-color:green}", 1, ".x1plg3iu{border-left-color:green}");
538
+ stylex.inject(".x1hnil3p{border-bottom-color:green}", 1);
539
+ stylex.inject(".x1s0fimb{border-left-color:green}", 1, ".x1s0fimb{border-right-color:green}");
540
+ stylex.inject(".x13fuv20{border-top-style:solid}", 1);
541
+ stylex.inject(".xu3j5b3{border-right-style:solid}", 1, ".xu3j5b3{border-left-style:solid}");
542
+ stylex.inject(".x1q0q8m5{border-bottom-style:solid}", 1);
543
+ stylex.inject(".x26u7qi{border-left-style:solid}", 1, ".x26u7qi{border-right-style:solid}");
544
+ stylex.inject(".x178xt8z{border-top-width:1px}", 1);
545
+ stylex.inject(".xm81vs4{border-right-width:1px}", 1, ".xm81vs4{border-left-width:1px}");
546
+ stylex.inject(".xso031l{border-bottom-width:1px}", 1);
547
+ stylex.inject(".xy80clv{border-left-width:1px}", 1, ".xy80clv{border-right-width:1px}");"
548
+ `);
549
+ });
550
+ });
551
+ });