@bookklik/senangstart-css 0.2.10 → 0.2.12
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.
- package/.agent/skills/add-utility/SKILL.md +65 -0
- package/.agent/workflows/add-utility.md +2 -0
- package/.agent/workflows/build.md +2 -0
- package/.agent/workflows/dev.md +2 -0
- package/AGENTS.md +30 -0
- package/dist/senangstart-css.js +362 -151
- package/dist/senangstart-css.min.js +175 -174
- package/dist/senangstart-tw.js +4 -4
- package/dist/senangstart-tw.min.js +1 -1
- package/docs/ms/reference/visual/ring-color.md +2 -2
- package/docs/ms/reference/visual/ring-offset.md +3 -3
- package/docs/ms/reference/visual/ring.md +5 -5
- package/docs/public/assets/senangstart-css.min.js +175 -174
- package/docs/public/llms.txt +10 -10
- package/docs/reference/visual/ring-color.md +2 -2
- package/docs/reference/visual/ring-offset.md +3 -3
- package/docs/reference/visual/ring.md +5 -5
- package/package.json +1 -1
- package/src/cdn/tw-conversion-engine.js +4 -4
- package/src/cli/commands/build.js +42 -14
- package/src/cli/commands/dev.js +157 -93
- package/src/compiler/generators/css.js +371 -199
- package/src/compiler/tokenizer.js +25 -23
- package/src/core/tokenizer-core.js +46 -19
- package/src/definitions/visual-borders.js +10 -10
- package/src/utils/common.js +456 -39
- package/src/utils/node-io.js +82 -0
- package/tests/integration/dev-recovery.test.js +231 -0
- package/tests/unit/cli/memory-limits.test.js +169 -0
- package/tests/unit/compiler/css-generation-error-handling.test.js +204 -0
- package/tests/unit/compiler/generators/css-errors.test.js +102 -0
- package/tests/unit/convert-tailwind.test.js +518 -442
- package/tests/unit/utils/common.test.js +376 -26
- package/tests/unit/utils/file-timeout.test.js +154 -0
- package/tests/unit/utils/theme-validation.test.js +181 -0
- package/tests/unit/compiler/generators/css.coverage.test.js +0 -833
- package/tests/unit/convert-tailwind.cli.test.js +0 -95
- package/tests/unit/security.test.js +0 -206
- /package/tests/unit/{convert-tailwind.coverage.test.js → convert-tailwind-edgecases.test.js} +0 -0
|
@@ -1,833 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { test } from 'node:test';
|
|
3
|
-
import assert from 'node:assert';
|
|
4
|
-
import {
|
|
5
|
-
generateCSS,
|
|
6
|
-
generateCSSVariables,
|
|
7
|
-
minifyCSS
|
|
8
|
-
} from '../../../../src/compiler/generators/css.js';
|
|
9
|
-
import { createTestConfig } from '../../../helpers/test-utils.js';
|
|
10
|
-
|
|
11
|
-
test('CSS Generator Coverage', async (t) => {
|
|
12
|
-
const config = createTestConfig();
|
|
13
|
-
|
|
14
|
-
await t.test('generateCSSVariables - Tailwind Scales', () => {
|
|
15
|
-
const css = generateCSSVariables(config);
|
|
16
|
-
assert.ok(css.includes('--tw-text-xs: 0.75rem'));
|
|
17
|
-
assert.ok(css.includes('--tw-leading-xs: 1rem'));
|
|
18
|
-
assert.ok(css.includes('--tw-font-bold: 700'));
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
await t.test('generateCSSVariables - Custom Line Heights', () => {
|
|
22
|
-
const customConfig = createTestConfig({
|
|
23
|
-
theme: {
|
|
24
|
-
fontSizeLineHeight: {
|
|
25
|
-
'base': '1.5',
|
|
26
|
-
'large': '1.2'
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
const css = generateCSSVariables(customConfig);
|
|
31
|
-
assert.ok(css.includes('--font-lh-base: 1.5'));
|
|
32
|
-
assert.ok(css.includes('--font-lh-large: 1.2'));
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
await t.test('Layout - Grid Column Span Full', () => {
|
|
36
|
-
const token = { property: 'col-span', value: 'full', attrType: 'layout', raw: 'col-span:full' };
|
|
37
|
-
const css = generateCSS([token], config);
|
|
38
|
-
assert.ok(css.includes('grid-column: 1 / -1'));
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
await t.test('Layout - Grid Column Start/End', () => {
|
|
42
|
-
const start = { property: 'col-start', value: '2', attrType: 'layout', raw: 'col-start:2' };
|
|
43
|
-
const end = { property: 'col-end', value: '4', attrType: 'layout', raw: 'col-end:4' };
|
|
44
|
-
const css = generateCSS([start, end], config);
|
|
45
|
-
assert.ok(css.includes('grid-column-start: 2'));
|
|
46
|
-
assert.ok(css.includes('grid-column-end: 4'));
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
await t.test('Layout - Grid Row Span Full', () => {
|
|
50
|
-
const token = { property: 'row-span', value: 'full', attrType: 'layout', raw: 'row-span:full' };
|
|
51
|
-
const css = generateCSS([token], config);
|
|
52
|
-
assert.ok(css.includes('grid-row: 1 / -1'));
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
await t.test('Layout - Grid Row Start/End', () => {
|
|
56
|
-
const start = { property: 'row-start', value: '1', attrType: 'layout', raw: 'row-start:1' };
|
|
57
|
-
const end = { property: 'row-end', value: '3', attrType: 'layout', raw: 'row-end:3' };
|
|
58
|
-
const css = generateCSS([start, end], config);
|
|
59
|
-
assert.ok(css.includes('grid-row-start: 1'));
|
|
60
|
-
assert.ok(css.includes('grid-row-end: 3'));
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
await t.test('Layout - Grid Auto Columns', () => {
|
|
64
|
-
const auto = { property: 'auto-cols', value: 'min', attrType: 'layout', raw: 'auto-cols:min' };
|
|
65
|
-
const arb = { property: 'auto-cols', value: 'minmax(100px, auto)', isArbitrary: true, attrType: 'layout', raw: 'auto-cols:[minmax(100px, auto)]' };
|
|
66
|
-
const css = generateCSS([auto, arb], config);
|
|
67
|
-
assert.ok(css.includes('grid-auto-columns: min-content'));
|
|
68
|
-
assert.ok(css.includes('grid-auto-columns: minmax(100px, auto)'));
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
await t.test('Layout - Grid Auto Rows', () => {
|
|
72
|
-
const auto = { property: 'auto-rows', value: 'fr', attrType: 'layout', raw: 'auto-rows:fr' };
|
|
73
|
-
const arb = { property: 'auto-rows', value: '200px', isArbitrary: true, attrType: 'layout', raw: 'auto-rows:[200px]' };
|
|
74
|
-
const css = generateCSS([auto, arb], config);
|
|
75
|
-
assert.ok(css.includes('grid-auto-rows: minmax(0, 1fr)'));
|
|
76
|
-
assert.ok(css.includes('grid-auto-rows: 200px'));
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
await t.test('Layout - Border Spacing', () => {
|
|
80
|
-
const base = { property: 'border-spacing', value: 'medium', attrType: 'layout', raw: 'border-spacing:medium' };
|
|
81
|
-
const x = { property: 'border-spacing-x', value: 'small', attrType: 'layout', raw: 'border-spacing-x:small' };
|
|
82
|
-
const y = { property: 'border-spacing-y', value: 'big', attrType: 'layout', raw: 'border-spacing-y:big' };
|
|
83
|
-
const css = generateCSS([base, x, y], config);
|
|
84
|
-
assert.ok(css.includes('border-spacing: var(--s-medium)'));
|
|
85
|
-
assert.ok(css.includes('border-spacing: var(--s-small) 0'));
|
|
86
|
-
assert.ok(css.includes('border-spacing: 0 var(--s-big)'));
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
await t.test('Visual - Transforms and 3D', () => {
|
|
90
|
-
const tokens = [
|
|
91
|
-
{ property: 'translate-x', value: 'full', attrType: 'visual', raw: 'translate-x:full' },
|
|
92
|
-
{ property: 'translate-x', value: '10px', isArbitrary: true, attrType: 'visual', raw: 'translate-x:[10px]' },
|
|
93
|
-
{ property: 'rotate-x', value: '45', attrType: 'visual', raw: 'rotate-x:45' },
|
|
94
|
-
{ property: 'rotate-x', value: '45deg', isArbitrary: true, attrType: 'visual', raw: 'rotate-x:[45deg]' },
|
|
95
|
-
{ property: 'rotate-y', value: '45', attrType: 'visual', raw: 'rotate-y:45' },
|
|
96
|
-
{ property: 'rotate-y', value: '45deg', isArbitrary: true, attrType: 'visual', raw: 'rotate-y:[45deg]' },
|
|
97
|
-
{ property: 'rotate-z', value: '45', attrType: 'visual', raw: 'rotate-z:45' },
|
|
98
|
-
{ property: 'rotate-z', value: '45deg', isArbitrary: true, attrType: 'visual', raw: 'rotate-z:[45deg]' },
|
|
99
|
-
{ property: 'skew-x', value: '10', attrType: 'visual', raw: 'skew-x:10' },
|
|
100
|
-
{ property: 'skew-x', value: '10deg', isArbitrary: true, attrType: 'visual', raw: 'skew-x:[10deg]' },
|
|
101
|
-
{ property: 'skew-y', value: '10', attrType: 'visual', raw: 'skew-y:10' },
|
|
102
|
-
{ property: 'skew-y', value: '10deg', isArbitrary: true, attrType: 'visual', raw: 'skew-y:[10deg]' },
|
|
103
|
-
{ property: '-skew-x', value: '10', attrType: 'visual', raw: '-skew-x:10' },
|
|
104
|
-
{ property: '-skew-x', value: '10deg', isArbitrary: true, attrType: 'visual', raw: '-skew-x:[10deg]' },
|
|
105
|
-
{ property: '-skew-y', value: '10', attrType: 'visual', raw: '-skew-y:10' },
|
|
106
|
-
{ property: '-skew-y', value: '10deg', isArbitrary: true, attrType: 'visual', raw: '-skew-y:[10deg]' },
|
|
107
|
-
{ property: 'translate-z', value: 'near', attrType: 'visual', raw: 'translate-z:near' },
|
|
108
|
-
{ property: 'translate-z', value: '10px', isArbitrary: true, attrType: 'visual', raw: 'translate-z:[10px]' },
|
|
109
|
-
{ property: 'origin', value: 'top-right', attrType: 'visual', raw: 'origin:top-right' },
|
|
110
|
-
{ property: 'origin', value: 'custom', attrType: 'visual', raw: 'origin:custom' },
|
|
111
|
-
{ property: 'origin', value: '10%_20%', isArbitrary: true, attrType: 'visual', raw: 'origin:[10%_20%]' },
|
|
112
|
-
{ property: 'perspective', value: 'big', attrType: 'visual', raw: 'perspective:big' },
|
|
113
|
-
{ property: 'perspective', value: 'unknown', attrType: 'visual', raw: 'perspective:unknown' },
|
|
114
|
-
{ property: 'perspective', value: '500px', isArbitrary: true, attrType: 'visual', raw: 'perspective:[500px]' },
|
|
115
|
-
{ property: 'perspective-origin', value: 'bottom-left', attrType: 'visual', raw: 'perspective-origin:bottom-left' },
|
|
116
|
-
{ property: 'perspective-origin', value: 'custom', attrType: 'visual', raw: 'perspective-origin:custom' },
|
|
117
|
-
{ property: 'perspective-origin', value: '10%_20%', isArbitrary: true, attrType: 'visual', raw: 'perspective-origin:[10%_20%]' }
|
|
118
|
-
];
|
|
119
|
-
const css = generateCSS(tokens, config);
|
|
120
|
-
assert.ok(css.includes('rotateX(45deg)'));
|
|
121
|
-
assert.ok(css.includes('skewX(-10deg)'));
|
|
122
|
-
|
|
123
|
-
// Branch coverage: directional translation & rotation defaults
|
|
124
|
-
const transDefaults = [
|
|
125
|
-
{ property: 'translate-y', value: 'unknown', attrType: 'visual', raw: 'translate-y:unknown' },
|
|
126
|
-
{ property: 'translate-z', value: 'unknown', attrType: 'visual', raw: 'translate-z:unknown' },
|
|
127
|
-
{ property: 'rotate-x', value: '90', attrType: 'visual', raw: 'rotate-x:90' },
|
|
128
|
-
{ property: 'rotate-y', value: '90', attrType: 'visual', raw: 'rotate-y:90' },
|
|
129
|
-
{ property: 'rotate-z', value: '90', attrType: 'visual', raw: 'rotate-z:90' }
|
|
130
|
-
];
|
|
131
|
-
const cssTransDefaults = generateCSS(transDefaults, config);
|
|
132
|
-
assert.ok(cssTransDefaults.includes('translateY(var(--s-unknown))'));
|
|
133
|
-
assert.ok(cssTransDefaults.includes('translateZ(var(--s-unknown))'));
|
|
134
|
-
assert.ok(cssTransDefaults.includes('rotateX(90deg)'));
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
await t.test('Visual - Transitions and Animations', () => {
|
|
138
|
-
const tokens = [
|
|
139
|
-
{ property: 'transition', value: 'colors', attrType: 'visual', raw: 'transition:colors' },
|
|
140
|
-
{ property: 'transition', value: 'opacity,transform', isArbitrary: true, attrType: 'visual', raw: 'transition:[opacity,transform]' },
|
|
141
|
-
{ property: 'duration', value: '150ms', isArbitrary: true, attrType: 'visual', raw: 'duration:[150ms]' },
|
|
142
|
-
{ property: 'duration', value: '0.5s', isArbitrary: true, attrType: 'visual', raw: 'duration:[0.5s]' },
|
|
143
|
-
{ property: 'ease', value: 'in-out', attrType: 'visual', raw: 'ease:in-out' },
|
|
144
|
-
{ property: 'ease', value: 'cubic-bezier(0,0,0,0)', isArbitrary: true, attrType: 'visual', raw: 'ease:[cubic-bezier(0,0,0,0)]' },
|
|
145
|
-
{ property: 'delay', value: '100', attrType: 'visual', raw: 'delay:100' },
|
|
146
|
-
{ property: 'delay', value: '0.2s', isArbitrary: true, attrType: 'visual', raw: 'delay:[0.2s]' },
|
|
147
|
-
{ property: 'animate', value: 'spin', attrType: 'visual', raw: 'animate:spin' },
|
|
148
|
-
{ property: 'animate', value: 'none', attrType: 'visual', raw: 'animate:none' },
|
|
149
|
-
{ property: 'animate', value: 'my-anim_2s_linear', isArbitrary: true, attrType: 'visual', raw: 'animate:[my-anim_2s_linear]' },
|
|
150
|
-
{ property: 'animation-duration', value: 'fast', attrType: 'visual', raw: 'animation-duration:fast' },
|
|
151
|
-
{ property: 'animation-delay', value: 'fast', attrType: 'visual', raw: 'animation-delay:fast' }
|
|
152
|
-
];
|
|
153
|
-
const css = generateCSS(tokens, config);
|
|
154
|
-
assert.ok(css.includes('transition:'));
|
|
155
|
-
assert.ok(css.includes('transition-duration: 150ms'));
|
|
156
|
-
assert.ok(css.includes('transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1)'));
|
|
157
|
-
assert.ok(css.includes('animation: my-anim 2s linear'));
|
|
158
|
-
assert.ok(css.includes('animation-duration: 150ms'));
|
|
159
|
-
assert.ok(css.includes('animation-delay: 150ms'));
|
|
160
|
-
|
|
161
|
-
// Branch coverage: fallback defaults
|
|
162
|
-
const defaults = [
|
|
163
|
-
{ property: 'duration', value: 'unknown', attrType: 'visual', raw: 'duration:unknown' },
|
|
164
|
-
{ property: 'ease', value: 'unknown', attrType: 'visual', raw: 'ease:unknown' },
|
|
165
|
-
{ property: 'delay', value: 'unknown', attrType: 'visual', raw: 'delay:unknown' },
|
|
166
|
-
{ property: 'animation-duration', value: 'unknown', attrType: 'visual', raw: 'animation-duration:unknown' },
|
|
167
|
-
{ property: 'animation-duration', value: '1s', isArbitrary: true, attrType: 'visual', raw: 'animation-duration:[1s]' },
|
|
168
|
-
{ property: 'animation-delay', value: '0.5s', isArbitrary: true, attrType: 'visual', raw: 'animation-delay:[0.5s]' }
|
|
169
|
-
];
|
|
170
|
-
const cssDefaults = generateCSS(defaults, config);
|
|
171
|
-
assert.ok(cssDefaults.includes('transition-duration: 200ms'));
|
|
172
|
-
assert.ok(cssDefaults.includes('transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1)'));
|
|
173
|
-
assert.ok(cssDefaults.includes('transition-delay: 200ms'));
|
|
174
|
-
assert.ok(cssDefaults.includes('animation-duration: 1s'));
|
|
175
|
-
assert.ok(cssDefaults.includes('animation-delay: 0.5s'));
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
await t.test('Visual - Filters and Blends', () => {
|
|
179
|
-
const tokens = [
|
|
180
|
-
{ property: 'blur', value: 'small', attrType: 'visual', raw: 'blur:small' },
|
|
181
|
-
{ property: 'blur', value: '10px', isArbitrary: true, attrType: 'visual', raw: 'blur:[10px]' },
|
|
182
|
-
{ property: '-blur', value: 'small', attrType: 'visual', raw: '-blur:small' },
|
|
183
|
-
{ property: 'brightness', value: '50', attrType: 'visual', raw: 'brightness:50' },
|
|
184
|
-
{ property: 'brightness', value: '0.5', isArbitrary: true, attrType: 'visual', raw: 'brightness:[0.5]' },
|
|
185
|
-
{ property: 'contrast', value: '50', attrType: 'visual', raw: 'contrast:50' },
|
|
186
|
-
{ property: 'grayscale', value: '50', attrType: 'visual', raw: 'grayscale:50' },
|
|
187
|
-
{ property: 'hue-rotate', value: '90', attrType: 'visual', raw: 'hue-rotate:90' },
|
|
188
|
-
{ property: '-hue-rotate', value: '90', attrType: 'visual', raw: '-hue-rotate:90' },
|
|
189
|
-
{ property: 'invert', value: '50', attrType: 'visual', raw: 'invert:50' },
|
|
190
|
-
{ property: 'saturate', value: '50', attrType: 'visual', raw: 'saturate:50' },
|
|
191
|
-
{ property: 'sepia', value: '50', attrType: 'visual', raw: 'sepia:50' },
|
|
192
|
-
{ property: 'drop-shadow', value: 'small', attrType: 'visual', raw: 'drop-shadow:small' },
|
|
193
|
-
{ property: 'drop-shadow', value: '0_0_5px_rgba(0,0,0,0.5)', isArbitrary: true, attrType: 'visual', raw: 'drop-shadow:[0_0_5px_rgba(0,0,0,0.5)]' },
|
|
194
|
-
{ property: 'backdrop-blur', value: 'small', attrType: 'visual', raw: 'backdrop-blur:small' },
|
|
195
|
-
{ property: 'brightness', value: '150', isArbitrary: true, attrType: 'visual', raw: 'brightness:[150]' },
|
|
196
|
-
{ property: 'contrast', value: '150', isArbitrary: true, attrType: 'visual', raw: 'contrast:[150]' },
|
|
197
|
-
{ property: 'grayscale', value: '50%', isArbitrary: true, attrType: 'visual', raw: 'grayscale:[50%]' },
|
|
198
|
-
{ property: 'hue-rotate', value: '45deg', isArbitrary: true, attrType: 'visual', raw: 'hue-rotate:[45deg]' },
|
|
199
|
-
{ property: 'invert', value: '50%', isArbitrary: true, attrType: 'visual', raw: 'invert:[50%]' },
|
|
200
|
-
{ property: 'saturate', value: '150', isArbitrary: true, attrType: 'visual', raw: 'saturate:[150]' },
|
|
201
|
-
{ property: 'sepia', value: '50%', isArbitrary: true, attrType: 'visual', raw: 'sepia:[50%]' },
|
|
202
|
-
{ property: 'backdrop-brightness', value: '150', isArbitrary: true, attrType: 'visual', raw: 'backdrop-brightness:[150]' },
|
|
203
|
-
{ property: 'backdrop-contrast', value: '150', isArbitrary: true, attrType: 'visual', raw: 'backdrop-contrast:[150]' },
|
|
204
|
-
{ property: 'backdrop-grayscale', value: '50%', isArbitrary: true, attrType: 'visual', raw: 'backdrop-grayscale:[50%]' },
|
|
205
|
-
{ property: 'backdrop-hue-rotate', value: '45deg', isArbitrary: true, attrType: 'visual', raw: 'backdrop-hue-rotate:[45deg]' },
|
|
206
|
-
{ property: 'backdrop-invert', value: '50%', isArbitrary: true, attrType: 'visual', raw: 'backdrop-invert:[50%]' },
|
|
207
|
-
{ property: 'backdrop-opacity', value: '0.5', isArbitrary: true, attrType: 'visual', raw: 'backdrop-opacity:[0.5]' },
|
|
208
|
-
{ property: 'backdrop-saturate', value: '150', isArbitrary: true, attrType: 'visual', raw: 'backdrop-saturate:[150]' },
|
|
209
|
-
{ property: 'backdrop-sepia', value: '50%', isArbitrary: true, attrType: 'visual', raw: 'backdrop-sepia:[50%]' },
|
|
210
|
-
{ property: 'mix-blend', value: 'multiply', attrType: 'visual', raw: 'mix-blend:multiply' },
|
|
211
|
-
{ property: 'bg-blend', value: 'screen', attrType: 'visual', raw: 'bg-blend:screen' }
|
|
212
|
-
];
|
|
213
|
-
const css = generateCSS(tokens, config);
|
|
214
|
-
assert.ok(css.includes('filter: brightness(150)'));
|
|
215
|
-
assert.ok(css.includes('backdrop-filter: brightness(150)'));
|
|
216
|
-
assert.ok(css.includes('filter: blur(4px)'));
|
|
217
|
-
assert.ok(css.includes('filter: blur(10px)'));
|
|
218
|
-
assert.ok(css.includes('backdrop-filter: blur(4px)'));
|
|
219
|
-
assert.ok(css.includes('mix-blend-mode: multiply'));
|
|
220
|
-
assert.ok(css.includes('background-blend-mode: screen'));
|
|
221
|
-
|
|
222
|
-
// Branch coverage: fallback defaults // Filters unknown
|
|
223
|
-
assert.match(generateCSS([{ property: 'backdrop-blur', value: 'unknown', attrType: 'visual', raw: 'backdrop-blur:unknown' }], createTestConfig()), /backdrop-filter: blur\(8px\)/);
|
|
224
|
-
const filterDefaults = [
|
|
225
|
-
{ property: 'brightness', value: 'unknown', attrType: 'visual', raw: 'brightness:unknown' },
|
|
226
|
-
{ property: 'contrast', value: 'unknown', attrType: 'visual', raw: 'contrast:unknown' },
|
|
227
|
-
{ property: 'drop-shadow', value: 'unknown', attrType: 'visual', raw: 'drop-shadow:unknown' },
|
|
228
|
-
{ property: 'grayscale', value: 'unknown', attrType: 'visual', raw: 'grayscale:unknown' },
|
|
229
|
-
{ property: 'invert', value: 'unknown', attrType: 'visual', raw: 'invert:unknown' },
|
|
230
|
-
{ property: 'saturate', value: 'unknown', attrType: 'visual', raw: 'saturate:unknown' },
|
|
231
|
-
{ property: 'sepia', value: 'unknown', attrType: 'visual', raw: 'sepia:unknown' },
|
|
232
|
-
{ property: 'blur', value: 'unknown', attrType: 'visual', raw: 'blur:unknown' },
|
|
233
|
-
{ property: 'backdrop-blur', value: 'unknown', attrType: 'visual', raw: 'backdrop-blur:unknown' },
|
|
234
|
-
{ property: 'backdrop-brightness', value: 'unknown', attrType: 'visual', raw: 'backdrop-brightness:unknown' },
|
|
235
|
-
{ property: 'backdrop-contrast', value: 'unknown', attrType: 'visual', raw: 'backdrop-contrast:unknown' },
|
|
236
|
-
{ property: 'backdrop-grayscale', value: 'unknown', attrType: 'visual', raw: 'backdrop-grayscale:unknown' },
|
|
237
|
-
{ property: 'backdrop-invert', value: 'unknown', attrType: 'visual', raw: 'backdrop-invert:unknown' },
|
|
238
|
-
{ property: 'backdrop-opacity', value: 'unknown', attrType: 'visual', raw: 'backdrop-opacity:unknown' },
|
|
239
|
-
{ property: 'backdrop-saturate', value: 'unknown', attrType: 'visual', raw: 'backdrop-saturate:unknown' },
|
|
240
|
-
{ property: 'backdrop-sepia', value: 'unknown', attrType: 'visual', raw: 'backdrop-sepia:unknown' }
|
|
241
|
-
];
|
|
242
|
-
const cssFilterDefaults = generateCSS(filterDefaults, config);
|
|
243
|
-
assert.ok(cssFilterDefaults.includes('filter: brightness(1)'));
|
|
244
|
-
assert.ok(cssFilterDefaults.includes('filter: blur(8px)'));
|
|
245
|
-
assert.ok(cssFilterDefaults.includes('backdrop-filter: blur(8px)'));
|
|
246
|
-
assert.ok(cssFilterDefaults.includes('backdrop-filter: opacity(1)'));
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
await t.test('Visual - Borders and Outlines', () => {
|
|
250
|
-
const tokens = [
|
|
251
|
-
{ property: 'border-w', value: '2', attrType: 'visual', raw: 'border-w:2' },
|
|
252
|
-
{ property: 'border-t-w', value: '2', attrType: 'visual', raw: 'border-t-w:2' },
|
|
253
|
-
{ property: 'border-l-w', value: '2', attrType: 'visual', raw: 'border-l-w:2' },
|
|
254
|
-
{ property: 'border-r-w', value: '2', attrType: 'visual', raw: 'border-r-w:2' },
|
|
255
|
-
{ property: 'border-b-w', value: '2', attrType: 'visual', raw: 'border-b-w:2' },
|
|
256
|
-
{ property: 'border-x-w', value: '2', attrType: 'visual', raw: 'border-x-w:2' },
|
|
257
|
-
{ property: 'border-y-w', value: '2', attrType: 'visual', raw: 'border-y-w:2' },
|
|
258
|
-
{ property: 'border', value: 'blue-500', attrType: 'visual', raw: 'border:blue-500' },
|
|
259
|
-
{ property: 'border-t', value: 'blue-500', attrType: 'visual', raw: 'border-t:blue-500' },
|
|
260
|
-
{ property: 'border-r', value: 'blue-500', attrType: 'visual', raw: 'border-r:blue-500' },
|
|
261
|
-
{ property: 'border-l', value: 'blue-500', attrType: 'visual', raw: 'border-l:blue-500' },
|
|
262
|
-
{ property: 'border-b', value: 'blue-500', attrType: 'visual', raw: 'border-b:blue-500' },
|
|
263
|
-
{ property: 'border-x', value: 'blue-500', attrType: 'visual', raw: 'border-x:blue-500' },
|
|
264
|
-
{ property: 'border-y', value: 'blue-500', attrType: 'visual', raw: 'border-y:blue-500' },
|
|
265
|
-
{ property: 'outline', value: 'blue-500', attrType: 'visual', raw: 'outline:blue-500' },
|
|
266
|
-
{ property: 'outline-offset', value: 'small', attrType: 'visual', raw: 'outline-offset:small' },
|
|
267
|
-
{ property: 'outline-offset', value: '2px', isArbitrary: true, attrType: 'visual', raw: 'outline-offset:[2px]' },
|
|
268
|
-
{ property: 'ring', value: 'none', attrType: 'visual', raw: 'ring:none' },
|
|
269
|
-
{ property: 'ring', value: 'thin', attrType: 'visual', raw: 'ring:thin' },
|
|
270
|
-
{ property: 'ring-color', value: 'blue-500', attrType: 'visual', raw: 'ring-color:blue-500' },
|
|
271
|
-
{ property: 'ring-w', value: '2', attrType: 'visual', raw: 'ring-w:2' },
|
|
272
|
-
{ property: 'ring-offset', value: 'regular', attrType: 'visual', raw: 'ring-offset:regular' },
|
|
273
|
-
{ property: 'ring-offset-color', value: 'white', attrType: 'visual', raw: 'ring-offset-color:white' },
|
|
274
|
-
{ property: 'rounded', value: 'medium', attrType: 'visual', raw: 'rounded:medium' },
|
|
275
|
-
{ property: 'mask-image', value: 'custom.png', isArbitrary: true, attrType: 'visual', raw: 'mask-image:[custom.png]' },
|
|
276
|
-
{ property: 'mask-position', value: '10px_20px', isArbitrary: true, attrType: 'visual', raw: 'mask-position:[10px_20px]' },
|
|
277
|
-
{ property: 'mask-size', value: '50%_auto', isArbitrary: true, attrType: 'visual', raw: 'mask-size:[50%_auto]' },
|
|
278
|
-
{ property: 'mask-repeat', value: 'custom-repeat', attrType: 'visual', raw: 'mask-repeat:custom-repeat' },
|
|
279
|
-
{ property: 'mask-origin', value: 'custom-origin', attrType: 'visual', raw: 'mask-origin:custom-origin' }
|
|
280
|
-
];
|
|
281
|
-
const css = generateCSS(tokens, config);
|
|
282
|
-
assert.ok(css.includes('mask-image: url(custom.png)'));
|
|
283
|
-
assert.ok(css.includes('mask-position: 10px 20px'));
|
|
284
|
-
assert.ok(css.includes('mask-size: 50% auto'));
|
|
285
|
-
assert.ok(css.includes('mask-repeat: custom-repeat'));
|
|
286
|
-
assert.ok(css.includes('mask-origin: custom-origin'));
|
|
287
|
-
assert.ok(css.includes('border-width: var(--s-2)'));
|
|
288
|
-
assert.ok(css.includes('border-top-width: var(--s-2)'));
|
|
289
|
-
assert.ok(css.includes('border-bottom-width: var(--s-2)'));
|
|
290
|
-
assert.ok(css.includes('border-left-width: var(--s-2)'));
|
|
291
|
-
assert.ok(css.includes('border-right-width: var(--s-2)'));
|
|
292
|
-
assert.ok(css.includes('border-color: var(--c-blue-500)'));
|
|
293
|
-
assert.ok(css.includes('border-top-color: var(--c-blue-500)'));
|
|
294
|
-
assert.ok(css.includes('border-radius: var(--r-medium)'));
|
|
295
|
-
assert.ok(css.includes('outline-color: var(--c-blue-500)'));
|
|
296
|
-
assert.ok(css.includes('outline-offset: var(--s-small)'));
|
|
297
|
-
assert.ok(css.includes('outline-offset: 2px'));
|
|
298
|
-
assert.ok(css.includes('--ss-ring-color: var(--c-blue-500)'));
|
|
299
|
-
assert.ok(css.includes('--ss-ring-width: 1px'));
|
|
300
|
-
assert.ok(css.includes('--ss-ring-offset-width: var(--s-regular)'));
|
|
301
|
-
});
|
|
302
|
-
|
|
303
|
-
await t.test('Space - Special Sizing (min, max, fit)', () => {
|
|
304
|
-
const w_min = { property: 'w', value: 'min', attrType: 'space', raw: 'w:min' };
|
|
305
|
-
const h_max = { property: 'h', value: 'max', attrType: 'space', raw: 'h:max' };
|
|
306
|
-
const css = generateCSS([w_min, h_max], config);
|
|
307
|
-
assert.ok(css.includes('width: min-content'));
|
|
308
|
-
assert.ok(css.includes('height: max-content'));
|
|
309
|
-
});
|
|
310
|
-
|
|
311
|
-
await t.test('Space - Tailwind Prefix & Negative', () => {
|
|
312
|
-
const pos = { property: 'p', value: 'tw-4', attrType: 'space', raw: 'p:tw-4' };
|
|
313
|
-
const neg = { property: 'm', value: '-tw-2', attrType: 'space', raw: 'm:-tw-2' };
|
|
314
|
-
const css = generateCSS([pos, neg], config);
|
|
315
|
-
assert.ok(css.includes('var(--tw-4)'));
|
|
316
|
-
assert.ok(css.includes('calc(var(--tw-2) * -1)'));
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
await t.test('Space - Percentage Adjectives', () => {
|
|
320
|
-
// Width with percentage adjectives
|
|
321
|
-
const w_full = { property: 'w', value: 'full', attrType: 'space', raw: 'w:full' };
|
|
322
|
-
const w_half = { property: 'w', value: 'half', attrType: 'space', raw: 'w:half' };
|
|
323
|
-
const w_third = { property: 'w', value: 'third', attrType: 'space', raw: 'w:third' };
|
|
324
|
-
const w_third_2x = { property: 'w', value: 'third-2x', attrType: 'space', raw: 'w:third-2x' };
|
|
325
|
-
const w_quarter = { property: 'w', value: 'quarter', attrType: 'space', raw: 'w:quarter' };
|
|
326
|
-
const w_quarter_3x = { property: 'w', value: 'quarter-3x', attrType: 'space', raw: 'w:quarter-3x' };
|
|
327
|
-
|
|
328
|
-
// Height with percentage adjectives
|
|
329
|
-
const h_half = { property: 'h', value: 'half', attrType: 'space', raw: 'h:half' };
|
|
330
|
-
|
|
331
|
-
// Fractional values (backwards compatibility)
|
|
332
|
-
const w_1_2 = { property: 'w', value: '1/2', attrType: 'space', raw: 'w:1/2' };
|
|
333
|
-
const h_2_3 = { property: 'h', value: '2/3', attrType: 'space', raw: 'h:2/3' };
|
|
334
|
-
|
|
335
|
-
const css = generateCSS([w_full, w_half, w_third, w_third_2x, w_quarter, w_quarter_3x, h_half, w_1_2, h_2_3], config);
|
|
336
|
-
assert.ok(css.includes('width: 100%'));
|
|
337
|
-
assert.ok(css.includes('width: 50%'));
|
|
338
|
-
assert.ok(css.includes('width: 33.333333%'));
|
|
339
|
-
assert.ok(css.includes('width: 66.666667%'));
|
|
340
|
-
assert.ok(css.includes('width: 25%'));
|
|
341
|
-
assert.ok(css.includes('width: 75%'));
|
|
342
|
-
assert.ok(css.includes('height: 50%'));
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
await t.test('Layout - Positioning Percentage Adjectives', () => {
|
|
346
|
-
// Positioning with percentage adjectives (for centering patterns)
|
|
347
|
-
const top_half = { property: 'top', value: 'half', attrType: 'layout', raw: 'top:half' };
|
|
348
|
-
const left_half = { property: 'left', value: 'half', attrType: 'layout', raw: 'left:half' };
|
|
349
|
-
const right_quarter = { property: 'right', value: 'quarter', attrType: 'layout', raw: 'right:quarter' };
|
|
350
|
-
|
|
351
|
-
// Negative percentage adjectives
|
|
352
|
-
const top_neg_half = { property: 'top', value: '-half', attrType: 'layout', raw: 'top:-half' };
|
|
353
|
-
|
|
354
|
-
// Fractional values
|
|
355
|
-
const left_1_3 = { property: 'left', value: '1/3', attrType: 'layout', raw: 'left:1/3' };
|
|
356
|
-
|
|
357
|
-
// Inset with percentage
|
|
358
|
-
const inset_full = { property: 'inset', value: 'full', attrType: 'layout', raw: 'inset:full' };
|
|
359
|
-
|
|
360
|
-
const css = generateCSS([top_half, left_half, right_quarter, top_neg_half, left_1_3, inset_full], config);
|
|
361
|
-
assert.ok(css.includes('top: 50%'));
|
|
362
|
-
assert.ok(css.includes('left: 50%'));
|
|
363
|
-
assert.ok(css.includes('right: 25%'));
|
|
364
|
-
assert.ok(css.includes('top: -50%'));
|
|
365
|
-
assert.ok(css.includes('left: 33.333333%'));
|
|
366
|
-
assert.ok(css.includes('inset: 100%'));
|
|
367
|
-
});
|
|
368
|
-
|
|
369
|
-
await t.test('Visual - Background Image URL and Gradients', () => {
|
|
370
|
-
const url = { property: 'bg-image', value: 'hero.jpg', attrType: 'visual', raw: 'bg-image:hero.jpg' };
|
|
371
|
-
const arb = { property: 'bg-image', value: 'custom.png', isArbitrary: true, attrType: 'visual', raw: 'bg-image:[custom.png]' };
|
|
372
|
-
const grad = { property: 'bg-image', value: 'gradient-to-t', attrType: 'visual', raw: 'bg-image:gradient-to-t' };
|
|
373
|
-
const css = generateCSS([url, arb, grad], config);
|
|
374
|
-
assert.ok(css.includes('background-image: url(hero.jpg)'));
|
|
375
|
-
assert.ok(css.includes('background-image: url(custom.png)'));
|
|
376
|
-
assert.ok(css.includes('linear-gradient(to top,'));
|
|
377
|
-
});
|
|
378
|
-
|
|
379
|
-
await t.test('Visual - Background Attachment & Clip', () => {
|
|
380
|
-
const attach = { property: 'bg-attachment', value: 'fixed', attrType: 'visual', raw: 'bg-attachment:fixed' };
|
|
381
|
-
const clip_text = { property: 'bg-clip', value: 'text', attrType: 'visual', raw: 'bg-clip:text' };
|
|
382
|
-
const css = generateCSS([attach, clip_text], config);
|
|
383
|
-
assert.ok(css.includes('background-attachment: fixed'));
|
|
384
|
-
assert.ok(css.includes('background-clip: text'));
|
|
385
|
-
});
|
|
386
|
-
|
|
387
|
-
await t.test('Visual - Opacity Edge Cases', () => {
|
|
388
|
-
const arb = { property: 'opacity', value: 'inherit', isArbitrary: true, attrType: 'visual', raw: 'opacity:[inherit]' };
|
|
389
|
-
const css = generateCSS([arb], config);
|
|
390
|
-
assert.ok(css.includes('opacity: inherit'));
|
|
391
|
-
});
|
|
392
|
-
|
|
393
|
-
await t.test('Integration - Peer Selectors', () => {
|
|
394
|
-
const tokens = [
|
|
395
|
-
{ raw: 'uid1', attrType: 'interact' },
|
|
396
|
-
{
|
|
397
|
-
raw: 'bg-primary',
|
|
398
|
-
attrType: 'visual',
|
|
399
|
-
property: 'bg',
|
|
400
|
-
value: 'primary',
|
|
401
|
-
state: 'hover'
|
|
402
|
-
}
|
|
403
|
-
];
|
|
404
|
-
const css = generateCSS(tokens, config);
|
|
405
|
-
assert.ok(css.includes('[interact~="uid1"]'), 'interact selector missing');
|
|
406
|
-
assert.ok(css.includes('~ [listens~="uid1"]'), 'listens selector missing');
|
|
407
|
-
});
|
|
408
|
-
|
|
409
|
-
await t.test('Integration - Divide with State', () => {
|
|
410
|
-
const token = {
|
|
411
|
-
raw: 'divide:primary',
|
|
412
|
-
attrType: 'visual',
|
|
413
|
-
property: 'divide',
|
|
414
|
-
value: 'primary',
|
|
415
|
-
state: 'hover'
|
|
416
|
-
};
|
|
417
|
-
const css = generateCSS([token], config);
|
|
418
|
-
assert.ok(css.includes('> :not([hidden]) ~ :not([hidden]):hover'));
|
|
419
|
-
});
|
|
420
|
-
|
|
421
|
-
await t.test('Integration - Unknown Breakpoints', () => {
|
|
422
|
-
const tokens = [
|
|
423
|
-
{
|
|
424
|
-
raw: 'unknown:block',
|
|
425
|
-
attrType: 'layout',
|
|
426
|
-
property: 'block',
|
|
427
|
-
value: 'block',
|
|
428
|
-
breakpoint: 'unknown-bp'
|
|
429
|
-
}
|
|
430
|
-
];
|
|
431
|
-
const css = generateCSS(tokens, config);
|
|
432
|
-
assert.ok(css.includes('@media'));
|
|
433
|
-
});
|
|
434
|
-
|
|
435
|
-
await t.test('Integration - Animation Keyframes', () => {
|
|
436
|
-
const css = generateCSS([], config);
|
|
437
|
-
assert.ok(css.includes('@keyframes spin'));
|
|
438
|
-
});
|
|
439
|
-
|
|
440
|
-
await t.test('Integration - Custom Dark Selector', () => {
|
|
441
|
-
const token = { state: 'dark', property: 'bg', value: 'black', attrType: 'visual', raw: 'dark:bg:black' };
|
|
442
|
-
const configCustom = createTestConfig({ darkMode: ['selector', '[data-theme="dark"]'] });
|
|
443
|
-
const css = generateCSS([token], configCustom);
|
|
444
|
-
assert.ok(css.includes('[data-theme="dark"] [visual~="dark:bg:black"]'));
|
|
445
|
-
});
|
|
446
|
-
|
|
447
|
-
await t.test('Visual - Font Weight Base', () => {
|
|
448
|
-
const token = { property: 'font', value: 'bold', attrType: 'visual', raw: 'font:bold' };
|
|
449
|
-
const css = generateCSS([token], config);
|
|
450
|
-
assert.ok(css.includes('font-weight: var(--fw-bold)'));
|
|
451
|
-
});
|
|
452
|
-
|
|
453
|
-
await t.test('Visual - Text Size Base', () => {
|
|
454
|
-
const token = { property: 'text-size', value: 'medium', attrType: 'visual', raw: 'text-size:medium' };
|
|
455
|
-
const css = generateCSS([token], config);
|
|
456
|
-
assert.ok(css.includes('font-size: var(--font-medium)'));
|
|
457
|
-
assert.ok(css.includes('line-height: var(--font-lh-medium)'));
|
|
458
|
-
});
|
|
459
|
-
|
|
460
|
-
await t.test('Layout - Grid Row Span Numeric', () => {
|
|
461
|
-
const token = { property: 'row-span', value: '2', attrType: 'layout', raw: 'row-span:2' };
|
|
462
|
-
const css = generateCSS([token], config);
|
|
463
|
-
assert.ok(css.includes('grid-row: span 2 / span 2'));
|
|
464
|
-
});
|
|
465
|
-
|
|
466
|
-
await t.test('Layout - Grid Template Columns and Rows', () => {
|
|
467
|
-
const cols_none = { property: 'grid-cols', value: 'none', attrType: 'layout', raw: 'grid-cols:none' };
|
|
468
|
-
const cols_sub = { property: 'grid-cols', value: 'subgrid', attrType: 'layout', raw: 'grid-cols:subgrid' };
|
|
469
|
-
const cols_arb = { property: 'grid-cols', value: '200px_1fr', isArbitrary: true, attrType: 'layout', raw: 'grid-cols:[200px_1fr]' };
|
|
470
|
-
|
|
471
|
-
const rows_none = { property: 'grid-rows', value: 'none', attrType: 'layout', raw: 'grid-rows:none' };
|
|
472
|
-
const rows_sub = { property: 'grid-rows', value: 'subgrid', attrType: 'layout', raw: 'grid-rows:subgrid' };
|
|
473
|
-
const rows_arb = { property: 'grid-rows', value: '100px_auto', isArbitrary: true, attrType: 'layout', raw: 'grid-rows:[100px_auto]' };
|
|
474
|
-
|
|
475
|
-
const css = generateCSS([cols_none, cols_sub, cols_arb, rows_none, rows_sub, rows_arb], config);
|
|
476
|
-
assert.ok(css.includes('grid-template-columns: none'));
|
|
477
|
-
assert.ok(css.includes('grid-template-columns: subgrid'));
|
|
478
|
-
assert.ok(css.includes('grid-template-columns: 200px 1fr'));
|
|
479
|
-
assert.ok(css.includes('grid-template-rows: none'));
|
|
480
|
-
assert.ok(css.includes('grid-template-rows: subgrid'));
|
|
481
|
-
assert.ok(css.includes('grid-template-rows: 100px auto'));
|
|
482
|
-
});
|
|
483
|
-
|
|
484
|
-
await t.test('Layout - Overflow and Aspect Ratio', () => {
|
|
485
|
-
const ov = { property: 'overflow', value: 'hidden', attrType: 'layout', raw: 'overflow:hidden' };
|
|
486
|
-
const ovX = { property: 'overflow-x', value: 'scroll', attrType: 'layout', raw: 'overflow-x:scroll' };
|
|
487
|
-
const ovY = { property: 'overflow-y', value: 'auto', attrType: 'layout', raw: 'overflow-y:auto' };
|
|
488
|
-
const aspectSquare = { property: 'aspect', value: 'square', attrType: 'layout', raw: 'aspect:square' };
|
|
489
|
-
const aspectVideo = { property: 'aspect', value: 'video', attrType: 'layout', raw: 'aspect:video' };
|
|
490
|
-
const aspectArb = { property: 'aspect', value: '21/9', isArbitrary: true, attrType: 'layout', raw: 'aspect:[21/9]' };
|
|
491
|
-
|
|
492
|
-
const css = generateCSS([ov, ovX, ovY, aspectSquare, aspectVideo, aspectArb], config);
|
|
493
|
-
assert.ok(css.includes('overflow: hidden'));
|
|
494
|
-
assert.ok(css.includes('overflow-x: scroll'));
|
|
495
|
-
assert.ok(css.includes('overflow-y: auto'));
|
|
496
|
-
assert.ok(css.includes('aspect-ratio: 1 / 1'));
|
|
497
|
-
assert.ok(css.includes('aspect-ratio: 16 / 9'));
|
|
498
|
-
assert.ok(css.includes('aspect-ratio: 21/9'));
|
|
499
|
-
});
|
|
500
|
-
|
|
501
|
-
await t.test('Layout - Object Fit and Position', () => {
|
|
502
|
-
const objFit = { property: 'object', value: 'cover', attrType: 'layout', raw: 'object:cover' };
|
|
503
|
-
const objPos = { property: 'object-pos', value: 'center_top', isArbitrary: true, attrType: 'layout', raw: 'object-pos:[center_top]' };
|
|
504
|
-
const placeItems = { property: 'place-items', value: 'center', attrType: 'layout', raw: 'place-items:center' };
|
|
505
|
-
const placeSelf = { property: 'place-self', value: 'end', attrType: 'layout', raw: 'place-self:end' };
|
|
506
|
-
const justifyItems = { property: 'justify-items', value: 'center', attrType: 'layout', raw: 'justify-items:center' };
|
|
507
|
-
const justifySelf = { property: 'justify-self', value: 'start', attrType: 'layout', raw: 'justify-self:start' };
|
|
508
|
-
const alignContent = { property: 'content', value: 'center', attrType: 'layout', raw: 'content:center' };
|
|
509
|
-
const placeContent = { property: 'place-content', value: 'evenly', attrType: 'layout', raw: 'place-content:evenly' };
|
|
510
|
-
const justify = { property: 'justify', value: 'between', attrType: 'layout', raw: 'justify:between' };
|
|
511
|
-
|
|
512
|
-
const css = generateCSS([objFit, objPos, placeItems, placeSelf, justifyItems, justifySelf, alignContent, placeContent, justify], config);
|
|
513
|
-
assert.ok(css.includes('object-fit: cover'));
|
|
514
|
-
assert.ok(css.includes('object-position: center top'));
|
|
515
|
-
assert.ok(css.includes('place-items: center'));
|
|
516
|
-
assert.ok(css.includes('place-self: end'));
|
|
517
|
-
assert.ok(css.includes('justify-items: center'));
|
|
518
|
-
assert.ok(css.includes('justify-self: start'));
|
|
519
|
-
assert.ok(css.includes('align-content: center'));
|
|
520
|
-
assert.ok(css.includes('place-content: space-evenly'));
|
|
521
|
-
assert.ok(css.includes('justify-content: space-between'));
|
|
522
|
-
});
|
|
523
|
-
|
|
524
|
-
await t.test('Layout - Inset and Positioning', () => {
|
|
525
|
-
const insetArb = { property: 'inset', value: '10px', isArbitrary: true, attrType: 'layout', raw: 'inset:[10px]' };
|
|
526
|
-
const topArb = { property: 'top', value: '5px', isArbitrary: true, attrType: 'layout', raw: 'top:[5px]' };
|
|
527
|
-
const insetX = { property: 'inset-x', value: '0', attrType: 'layout', raw: 'inset-x:0' };
|
|
528
|
-
const insetY = { property: 'inset-y', value: 'medium', attrType: 'layout', raw: 'inset-y:medium' };
|
|
529
|
-
|
|
530
|
-
const css = generateCSS([insetArb, topArb, insetX, insetY], config);
|
|
531
|
-
assert.ok(css.includes('inset: 10px'));
|
|
532
|
-
assert.ok(css.includes('top: 5px'));
|
|
533
|
-
assert.ok(css.includes('left: 0; right: 0;'));
|
|
534
|
-
assert.ok(css.includes('top: var(--s-medium); bottom: var(--s-medium);'));
|
|
535
|
-
});
|
|
536
|
-
|
|
537
|
-
await t.test('Layout - Columns and Overscroll', () => {
|
|
538
|
-
const cols = { property: 'cols', value: '3', attrType: 'layout', raw: 'cols:3' };
|
|
539
|
-
const over = { property: 'overscroll', value: 'contain', attrType: 'layout', raw: 'overscroll:contain' };
|
|
540
|
-
const overX = { property: 'overscroll-x', value: 'none', attrType: 'layout', raw: 'overscroll-x:none' };
|
|
541
|
-
const overY = { property: 'overscroll-y', value: 'auto', attrType: 'layout', raw: 'overscroll-y:auto' };
|
|
542
|
-
|
|
543
|
-
const css = generateCSS([cols, over, overX, overY], config);
|
|
544
|
-
assert.ok(css.includes('columns: 3'));
|
|
545
|
-
assert.ok(css.includes('overscroll-behavior: contain'));
|
|
546
|
-
assert.ok(css.includes('overscroll-behavior-x: none'));
|
|
547
|
-
assert.ok(css.includes('overscroll-behavior-y: auto'));
|
|
548
|
-
});
|
|
549
|
-
|
|
550
|
-
await t.test('Layout - Flex and Order', () => {
|
|
551
|
-
const basis = { property: 'basis', value: 'medium', attrType: 'layout', raw: 'basis:medium' };
|
|
552
|
-
const basisArb = { property: 'basis', value: '10px', isArbitrary: true, attrType: 'layout', raw: 'basis:[10px]' };
|
|
553
|
-
const flex1 = { property: 'flex', value: '1', attrType: 'layout', raw: 'flex:1' };
|
|
554
|
-
const flexAuto = { property: 'flex', value: 'auto', attrType: 'layout', raw: 'flex:auto' };
|
|
555
|
-
const flexInitial = { property: 'flex', value: 'initial', attrType: 'layout', raw: 'flex:initial' };
|
|
556
|
-
const flexNone = { property: 'flex', value: 'none', attrType: 'layout', raw: 'flex:none' };
|
|
557
|
-
const orderFirst = { property: 'order', value: 'first', attrType: 'layout', raw: 'order:first' };
|
|
558
|
-
const orderLast = { property: 'order', value: 'last', attrType: 'layout', raw: 'order:last' };
|
|
559
|
-
const orderNone = { property: 'order', value: 'none', attrType: 'layout', raw: 'order:none' };
|
|
560
|
-
const orderVal = { property: 'order', value: '5', attrType: 'layout', raw: 'order:5' };
|
|
561
|
-
|
|
562
|
-
const css = generateCSS([basis, basisArb, flex1, flexAuto, flexInitial, flexNone, orderFirst, orderLast, orderNone, orderVal], config);
|
|
563
|
-
assert.ok(css.includes('flex-basis: var(--s-medium)'));
|
|
564
|
-
assert.ok(css.includes('flex-basis: 10px'));
|
|
565
|
-
assert.ok(css.includes('order: -9999'));
|
|
566
|
-
});
|
|
567
|
-
|
|
568
|
-
await t.test('Layout - Map Branch Coverage', () => {
|
|
569
|
-
const tokens = [
|
|
570
|
-
{ property: 'items', value: 'start', attrType: 'layout', raw: 'items:start' },
|
|
571
|
-
{ property: 'items', value: 'custom', attrType: 'layout', raw: 'items:custom' },
|
|
572
|
-
{ property: 'self', value: 'center', attrType: 'layout', raw: 'self:center' },
|
|
573
|
-
{ property: 'self', value: 'custom', attrType: 'layout', raw: 'self:custom' },
|
|
574
|
-
{ property: 'place-content', value: 'between', attrType: 'layout', raw: 'place-content:between' },
|
|
575
|
-
{ property: 'place-content', value: 'custom', attrType: 'layout', raw: 'place-content:custom' },
|
|
576
|
-
{ property: 'justify-items', value: 'start', attrType: 'layout', raw: 'justify-items:start' },
|
|
577
|
-
{ property: 'justify-items', value: 'custom', attrType: 'layout', raw: 'justify-items:custom' },
|
|
578
|
-
{ property: 'justify-self', value: 'end', attrType: 'layout', raw: 'justify-self:end' },
|
|
579
|
-
{ property: 'justify-self', value: 'custom', attrType: 'layout', raw: 'justify-self:custom' },
|
|
580
|
-
{ property: 'align-content', value: 'center', attrType: 'layout', raw: 'align-content:center' },
|
|
581
|
-
{ property: 'align-content', value: 'custom', attrType: 'layout', raw: 'align-content:custom' },
|
|
582
|
-
{ property: 'object-fit', value: 'cover', attrType: 'layout', raw: 'object-fit:cover' },
|
|
583
|
-
{ property: 'object-fit', value: 'custom', attrType: 'layout', raw: 'object-fit:custom' },
|
|
584
|
-
{ property: 'object-position', value: 'bottom', attrType: 'layout', raw: 'object-position:bottom' },
|
|
585
|
-
{ property: 'object-position', value: 'custom', attrType: 'layout', raw: 'object-position:custom' },
|
|
586
|
-
{ property: 'overflow', value: 'hidden', attrType: 'layout', raw: 'overflow:hidden' },
|
|
587
|
-
{ property: 'overflow', value: 'visible_scroll', attrType: 'layout', raw: 'overflow:visible_scroll' },
|
|
588
|
-
{ property: 'overflow-x', value: 'auto', attrType: 'layout', raw: 'overflow-x:auto' },
|
|
589
|
-
{ property: 'overflow-y', value: 'scroll', attrType: 'layout', raw: 'overflow-y:scroll' },
|
|
590
|
-
{ property: 'overscroll', value: 'none', attrType: 'layout', raw: 'overscroll:none' },
|
|
591
|
-
{ property: 'overscroll-x', value: 'contain', attrType: 'layout', raw: 'overscroll-x:contain' },
|
|
592
|
-
{ property: 'overscroll-y', value: 'auto', attrType: 'layout', raw: 'overscroll-y:auto' }
|
|
593
|
-
];
|
|
594
|
-
const css = generateCSS(tokens, config);
|
|
595
|
-
assert.ok(css.includes('align-items: flex-start'));
|
|
596
|
-
assert.ok(css.includes('align-items: custom'));
|
|
597
|
-
});
|
|
598
|
-
|
|
599
|
-
await t.test('Branch Coverage - Full Sweep', () => {
|
|
600
|
-
const tokens = [
|
|
601
|
-
// Scale
|
|
602
|
-
{ property: 'scale', value: '50', attrType: 'visual', raw: 'scale:50' },
|
|
603
|
-
{ property: 'scale', value: '0.5', isArbitrary: true, attrType: 'visual', raw: 'scale:[0.5]' },
|
|
604
|
-
{ property: 'scale-x', value: '50', attrType: 'visual', raw: 'scale-x:50' },
|
|
605
|
-
{ property: 'scale-x', value: '0.5', isArbitrary: true, attrType: 'visual', raw: 'scale-x:[0.5]' },
|
|
606
|
-
{ property: 'scale-y', value: '50', attrType: 'visual', raw: 'scale-y:50' },
|
|
607
|
-
{ property: 'scale-y', value: '0.5', isArbitrary: true, attrType: 'visual', raw: 'scale-y:[0.5]' },
|
|
608
|
-
// Typography
|
|
609
|
-
{ property: 'font-family', value: 'sans', attrType: 'visual', raw: 'font-family:sans' },
|
|
610
|
-
{ property: 'font-family', value: 'Arial', isArbitrary: true, attrType: 'visual', raw: 'font-family:[Arial]' },
|
|
611
|
-
{ property: 'letter-spacing', value: 'wide', attrType: 'visual', raw: 'letter-spacing:wide' },
|
|
612
|
-
{ property: 'letter-spacing', value: '0.1em', isArbitrary: true, attrType: 'visual', raw: 'letter-spacing:[0.1em]' },
|
|
613
|
-
{ property: 'line-height', value: 'loose', attrType: 'visual', raw: 'line-height:loose' },
|
|
614
|
-
{ property: 'line-height', value: '2', isArbitrary: true, attrType: 'visual', raw: 'line-height:[2]' },
|
|
615
|
-
// Rotate
|
|
616
|
-
{ property: 'rotate', value: '45', attrType: 'visual', raw: 'rotate:45' },
|
|
617
|
-
{ property: 'rotate', value: '45deg', isArbitrary: true, attrType: 'visual', raw: 'rotate:[45deg]' },
|
|
618
|
-
// Translation
|
|
619
|
-
{ property: 'translate-x', value: 'medium', attrType: 'visual', raw: 'translate-x:medium' },
|
|
620
|
-
{ property: 'translate-y', value: 'medium', attrType: 'visual', raw: 'translate-y:medium' },
|
|
621
|
-
{ property: '-translate-x', value: 'medium', attrType: 'visual', raw: '-translate-x:medium' },
|
|
622
|
-
{ property: '-translate-x', value: '10px', isArbitrary: true, attrType: 'visual', raw: '-translate-x:[10px]' },
|
|
623
|
-
{ property: '-translate-y', value: 'medium', attrType: 'visual', raw: '-translate-y:medium' },
|
|
624
|
-
{ property: '-translate-y', value: '10px', isArbitrary: true, attrType: 'visual', raw: '-translate-y:[10px]' },
|
|
625
|
-
// Skew
|
|
626
|
-
{ property: 'skew-x', value: '10', attrType: 'visual', raw: 'skew-x:10' },
|
|
627
|
-
{ property: 'skew-y', value: '10', attrType: 'visual', raw: 'skew-y:10' },
|
|
628
|
-
{ property: '-skew-x', value: '10', attrType: 'visual', raw: '-skew-x:10' },
|
|
629
|
-
{ property: '-skew-y', value: '10', attrType: 'visual', raw: '-skew-y:10' },
|
|
630
|
-
// Interactivity
|
|
631
|
-
{ property: 'resize', value: 'both', attrType: 'visual', raw: 'resize:both' },
|
|
632
|
-
{ property: 'resize', value: 'custom', attrType: 'visual', raw: 'resize:custom' },
|
|
633
|
-
// SVG
|
|
634
|
-
{ property: 'fill', value: 'red-500', attrType: 'visual', raw: 'fill:red-500' },
|
|
635
|
-
{ property: 'fill', value: 'none', attrType: 'visual', raw: 'fill:none' },
|
|
636
|
-
{ property: 'fill', value: 'current', attrType: 'visual', raw: 'fill:current' },
|
|
637
|
-
{ property: 'fill', value: '#ff0000', isArbitrary: true, attrType: 'visual', raw: 'fill:[#ff0000]' },
|
|
638
|
-
{ property: 'stroke', value: 'red-500', attrType: 'visual', raw: 'stroke:red-500' },
|
|
639
|
-
{ property: 'stroke', value: 'none', attrType: 'visual', raw: 'stroke:none' },
|
|
640
|
-
{ property: 'stroke', value: 'current', attrType: 'visual', raw: 'stroke:current' },
|
|
641
|
-
{ property: 'stroke', value: '#ff0000', isArbitrary: true, attrType: 'visual', raw: 'stroke:[#ff0000]' },
|
|
642
|
-
{ property: 'stroke-w', value: '2', attrType: 'visual', raw: 'stroke-w:2' },
|
|
643
|
-
{ property: 'stroke-w', value: '10px', isArbitrary: true, attrType: 'visual', raw: 'stroke-w:[10px]' }
|
|
644
|
-
];
|
|
645
|
-
const css = generateCSS(tokens, config);
|
|
646
|
-
assert.ok(css.length > 0);
|
|
647
|
-
});
|
|
648
|
-
|
|
649
|
-
await t.test('Interactivity - Scroll and Touch Snap', () => {
|
|
650
|
-
// Scroll margin/padding (static and arbitrary)
|
|
651
|
-
const tokens = [
|
|
652
|
-
{ property: 'scroll-m', value: 'big', attrType: 'visual', raw: 'scroll-m:big' },
|
|
653
|
-
{ property: 'scroll-m', value: '10px', isArbitrary: true, attrType: 'visual', raw: 'scroll-m:[10px]' },
|
|
654
|
-
{ property: 'scroll-m-t', value: '10px', isArbitrary: true, attrType: 'visual', raw: 'scroll-m-t:[10px]' },
|
|
655
|
-
{ property: 'scroll-m-r', value: 'small', attrType: 'visual', raw: 'scroll-m-r:small' },
|
|
656
|
-
{ property: 'scroll-m-r', value: '5px', isArbitrary: true, attrType: 'visual', raw: 'scroll-m-r:[5px]' },
|
|
657
|
-
{ property: 'scroll-m-b', value: 'small', attrType: 'visual', raw: 'scroll-m-b:small' },
|
|
658
|
-
{ property: 'scroll-m-b', value: '5px', isArbitrary: true, attrType: 'visual', raw: 'scroll-m-b:[5px]' },
|
|
659
|
-
{ property: 'scroll-m-l', value: 'small', attrType: 'visual', raw: 'scroll-m-l:small' },
|
|
660
|
-
{ property: 'scroll-m-l', value: '5px', isArbitrary: true, attrType: 'visual', raw: 'scroll-m-l:[5px]' },
|
|
661
|
-
{ property: 'scroll-m-x', value: 'small', attrType: 'visual', raw: 'scroll-m-x:small' },
|
|
662
|
-
{ property: 'scroll-m-x', value: '5px', isArbitrary: true, attrType: 'visual', raw: 'scroll-m-x:[5px]' },
|
|
663
|
-
{ property: 'scroll-m-y', value: 'small', attrType: 'visual', raw: 'scroll-m-y:small' },
|
|
664
|
-
{ property: 'scroll-m-y', value: '5px', isArbitrary: true, attrType: 'visual', raw: 'scroll-m-y:[5px]' },
|
|
665
|
-
{ property: 'scroll-p', value: 'big', attrType: 'visual', raw: 'scroll-p:big' },
|
|
666
|
-
{ property: 'scroll-p', value: '20px', isArbitrary: true, attrType: 'visual', raw: 'scroll-p:[20px]' },
|
|
667
|
-
{ property: 'scroll-p-t', value: '10px', isArbitrary: true, attrType: 'visual', raw: 'scroll-p-t:[10px]' },
|
|
668
|
-
{ property: 'scroll-p-r', value: 'small', attrType: 'visual', raw: 'scroll-p-r:small' },
|
|
669
|
-
{ property: 'scroll-p-r', value: '5px', isArbitrary: true, attrType: 'visual', raw: 'scroll-p-r:[5px]' },
|
|
670
|
-
{ property: 'scroll-p-b', value: 'small', attrType: 'visual', raw: 'scroll-p-b:small' },
|
|
671
|
-
{ property: 'scroll-p-b', value: '5px', isArbitrary: true, attrType: 'visual', raw: 'scroll-p-b:[5px]' },
|
|
672
|
-
{ property: 'scroll-p-l', value: 'small', attrType: 'visual', raw: 'scroll-p-l:small' },
|
|
673
|
-
{ property: 'scroll-p-l', value: '5px', isArbitrary: true, attrType: 'visual', raw: 'scroll-p-l:[5px]' },
|
|
674
|
-
{ property: 'scroll-p-x', value: 'small', attrType: 'visual', raw: 'scroll-p-x:small' },
|
|
675
|
-
{ property: 'scroll-p-x', value: '5px', isArbitrary: true, attrType: 'visual', raw: 'scroll-p-x:[5px]' },
|
|
676
|
-
{ property: 'scroll-p-y', value: 'small', attrType: 'visual', raw: 'scroll-p-y:small' },
|
|
677
|
-
{ property: 'scroll-p-y', value: '5px', isArbitrary: true, attrType: 'visual', raw: 'scroll-p-y:[5px]' },
|
|
678
|
-
// Snap type presets and arbitrary (covers snapMap[value] || value)
|
|
679
|
-
{ property: 'snap', value: 'x', attrType: 'visual', raw: 'snap:x' },
|
|
680
|
-
{ property: 'snap', value: 'custom-mandatory', attrType: 'visual', raw: 'snap:custom-mandatory' },
|
|
681
|
-
// Touch action presets and arbitrary
|
|
682
|
-
{ property: 'touch', value: 'auto', attrType: 'visual', raw: 'touch:auto' },
|
|
683
|
-
{ property: 'touch', value: 'custom-action', attrType: 'visual', raw: 'touch:custom-action' },
|
|
684
|
-
// Will change presets and arbitrary
|
|
685
|
-
{ property: 'will-change', value: 'scroll', attrType: 'visual', raw: 'will-change:scroll' },
|
|
686
|
-
{ property: 'will-change', value: 'filter', attrType: 'visual', raw: 'will-change:filter' },
|
|
687
|
-
// Other interactivity
|
|
688
|
-
{ property: 'accent', value: 'red-500', attrType: 'visual', raw: 'accent:red-500' },
|
|
689
|
-
{ property: 'accent', value: '#ff0000', isArbitrary: true, attrType: 'visual', raw: 'accent:[#ff0000]' },
|
|
690
|
-
{ property: 'appearance', value: 'none', attrType: 'visual', raw: 'appearance:none' },
|
|
691
|
-
{ property: 'caret', value: 'blue-500', attrType: 'visual', raw: 'caret:blue-500' },
|
|
692
|
-
{ property: 'caret', value: '#0000ff', isArbitrary: true, attrType: 'visual', raw: 'caret:[#0000ff]' },
|
|
693
|
-
{ property: 'cursor', value: 'pointer', attrType: 'visual', raw: 'cursor:pointer' },
|
|
694
|
-
{ property: 'select', value: 'none', attrType: 'visual', raw: 'select:none' },
|
|
695
|
-
{ property: 'field-sizing', value: 'content', attrType: 'visual', raw: 'field-sizing:content' },
|
|
696
|
-
{ property: 'forced-colors', value: 'none', attrType: 'visual', raw: 'forced-colors:none' }
|
|
697
|
-
];
|
|
698
|
-
|
|
699
|
-
const css = generateCSS(tokens, config);
|
|
700
|
-
assert.ok(css.includes('scroll-margin: var(--s-big)'));
|
|
701
|
-
assert.ok(css.includes('scroll-margin: 10px'));
|
|
702
|
-
assert.ok(css.includes('scroll-margin-top: 10px'));
|
|
703
|
-
assert.ok(css.includes('scroll-padding: var(--s-big)'));
|
|
704
|
-
assert.ok(css.includes('scroll-padding: 20px'));
|
|
705
|
-
assert.ok(css.includes('scroll-snap-type: x mandatory'));
|
|
706
|
-
assert.ok(css.includes('scroll-snap-type: custom-mandatory'));
|
|
707
|
-
assert.ok(css.includes('touch-action: auto'));
|
|
708
|
-
assert.ok(css.includes('touch-action: custom-action'));
|
|
709
|
-
assert.ok(css.includes('will-change: scroll-position'));
|
|
710
|
-
assert.ok(css.includes('will-change: filter'));
|
|
711
|
-
assert.ok(css.includes('accent-color: var(--c-red-500)'));
|
|
712
|
-
assert.ok(css.includes('accent-color: #ff0000'));
|
|
713
|
-
});
|
|
714
|
-
|
|
715
|
-
await t.test('Integration - Branch Edge Cases', () => {
|
|
716
|
-
// 1. Dark mode missing in config (defaults to 'media')
|
|
717
|
-
const darkToken = { property: 'bg', value: 'red-500', state: 'dark', attrType: 'visual', raw: 'dark:bg:red-500' };
|
|
718
|
-
const configNoDark = createTestConfig({ darkMode: undefined });
|
|
719
|
-
const cssDark = generateCSS([darkToken], configNoDark);
|
|
720
|
-
assert.ok(cssDark.includes('@media (prefers-color-scheme: dark)'));
|
|
721
|
-
|
|
722
|
-
// 2. Responsive display reset - already covered but let's ensure the 'has(bpToken.raw)' branch
|
|
723
|
-
const baseFlex = { property: 'flex', attrType: 'layout', raw: 'flex' };
|
|
724
|
-
const respFlex = { property: 'flex', breakpoint: 'tab', attrType: 'layout', raw: 'flex' }; // Same as base, should NOT trigger reset
|
|
725
|
-
const cssReset = generateCSS([baseFlex, respFlex], config);
|
|
726
|
-
// Should NOT contain revert-layer because they are the same
|
|
727
|
-
assert.ok(!cssReset.includes('revert-layer'));
|
|
728
|
-
|
|
729
|
-
// 3. Token without attrType or unknown category
|
|
730
|
-
const noAttr = { property: 'display', value: 'block', raw: 'display-block' };
|
|
731
|
-
const unknownCat = { property: 'display', value: 'block', attrType: 'unknown', raw: 'unknown:block' };
|
|
732
|
-
const cssNoAttr = generateCSS([noAttr, unknownCat], config);
|
|
733
|
-
assert.ok(cssNoAttr.length > 0);
|
|
734
|
-
|
|
735
|
-
// 4. Unknown visual property
|
|
736
|
-
const unknownProp = { property: 'unknown-visual', value: 'value', attrType: 'visual', raw: 'unknown-visual:value' };
|
|
737
|
-
const cssUnknown = generateCSS([unknownProp], config);
|
|
738
|
-
assert.ok(!cssUnknown.includes('unknown-visual'));
|
|
739
|
-
});
|
|
740
|
-
|
|
741
|
-
await t.test('Integration - Preflight', () => {
|
|
742
|
-
const configPreflight = createTestConfig({ preflight: true });
|
|
743
|
-
const css = generateCSS([], configPreflight);
|
|
744
|
-
assert.ok(css.includes('SenangStart Preflight') || css.includes('box-sizing: border-box'));
|
|
745
|
-
});
|
|
746
|
-
|
|
747
|
-
await t.test('Integration - Responsive Display Reset', () => {
|
|
748
|
-
const tokens = [
|
|
749
|
-
{ raw: 'hidden', attrType: 'layout', property: 'hidden', value: 'hidden' },
|
|
750
|
-
{ raw: 'tab:flex', attrType: 'layout', property: 'flex', value: 'flex', breakpoint: 'tab' }
|
|
751
|
-
];
|
|
752
|
-
const css = generateCSS(tokens, config);
|
|
753
|
-
assert.ok(css.includes('[layout~="tab:flex"] { display: revert-layer; }'));
|
|
754
|
-
});
|
|
755
|
-
await t.test('Interactivity and Snap Utilities', () => {
|
|
756
|
-
const config = createTestConfig();
|
|
757
|
-
const res = generateCSS([
|
|
758
|
-
{ property: 'transform-style', value: 'preserve-3d', attrType: 'visual', raw: 'transform-style:preserve-3d' },
|
|
759
|
-
{ property: 'backface', value: 'hidden', attrType: 'visual', raw: 'backface:hidden' },
|
|
760
|
-
{ property: 'color-scheme', value: 'dark', attrType: 'visual', raw: 'color-scheme:dark' },
|
|
761
|
-
{ property: 'pointer-events', value: 'none', attrType: 'visual', raw: 'pointer-events:none' },
|
|
762
|
-
{ property: 'scroll', value: 'smooth', attrType: 'visual', raw: 'scroll:smooth' },
|
|
763
|
-
{ property: 'snap-align', value: 'center', attrType: 'visual', raw: 'snap-align:center' },
|
|
764
|
-
{ property: 'snap-stop', value: 'always', attrType: 'visual', raw: 'snap-stop:always' },
|
|
765
|
-
{ property: 'accent', value: 'blue-500', attrType: 'visual', raw: 'accent:blue-500' },
|
|
766
|
-
{ property: 'caret', value: 'red-500', attrType: 'visual', raw: 'caret:red-500' },
|
|
767
|
-
{ property: 'scroll-m-x', value: '4', attrType: 'visual', raw: 'scroll-m-x:4' },
|
|
768
|
-
{ property: 'scroll-m-y', value: '4', attrType: 'visual', raw: 'scroll-m-y:4' },
|
|
769
|
-
{ property: 'scroll-p-x', value: '4', attrType: 'visual', raw: 'scroll-p-x:4' },
|
|
770
|
-
{ property: 'scroll-p-y', value: '4', attrType: 'visual', raw: 'scroll-p-y:4' },
|
|
771
|
-
{ property: 'touch', value: 'none', attrType: 'visual', raw: 'touch:none' },
|
|
772
|
-
{ property: 'select', value: 'none', attrType: 'visual', raw: 'select:none' },
|
|
773
|
-
{ property: 'will-change', value: 'transform', attrType: 'visual', raw: 'will-change:transform' }
|
|
774
|
-
], config);
|
|
775
|
-
|
|
776
|
-
assert.match(res, /transform-style: preserve-3d/);
|
|
777
|
-
assert.match(res, /backface-visibility: hidden/);
|
|
778
|
-
assert.match(res, /color-scheme: dark/);
|
|
779
|
-
assert.match(res, /pointer-events: none/);
|
|
780
|
-
assert.match(res, /scroll-behavior: smooth/);
|
|
781
|
-
assert.match(res, /scroll-snap-align: center/);
|
|
782
|
-
assert.match(res, /scroll-snap-stop: always/);
|
|
783
|
-
assert.match(res, /accent-color: var\(--c-blue-500\)/);
|
|
784
|
-
assert.match(res, /caret-color: var\(--c-red-500\)/);
|
|
785
|
-
assert.match(res, /scroll-margin-left: var\(--s-4\); scroll-margin-right: var\(--s-4\);/);
|
|
786
|
-
assert.match(res, /touch-action: none/);
|
|
787
|
-
assert.match(res, /user-select: none/);
|
|
788
|
-
assert.match(res, /will-change: transform/);
|
|
789
|
-
});
|
|
790
|
-
|
|
791
|
-
await t.test('Space Shortcuts', () => {
|
|
792
|
-
const config = createTestConfig();
|
|
793
|
-
const res = generateCSS([
|
|
794
|
-
{ property: 'p-x', value: '4', attrType: 'space', raw: 'p-x:4' },
|
|
795
|
-
{ property: 'p-y', value: '4', attrType: 'space', raw: 'p-y:4' },
|
|
796
|
-
{ property: 'm-x', value: '4', attrType: 'space', raw: 'm-x:4' },
|
|
797
|
-
{ property: 'm-y', value: '4', attrType: 'space', raw: 'm-y:4' },
|
|
798
|
-
{ property: 'g-x', value: '4', attrType: 'space', raw: 'g-x:4' },
|
|
799
|
-
{ property: 'g-y', value: '4', attrType: 'space', raw: 'g-y:4' }
|
|
800
|
-
], config);
|
|
801
|
-
|
|
802
|
-
assert.match(res, /padding-left: var\(--s-4\); padding-right: var\(--s-4\);/);
|
|
803
|
-
assert.match(res, /padding-top: var\(--s-4\); padding-bottom: var\(--s-4\);/);
|
|
804
|
-
assert.match(res, /margin-left: var\(--s-4\); margin-right: var\(--s-4\);/);
|
|
805
|
-
assert.match(res, /margin-top: var\(--s-4\); margin-bottom: var\(--s-4\);/);
|
|
806
|
-
assert.match(res, /column-gap: var\(--s-4\);/);
|
|
807
|
-
assert.match(res, /row-gap: var\(--s-4\);/);
|
|
808
|
-
});
|
|
809
|
-
|
|
810
|
-
await t.test('Dark Mode Selector Strategy', () => {
|
|
811
|
-
const tokens = [{ property: 'opacity', value: '50', attrType: 'visual', state: 'dark', raw: 'dark:opacity:50' }];
|
|
812
|
-
const config = createTestConfig({ darkMode: 'selector' });
|
|
813
|
-
const res = generateCSS(tokens, config);
|
|
814
|
-
assert.match(res, /\.dark \[visual~="dark:opacity:50"\]/);
|
|
815
|
-
|
|
816
|
-
// Custom selector
|
|
817
|
-
const config2 = createTestConfig({ darkMode: ['selector', '[data-theme="dark"]'] });
|
|
818
|
-
const res2 = generateCSS(tokens, config2);
|
|
819
|
-
assert.match(res2, /\[data-theme="dark"\] \[visual~="dark:opacity:50"\]/);
|
|
820
|
-
});
|
|
821
|
-
|
|
822
|
-
await t.test('Minify CSS', () => {
|
|
823
|
-
const input = `
|
|
824
|
-
/* comment */
|
|
825
|
-
.foo {
|
|
826
|
-
color: red;
|
|
827
|
-
margin: 10px 20px ;
|
|
828
|
-
}
|
|
829
|
-
`;
|
|
830
|
-
const minified = minifyCSS(input);
|
|
831
|
-
assert.strictEqual(minified, '.foo{color:red;margin:10px 20px;}');
|
|
832
|
-
});
|
|
833
|
-
});
|