@styleframe/core 1.0.0 → 1.0.2
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/CHANGELOG.md +12 -0
- package/LICENSE +21 -0
- package/dist/styleframe.d.ts +301 -0
- package/dist/styleframe.js +528 -0
- package/dist/styleframe.umd.cjs +1 -0
- package/package.json +13 -3
- package/.tsbuildinfo +0 -1
- package/src/index.ts +0 -5
- package/src/styleframe.ts +0 -64
- package/src/tokens/atRule.test.ts +0 -1013
- package/src/tokens/atRule.ts +0 -67
- package/src/tokens/css.test.ts +0 -404
- package/src/tokens/css.ts +0 -23
- package/src/tokens/declarations.test.ts +0 -584
- package/src/tokens/declarations.ts +0 -71
- package/src/tokens/index.ts +0 -11
- package/src/tokens/modifier.test.ts +0 -90
- package/src/tokens/modifier.ts +0 -86
- package/src/tokens/recipe.test.ts +0 -105
- package/src/tokens/recipe.ts +0 -32
- package/src/tokens/ref.test.ts +0 -430
- package/src/tokens/ref.ts +0 -24
- package/src/tokens/root.test.ts +0 -70
- package/src/tokens/root.ts +0 -14
- package/src/tokens/selector.test.ts +0 -440
- package/src/tokens/selector.ts +0 -47
- package/src/tokens/theme.test.ts +0 -338
- package/src/tokens/theme.ts +0 -26
- package/src/tokens/utility.test.ts +0 -1456
- package/src/tokens/utility.ts +0 -92
- package/src/tokens/variable.test.ts +0 -235
- package/src/tokens/variable.ts +0 -42
- package/src/typeGuards.test.ts +0 -33
- package/src/typeGuards.ts +0 -98
- package/src/types/declarations.ts +0 -42
- package/src/types/index.ts +0 -3
- package/src/types/options.ts +0 -22
- package/src/types/tokens.ts +0 -149
- package/src/utils/capitalizeFirst.ts +0 -9
- package/src/utils/deepClone.ts +0 -317
- package/src/utils/getters.test.ts +0 -399
- package/src/utils/getters.ts +0 -36
- package/src/utils/index.ts +0 -4
- package/src/utils/merge.test.ts +0 -978
- package/src/utils/merge.ts +0 -73
- package/src/vite-env.d.ts +0 -1
- package/tsconfig.json +0 -7
- package/vite.config.ts +0 -5
|
@@ -1,1013 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it } from "vitest";
|
|
2
|
-
import type { AtRule, Root, Selector } from "../types";
|
|
3
|
-
import {
|
|
4
|
-
createAtRuleFunction,
|
|
5
|
-
createKeyframesFunction,
|
|
6
|
-
createMediaFunction,
|
|
7
|
-
} from "./atRule";
|
|
8
|
-
import { createRoot } from "./root";
|
|
9
|
-
import { createSelectorFunction } from "./selector";
|
|
10
|
-
import { createVariableFunction } from "./variable";
|
|
11
|
-
|
|
12
|
-
// ... existing code ...
|
|
13
|
-
|
|
14
|
-
describe("createAtRuleFunction", () => {
|
|
15
|
-
let root: Root;
|
|
16
|
-
let selectorInstance: Selector;
|
|
17
|
-
let selector: ReturnType<typeof createSelectorFunction>;
|
|
18
|
-
let atRule: ReturnType<typeof createAtRuleFunction>;
|
|
19
|
-
|
|
20
|
-
beforeEach(() => {
|
|
21
|
-
root = createRoot();
|
|
22
|
-
selector = createSelectorFunction(root, root);
|
|
23
|
-
selectorInstance = selector(".test", {});
|
|
24
|
-
atRule = createAtRuleFunction(selectorInstance, root);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
describe("basic at-rule creation", () => {
|
|
28
|
-
it("should create a supports at-rule with callback", () => {
|
|
29
|
-
const result = atRule("supports", "(display: grid)", ({ selector }) => {
|
|
30
|
-
selector(".grid-container", {
|
|
31
|
-
display: "grid",
|
|
32
|
-
gridTemplateColumns: "1fr 1fr 1fr",
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
expect(result).toEqual({
|
|
37
|
-
type: "at-rule",
|
|
38
|
-
identifier: "supports",
|
|
39
|
-
rule: "(display: grid)",
|
|
40
|
-
variables: [],
|
|
41
|
-
declarations: {},
|
|
42
|
-
children: [
|
|
43
|
-
{
|
|
44
|
-
type: "selector",
|
|
45
|
-
query: ".grid-container",
|
|
46
|
-
variables: [],
|
|
47
|
-
declarations: {
|
|
48
|
-
display: "grid",
|
|
49
|
-
gridTemplateColumns: "1fr 1fr 1fr",
|
|
50
|
-
},
|
|
51
|
-
children: [],
|
|
52
|
-
},
|
|
53
|
-
],
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it("should create a font-face at-rule with declarations", () => {
|
|
58
|
-
const result = atRule("font-face", "", {
|
|
59
|
-
fontFamily: "'Open Sans'",
|
|
60
|
-
src: "url('fonts/OpenSans-Regular.woff2') format('woff2')",
|
|
61
|
-
fontWeight: "normal",
|
|
62
|
-
fontStyle: "normal",
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
expect(result).toEqual({
|
|
66
|
-
type: "at-rule",
|
|
67
|
-
identifier: "font-face",
|
|
68
|
-
rule: "",
|
|
69
|
-
variables: [],
|
|
70
|
-
declarations: {
|
|
71
|
-
fontFamily: "'Open Sans'",
|
|
72
|
-
src: "url('fonts/OpenSans-Regular.woff2') format('woff2')",
|
|
73
|
-
fontWeight: "normal",
|
|
74
|
-
fontStyle: "normal",
|
|
75
|
-
},
|
|
76
|
-
children: [],
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it("should create an import at-rule with empty rule", () => {
|
|
81
|
-
const result = atRule("import", "url('styles.css')", {});
|
|
82
|
-
|
|
83
|
-
expect(result).toEqual({
|
|
84
|
-
type: "at-rule",
|
|
85
|
-
identifier: "import",
|
|
86
|
-
rule: "url('styles.css')",
|
|
87
|
-
variables: [],
|
|
88
|
-
declarations: {},
|
|
89
|
-
children: [],
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it("should add at-rule to parent children", () => {
|
|
94
|
-
const initialChildrenLength = selectorInstance.children.length;
|
|
95
|
-
|
|
96
|
-
atRule("charset", "UTF-8", {});
|
|
97
|
-
|
|
98
|
-
expect(selectorInstance.children).toHaveLength(initialChildrenLength + 1);
|
|
99
|
-
|
|
100
|
-
const lastChild = selectorInstance.children[
|
|
101
|
-
selectorInstance.children.length - 1
|
|
102
|
-
] as AtRule;
|
|
103
|
-
expect(lastChild.type).toBe("at-rule");
|
|
104
|
-
expect(lastChild.identifier).toBe("charset");
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
describe("supports at-rule tests", () => {
|
|
109
|
-
it("should create a supports at-rule with feature query", () => {
|
|
110
|
-
const result = atRule("supports", "(display: flex)", {
|
|
111
|
-
display: "flex",
|
|
112
|
-
flexDirection: "column",
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
expect(result.type).toBe("at-rule");
|
|
116
|
-
expect(result.identifier).toBe("supports");
|
|
117
|
-
expect(result.rule).toBe("(display: flex)");
|
|
118
|
-
expect(result.declarations).toEqual({
|
|
119
|
-
display: "flex",
|
|
120
|
-
flexDirection: "column",
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it("should create a supports at-rule with multiple conditions", () => {
|
|
125
|
-
const result = atRule(
|
|
126
|
-
"supports",
|
|
127
|
-
"(display: grid) and (gap: 1rem)",
|
|
128
|
-
({ selector }) => {
|
|
129
|
-
selector(".modern-grid", {
|
|
130
|
-
display: "grid",
|
|
131
|
-
gap: "1rem",
|
|
132
|
-
});
|
|
133
|
-
},
|
|
134
|
-
);
|
|
135
|
-
|
|
136
|
-
expect(result.identifier).toBe("supports");
|
|
137
|
-
expect(result.rule).toBe("(display: grid) and (gap: 1rem)");
|
|
138
|
-
expect(result.children[0]).toEqual({
|
|
139
|
-
type: "selector",
|
|
140
|
-
query: ".modern-grid",
|
|
141
|
-
variables: [],
|
|
142
|
-
declarations: {
|
|
143
|
-
display: "grid",
|
|
144
|
-
gap: "1rem",
|
|
145
|
-
},
|
|
146
|
-
children: [],
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it("should create a supports at-rule with not operator", () => {
|
|
151
|
-
const result = atRule("supports", "not (display: grid)", {
|
|
152
|
-
display: "flex",
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
expect(result.identifier).toBe("supports");
|
|
156
|
-
expect(result.rule).toBe("not (display: grid)");
|
|
157
|
-
expect(result.declarations).toEqual({
|
|
158
|
-
display: "flex",
|
|
159
|
-
});
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
describe("font-face at-rule tests", () => {
|
|
164
|
-
it("should create a font-face at-rule with multiple font formats", () => {
|
|
165
|
-
const result = atRule("font-face", "", {
|
|
166
|
-
fontFamily: "'My Custom Font'",
|
|
167
|
-
src: "url('fonts/custom.woff2') format('woff2'), url('fonts/custom.woff') format('woff')",
|
|
168
|
-
fontWeight: "700",
|
|
169
|
-
fontStyle: "normal",
|
|
170
|
-
fontDisplay: "swap",
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
expect(result.identifier).toBe("font-face");
|
|
174
|
-
expect(result.rule).toBe("");
|
|
175
|
-
expect(result.declarations).toEqual({
|
|
176
|
-
fontFamily: "'My Custom Font'",
|
|
177
|
-
src: "url('fonts/custom.woff2') format('woff2'), url('fonts/custom.woff') format('woff')",
|
|
178
|
-
fontWeight: "700",
|
|
179
|
-
fontStyle: "normal",
|
|
180
|
-
fontDisplay: "swap",
|
|
181
|
-
});
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
it("should create a font-face at-rule with unicode-range", () => {
|
|
185
|
-
const result = atRule("font-face", "", {
|
|
186
|
-
fontFamily: "'Noto Sans'",
|
|
187
|
-
src: "url('fonts/NotoSans-Latin.woff2') format('woff2')",
|
|
188
|
-
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC",
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
expect(result.identifier).toBe("font-face");
|
|
192
|
-
expect(result.declarations).toEqual({
|
|
193
|
-
fontFamily: "'Noto Sans'",
|
|
194
|
-
src: "url('fonts/NotoSans-Latin.woff2') format('woff2')",
|
|
195
|
-
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC",
|
|
196
|
-
});
|
|
197
|
-
});
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
describe("container at-rule tests", () => {
|
|
201
|
-
it("should create a container at-rule", () => {
|
|
202
|
-
const result = atRule("container", "", ({ selector }) => {
|
|
203
|
-
selector(".responsive-element", {
|
|
204
|
-
maxWidth: "100%",
|
|
205
|
-
});
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
expect(result.identifier).toBe("container");
|
|
209
|
-
expect(result.rule).toBe("");
|
|
210
|
-
expect(result.children[0]).toEqual({
|
|
211
|
-
type: "selector",
|
|
212
|
-
query: ".responsive-element",
|
|
213
|
-
variables: [],
|
|
214
|
-
declarations: {
|
|
215
|
-
maxWidth: "100%",
|
|
216
|
-
},
|
|
217
|
-
children: [],
|
|
218
|
-
});
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
it("should create a container at-rule with container name", () => {
|
|
222
|
-
const result = atRule("container", "sidebar (min-width: 768px)", {
|
|
223
|
-
padding: "1rem",
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
expect(result.identifier).toBe("container");
|
|
227
|
-
expect(result.rule).toBe("sidebar (min-width: 768px)");
|
|
228
|
-
expect(result.declarations).toEqual({
|
|
229
|
-
padding: "1rem",
|
|
230
|
-
});
|
|
231
|
-
});
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
describe("layer at-rule tests", () => {
|
|
235
|
-
it("should create a layer at-rule with declarations", () => {
|
|
236
|
-
const result = atRule("layer", "base", ({ selector }) => {
|
|
237
|
-
selector("body", {
|
|
238
|
-
margin: "0",
|
|
239
|
-
padding: "0",
|
|
240
|
-
});
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
expect(result.identifier).toBe("layer");
|
|
244
|
-
expect(result.rule).toBe("base");
|
|
245
|
-
expect(result.children[0]).toEqual({
|
|
246
|
-
type: "selector",
|
|
247
|
-
query: "body",
|
|
248
|
-
variables: [],
|
|
249
|
-
declarations: {
|
|
250
|
-
margin: "0",
|
|
251
|
-
padding: "0",
|
|
252
|
-
},
|
|
253
|
-
children: [],
|
|
254
|
-
});
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
it("should create a layer at-rule for multiple layers", () => {
|
|
258
|
-
const result = atRule("layer", "utilities, components, base", {});
|
|
259
|
-
|
|
260
|
-
expect(result.identifier).toBe("layer");
|
|
261
|
-
expect(result.rule).toBe("utilities, components, base");
|
|
262
|
-
expect(result.declarations).toEqual({});
|
|
263
|
-
});
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
describe("property at-rule tests", () => {
|
|
267
|
-
it("should create a property at-rule", () => {
|
|
268
|
-
const result = atRule("property", "--brand-color", {
|
|
269
|
-
syntax: "<color>",
|
|
270
|
-
inherits: "true",
|
|
271
|
-
initialValue: "#1a73e8",
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
expect(result.identifier).toBe("property");
|
|
275
|
-
expect(result.rule).toBe("--brand-color");
|
|
276
|
-
expect(result.declarations).toEqual({
|
|
277
|
-
syntax: "<color>",
|
|
278
|
-
inherits: "true",
|
|
279
|
-
initialValue: "#1a73e8",
|
|
280
|
-
});
|
|
281
|
-
});
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
describe("page at-rule tests", () => {
|
|
285
|
-
it("should create a page at-rule", () => {
|
|
286
|
-
const result = atRule("page", "", {
|
|
287
|
-
margin: "2cm",
|
|
288
|
-
size: "A4",
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
expect(result.identifier).toBe("page");
|
|
292
|
-
expect(result.rule).toBe("");
|
|
293
|
-
expect(result.declarations).toEqual({
|
|
294
|
-
margin: "2cm",
|
|
295
|
-
size: "A4",
|
|
296
|
-
});
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
it("should create a page at-rule with pseudo-class", () => {
|
|
300
|
-
const result = atRule("page", ":first", {
|
|
301
|
-
margin: "3cm",
|
|
302
|
-
counterIncrement: "page",
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
expect(result.identifier).toBe("page");
|
|
306
|
-
expect(result.rule).toBe(":first");
|
|
307
|
-
expect(result.declarations).toEqual({
|
|
308
|
-
margin: "3cm",
|
|
309
|
-
counterIncrement: "page",
|
|
310
|
-
});
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
it("should create a page at-rule with named page", () => {
|
|
314
|
-
const result = atRule("page", "chapter", ({ atRule }) => {
|
|
315
|
-
atRule("top-center", "", {
|
|
316
|
-
content: "string(chapter-title)",
|
|
317
|
-
});
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
expect(result.identifier).toBe("page");
|
|
321
|
-
expect(result.rule).toBe("chapter");
|
|
322
|
-
|
|
323
|
-
const firstChild = result.children[0] as AtRule;
|
|
324
|
-
|
|
325
|
-
expect(firstChild?.type).toBe("at-rule");
|
|
326
|
-
expect(firstChild?.identifier).toBe("top-center");
|
|
327
|
-
});
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
describe("complex at-rule nesting", () => {
|
|
331
|
-
it("should support nesting at-rules", () => {
|
|
332
|
-
const result = atRule("supports", "(display: grid)", ({ atRule }) => {
|
|
333
|
-
atRule("media", "(min-width: 768px)", {
|
|
334
|
-
display: "grid",
|
|
335
|
-
});
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
expect(result.children[0]).toEqual({
|
|
339
|
-
type: "at-rule",
|
|
340
|
-
identifier: "media",
|
|
341
|
-
rule: "(min-width: 768px)",
|
|
342
|
-
variables: [],
|
|
343
|
-
declarations: {
|
|
344
|
-
display: "grid",
|
|
345
|
-
},
|
|
346
|
-
children: [],
|
|
347
|
-
});
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
it("should support deep nesting with multiple at-rules", () => {
|
|
351
|
-
const result = atRule(
|
|
352
|
-
"supports",
|
|
353
|
-
"(display: grid)",
|
|
354
|
-
({ atRule, selector }) => {
|
|
355
|
-
atRule("media", "(min-width: 768px)", ({ atRule }) => {
|
|
356
|
-
atRule("container", "(min-width: 500px)", {
|
|
357
|
-
display: "grid",
|
|
358
|
-
});
|
|
359
|
-
});
|
|
360
|
-
|
|
361
|
-
selector(".fallback", {
|
|
362
|
-
display: "flex",
|
|
363
|
-
});
|
|
364
|
-
},
|
|
365
|
-
);
|
|
366
|
-
|
|
367
|
-
const nestedMedia = result.children[0] as AtRule;
|
|
368
|
-
expect(nestedMedia.type).toBe("at-rule");
|
|
369
|
-
expect(nestedMedia.identifier).toBe("media");
|
|
370
|
-
|
|
371
|
-
const nestedContainer = nestedMedia.children[0] as AtRule;
|
|
372
|
-
expect(nestedContainer.type).toBe("at-rule");
|
|
373
|
-
expect(nestedContainer.identifier).toBe("container");
|
|
374
|
-
expect(nestedContainer.declarations).toEqual({
|
|
375
|
-
display: "grid",
|
|
376
|
-
});
|
|
377
|
-
|
|
378
|
-
const fallbackSelector = result.children[1] as Selector;
|
|
379
|
-
expect(fallbackSelector.type).toBe("selector");
|
|
380
|
-
expect(fallbackSelector.query).toBe(".fallback");
|
|
381
|
-
});
|
|
382
|
-
});
|
|
383
|
-
|
|
384
|
-
describe("callback context functions in at-rules", () => {
|
|
385
|
-
it("should provide variable function in context", () => {
|
|
386
|
-
const result = atRule("layer", "theme", ({ variable }) => {
|
|
387
|
-
const color = variable("primary-color", "#0066cc");
|
|
388
|
-
expect(color.name).toBe("primary-color");
|
|
389
|
-
expect(color.value).toBe("#0066cc");
|
|
390
|
-
|
|
391
|
-
return {
|
|
392
|
-
backgroundColor: color.value as string,
|
|
393
|
-
};
|
|
394
|
-
});
|
|
395
|
-
|
|
396
|
-
expect(result.variables).toHaveLength(1);
|
|
397
|
-
expect(result.declarations).toEqual({
|
|
398
|
-
backgroundColor: "#0066cc",
|
|
399
|
-
});
|
|
400
|
-
});
|
|
401
|
-
});
|
|
402
|
-
});
|
|
403
|
-
|
|
404
|
-
describe("createMediaFunction", () => {
|
|
405
|
-
let root: Root;
|
|
406
|
-
let selector: Selector;
|
|
407
|
-
let media: ReturnType<typeof createMediaFunction>;
|
|
408
|
-
let variable: ReturnType<typeof createVariableFunction>;
|
|
409
|
-
|
|
410
|
-
beforeEach(() => {
|
|
411
|
-
root = createRoot();
|
|
412
|
-
selector = {
|
|
413
|
-
type: "selector",
|
|
414
|
-
query: ".test",
|
|
415
|
-
variables: [],
|
|
416
|
-
declarations: {},
|
|
417
|
-
children: [],
|
|
418
|
-
};
|
|
419
|
-
media = createMediaFunction(selector, root);
|
|
420
|
-
variable = createVariableFunction(root, root);
|
|
421
|
-
});
|
|
422
|
-
|
|
423
|
-
describe("basic media query creation", () => {
|
|
424
|
-
it("should create a media query with callback only", () => {
|
|
425
|
-
const result = media("(min-width: 768px)", ({ selector }) => {
|
|
426
|
-
selector(".container", {
|
|
427
|
-
width: "750px",
|
|
428
|
-
});
|
|
429
|
-
});
|
|
430
|
-
|
|
431
|
-
expect(result).toEqual({
|
|
432
|
-
type: "at-rule",
|
|
433
|
-
identifier: "media",
|
|
434
|
-
rule: "(min-width: 768px)",
|
|
435
|
-
variables: [],
|
|
436
|
-
declarations: {},
|
|
437
|
-
children: [
|
|
438
|
-
{
|
|
439
|
-
type: "selector",
|
|
440
|
-
query: ".container",
|
|
441
|
-
variables: [],
|
|
442
|
-
declarations: {
|
|
443
|
-
width: "750px",
|
|
444
|
-
},
|
|
445
|
-
children: [],
|
|
446
|
-
},
|
|
447
|
-
],
|
|
448
|
-
});
|
|
449
|
-
});
|
|
450
|
-
|
|
451
|
-
it("should create a media query with declarations and callback", () => {
|
|
452
|
-
const result = media("(min-width: 768px)", ({ selector }) => {
|
|
453
|
-
selector(".text", {
|
|
454
|
-
lineHeight: "1.4",
|
|
455
|
-
});
|
|
456
|
-
|
|
457
|
-
return {
|
|
458
|
-
fontSize: "18px",
|
|
459
|
-
};
|
|
460
|
-
});
|
|
461
|
-
|
|
462
|
-
expect(result.type).toBe("at-rule");
|
|
463
|
-
expect(result.identifier).toBe("media");
|
|
464
|
-
expect(result.rule).toBe("(min-width: 768px)");
|
|
465
|
-
expect(result.declarations).toEqual({
|
|
466
|
-
fontSize: "18px",
|
|
467
|
-
});
|
|
468
|
-
expect(result.children).toHaveLength(1);
|
|
469
|
-
expect(result.children[0]).toEqual({
|
|
470
|
-
type: "selector",
|
|
471
|
-
query: ".text",
|
|
472
|
-
variables: [],
|
|
473
|
-
declarations: {
|
|
474
|
-
lineHeight: "1.4",
|
|
475
|
-
},
|
|
476
|
-
children: [],
|
|
477
|
-
});
|
|
478
|
-
});
|
|
479
|
-
|
|
480
|
-
it("should create a media query with declarations only", () => {
|
|
481
|
-
const result = media("(max-width: 767px)", {
|
|
482
|
-
fontSize: "14px",
|
|
483
|
-
padding: "0.5rem",
|
|
484
|
-
});
|
|
485
|
-
|
|
486
|
-
expect(result).toEqual({
|
|
487
|
-
type: "at-rule",
|
|
488
|
-
identifier: "media",
|
|
489
|
-
rule: "(max-width: 767px)",
|
|
490
|
-
variables: [],
|
|
491
|
-
declarations: {
|
|
492
|
-
fontSize: "14px",
|
|
493
|
-
padding: "0.5rem",
|
|
494
|
-
},
|
|
495
|
-
children: [],
|
|
496
|
-
});
|
|
497
|
-
});
|
|
498
|
-
|
|
499
|
-
it("should add media query to context children", () => {
|
|
500
|
-
const initialChildrenLength = selector.children.length;
|
|
501
|
-
|
|
502
|
-
media("(min-width: 1024px)", {
|
|
503
|
-
width: "980px",
|
|
504
|
-
});
|
|
505
|
-
|
|
506
|
-
expect(selector.children).toHaveLength(initialChildrenLength + 1);
|
|
507
|
-
|
|
508
|
-
const lastChild = selector.children[
|
|
509
|
-
selector.children.length - 1
|
|
510
|
-
] as AtRule;
|
|
511
|
-
expect(lastChild.type).toBe("at-rule");
|
|
512
|
-
});
|
|
513
|
-
});
|
|
514
|
-
|
|
515
|
-
describe("context parameter handling", () => {
|
|
516
|
-
it("should work with root context", () => {
|
|
517
|
-
const mediaWithRootContext = createMediaFunction(root, root);
|
|
518
|
-
|
|
519
|
-
const result = mediaWithRootContext(
|
|
520
|
-
"(min-width: 768px)",
|
|
521
|
-
({ selector }) => {
|
|
522
|
-
selector(".root-selector", {
|
|
523
|
-
margin: "0 auto",
|
|
524
|
-
});
|
|
525
|
-
},
|
|
526
|
-
);
|
|
527
|
-
|
|
528
|
-
expect(result.children[0]).toEqual({
|
|
529
|
-
type: "selector",
|
|
530
|
-
query: ".root-selector",
|
|
531
|
-
variables: [],
|
|
532
|
-
declarations: {
|
|
533
|
-
margin: "0 auto",
|
|
534
|
-
},
|
|
535
|
-
children: [],
|
|
536
|
-
});
|
|
537
|
-
});
|
|
538
|
-
|
|
539
|
-
it("should work with selector context", () => {
|
|
540
|
-
const mediaWithSelectorContext = createMediaFunction(selector, root);
|
|
541
|
-
|
|
542
|
-
const result = mediaWithSelectorContext("(min-width: 768px)", {
|
|
543
|
-
padding: "2rem",
|
|
544
|
-
});
|
|
545
|
-
|
|
546
|
-
expect(result.declarations).toEqual({
|
|
547
|
-
padding: "2rem",
|
|
548
|
-
});
|
|
549
|
-
});
|
|
550
|
-
});
|
|
551
|
-
|
|
552
|
-
describe("callback context functions", () => {
|
|
553
|
-
it("should provide variable function in context", () => {
|
|
554
|
-
media("(min-width: 768px)", ({ variable }) => {
|
|
555
|
-
const testVar = variable("test-media-var", "2rem");
|
|
556
|
-
expect(testVar.name).toBe("test-media-var");
|
|
557
|
-
expect(testVar.value).toBe("2rem");
|
|
558
|
-
});
|
|
559
|
-
});
|
|
560
|
-
|
|
561
|
-
it("should provide selector function in context", () => {
|
|
562
|
-
const result = media("(min-width: 768px)", ({ selector }) => {
|
|
563
|
-
selector(".media-selector", {
|
|
564
|
-
display: "block",
|
|
565
|
-
});
|
|
566
|
-
});
|
|
567
|
-
|
|
568
|
-
expect(result.children[0]).toEqual({
|
|
569
|
-
type: "selector",
|
|
570
|
-
query: ".media-selector",
|
|
571
|
-
variables: [],
|
|
572
|
-
declarations: {
|
|
573
|
-
display: "block",
|
|
574
|
-
},
|
|
575
|
-
children: [],
|
|
576
|
-
});
|
|
577
|
-
});
|
|
578
|
-
|
|
579
|
-
it("should provide nested media function in context", () => {
|
|
580
|
-
const result = media("(min-width: 768px)", ({ media }) => {
|
|
581
|
-
media("(orientation: landscape)", {
|
|
582
|
-
width: "100vw",
|
|
583
|
-
});
|
|
584
|
-
});
|
|
585
|
-
|
|
586
|
-
expect(result.children[0]).toEqual({
|
|
587
|
-
type: "at-rule",
|
|
588
|
-
identifier: "media",
|
|
589
|
-
rule: "(orientation: landscape)",
|
|
590
|
-
variables: [],
|
|
591
|
-
declarations: {
|
|
592
|
-
width: "100vw",
|
|
593
|
-
},
|
|
594
|
-
children: [],
|
|
595
|
-
});
|
|
596
|
-
});
|
|
597
|
-
|
|
598
|
-
it("should allow chaining multiple context functions", () => {
|
|
599
|
-
const result = media("(min-width: 768px)", ({ variable, selector }) => {
|
|
600
|
-
const spacing = variable("media-spacing", "2rem");
|
|
601
|
-
|
|
602
|
-
selector(".spaced", {
|
|
603
|
-
margin: spacing.value as string,
|
|
604
|
-
});
|
|
605
|
-
});
|
|
606
|
-
|
|
607
|
-
expect(result.children).toHaveLength(1); // selector
|
|
608
|
-
expect(result.variables).toHaveLength(1); // variable
|
|
609
|
-
});
|
|
610
|
-
});
|
|
611
|
-
|
|
612
|
-
describe("media query strings", () => {
|
|
613
|
-
it("should handle simple min-width queries", () => {
|
|
614
|
-
const result = media("(min-width: 768px)", {});
|
|
615
|
-
|
|
616
|
-
expect(result.rule).toBe("(min-width: 768px)");
|
|
617
|
-
});
|
|
618
|
-
|
|
619
|
-
it("should handle complex media queries", () => {
|
|
620
|
-
const complexQuery =
|
|
621
|
-
"(min-width: 768px) and (max-width: 1023px) and (orientation: landscape)";
|
|
622
|
-
const result = media(complexQuery, {});
|
|
623
|
-
|
|
624
|
-
expect(result.rule).toBe(complexQuery);
|
|
625
|
-
});
|
|
626
|
-
|
|
627
|
-
it("should handle feature queries", () => {
|
|
628
|
-
const result = media("(prefers-color-scheme: dark)", {
|
|
629
|
-
backgroundColor: "#1a1a1a",
|
|
630
|
-
});
|
|
631
|
-
|
|
632
|
-
expect(result.rule).toBe("(prefers-color-scheme: dark)");
|
|
633
|
-
expect(result.declarations.backgroundColor).toBe("#1a1a1a");
|
|
634
|
-
});
|
|
635
|
-
|
|
636
|
-
it("should handle resolution queries", () => {
|
|
637
|
-
const result = media(
|
|
638
|
-
"(-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi)",
|
|
639
|
-
{
|
|
640
|
-
backgroundImage: 'url("image@2x.png")',
|
|
641
|
-
},
|
|
642
|
-
);
|
|
643
|
-
|
|
644
|
-
expect(result.rule).toBe(
|
|
645
|
-
"(-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi)",
|
|
646
|
-
);
|
|
647
|
-
});
|
|
648
|
-
|
|
649
|
-
it("should handle empty query string", () => {
|
|
650
|
-
const result = media("", {
|
|
651
|
-
display: "none",
|
|
652
|
-
});
|
|
653
|
-
|
|
654
|
-
expect(result.rule).toBe("");
|
|
655
|
-
});
|
|
656
|
-
});
|
|
657
|
-
|
|
658
|
-
describe("nested media queries", () => {
|
|
659
|
-
it("should support nesting media queries", () => {
|
|
660
|
-
const result = media("(min-width: 768px)", ({ media }) => {
|
|
661
|
-
media("(orientation: portrait)", {
|
|
662
|
-
width: "100%",
|
|
663
|
-
});
|
|
664
|
-
});
|
|
665
|
-
|
|
666
|
-
expect(result.children[0]).toEqual({
|
|
667
|
-
type: "at-rule",
|
|
668
|
-
identifier: "media",
|
|
669
|
-
rule: "(orientation: portrait)",
|
|
670
|
-
variables: [],
|
|
671
|
-
declarations: {
|
|
672
|
-
width: "100%",
|
|
673
|
-
},
|
|
674
|
-
children: [],
|
|
675
|
-
});
|
|
676
|
-
});
|
|
677
|
-
|
|
678
|
-
it("should support deep nesting", () => {
|
|
679
|
-
const result = media("(min-width: 768px)", ({ media }) => {
|
|
680
|
-
media("(max-width: 1023px)", ({ selector }) => {
|
|
681
|
-
selector(".nested-selector", {
|
|
682
|
-
padding: "1rem",
|
|
683
|
-
});
|
|
684
|
-
});
|
|
685
|
-
});
|
|
686
|
-
|
|
687
|
-
const nestedMedia = result.children[0] as AtRule;
|
|
688
|
-
expect(nestedMedia.type).toBe("at-rule");
|
|
689
|
-
expect(nestedMedia.identifier).toBe("media");
|
|
690
|
-
expect(nestedMedia.rule).toBe("(max-width: 1023px)");
|
|
691
|
-
expect(nestedMedia.children[0]).toEqual({
|
|
692
|
-
type: "selector",
|
|
693
|
-
query: ".nested-selector",
|
|
694
|
-
variables: [],
|
|
695
|
-
declarations: {
|
|
696
|
-
padding: "1rem",
|
|
697
|
-
},
|
|
698
|
-
children: [],
|
|
699
|
-
});
|
|
700
|
-
});
|
|
701
|
-
});
|
|
702
|
-
|
|
703
|
-
describe("declarations handling", () => {
|
|
704
|
-
it("should handle empty declarations", () => {
|
|
705
|
-
const result = media("(min-width: 768px)", {});
|
|
706
|
-
|
|
707
|
-
expect(result.declarations).toEqual({});
|
|
708
|
-
});
|
|
709
|
-
|
|
710
|
-
it("should handle single declaration", () => {
|
|
711
|
-
const result = media("(min-width: 768px)", {
|
|
712
|
-
width: "750px",
|
|
713
|
-
});
|
|
714
|
-
|
|
715
|
-
expect(result.declarations).toEqual({
|
|
716
|
-
width: "750px",
|
|
717
|
-
});
|
|
718
|
-
});
|
|
719
|
-
|
|
720
|
-
it("should handle multiple declarations", () => {
|
|
721
|
-
const result = media("(min-width: 768px)", {
|
|
722
|
-
width: "750px",
|
|
723
|
-
margin: "0 auto",
|
|
724
|
-
padding: "2rem",
|
|
725
|
-
});
|
|
726
|
-
|
|
727
|
-
expect(result.declarations).toEqual({
|
|
728
|
-
width: "750px",
|
|
729
|
-
margin: "0 auto",
|
|
730
|
-
padding: "2rem",
|
|
731
|
-
});
|
|
732
|
-
});
|
|
733
|
-
|
|
734
|
-
it("should handle CSS custom properties", () => {
|
|
735
|
-
const result = media("(min-width: 768px)", {
|
|
736
|
-
"--primary-color": "#006cff",
|
|
737
|
-
"--spacing": "2rem",
|
|
738
|
-
});
|
|
739
|
-
|
|
740
|
-
expect(result.declarations).toEqual({
|
|
741
|
-
"--primary-color": "#006cff",
|
|
742
|
-
"--spacing": "2rem",
|
|
743
|
-
});
|
|
744
|
-
});
|
|
745
|
-
});
|
|
746
|
-
|
|
747
|
-
describe("real-world usage patterns", () => {
|
|
748
|
-
it("should support responsive typography", () => {
|
|
749
|
-
const result = media("(min-width: 768px)", ({ selector }) => {
|
|
750
|
-
selector(".responsive-text", {
|
|
751
|
-
fontSize: "18px",
|
|
752
|
-
lineHeight: "1.4",
|
|
753
|
-
});
|
|
754
|
-
});
|
|
755
|
-
|
|
756
|
-
expect(result.children[0]).toEqual({
|
|
757
|
-
type: "selector",
|
|
758
|
-
query: ".responsive-text",
|
|
759
|
-
variables: [],
|
|
760
|
-
declarations: {
|
|
761
|
-
fontSize: "18px",
|
|
762
|
-
lineHeight: "1.4",
|
|
763
|
-
},
|
|
764
|
-
children: [],
|
|
765
|
-
});
|
|
766
|
-
});
|
|
767
|
-
|
|
768
|
-
it("should support responsive grid layouts", () => {
|
|
769
|
-
const result = media("(min-width: 1024px)", ({ selector }) => {
|
|
770
|
-
selector(".grid", {
|
|
771
|
-
gridTemplateColumns: "repeat(4, 1fr)",
|
|
772
|
-
gap: "2rem",
|
|
773
|
-
});
|
|
774
|
-
});
|
|
775
|
-
|
|
776
|
-
expect(result.children[0]).toEqual({
|
|
777
|
-
type: "selector",
|
|
778
|
-
query: ".grid",
|
|
779
|
-
variables: [],
|
|
780
|
-
declarations: {
|
|
781
|
-
gridTemplateColumns: "repeat(4, 1fr)",
|
|
782
|
-
gap: "2rem",
|
|
783
|
-
},
|
|
784
|
-
children: [],
|
|
785
|
-
});
|
|
786
|
-
});
|
|
787
|
-
|
|
788
|
-
it("should support breakpoint variables", () => {
|
|
789
|
-
const breakpointMd = variable("breakpoint-md", "768px");
|
|
790
|
-
|
|
791
|
-
const result = media(
|
|
792
|
-
`(min-width: ${breakpointMd.value})`,
|
|
793
|
-
({ selector, variable }) => {
|
|
794
|
-
const spacing = variable("tablet-spacing", "1.5rem");
|
|
795
|
-
selector(".responsive-container", {
|
|
796
|
-
padding: spacing.value as string,
|
|
797
|
-
});
|
|
798
|
-
},
|
|
799
|
-
);
|
|
800
|
-
|
|
801
|
-
expect(result.children).toHaveLength(1); // selector
|
|
802
|
-
expect(result.variables).toHaveLength(1); // variable
|
|
803
|
-
});
|
|
804
|
-
|
|
805
|
-
it("should support dark mode queries", () => {
|
|
806
|
-
const result = media("(prefers-color-scheme: dark)", ({ selector }) => {
|
|
807
|
-
selector(".theme-aware", {
|
|
808
|
-
backgroundColor: "#1a1a1a",
|
|
809
|
-
color: "#ffffff",
|
|
810
|
-
});
|
|
811
|
-
});
|
|
812
|
-
|
|
813
|
-
expect(result.rule).toBe("(prefers-color-scheme: dark)");
|
|
814
|
-
});
|
|
815
|
-
|
|
816
|
-
it("should support reduced motion queries", () => {
|
|
817
|
-
const result = media(
|
|
818
|
-
"(prefers-reduced-motion: reduce)",
|
|
819
|
-
({ selector }) => {
|
|
820
|
-
selector(".animated", {
|
|
821
|
-
animation: "none",
|
|
822
|
-
transition: "none",
|
|
823
|
-
});
|
|
824
|
-
},
|
|
825
|
-
);
|
|
826
|
-
|
|
827
|
-
expect(result.rule).toBe("(prefers-reduced-motion: reduce)");
|
|
828
|
-
});
|
|
829
|
-
});
|
|
830
|
-
|
|
831
|
-
describe("function overloading", () => {
|
|
832
|
-
it("should distinguish between callback and declarations as second parameter", () => {
|
|
833
|
-
const callbackResult = media("(min-width: 768px)", ({ selector }) => {
|
|
834
|
-
selector(".callback-test", { width: "100%" });
|
|
835
|
-
});
|
|
836
|
-
|
|
837
|
-
const declarationsResult = media("(min-width: 768px)", {
|
|
838
|
-
width: "750px",
|
|
839
|
-
});
|
|
840
|
-
|
|
841
|
-
expect(callbackResult.declarations).toEqual({});
|
|
842
|
-
expect(callbackResult.children).toHaveLength(1);
|
|
843
|
-
|
|
844
|
-
expect(declarationsResult.declarations).toEqual({ width: "750px" });
|
|
845
|
-
expect(declarationsResult.children).toHaveLength(0);
|
|
846
|
-
});
|
|
847
|
-
|
|
848
|
-
it("should handle three-parameter form correctly", () => {
|
|
849
|
-
const result = media("(min-width: 768px)", ({ selector }) => {
|
|
850
|
-
selector(".three-param-test", {
|
|
851
|
-
lineHeight: "1.4",
|
|
852
|
-
});
|
|
853
|
-
|
|
854
|
-
return {
|
|
855
|
-
fontSize: "18px",
|
|
856
|
-
};
|
|
857
|
-
});
|
|
858
|
-
|
|
859
|
-
expect(result.declarations).toEqual({ fontSize: "18px" });
|
|
860
|
-
expect(result.children).toHaveLength(1);
|
|
861
|
-
});
|
|
862
|
-
});
|
|
863
|
-
|
|
864
|
-
describe("edge cases", () => {
|
|
865
|
-
it("should handle multiple media queries with same query string", () => {
|
|
866
|
-
const result1 = media("(min-width: 768px)", { width: "750px" });
|
|
867
|
-
const result2 = media("(min-width: 768px)", { height: "100vh" });
|
|
868
|
-
|
|
869
|
-
expect(result1).not.toBe(result2);
|
|
870
|
-
expect(result1.rule).toBe(result2.rule);
|
|
871
|
-
expect(result1.declarations).not.toEqual(result2.declarations);
|
|
872
|
-
});
|
|
873
|
-
|
|
874
|
-
it("should maintain proper structure with empty callback", () => {
|
|
875
|
-
const result = media("(min-width: 768px)", () => {
|
|
876
|
-
// Empty callback
|
|
877
|
-
});
|
|
878
|
-
|
|
879
|
-
expect(result).toEqual({
|
|
880
|
-
type: "at-rule",
|
|
881
|
-
identifier: "media",
|
|
882
|
-
rule: "(min-width: 768px)",
|
|
883
|
-
variables: [],
|
|
884
|
-
declarations: {},
|
|
885
|
-
children: [],
|
|
886
|
-
});
|
|
887
|
-
});
|
|
888
|
-
|
|
889
|
-
it("should handle special characters in media queries", () => {
|
|
890
|
-
const complexQuery =
|
|
891
|
-
"screen and (min-width: 768px) and (max-width: 1023.98px)";
|
|
892
|
-
const result = media(complexQuery, {});
|
|
893
|
-
|
|
894
|
-
expect(result.rule).toBe(complexQuery);
|
|
895
|
-
});
|
|
896
|
-
});
|
|
897
|
-
|
|
898
|
-
describe("function context independence", () => {
|
|
899
|
-
it("should create independent functions for different contexts", () => {
|
|
900
|
-
const context1 = createRoot();
|
|
901
|
-
const context2: Selector = {
|
|
902
|
-
type: "selector",
|
|
903
|
-
query: ".different",
|
|
904
|
-
variables: [],
|
|
905
|
-
declarations: {},
|
|
906
|
-
children: [],
|
|
907
|
-
};
|
|
908
|
-
|
|
909
|
-
const media1 = createMediaFunction(context1, root);
|
|
910
|
-
const media2 = createMediaFunction(context2, root);
|
|
911
|
-
|
|
912
|
-
const result1 = media1("(min-width: 768px)", { width: "100%" });
|
|
913
|
-
const result2 = media2("(min-width: 768px)", { width: "750px" });
|
|
914
|
-
|
|
915
|
-
expect(media1).not.toBe(media2);
|
|
916
|
-
expect(result1.declarations).not.toEqual(result2.declarations);
|
|
917
|
-
});
|
|
918
|
-
});
|
|
919
|
-
});
|
|
920
|
-
|
|
921
|
-
describe("createKeyframesFunction", () => {
|
|
922
|
-
let root: Root;
|
|
923
|
-
let keyframes: ReturnType<typeof createKeyframesFunction>;
|
|
924
|
-
let selector: ReturnType<typeof createSelectorFunction>;
|
|
925
|
-
|
|
926
|
-
beforeEach(() => {
|
|
927
|
-
root = createRoot();
|
|
928
|
-
keyframes = createKeyframesFunction(root, root);
|
|
929
|
-
selector = createSelectorFunction(root, root);
|
|
930
|
-
});
|
|
931
|
-
|
|
932
|
-
it("should create keyframes with the correct structure", () => {
|
|
933
|
-
const fadeInKeyframes = keyframes("fade-in", {
|
|
934
|
-
"0%": {
|
|
935
|
-
opacity: 0,
|
|
936
|
-
transform: "translateY(20px)",
|
|
937
|
-
},
|
|
938
|
-
"100%": {
|
|
939
|
-
opacity: 1,
|
|
940
|
-
transform: "translateY(0)",
|
|
941
|
-
},
|
|
942
|
-
});
|
|
943
|
-
|
|
944
|
-
expect(fadeInKeyframes).toEqual({
|
|
945
|
-
type: "at-rule",
|
|
946
|
-
identifier: "keyframes",
|
|
947
|
-
rule: "fade-in",
|
|
948
|
-
children: [],
|
|
949
|
-
variables: [],
|
|
950
|
-
declarations: {
|
|
951
|
-
"0%": {
|
|
952
|
-
opacity: 0,
|
|
953
|
-
transform: "translateY(20px)",
|
|
954
|
-
},
|
|
955
|
-
"100%": {
|
|
956
|
-
opacity: 1,
|
|
957
|
-
transform: "translateY(0)",
|
|
958
|
-
},
|
|
959
|
-
},
|
|
960
|
-
});
|
|
961
|
-
|
|
962
|
-
expect(root.children).toContain(fadeInKeyframes);
|
|
963
|
-
});
|
|
964
|
-
|
|
965
|
-
it("should support multiple keyframe stops", () => {
|
|
966
|
-
const bounceKeyframes = keyframes("bounce", {
|
|
967
|
-
"0%": {
|
|
968
|
-
transform: "translateY(0)",
|
|
969
|
-
animationTimingFunction: "ease-out",
|
|
970
|
-
},
|
|
971
|
-
"25%": {
|
|
972
|
-
transform: "translateY(-20px)",
|
|
973
|
-
animationTimingFunction: "ease-in",
|
|
974
|
-
},
|
|
975
|
-
"50%": {
|
|
976
|
-
transform: "translateY(0)",
|
|
977
|
-
animationTimingFunction: "ease-out",
|
|
978
|
-
},
|
|
979
|
-
"75%": {
|
|
980
|
-
transform: "translateY(-10px)",
|
|
981
|
-
animationTimingFunction: "ease-in",
|
|
982
|
-
},
|
|
983
|
-
"100%": {
|
|
984
|
-
transform: "translateY(0)",
|
|
985
|
-
animationTimingFunction: "ease-out",
|
|
986
|
-
},
|
|
987
|
-
});
|
|
988
|
-
|
|
989
|
-
expect(Object.keys(bounceKeyframes.declarations)).toHaveLength(5);
|
|
990
|
-
expect(bounceKeyframes.declarations["0%"]).toBeDefined();
|
|
991
|
-
expect(bounceKeyframes.declarations["25%"]).toBeDefined();
|
|
992
|
-
expect(bounceKeyframes.declarations["50%"]).toBeDefined();
|
|
993
|
-
expect(bounceKeyframes.declarations["75%"]).toBeDefined();
|
|
994
|
-
expect(bounceKeyframes.declarations["100%"]).toBeDefined();
|
|
995
|
-
});
|
|
996
|
-
|
|
997
|
-
it("should be accessible in the declarations context", () => {
|
|
998
|
-
selector(".test", ({ keyframes }) => {
|
|
999
|
-
const fadeIn = keyframes("fade-in", {
|
|
1000
|
-
"0%": { opacity: 0 },
|
|
1001
|
-
"100%": { opacity: 1 },
|
|
1002
|
-
});
|
|
1003
|
-
|
|
1004
|
-
expect(fadeIn.type).toBe("at-rule");
|
|
1005
|
-
expect(fadeIn.identifier).toBe("keyframes");
|
|
1006
|
-
expect(fadeIn.rule).toBe("fade-in");
|
|
1007
|
-
expect(fadeIn.declarations).toEqual({
|
|
1008
|
-
"0%": { opacity: 0 },
|
|
1009
|
-
"100%": { opacity: 1 },
|
|
1010
|
-
});
|
|
1011
|
-
});
|
|
1012
|
-
});
|
|
1013
|
-
});
|