@praxisjs/motion 0.2.3 → 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.
Files changed (39) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/dist/__tests__/decorators.test.d.ts +2 -0
  3. package/dist/__tests__/decorators.test.d.ts.map +1 -0
  4. package/dist/__tests__/decorators.test.js +139 -0
  5. package/dist/__tests__/decorators.test.js.map +1 -0
  6. package/dist/__tests__/easings.test.js +64 -55
  7. package/dist/__tests__/easings.test.js.map +1 -1
  8. package/dist/__tests__/spring.test.js +59 -34
  9. package/dist/__tests__/spring.test.js.map +1 -1
  10. package/dist/__tests__/transition.test.js +71 -44
  11. package/dist/__tests__/transition.test.js.map +1 -1
  12. package/dist/__tests__/tween.test.js +74 -94
  13. package/dist/__tests__/tween.test.js.map +1 -1
  14. package/dist/decorators.d.ts +3 -1
  15. package/dist/decorators.d.ts.map +1 -1
  16. package/dist/decorators.js +39 -16
  17. package/dist/decorators.js.map +1 -1
  18. package/dist/index.d.ts +2 -10
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +1 -6
  21. package/dist/index.js.map +1 -1
  22. package/package.json +3 -2
  23. package/src/__tests__/decorators.test.ts +152 -0
  24. package/src/__tests__/easings.test.ts +66 -59
  25. package/src/__tests__/spring.test.ts +66 -34
  26. package/src/__tests__/transition.test.ts +74 -46
  27. package/src/__tests__/tween.test.ts +77 -95
  28. package/src/decorators.ts +42 -15
  29. package/src/index.ts +2 -15
  30. package/dist/__tests__/use-motion.test.d.ts +0 -2
  31. package/dist/__tests__/use-motion.test.d.ts.map +0 -1
  32. package/dist/__tests__/use-motion.test.js +0 -139
  33. package/dist/__tests__/use-motion.test.js.map +0 -1
  34. package/dist/use-motion.d.ts +0 -20
  35. package/dist/use-motion.d.ts.map +0 -1
  36. package/dist/use-motion.js +0 -58
  37. package/dist/use-motion.js.map +0 -1
  38. package/src/__tests__/use-motion.test.ts +0 -172
  39. 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
- const EPSILON = 1e-6;
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
- function nearly(a: number, b: number) {
8
- return Math.abs(a - b) < EPSILON;
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
- describe("boundary conditions (t=0 0, t=1 → 1)", () => {
13
- for (const [name, fn] of Object.entries(easings)) {
14
- it(`${name}(0) === 0`, () => {
15
- expect(nearly(fn(0), 0)).toBe(true);
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
- describe("linear", () => {
24
- it("returns t unchanged", () => {
25
- expect(easings.linear(0.5)).toBe(0.5);
26
- expect(easings.linear(0.25)).toBe(0.25);
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
- describe("easeIn", () => {
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
- describe("easeOut", () => {
37
- it("is faster at start than end", () => {
38
- expect(easings.easeOut(0.75)).toBeGreaterThan(0.75);
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
- describe("easeInOut", () => {
43
- it("is symmetric around 0.5", () => {
44
- const v = easings.easeInOut(0.5);
45
- expect(nearly(v, 0.5)).toBe(true);
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
- describe("easeInCubic", () => {
50
- it("is t³", () => {
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
- describe("bounce", () => {
56
- it("stays within [0, 1] for t in [0, 1]", () => {
57
- for (let t = 0; t <= 1; t += 0.1) {
58
- const v = easings.bounce(t);
59
- expect(v).toBeGreaterThanOrEqual(0);
60
- expect(v).toBeLessThanOrEqual(1 + EPSILON);
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
- describe("elastic", () => {
66
- it("returns 0 at t=0 and 1 at t=1", () => {
67
- expect(easings.elastic(0)).toBe(0);
68
- expect(easings.elastic(1)).toBe(1);
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 string key to the easing function", () => {
71
+ it("resolves a named easing", () => {
75
72
  const fn = resolveEasing("linear");
76
- expect(fn).toBe(easings.linear);
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("passes through a custom function", () => {
80
- const custom = (t: number) => t * t * t;
81
- expect(resolveEasing(custom)).toBe(custom);
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
- describe("spring", () => {
7
- it("initializes value to the starting number", () => {
8
- vi.useFakeTimers();
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
- vi.clearAllTimers();
12
- vi.useRealTimers();
19
+ s.stop();
13
20
  });
14
21
 
15
- it("target signal starts at the initial value", () => {
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
- vi.clearAllTimers();
20
- vi.useRealTimers();
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("stop() cancels without throwing", () => {
24
- vi.useFakeTimers();
36
+ it("setting target triggers animation", () => {
25
37
  const s = spring(0);
26
- expect(() => { s.stop(); }).not.toThrow();
27
- vi.clearAllTimers();
28
- vi.useRealTimers();
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("stop() can be called multiple times safely", () => {
32
- vi.useFakeTimers();
33
- const s = spring(5);
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("updating target signal triggers animation", () => {
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
- // Run a few frames
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("accepts custom spring options", () => {
54
- vi.useFakeTimers();
55
- const s = spring(0, { stiffness: 0.5, damping: 0.9, mass: 2, precision: 0.01 });
56
- expect(s.value()).toBe(0);
57
- vi.clearAllTimers();
58
- vi.useRealTimers();
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
- describe("createTransition", () => {
7
- it("enter() adds and removes CSS classes", async () => {
8
- vi.useFakeTimers();
9
- const t = createTransition({ name: "fade", duration: 100 });
10
- const el = document.createElement("div");
6
+ beforeEach(() => {
7
+ vi.useFakeTimers();
8
+ });
11
9
 
12
- const p = t.enter(el);
10
+ afterEach(() => {
11
+ vi.clearAllTimers();
12
+ vi.useRealTimers();
13
+ });
14
+
15
+ function makeEl() {
16
+ return document.createElement("div");
17
+ }
13
18
 
14
- // enter-from should have been added immediately
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
- // requestAnimationFrame fires
18
- await vi.runAllTimersAsync();
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 and removes CSS classes", async () => {
27
- vi.useFakeTimers();
28
- const t = createTransition({ name: "slide", duration: 100 });
29
- const el = document.createElement("div");
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
- await vi.runAllTimersAsync();
35
- await p;
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("calls onEnter callback", async () => {
43
- vi.useFakeTimers();
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, duration: 0 });
46
- const el = document.createElement("div");
47
- const p = t.enter(el);
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", async () => {
55
- vi.useFakeTimers();
87
+ it("calls onLeave callback with element", () => {
56
88
  const onLeave = vi.fn();
57
- const t = createTransition({ onLeave, duration: 0 });
58
- const el = document.createElement("div");
59
- const p = t.leave(el);
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 'transition' as default name", async () => {
67
- vi.useFakeTimers();
68
- const t = createTransition();
69
- const el = document.createElement("div");
70
- t.enter(el);
71
- expect(el.classList.contains("transition-enter-from")).toBe(true);
72
- await vi.runAllTimersAsync();
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
  });