@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
package/README.md
CHANGED
|
@@ -10,15 +10,16 @@ The result: GPU-composited 60/120 FPS animations with a 3.2KB footprint.
|
|
|
10
10
|
|
|
11
11
|
### How It Compares
|
|
12
12
|
|
|
13
|
-
| Library
|
|
14
|
-
|
|
|
15
|
-
| **@pyreon/kinetic**
|
|
16
|
-
| Motion (framer-motion) | ~34 KB
|
|
17
|
-
| @react-spring/web
|
|
18
|
-
| react-transition-group | ~5 KB
|
|
19
|
-
| AutoAnimate
|
|
13
|
+
| Library | Gzipped | Engine | Enter/Exit | Stagger | List Recon. | Collapse | Reduced Motion |
|
|
14
|
+
| ---------------------- | ---------- | ------------------- | ---------- | ------- | ----------- | -------- | -------------- |
|
|
15
|
+
| **@pyreon/kinetic** | **3.2 KB** | CSS transitions | Yes | Yes | Yes | Yes | Yes |
|
|
16
|
+
| Motion (framer-motion) | ~34 KB | JS (rAF + WAAPI) | Yes | Yes | Yes | Quirky | Yes |
|
|
17
|
+
| @react-spring/web | ~16-24 KB | JS (spring physics) | Yes | Partial | Yes | Manual | Yes |
|
|
18
|
+
| react-transition-group | ~5 KB | CSS classes | Yes | No | Yes | No | No |
|
|
19
|
+
| AutoAnimate | ~2.5 KB | JS (FLIP) | Yes | No | Yes | No | Yes |
|
|
20
20
|
|
|
21
21
|
**Key advantages:**
|
|
22
|
+
|
|
22
23
|
- **10x smaller than Motion** for CSS-transition use cases
|
|
23
24
|
- **CSS-first**: `transform`/`opacity` run on GPU compositor thread, not main thread
|
|
24
25
|
- **Only library** combining CSS transitions + stagger + collapse + list reconciliation
|
|
@@ -53,9 +54,9 @@ FadeDiv({ show: show(), children: 'Hello, world!' })
|
|
|
53
54
|
Creates an animated component. `tag` can be any HTML element string or Pyreon component.
|
|
54
55
|
|
|
55
56
|
```ts
|
|
56
|
-
kinetic('div')
|
|
57
|
-
kinetic('section')
|
|
58
|
-
kinetic(MyComponent)
|
|
57
|
+
kinetic('div') // HTML element
|
|
58
|
+
kinetic('section') // Any HTML tag
|
|
59
|
+
kinetic(MyComponent) // Pyreon component
|
|
59
60
|
```
|
|
60
61
|
|
|
61
62
|
Returns a renderable Pyreon component with chain methods attached. Default mode: **transition**.
|
|
@@ -109,7 +110,7 @@ Height animation with `overflow: hidden`. Measures `scrollHeight` automatically.
|
|
|
109
110
|
```ts
|
|
110
111
|
const Accordion = kinetic('div').collapse()
|
|
111
112
|
const FancyAccordion = kinetic('section').collapse({
|
|
112
|
-
transition: 'height 400ms cubic-bezier(0.4, 0, 0.2, 1)'
|
|
113
|
+
transition: 'height 400ms cubic-bezier(0.4, 0, 0.2, 1)',
|
|
113
114
|
})
|
|
114
115
|
|
|
115
116
|
Accordion({ show: isExpanded, children: 'Expandable content' })
|
|
@@ -122,11 +123,14 @@ Staggered entrance/exit for child elements.
|
|
|
122
123
|
```ts
|
|
123
124
|
const StaggerList = kinetic('ul').preset(slideUp).stagger({ interval: 75 })
|
|
124
125
|
|
|
125
|
-
StaggerList({
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
126
|
+
StaggerList({
|
|
127
|
+
show: isVisible,
|
|
128
|
+
children: [
|
|
129
|
+
h('li', { key: '1' }, 'Item 1'),
|
|
130
|
+
h('li', { key: '2' }, 'Item 2'),
|
|
131
|
+
h('li', { key: '3' }, 'Item 3'),
|
|
132
|
+
],
|
|
133
|
+
})
|
|
130
134
|
```
|
|
131
135
|
|
|
132
136
|
#### Group
|
|
@@ -136,9 +140,7 @@ Key-based enter/exit — adding a child triggers enter animation, removing trigg
|
|
|
136
140
|
```ts
|
|
137
141
|
const AnimatedList = kinetic('ul').preset(fade).group()
|
|
138
142
|
|
|
139
|
-
AnimatedList({ children: items.map(item =>
|
|
140
|
-
h('li', { key: item.id }, item.text)
|
|
141
|
-
)})
|
|
143
|
+
AnimatedList({ children: items.map((item) => h('li', { key: item.id }, item.text)) })
|
|
142
144
|
```
|
|
143
145
|
|
|
144
146
|
### Inline Configuration
|
|
@@ -199,8 +201,9 @@ Kinetic and rocketstyle compose naturally:
|
|
|
199
201
|
```ts
|
|
200
202
|
import rocketstyle from '@pyreon/rocketstyle'
|
|
201
203
|
|
|
202
|
-
const Button = rocketstyle()({ component: 'button', name: 'Button' })
|
|
203
|
-
|
|
204
|
+
const Button = rocketstyle()({ component: 'button', name: 'Button' }).theme({
|
|
205
|
+
primaryColor: 'blue',
|
|
206
|
+
})
|
|
204
207
|
|
|
205
208
|
const AnimatedButton = kinetic(Button).preset(fade)
|
|
206
209
|
|
|
@@ -210,9 +213,9 @@ AnimatedButton({ show: isVisible, primary: true, size: 'large', children: 'Click
|
|
|
210
213
|
|
|
211
214
|
## Peer Dependencies
|
|
212
215
|
|
|
213
|
-
| Package
|
|
214
|
-
|
|
|
215
|
-
| @pyreon/core
|
|
216
|
+
| Package | Version |
|
|
217
|
+
| ------------------ | -------- |
|
|
218
|
+
| @pyreon/core | >= 0.0.1 |
|
|
216
219
|
| @pyreon/reactivity | >= 0.0.1 |
|
|
217
220
|
|
|
218
221
|
## License
|
package/lib/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { Signal } from "@pyreon/reactivity";
|
|
|
4
4
|
//#region src/types.d.ts
|
|
5
5
|
type CSSProperties = Record<string, string | number | undefined>;
|
|
6
6
|
/** Internal lifecycle stages of a transition. */
|
|
7
|
-
type TransitionStage =
|
|
7
|
+
type TransitionStage = 'hidden' | 'entering' | 'entered' | 'leaving';
|
|
8
8
|
/** Class-based transition definition. */
|
|
9
9
|
type ClassTransitionProps = {
|
|
10
10
|
/** Classes applied during the entire enter phase */enter?: string | undefined; /** Classes applied on first frame of enter, removed on next frame */
|
|
@@ -38,7 +38,7 @@ type TransitionStateResult = {
|
|
|
38
38
|
};
|
|
39
39
|
//#endregion
|
|
40
40
|
//#region src/kinetic/types.d.ts
|
|
41
|
-
type KineticMode =
|
|
41
|
+
type KineticMode = 'transition' | 'collapse' | 'stagger' | 'group';
|
|
42
42
|
type ClassConfig = {
|
|
43
43
|
active?: string | undefined;
|
|
44
44
|
from?: string | undefined;
|
|
@@ -91,8 +91,8 @@ type KineticGroupProps<_Tag extends string> = Record<string, unknown> & {
|
|
|
91
91
|
timeout?: number | undefined;
|
|
92
92
|
children: VNodeChild;
|
|
93
93
|
} & Partial<TransitionCallbacks>;
|
|
94
|
-
type KineticComponentProps<Tag extends string, Mode extends KineticMode> = Mode extends
|
|
95
|
-
type ConfigOpts<Mode extends KineticMode> = Mode extends
|
|
94
|
+
type KineticComponentProps<Tag extends string, Mode extends KineticMode> = Mode extends 'collapse' ? KineticCollapseProps<Tag> : Mode extends 'stagger' ? KineticStaggerProps<Tag> : Mode extends 'group' ? KineticGroupProps<Tag> : KineticTransitionProps<Tag>;
|
|
95
|
+
type ConfigOpts<Mode extends KineticMode> = Mode extends 'collapse' ? CollapseConfigOpts : Mode extends 'stagger' ? StaggerConfigOpts : Mode extends 'group' ? GroupConfigOpts : TransitionConfigOpts;
|
|
96
96
|
type KineticChain<Tag extends string, Mode extends KineticMode> = {
|
|
97
97
|
displayName: string;
|
|
98
98
|
preset: (preset: StyleTransitionProps & ClassTransitionProps) => KineticComponent<Tag, Mode>;
|
|
@@ -106,14 +106,14 @@ type KineticChain<Tag extends string, Mode extends KineticMode> = {
|
|
|
106
106
|
leaveClass: (opts: ClassConfig) => KineticComponent<Tag, Mode>;
|
|
107
107
|
config: (opts: ConfigOpts<Mode>) => KineticComponent<Tag, Mode>;
|
|
108
108
|
on: (callbacks: Partial<TransitionCallbacks>) => KineticComponent<Tag, Mode>;
|
|
109
|
-
collapse: (opts?: CollapseConfigOpts) => KineticComponent<Tag,
|
|
109
|
+
collapse: (opts?: CollapseConfigOpts) => KineticComponent<Tag, 'collapse'>;
|
|
110
110
|
stagger: (opts?: {
|
|
111
111
|
interval?: number | undefined;
|
|
112
112
|
reverseLeave?: boolean | undefined;
|
|
113
|
-
}) => KineticComponent<Tag,
|
|
114
|
-
group: () => KineticComponent<Tag,
|
|
113
|
+
}) => KineticComponent<Tag, 'stagger'>;
|
|
114
|
+
group: () => KineticComponent<Tag, 'group'>;
|
|
115
115
|
};
|
|
116
|
-
type KineticComponent<Tag extends string, Mode extends KineticMode =
|
|
116
|
+
type KineticComponent<Tag extends string, Mode extends KineticMode = 'transition'> = ComponentFn<KineticComponentProps<Tag, Mode>> & KineticChain<Tag, Mode>;
|
|
117
117
|
//#endregion
|
|
118
118
|
//#region src/kinetic.d.ts
|
|
119
119
|
/**
|
package/package.json
CHANGED
|
@@ -1,24 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pyreon/kinetic",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.7",
|
|
4
|
+
"description": "CSS-transition-based animation components for Pyreon",
|
|
5
|
+
"license": "MIT",
|
|
4
6
|
"repository": {
|
|
5
7
|
"type": "git",
|
|
6
8
|
"url": "https://github.com/pyreon/pyreon",
|
|
7
9
|
"directory": "packages/ui-system/kinetic"
|
|
8
10
|
},
|
|
9
|
-
"description": "CSS-transition-based animation components for Pyreon",
|
|
10
|
-
"license": "MIT",
|
|
11
|
-
"type": "module",
|
|
12
|
-
"sideEffects": false,
|
|
13
|
-
"exports": {
|
|
14
|
-
".": {
|
|
15
|
-
"bun": "./src/index.ts",
|
|
16
|
-
"import": "./lib/index.js",
|
|
17
|
-
"types": "./lib/index.d.ts"
|
|
18
|
-
}
|
|
19
|
-
},
|
|
20
|
-
"types": "./lib/index.d.ts",
|
|
21
|
-
"main": "./lib/index.js",
|
|
22
11
|
"files": [
|
|
23
12
|
"lib",
|
|
24
13
|
"!lib/**/*.map",
|
|
@@ -27,8 +16,16 @@
|
|
|
27
16
|
"LICENSE",
|
|
28
17
|
"src"
|
|
29
18
|
],
|
|
30
|
-
"
|
|
31
|
-
|
|
19
|
+
"type": "module",
|
|
20
|
+
"sideEffects": false,
|
|
21
|
+
"main": "./lib/index.js",
|
|
22
|
+
"types": "./lib/index.d.ts",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"bun": "./src/index.ts",
|
|
26
|
+
"import": "./lib/index.js",
|
|
27
|
+
"types": "./lib/index.d.ts"
|
|
28
|
+
}
|
|
32
29
|
},
|
|
33
30
|
"publishConfig": {
|
|
34
31
|
"access": "public"
|
|
@@ -37,18 +34,21 @@
|
|
|
37
34
|
"prepublish": "bun run build",
|
|
38
35
|
"build": "bun run vl_rolldown_build",
|
|
39
36
|
"build:watch": "bun run vl_rolldown_build-watch",
|
|
40
|
-
"lint": "
|
|
37
|
+
"lint": "oxlint .",
|
|
41
38
|
"test": "vitest run",
|
|
42
39
|
"test:coverage": "vitest run --coverage",
|
|
43
40
|
"test:watch": "vitest",
|
|
44
41
|
"typecheck": "tsc --noEmit"
|
|
45
42
|
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@pyreon/typescript": "^0.11.7",
|
|
45
|
+
"@vitus-labs/tools-rolldown": "^1.15.3"
|
|
46
|
+
},
|
|
46
47
|
"peerDependencies": {
|
|
47
|
-
"@pyreon/core": "^0.11.
|
|
48
|
-
"@pyreon/reactivity": "^0.11.
|
|
48
|
+
"@pyreon/core": "^0.11.7",
|
|
49
|
+
"@pyreon/reactivity": "^0.11.7"
|
|
49
50
|
},
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"@pyreon/typescript": "^0.11.5"
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">= 22"
|
|
53
53
|
}
|
|
54
54
|
}
|
package/src/Collapse.tsx
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import type { VNode } from
|
|
2
|
-
import { createRef, Show } from
|
|
3
|
-
import { runUntracked, signal, watch } from
|
|
4
|
-
import type { CollapseProps, TransitionStage } from
|
|
5
|
-
import useAnimationEnd from
|
|
6
|
-
import { useReducedMotion } from
|
|
1
|
+
import type { VNode } from '@pyreon/core'
|
|
2
|
+
import { createRef, Show } from '@pyreon/core'
|
|
3
|
+
import { runUntracked, signal, watch } from '@pyreon/reactivity'
|
|
4
|
+
import type { CollapseProps, TransitionStage } from './types'
|
|
5
|
+
import useAnimationEnd from './useAnimationEnd'
|
|
6
|
+
import { useReducedMotion } from './useReducedMotion'
|
|
7
7
|
|
|
8
8
|
const Collapse = ({
|
|
9
9
|
show,
|
|
10
|
-
transition =
|
|
10
|
+
transition = 'height 300ms ease',
|
|
11
11
|
appear = false,
|
|
12
12
|
timeout = 5000,
|
|
13
13
|
onEnter,
|
|
@@ -30,7 +30,7 @@ const Collapse = ({
|
|
|
30
30
|
const initialShow = show()
|
|
31
31
|
// When appear=true and show starts true, mount but defer animation until ref is wired
|
|
32
32
|
const needsAppear = appear && initialShow
|
|
33
|
-
const stage = signal<TransitionStage>(initialShow ?
|
|
33
|
+
const stage = signal<TransitionStage>(initialShow ? 'entered' : 'hidden')
|
|
34
34
|
let isInitialMount = true
|
|
35
35
|
let appearTriggered = false
|
|
36
36
|
|
|
@@ -39,7 +39,7 @@ const Collapse = ({
|
|
|
39
39
|
if (needsAppear) {
|
|
40
40
|
const orig = wrapperRef
|
|
41
41
|
const proxy = { current: null as HTMLDivElement | null }
|
|
42
|
-
Object.defineProperty(proxy,
|
|
42
|
+
Object.defineProperty(proxy, 'current', {
|
|
43
43
|
get() {
|
|
44
44
|
return orig.current
|
|
45
45
|
},
|
|
@@ -47,7 +47,7 @@ const Collapse = ({
|
|
|
47
47
|
orig.current = node
|
|
48
48
|
if (node && !appearTriggered) {
|
|
49
49
|
appearTriggered = true
|
|
50
|
-
queueMicrotask(() => stage.set(
|
|
50
|
+
queueMicrotask(() => stage.set('entering'))
|
|
51
51
|
}
|
|
52
52
|
},
|
|
53
53
|
})
|
|
@@ -65,10 +65,10 @@ const Collapse = ({
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
const currentStage = runUntracked(() => stage())
|
|
68
|
-
if (showVal && (currentStage ===
|
|
69
|
-
stage.set(
|
|
70
|
-
} else if (!showVal && (currentStage ===
|
|
71
|
-
stage.set(
|
|
68
|
+
if (showVal && (currentStage === 'hidden' || currentStage === 'leaving')) {
|
|
69
|
+
stage.set('entering')
|
|
70
|
+
} else if (!showVal && (currentStage === 'entered' || currentStage === 'entering')) {
|
|
71
|
+
stage.set('leaving')
|
|
72
72
|
}
|
|
73
73
|
},
|
|
74
74
|
{ immediate: true },
|
|
@@ -83,44 +83,44 @@ const Collapse = ({
|
|
|
83
83
|
if (!wrapper || !content) return
|
|
84
84
|
|
|
85
85
|
if (reducedMotion()) {
|
|
86
|
-
if (currentStage ===
|
|
86
|
+
if (currentStage === 'entering') {
|
|
87
87
|
callbacks.onEnter?.()
|
|
88
|
-
wrapper.style.height =
|
|
89
|
-
wrapper.style.overflow =
|
|
88
|
+
wrapper.style.height = 'auto'
|
|
89
|
+
wrapper.style.overflow = ''
|
|
90
90
|
callbacks.onAfterEnter?.()
|
|
91
|
-
stage.set(
|
|
92
|
-
} else if (currentStage ===
|
|
91
|
+
stage.set('entered')
|
|
92
|
+
} else if (currentStage === 'leaving') {
|
|
93
93
|
callbacks.onLeave?.()
|
|
94
|
-
wrapper.style.height =
|
|
95
|
-
wrapper.style.overflow =
|
|
94
|
+
wrapper.style.height = '0px'
|
|
95
|
+
wrapper.style.overflow = 'hidden'
|
|
96
96
|
callbacks.onAfterLeave?.()
|
|
97
|
-
stage.set(
|
|
97
|
+
stage.set('hidden')
|
|
98
98
|
}
|
|
99
99
|
return
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
if (currentStage ===
|
|
102
|
+
if (currentStage === 'entering') {
|
|
103
103
|
callbacks.onEnter?.()
|
|
104
104
|
const height = content.scrollHeight
|
|
105
|
-
wrapper.style.transition =
|
|
106
|
-
wrapper.style.height =
|
|
107
|
-
wrapper.style.overflow =
|
|
105
|
+
wrapper.style.transition = 'none'
|
|
106
|
+
wrapper.style.height = '0px'
|
|
107
|
+
wrapper.style.overflow = 'hidden'
|
|
108
108
|
// Force reflow so the browser registers height: 0
|
|
109
109
|
void wrapper.offsetHeight
|
|
110
110
|
wrapper.style.transition = transition
|
|
111
111
|
wrapper.style.height = `${height}px`
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
if (currentStage ===
|
|
114
|
+
if (currentStage === 'leaving') {
|
|
115
115
|
callbacks.onLeave?.()
|
|
116
116
|
const height = content.scrollHeight
|
|
117
|
-
wrapper.style.transition =
|
|
117
|
+
wrapper.style.transition = 'none'
|
|
118
118
|
wrapper.style.height = `${height}px`
|
|
119
|
-
wrapper.style.overflow =
|
|
119
|
+
wrapper.style.overflow = 'hidden'
|
|
120
120
|
// Force reflow
|
|
121
121
|
void wrapper.offsetHeight
|
|
122
122
|
wrapper.style.transition = transition
|
|
123
|
-
wrapper.style.height =
|
|
123
|
+
wrapper.style.height = '0px'
|
|
124
124
|
}
|
|
125
125
|
},
|
|
126
126
|
{ immediate: true },
|
|
@@ -129,36 +129,36 @@ const Collapse = ({
|
|
|
129
129
|
// Listen for animation end
|
|
130
130
|
useAnimationEnd({
|
|
131
131
|
ref: wrapperRef,
|
|
132
|
-
active: () => (stage() ===
|
|
132
|
+
active: () => (stage() === 'entering' || stage() === 'leaving') && !reducedMotion(),
|
|
133
133
|
timeout,
|
|
134
134
|
onEnd: () => {
|
|
135
135
|
const wrapper = wrapperRef.current
|
|
136
|
-
if (stage() ===
|
|
136
|
+
if (stage() === 'entering') {
|
|
137
137
|
if (wrapper) {
|
|
138
|
-
wrapper.style.height =
|
|
139
|
-
wrapper.style.overflow =
|
|
140
|
-
wrapper.style.transition =
|
|
138
|
+
wrapper.style.height = 'auto'
|
|
139
|
+
wrapper.style.overflow = ''
|
|
140
|
+
wrapper.style.transition = ''
|
|
141
141
|
}
|
|
142
142
|
callbacks.onAfterEnter?.()
|
|
143
|
-
stage.set(
|
|
144
|
-
} else if (stage() ===
|
|
143
|
+
stage.set('entered')
|
|
144
|
+
} else if (stage() === 'leaving') {
|
|
145
145
|
callbacks.onAfterLeave?.()
|
|
146
|
-
stage.set(
|
|
146
|
+
stage.set('hidden')
|
|
147
147
|
}
|
|
148
148
|
},
|
|
149
149
|
})
|
|
150
150
|
|
|
151
|
-
const shouldRender = () => stage() !==
|
|
151
|
+
const shouldRender = () => stage() !== 'hidden'
|
|
152
152
|
|
|
153
153
|
return (
|
|
154
154
|
<div
|
|
155
155
|
ref={wrapperRef}
|
|
156
156
|
style={{
|
|
157
|
-
...(stage() !==
|
|
158
|
-
...(stage() ===
|
|
159
|
-
? { height:
|
|
160
|
-
: stage() ===
|
|
161
|
-
? { height:
|
|
157
|
+
...(stage() !== 'entered' ? { overflow: 'hidden' } : {}),
|
|
158
|
+
...(stage() === 'hidden'
|
|
159
|
+
? { height: '0px' }
|
|
160
|
+
: stage() === 'entered'
|
|
161
|
+
? { height: 'auto' }
|
|
162
162
|
: {}),
|
|
163
163
|
}}
|
|
164
164
|
>
|
package/src/Stagger.tsx
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type { VNode } from
|
|
2
|
-
import Transition from
|
|
3
|
-
import type { CSSProperties, StaggerProps } from
|
|
4
|
-
import { cloneVNode } from
|
|
1
|
+
import type { VNode } from '@pyreon/core'
|
|
2
|
+
import Transition from './Transition'
|
|
3
|
+
import type { CSSProperties, StaggerProps } from './types'
|
|
4
|
+
import { cloneVNode } from './utils'
|
|
5
5
|
|
|
6
6
|
const isVNode = (child: unknown): child is VNode =>
|
|
7
|
-
child != null && typeof child ===
|
|
7
|
+
child != null && typeof child === 'object' && 'type' in (child as object)
|
|
8
8
|
|
|
9
9
|
const Stagger = ({
|
|
10
10
|
show,
|
|
@@ -37,8 +37,8 @@ const Stagger = ({
|
|
|
37
37
|
{cloneVNode(child, {
|
|
38
38
|
style: {
|
|
39
39
|
...((child.props as Record<string, unknown>)?.style as CSSProperties | undefined),
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
'--stagger-index': staggerIndex,
|
|
41
|
+
'--stagger-interval': `${interval}ms`,
|
|
42
42
|
transitionDelay: `${delay}ms`,
|
|
43
43
|
} as CSSProperties,
|
|
44
44
|
})}
|
package/src/Transition.tsx
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type { VNode } from
|
|
2
|
-
import { createRef, Show } from
|
|
3
|
-
import { watch } from
|
|
4
|
-
import type { ClassTransitionProps, StyleTransitionProps, TransitionProps } 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, TransitionProps } 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
|
const applyEnter = (
|
|
11
11
|
el: HTMLElement,
|
|
@@ -68,11 +68,11 @@ const applyReducedMotion = (
|
|
|
68
68
|
},
|
|
69
69
|
complete: () => void,
|
|
70
70
|
) => {
|
|
71
|
-
if (stage ===
|
|
71
|
+
if (stage === 'entering') {
|
|
72
72
|
callbacks.onEnter?.()
|
|
73
73
|
callbacks.onAfterEnter?.()
|
|
74
74
|
complete()
|
|
75
|
-
} else if (stage ===
|
|
75
|
+
} else if (stage === 'leaving') {
|
|
76
76
|
callbacks.onLeave?.()
|
|
77
77
|
callbacks.onAfterLeave?.()
|
|
78
78
|
complete()
|
|
@@ -145,12 +145,12 @@ const Transition = ({
|
|
|
145
145
|
|
|
146
146
|
useAnimationEnd({
|
|
147
147
|
ref: elementRef,
|
|
148
|
-
active: () => (stage() ===
|
|
148
|
+
active: () => (stage() === 'entering' || stage() === 'leaving') && !reducedMotion(),
|
|
149
149
|
timeout,
|
|
150
150
|
onEnd: () => {
|
|
151
|
-
if (stage() ===
|
|
151
|
+
if (stage() === 'entering') {
|
|
152
152
|
callbacks.onAfterEnter?.()
|
|
153
|
-
} else if (stage() ===
|
|
153
|
+
} else if (stage() === 'leaving') {
|
|
154
154
|
callbacks.onAfterLeave?.()
|
|
155
155
|
}
|
|
156
156
|
complete()
|
|
@@ -168,21 +168,21 @@ const Transition = ({
|
|
|
168
168
|
return
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
-
if (currentStage ===
|
|
171
|
+
if (currentStage === 'entering') {
|
|
172
172
|
callbacks.onEnter?.()
|
|
173
173
|
const frameId = applyEnter(el, transitionConfig)
|
|
174
174
|
return () => cancelAnimationFrame(frameId)
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
-
if (currentStage ===
|
|
177
|
+
if (currentStage === 'leaving') {
|
|
178
178
|
callbacks.onLeave?.()
|
|
179
179
|
const frameId = applyLeave(el, transitionConfig)
|
|
180
180
|
return () => cancelAnimationFrame(frameId)
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
-
if (currentStage ===
|
|
183
|
+
if (currentStage === 'entered') {
|
|
184
184
|
removeClasses(el, enter)
|
|
185
|
-
el.style.transition =
|
|
185
|
+
el.style.transition = ''
|
|
186
186
|
}
|
|
187
187
|
},
|
|
188
188
|
{ immediate: true },
|
|
@@ -198,7 +198,7 @@ const Transition = ({
|
|
|
198
198
|
ref: mergedRef,
|
|
199
199
|
style: mergeStyles(
|
|
200
200
|
childProps.style as Record<string, string | number | undefined> | undefined,
|
|
201
|
-
{ display:
|
|
201
|
+
{ display: 'none' },
|
|
202
202
|
),
|
|
203
203
|
})
|
|
204
204
|
}
|
package/src/TransitionGroup.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { VNode } from
|
|
2
|
-
import { signal } from
|
|
3
|
-
import Transition from
|
|
4
|
-
import type { ClassTransitionProps, StyleTransitionProps, TransitionCallbacks } from
|
|
1
|
+
import type { VNode } from '@pyreon/core'
|
|
2
|
+
import { signal } from '@pyreon/reactivity'
|
|
3
|
+
import Transition from './Transition'
|
|
4
|
+
import type { ClassTransitionProps, StyleTransitionProps, TransitionCallbacks } from './types'
|
|
5
5
|
|
|
6
6
|
export type TransitionGroupProps = ClassTransitionProps &
|
|
7
7
|
StyleTransitionProps &
|
|
@@ -19,7 +19,7 @@ export type TransitionGroupProps = ClassTransitionProps &
|
|
|
19
19
|
type KeyedChild = { key: string | number; element: VNode }
|
|
20
20
|
|
|
21
21
|
const isVNode = (child: unknown): child is VNode =>
|
|
22
|
-
child != null && typeof child ===
|
|
22
|
+
child != null && typeof child === 'object' && 'type' in (child as object)
|
|
23
23
|
|
|
24
24
|
const getKeyedChildren = (children: VNode[]): KeyedChild[] => {
|
|
25
25
|
const result: KeyedChild[] = []
|
|
@@ -54,7 +54,7 @@ const TransitionGroup = ({
|
|
|
54
54
|
const forceUpdate = signal(0)
|
|
55
55
|
|
|
56
56
|
// Normalize children to an accessor for uniform handling
|
|
57
|
-
const getChildren = typeof children ===
|
|
57
|
+
const getChildren = typeof children === 'function' ? (children as () => VNode[]) : () => children
|
|
58
58
|
|
|
59
59
|
// Track initial keys for appear animation logic
|
|
60
60
|
const initialKeyed = getKeyedChildren(getChildren())
|