@pyreon/kinetic 0.24.4 → 0.24.6

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 (37) hide show
  1. package/package.json +10 -12
  2. package/src/Collapse.tsx +0 -166
  3. package/src/Stagger.tsx +0 -63
  4. package/src/Transition.tsx +0 -280
  5. package/src/TransitionGroup.tsx +0 -139
  6. package/src/__tests__/Collapse.test.tsx +0 -803
  7. package/src/__tests__/GroupRenderer.test.tsx +0 -434
  8. package/src/__tests__/StaggerRenderer.test.tsx +0 -523
  9. package/src/__tests__/Transition.ssr.test.tsx +0 -183
  10. package/src/__tests__/Transition.test.tsx +0 -403
  11. package/src/__tests__/TransitionItem.test.tsx +0 -514
  12. package/src/__tests__/kinetic-modes.ssr.test.tsx +0 -214
  13. package/src/__tests__/kinetic.browser.test.tsx +0 -327
  14. package/src/__tests__/kinetic.test.tsx +0 -565
  15. package/src/__tests__/presets.test.ts +0 -46
  16. package/src/__tests__/stagger-component-children-hydration.test.tsx +0 -191
  17. package/src/__tests__/top-level-transition-stagger-function-children.test.tsx +0 -141
  18. package/src/__tests__/useAnimationEnd.test.ts +0 -194
  19. package/src/__tests__/useReducedMotion.test.ts +0 -160
  20. package/src/__tests__/useTransitionState.test.ts +0 -132
  21. package/src/__tests__/utils.test.ts +0 -139
  22. package/src/index.ts +0 -15
  23. package/src/jsx-augment.d.ts +0 -12
  24. package/src/kinetic/CollapseRenderer.tsx +0 -216
  25. package/src/kinetic/GroupRenderer.tsx +0 -149
  26. package/src/kinetic/StaggerRenderer.tsx +0 -94
  27. package/src/kinetic/TransitionItem.tsx +0 -250
  28. package/src/kinetic/TransitionRenderer.tsx +0 -230
  29. package/src/kinetic/createKineticComponent.tsx +0 -224
  30. package/src/kinetic/types.ts +0 -149
  31. package/src/kinetic.ts +0 -25
  32. package/src/presets.ts +0 -66
  33. package/src/types.ts +0 -118
  34. package/src/useAnimationEnd.ts +0 -59
  35. package/src/useReducedMotion.ts +0 -28
  36. package/src/useTransitionState.ts +0 -62
  37. package/src/utils.ts +0 -113
