@pyreon/kinetic 0.24.5 → 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.
- package/package.json +10 -12
- package/src/Collapse.tsx +0 -166
- package/src/Stagger.tsx +0 -63
- package/src/Transition.tsx +0 -280
- package/src/TransitionGroup.tsx +0 -139
- package/src/__tests__/Collapse.test.tsx +0 -803
- package/src/__tests__/GroupRenderer.test.tsx +0 -434
- package/src/__tests__/StaggerRenderer.test.tsx +0 -523
- package/src/__tests__/Transition.ssr.test.tsx +0 -183
- package/src/__tests__/Transition.test.tsx +0 -403
- package/src/__tests__/TransitionItem.test.tsx +0 -514
- package/src/__tests__/kinetic-modes.ssr.test.tsx +0 -214
- package/src/__tests__/kinetic.browser.test.tsx +0 -327
- package/src/__tests__/kinetic.test.tsx +0 -565
- package/src/__tests__/presets.test.ts +0 -46
- package/src/__tests__/stagger-component-children-hydration.test.tsx +0 -191
- package/src/__tests__/top-level-transition-stagger-function-children.test.tsx +0 -141
- package/src/__tests__/useAnimationEnd.test.ts +0 -194
- package/src/__tests__/useReducedMotion.test.ts +0 -160
- package/src/__tests__/useTransitionState.test.ts +0 -132
- package/src/__tests__/utils.test.ts +0 -139
- package/src/index.ts +0 -15
- package/src/jsx-augment.d.ts +0 -12
- package/src/kinetic/CollapseRenderer.tsx +0 -216
- package/src/kinetic/GroupRenderer.tsx +0 -149
- package/src/kinetic/StaggerRenderer.tsx +0 -94
- package/src/kinetic/TransitionItem.tsx +0 -250
- package/src/kinetic/TransitionRenderer.tsx +0 -230
- package/src/kinetic/createKineticComponent.tsx +0 -224
- package/src/kinetic/types.ts +0 -149
- package/src/kinetic.ts +0 -25
- package/src/presets.ts +0 -66
- package/src/types.ts +0 -118
- package/src/useAnimationEnd.ts +0 -59
- package/src/useReducedMotion.ts +0 -28
- package/src/useTransitionState.ts +0 -62
- package/src/utils.ts +0 -113
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { createRef } from '@pyreon/core'
|
|
2
|
-
import { runUntracked, signal, watch } from '@pyreon/reactivity'
|
|
3
|
-
import type { TransitionStage, TransitionStateResult } from './types'
|
|
4
|
-
|
|
5
|
-
export type UseTransitionState = (options: {
|
|
6
|
-
show: () => boolean
|
|
7
|
-
appear?: boolean | undefined
|
|
8
|
-
}) => TransitionStateResult
|
|
9
|
-
|
|
10
|
-
const useTransitionState: UseTransitionState = ({ show, appear = false }) => {
|
|
11
|
-
const initialShow = show()
|
|
12
|
-
// When appear=true and show starts true, mount the element (stage='entered')
|
|
13
|
-
// but defer the enter animation until the ref is connected.
|
|
14
|
-
const needsAppear = appear && initialShow
|
|
15
|
-
const stage = signal<TransitionStage>(initialShow ? 'entered' : 'hidden')
|
|
16
|
-
const elementRef = createRef<HTMLElement>()
|
|
17
|
-
let isInitialMount = true
|
|
18
|
-
let appearTriggered = false
|
|
19
|
-
|
|
20
|
-
// Ref callback that triggers the appear animation once the element is wired
|
|
21
|
-
const refCallback = (node: HTMLElement | null) => {
|
|
22
|
-
elementRef.current = node
|
|
23
|
-
if (node && needsAppear && !appearTriggered) {
|
|
24
|
-
appearTriggered = true
|
|
25
|
-
stage.set('entering')
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
watch(
|
|
30
|
-
show,
|
|
31
|
-
(showVal) => {
|
|
32
|
-
if (isInitialMount) {
|
|
33
|
-
isInitialMount = false
|
|
34
|
-
// appear case is handled by refCallback above
|
|
35
|
-
return
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const currentStage = runUntracked(() => stage())
|
|
39
|
-
if (showVal && (currentStage === 'hidden' || currentStage === 'leaving')) {
|
|
40
|
-
stage.set('entering')
|
|
41
|
-
} else if (!showVal && (currentStage === 'entered' || currentStage === 'entering')) {
|
|
42
|
-
stage.set('leaving')
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
{ immediate: true },
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
const complete = () => {
|
|
49
|
-
const current = stage()
|
|
50
|
-
if (current === 'entering') stage.set('entered')
|
|
51
|
-
if (current === 'leaving') stage.set('hidden')
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return {
|
|
55
|
-
stage,
|
|
56
|
-
ref: refCallback,
|
|
57
|
-
shouldMount: () => stage() !== 'hidden',
|
|
58
|
-
complete,
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export default useTransitionState
|
package/src/utils.ts
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import type { Ref, VNode } from '@pyreon/core'
|
|
2
|
-
import type { CSSProperties } from './types'
|
|
3
|
-
|
|
4
|
-
const splitCache = new Map<string, string[]>()
|
|
5
|
-
const splitClasses = (classes: string): string[] => {
|
|
6
|
-
let cached = splitCache.get(classes)
|
|
7
|
-
if (!cached) {
|
|
8
|
-
cached = classes.split(/\s+/).filter(Boolean)
|
|
9
|
-
splitCache.set(classes, cached)
|
|
10
|
-
}
|
|
11
|
-
return cached
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/** Adds space-separated CSS classes to an element. */
|
|
15
|
-
export const addClasses = (el: HTMLElement, classes: string | undefined) => {
|
|
16
|
-
if (!classes) return
|
|
17
|
-
const list = splitClasses(classes)
|
|
18
|
-
if (list.length > 0) el.classList.add(...list)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/** Removes space-separated CSS classes from an element. */
|
|
22
|
-
export const removeClasses = (el: HTMLElement, classes: string | undefined) => {
|
|
23
|
-
if (!classes) return
|
|
24
|
-
const list = splitClasses(classes)
|
|
25
|
-
if (list.length > 0) el.classList.remove(...list)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Executes callback after two animation frames (double-rAF).
|
|
30
|
-
* Ensures the browser paints the current state before applying changes,
|
|
31
|
-
* which is required for CSS transitions to trigger. Returns 0 on SSR —
|
|
32
|
-
* the typeof-window guard makes the SSR-safety contract explicit (callers
|
|
33
|
-
* are always browser-only via `onMount`, but the rule can't AST-trace it).
|
|
34
|
-
*/
|
|
35
|
-
export const nextFrame = (callback: () => void): number => {
|
|
36
|
-
if (typeof requestAnimationFrame === 'undefined') return 0
|
|
37
|
-
return requestAnimationFrame(() => {
|
|
38
|
-
requestAnimationFrame(callback)
|
|
39
|
-
})
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/** Merges two className strings, filtering undefined/empty. */
|
|
43
|
-
export const mergeClassNames = (
|
|
44
|
-
existing: string | undefined,
|
|
45
|
-
additional: string | undefined,
|
|
46
|
-
): string | undefined => {
|
|
47
|
-
const parts = [existing, additional].filter(Boolean)
|
|
48
|
-
return parts.length > 0 ? parts.join(' ') : undefined
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/** Merges two CSSProperties objects, with `b` taking precedence. */
|
|
52
|
-
export const mergeStyles = (
|
|
53
|
-
a: CSSProperties | undefined,
|
|
54
|
-
b: CSSProperties | undefined,
|
|
55
|
-
): CSSProperties | undefined => {
|
|
56
|
-
if (!a && !b) return undefined
|
|
57
|
-
if (!a) return b
|
|
58
|
-
if (!b) return a
|
|
59
|
-
return { ...a, ...b }
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// ─── Ref & Motion Utilities ─────────────────────────────────
|
|
63
|
-
|
|
64
|
-
type RefCallback<T> = (node: T | null) => void
|
|
65
|
-
type RefLike<T> = RefCallback<T> | Ref<T>
|
|
66
|
-
|
|
67
|
-
/** Merges multiple refs (callback or object) into a single callback ref. */
|
|
68
|
-
export const mergeRefs = <T>(...refs: (RefLike<T> | undefined)[]): ((node: T | null) => void) => {
|
|
69
|
-
return (node: T | null) => {
|
|
70
|
-
for (const ref of refs) {
|
|
71
|
-
if (!ref) continue
|
|
72
|
-
if (typeof ref === 'function') {
|
|
73
|
-
ref(node)
|
|
74
|
-
} else {
|
|
75
|
-
;(ref as { current: unknown }).current = node
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/** Clones a VNode with merged props. */
|
|
82
|
-
export const cloneVNode = (vnode: VNode, extraProps: Record<string, unknown>): VNode => ({
|
|
83
|
-
...vnode,
|
|
84
|
-
props: { ...vnode.props, ...extraProps },
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Resolves a `children` value the Pyreon compiler may have wrapped in a
|
|
89
|
-
* deferred accessor.
|
|
90
|
-
*
|
|
91
|
-
* **Why:** the compiler's prop-inlining pass rewrites `<Comp>{children}</Comp>`
|
|
92
|
-
* to `Comp({ ..., children: () => <inlined-expression> })` whenever
|
|
93
|
-
* `children` is a local `const` derived from a getter-shaped binding
|
|
94
|
-
* (`const children = childHolder.children` after `splitProps`). DOM-side
|
|
95
|
-
* consumers route through `mountChild` which already treats function
|
|
96
|
-
* children as reactive accessors, so the wrap is invisible there. Kinetic's
|
|
97
|
-
* Stagger/Group/Transition/Collapse renderers iterate `children` directly
|
|
98
|
-
* at the VNode level (to build per-child `TransitionItem`s), so a wrapped
|
|
99
|
-
* function landed in `Array.isArray(children) ? children : [children]` as
|
|
100
|
-
* `[function]` → `.filter(isVNode)` → `[]` → the rendered `<div>` had zero
|
|
101
|
-
* children → SSR content vanished post-hydration. Reproducer:
|
|
102
|
-
* `examples/bokisch.com`'s Intro section with `kinetic('div').stagger()`
|
|
103
|
-
* + `appear` + `show={() => true}` + component children → SSG HTML had
|
|
104
|
-
* `<h1>Hello</h1>`, post-hydrate the entire subtree was replaced by
|
|
105
|
-
* `<!--pyreon-->` markers.
|
|
106
|
-
*
|
|
107
|
-
* Kinetic deliberately snapshots children at render time (animation state
|
|
108
|
-
* is per-item, built once) — it does NOT observe children changes after
|
|
109
|
-
* the initial render. Eagerly unwrapping the function matches that
|
|
110
|
-
* contract; no reactivity is lost.
|
|
111
|
-
*/
|
|
112
|
-
export const resolveChildren = <T>(children: T | (() => T)): T =>
|
|
113
|
-
(typeof children === 'function' ? (children as () => T)() : children) as T
|