@cwcss/crosswind 0.1.5 → 0.2.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 (87) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +52 -0
  3. package/dist/bin/cli.js +14615 -0
  4. package/dist/build.d.ts +24 -0
  5. package/dist/config.d.ts +5 -0
  6. package/dist/generator.d.ts +31 -0
  7. package/dist/index.d.ts +10 -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/src/index.js +12848 -0
  23. package/dist/transformer-compile-class.d.ts +37 -0
  24. package/{src/types.ts → dist/types.d.ts} +17 -86
  25. package/package.json +2 -16
  26. package/PLUGIN.md +0 -235
  27. package/benchmark/framework-comparison.bench.ts +0 -850
  28. package/bin/cli.ts +0 -365
  29. package/bin/crosswind +0 -0
  30. package/bin/headwind +0 -0
  31. package/build.ts +0 -8
  32. package/crosswind.config.ts +0 -9
  33. package/example/comprehensive.html +0 -70
  34. package/example/index.html +0 -21
  35. package/example/output.css +0 -236
  36. package/examples/plugin/README.md +0 -112
  37. package/examples/plugin/build.ts +0 -32
  38. package/examples/plugin/src/index.html +0 -34
  39. package/examples/plugin/src/index.ts +0 -7
  40. package/headwind +0 -2
  41. package/src/build.ts +0 -101
  42. package/src/config.ts +0 -529
  43. package/src/generator.ts +0 -2173
  44. package/src/index.ts +0 -10
  45. package/src/parser.ts +0 -1471
  46. package/src/plugin.ts +0 -118
  47. package/src/preflight-forms.ts +0 -229
  48. package/src/preflight.ts +0 -388
  49. package/src/rules-advanced.ts +0 -477
  50. package/src/rules-effects.ts +0 -461
  51. package/src/rules-forms.ts +0 -103
  52. package/src/rules-grid.ts +0 -241
  53. package/src/rules-interactivity.ts +0 -525
  54. package/src/rules-layout.ts +0 -385
  55. package/src/rules-transforms.ts +0 -412
  56. package/src/rules-typography.ts +0 -486
  57. package/src/rules.ts +0 -809
  58. package/src/scanner.ts +0 -84
  59. package/src/transformer-compile-class.ts +0 -275
  60. package/test/advanced-features.test.ts +0 -911
  61. package/test/arbitrary.test.ts +0 -396
  62. package/test/attributify.test.ts +0 -592
  63. package/test/bracket-syntax.test.ts +0 -1133
  64. package/test/build.test.ts +0 -99
  65. package/test/colors.test.ts +0 -934
  66. package/test/flexbox.test.ts +0 -669
  67. package/test/generator.test.ts +0 -597
  68. package/test/grid.test.ts +0 -584
  69. package/test/layout.test.ts +0 -404
  70. package/test/modifiers.test.ts +0 -417
  71. package/test/parser.test.ts +0 -564
  72. package/test/performance-regression.test.ts +0 -376
  73. package/test/performance.test.ts +0 -568
  74. package/test/plugin.test.ts +0 -160
  75. package/test/scanner.test.ts +0 -94
  76. package/test/sizing.test.ts +0 -481
  77. package/test/spacing.test.ts +0 -394
  78. package/test/transformer-compile-class.test.ts +0 -287
  79. package/test/transforms.test.ts +0 -448
  80. package/test/typography.test.ts +0 -632
  81. package/test/variants-form-states.test.ts +0 -225
  82. package/test/variants-group-peer.test.ts +0 -66
  83. package/test/variants-media.test.ts +0 -213
  84. package/test/variants-positional.test.ts +0 -58
  85. package/test/variants-pseudo-elements.test.ts +0 -47
  86. package/test/variants-state.test.ts +0 -62
  87. package/tsconfig.json +0 -18
