@praxisjs/motion 0.2.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +56 -0
- package/dist/__tests__/decorators.test.d.ts +2 -0
- package/dist/__tests__/decorators.test.d.ts.map +1 -0
- package/dist/__tests__/decorators.test.js +139 -0
- package/dist/__tests__/decorators.test.js.map +1 -0
- package/dist/__tests__/easings.test.js +64 -55
- package/dist/__tests__/easings.test.js.map +1 -1
- package/dist/__tests__/spring.test.js +59 -34
- package/dist/__tests__/spring.test.js.map +1 -1
- package/dist/__tests__/transition.test.js +71 -44
- package/dist/__tests__/transition.test.js.map +1 -1
- package/dist/__tests__/tween.test.js +74 -94
- package/dist/__tests__/tween.test.js.map +1 -1
- package/dist/decorators.d.ts +3 -1
- package/dist/decorators.d.ts.map +1 -1
- package/dist/decorators.js +39 -16
- package/dist/decorators.js.map +1 -1
- package/dist/index.d.ts +2 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -6
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/src/__tests__/decorators.test.ts +152 -0
- package/src/__tests__/easings.test.ts +66 -59
- package/src/__tests__/spring.test.ts +66 -34
- package/src/__tests__/transition.test.ts +74 -46
- package/src/__tests__/tween.test.ts +77 -95
- package/src/decorators.ts +42 -15
- package/src/index.ts +2 -15
- package/dist/__tests__/use-motion.test.d.ts +0 -2
- package/dist/__tests__/use-motion.test.d.ts.map +0 -1
- package/dist/__tests__/use-motion.test.js +0 -139
- package/dist/__tests__/use-motion.test.js.map +0 -1
- package/dist/use-motion.d.ts +0 -20
- package/dist/use-motion.d.ts.map +0 -1
- package/dist/use-motion.js +0 -58
- package/dist/use-motion.js.map +0 -1
- package/src/__tests__/use-motion.test.ts +0 -172
- package/src/use-motion.ts +0 -89
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
import { describe, it, expect, vi } from "vitest";
|
|
3
|
+
|
|
4
|
+
import { Tween, Spring } from "../decorators";
|
|
5
|
+
|
|
6
|
+
function makeCtx(name: string) {
|
|
7
|
+
const initializers: Array<(this: unknown) => void> = [];
|
|
8
|
+
return {
|
|
9
|
+
ctx: {
|
|
10
|
+
name,
|
|
11
|
+
kind: "field" as const,
|
|
12
|
+
addInitializer(fn: (this: unknown) => void) { initializers.push(fn); },
|
|
13
|
+
} as ClassFieldDecoratorContext,
|
|
14
|
+
run(instance: unknown) {
|
|
15
|
+
initializers.forEach((fn) => { fn.call(instance); });
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// ── @Tween ────────────────────────────────────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
describe("@Tween", () => {
|
|
23
|
+
it("returns 0 before any value is set", () => {
|
|
24
|
+
vi.useFakeTimers();
|
|
25
|
+
const { ctx, run } = makeCtx("opacity");
|
|
26
|
+
Tween()(undefined, ctx);
|
|
27
|
+
const instance: Record<string, unknown> = {};
|
|
28
|
+
run(instance);
|
|
29
|
+
expect(instance.opacity).toBe(0);
|
|
30
|
+
vi.clearAllTimers();
|
|
31
|
+
vi.useRealTimers();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("creates a numeric getter/setter on first assignment", () => {
|
|
35
|
+
vi.useFakeTimers();
|
|
36
|
+
const { ctx, run } = makeCtx("x");
|
|
37
|
+
Tween()(undefined, ctx);
|
|
38
|
+
const instance: Record<string, unknown> = {};
|
|
39
|
+
run(instance);
|
|
40
|
+
instance.x = 10;
|
|
41
|
+
expect(typeof instance.x).toBe("number");
|
|
42
|
+
vi.clearAllTimers();
|
|
43
|
+
vi.useRealTimers();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("updating the property updates the tween target", () => {
|
|
47
|
+
vi.useFakeTimers();
|
|
48
|
+
const { ctx, run } = makeCtx("scale");
|
|
49
|
+
Tween()(undefined, ctx);
|
|
50
|
+
const instance: Record<string, unknown> = {};
|
|
51
|
+
run(instance);
|
|
52
|
+
instance.scale = 1;
|
|
53
|
+
instance.scale = 2;
|
|
54
|
+
expect(typeof instance.scale).toBe("number");
|
|
55
|
+
vi.clearAllTimers();
|
|
56
|
+
vi.useRealTimers();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("accepts TweenOptions", () => {
|
|
60
|
+
vi.useFakeTimers();
|
|
61
|
+
const { ctx, run } = makeCtx("y");
|
|
62
|
+
Tween({ duration: 500, easing: "linear", delay: 50 })(undefined, ctx);
|
|
63
|
+
const instance: Record<string, unknown> = {};
|
|
64
|
+
run(instance);
|
|
65
|
+
instance.y = 100;
|
|
66
|
+
expect(typeof instance.y).toBe("number");
|
|
67
|
+
vi.clearAllTimers();
|
|
68
|
+
vi.useRealTimers();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("each instance gets its own tween", () => {
|
|
72
|
+
vi.useFakeTimers();
|
|
73
|
+
const { ctx, run } = makeCtx("val");
|
|
74
|
+
Tween()(undefined, ctx);
|
|
75
|
+
const a: Record<string, unknown> = {};
|
|
76
|
+
const b: Record<string, unknown> = {};
|
|
77
|
+
run(a);
|
|
78
|
+
run(b);
|
|
79
|
+
a.val = 10;
|
|
80
|
+
b.val = 50;
|
|
81
|
+
expect(a.val).not.toBe(b.val);
|
|
82
|
+
vi.clearAllTimers();
|
|
83
|
+
vi.useRealTimers();
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// ── @Spring ───────────────────────────────────────────────────────────────────
|
|
88
|
+
|
|
89
|
+
describe("@Spring", () => {
|
|
90
|
+
it("returns 0 before any value is set", () => {
|
|
91
|
+
vi.useFakeTimers();
|
|
92
|
+
const { ctx, run } = makeCtx("x");
|
|
93
|
+
Spring()(undefined, ctx);
|
|
94
|
+
const instance: Record<string, unknown> = {};
|
|
95
|
+
run(instance);
|
|
96
|
+
expect(instance.x).toBe(0);
|
|
97
|
+
vi.clearAllTimers();
|
|
98
|
+
vi.useRealTimers();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("creates a numeric getter/setter on first assignment", () => {
|
|
102
|
+
vi.useFakeTimers();
|
|
103
|
+
const { ctx, run } = makeCtx("y");
|
|
104
|
+
Spring()(undefined, ctx);
|
|
105
|
+
const instance: Record<string, unknown> = {};
|
|
106
|
+
run(instance);
|
|
107
|
+
instance.y = 42;
|
|
108
|
+
expect(typeof instance.y).toBe("number");
|
|
109
|
+
vi.clearAllTimers();
|
|
110
|
+
vi.useRealTimers();
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("updating the property sets the spring target", () => {
|
|
114
|
+
vi.useFakeTimers();
|
|
115
|
+
const { ctx, run } = makeCtx("scale");
|
|
116
|
+
Spring()(undefined, ctx);
|
|
117
|
+
const instance: Record<string, unknown> = {};
|
|
118
|
+
run(instance);
|
|
119
|
+
instance.scale = 1;
|
|
120
|
+
instance.scale = 2;
|
|
121
|
+
expect(typeof instance.scale).toBe("number");
|
|
122
|
+
vi.clearAllTimers();
|
|
123
|
+
vi.useRealTimers();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("accepts SpringOptions", () => {
|
|
127
|
+
vi.useFakeTimers();
|
|
128
|
+
const { ctx, run } = makeCtx("opacity");
|
|
129
|
+
Spring({ stiffness: 0.3, damping: 0.9, mass: 2 })(undefined, ctx);
|
|
130
|
+
const instance: Record<string, unknown> = {};
|
|
131
|
+
run(instance);
|
|
132
|
+
instance.opacity = 1;
|
|
133
|
+
expect(typeof instance.opacity).toBe("number");
|
|
134
|
+
vi.clearAllTimers();
|
|
135
|
+
vi.useRealTimers();
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it("each instance gets its own spring", () => {
|
|
139
|
+
vi.useFakeTimers();
|
|
140
|
+
const { ctx, run } = makeCtx("val");
|
|
141
|
+
Spring()(undefined, ctx);
|
|
142
|
+
const a: Record<string, unknown> = {};
|
|
143
|
+
const b: Record<string, unknown> = {};
|
|
144
|
+
run(a);
|
|
145
|
+
run(b);
|
|
146
|
+
a.val = 10;
|
|
147
|
+
b.val = 50;
|
|
148
|
+
expect(a.val).not.toBe(b.val);
|
|
149
|
+
vi.clearAllTimers();
|
|
150
|
+
vi.useRealTimers();
|
|
151
|
+
});
|
|
152
|
+
});
|
|
@@ -2,82 +2,89 @@ import { describe, it, expect } from "vitest";
|
|
|
2
2
|
|
|
3
3
|
import { easings, resolveEasing } from "../easings";
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
describe("easings.linear", () => {
|
|
6
|
+
it("returns 0 at t=0", () => expect(easings.linear(0)).toBe(0));
|
|
7
|
+
it("returns 0.5 at t=0.5", () => expect(easings.linear(0.5)).toBe(0.5));
|
|
8
|
+
it("returns 1 at t=1", () => expect(easings.linear(1)).toBe(1));
|
|
9
|
+
});
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
11
|
+
describe("easings.easeIn", () => {
|
|
12
|
+
it("returns 0 at t=0", () => expect(easings.easeIn(0)).toBe(0));
|
|
13
|
+
it("returns 0.25 at t=0.5", () => expect(easings.easeIn(0.5)).toBe(0.25));
|
|
14
|
+
it("returns 1 at t=1", () => expect(easings.easeIn(1)).toBe(1));
|
|
15
|
+
});
|
|
10
16
|
|
|
11
|
-
describe("easings", () => {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
});
|
|
17
|
-
it(`${name}(1) === 1`, () => {
|
|
18
|
-
expect(nearly(fn(1), 1)).toBe(true);
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
});
|
|
17
|
+
describe("easings.easeOut", () => {
|
|
18
|
+
it("returns 0 at t=0", () => expect(easings.easeOut(0)).toBe(0));
|
|
19
|
+
it("returns 0.75 at t=0.5", () => expect(easings.easeOut(0.5)).toBe(0.75));
|
|
20
|
+
it("returns 1 at t=1", () => expect(easings.easeOut(1)).toBe(1));
|
|
21
|
+
});
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
describe("easings.easeInOut", () => {
|
|
24
|
+
it("returns 0 at t=0", () => expect(easings.easeInOut(0)).toBe(0));
|
|
25
|
+
it("returns 0.5 at t=0.5", () => expect(easings.easeInOut(0.5)).toBe(0.5));
|
|
26
|
+
it("returns 1 at t=1", () => expect(easings.easeInOut(1)).toBe(1));
|
|
27
|
+
it("uses easeIn branch for t<0.5", () => {
|
|
28
|
+
expect(easings.easeInOut(0.25)).toBeCloseTo(0.125);
|
|
28
29
|
});
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
it("is slower at start than end (t² curve)", () => {
|
|
32
|
-
expect(easings.easeIn(0.25)).toBeLessThan(0.25);
|
|
33
|
-
});
|
|
30
|
+
it("uses easeOut branch for t>=0.5", () => {
|
|
31
|
+
expect(easings.easeInOut(0.75)).toBeCloseTo(0.875);
|
|
34
32
|
});
|
|
33
|
+
});
|
|
35
34
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
describe("easings.easeInCubic", () => {
|
|
36
|
+
it("returns 0 at t=0", () => expect(easings.easeInCubic(0)).toBe(0));
|
|
37
|
+
it("returns 0.125 at t=0.5", () => expect(easings.easeInCubic(0.5)).toBe(0.125));
|
|
38
|
+
it("returns 1 at t=1", () => expect(easings.easeInCubic(1)).toBe(1));
|
|
39
|
+
});
|
|
41
40
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
describe("easings.bounce", () => {
|
|
42
|
+
it("returns 0 at t=0", () => expect(easings.bounce(0)).toBe(0));
|
|
43
|
+
it("returns 1 at t=1", () => expect(easings.bounce(1)).toBeCloseTo(1));
|
|
44
|
+
it("handles first branch (t < 1/2.75)", () => {
|
|
45
|
+
const t = 0.2;
|
|
46
|
+
expect(easings.bounce(t)).toBeGreaterThan(0);
|
|
47
47
|
});
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
expect(nearly(easings.easeInCubic(0.5), 0.125)).toBe(true);
|
|
52
|
-
});
|
|
48
|
+
it("handles second branch (t < 2/2.75)", () => {
|
|
49
|
+
const t = 0.5;
|
|
50
|
+
expect(easings.bounce(t)).toBeGreaterThan(0.7);
|
|
53
51
|
});
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
});
|
|
52
|
+
it("handles third branch (t < 2.5/2.75)", () => {
|
|
53
|
+
const t = 0.85;
|
|
54
|
+
expect(easings.bounce(t)).toBeGreaterThan(0.9);
|
|
55
|
+
});
|
|
56
|
+
it("handles fourth branch (t >= 2.5/2.75)", () => {
|
|
57
|
+
const t = 0.97;
|
|
58
|
+
expect(easings.bounce(t)).toBeGreaterThan(0.98);
|
|
63
59
|
});
|
|
60
|
+
});
|
|
64
61
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
62
|
+
describe("easings.elastic", () => {
|
|
63
|
+
it("returns 0 at t=0", () => expect(easings.elastic(0)).toBe(0));
|
|
64
|
+
it("returns 1 at t=1", () => expect(easings.elastic(1)).toBe(1));
|
|
65
|
+
it("returns a negative value mid-range (overshoot)", () => {
|
|
66
|
+
expect(easings.elastic(0.5)).toBeLessThan(0);
|
|
70
67
|
});
|
|
71
68
|
});
|
|
72
69
|
|
|
73
70
|
describe("resolveEasing", () => {
|
|
74
|
-
it("resolves a
|
|
71
|
+
it("resolves a named easing", () => {
|
|
75
72
|
const fn = resolveEasing("linear");
|
|
76
|
-
expect(fn).toBe(
|
|
73
|
+
expect(fn(0.5)).toBe(0.5);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("returns a custom function as-is", () => {
|
|
77
|
+
const custom = (t: number) => t * 2;
|
|
78
|
+
const fn = resolveEasing(custom);
|
|
79
|
+
expect(fn).toBe(custom);
|
|
80
|
+
expect(fn(0.5)).toBe(1);
|
|
77
81
|
});
|
|
78
82
|
|
|
79
|
-
it("
|
|
80
|
-
const
|
|
81
|
-
|
|
83
|
+
it("resolves all named easings", () => {
|
|
84
|
+
const names = ["linear", "easeIn", "easeOut", "easeInOut", "easeInCubic", "bounce", "elastic"] as const;
|
|
85
|
+
for (const name of names) {
|
|
86
|
+
const fn = resolveEasing(name);
|
|
87
|
+
expect(typeof fn).toBe("function");
|
|
88
|
+
}
|
|
82
89
|
});
|
|
83
90
|
});
|
|
@@ -1,60 +1,92 @@
|
|
|
1
1
|
// @vitest-environment jsdom
|
|
2
|
-
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
3
3
|
|
|
4
4
|
import { spring } from "../spring";
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
vi.useFakeTimers();
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
vi.clearAllTimers();
|
|
12
|
+
vi.useRealTimers();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
describe("spring()", () => {
|
|
16
|
+
it("starts at the initial value", () => {
|
|
9
17
|
const s = spring(42);
|
|
10
18
|
expect(s.value()).toBe(42);
|
|
11
|
-
|
|
12
|
-
vi.useRealTimers();
|
|
19
|
+
s.stop();
|
|
13
20
|
});
|
|
14
21
|
|
|
15
|
-
it("target
|
|
16
|
-
vi.useFakeTimers();
|
|
22
|
+
it("target starts equal to initial value", () => {
|
|
17
23
|
const s = spring(10);
|
|
18
24
|
expect(s.target()).toBe(10);
|
|
19
|
-
|
|
20
|
-
|
|
25
|
+
s.stop();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("stop() cancels pending animation", () => {
|
|
29
|
+
const s = spring(0);
|
|
30
|
+
s.target.set(100);
|
|
31
|
+
s.stop();
|
|
32
|
+
const valueAfterStop = s.value();
|
|
33
|
+
expect(typeof valueAfterStop).toBe("number");
|
|
21
34
|
});
|
|
22
35
|
|
|
23
|
-
it("
|
|
24
|
-
vi.useFakeTimers();
|
|
36
|
+
it("setting target triggers animation", () => {
|
|
25
37
|
const s = spring(0);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
38
|
+
s.target.set(100);
|
|
39
|
+
expect(s.target()).toBe(100);
|
|
40
|
+
s.stop();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("accepts custom stiffness and damping", () => {
|
|
44
|
+
const s = spring(0, { stiffness: 0.5, damping: 0.9 });
|
|
45
|
+
s.target.set(50);
|
|
46
|
+
expect(s.target()).toBe(50);
|
|
47
|
+
s.stop();
|
|
29
48
|
});
|
|
30
49
|
|
|
31
|
-
it("
|
|
32
|
-
|
|
33
|
-
|
|
50
|
+
it("accepts custom mass and precision", () => {
|
|
51
|
+
const s = spring(0, { mass: 2, precision: 0.01 });
|
|
52
|
+
s.target.set(100);
|
|
53
|
+
expect(typeof s.value()).toBe("number");
|
|
54
|
+
s.stop();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("value is a computed (function)", () => {
|
|
58
|
+
const s = spring(0);
|
|
59
|
+
expect(typeof s.value).toBe("function");
|
|
34
60
|
s.stop();
|
|
35
|
-
expect(() => { s.stop(); }).not.toThrow();
|
|
36
|
-
vi.clearAllTimers();
|
|
37
|
-
vi.useRealTimers();
|
|
38
61
|
});
|
|
39
62
|
|
|
40
|
-
it("
|
|
41
|
-
vi.useFakeTimers();
|
|
63
|
+
it("target is a signal with a set method", () => {
|
|
42
64
|
const s = spring(0);
|
|
65
|
+
expect(typeof s.target.set).toBe("function");
|
|
66
|
+
s.stop();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("settting target multiple times accumulates velocity direction", () => {
|
|
70
|
+
const s = spring(0, { stiffness: 0.5, damping: 0.5 });
|
|
71
|
+
s.target.set(10);
|
|
72
|
+
s.target.set(20);
|
|
73
|
+
expect(s.target()).toBe(20);
|
|
74
|
+
s.stop();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("tick advances value toward target", () => {
|
|
78
|
+
const s = spring(0, { stiffness: 0.5, damping: 0.8, precision: 0.01 });
|
|
43
79
|
s.target.set(100);
|
|
44
|
-
|
|
45
|
-
vi.advanceTimersByTime(100);
|
|
46
|
-
// Value should have moved towards 100
|
|
80
|
+
vi.advanceTimersByTime(50);
|
|
47
81
|
expect(s.value()).toBeGreaterThan(0);
|
|
48
82
|
s.stop();
|
|
49
|
-
vi.clearAllTimers();
|
|
50
|
-
vi.useRealTimers();
|
|
51
83
|
});
|
|
52
84
|
|
|
53
|
-
it("
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
85
|
+
it("moves value closer to target over time", () => {
|
|
86
|
+
const s = spring(0, { stiffness: 0.5, damping: 0.95, precision: 0.01 });
|
|
87
|
+
s.target.set(100);
|
|
88
|
+
vi.advanceTimersByTime(500);
|
|
89
|
+
// Value should have moved significantly toward target
|
|
90
|
+
expect(s.value()).toBeGreaterThan(10);
|
|
59
91
|
});
|
|
60
92
|
});
|
|
@@ -1,75 +1,103 @@
|
|
|
1
1
|
// @vitest-environment jsdom
|
|
2
|
-
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
3
3
|
|
|
4
4
|
import { createTransition } from "../transition";
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const t = createTransition({ name: "fade", duration: 100 });
|
|
10
|
-
const el = document.createElement("div");
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
vi.useFakeTimers();
|
|
8
|
+
});
|
|
11
9
|
|
|
12
|
-
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
vi.clearAllTimers();
|
|
12
|
+
vi.useRealTimers();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
function makeEl() {
|
|
16
|
+
return document.createElement("div");
|
|
17
|
+
}
|
|
13
18
|
|
|
14
|
-
|
|
19
|
+
describe("createTransition()", () => {
|
|
20
|
+
it("enter() adds enter-from class immediately", () => {
|
|
21
|
+
const t = createTransition({ name: "fade" });
|
|
22
|
+
const el = makeEl();
|
|
23
|
+
void t.enter(el);
|
|
15
24
|
expect(el.classList.contains("fade-enter-from")).toBe(true);
|
|
25
|
+
});
|
|
16
26
|
|
|
17
|
-
|
|
18
|
-
|
|
27
|
+
it("enter() removes enter-from and adds enter-to after rAF", () => {
|
|
28
|
+
const t = createTransition({ name: "fade", duration: 1000 });
|
|
29
|
+
const el = makeEl();
|
|
30
|
+
void t.enter(el);
|
|
31
|
+
// Advance past rAF (16ms) but not past duration (1000ms)
|
|
32
|
+
vi.advanceTimersByTime(20);
|
|
33
|
+
expect(el.classList.contains("fade-enter-from")).toBe(false);
|
|
34
|
+
expect(el.classList.contains("fade-enter-to")).toBe(true);
|
|
35
|
+
});
|
|
19
36
|
|
|
37
|
+
it("enter() resolves and cleans up after duration", async () => {
|
|
38
|
+
const t = createTransition({ name: "fade", duration: 300 });
|
|
39
|
+
const el = makeEl();
|
|
40
|
+
const p = t.enter(el);
|
|
41
|
+
vi.advanceTimersByTime(300);
|
|
20
42
|
await p;
|
|
21
|
-
expect(el.classList.contains("fade-enter-from")).toBe(false);
|
|
22
43
|
expect(el.classList.contains("fade-enter-to")).toBe(false);
|
|
23
|
-
vi.useRealTimers();
|
|
24
44
|
});
|
|
25
45
|
|
|
26
|
-
it("leave() adds
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const p = t.leave(el);
|
|
46
|
+
it("leave() adds leave-from class immediately", () => {
|
|
47
|
+
const t = createTransition({ name: "slide" });
|
|
48
|
+
const el = makeEl();
|
|
49
|
+
void t.leave(el);
|
|
32
50
|
expect(el.classList.contains("slide-leave-from")).toBe(true);
|
|
51
|
+
});
|
|
33
52
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
53
|
+
it("leave() removes leave-from and adds leave-to after rAF", () => {
|
|
54
|
+
const t = createTransition({ name: "slide", duration: 1000 });
|
|
55
|
+
const el = makeEl();
|
|
56
|
+
void t.leave(el);
|
|
57
|
+
// Advance past rAF (16ms) but not past duration (1000ms)
|
|
58
|
+
vi.advanceTimersByTime(20);
|
|
37
59
|
expect(el.classList.contains("slide-leave-from")).toBe(false);
|
|
60
|
+
expect(el.classList.contains("slide-leave-to")).toBe(true);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("leave() resolves and cleans up after duration", async () => {
|
|
64
|
+
const t = createTransition({ name: "slide", duration: 200 });
|
|
65
|
+
const el = makeEl();
|
|
66
|
+
const p = t.leave(el);
|
|
67
|
+
vi.advanceTimersByTime(200);
|
|
68
|
+
await p;
|
|
38
69
|
expect(el.classList.contains("slide-leave-to")).toBe(false);
|
|
39
|
-
vi.useRealTimers();
|
|
40
70
|
});
|
|
41
71
|
|
|
42
|
-
it("
|
|
43
|
-
|
|
72
|
+
it("uses default name 'transition' when none provided", () => {
|
|
73
|
+
const t = createTransition();
|
|
74
|
+
const el = makeEl();
|
|
75
|
+
void t.enter(el);
|
|
76
|
+
expect(el.classList.contains("transition-enter-from")).toBe(true);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("calls onEnter callback with element", () => {
|
|
44
80
|
const onEnter = vi.fn();
|
|
45
|
-
const t = createTransition({ onEnter
|
|
46
|
-
const el =
|
|
47
|
-
|
|
81
|
+
const t = createTransition({ onEnter });
|
|
82
|
+
const el = makeEl();
|
|
83
|
+
void t.enter(el);
|
|
48
84
|
expect(onEnter).toHaveBeenCalledWith(el);
|
|
49
|
-
await vi.runAllTimersAsync();
|
|
50
|
-
await p;
|
|
51
|
-
vi.useRealTimers();
|
|
52
85
|
});
|
|
53
86
|
|
|
54
|
-
it("calls onLeave callback",
|
|
55
|
-
vi.useFakeTimers();
|
|
87
|
+
it("calls onLeave callback with element", () => {
|
|
56
88
|
const onLeave = vi.fn();
|
|
57
|
-
const t = createTransition({ onLeave
|
|
58
|
-
const el =
|
|
59
|
-
|
|
89
|
+
const t = createTransition({ onLeave });
|
|
90
|
+
const el = makeEl();
|
|
91
|
+
void t.leave(el);
|
|
60
92
|
expect(onLeave).toHaveBeenCalledWith(el);
|
|
61
|
-
await vi.runAllTimersAsync();
|
|
62
|
-
await p;
|
|
63
|
-
vi.useRealTimers();
|
|
64
93
|
});
|
|
65
94
|
|
|
66
|
-
it("uses
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
vi.useRealTimers();
|
|
95
|
+
it("uses default duration of 300ms", async () => {
|
|
96
|
+
const t = createTransition({ name: "x" });
|
|
97
|
+
const el = makeEl();
|
|
98
|
+
const p = t.enter(el);
|
|
99
|
+
vi.advanceTimersByTime(300);
|
|
100
|
+
await p;
|
|
101
|
+
expect(el.classList.contains("x-enter-to")).toBe(false);
|
|
74
102
|
});
|
|
75
103
|
});
|