@cwcss/crosswind 0.1.5 → 0.1.6

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 (86) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +390 -0
  3. package/dist/build.d.ts +24 -0
  4. package/dist/config.d.ts +5 -0
  5. package/dist/generator.d.ts +31 -0
  6. package/dist/index.d.ts +10 -0
  7. package/dist/index.js +12798 -0
  8. package/dist/parser.d.ts +42 -0
  9. package/dist/plugin.d.ts +22 -0
  10. package/dist/preflight-forms.d.ts +5 -0
  11. package/dist/preflight.d.ts +2 -0
  12. package/dist/rules-advanced.d.ts +27 -0
  13. package/dist/rules-effects.d.ts +25 -0
  14. package/dist/rules-forms.d.ts +7 -0
  15. package/dist/rules-grid.d.ts +13 -0
  16. package/dist/rules-interactivity.d.ts +41 -0
  17. package/dist/rules-layout.d.ts +26 -0
  18. package/dist/rules-transforms.d.ts +33 -0
  19. package/dist/rules-typography.d.ts +41 -0
  20. package/dist/rules.d.ts +39 -0
  21. package/dist/scanner.d.ts +18 -0
  22. package/dist/transformer-compile-class.d.ts +37 -0
  23. package/{src/types.ts → dist/types.d.ts} +17 -86
  24. package/package.json +1 -1
  25. package/PLUGIN.md +0 -235
  26. package/benchmark/framework-comparison.bench.ts +0 -850
  27. package/bin/cli.ts +0 -365
  28. package/bin/crosswind +0 -0
  29. package/bin/headwind +0 -0
  30. package/build.ts +0 -8
  31. package/crosswind.config.ts +0 -9
  32. package/example/comprehensive.html +0 -70
  33. package/example/index.html +0 -21
  34. package/example/output.css +0 -236
  35. package/examples/plugin/README.md +0 -112
  36. package/examples/plugin/build.ts +0 -32
  37. package/examples/plugin/src/index.html +0 -34
  38. package/examples/plugin/src/index.ts +0 -7
  39. package/headwind +0 -2
  40. package/src/build.ts +0 -101
  41. package/src/config.ts +0 -529
  42. package/src/generator.ts +0 -2173
  43. package/src/index.ts +0 -10
  44. package/src/parser.ts +0 -1471
  45. package/src/plugin.ts +0 -118
  46. package/src/preflight-forms.ts +0 -229
  47. package/src/preflight.ts +0 -388
  48. package/src/rules-advanced.ts +0 -477
  49. package/src/rules-effects.ts +0 -461
  50. package/src/rules-forms.ts +0 -103
  51. package/src/rules-grid.ts +0 -241
  52. package/src/rules-interactivity.ts +0 -525
  53. package/src/rules-layout.ts +0 -385
  54. package/src/rules-transforms.ts +0 -412
  55. package/src/rules-typography.ts +0 -486
  56. package/src/rules.ts +0 -809
  57. package/src/scanner.ts +0 -84
  58. package/src/transformer-compile-class.ts +0 -275
  59. package/test/advanced-features.test.ts +0 -911
  60. package/test/arbitrary.test.ts +0 -396
  61. package/test/attributify.test.ts +0 -592
  62. package/test/bracket-syntax.test.ts +0 -1133
  63. package/test/build.test.ts +0 -99
  64. package/test/colors.test.ts +0 -934
  65. package/test/flexbox.test.ts +0 -669
  66. package/test/generator.test.ts +0 -597
  67. package/test/grid.test.ts +0 -584
  68. package/test/layout.test.ts +0 -404
  69. package/test/modifiers.test.ts +0 -417
  70. package/test/parser.test.ts +0 -564
  71. package/test/performance-regression.test.ts +0 -376
  72. package/test/performance.test.ts +0 -568
  73. package/test/plugin.test.ts +0 -160
  74. package/test/scanner.test.ts +0 -94
  75. package/test/sizing.test.ts +0 -481
  76. package/test/spacing.test.ts +0 -394
  77. package/test/transformer-compile-class.test.ts +0 -287
  78. package/test/transforms.test.ts +0 -448
  79. package/test/typography.test.ts +0 -632
  80. package/test/variants-form-states.test.ts +0 -225
  81. package/test/variants-group-peer.test.ts +0 -66
  82. package/test/variants-media.test.ts +0 -213
  83. package/test/variants-positional.test.ts +0 -58
  84. package/test/variants-pseudo-elements.test.ts +0 -47
  85. package/test/variants-state.test.ts +0 -62
  86. package/tsconfig.json +0 -18
