@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,116 +1,116 @@
|
|
|
1
|
-
import { describe, expect, it } from
|
|
2
|
-
import type { CSSProperties } from
|
|
3
|
-
import { addClasses, mergeClassNames, mergeStyles, nextFrame, removeClasses } from
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import type { CSSProperties } from '../types'
|
|
3
|
+
import { addClasses, mergeClassNames, mergeStyles, nextFrame, removeClasses } from '../utils'
|
|
4
4
|
|
|
5
|
-
describe(
|
|
6
|
-
it(
|
|
7
|
-
expect(mergeClassNames(
|
|
5
|
+
describe('mergeClassNames', () => {
|
|
6
|
+
it('merges two class strings', () => {
|
|
7
|
+
expect(mergeClassNames('a', 'b')).toBe('a b')
|
|
8
8
|
})
|
|
9
9
|
|
|
10
|
-
it(
|
|
11
|
-
expect(mergeClassNames(
|
|
10
|
+
it('returns existing when additional is undefined', () => {
|
|
11
|
+
expect(mergeClassNames('a', undefined)).toBe('a')
|
|
12
12
|
})
|
|
13
13
|
|
|
14
|
-
it(
|
|
15
|
-
expect(mergeClassNames(undefined,
|
|
14
|
+
it('returns additional when existing is undefined', () => {
|
|
15
|
+
expect(mergeClassNames(undefined, 'b')).toBe('b')
|
|
16
16
|
})
|
|
17
17
|
|
|
18
|
-
it(
|
|
18
|
+
it('returns undefined when both are undefined', () => {
|
|
19
19
|
expect(mergeClassNames(undefined, undefined)).toBeUndefined()
|
|
20
20
|
})
|
|
21
21
|
|
|
22
|
-
it(
|
|
23
|
-
expect(mergeClassNames(
|
|
22
|
+
it('returns undefined when both are empty strings', () => {
|
|
23
|
+
expect(mergeClassNames('', '')).toBeUndefined()
|
|
24
24
|
})
|
|
25
25
|
|
|
26
|
-
it(
|
|
27
|
-
expect(mergeClassNames(
|
|
26
|
+
it('filters out empty strings', () => {
|
|
27
|
+
expect(mergeClassNames('a', '')).toBe('a')
|
|
28
28
|
})
|
|
29
29
|
})
|
|
30
30
|
|
|
31
|
-
describe(
|
|
32
|
-
it(
|
|
33
|
-
const a = { color:
|
|
34
|
-
const b = { color:
|
|
35
|
-
expect(mergeStyles(a, b)).toEqual({ color:
|
|
31
|
+
describe('mergeStyles', () => {
|
|
32
|
+
it('merges two style objects with b taking precedence', () => {
|
|
33
|
+
const a = { color: 'red', fontSize: '12px' } as CSSProperties
|
|
34
|
+
const b = { color: 'blue' } as CSSProperties
|
|
35
|
+
expect(mergeStyles(a, b)).toEqual({ color: 'blue', fontSize: '12px' })
|
|
36
36
|
})
|
|
37
37
|
|
|
38
|
-
it(
|
|
38
|
+
it('returns undefined when both are undefined', () => {
|
|
39
39
|
expect(mergeStyles(undefined, undefined)).toBeUndefined()
|
|
40
40
|
})
|
|
41
41
|
|
|
42
|
-
it(
|
|
43
|
-
const b = { color:
|
|
42
|
+
it('returns b when a is undefined', () => {
|
|
43
|
+
const b = { color: 'blue' } as CSSProperties
|
|
44
44
|
expect(mergeStyles(undefined, b)).toBe(b)
|
|
45
45
|
})
|
|
46
46
|
|
|
47
|
-
it(
|
|
48
|
-
const a = { color:
|
|
47
|
+
it('returns a when b is undefined', () => {
|
|
48
|
+
const a = { color: 'red' } as CSSProperties
|
|
49
49
|
expect(mergeStyles(a, undefined)).toBe(a)
|
|
50
50
|
})
|
|
51
51
|
})
|
|
52
52
|
|
|
53
|
-
describe(
|
|
54
|
-
it(
|
|
55
|
-
const el = document.createElement(
|
|
56
|
-
addClasses(el,
|
|
57
|
-
expect(el.classList.contains(
|
|
58
|
-
expect(el.classList.contains(
|
|
53
|
+
describe('addClasses', () => {
|
|
54
|
+
it('adds space-separated classes to an element', () => {
|
|
55
|
+
const el = document.createElement('div')
|
|
56
|
+
addClasses(el, 'foo bar')
|
|
57
|
+
expect(el.classList.contains('foo')).toBe(true)
|
|
58
|
+
expect(el.classList.contains('bar')).toBe(true)
|
|
59
59
|
})
|
|
60
60
|
|
|
61
|
-
it(
|
|
62
|
-
const el = document.createElement(
|
|
61
|
+
it('does nothing when classes is undefined', () => {
|
|
62
|
+
const el = document.createElement('div')
|
|
63
63
|
addClasses(el, undefined)
|
|
64
64
|
expect(el.classList.length).toBe(0)
|
|
65
65
|
})
|
|
66
66
|
|
|
67
|
-
it(
|
|
68
|
-
const el = document.createElement(
|
|
69
|
-
addClasses(el,
|
|
67
|
+
it('does nothing when classes is empty string', () => {
|
|
68
|
+
const el = document.createElement('div')
|
|
69
|
+
addClasses(el, '')
|
|
70
70
|
expect(el.classList.length).toBe(0)
|
|
71
71
|
})
|
|
72
72
|
|
|
73
|
-
it(
|
|
74
|
-
const el = document.createElement(
|
|
75
|
-
addClasses(el,
|
|
73
|
+
it('does nothing when classes is whitespace-only', () => {
|
|
74
|
+
const el = document.createElement('div')
|
|
75
|
+
addClasses(el, ' ')
|
|
76
76
|
expect(el.classList.length).toBe(0)
|
|
77
77
|
})
|
|
78
78
|
})
|
|
79
79
|
|
|
80
|
-
describe(
|
|
81
|
-
it(
|
|
82
|
-
const el = document.createElement(
|
|
83
|
-
el.classList.add(
|
|
84
|
-
removeClasses(el,
|
|
85
|
-
expect(el.classList.contains(
|
|
86
|
-
expect(el.classList.contains(
|
|
87
|
-
expect(el.classList.contains(
|
|
80
|
+
describe('removeClasses', () => {
|
|
81
|
+
it('removes space-separated classes from an element', () => {
|
|
82
|
+
const el = document.createElement('div')
|
|
83
|
+
el.classList.add('foo', 'bar', 'baz')
|
|
84
|
+
removeClasses(el, 'foo bar')
|
|
85
|
+
expect(el.classList.contains('foo')).toBe(false)
|
|
86
|
+
expect(el.classList.contains('bar')).toBe(false)
|
|
87
|
+
expect(el.classList.contains('baz')).toBe(true)
|
|
88
88
|
})
|
|
89
89
|
|
|
90
|
-
it(
|
|
91
|
-
const el = document.createElement(
|
|
92
|
-
el.classList.add(
|
|
90
|
+
it('does nothing when classes is undefined', () => {
|
|
91
|
+
const el = document.createElement('div')
|
|
92
|
+
el.classList.add('foo')
|
|
93
93
|
removeClasses(el, undefined)
|
|
94
|
-
expect(el.classList.contains(
|
|
94
|
+
expect(el.classList.contains('foo')).toBe(true)
|
|
95
95
|
})
|
|
96
96
|
|
|
97
|
-
it(
|
|
98
|
-
const el = document.createElement(
|
|
99
|
-
el.classList.add(
|
|
100
|
-
removeClasses(el,
|
|
101
|
-
expect(el.classList.contains(
|
|
97
|
+
it('does nothing when classes is empty string', () => {
|
|
98
|
+
const el = document.createElement('div')
|
|
99
|
+
el.classList.add('foo')
|
|
100
|
+
removeClasses(el, '')
|
|
101
|
+
expect(el.classList.contains('foo')).toBe(true)
|
|
102
102
|
})
|
|
103
103
|
|
|
104
|
-
it(
|
|
105
|
-
const el = document.createElement(
|
|
106
|
-
el.classList.add(
|
|
107
|
-
removeClasses(el,
|
|
108
|
-
expect(el.classList.contains(
|
|
104
|
+
it('does nothing when classes is whitespace-only', () => {
|
|
105
|
+
const el = document.createElement('div')
|
|
106
|
+
el.classList.add('foo')
|
|
107
|
+
removeClasses(el, ' ')
|
|
108
|
+
expect(el.classList.contains('foo')).toBe(true)
|
|
109
109
|
})
|
|
110
110
|
})
|
|
111
111
|
|
|
112
|
-
describe(
|
|
113
|
-
it(
|
|
112
|
+
describe('nextFrame', () => {
|
|
113
|
+
it('calls callback after double rAF', () => {
|
|
114
114
|
const callbacks: (() => void)[] = []
|
|
115
115
|
const originalRaf = globalThis.requestAnimationFrame
|
|
116
116
|
globalThis.requestAnimationFrame = ((cb: () => void) => {
|
package/src/index.ts
CHANGED
|
@@ -1,23 +1,15 @@
|
|
|
1
|
-
export { default as kinetic } from
|
|
2
|
-
export type { KineticComponent } from
|
|
3
|
-
export type { Preset } from
|
|
4
|
-
export {
|
|
5
|
-
fade,
|
|
6
|
-
presets,
|
|
7
|
-
scaleIn,
|
|
8
|
-
slideDown,
|
|
9
|
-
slideLeft,
|
|
10
|
-
slideRight,
|
|
11
|
-
slideUp,
|
|
12
|
-
} from "./presets"
|
|
1
|
+
export { default as kinetic } from './kinetic'
|
|
2
|
+
export type { KineticComponent } from './kinetic/types'
|
|
3
|
+
export type { Preset } from './presets'
|
|
4
|
+
export { fade, presets, scaleIn, slideDown, slideLeft, slideRight, slideUp } from './presets'
|
|
13
5
|
export type {
|
|
14
6
|
ClassTransitionProps,
|
|
15
7
|
StyleTransitionProps,
|
|
16
8
|
TransitionCallbacks,
|
|
17
9
|
TransitionStage,
|
|
18
10
|
TransitionStateResult,
|
|
19
|
-
} from
|
|
20
|
-
export type { UseAnimationEnd } from
|
|
21
|
-
export { default as useAnimationEnd } from
|
|
22
|
-
export type { UseTransitionState } from
|
|
23
|
-
export { default as useTransitionState } from
|
|
11
|
+
} from './types'
|
|
12
|
+
export type { UseAnimationEnd } from './useAnimationEnd'
|
|
13
|
+
export { default as useAnimationEnd } from './useAnimationEnd'
|
|
14
|
+
export type { UseTransitionState } from './useTransitionState'
|
|
15
|
+
export { default as useTransitionState } from './useTransitionState'
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type { VNode } from
|
|
2
|
-
import { createRef, h, Show } from
|
|
3
|
-
import { runUntracked, signal, watch } from
|
|
4
|
-
import type { CSSProperties, TransitionCallbacks, TransitionStage } from
|
|
5
|
-
import useAnimationEnd from
|
|
6
|
-
import { useReducedMotion } from
|
|
7
|
-
import type { KineticConfig } from
|
|
1
|
+
import type { VNode } from '@pyreon/core'
|
|
2
|
+
import { createRef, h, Show } from '@pyreon/core'
|
|
3
|
+
import { runUntracked, signal, watch } from '@pyreon/reactivity'
|
|
4
|
+
import type { CSSProperties, TransitionCallbacks, TransitionStage } from '../types'
|
|
5
|
+
import useAnimationEnd from '../useAnimationEnd'
|
|
6
|
+
import { useReducedMotion } from '../useReducedMotion'
|
|
7
|
+
import type { KineticConfig } from './types'
|
|
8
8
|
|
|
9
9
|
type CollapseRendererProps = {
|
|
10
10
|
config: KineticConfig
|
|
@@ -38,11 +38,11 @@ const CollapseRenderer = ({
|
|
|
38
38
|
|
|
39
39
|
const effectiveAppear = appear ?? config.appear ?? false
|
|
40
40
|
const effectiveTimeout = timeout ?? config.timeout ?? 5000
|
|
41
|
-
const effectiveTransition = transition ?? config.transition ??
|
|
41
|
+
const effectiveTransition = transition ?? config.transition ?? 'height 300ms ease'
|
|
42
42
|
|
|
43
43
|
const initialShow = show()
|
|
44
44
|
const needsAppear = effectiveAppear && initialShow
|
|
45
|
-
const stage = signal<TransitionStage>(initialShow ?
|
|
45
|
+
const stage = signal<TransitionStage>(initialShow ? 'entered' : 'hidden')
|
|
46
46
|
let isInitialMount = true
|
|
47
47
|
let appearTriggered = false
|
|
48
48
|
|
|
@@ -50,7 +50,7 @@ const CollapseRenderer = ({
|
|
|
50
50
|
if (needsAppear) {
|
|
51
51
|
const orig = wrapperRef
|
|
52
52
|
const proxy = { current: null as HTMLElement | null }
|
|
53
|
-
Object.defineProperty(proxy,
|
|
53
|
+
Object.defineProperty(proxy, 'current', {
|
|
54
54
|
get() {
|
|
55
55
|
return orig.current
|
|
56
56
|
},
|
|
@@ -58,7 +58,7 @@ const CollapseRenderer = ({
|
|
|
58
58
|
orig.current = node
|
|
59
59
|
if (node && !appearTriggered) {
|
|
60
60
|
appearTriggered = true
|
|
61
|
-
queueMicrotask(() => stage.set(
|
|
61
|
+
queueMicrotask(() => stage.set('entering'))
|
|
62
62
|
}
|
|
63
63
|
},
|
|
64
64
|
})
|
|
@@ -76,10 +76,10 @@ const CollapseRenderer = ({
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
const currentStage = runUntracked(() => stage())
|
|
79
|
-
if (showVal && (currentStage ===
|
|
80
|
-
stage.set(
|
|
81
|
-
} else if (!showVal && (currentStage ===
|
|
82
|
-
stage.set(
|
|
79
|
+
if (showVal && (currentStage === 'hidden' || currentStage === 'leaving')) {
|
|
80
|
+
stage.set('entering')
|
|
81
|
+
} else if (!showVal && (currentStage === 'entered' || currentStage === 'entering')) {
|
|
82
|
+
stage.set('leaving')
|
|
83
83
|
}
|
|
84
84
|
},
|
|
85
85
|
{ immediate: true },
|
|
@@ -94,44 +94,44 @@ const CollapseRenderer = ({
|
|
|
94
94
|
if (!wrapper || !content) return
|
|
95
95
|
|
|
96
96
|
if (reducedMotion()) {
|
|
97
|
-
if (currentStage ===
|
|
97
|
+
if (currentStage === 'entering') {
|
|
98
98
|
callbacks.onEnter?.()
|
|
99
|
-
wrapper.style.height =
|
|
100
|
-
wrapper.style.overflow =
|
|
99
|
+
wrapper.style.height = 'auto'
|
|
100
|
+
wrapper.style.overflow = ''
|
|
101
101
|
callbacks.onAfterEnter?.()
|
|
102
|
-
stage.set(
|
|
103
|
-
} else if (currentStage ===
|
|
102
|
+
stage.set('entered')
|
|
103
|
+
} else if (currentStage === 'leaving') {
|
|
104
104
|
callbacks.onLeave?.()
|
|
105
|
-
wrapper.style.height =
|
|
106
|
-
wrapper.style.overflow =
|
|
105
|
+
wrapper.style.height = '0px'
|
|
106
|
+
wrapper.style.overflow = 'hidden'
|
|
107
107
|
callbacks.onAfterLeave?.()
|
|
108
|
-
stage.set(
|
|
108
|
+
stage.set('hidden')
|
|
109
109
|
}
|
|
110
110
|
return
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
if (currentStage ===
|
|
113
|
+
if (currentStage === 'entering') {
|
|
114
114
|
callbacks.onEnter?.()
|
|
115
115
|
const height = content.scrollHeight
|
|
116
|
-
wrapper.style.transition =
|
|
117
|
-
wrapper.style.height =
|
|
118
|
-
wrapper.style.overflow =
|
|
116
|
+
wrapper.style.transition = 'none'
|
|
117
|
+
wrapper.style.height = '0px'
|
|
118
|
+
wrapper.style.overflow = 'hidden'
|
|
119
119
|
// Force reflow
|
|
120
120
|
void wrapper.offsetHeight
|
|
121
121
|
wrapper.style.transition = effectiveTransition
|
|
122
122
|
wrapper.style.height = `${height}px`
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
if (currentStage ===
|
|
125
|
+
if (currentStage === 'leaving') {
|
|
126
126
|
callbacks.onLeave?.()
|
|
127
127
|
const height = content.scrollHeight
|
|
128
|
-
wrapper.style.transition =
|
|
128
|
+
wrapper.style.transition = 'none'
|
|
129
129
|
wrapper.style.height = `${height}px`
|
|
130
|
-
wrapper.style.overflow =
|
|
130
|
+
wrapper.style.overflow = 'hidden'
|
|
131
131
|
// Force reflow
|
|
132
132
|
void wrapper.offsetHeight
|
|
133
133
|
wrapper.style.transition = effectiveTransition
|
|
134
|
-
wrapper.style.height =
|
|
134
|
+
wrapper.style.height = '0px'
|
|
135
135
|
}
|
|
136
136
|
},
|
|
137
137
|
{ immediate: true },
|
|
@@ -139,31 +139,31 @@ const CollapseRenderer = ({
|
|
|
139
139
|
|
|
140
140
|
useAnimationEnd({
|
|
141
141
|
ref: wrapperRef,
|
|
142
|
-
active: () => (stage() ===
|
|
142
|
+
active: () => (stage() === 'entering' || stage() === 'leaving') && !reducedMotion(),
|
|
143
143
|
timeout: effectiveTimeout,
|
|
144
144
|
onEnd: () => {
|
|
145
145
|
const wrapper = wrapperRef.current
|
|
146
|
-
if (stage() ===
|
|
146
|
+
if (stage() === 'entering') {
|
|
147
147
|
if (wrapper) {
|
|
148
|
-
wrapper.style.height =
|
|
149
|
-
wrapper.style.overflow =
|
|
150
|
-
wrapper.style.transition =
|
|
148
|
+
wrapper.style.height = 'auto'
|
|
149
|
+
wrapper.style.overflow = ''
|
|
150
|
+
wrapper.style.transition = ''
|
|
151
151
|
}
|
|
152
152
|
callbacks.onAfterEnter?.()
|
|
153
|
-
stage.set(
|
|
154
|
-
} else if (stage() ===
|
|
153
|
+
stage.set('entered')
|
|
154
|
+
} else if (stage() === 'leaving') {
|
|
155
155
|
callbacks.onAfterLeave?.()
|
|
156
|
-
stage.set(
|
|
156
|
+
stage.set('hidden')
|
|
157
157
|
}
|
|
158
158
|
},
|
|
159
159
|
})
|
|
160
160
|
|
|
161
|
-
const shouldRender = () => stage() !==
|
|
161
|
+
const shouldRender = () => stage() !== 'hidden'
|
|
162
162
|
|
|
163
163
|
const wrapperStyle: CSSProperties = {
|
|
164
164
|
...((htmlProps.style as CSSProperties) ?? {}),
|
|
165
|
-
...(stage() !==
|
|
166
|
-
...(stage() ===
|
|
165
|
+
...(stage() !== 'entered' ? { overflow: 'hidden' } : {}),
|
|
166
|
+
...(stage() === 'hidden' ? { height: '0px' } : stage() === 'entered' ? { height: 'auto' } : {}),
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
return h(
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { VNode } from
|
|
2
|
-
import { h } from
|
|
3
|
-
import { signal } from
|
|
4
|
-
import type { TransitionCallbacks } from
|
|
5
|
-
import TransitionItem from
|
|
6
|
-
import type { KineticConfig } from
|
|
1
|
+
import type { VNode } from '@pyreon/core'
|
|
2
|
+
import { h } from '@pyreon/core'
|
|
3
|
+
import { signal } from '@pyreon/reactivity'
|
|
4
|
+
import type { TransitionCallbacks } from '../types'
|
|
5
|
+
import TransitionItem from './TransitionItem'
|
|
6
|
+
import type { KineticConfig } from './types'
|
|
7
7
|
|
|
8
8
|
type GroupRendererProps = {
|
|
9
9
|
config: KineticConfig
|
|
@@ -22,7 +22,7 @@ type GroupRendererProps = {
|
|
|
22
22
|
type KeyedChild = { key: string | number; element: VNode }
|
|
23
23
|
|
|
24
24
|
const isVNode = (child: unknown): child is VNode =>
|
|
25
|
-
child != null && typeof child ===
|
|
25
|
+
child != null && typeof child === 'object' && 'type' in (child as object)
|
|
26
26
|
|
|
27
27
|
const getKeyedChildren = (children: VNode[]): KeyedChild[] => {
|
|
28
28
|
const result: KeyedChild[] = []
|
|
@@ -62,7 +62,7 @@ const GroupRenderer = ({
|
|
|
62
62
|
const forceUpdate = signal(0)
|
|
63
63
|
|
|
64
64
|
// Normalize children to an accessor
|
|
65
|
-
const getChildren = typeof children ===
|
|
65
|
+
const getChildren = typeof children === 'function' ? (children as () => VNode[]) : () => children
|
|
66
66
|
|
|
67
67
|
// Track initial keys for appear animation logic
|
|
68
68
|
const initialKeyed = getKeyedChildren(getChildren())
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { VNode } from
|
|
2
|
-
import { h } from
|
|
3
|
-
import type { CSSProperties, TransitionCallbacks } from
|
|
4
|
-
import { cloneVNode } from
|
|
5
|
-
import TransitionItem from
|
|
6
|
-
import type { KineticConfig } from
|
|
1
|
+
import type { VNode } from '@pyreon/core'
|
|
2
|
+
import { h } from '@pyreon/core'
|
|
3
|
+
import type { CSSProperties, TransitionCallbacks } from '../types'
|
|
4
|
+
import { cloneVNode } from '../utils'
|
|
5
|
+
import TransitionItem from './TransitionItem'
|
|
6
|
+
import type { KineticConfig } from './types'
|
|
7
7
|
|
|
8
8
|
type StaggerRendererProps = {
|
|
9
9
|
config: KineticConfig
|
|
@@ -18,7 +18,7 @@ type StaggerRendererProps = {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
const isVNode = (child: unknown): child is VNode =>
|
|
21
|
-
child != null && typeof child ===
|
|
21
|
+
child != null && typeof child === 'object' && 'type' in (child as object)
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* Renders children with staggered enter/exit animation.
|
|
@@ -73,8 +73,8 @@ const StaggerRenderer = ({
|
|
|
73
73
|
{cloneVNode(child, {
|
|
74
74
|
style: {
|
|
75
75
|
...((child.props as Record<string, unknown>)?.style as CSSProperties | undefined),
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
'--stagger-index': staggerIndex,
|
|
77
|
+
'--stagger-interval': `${effectiveInterval}ms`,
|
|
78
78
|
transitionDelay: `${delay}ms`,
|
|
79
79
|
} as CSSProperties,
|
|
80
80
|
})}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type { VNode } from
|
|
2
|
-
import { createRef, Show } from
|
|
3
|
-
import { watch } from
|
|
4
|
-
import type { ClassTransitionProps, StyleTransitionProps, TransitionCallbacks } from
|
|
5
|
-
import useAnimationEnd from
|
|
6
|
-
import { useReducedMotion } from
|
|
7
|
-
import useTransitionState from
|
|
8
|
-
import { addClasses, cloneVNode, mergeRefs, mergeStyles, nextFrame, removeClasses } from
|
|
1
|
+
import type { VNode } from '@pyreon/core'
|
|
2
|
+
import { createRef, Show } from '@pyreon/core'
|
|
3
|
+
import { watch } from '@pyreon/reactivity'
|
|
4
|
+
import type { ClassTransitionProps, StyleTransitionProps, TransitionCallbacks } from '../types'
|
|
5
|
+
import useAnimationEnd from '../useAnimationEnd'
|
|
6
|
+
import { useReducedMotion } from '../useReducedMotion'
|
|
7
|
+
import useTransitionState from '../useTransitionState'
|
|
8
|
+
import { addClasses, cloneVNode, mergeRefs, mergeStyles, nextFrame, removeClasses } from '../utils'
|
|
9
9
|
|
|
10
10
|
type TransitionItemProps = ClassTransitionProps &
|
|
11
11
|
StyleTransitionProps &
|
|
@@ -52,11 +52,11 @@ const applyReducedMotion = (
|
|
|
52
52
|
callbacks: Partial<TransitionCallbacks>,
|
|
53
53
|
complete: () => void,
|
|
54
54
|
) => {
|
|
55
|
-
if (stage ===
|
|
55
|
+
if (stage === 'entering') {
|
|
56
56
|
callbacks.onEnter?.()
|
|
57
57
|
callbacks.onAfterEnter?.()
|
|
58
58
|
complete()
|
|
59
|
-
} else if (stage ===
|
|
59
|
+
} else if (stage === 'leaving') {
|
|
60
60
|
callbacks.onLeave?.()
|
|
61
61
|
callbacks.onAfterLeave?.()
|
|
62
62
|
complete()
|
|
@@ -128,12 +128,12 @@ const TransitionItem = ({
|
|
|
128
128
|
|
|
129
129
|
useAnimationEnd({
|
|
130
130
|
ref: elementRef,
|
|
131
|
-
active: () => (stage() ===
|
|
131
|
+
active: () => (stage() === 'entering' || stage() === 'leaving') && !reducedMotion(),
|
|
132
132
|
timeout,
|
|
133
133
|
onEnd: () => {
|
|
134
|
-
if (stage() ===
|
|
134
|
+
if (stage() === 'entering') {
|
|
135
135
|
callbacks.onAfterEnter?.()
|
|
136
|
-
} else if (stage() ===
|
|
136
|
+
} else if (stage() === 'leaving') {
|
|
137
137
|
callbacks.onAfterLeave?.()
|
|
138
138
|
}
|
|
139
139
|
complete()
|
|
@@ -151,21 +151,21 @@ const TransitionItem = ({
|
|
|
151
151
|
return
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
if (currentStage ===
|
|
154
|
+
if (currentStage === 'entering') {
|
|
155
155
|
callbacks.onEnter?.()
|
|
156
156
|
const frameId = applyEnter(el, transitionConfig)
|
|
157
157
|
return () => cancelAnimationFrame(frameId)
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
-
if (currentStage ===
|
|
160
|
+
if (currentStage === 'leaving') {
|
|
161
161
|
callbacks.onLeave?.()
|
|
162
162
|
const frameId = applyLeave(el, transitionConfig)
|
|
163
163
|
return () => cancelAnimationFrame(frameId)
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
-
if (currentStage ===
|
|
166
|
+
if (currentStage === 'entered') {
|
|
167
167
|
removeClasses(el, enter)
|
|
168
|
-
el.style.transition =
|
|
168
|
+
el.style.transition = ''
|
|
169
169
|
}
|
|
170
170
|
},
|
|
171
171
|
{ immediate: true },
|
|
@@ -183,7 +183,7 @@ const TransitionItem = ({
|
|
|
183
183
|
(children.props as Record<string, unknown>)?.style as
|
|
184
184
|
| Record<string, string | number | undefined>
|
|
185
185
|
| undefined,
|
|
186
|
-
{ display:
|
|
186
|
+
{ display: 'none' },
|
|
187
187
|
),
|
|
188
188
|
})
|
|
189
189
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import type { VNode } from
|
|
2
|
-
import { createRef, h, Show } from
|
|
3
|
-
import { watch } from
|
|
4
|
-
import type { CSSProperties, TransitionCallbacks } from
|
|
5
|
-
import useAnimationEnd from
|
|
6
|
-
import { useReducedMotion } from
|
|
7
|
-
import useTransitionState from
|
|
8
|
-
import { addClasses, mergeRefs, nextFrame, removeClasses } from
|
|
9
|
-
import type { KineticConfig } from
|
|
1
|
+
import type { VNode } from '@pyreon/core'
|
|
2
|
+
import { createRef, h, Show } from '@pyreon/core'
|
|
3
|
+
import { watch } from '@pyreon/reactivity'
|
|
4
|
+
import type { CSSProperties, TransitionCallbacks } from '../types'
|
|
5
|
+
import useAnimationEnd from '../useAnimationEnd'
|
|
6
|
+
import { useReducedMotion } from '../useReducedMotion'
|
|
7
|
+
import useTransitionState from '../useTransitionState'
|
|
8
|
+
import { addClasses, mergeRefs, nextFrame, removeClasses } from '../utils'
|
|
9
|
+
import type { KineticConfig } from './types'
|
|
10
10
|
|
|
11
11
|
type TransitionRendererProps = {
|
|
12
12
|
config: KineticConfig
|
|
@@ -53,11 +53,11 @@ const applyReducedMotion = (
|
|
|
53
53
|
cbs: Partial<TransitionCallbacks>,
|
|
54
54
|
complete: () => void,
|
|
55
55
|
) => {
|
|
56
|
-
if (stage ===
|
|
56
|
+
if (stage === 'entering') {
|
|
57
57
|
cbs.onEnter?.()
|
|
58
58
|
cbs.onAfterEnter?.()
|
|
59
59
|
complete()
|
|
60
|
-
} else if (stage ===
|
|
60
|
+
} else if (stage === 'leaving') {
|
|
61
61
|
cbs.onLeave?.()
|
|
62
62
|
cbs.onAfterLeave?.()
|
|
63
63
|
complete()
|
|
@@ -97,12 +97,12 @@ const TransitionRenderer = ({
|
|
|
97
97
|
|
|
98
98
|
useAnimationEnd({
|
|
99
99
|
ref: elementRef,
|
|
100
|
-
active: () => (stage() ===
|
|
100
|
+
active: () => (stage() === 'entering' || stage() === 'leaving') && !reducedMotion(),
|
|
101
101
|
timeout: effectiveTimeout,
|
|
102
102
|
onEnd: () => {
|
|
103
|
-
if (stage() ===
|
|
103
|
+
if (stage() === 'entering') {
|
|
104
104
|
callbacks.onAfterEnter?.()
|
|
105
|
-
} else if (stage() ===
|
|
105
|
+
} else if (stage() === 'leaving') {
|
|
106
106
|
callbacks.onAfterLeave?.()
|
|
107
107
|
}
|
|
108
108
|
complete()
|
|
@@ -120,21 +120,21 @@ const TransitionRenderer = ({
|
|
|
120
120
|
return
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
if (currentStage ===
|
|
123
|
+
if (currentStage === 'entering') {
|
|
124
124
|
callbacks.onEnter?.()
|
|
125
125
|
const frameId = applyEnter(el, config)
|
|
126
126
|
return () => cancelAnimationFrame(frameId)
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
if (currentStage ===
|
|
129
|
+
if (currentStage === 'leaving') {
|
|
130
130
|
callbacks.onLeave?.()
|
|
131
131
|
const frameId = applyLeave(el, config)
|
|
132
132
|
return () => cancelAnimationFrame(frameId)
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
-
if (currentStage ===
|
|
135
|
+
if (currentStage === 'entered') {
|
|
136
136
|
removeClasses(el, config.enter)
|
|
137
|
-
el.style.transition =
|
|
137
|
+
el.style.transition = ''
|
|
138
138
|
}
|
|
139
139
|
},
|
|
140
140
|
{ immediate: true },
|
|
@@ -153,7 +153,7 @@ const TransitionRenderer = ({
|
|
|
153
153
|
...htmlProps,
|
|
154
154
|
style: {
|
|
155
155
|
...((htmlProps.style as CSSProperties) ?? {}),
|
|
156
|
-
display:
|
|
156
|
+
display: 'none',
|
|
157
157
|
},
|
|
158
158
|
},
|
|
159
159
|
children,
|