@@ -1,477 +0,0 @@
1
- import type { UtilityRule } from './rules'
2
-
3
- // Advanced utilities
4
-
5
- // Min/Max sizing
6
- export const minMaxSizingRule: UtilityRule = (parsed, config) => {
7
- const minMaxMap: Record<string, string> = {
8
- '0': '0',
9
- 'full': '100%',
10
- 'min': 'min-content',
11
- 'max': 'max-content',
12
- 'fit': 'fit-content',
13
- 'none': 'none',
14
- 'xs': '20rem',
15
- 'sm': '24rem',
16
- 'md': '28rem',
17
- 'lg': '32rem',
18
- 'xl': '36rem',
19
- '2xl': '42rem',
20
- '3xl': '48rem',
21
- '4xl': '56rem',
22
- '5xl': '64rem',
23
- '6xl': '72rem',
24
- '7xl': '80rem',
25
- 'screen': '100vw',
26
- }
27
-
28
- if (parsed.utility === 'min-w' && parsed.value) {
29
- const value = config.theme.spacing[parsed.value] || minMaxMap[parsed.value] || parsed.value
30
- return { 'min-width': value } as Record<string, string>
31
- }
32
- if (parsed.utility === 'max-w' && parsed.value) {
33
- const value = config.theme.spacing[parsed.value] || minMaxMap[parsed.value] || parsed.value
34
- return { 'max-width': value } as Record<string, string>
35
- }
36
- if (parsed.utility === 'min-h' && parsed.value) {
37
- const hMap: Record<string, string> = { ...minMaxMap, screen: '100vh' }
38
- const value = config.theme.spacing[parsed.value] || hMap[parsed.value] || parsed.value
39
- return { 'min-height': value } as Record<string, string>
40
- }
41
- if (parsed.utility === 'max-h' && parsed.value) {
42
- const hMap: Record<string, string> = { ...minMaxMap, screen: '100vh' }
43
- const value = config.theme.spacing[parsed.value] || hMap[parsed.value] || parsed.value
44
- return { 'max-height': value } as Record<string, string>
45
- }
46
- }
47
-
48
- // Ring utilities
49
- export const ringRule: UtilityRule = (parsed, config) => {
50
- if (parsed.utility === 'ring') {
51
- // Handle ring-inset
52
- if (parsed.value === 'inset') {
53
- return { '--hw-ring-inset': 'inset' } as Record<string, string>
54
- }
55
-
56
- // Check if this is a ring color (e.g., ring-sky-500)
57
- if (parsed.value) {
58
- const parts = parsed.value.split('-')
59
- if (parts.length >= 2) {
60
- const colorName = parts.slice(0, -1).join('-')
61
- const shade = parts[parts.length - 1]
62
- const colorValue = config.theme.colors[colorName]
63
- if (typeof colorValue === 'object' && colorValue[shade]) {
64
- return { '--hw-ring-color': colorValue[shade] } as Record<string, string>
65
- }
66
- // Also check if it's a direct color value (like custom colors)
67
- if (config.theme.colors[parsed.value]) {
68
- return { '--hw-ring-color': config.theme.colors[parsed.value] } as Record<string, string>
69
- }
70
- }
71
- }
72
-
73
- // Handle ring width
74
- const widths: Record<string, string> = {
75
- 0: '0',
76
- 1: '1px',
77
- 2: '2px',
78
- 4: '4px',
79
- 8: '8px',
80
- DEFAULT: '3px',
81
- }
82
- const width = parsed.value ? widths[parsed.value] || parsed.value : widths.DEFAULT
83
- return {
84
- '--hw-ring-offset-shadow': 'var(--hw-ring-inset) 0 0 0 var(--hw-ring-offset-width) var(--hw-ring-offset-color)',
85
- '--hw-ring-shadow': `var(--hw-ring-inset) 0 0 0 calc(${width} + var(--hw-ring-offset-width)) var(--hw-ring-color)`,
86
- 'box-shadow': 'var(--hw-ring-offset-shadow), var(--hw-ring-shadow), var(--hw-shadow, 0 0 #0000)',
87
- } as Record<string, string>
88
- }
89
-
90
- if (parsed.utility === 'ring-offset' && parsed.value) {
91
- // First check if it's a width value
92
- const widths: Record<string, string> = {
93
- 0: '0px',
94
- 1: '1px',
95
- 2: '2px',
96
- 4: '4px',
97
- 8: '8px',
98
- }
99
- if (widths[parsed.value]) {
100
- return { '--hw-ring-offset-width': widths[parsed.value] } as Record<string, string>
101
- }
102
-
103
- // Otherwise, treat as a color (e.g., ring-offset-ocean-blue)
104
- const parts = parsed.value.split('-')
105
- if (parts.length >= 2) {
106
- const colorName = parts.slice(0, -1).join('-')
107
- const shade = parts[parts.length - 1]
108
- const colorValue = config.theme.colors[colorName]
109
- if (typeof colorValue === 'object' && colorValue[shade]) {
110
- return { '--hw-ring-offset-color': colorValue[shade] } as Record<string, string>
111
- }
112
- }
113
- // Check for direct color (e.g., ring-offset-black)
114
- const directColor = config.theme.colors[parsed.value]
115
- if (typeof directColor === 'string') {
116
- return { '--hw-ring-offset-color': directColor } as Record<string, string>
117
- }
118
- }
119
-
120
- // Ring opacity
121
- if (parsed.utility === 'ring-opacity' && parsed.value) {
122
- const opacityMap: Record<string, string> = {
123
- 0: '0', 5: '0.05', 10: '0.1', 20: '0.2', 25: '0.25',
124
- 30: '0.3', 40: '0.4', 50: '0.5', 60: '0.6', 70: '0.7',
125
- 75: '0.75', 80: '0.8', 90: '0.9', 95: '0.95', 100: '1',
126
- }
127
- return { '--hw-ring-opacity': opacityMap[parsed.value] || parsed.value } as Record<string, string>
128
- }
129
- }
130
-
131
- // Border opacity utility
132
- export const borderOpacityRule: UtilityRule = (parsed) => {
133
- if (parsed.utility === 'border-opacity' && parsed.value) {
134
- const opacityMap: Record<string, string> = {
135
- 0: '0', 5: '0.05', 10: '0.1', 20: '0.2', 25: '0.25',
136
- 30: '0.3', 40: '0.4', 50: '0.5', 60: '0.6', 70: '0.7',
137
- 75: '0.75', 80: '0.8', 90: '0.9', 95: '0.95', 100: '1',
138
- }
139
- return { '--hw-border-opacity': opacityMap[parsed.value] || parsed.value } as Record<string, string>
140
- }
141
- }
142
-
143
- // Space utilities (child spacing)
144
- export const spaceRule: UtilityRule = (parsed, config) => {
145
- if (parsed.utility === 'space-x' && parsed.value) {
146
- let spacing: string
147
- if (parsed.value.startsWith('-')) {
148
- const positiveValue = parsed.value.slice(1)
149
- const baseSpacing = config.theme.spacing[positiveValue]
150
- spacing = baseSpacing ? `-${baseSpacing}` : parsed.value
151
- }
152
- else {
153
- spacing = config.theme.spacing[parsed.value] || parsed.value
154
- }
155
-
156
- return {
157
- properties: {
158
- '--hw-space-x-reverse': '0',
159
- 'margin-right': `calc(${spacing} * var(--hw-space-x-reverse))`,
160
- 'margin-left': `calc(${spacing} * calc(1 - var(--hw-space-x-reverse)))`,
161
- } as Record<string, string>,
162
- childSelector: '> :not([hidden]) ~ :not([hidden])',
163
- }
164
- }
165
-
166
- if (parsed.utility === 'space-y' && parsed.value) {
167
- let spacing: string
168
- if (parsed.value.startsWith('-')) {
169
- const positiveValue = parsed.value.slice(1)
170
- const baseSpacing = config.theme.spacing[positiveValue]
171
- spacing = baseSpacing ? `-${baseSpacing}` : parsed.value
172
- }
173
- else {
174
- spacing = config.theme.spacing[parsed.value] || parsed.value
175
- }
176
-
177
- return {
178
- properties: {
179
- '--hw-space-y-reverse': '0',
180
- 'margin-top': `calc(${spacing} * calc(1 - var(--hw-space-y-reverse)))`,
181
- 'margin-bottom': `calc(${spacing} * var(--hw-space-y-reverse))`,
182
- } as Record<string, string>,
183
- childSelector: '> :not([hidden]) ~ :not([hidden])',
184
- }
185
- }
186
- }
187
-
188
- // Border style utilities
189
- export const borderStyleRule: UtilityRule = (parsed) => {
190
- if (parsed.utility === 'border' && parsed.value) {
191
- const styles: Record<string, string> = {
192
- solid: 'solid',
193
- dashed: 'dashed',
194
- dotted: 'dotted',
195
- double: 'double',
196
- hidden: 'hidden',
197
- none: 'none',
198
- }
199
- if (styles[parsed.value]) {
200
- return { 'border-style': styles[parsed.value] }
201
- }
202
- }
203
- }
204
-
205
- // Divide utilities (borders between children)
206
- export const divideRule: UtilityRule = (parsed, config) => {
207
- // Handle divide styles: divide-solid, divide-dashed, divide-dotted
208
- if (parsed.utility === 'divide' && parsed.value) {
209
- const styles: Record<string, string> = {
210
- solid: 'solid',
211
- dashed: 'dashed',
212
- dotted: 'dotted',
213
- double: 'double',
214
- none: 'none',
215
- }
216
- if (styles[parsed.value]) {
217
- return {
218
- properties: {
219
- 'border-style': styles[parsed.value],
220
- } as Record<string, string>,
221
- childSelector: '> :not([hidden]) ~ :not([hidden])',
222
- }
223
- }
224
- }
225
-
226
- if (parsed.utility === 'divide-x') {
227
- const widths: Record<string, string> = {
228
- 0: '0',
229
- 2: '2px',
230
- 4: '4px',
231
- 8: '8px',
232
- DEFAULT: '1px',
233
- }
234
- const width = parsed.value ? (widths[parsed.value] || parsed.value) : widths.DEFAULT
235
-
236
- return {
237
- properties: {
238
- '--hw-divide-x-reverse': '0',
239
- 'border-right-width': `calc(${width} * var(--hw-divide-x-reverse))`,
240
- 'border-left-width': `calc(${width} * calc(1 - var(--hw-divide-x-reverse)))`,
241
- } as Record<string, string>,
242
- childSelector: '> :not([hidden]) ~ :not([hidden])',
243
- }
244
- }
245
-
246
- if (parsed.utility === 'divide-y') {
247
- const widths: Record<string, string> = {
248
- 0: '0',
249
- 2: '2px',
250
- 4: '4px',
251
- 8: '8px',
252
- DEFAULT: '1px',
253
- }
254
- const width = parsed.value ? (widths[parsed.value] || parsed.value) : widths.DEFAULT
255
-
256
- return {
257
- properties: {
258
- '--hw-divide-y-reverse': '0',
259
- 'border-top-width': `calc(${width} * calc(1 - var(--hw-divide-y-reverse)))`,
260
- 'border-bottom-width': `calc(${width} * var(--hw-divide-y-reverse))`,
261
- } as Record<string, string>,
262
- childSelector: '> :not([hidden]) ~ :not([hidden])',
263
- }
264
- }
265
-
266
- if (parsed.utility === 'divide' && parsed.value) {
267
- // divide-{color}-{shade}
268
- const parts = parsed.value.split('-')
269
- if (parts.length >= 2) {
270
- const colorName = parts.slice(0, -1).join('-')
271
- const shade = parts[parts.length - 1]
272
- const colorValue = config.theme.colors[colorName]
273
- if (typeof colorValue === 'object' && colorValue[shade]) {
274
- return {
275
- properties: {
276
- 'border-color': colorValue[shade],
277
- } as Record<string, string>,
278
- childSelector: '> :not([hidden]) ~ :not([hidden])',
279
- }
280
- }
281
- }
282
- }
283
- }
284
-
285
- // Gradient color stops
286
- export const gradientStopsRule: UtilityRule = (parsed, config) => {
287
- const getColor = (value: string) => {
288
- // First check if it's a direct color value (e.g., ocean-blue, black, white)
289
- const directColor = config.theme.colors[value]
290
- if (typeof directColor === 'string') {
291
- return directColor
292
- }
293
-
294
- // Then check if it's a color-shade combination (e.g., sky-500, blue-gray-200)
295
- const parts = value.split('-')
296
- if (parts.length >= 2) {
297
- const colorName = parts.slice(0, -1).join('-')
298
- const shade = parts[parts.length - 1]
299
- const colorValue = config.theme.colors[colorName]
300
- if (typeof colorValue === 'object' && colorValue[shade]) {
301
- return colorValue[shade]
302
- }
303
- }
304
- return value
305
- }
306
-
307
- if (parsed.utility === 'from' && parsed.value) {
308
- const color = getColor(parsed.value)
309
- return {
310
- '--hw-gradient-from': color,
311
- '--hw-gradient-to': 'rgb(255 255 255 / 0)',
312
- '--hw-gradient-stops': 'var(--hw-gradient-from), var(--hw-gradient-to)',
313
- } as Record<string, string>
314
- }
315
-
316
- if (parsed.utility === 'via' && parsed.value) {
317
- const color = getColor(parsed.value)
318
- return {
319
- '--hw-gradient-to': 'rgb(255 255 255 / 0)',
320
- '--hw-gradient-stops': `var(--hw-gradient-from), ${color}, var(--hw-gradient-to)`,
321
- } as Record<string, string>
322
- }
323
-
324
- if (parsed.utility === 'to' && parsed.value) {
325
- const color = getColor(parsed.value)
326
- return {
327
- '--hw-gradient-to': color,
328
- '--hw-gradient-stops': 'var(--hw-gradient-from), var(--hw-gradient-to)',
329
- } as Record<string, string>
330
- }
331
- }
332
-
333
- // Flex order
334
- export const flexOrderRule: UtilityRule = (parsed) => {
335
- if (parsed.utility === 'order' && parsed.value) {
336
- const orders: Record<string, string> = {
337
- first: '-9999',
338
- last: '9999',
339
- none: '0',
340
- 1: '1',
341
- 2: '2',
342
- 3: '3',
343
- 4: '4',
344
- 5: '5',
345
- 6: '6',
346
- 7: '7',
347
- 8: '8',
348
- 9: '9',
349
- 10: '10',
350
- 11: '11',
351
- 12: '12',
352
- }
353
- return { order: orders[parsed.value] || parsed.value }
354
- }
355
- }
356
-
357
- // Flex basis
358
- export const flexBasisRule: UtilityRule = (parsed, config) => {
359
- if (parsed.utility === 'basis' && parsed.value) {
360
- // Handle fractions
361
- if (parsed.value.includes('/')) {
362
- const [num, denom] = parsed.value.split('/').map(Number)
363
- return { 'flex-basis': `${(num / denom) * 100}%` }
364
- }
365
-
366
- const bases: Record<string, string> = {
367
- auto: 'auto',
368
- full: '100%',
369
- 0: '0',
370
- }
371
- return { 'flex-basis': bases[parsed.value] || config.theme.spacing[parsed.value] || parsed.value }
372
- }
373
- }
374
-
375
- // Justify/Align self
376
- export const justifySelfRule: UtilityRule = (parsed) => {
377
- if (parsed.utility === 'justify-self') {
378
- const values: Record<string, string> = {
379
- auto: 'auto',
380
- start: 'start',
381
- end: 'end',
382
- center: 'center',
383
- stretch: 'stretch',
384
- }
385
- return parsed.value ? { 'justify-self': values[parsed.value] || parsed.value } : undefined
386
- }
387
- }
388
-
389
- export const alignSelfRule: UtilityRule = (parsed) => {
390
- if (parsed.utility === 'self') {
391
- const values: Record<string, string> = {
392
- auto: 'auto',
393
- start: 'flex-start',
394
- end: 'flex-end',
395
- center: 'center',
396
- stretch: 'stretch',
397
- baseline: 'baseline',
398
- }
399
- return parsed.value ? { 'align-self': values[parsed.value] || parsed.value } : undefined
400
- }
401
- }
402
-
403
- // Container utility with responsive max-widths
404
- export const containerRule: UtilityRule = (parsed, config) => {
405
- if (parsed.utility === 'container') {
406
- // container without value - centered container with responsive max-width
407
- if (!parsed.value) {
408
- // Use clamp for modern responsive max-width behavior
409
- // Max-width scales with breakpoints: sm=640, md=768, lg=1024, xl=1280, 2xl=1536
410
- const xl = config.theme.screens['xl'] || '1280px'
411
- return {
412
- 'width': '100%',
413
- 'margin-left': 'auto',
414
- 'margin-right': 'auto',
415
- 'max-width': xl,
416
- }
417
- }
418
-
419
- // container-{breakpoint} for specific max-widths
420
- const breakpointMap: Record<string, string> = {
421
- 'sm': config.theme.screens['sm'] || '640px',
422
- 'md': config.theme.screens['md'] || '768px',
423
- 'lg': config.theme.screens['lg'] || '1024px',
424
- 'xl': config.theme.screens['xl'] || '1280px',
425
- '2xl': config.theme.screens['2xl'] || '1536px',
426
- 'full': '100%',
427
- 'prose': '65ch',
428
- '3xl': '1920px',
429
- }
430
-
431
- if (breakpointMap[parsed.value]) {
432
- return {
433
- 'width': '100%',
434
- 'margin-left': 'auto',
435
- 'margin-right': 'auto',
436
- 'max-width': breakpointMap[parsed.value],
437
- }
438
- }
439
-
440
- // Arbitrary value support: container-[800px]
441
- if (parsed.arbitrary) {
442
- return {
443
- 'width': '100%',
444
- 'margin-left': 'auto',
445
- 'margin-right': 'auto',
446
- 'max-width': parsed.value,
447
- }
448
- }
449
- }
450
- }
451
-
452
- // Arbitrary properties
453
- export const arbitraryPropertyRule: UtilityRule = (parsed) => {
454
- // Only handle true arbitrary properties: [color:red], [mask-type:alpha]
455
- // NOT arbitrary values like w-[100px]
456
- const rawWithoutImportant = parsed.raw.replace(/^!/, '')
457
- if (parsed.arbitrary && parsed.utility && parsed.value && rawWithoutImportant.startsWith('[')) {
458
- // Arbitrary properties start with [ and have the pattern [prop:value]
459
- return { [parsed.utility]: parsed.value }
460
- }
461
- }
462
-
463
- export const advancedRules: UtilityRule[] = [
464
- minMaxSizingRule,
465
- ringRule,
466
- borderOpacityRule,
467
- borderStyleRule,
468
- spaceRule,
469
- divideRule,
470
- gradientStopsRule,
471
- flexOrderRule,
472
- flexBasisRule,
473
- justifySelfRule,
474
- alignSelfRule,
475
- containerRule,
476
- arbitraryPropertyRule,
477
- ]