@@ -1,911 +0,0 @@
1
- import type { CustomRule } from '../src/types'
2
- import { describe, expect, it } from 'bun:test'
3
- import { defaultConfig } from '../src/config'
4
- import { CSSGenerator } from '../src/generator'
5
-
6
- describe('Advanced Features', () => {
7
- describe('Filter utilities', () => {
8
- it('should handle blur filter', () => {
9
- const gen = new CSSGenerator(defaultConfig)
10
- gen.generate('blur')
11
- gen.generate('blur-sm')
12
- gen.generate('blur-lg')
13
- gen.generate('blur-none')
14
- const css = gen.toCSS(false)
15
- expect(css).toContain('blur')
16
- })
17
-
18
- it('should handle brightness filter', () => {
19
- const gen = new CSSGenerator(defaultConfig)
20
- gen.generate('brightness-0')
21
- gen.generate('brightness-50')
22
- gen.generate('brightness-100')
23
- gen.generate('brightness-150')
24
- const css = gen.toCSS(false)
25
- expect(css).toContain('brightness')
26
- })
27
-
28
- it('should handle contrast filter', () => {
29
- const gen = new CSSGenerator(defaultConfig)
30
- gen.generate('contrast-0')
31
- gen.generate('contrast-100')
32
- gen.generate('contrast-150')
33
- const css = gen.toCSS(false)
34
- expect(css).toContain('contrast')
35
- })
36
-
37
- it('should handle grayscale filter', () => {
38
- const gen = new CSSGenerator(defaultConfig)
39
- gen.generate('grayscale-0')
40
- gen.generate('grayscale')
41
- const css = gen.toCSS(false)
42
- expect(css).toContain('grayscale')
43
- })
44
-
45
- it('should handle invert filter', () => {
46
- const gen = new CSSGenerator(defaultConfig)
47
- gen.generate('invert-0')
48
- gen.generate('invert')
49
- const css = gen.toCSS(false)
50
- expect(css).toContain('invert')
51
- })
52
-
53
- it('should handle saturate filter', () => {
54
- const gen = new CSSGenerator(defaultConfig)
55
- gen.generate('saturate-0')
56
- gen.generate('saturate-50')
57
- gen.generate('saturate-100')
58
- gen.generate('saturate-200')
59
- const css = gen.toCSS(false)
60
- expect(css).toContain('saturate')
61
- })
62
-
63
- it('should handle sepia filter', () => {
64
- const gen = new CSSGenerator(defaultConfig)
65
- gen.generate('sepia-0')
66
- gen.generate('sepia')
67
- const css = gen.toCSS(false)
68
- expect(css).toContain('sepia')
69
- })
70
-
71
- it('should handle hue-rotate filter', () => {
72
- const gen = new CSSGenerator(defaultConfig)
73
- gen.generate('hue-rotate-0')
74
- gen.generate('hue-rotate-30')
75
- gen.generate('hue-rotate-90')
76
- gen.generate('hue-rotate-180')
77
- const css = gen.toCSS(false)
78
- expect(css).toContain('hue')
79
- })
80
-
81
- it('should handle drop-shadow filter', () => {
82
- const gen = new CSSGenerator(defaultConfig)
83
- gen.generate('drop-shadow')
84
- gen.generate('drop-shadow-sm')
85
- gen.generate('drop-shadow-lg')
86
- gen.generate('drop-shadow-none')
87
- const css = gen.toCSS(false)
88
- expect(css).toContain('drop-shadow')
89
- })
90
-
91
- it('should handle filter-none', () => {
92
- const gen = new CSSGenerator(defaultConfig)
93
- gen.generate('filter-none')
94
- const css = gen.toCSS(false)
95
- expect(css).toContain('filter')
96
- })
97
- })
98
-
99
- describe('Backdrop filter utilities', () => {
100
- it('should handle backdrop-blur', () => {
101
- const gen = new CSSGenerator(defaultConfig)
102
- gen.generate('backdrop-blur')
103
- gen.generate('backdrop-blur-sm')
104
- gen.generate('backdrop-blur-lg')
105
- gen.generate('backdrop-blur-none')
106
- const css = gen.toCSS(false)
107
- expect(css).toContain('backdrop')
108
- })
109
-
110
- it('should handle backdrop-brightness', () => {
111
- const gen = new CSSGenerator(defaultConfig)
112
- gen.generate('backdrop-brightness-0')
113
- gen.generate('backdrop-brightness-100')
114
- gen.generate('backdrop-brightness-150')
115
- const css = gen.toCSS(false)
116
- expect(css).toContain('backdrop')
117
- })
118
-
119
- it('should handle backdrop-contrast', () => {
120
- const gen = new CSSGenerator(defaultConfig)
121
- gen.generate('backdrop-contrast-0')
122
- gen.generate('backdrop-contrast-100')
123
- const css = gen.toCSS(false)
124
- expect(css).toContain('backdrop')
125
- })
126
-
127
- it('should handle backdrop-grayscale', () => {
128
- const gen = new CSSGenerator(defaultConfig)
129
- gen.generate('backdrop-grayscale-0')
130
- gen.generate('backdrop-grayscale')
131
- const css = gen.toCSS(false)
132
- expect(css).toContain('backdrop')
133
- })
134
-
135
- it('should handle backdrop-saturate', () => {
136
- const gen = new CSSGenerator(defaultConfig)
137
- gen.generate('backdrop-saturate-0')
138
- gen.generate('backdrop-saturate-100')
139
- const css = gen.toCSS(false)
140
- expect(css).toContain('backdrop')
141
- })
142
-
143
- it('should handle backdrop-sepia', () => {
144
- const gen = new CSSGenerator(defaultConfig)
145
- gen.generate('backdrop-sepia-0')
146
- gen.generate('backdrop-sepia')
147
- const css = gen.toCSS(false)
148
- expect(css).toContain('backdrop')
149
- })
150
-
151
- it('should handle backdrop-invert', () => {
152
- const gen = new CSSGenerator(defaultConfig)
153
- gen.generate('backdrop-invert-0')
154
- gen.generate('backdrop-invert')
155
- const css = gen.toCSS(false)
156
- expect(css).toContain('backdrop')
157
- })
158
- })
159
-
160
- describe('Transition utilities', () => {
161
- it('should handle transition property', () => {
162
- const gen = new CSSGenerator(defaultConfig)
163
- gen.generate('transition')
164
- gen.generate('transition-none')
165
- gen.generate('transition-all')
166
- gen.generate('transition-colors')
167
- gen.generate('transition-opacity')
168
- gen.generate('transition-shadow')
169
- gen.generate('transition-transform')
170
- const css = gen.toCSS(false)
171
- expect(css).toContain('transition')
172
- })
173
-
174
- it('should handle transition duration', () => {
175
- const gen = new CSSGenerator(defaultConfig)
176
- gen.generate('duration-75')
177
- gen.generate('duration-100')
178
- gen.generate('duration-150')
179
- gen.generate('duration-200')
180
- gen.generate('duration-300')
181
- gen.generate('duration-500')
182
- gen.generate('duration-700')
183
- gen.generate('duration-1000')
184
- const css = gen.toCSS(false)
185
- expect(css).toContain('duration')
186
- })
187
-
188
- it('should handle transition timing', () => {
189
- const gen = new CSSGenerator(defaultConfig)
190
- gen.generate('ease-linear')
191
- gen.generate('ease-in')
192
- gen.generate('ease-out')
193
- gen.generate('ease-in-out')
194
- const css = gen.toCSS(false)
195
- expect(css).toContain('ease')
196
- })
197
-
198
- it('should handle transition delay', () => {
199
- const gen = new CSSGenerator(defaultConfig)
200
- gen.generate('delay-75')
201
- gen.generate('delay-100')
202
- gen.generate('delay-150')
203
- gen.generate('delay-200')
204
- gen.generate('delay-300')
205
- const css = gen.toCSS(false)
206
- expect(css).toContain('delay')
207
- })
208
-
209
- it('should handle custom transition duration', () => {
210
- const gen = new CSSGenerator(defaultConfig)
211
- gen.generate('duration-[2s]')
212
- gen.generate('delay-[500ms]')
213
- const css = gen.toCSS(false)
214
- expect(css).toContain('2s')
215
- expect(css).toContain('500ms')
216
- })
217
- })
218
-
219
- describe('Animation utilities', () => {
220
- it('should handle animation types', () => {
221
- const gen = new CSSGenerator(defaultConfig)
222
- gen.generate('animate-none')
223
- gen.generate('animate-spin')
224
- gen.generate('animate-ping')
225
- gen.generate('animate-pulse')
226
- gen.generate('animate-bounce')
227
- const css = gen.toCSS(false)
228
- expect(css).toContain('animation')
229
- })
230
-
231
- it('should handle custom animation', () => {
232
- const gen = new CSSGenerator(defaultConfig)
233
- gen.generate('animate-[wiggle_1s_ease-in-out_infinite]')
234
- const css = gen.toCSS(false)
235
- expect(css).toContain('wiggle')
236
- })
237
- })
238
-
239
- describe('Table utilities', () => {
240
- it('should handle border-collapse', () => {
241
- const gen = new CSSGenerator(defaultConfig)
242
- gen.generate('border-collapse')
243
- gen.generate('border-separate')
244
- const css = gen.toCSS(false)
245
- expect(css).toContain('border-collapse')
246
- })
247
-
248
- it('should handle border-spacing', () => {
249
- const gen = new CSSGenerator(defaultConfig)
250
- gen.generate('border-spacing-0')
251
- gen.generate('border-spacing-1')
252
- gen.generate('border-spacing-2')
253
- gen.generate('border-spacing-x-4')
254
- gen.generate('border-spacing-y-4')
255
- const css = gen.toCSS(false)
256
- expect(css).toContain('border-spacing')
257
- })
258
-
259
- it('should handle table-layout', () => {
260
- const gen = new CSSGenerator(defaultConfig)
261
- gen.generate('table-auto')
262
- gen.generate('table-fixed')
263
- const css = gen.toCSS(false)
264
- expect(css).toContain('table-layout')
265
- })
266
-
267
- it('should handle caption-side', () => {
268
- const gen = new CSSGenerator(defaultConfig)
269
- gen.generate('caption-top')
270
- gen.generate('caption-bottom')
271
- const css = gen.toCSS(false)
272
- expect(css).toContain('caption-side')
273
- })
274
- })
275
-
276
- describe('Advanced interactivity', () => {
277
- it('should handle accent-color', () => {
278
- const gen = new CSSGenerator(defaultConfig)
279
- gen.generate('accent-auto')
280
- gen.generate('accent-blue-500')
281
- gen.generate('accent-red-500')
282
- const css = gen.toCSS(false)
283
- expect(css).toContain('accent-color')
284
- })
285
-
286
- it('should handle appearance', () => {
287
- const gen = new CSSGenerator(defaultConfig)
288
- gen.generate('appearance-none')
289
- gen.generate('appearance-auto')
290
- const css = gen.toCSS(false)
291
- expect(css).toContain('appearance')
292
- })
293
-
294
- it('should handle caret-color', () => {
295
- const gen = new CSSGenerator(defaultConfig)
296
- gen.generate('caret-auto')
297
- gen.generate('caret-blue-500')
298
- gen.generate('caret-transparent')
299
- const css = gen.toCSS(false)
300
- expect(css).toContain('caret-color')
301
- })
302
-
303
- it('should handle color-scheme', () => {
304
- const gen = new CSSGenerator(defaultConfig)
305
- gen.generate('color-scheme-light')
306
- gen.generate('color-scheme-dark')
307
- gen.generate('color-scheme-auto')
308
- const css = gen.toCSS(false)
309
- expect(css).toContain('color-scheme')
310
- })
311
-
312
- it('should handle field-sizing', () => {
313
- const gen = new CSSGenerator(defaultConfig)
314
- gen.generate('field-sizing-content')
315
- gen.generate('field-sizing-fixed')
316
- const css = gen.toCSS(false)
317
- expect(css).toContain('field-sizing')
318
- })
319
-
320
- it('should handle touch-action', () => {
321
- const gen = new CSSGenerator(defaultConfig)
322
- gen.generate('touch-auto')
323
- gen.generate('touch-none')
324
- gen.generate('touch-pan-x')
325
- gen.generate('touch-pan-y')
326
- gen.generate('touch-pan-left')
327
- gen.generate('touch-pan-right')
328
- gen.generate('touch-pan-up')
329
- gen.generate('touch-pan-down')
330
- gen.generate('touch-pinch-zoom')
331
- gen.generate('touch-manipulation')
332
- const css = gen.toCSS(false)
333
- expect(css).toContain('touch-action')
334
- })
335
- })
336
-
337
- describe('Scroll utilities', () => {
338
- it('should handle scroll-margin', () => {
339
- const gen = new CSSGenerator(defaultConfig)
340
- gen.generate('scroll-m-0')
341
- gen.generate('scroll-m-4')
342
- gen.generate('scroll-mx-4')
343
- gen.generate('scroll-my-4')
344
- gen.generate('scroll-mt-4')
345
- gen.generate('scroll-mr-4')
346
- gen.generate('scroll-mb-4')
347
- gen.generate('scroll-ml-4')
348
- const css = gen.toCSS(false)
349
- expect(css).toContain('scroll-margin')
350
- })
351
-
352
- it('should handle scroll-padding', () => {
353
- const gen = new CSSGenerator(defaultConfig)
354
- gen.generate('scroll-p-0')
355
- gen.generate('scroll-p-4')
356
- gen.generate('scroll-px-4')
357
- gen.generate('scroll-py-4')
358
- gen.generate('scroll-pt-4')
359
- gen.generate('scroll-pr-4')
360
- gen.generate('scroll-pb-4')
361
- gen.generate('scroll-pl-4')
362
- const css = gen.toCSS(false)
363
- expect(css).toContain('scroll-padding')
364
- })
365
-
366
- it('should handle scroll-snap-type', () => {
367
- const gen = new CSSGenerator(defaultConfig)
368
- gen.generate('snap-none')
369
- gen.generate('snap-x')
370
- gen.generate('snap-y')
371
- gen.generate('snap-both')
372
- gen.generate('snap-mandatory')
373
- gen.generate('snap-proximity')
374
- const css = gen.toCSS(false)
375
- expect(css).toContain('scroll-snap')
376
- })
377
-
378
- it('should handle scroll-snap-align', () => {
379
- const gen = new CSSGenerator(defaultConfig)
380
- gen.generate('snap-start')
381
- gen.generate('snap-end')
382
- gen.generate('snap-center')
383
- gen.generate('snap-align-none')
384
- const css = gen.toCSS(false)
385
- expect(css).toContain('scroll-snap-align')
386
- })
387
-
388
- it('should handle scroll-snap-stop', () => {
389
- const gen = new CSSGenerator(defaultConfig)
390
- gen.generate('snap-normal')
391
- gen.generate('snap-always')
392
- const css = gen.toCSS(false)
393
- expect(css).toContain('scroll-snap-stop')
394
- })
395
- })
396
-
397
- describe('Child selectors', () => {
398
- it('should handle space-x utilities', () => {
399
- const gen = new CSSGenerator(defaultConfig)
400
- gen.generate('space-x-0')
401
- gen.generate('space-x-4')
402
- gen.generate('space-x-8')
403
- gen.generate('space-x-reverse')
404
- const css = gen.toCSS(false)
405
- expect(css).toContain('--hw-space-x-reverse')
406
- expect(css).toContain('margin-right')
407
- expect(css).toContain('margin-left')
408
- })
409
-
410
- it('should handle space-y utilities', () => {
411
- const gen = new CSSGenerator(defaultConfig)
412
- gen.generate('space-y-0')
413
- gen.generate('space-y-4')
414
- gen.generate('space-y-8')
415
- gen.generate('space-y-reverse')
416
- const css = gen.toCSS(false)
417
- expect(css).toContain('--hw-space-y-reverse')
418
- expect(css).toContain('margin-top')
419
- expect(css).toContain('margin-bottom')
420
- })
421
-
422
- it('should handle negative space values', () => {
423
- const gen = new CSSGenerator(defaultConfig)
424
- gen.generate('-space-x-4')
425
- gen.generate('-space-y-4')
426
- const css = gen.toCSS(false)
427
- expect(css).toContain('-')
428
- })
429
-
430
- it('should handle divide-x utilities', () => {
431
- const gen = new CSSGenerator(defaultConfig)
432
- gen.generate('divide-x')
433
- gen.generate('divide-x-0')
434
- gen.generate('divide-x-2')
435
- gen.generate('divide-x-4')
436
- gen.generate('divide-x-reverse')
437
- const css = gen.toCSS(false)
438
- expect(css).toContain('border')
439
- })
440
-
441
- it('should handle divide-y utilities', () => {
442
- const gen = new CSSGenerator(defaultConfig)
443
- gen.generate('divide-y')
444
- gen.generate('divide-y-0')
445
- gen.generate('divide-y-2')
446
- gen.generate('divide-y-4')
447
- gen.generate('divide-y-reverse')
448
- const css = gen.toCSS(false)
449
- expect(css).toContain('border')
450
- })
451
-
452
- it('should handle divide style utilities', () => {
453
- const gen = new CSSGenerator(defaultConfig)
454
- gen.generate('divide-solid')
455
- gen.generate('divide-dashed')
456
- gen.generate('divide-dotted')
457
- gen.generate('divide-double')
458
- gen.generate('divide-none')
459
- const css = gen.toCSS(false)
460
- expect(css).toContain('border-style')
461
- })
462
-
463
- it('should handle divide color utilities', () => {
464
- const gen = new CSSGenerator(defaultConfig)
465
- gen.generate('divide-blue-500')
466
- gen.generate('divide-red-500')
467
- gen.generate('divide-gray-300')
468
- const css = gen.toCSS(false)
469
- expect(css).toContain('border-color')
470
- })
471
- })
472
-
473
- describe('Custom rules', () => {
474
- it('should apply custom rules', () => {
475
- const customRule: CustomRule = [
476
- /^custom-utility$/,
477
- () => ({ 'custom-property': 'custom-value' }),
478
- ]
479
- const config = {
480
- ...defaultConfig,
481
- rules: [customRule],
482
- }
483
- const gen = new CSSGenerator(config)
484
- gen.generate('custom-utility')
485
- const css = gen.toCSS(false)
486
- expect(css).toContain('custom-property: custom-value')
487
- })
488
-
489
- it('should handle multiple custom rules', () => {
490
- const rules: CustomRule[] = [
491
- [/^rule1-/, () => ({ prop1: 'value1' })],
492
- [/^rule2-/, () => ({ prop2: 'value2' })],
493
- ]
494
- const config = {
495
- ...defaultConfig,
496
- rules,
497
- }
498
- const gen = new CSSGenerator(config)
499
- gen.generate('rule1-test')
500
- gen.generate('rule2-test')
501
- const css = gen.toCSS(false)
502
- expect(css).toContain('prop1: value1')
503
- expect(css).toContain('prop2: value2')
504
- })
505
-
506
- it('should prioritize custom rules over default rules', () => {
507
- const customRule: CustomRule = [
508
- /^p-custom$/,
509
- () => ({ padding: '999px' }),
510
- ]
511
- const config = {
512
- ...defaultConfig,
513
- rules: [customRule],
514
- }
515
- const gen = new CSSGenerator(config)
516
- gen.generate('p-custom')
517
- const css = gen.toCSS(false)
518
- expect(css).toContain('padding: 999px')
519
- })
520
- })
521
-
522
- describe('Presets', () => {
523
- it('should apply preset theme', () => {
524
- const preset = {
525
- name: 'custom-preset',
526
- theme: {
527
- colors: {
528
- preset: {
529
- 500: '#custom',
530
- },
531
- },
532
- },
533
- }
534
- const config = {
535
- ...defaultConfig,
536
- presets: [preset],
537
- }
538
- const gen = new CSSGenerator(config)
539
- gen.generate('bg-preset-500')
540
- const css = gen.toCSS(false)
541
- expect(css).toContain('#custom')
542
- })
543
-
544
- it('should apply multiple presets', () => {
545
- const preset1 = {
546
- name: 'preset1',
547
- theme: {
548
- colors: {
549
- preset1: {
550
- 500: '#preset1',
551
- },
552
- },
553
- },
554
- }
555
- const preset2 = {
556
- name: 'preset2',
557
- theme: {
558
- colors: {
559
- preset2: {
560
- 500: '#preset2',
561
- },
562
- },
563
- },
564
- }
565
- const config = {
566
- ...defaultConfig,
567
- presets: [preset1, preset2],
568
- }
569
- const gen = new CSSGenerator(config)
570
- gen.generate('bg-preset1-500')
571
- gen.generate('bg-preset2-500')
572
- const css = gen.toCSS(false)
573
- expect(css).toContain('#preset1')
574
- expect(css).toContain('#preset2')
575
- })
576
-
577
- it('should merge preset rules with default rules', () => {
578
- const preset = {
579
- name: 'spacing-preset',
580
- theme: {
581
- spacing: {
582
- huge: '10rem',
583
- },
584
- },
585
- }
586
- const config = {
587
- ...defaultConfig,
588
- presets: [preset],
589
- }
590
- const gen = new CSSGenerator(config)
591
- gen.generate('p-huge')
592
- gen.generate('p-4') // Default spacing
593
- const css = gen.toCSS(false)
594
- expect(css).toContain('10rem')
595
- expect(css).toContain('1rem')
596
- })
597
- })
598
-
599
- describe('Blocklist', () => {
600
- it('should exclude blocklisted classes', () => {
601
- const config = {
602
- ...defaultConfig,
603
- blocklist: ['debug-*', 'test-*'],
604
- }
605
- const gen = new CSSGenerator(config)
606
- gen.generate('debug-border')
607
- gen.generate('test-utility')
608
- gen.generate('p-4') // Should work
609
- const css = gen.toCSS(false)
610
- expect(css).not.toContain('debug')
611
- expect(css).not.toContain('test')
612
- expect(css).toContain('padding: 1rem')
613
- })
614
-
615
- it('should handle wildcard blocklist patterns', () => {
616
- const config = {
617
- ...defaultConfig,
618
- blocklist: ['*-deprecated', 'old-*'],
619
- }
620
- const gen = new CSSGenerator(config)
621
- gen.generate('flex-deprecated')
622
- gen.generate('old-utility')
623
- gen.generate('flex') // Should work
624
- const css = gen.toCSS(false)
625
- expect(css).not.toContain('.flex-deprecated')
626
- expect(css).not.toContain('.old-utility')
627
- expect(css).toContain('display: flex')
628
- })
629
-
630
- it('should handle exact match blocklist', () => {
631
- const config = {
632
- ...defaultConfig,
633
- blocklist: ['p-4', 'm-4'],
634
- }
635
- const gen = new CSSGenerator(config)
636
- gen.generate('p-4')
637
- gen.generate('m-4')
638
- gen.generate('p-8') // Should work
639
- const css = gen.toCSS(false)
640
- expect(css).not.toContain('padding: 1rem')
641
- expect(css).not.toContain('margin: 1rem')
642
- expect(css).toContain('padding: 2rem')
643
- })
644
- })
645
-
646
- describe('Complex combinations', () => {
647
- it('should handle filters with variants', () => {
648
- const gen = new CSSGenerator(defaultConfig)
649
- gen.generate('hover:blur-sm')
650
- gen.generate('focus:brightness-150')
651
- gen.generate('dark:grayscale-100')
652
- const css = gen.toCSS(false)
653
- expect(css).toContain(':hover')
654
- expect(css).toContain(':focus')
655
- expect(css).toContain('blur')
656
- expect(css).toContain('brightness')
657
- expect(css).toContain('grayscale')
658
- })
659
-
660
- it('should handle transitions with important', () => {
661
- const gen = new CSSGenerator(defaultConfig)
662
- gen.generate('!transition-all')
663
- gen.generate('!duration-300')
664
- gen.generate('!ease-in-out')
665
- const css = gen.toCSS(false)
666
- expect(css).toContain('!important')
667
- expect(css).toContain('transition')
668
- expect(css).toContain('duration')
669
- })
670
-
671
- it('should handle child selectors with responsive variants', () => {
672
- const gen = new CSSGenerator(defaultConfig)
673
- gen.generate('sm:space-x-4')
674
- gen.generate('md:divide-y-2')
675
- gen.generate('lg:space-y-8')
676
- const css = gen.toCSS(false)
677
- expect(css).toContain('@media')
678
- expect(css).toContain('space')
679
- })
680
-
681
- it('should handle animations with responsive variants', () => {
682
- const gen = new CSSGenerator(defaultConfig)
683
- gen.generate('sm:animate-spin')
684
- gen.generate('md:animate-bounce')
685
- gen.generate('hover:animate-pulse')
686
- const css = gen.toCSS(false)
687
- expect(css).toContain('animation')
688
- })
689
- })
690
-
691
- describe('Multi-segment color names', () => {
692
- it('should handle blue-gray color with custom config', () => {
693
- const config = {
694
- ...defaultConfig,
695
- theme: {
696
- ...defaultConfig.theme,
697
- colors: {
698
- ...defaultConfig.theme.colors,
699
- 'blue-gray': {
700
- 200: '#e2e8f0',
701
- 500: '#64748b',
702
- 700: '#334155',
703
- },
704
- },
705
- },
706
- }
707
- const gen = new CSSGenerator(config)
708
- gen.generate('text-blue-gray-200')
709
- gen.generate('bg-blue-gray-500')
710
- gen.generate('border-blue-gray-700')
711
- const css = gen.toCSS(false)
712
- expect(css).toContain('#e2e8f0') // blue-gray-200
713
- expect(css).toContain('#64748b') // blue-gray-500
714
- expect(css).toContain('#334155') // blue-gray-700
715
- })
716
-
717
- it('should handle sky color', () => {
718
- const gen = new CSSGenerator(defaultConfig)
719
- gen.generate('text-sky-400')
720
- gen.generate('bg-sky-500')
721
- gen.generate('border-sky-600')
722
- const css = gen.toCSS(false)
723
- expect(css).toContain('oklch(74.6% 0.16 232.661)') // sky-400
724
- expect(css).toContain('oklch(68.5% 0.169 237.323)') // sky-500
725
- expect(css).toContain('oklch(58.8% 0.158 241.966)') // sky-600
726
- })
727
-
728
- it('should handle cyan color', () => {
729
- const gen = new CSSGenerator(defaultConfig)
730
- gen.generate('text-cyan-400')
731
- gen.generate('bg-cyan-500')
732
- gen.generate('border-cyan-600')
733
- const css = gen.toCSS(false)
734
- expect(css).toContain('oklch(78.9% 0.154 211.53)') // cyan-400
735
- expect(css).toContain('oklch(71.5% 0.143 215.221)') // cyan-500
736
- expect(css).toContain('oklch(60.9% 0.126 221.723)') // cyan-600
737
- })
738
- })
739
-
740
- describe('Ring offset colors', () => {
741
- it('should handle ring-offset width', () => {
742
- const gen = new CSSGenerator(defaultConfig)
743
- gen.generate('ring-offset-0')
744
- gen.generate('ring-offset-1')
745
- gen.generate('ring-offset-2')
746
- gen.generate('ring-offset-4')
747
- const css = gen.toCSS(false)
748
- expect(css).toContain('--hw-ring-offset-width')
749
- expect(css).toContain('0px')
750
- expect(css).toContain('1px')
751
- expect(css).toContain('2px')
752
- expect(css).toContain('4px')
753
- })
754
-
755
- it('should handle ring-offset with single color', () => {
756
- const gen = new CSSGenerator(defaultConfig)
757
- gen.generate('ring-offset-black')
758
- gen.generate('ring-offset-white')
759
- const css = gen.toCSS(false)
760
- expect(css).toContain('--hw-ring-offset-color')
761
- expect(css).toContain('#000')
762
- expect(css).toContain('#fff')
763
- })
764
-
765
- it('should handle ring-offset with two-segment color', () => {
766
- const gen = new CSSGenerator(defaultConfig)
767
- gen.generate('ring-offset-blue-500')
768
- gen.generate('ring-offset-red-500')
769
- gen.generate('ring-offset-gray-300')
770
- const css = gen.toCSS(false)
771
- expect(css).toContain('--hw-ring-offset-color')
772
- expect(css).toContain('oklch(62.3% 0.214 259.815)') // blue-500
773
- expect(css).toContain('oklch(63.7% 0.237 25.331)') // red-500
774
- expect(css).toContain('oklch(87.2% 0.01 258.338)') // gray-300
775
- })
776
-
777
- it('should handle ring-offset with multi-segment color names', () => {
778
- const gen = new CSSGenerator(defaultConfig)
779
- gen.generate('ring-offset-sky-400')
780
- gen.generate('ring-offset-cyan-600')
781
- const css = gen.toCSS(false)
782
- expect(css).toContain('--hw-ring-offset-color')
783
- expect(css).toContain('oklch(74.6% 0.16 232.661)') // sky-400
784
- expect(css).toContain('oklch(60.9% 0.126 221.723)') // cyan-600
785
- })
786
- })
787
-
788
- describe('Gradient utilities', () => {
789
- it('should handle gradient direction utilities', () => {
790
- const gen = new CSSGenerator(defaultConfig)
791
- gen.generate('bg-gradient-to-r')
792
- gen.generate('bg-gradient-to-l')
793
- gen.generate('bg-gradient-to-t')
794
- gen.generate('bg-gradient-to-b')
795
- gen.generate('bg-gradient-to-tr')
796
- gen.generate('bg-gradient-to-br')
797
- gen.generate('bg-gradient-to-bl')
798
- gen.generate('bg-gradient-to-tl')
799
- const css = gen.toCSS(false)
800
- expect(css).toContain('linear-gradient')
801
- expect(css).toContain('to right')
802
- expect(css).toContain('to left')
803
- expect(css).toContain('to top')
804
- expect(css).toContain('to bottom')
805
- })
806
-
807
- it('should handle gradient color stops', () => {
808
- const gen = new CSSGenerator(defaultConfig)
809
- gen.generate('from-blue-500')
810
- gen.generate('via-gray-300')
811
- gen.generate('to-red-500')
812
- const css = gen.toCSS(false)
813
- expect(css).toContain('--hw-gradient-from')
814
- expect(css).toContain('--hw-gradient-to')
815
- expect(css).toContain('--hw-gradient-stops')
816
- expect(css).toContain('oklch(62.3% 0.214 259.815)') // blue-500
817
- expect(css).toContain('oklch(63.7% 0.237 25.331)') // red-500
818
- })
819
-
820
- it('should handle gradient with multi-segment colors', () => {
821
- const gen = new CSSGenerator(defaultConfig)
822
- gen.generate('via-sky-400')
823
- gen.generate('to-cyan-600')
824
- const css = gen.toCSS(false)
825
- expect(css).toContain('--hw-gradient-to')
826
- expect(css).toContain('--hw-gradient-stops')
827
- expect(css).toContain('oklch(74.6% 0.16 232.661)') // sky-400
828
- expect(css).toContain('oklch(60.9% 0.126 221.723)') // cyan-600
829
- })
830
-
831
- it('should handle gradient with hover variants', () => {
832
- const gen = new CSSGenerator(defaultConfig)
833
- gen.generate('hover:from-sky-500')
834
- gen.generate('hover:to-cyan-500')
835
- gen.generate('hover:via-blue-500')
836
- const css = gen.toCSS(false)
837
- expect(css).toContain(':hover')
838
- expect(css).toContain('--hw-gradient-from')
839
- expect(css).toContain('--hw-gradient-to')
840
- expect(css).toContain('oklch(68.5% 0.169 237.323)') // sky-500
841
- expect(css).toContain('oklch(71.5% 0.143 215.221)') // cyan-500
842
- })
843
-
844
- it('should handle complete gradient combination', () => {
845
- const gen = new CSSGenerator(defaultConfig)
846
- gen.generate('bg-gradient-to-r')
847
- gen.generate('from-sky-500')
848
- gen.generate('to-cyan-500')
849
- const css = gen.toCSS(false)
850
- expect(css).toContain('linear-gradient(to right, var(--hw-gradient-stops))')
851
- expect(css).toContain('--hw-gradient-from: oklch(68.5% 0.169 237.323)') // sky-500
852
- expect(css).toContain('--hw-gradient-to: oklch(71.5% 0.143 215.221)') // cyan-500
853
- })
854
-
855
- it('should properly update gradient stops when using to-{color}', () => {
856
- const gen = new CSSGenerator(defaultConfig)
857
- gen.generate('from-blue-500')
858
- gen.generate('to-red-500')
859
- const css = gen.toCSS(false)
860
- // Both from and to should set --hw-gradient-stops
861
- const fromMatch = css.match(/\.from-blue-500\s*\{[^}]*\}/)
862
- const toMatch = css.match(/\.to-red-500\s*\{[^}]*\}/)
863
- expect(fromMatch).toBeTruthy()
864
- expect(toMatch).toBeTruthy()
865
- expect(fromMatch![0]).toContain('--hw-gradient-stops')
866
- expect(toMatch![0]).toContain('--hw-gradient-stops')
867
- })
868
- })
869
-
870
- describe('Accessibility utilities', () => {
871
- it('should handle sr-only utility', () => {
872
- const gen = new CSSGenerator(defaultConfig)
873
- gen.generate('sr-only')
874
- const css = gen.toCSS(false)
875
- expect(css).toContain('position: absolute')
876
- expect(css).toContain('width: 1px')
877
- expect(css).toContain('height: 1px')
878
- expect(css).toContain('padding: 0')
879
- expect(css).toContain('margin: -1px')
880
- expect(css).toContain('overflow: hidden')
881
- expect(css).toContain('clip: rect(0, 0, 0, 0)')
882
- expect(css).toContain('white-space: nowrap')
883
- expect(css).toContain('border-width: 0')
884
- })
885
-
886
- it('should handle not-sr-only utility', () => {
887
- const gen = new CSSGenerator(defaultConfig)
888
- gen.generate('not-sr-only')
889
- const css = gen.toCSS(false)
890
- expect(css).toContain('position: static')
891
- expect(css).toContain('width: auto')
892
- expect(css).toContain('height: auto')
893
- expect(css).toContain('padding: 0')
894
- expect(css).toContain('margin: 0')
895
- expect(css).toContain('overflow: visible')
896
- expect(css).toContain('clip: auto')
897
- expect(css).toContain('white-space: normal')
898
- })
899
-
900
- it('should handle accessibility in forms', () => {
901
- const gen = new CSSGenerator(defaultConfig)
902
- // sr-only is typically used for labels and screen reader text
903
- gen.generate('sr-only')
904
- const css = gen.toCSS(false)
905
- // Verify all required properties for accessibility
906
- expect(css).toContain('position')
907
- expect(css).toContain('width')
908
- expect(css).toContain('height')
909
- })
910
- })
911
- })