@@ -1,224 +0,0 @@
1
- import type { VNode } from '@pyreon/core'
2
- import { splitProps } from '@pyreon/core'
3
- import type { CSSProperties, TransitionCallbacks } from '../types'
4
- import CollapseRenderer from './CollapseRenderer'
5
- import GroupRenderer from './GroupRenderer'
6
- import StaggerRenderer from './StaggerRenderer'
7
- import TransitionRenderer from './TransitionRenderer'
8
- import type { ClassConfig, KineticComponent, KineticConfig, KineticMode } from './types'
9
-
10
- /** Keys that are kinetic-specific and should not be forwarded as HTML attrs. */
11
- const KINETIC_KEYS = new Set([
12
- 'show',
13
- 'appear',
14
- 'unmount',
15
- 'timeout',
16
- 'transition',
17
- 'interval',
18
- 'reverseLeave',
19
- 'onEnter',
20
- 'onAfterEnter',
21
- 'onLeave',
22
- 'onAfterLeave',
23
- ])
24
-
25
- /**
26
- * Core factory. Creates a component that delegates to the appropriate
27
- * renderer based on config.mode, then attaches immutable chain methods
28
- * via Object.assign.
29
- */
30
- const createKineticComponent = <Tag extends string, Mode extends KineticMode = 'transition'>(
31
- config: KineticConfig,
32
- ): KineticComponent<Tag, Mode> => {
33
- const Component = (props: Record<string, unknown>): VNode | null => {
34
- // Separate kinetic-specific props from HTML pass-through props.
35
- // MUST use splitProps (descriptor-preserving) — a plain
36
- // `htmlProps[key] = props[key]` value-copy fires every getter at
37
- // component-setup time. The compiler emits `<KineticDiv class={sig()}>`
38
- // as `_rp(() => sig())`, which `makeReactiveProps` turns into a getter
39
- // on `props`; reading it here (outside any tracking scope) would
40
- // collapse it to a static snapshot and freeze the HTML attr forever.
41
- // splitProps copies DESCRIPTORS via Object.getOwnPropertyDescriptor +
42
- // Object.defineProperty, so the getter survives to the renderer's
43
- // `h(config.tag, htmlProps)` where runtime-dom's applyProps detects
44
- // the descriptor and wraps the read in renderEffect.
45
- // `props` is `Record<string, unknown>`, so `Omit<…, string>` collapses
46
- // to `{}` at the type level — the runtime split is correct (splitProps
47
- // copies descriptors for every own key not in the pick set), only the
48
- // inferred result types degrade. Cast back to the real shape.
49
- const [kineticProps, htmlPropsWithChildren] = splitProps(props, [...KINETIC_KEYS]) as [
50
- Record<string, unknown>,
51
- Record<string, unknown>,
52
- ]
53
-
54
- const {
55
- show,
56
- appear,
57
- unmount,
58
- timeout,
59
- transition,
60
- interval,
61
- reverseLeave,
62
- onEnter,
63
- onAfterEnter,
64
- onLeave,
65
- onAfterLeave,
66
- } = kineticProps as {
67
- show?: () => boolean
68
- appear?: boolean
69
- unmount?: boolean
70
- timeout?: number
71
- transition?: string
72
- interval?: number
73
- reverseLeave?: boolean
74
- } & Partial<TransitionCallbacks>
75
-
76
- const callbacks: Partial<TransitionCallbacks> = {
77
- onEnter: onEnter ?? config.onEnter,
78
- onAfterEnter: onAfterEnter ?? config.onAfterEnter,
79
- onLeave: onLeave ?? config.onLeave,
80
- onAfterLeave: onAfterLeave ?? config.onAfterLeave,
81
- }
82
-
83
- // Carve `children` out of the HTML pass-through set — also via
84
- // splitProps so the remaining HTML attrs keep their getter
85
- // descriptors (`const { children, ...restHtml } = …` is the same
86
- // value-copy footgun as the split above).
87
- const [childHolder, restHtml] = splitProps(htmlPropsWithChildren, ['children'])
88
- const children = childHolder.children
89
-
90
- if (config.mode === 'collapse') {
91
- return (
92
- <CollapseRenderer
93
- config={config}
94
- htmlProps={restHtml}
95
- show={show as () => boolean}
96
- appear={appear}
97
- timeout={timeout}
98
- transition={transition}
99
- callbacks={callbacks}
100
- >
101
- {children as VNode | VNode[]}
102
- </CollapseRenderer>
103
- )
104
- }
105
-
106
- if (config.mode === 'stagger') {
107
- return (
108
- <StaggerRenderer
109
- config={config}
110
- htmlProps={restHtml}
111
- show={show as () => boolean}
112
- appear={appear}
113
- timeout={timeout}
114
- interval={interval}
115
- reverseLeave={reverseLeave}
116
- callbacks={callbacks}
117
- >
118
- {children as VNode[]}
119
- </StaggerRenderer>
120
- )
121
- }
122
-
123
- if (config.mode === 'group') {
124
- return (
125
- <GroupRenderer
126
- config={config}
127
- htmlProps={restHtml}
128
- appear={appear}
129
- timeout={timeout}
130
- callbacks={callbacks}
131
- >
132
- {children as VNode[]}
133
- </GroupRenderer>
134
- )
135
- }
136
-
137
- // Default: transition mode
138
- return (
139
- <TransitionRenderer
140
- config={config}
141
- htmlProps={restHtml}
142
- show={show as () => boolean}
143
- appear={appear}
144
- unmount={unmount}
145
- timeout={timeout}
146
- callbacks={callbacks}
147
- >
148
- {children as VNode | VNode[]}
149
- </TransitionRenderer>
150
- )
151
- }
152
-
153
- Component.displayName = `kinetic(${config.tag})`
154
-
155
- // Immutable chain methods — each returns a new component with merged config.
156
- return Object.assign(Component, {
157
- preset: (preset: Record<string, unknown>) =>
158
- createKineticComponent<Tag, Mode>({
159
- ...config,
160
- ...preset,
161
- } as KineticConfig),
162
-
163
- enter: (styles: CSSProperties) =>
164
- createKineticComponent<Tag, Mode>({ ...config, enterStyle: styles }),
165
-
166
- enterTo: (styles: CSSProperties) =>
167
- createKineticComponent<Tag, Mode>({ ...config, enterToStyle: styles }),
168
-
169
- enterTransition: (value: string) =>
170
- createKineticComponent<Tag, Mode>({ ...config, enterTransition: value }),
171
-
172
- leave: (styles: CSSProperties) =>
173
- createKineticComponent<Tag, Mode>({ ...config, leaveStyle: styles }),
174
-
175
- leaveTo: (styles: CSSProperties) =>
176
- createKineticComponent<Tag, Mode>({ ...config, leaveToStyle: styles }),
177
-
178
- leaveTransition: (value: string) =>
179
- createKineticComponent<Tag, Mode>({ ...config, leaveTransition: value }),
180
-
181
- enterClass: ({ active, from, to }: ClassConfig) =>
182
- createKineticComponent<Tag, Mode>({
183
- ...config,
184
- enter: active,
185
- enterFrom: from,
186
- enterTo: to,
187
- }),
188
-
189
- leaveClass: ({ active, from, to }: ClassConfig) =>
190
- createKineticComponent<Tag, Mode>({
191
- ...config,
192
- leave: active,
193
- leaveFrom: from,
194
- leaveTo: to,
195
- }),
196
-
197
- config: (opts: Record<string, unknown>) =>
198
- createKineticComponent<Tag, Mode>({
199
- ...config,
200
- ...opts,
201
- } as KineticConfig),
202
-
203
- on: (cbs: Partial<TransitionCallbacks>) =>
204
- createKineticComponent<Tag, Mode>({ ...config, ...cbs }),
205
-
206
- collapse: (opts?: { transition?: string }) =>
207
- createKineticComponent<Tag, 'collapse'>({
208
- ...config,
209
- mode: 'collapse',
210
- ...opts,
211
- }),
212
-
213
- stagger: (opts?: { interval?: number; reverseLeave?: boolean }) =>
214
- createKineticComponent<Tag, 'stagger'>({
215
- ...config,
216
- mode: 'stagger',
217
- ...opts,
218
- }),
219
-
220
- group: () => createKineticComponent<Tag, 'group'>({ ...config, mode: 'group' }),
221
- }) as unknown as KineticComponent<Tag, Mode>
222
- }
223
-
224
- export default createKineticComponent
@@ -1,149 +0,0 @@
1
- import type { ComponentFn, VNodeChild } from '@pyreon/core'
2
- import type {
3
- ClassTransitionProps,
4
- CSSProperties,
5
- StyleTransitionProps,
6
- TransitionCallbacks,
7
- } from '../types'
8
-
9
- // ─── Kinetic Modes ────────────────────────────────────────
10
-
11
- export type KineticMode = 'transition' | 'collapse' | 'stagger' | 'group'
12
-
13
- // ─── Internal Config (accumulated through chaining) ──────
14
-
15
- export type KineticConfig = StyleTransitionProps &
16
- ClassTransitionProps &
17
- TransitionCallbacks & {
18
- tag: string
19
- mode: KineticMode
20
- appear?: boolean | undefined
21
- unmount?: boolean | undefined
22
- timeout?: number | undefined
23
- /** Collapse: CSS transition for height. */
24
- transition?: string | undefined
25
- /** Stagger: delay between each child in ms. */
26
- interval?: number | undefined
27
- /** Stagger: reverse order on leave. */
28
- reverseLeave?: boolean | undefined
29
- }
30
-
31
- // ─── Class Config (for .enterClass / .leaveClass) ────────
32
-
33
- export type ClassConfig = {
34
- active?: string | undefined
35
- from?: string | undefined
36
- to?: string | undefined
37
- }
38
-
39
- // ─── Mode-specific config options for .config() ──────────
40
-
41
- export type TransitionConfigOpts = {
42
- appear?: boolean | undefined
43
- unmount?: boolean | undefined
44
- timeout?: number | undefined
45
- }
46
-
47
- export type CollapseConfigOpts = {
48
- appear?: boolean | undefined
49
- timeout?: number | undefined
50
- transition?: string | undefined
51
- }
52
-
53
- export type StaggerConfigOpts = {
54
- appear?: boolean | undefined
55
- timeout?: number | undefined
56
- interval?: number | undefined
57
- reverseLeave?: boolean | undefined
58
- }
59
-
60
- export type GroupConfigOpts = {
61
- appear?: boolean | undefined
62
- timeout?: number | undefined
63
- }
64
-
65
- // ─── Mode-specific component props ───────────────────────
66
-
67
- export type KineticTransitionProps<_Tag extends string> = Record<string, unknown> & {
68
- show: () => boolean
69
- appear?: boolean | undefined
70
- unmount?: boolean | undefined
71
- timeout?: number | undefined
72
- children?: VNodeChild | undefined
73
- } & Partial<TransitionCallbacks>
74
-
75
- export type KineticCollapseProps<_Tag extends string> = Record<string, unknown> & {
76
- show: () => boolean
77
- appear?: boolean | undefined
78
- timeout?: number | undefined
79
- transition?: string | undefined
80
- children?: VNodeChild | undefined
81
- } & Partial<TransitionCallbacks>
82
-
83
- export type KineticStaggerProps<_Tag extends string> = Record<string, unknown> & {
84
- show: () => boolean
85
- appear?: boolean | undefined
86
- timeout?: number | undefined
87
- interval?: number | undefined
88
- reverseLeave?: boolean | undefined
89
- children: VNodeChild
90
- } & Partial<TransitionCallbacks>
91
-
92
- export type KineticGroupProps<_Tag extends string> = Record<string, unknown> & {
93
- appear?: boolean | undefined
94
- timeout?: number | undefined
95
- children: VNodeChild
96
- } & Partial<TransitionCallbacks>
97
-
98
- // ─── Conditional props based on mode ─────────────────────
99
-
100
- export type KineticComponentProps<
101
- Tag extends string,
102
- Mode extends KineticMode,
103
- > = Mode extends 'collapse'
104
- ? KineticCollapseProps<Tag>
105
- : Mode extends 'stagger'
106
- ? KineticStaggerProps<Tag>
107
- : Mode extends 'group'
108
- ? KineticGroupProps<Tag>
109
- : KineticTransitionProps<Tag>
110
-
111
- // ─── Conditional config opts based on mode ───────────────
112
-
113
- type ConfigOpts<Mode extends KineticMode> = Mode extends 'collapse'
114
- ? CollapseConfigOpts
115
- : Mode extends 'stagger'
116
- ? StaggerConfigOpts
117
- : Mode extends 'group'
118
- ? GroupConfigOpts
119
- : TransitionConfigOpts
120
-
121
- // ─── Chain methods ───────────────────────────────────────
122
-
123
- export type KineticChain<Tag extends string, Mode extends KineticMode> = {
124
- displayName: string
125
- preset: (preset: StyleTransitionProps & ClassTransitionProps) => KineticComponent<Tag, Mode>
126
- enter: (styles: CSSProperties) => KineticComponent<Tag, Mode>
127
- enterTo: (styles: CSSProperties) => KineticComponent<Tag, Mode>
128
- enterTransition: (value: string) => KineticComponent<Tag, Mode>
129
- leave: (styles: CSSProperties) => KineticComponent<Tag, Mode>
130
- leaveTo: (styles: CSSProperties) => KineticComponent<Tag, Mode>
131
- leaveTransition: (value: string) => KineticComponent<Tag, Mode>
132
- enterClass: (opts: ClassConfig) => KineticComponent<Tag, Mode>
133
- leaveClass: (opts: ClassConfig) => KineticComponent<Tag, Mode>
134
- config: (opts: ConfigOpts<Mode>) => KineticComponent<Tag, Mode>
135
- on: (callbacks: Partial<TransitionCallbacks>) => KineticComponent<Tag, Mode>
136
- collapse: (opts?: CollapseConfigOpts) => KineticComponent<Tag, 'collapse'>
137
- stagger: (opts?: {
138
- interval?: number | undefined
139
- reverseLeave?: boolean | undefined
140
- }) => KineticComponent<Tag, 'stagger'>
141
- group: () => KineticComponent<Tag, 'group'>
142
- }
143
-
144
- // ─── The full kinetic component: renderable + chainable ───
145
-
146
- export type KineticComponent<
147
- Tag extends string,
148
- Mode extends KineticMode = 'transition',
149
- > = ComponentFn<KineticComponentProps<Tag, Mode>> & KineticChain<Tag, Mode>
package/src/kinetic.ts DELETED
@@ -1,25 +0,0 @@
1
- import createKineticComponent from './kinetic/createKineticComponent'
2
- import type { KineticComponent } from './kinetic/types'
3
-
4
- /**
5
- * Creates a reusable animated component via immutable chaining.
6
- *
7
- * @example
8
- * ```tsx
9
- * // Transition (default)
10
- * const FadeDiv = kinetic('div').preset(fade)
11
- *
12
- * // Collapse
13
- * const Accordion = kinetic('div').collapse()
14
- *
15
- * // Stagger
16
- * const StaggerList = kinetic('ul').preset(slideUp).stagger({ interval: 50 })
17
- *
18
- * // Group (key-based enter/exit)
19
- * const AnimatedList = kinetic('ul').preset(fade).group()
20
- * ```
21
- */
22
- const kinetic = <Tag extends string>(tag: Tag): KineticComponent<Tag, 'transition'> =>
23
- createKineticComponent<Tag, 'transition'>({ tag, mode: 'transition' })
24
-
25
- export default kinetic
package/src/presets.ts DELETED
@@ -1,66 +0,0 @@
1
- import type { ClassTransitionProps, StyleTransitionProps } from './types'
2
-
3
- export type Preset = StyleTransitionProps & ClassTransitionProps
4
-
5
- export const fade: Preset = {
6
- enterStyle: { opacity: 0 },
7
- enterToStyle: { opacity: 1 },
8
- enterTransition: 'opacity 300ms ease-out',
9
- leaveStyle: { opacity: 1 },
10
- leaveToStyle: { opacity: 0 },
11
- leaveTransition: 'opacity 200ms ease-in',
12
- }
13
-
14
- export const scaleIn: Preset = {
15
- enterStyle: { opacity: 0, transform: 'scale(0.95)' },
16
- enterToStyle: { opacity: 1, transform: 'scale(1)' },
17
- enterTransition: 'opacity 300ms ease-out, transform 300ms ease-out',
18
- leaveStyle: { opacity: 1, transform: 'scale(1)' },
19
- leaveToStyle: { opacity: 0, transform: 'scale(0.95)' },
20
- leaveTransition: 'opacity 200ms ease-in, transform 200ms ease-in',
21
- }
22
-
23
- export const slideUp: Preset = {
24
- enterStyle: { opacity: 0, transform: 'translateY(16px)' },
25
- enterToStyle: { opacity: 1, transform: 'translateY(0)' },
26
- enterTransition: 'opacity 300ms ease-out, transform 300ms ease-out',
27
- leaveStyle: { opacity: 1, transform: 'translateY(0)' },
28
- leaveToStyle: { opacity: 0, transform: 'translateY(16px)' },
29
- leaveTransition: 'opacity 200ms ease-in, transform 200ms ease-in',
30
- }
31
-
32
- export const slideDown: Preset = {
33
- enterStyle: { opacity: 0, transform: 'translateY(-16px)' },
34
- enterToStyle: { opacity: 1, transform: 'translateY(0)' },
35
- enterTransition: 'opacity 300ms ease-out, transform 300ms ease-out',
36
- leaveStyle: { opacity: 1, transform: 'translateY(0)' },
37
- leaveToStyle: { opacity: 0, transform: 'translateY(-16px)' },
38
- leaveTransition: 'opacity 200ms ease-in, transform 200ms ease-in',
39
- }
40
-
41
- export const slideLeft: Preset = {
42
- enterStyle: { opacity: 0, transform: 'translateX(16px)' },
43
- enterToStyle: { opacity: 1, transform: 'translateX(0)' },
44
- enterTransition: 'opacity 300ms ease-out, transform 300ms ease-out',
45
- leaveStyle: { opacity: 1, transform: 'translateX(0)' },
46
- leaveToStyle: { opacity: 0, transform: 'translateX(16px)' },
47
- leaveTransition: 'opacity 200ms ease-in, transform 200ms ease-in',
48
- }
49
-
50
- export const slideRight: Preset = {
51
- enterStyle: { opacity: 0, transform: 'translateX(-16px)' },
52
- enterToStyle: { opacity: 1, transform: 'translateX(0)' },
53
- enterTransition: 'opacity 300ms ease-out, transform 300ms ease-out',
54
- leaveStyle: { opacity: 1, transform: 'translateX(0)' },
55
- leaveToStyle: { opacity: 0, transform: 'translateX(-16px)' },
56
- leaveTransition: 'opacity 200ms ease-in, transform 200ms ease-in',
57
- }
58
-
59
- export const presets = {
60
- fade,
61
- scaleIn,
62
- slideUp,
63
- slideDown,
64
- slideLeft,
65
- slideRight,
66
- } as const
package/src/types.ts DELETED
@@ -1,118 +0,0 @@
1
- import type { Ref, VNode } from '@pyreon/core'
2
- import type { Signal } from '@pyreon/reactivity'
3
-
4
- export type CSSProperties = Record<string, string | number | undefined>
5
-
6
- /** Internal lifecycle stages of a transition. */
7
- export type TransitionStage = 'hidden' | 'entering' | 'entered' | 'leaving'
8
-
9
- /** Class-based transition definition. */
10
- export type ClassTransitionProps = {
11
- /** Classes applied during the entire enter phase */
12
- enter?: string | undefined
13
- /** Classes applied on first frame of enter, removed on next frame */
14
- enterFrom?: string | undefined
15
- /** Classes applied on second frame of enter, kept until complete */
16
- enterTo?: string | undefined
17
- /** Classes applied during the entire leave phase */
18
- leave?: string | undefined
19
- /** Classes applied on first frame of leave */
20
- leaveFrom?: string | undefined
21
- /** Classes applied on second frame of leave, kept until complete */
22
- leaveTo?: string | undefined
23
- }
24
-
25
- /** Style-object transition definition (zero-CSS option). */
26
- export type StyleTransitionProps = {
27
- /** Inline styles for the start of enter */
28
- enterStyle?: CSSProperties | undefined
29
- /** Inline styles for the end of enter */
30
- enterToStyle?: CSSProperties | undefined
31
- /** CSS transition shorthand applied during enter */
32
- enterTransition?: string | undefined
33
- /** Inline styles for the start of leave */
34
- leaveStyle?: CSSProperties | undefined
35
- /** Inline styles for the end of leave */
36
- leaveToStyle?: CSSProperties | undefined
37
- /** CSS transition shorthand applied during leave */
38
- leaveTransition?: string | undefined
39
- }
40
-
41
- /** Lifecycle callbacks. */
42
- export type TransitionCallbacks = {
43
- /** Called immediately when entering begins */
44
- onEnter?: (() => void) | undefined
45
- /** Called when enter animation completes */
46
- onAfterEnter?: (() => void) | undefined
47
- /** Called immediately when leaving begins */
48
- onLeave?: (() => void) | undefined
49
- /** Called when leave animation completes */
50
- onAfterLeave?: (() => void) | undefined
51
- }
52
-
53
- export type TransitionProps = ClassTransitionProps &
54
- StyleTransitionProps &
55
- TransitionCallbacks & {
56
- /** Reactive accessor controlling visibility. true = enter, false = leave + unmount. */
57
- show: () => boolean
58
- /** If true, runs enter animation on initial mount. Default: false. */
59
- appear?: boolean | undefined
60
- /** If true (default), unmounts when hidden. If false, keeps with display:none. */
61
- unmount?: boolean | undefined
62
- /** Safety timeout in ms. Default: 5000. */
63
- timeout?: number | undefined
64
- /** Single child element. Must accept ref. */
65
- children: VNode
66
- }
67
-
68
- export type TransitionGroupProps = ClassTransitionProps &
69
- StyleTransitionProps &
70
- TransitionCallbacks & {
71
- /** If true, animates initial children on mount. Default: false. */
72
- appear?: boolean | undefined
73
- /** Safety timeout in ms. Default: 5000. */
74
- timeout?: number | undefined
75
- /** Children with unique keys. */
76
- children: VNode[]
77
- }
78
-
79
- export type StaggerProps = ClassTransitionProps &
80
- StyleTransitionProps &
81
- TransitionCallbacks & {
82
- /** Reactive accessor controlling visibility of all children. */
83
- show: () => boolean
84
- /** Delay between each child's animation start in ms. Default: 50. */
85
- interval?: number | undefined
86
- /** If true, reverses stagger order on leave. Default: false. */
87
- reverseLeave?: boolean | undefined
88
- /** If true, animates on initial mount. Default: false. */
89
- appear?: boolean | undefined
90
- /** Safety timeout in ms. Default: 5000. */
91
- timeout?: number | undefined
92
- /** Children to stagger. */
93
- children: VNode[]
94
- }
95
-
96
- export type CollapseProps = TransitionCallbacks & {
97
- /** Reactive accessor controlling expanded/collapsed state. */
98
- show: () => boolean
99
- /** CSS transition for height. Default: "height 300ms ease". */
100
- transition?: string | undefined
101
- /** If true, animates on initial mount. Default: false. */
102
- appear?: boolean | undefined
103
- /** Safety timeout in ms. Default: 5000. */
104
- timeout?: number | undefined
105
- /** The content to collapse. */
106
- children: VNode
107
- }
108
-
109
- export type TransitionStateResult = {
110
- /** Current lifecycle stage (signal) */
111
- stage: Signal<TransitionStage>
112
- /** Ref callback to attach to the transitioning element */
113
- ref: Ref<HTMLElement> | ((node: HTMLElement | null) => void)
114
- /** Reactive accessor: whether the element should be rendered */
115
- shouldMount: () => boolean
116
- /** Call when the current animation finishes */
117
- complete: () => void
118
- }
@@ -1,59 +0,0 @@
1
- import type { Ref } from '@pyreon/core'
2
- import { watch } from '@pyreon/reactivity'
3
-
4
- const DEFAULT_TIMEOUT = 5000
5
-
6
- export type UseAnimationEnd = (options: {
7
- ref: Ref<HTMLElement>
8
- onEnd: () => void
9
- active: () => boolean
10
- timeout?: number | undefined
11
- }) => void
12
-
13
- const useAnimationEnd: UseAnimationEnd = ({ ref, onEnd, active, timeout = DEFAULT_TIMEOUT }) => {
14
- let called = false
15
-
16
- watch(
17
- active,
18
- (isActive) => {
19
- if (!isActive) {
20
- called = false
21
- return
22
- }
23
-
24
- const el = ref.current
25
- if (!el) return
26
-
27
- called = false
28
-
29
- const done = () => {
30
- if (called) return
31
- called = true
32
- el.removeEventListener('transitionend', handleEnd)
33
- el.removeEventListener('animationend', handleEnd)
34
- clearTimeout(timer)
35
- onEnd()
36
- }
37
-
38
- const handleEnd = (e: Event) => {
39
- // Ignore bubbled events from children
40
- if (e.target !== el) return
41
- done()
42
- }
43
-
44
- el.addEventListener('transitionend', handleEnd)
45
- el.addEventListener('animationend', handleEnd)
46
-
47
- const timer = setTimeout(done, timeout)
48
-
49
- return () => {
50
- el.removeEventListener('transitionend', handleEnd)
51
- el.removeEventListener('animationend', handleEnd)
52
- clearTimeout(timer)
53
- }
54
- },
55
- { immediate: true },
56
- )
57
- }
58
-
59
- export default useAnimationEnd
@@ -1,28 +0,0 @@
1
- import { onMount, onUnmount } from '@pyreon/core'
2
- import { signal } from '@pyreon/reactivity'
3
-
4
- /**
5
- * Inline reduced-motion check for kinetic package.
6
- * Avoids depending on @pyreon/hooks for a single media query.
7
- */
8
- export function useReducedMotion(): () => boolean {
9
- const matches = signal(false)
10
- let mql: MediaQueryList | undefined
11
-
12
- const onChange = (e: MediaQueryListEvent) => {
13
- matches.set(e.matches)
14
- }
15
-
16
- onMount(() => {
17
- mql = window.matchMedia('(prefers-reduced-motion: reduce)')
18
- matches.set(mql.matches)
19
- mql.addEventListener('change', onChange)
20
- return undefined
21
- })
22
-
23
- onUnmount(() => {
24
- mql?.removeEventListener('change', onChange)
25
- })
26
-
27
- return matches
28
- }