@pyreon/kinetic 0.11.5 → 0.11.7
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/README.md +27 -24
- package/lib/index.d.ts +8 -8
- package/package.json +22 -22
- package/src/Collapse.tsx +44 -44
- package/src/Stagger.tsx +7 -7
- package/src/Transition.tsx +18 -18
- package/src/TransitionGroup.tsx +6 -6
- package/src/__tests__/Collapse.test.tsx +125 -125
- package/src/__tests__/GroupRenderer.test.tsx +78 -78
- package/src/__tests__/StaggerRenderer.test.tsx +99 -99
- package/src/__tests__/Transition.test.tsx +89 -89
- package/src/__tests__/TransitionItem.test.tsx +120 -120
- package/src/__tests__/kinetic.test.tsx +135 -135
- package/src/__tests__/presets.test.ts +15 -15
- package/src/__tests__/useAnimationEnd.test.ts +33 -33
- package/src/__tests__/useReducedMotion.test.ts +22 -22
- package/src/__tests__/useTransitionState.test.ts +38 -38
- package/src/__tests__/utils.test.ts +63 -63
- package/src/index.ts +9 -17
- package/src/kinetic/CollapseRenderer.tsx +42 -42
- package/src/kinetic/GroupRenderer.tsx +8 -8
- package/src/kinetic/StaggerRenderer.tsx +9 -9
- package/src/kinetic/TransitionItem.tsx +18 -18
- package/src/kinetic/TransitionRenderer.tsx +19 -19
- package/src/kinetic/createKineticComponent.tsx +27 -27
- package/src/kinetic/types.ts +13 -13
- package/src/kinetic.ts +4 -4
- package/src/presets.ts +33 -33
- package/src/types.ts +3 -3
- package/src/useAnimationEnd.ts +8 -8
- package/src/useReducedMotion.ts +5 -5
- package/src/useTransitionState.ts +12 -12
- package/src/utils.ts +4 -4
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
import { signal } from
|
|
2
|
-
import useAnimationEnd from
|
|
1
|
+
import { signal } from '@pyreon/reactivity'
|
|
2
|
+
import useAnimationEnd from '../useAnimationEnd'
|
|
3
3
|
|
|
4
4
|
const createMockRef = () => {
|
|
5
|
-
const el = document.createElement(
|
|
5
|
+
const el = document.createElement('div')
|
|
6
6
|
return { current: el }
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
describe(
|
|
9
|
+
describe('useAnimationEnd', () => {
|
|
10
10
|
beforeEach(() => vi.useFakeTimers())
|
|
11
11
|
afterEach(() => vi.useRealTimers())
|
|
12
12
|
|
|
13
|
-
it(
|
|
13
|
+
it('calls onEnd when transitionend fires on the element', () => {
|
|
14
14
|
const onEnd = vi.fn()
|
|
15
15
|
const ref = createMockRef()
|
|
16
16
|
const active = signal(true)
|
|
17
17
|
|
|
18
18
|
useAnimationEnd({ ref, onEnd, active })
|
|
19
19
|
|
|
20
|
-
const event = new Event(
|
|
21
|
-
Object.defineProperty(event,
|
|
20
|
+
const event = new Event('transitionend', { bubbles: true })
|
|
21
|
+
Object.defineProperty(event, 'target', { value: ref.current })
|
|
22
22
|
ref.current.dispatchEvent(event)
|
|
23
23
|
|
|
24
24
|
expect(onEnd).toHaveBeenCalledTimes(1)
|
|
25
25
|
})
|
|
26
26
|
|
|
27
|
-
it(
|
|
27
|
+
it('calls onEnd when animationend fires on the element', () => {
|
|
28
28
|
const onEnd = vi.fn()
|
|
29
29
|
const ref = createMockRef()
|
|
30
30
|
const active = signal(true)
|
|
31
31
|
|
|
32
32
|
useAnimationEnd({ ref, onEnd, active })
|
|
33
33
|
|
|
34
|
-
const event = new Event(
|
|
35
|
-
Object.defineProperty(event,
|
|
34
|
+
const event = new Event('animationend', { bubbles: true })
|
|
35
|
+
Object.defineProperty(event, 'target', { value: ref.current })
|
|
36
36
|
ref.current.dispatchEvent(event)
|
|
37
37
|
|
|
38
38
|
expect(onEnd).toHaveBeenCalledTimes(1)
|
|
39
39
|
})
|
|
40
40
|
|
|
41
|
-
it(
|
|
41
|
+
it('ignores bubbled events from children', () => {
|
|
42
42
|
const onEnd = vi.fn()
|
|
43
43
|
const ref = createMockRef()
|
|
44
|
-
const child = document.createElement(
|
|
44
|
+
const child = document.createElement('span')
|
|
45
45
|
ref.current.appendChild(child)
|
|
46
46
|
const active = signal(true)
|
|
47
47
|
|
|
48
48
|
useAnimationEnd({ ref, onEnd, active })
|
|
49
49
|
|
|
50
|
-
const event = new Event(
|
|
50
|
+
const event = new Event('transitionend', { bubbles: true })
|
|
51
51
|
child.dispatchEvent(event)
|
|
52
52
|
|
|
53
53
|
expect(onEnd).not.toHaveBeenCalled()
|
|
54
54
|
})
|
|
55
55
|
|
|
56
|
-
it(
|
|
56
|
+
it('fires timeout fallback when no event fires', () => {
|
|
57
57
|
const onEnd = vi.fn()
|
|
58
58
|
const ref = createMockRef()
|
|
59
59
|
const active = signal(true)
|
|
@@ -67,7 +67,7 @@ describe("useAnimationEnd", () => {
|
|
|
67
67
|
expect(onEnd).toHaveBeenCalledTimes(1)
|
|
68
68
|
})
|
|
69
69
|
|
|
70
|
-
it(
|
|
70
|
+
it('uses default timeout of 5000ms', () => {
|
|
71
71
|
const onEnd = vi.fn()
|
|
72
72
|
const ref = createMockRef()
|
|
73
73
|
const active = signal(true)
|
|
@@ -81,25 +81,25 @@ describe("useAnimationEnd", () => {
|
|
|
81
81
|
expect(onEnd).toHaveBeenCalledTimes(1)
|
|
82
82
|
})
|
|
83
83
|
|
|
84
|
-
it(
|
|
84
|
+
it('only fires onEnd once even if multiple events fire', () => {
|
|
85
85
|
const onEnd = vi.fn()
|
|
86
86
|
const ref = createMockRef()
|
|
87
87
|
const active = signal(true)
|
|
88
88
|
|
|
89
89
|
useAnimationEnd({ ref, onEnd, active })
|
|
90
90
|
|
|
91
|
-
const event1 = new Event(
|
|
92
|
-
Object.defineProperty(event1,
|
|
91
|
+
const event1 = new Event('transitionend', { bubbles: true })
|
|
92
|
+
Object.defineProperty(event1, 'target', { value: ref.current })
|
|
93
93
|
ref.current.dispatchEvent(event1)
|
|
94
94
|
|
|
95
|
-
const event2 = new Event(
|
|
96
|
-
Object.defineProperty(event2,
|
|
95
|
+
const event2 = new Event('animationend', { bubbles: true })
|
|
96
|
+
Object.defineProperty(event2, 'target', { value: ref.current })
|
|
97
97
|
ref.current.dispatchEvent(event2)
|
|
98
98
|
|
|
99
99
|
expect(onEnd).toHaveBeenCalledTimes(1)
|
|
100
100
|
})
|
|
101
101
|
|
|
102
|
-
it(
|
|
102
|
+
it('does not fire when active is false', () => {
|
|
103
103
|
const onEnd = vi.fn()
|
|
104
104
|
const ref = createMockRef()
|
|
105
105
|
const active = signal(false)
|
|
@@ -111,7 +111,7 @@ describe("useAnimationEnd", () => {
|
|
|
111
111
|
expect(onEnd).not.toHaveBeenCalled()
|
|
112
112
|
})
|
|
113
113
|
|
|
114
|
-
it(
|
|
114
|
+
it('does not fire when active=true but ref.current is null', () => {
|
|
115
115
|
const onEnd = vi.fn()
|
|
116
116
|
const ref = { current: null } as { current: HTMLElement | null }
|
|
117
117
|
const active = signal(true)
|
|
@@ -124,7 +124,7 @@ describe("useAnimationEnd", () => {
|
|
|
124
124
|
expect(onEnd).not.toHaveBeenCalled()
|
|
125
125
|
})
|
|
126
126
|
|
|
127
|
-
it(
|
|
127
|
+
it('does not call onEnd twice when transitionend fires and then timeout fires', () => {
|
|
128
128
|
const onEnd = vi.fn()
|
|
129
129
|
const ref = createMockRef()
|
|
130
130
|
const active = signal(true)
|
|
@@ -132,8 +132,8 @@ describe("useAnimationEnd", () => {
|
|
|
132
132
|
useAnimationEnd({ ref, onEnd, active, timeout: 1000 })
|
|
133
133
|
|
|
134
134
|
// First: transitionend fires — calls done()
|
|
135
|
-
const event = new Event(
|
|
136
|
-
Object.defineProperty(event,
|
|
135
|
+
const event = new Event('transitionend', { bubbles: true })
|
|
136
|
+
Object.defineProperty(event, 'target', { value: ref.current })
|
|
137
137
|
ref.current.dispatchEvent(event)
|
|
138
138
|
|
|
139
139
|
expect(onEnd).toHaveBeenCalledTimes(1)
|
|
@@ -144,7 +144,7 @@ describe("useAnimationEnd", () => {
|
|
|
144
144
|
expect(onEnd).toHaveBeenCalledTimes(1)
|
|
145
145
|
})
|
|
146
146
|
|
|
147
|
-
it(
|
|
147
|
+
it('does not call onEnd twice when timeout fires and then transitionend fires', () => {
|
|
148
148
|
const onEnd = vi.fn()
|
|
149
149
|
const ref = createMockRef()
|
|
150
150
|
const active = signal(true)
|
|
@@ -157,14 +157,14 @@ describe("useAnimationEnd", () => {
|
|
|
157
157
|
expect(onEnd).toHaveBeenCalledTimes(1)
|
|
158
158
|
|
|
159
159
|
// Second: transitionend fires — should be no-op via called guard
|
|
160
|
-
const event = new Event(
|
|
161
|
-
Object.defineProperty(event,
|
|
160
|
+
const event = new Event('transitionend', { bubbles: true })
|
|
161
|
+
Object.defineProperty(event, 'target', { value: ref.current })
|
|
162
162
|
ref.current.dispatchEvent(event)
|
|
163
163
|
|
|
164
164
|
expect(onEnd).toHaveBeenCalledTimes(1)
|
|
165
165
|
})
|
|
166
166
|
|
|
167
|
-
it(
|
|
167
|
+
it('resets called when active transitions from true to false', () => {
|
|
168
168
|
const onEnd = vi.fn()
|
|
169
169
|
const ref = createMockRef()
|
|
170
170
|
const active = signal(true)
|
|
@@ -172,8 +172,8 @@ describe("useAnimationEnd", () => {
|
|
|
172
172
|
useAnimationEnd({ ref, onEnd, active, timeout: 1000 })
|
|
173
173
|
|
|
174
174
|
// Fire to set called = true
|
|
175
|
-
const event = new Event(
|
|
176
|
-
Object.defineProperty(event,
|
|
175
|
+
const event = new Event('transitionend', { bubbles: true })
|
|
176
|
+
Object.defineProperty(event, 'target', { value: ref.current })
|
|
177
177
|
ref.current.dispatchEvent(event)
|
|
178
178
|
|
|
179
179
|
expect(onEnd).toHaveBeenCalledTimes(1)
|
|
@@ -185,8 +185,8 @@ describe("useAnimationEnd", () => {
|
|
|
185
185
|
active.set(true)
|
|
186
186
|
|
|
187
187
|
// Should be able to fire again
|
|
188
|
-
const event2 = new Event(
|
|
189
|
-
Object.defineProperty(event2,
|
|
188
|
+
const event2 = new Event('transitionend', { bubbles: true })
|
|
189
|
+
Object.defineProperty(event2, 'target', { value: ref.current })
|
|
190
190
|
ref.current.dispatchEvent(event2)
|
|
191
191
|
|
|
192
192
|
expect(onEnd).toHaveBeenCalledTimes(2)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
let mountCallbacks: Array<() => undefined | (() => void)> = []
|
|
3
3
|
let unmountCallbacks: Array<() => void> = []
|
|
4
4
|
|
|
5
|
-
vi.mock(
|
|
5
|
+
vi.mock('@pyreon/core', () => ({
|
|
6
6
|
onMount: vi.fn((cb: () => undefined | (() => void)) => {
|
|
7
7
|
mountCallbacks.push(cb)
|
|
8
8
|
}),
|
|
@@ -11,7 +11,7 @@ vi.mock("@pyreon/core", () => ({
|
|
|
11
11
|
}),
|
|
12
12
|
}))
|
|
13
13
|
|
|
14
|
-
vi.mock(
|
|
14
|
+
vi.mock('@pyreon/reactivity', () => {
|
|
15
15
|
const signal = <T>(initial: T) => {
|
|
16
16
|
let value = initial
|
|
17
17
|
const s = (() => value) as (() => T) & {
|
|
@@ -39,20 +39,20 @@ vi.mock("@pyreon/reactivity", () => {
|
|
|
39
39
|
return { signal }
|
|
40
40
|
})
|
|
41
41
|
|
|
42
|
-
import { useReducedMotion } from
|
|
42
|
+
import { useReducedMotion } from '../useReducedMotion'
|
|
43
43
|
|
|
44
|
-
describe(
|
|
44
|
+
describe('useReducedMotion', () => {
|
|
45
45
|
let changeHandlers: Array<(e: any) => void>
|
|
46
46
|
let removedHandlers: Array<(e: any) => void>
|
|
47
47
|
|
|
48
48
|
const createMockMQL = (matches: boolean) => ({
|
|
49
49
|
matches,
|
|
50
|
-
media:
|
|
50
|
+
media: '(prefers-reduced-motion: reduce)',
|
|
51
51
|
addEventListener: vi.fn((event: string, handler: (e: any) => void) => {
|
|
52
|
-
if (event ===
|
|
52
|
+
if (event === 'change') changeHandlers.push(handler)
|
|
53
53
|
}),
|
|
54
54
|
removeEventListener: vi.fn((event: string, handler: (e: any) => void) => {
|
|
55
|
-
if (event ===
|
|
55
|
+
if (event === 'change') removedHandlers.push(handler)
|
|
56
56
|
}),
|
|
57
57
|
})
|
|
58
58
|
|
|
@@ -67,18 +67,18 @@ describe("useReducedMotion", () => {
|
|
|
67
67
|
vi.restoreAllMocks()
|
|
68
68
|
})
|
|
69
69
|
|
|
70
|
-
it(
|
|
70
|
+
it('returns false initially', () => {
|
|
71
71
|
vi.stubGlobal(
|
|
72
|
-
|
|
72
|
+
'matchMedia',
|
|
73
73
|
vi.fn(() => createMockMQL(false)),
|
|
74
74
|
)
|
|
75
75
|
const result = useReducedMotion()
|
|
76
76
|
expect(result()).toBe(false)
|
|
77
77
|
})
|
|
78
78
|
|
|
79
|
-
it(
|
|
79
|
+
it('reads matchMedia state on mount (true)', () => {
|
|
80
80
|
vi.stubGlobal(
|
|
81
|
-
|
|
81
|
+
'matchMedia',
|
|
82
82
|
vi.fn(() => createMockMQL(true)),
|
|
83
83
|
)
|
|
84
84
|
const result = useReducedMotion()
|
|
@@ -89,9 +89,9 @@ describe("useReducedMotion", () => {
|
|
|
89
89
|
expect(result()).toBe(true)
|
|
90
90
|
})
|
|
91
91
|
|
|
92
|
-
it(
|
|
92
|
+
it('reads matchMedia state on mount (false)', () => {
|
|
93
93
|
vi.stubGlobal(
|
|
94
|
-
|
|
94
|
+
'matchMedia',
|
|
95
95
|
vi.fn(() => createMockMQL(false)),
|
|
96
96
|
)
|
|
97
97
|
const result = useReducedMotion()
|
|
@@ -101,9 +101,9 @@ describe("useReducedMotion", () => {
|
|
|
101
101
|
expect(result()).toBe(false)
|
|
102
102
|
})
|
|
103
103
|
|
|
104
|
-
it(
|
|
104
|
+
it('reacts to change events', () => {
|
|
105
105
|
vi.stubGlobal(
|
|
106
|
-
|
|
106
|
+
'matchMedia',
|
|
107
107
|
vi.fn(() => createMockMQL(false)),
|
|
108
108
|
)
|
|
109
109
|
const result = useReducedMotion()
|
|
@@ -119,19 +119,19 @@ describe("useReducedMotion", () => {
|
|
|
119
119
|
expect(result()).toBe(true)
|
|
120
120
|
})
|
|
121
121
|
|
|
122
|
-
it(
|
|
122
|
+
it('queries the correct media string', () => {
|
|
123
123
|
const mockMatchMedia = vi.fn(() => createMockMQL(false))
|
|
124
|
-
vi.stubGlobal(
|
|
124
|
+
vi.stubGlobal('matchMedia', mockMatchMedia)
|
|
125
125
|
|
|
126
126
|
useReducedMotion()
|
|
127
127
|
for (const cb of mountCallbacks) cb()
|
|
128
128
|
|
|
129
|
-
expect(mockMatchMedia).toHaveBeenCalledWith(
|
|
129
|
+
expect(mockMatchMedia).toHaveBeenCalledWith('(prefers-reduced-motion: reduce)')
|
|
130
130
|
})
|
|
131
131
|
|
|
132
|
-
it(
|
|
132
|
+
it('registers a change listener on mount', () => {
|
|
133
133
|
vi.stubGlobal(
|
|
134
|
-
|
|
134
|
+
'matchMedia',
|
|
135
135
|
vi.fn(() => createMockMQL(false)),
|
|
136
136
|
)
|
|
137
137
|
useReducedMotion()
|
|
@@ -141,9 +141,9 @@ describe("useReducedMotion", () => {
|
|
|
141
141
|
expect(changeHandlers).toHaveLength(1)
|
|
142
142
|
})
|
|
143
143
|
|
|
144
|
-
it(
|
|
144
|
+
it('removes the change listener on unmount', () => {
|
|
145
145
|
vi.stubGlobal(
|
|
146
|
-
|
|
146
|
+
'matchMedia',
|
|
147
147
|
vi.fn(() => createMockMQL(false)),
|
|
148
148
|
)
|
|
149
149
|
useReducedMotion()
|
|
@@ -1,132 +1,132 @@
|
|
|
1
|
-
import { signal } from
|
|
2
|
-
import useTransitionState from
|
|
1
|
+
import { signal } from '@pyreon/reactivity'
|
|
2
|
+
import useTransitionState from '../useTransitionState'
|
|
3
3
|
|
|
4
|
-
describe(
|
|
5
|
-
it(
|
|
4
|
+
describe('useTransitionState', () => {
|
|
5
|
+
it('initial state is hidden when show=false', () => {
|
|
6
6
|
const show = signal(false)
|
|
7
7
|
const result = useTransitionState({ show })
|
|
8
|
-
expect(result.stage()).toBe(
|
|
8
|
+
expect(result.stage()).toBe('hidden')
|
|
9
9
|
expect(result.shouldMount()).toBe(false)
|
|
10
10
|
})
|
|
11
11
|
|
|
12
|
-
it(
|
|
12
|
+
it('initial state is entered when show=true and appear=false', () => {
|
|
13
13
|
const show = signal(true)
|
|
14
14
|
const result = useTransitionState({ show })
|
|
15
|
-
expect(result.stage()).toBe(
|
|
15
|
+
expect(result.stage()).toBe('entered')
|
|
16
16
|
expect(result.shouldMount()).toBe(true)
|
|
17
17
|
})
|
|
18
18
|
|
|
19
|
-
it(
|
|
19
|
+
it('transitions to entering when show changes false->true', () => {
|
|
20
20
|
const show = signal(false)
|
|
21
21
|
const result = useTransitionState({ show })
|
|
22
22
|
|
|
23
|
-
expect(result.stage()).toBe(
|
|
23
|
+
expect(result.stage()).toBe('hidden')
|
|
24
24
|
|
|
25
25
|
show.set(true)
|
|
26
|
-
expect(result.stage()).toBe(
|
|
26
|
+
expect(result.stage()).toBe('entering')
|
|
27
27
|
expect(result.shouldMount()).toBe(true)
|
|
28
28
|
})
|
|
29
29
|
|
|
30
|
-
it(
|
|
30
|
+
it('complete() transitions entering->entered', () => {
|
|
31
31
|
const show = signal(false)
|
|
32
32
|
const result = useTransitionState({ show })
|
|
33
33
|
|
|
34
34
|
show.set(true)
|
|
35
|
-
expect(result.stage()).toBe(
|
|
35
|
+
expect(result.stage()).toBe('entering')
|
|
36
36
|
|
|
37
37
|
result.complete()
|
|
38
|
-
expect(result.stage()).toBe(
|
|
38
|
+
expect(result.stage()).toBe('entered')
|
|
39
39
|
})
|
|
40
40
|
|
|
41
|
-
it(
|
|
41
|
+
it('transitions to leaving when show changes true->false', () => {
|
|
42
42
|
const show = signal(true)
|
|
43
43
|
const result = useTransitionState({ show })
|
|
44
44
|
|
|
45
|
-
expect(result.stage()).toBe(
|
|
45
|
+
expect(result.stage()).toBe('entered')
|
|
46
46
|
|
|
47
47
|
show.set(false)
|
|
48
|
-
expect(result.stage()).toBe(
|
|
48
|
+
expect(result.stage()).toBe('leaving')
|
|
49
49
|
expect(result.shouldMount()).toBe(true)
|
|
50
50
|
})
|
|
51
51
|
|
|
52
|
-
it(
|
|
52
|
+
it('complete() transitions leaving->hidden', () => {
|
|
53
53
|
const show = signal(true)
|
|
54
54
|
const result = useTransitionState({ show })
|
|
55
55
|
|
|
56
56
|
show.set(false)
|
|
57
|
-
expect(result.stage()).toBe(
|
|
57
|
+
expect(result.stage()).toBe('leaving')
|
|
58
58
|
|
|
59
59
|
result.complete()
|
|
60
|
-
expect(result.stage()).toBe(
|
|
60
|
+
expect(result.stage()).toBe('hidden')
|
|
61
61
|
expect(result.shouldMount()).toBe(false)
|
|
62
62
|
})
|
|
63
63
|
|
|
64
|
-
it(
|
|
64
|
+
it('appear=true enters after ref is connected', () => {
|
|
65
65
|
const show = signal(true)
|
|
66
66
|
const result = useTransitionState({ show, appear: true })
|
|
67
67
|
// Before ref is wired, element should be mounted but stage is 'entered'
|
|
68
|
-
expect(result.stage()).toBe(
|
|
68
|
+
expect(result.stage()).toBe('entered')
|
|
69
69
|
expect(result.shouldMount()).toBe(true)
|
|
70
70
|
|
|
71
71
|
// Simulate ref connection (as the renderer would do)
|
|
72
|
-
const el = document.createElement(
|
|
73
|
-
if (typeof result.ref ===
|
|
72
|
+
const el = document.createElement('div')
|
|
73
|
+
if (typeof result.ref === 'function') {
|
|
74
74
|
result.ref(el)
|
|
75
75
|
}
|
|
76
76
|
// Now the appear animation should trigger
|
|
77
|
-
expect(result.stage()).toBe(
|
|
77
|
+
expect(result.stage()).toBe('entering')
|
|
78
78
|
})
|
|
79
79
|
|
|
80
|
-
it(
|
|
80
|
+
it('complete() is a no-op in entered state', () => {
|
|
81
81
|
const show = signal(true)
|
|
82
82
|
const result = useTransitionState({ show })
|
|
83
83
|
|
|
84
|
-
expect(result.stage()).toBe(
|
|
84
|
+
expect(result.stage()).toBe('entered')
|
|
85
85
|
|
|
86
86
|
result.complete()
|
|
87
|
-
expect(result.stage()).toBe(
|
|
87
|
+
expect(result.stage()).toBe('entered')
|
|
88
88
|
})
|
|
89
89
|
|
|
90
|
-
it(
|
|
90
|
+
it('complete() is a no-op in hidden state', () => {
|
|
91
91
|
const show = signal(false)
|
|
92
92
|
const result = useTransitionState({ show })
|
|
93
93
|
|
|
94
|
-
expect(result.stage()).toBe(
|
|
94
|
+
expect(result.stage()).toBe('hidden')
|
|
95
95
|
|
|
96
96
|
result.complete()
|
|
97
|
-
expect(result.stage()).toBe(
|
|
97
|
+
expect(result.stage()).toBe('hidden')
|
|
98
98
|
})
|
|
99
99
|
|
|
100
|
-
it(
|
|
100
|
+
it('handles rapid toggling true->false->true', () => {
|
|
101
101
|
const show = signal(true)
|
|
102
102
|
const result = useTransitionState({ show })
|
|
103
103
|
|
|
104
104
|
// Start leave
|
|
105
105
|
show.set(false)
|
|
106
|
-
expect(result.stage()).toBe(
|
|
106
|
+
expect(result.stage()).toBe('leaving')
|
|
107
107
|
|
|
108
108
|
// Interrupt with enter before leave completes
|
|
109
109
|
show.set(true)
|
|
110
|
-
expect(result.stage()).toBe(
|
|
110
|
+
expect(result.stage()).toBe('entering')
|
|
111
111
|
})
|
|
112
112
|
|
|
113
|
-
it(
|
|
113
|
+
it('handles rapid toggling false->true->false (entering to leaving)', () => {
|
|
114
114
|
const show = signal(false)
|
|
115
115
|
const result = useTransitionState({ show })
|
|
116
116
|
|
|
117
117
|
// Start enter
|
|
118
118
|
show.set(true)
|
|
119
|
-
expect(result.stage()).toBe(
|
|
119
|
+
expect(result.stage()).toBe('entering')
|
|
120
120
|
|
|
121
121
|
// Interrupt with leave before enter completes
|
|
122
122
|
show.set(false)
|
|
123
|
-
expect(result.stage()).toBe(
|
|
123
|
+
expect(result.stage()).toBe('leaving')
|
|
124
124
|
})
|
|
125
125
|
|
|
126
|
-
it(
|
|
126
|
+
it('provides a ref (callback or object)', () => {
|
|
127
127
|
const show = signal(false)
|
|
128
128
|
const result = useTransitionState({ show })
|
|
129
129
|
expect(result.ref).toBeDefined()
|
|
130
|
-
expect(typeof result.ref ===
|
|
130
|
+
expect(typeof result.ref === 'function' || 'current' in result.ref).toBe(true)
|
|
131
131
|
})
|
|
132
132
|
})
|