@humanspeak/svelte-motion 0.4.3 → 0.4.5
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 +23 -0
- package/dist/components/layoutScroll.context.d.ts +36 -0
- package/dist/components/layoutScroll.context.js +32 -0
- package/dist/components/variantContext.context.d.ts +20 -0
- package/dist/components/variantContext.context.js +25 -0
- package/dist/html/_MotionContainer.svelte +98 -12
- package/dist/types.d.ts +47 -1
- package/dist/utils/layout.d.ts +24 -2
- package/dist/utils/layout.js +38 -3
- package/dist/utils/variants.d.ts +35 -41
- package/dist/utils/variants.js +42 -45
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -214,6 +214,29 @@ Supported drag props:
|
|
|
214
214
|
|
|
215
215
|
- String variant keys are resolved from `variants`.
|
|
216
216
|
- Variant state inherits through context.
|
|
217
|
+
- A variant entry can be a `(custom) => keyframes` factory. The `custom` prop is forwarded — useful for staggered lists where each child needs its own offset or delay. Children without `custom` inherit the nearest motion ancestor's value.
|
|
218
|
+
|
|
219
|
+
```svelte
|
|
220
|
+
<script lang="ts">
|
|
221
|
+
import { motion, type Variants } from '@humanspeak/svelte-motion'
|
|
222
|
+
|
|
223
|
+
const variants: Variants = {
|
|
224
|
+
hidden: { opacity: 0, x: -100 },
|
|
225
|
+
visible: (i) => ({
|
|
226
|
+
opacity: 1,
|
|
227
|
+
x: 0,
|
|
228
|
+
transition: { delay: (i as number) * 0.1 }
|
|
229
|
+
})
|
|
230
|
+
}
|
|
231
|
+
const items = ['Alpha', 'Beta', 'Gamma', 'Delta']
|
|
232
|
+
</script>
|
|
233
|
+
|
|
234
|
+
{#each items as item, i}
|
|
235
|
+
<motion.li custom={i} {variants} initial="hidden" animate="visible">
|
|
236
|
+
{item}
|
|
237
|
+
</motion.li>
|
|
238
|
+
{/each}
|
|
239
|
+
```
|
|
217
240
|
|
|
218
241
|
## Layout animation
|
|
219
242
|
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deferred references to the chain of `layoutScroll` ancestors for the
|
|
3
|
+
* current subtree. Returned as a thunk because element refs are bound
|
|
4
|
+
* after mount; consumers invoke at measurement time.
|
|
5
|
+
*
|
|
6
|
+
* Order is closest-first. Order doesn't matter for the current scroll-
|
|
7
|
+
* offset sum, but is preserved so future per-container semantics (e.g.
|
|
8
|
+
* a `scroll.wasRoot` marker like framer-motion) can iterate deterministically.
|
|
9
|
+
*/
|
|
10
|
+
export type LayoutScrollContainerRef = () => Array<HTMLElement | null | undefined>;
|
|
11
|
+
/**
|
|
12
|
+
* Publish the scroll-container chain for descendant motion components.
|
|
13
|
+
*
|
|
14
|
+
* Called on a `motion.*` component with `layoutScroll` enabled during
|
|
15
|
+
* its init phase. The provided thunk should resolve to `[...ancestorChain,
|
|
16
|
+
* ownElement]` — descendants get the full chain in one call.
|
|
17
|
+
*
|
|
18
|
+
* Mirrors framer-motion's `removeElementScroll`, which walks the path
|
|
19
|
+
* and sums every `layoutScroll` ancestor's offset.
|
|
20
|
+
*
|
|
21
|
+
* @param ref Thunk returning the full ancestor chain (closest first).
|
|
22
|
+
*/
|
|
23
|
+
export declare const setLayoutScrollContainer: (ref: LayoutScrollContainerRef) => void;
|
|
24
|
+
/**
|
|
25
|
+
* Capture the ancestor chain thunk at component init.
|
|
26
|
+
*
|
|
27
|
+
* Important: call this **before** the same component calls
|
|
28
|
+
* `setLayoutScrollContainer(...)`. Otherwise the lookup returns the
|
|
29
|
+
* component's own thunk (Svelte `setContext` shadows from the call site
|
|
30
|
+
* down) and the chain collapses.
|
|
31
|
+
*
|
|
32
|
+
* Returns `undefined` when no ancestor has `layoutScroll`.
|
|
33
|
+
*
|
|
34
|
+
* @returns Ancestor chain thunk, or `undefined`.
|
|
35
|
+
*/
|
|
36
|
+
export declare const getLayoutScrollContainerRef: () => LayoutScrollContainerRef | undefined;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { getContext, setContext } from 'svelte';
|
|
2
|
+
const LAYOUT_SCROLL_CONTEXT_KEY = Symbol('layout-scroll-container');
|
|
3
|
+
/**
|
|
4
|
+
* Publish the scroll-container chain for descendant motion components.
|
|
5
|
+
*
|
|
6
|
+
* Called on a `motion.*` component with `layoutScroll` enabled during
|
|
7
|
+
* its init phase. The provided thunk should resolve to `[...ancestorChain,
|
|
8
|
+
* ownElement]` — descendants get the full chain in one call.
|
|
9
|
+
*
|
|
10
|
+
* Mirrors framer-motion's `removeElementScroll`, which walks the path
|
|
11
|
+
* and sums every `layoutScroll` ancestor's offset.
|
|
12
|
+
*
|
|
13
|
+
* @param ref Thunk returning the full ancestor chain (closest first).
|
|
14
|
+
*/
|
|
15
|
+
export const setLayoutScrollContainer = (ref) => {
|
|
16
|
+
setContext(LAYOUT_SCROLL_CONTEXT_KEY, ref);
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Capture the ancestor chain thunk at component init.
|
|
20
|
+
*
|
|
21
|
+
* Important: call this **before** the same component calls
|
|
22
|
+
* `setLayoutScrollContainer(...)`. Otherwise the lookup returns the
|
|
23
|
+
* component's own thunk (Svelte `setContext` shadows from the call site
|
|
24
|
+
* down) and the chain collapses.
|
|
25
|
+
*
|
|
26
|
+
* Returns `undefined` when no ancestor has `layoutScroll`.
|
|
27
|
+
*
|
|
28
|
+
* @returns Ancestor chain thunk, or `undefined`.
|
|
29
|
+
*/
|
|
30
|
+
export const getLayoutScrollContainerRef = () => {
|
|
31
|
+
return getContext(LAYOUT_SCROLL_CONTEXT_KEY);
|
|
32
|
+
};
|
|
@@ -25,3 +25,23 @@ export declare const setInitialFalseContext: (value: boolean) => void;
|
|
|
25
25
|
* @returns `true` if a parent set `initial={false}`, otherwise `false`.
|
|
26
26
|
*/
|
|
27
27
|
export declare const getInitialFalseContext: () => boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Provide a writable store carrying the current motion component's
|
|
30
|
+
* `custom` value so descendant motion components without their own
|
|
31
|
+
* `custom` prop can inherit it — and re-resolve their variants when the
|
|
32
|
+
* parent's `custom` changes.
|
|
33
|
+
*
|
|
34
|
+
* Mirrors framer-motion's variant-tree custom propagation. A store
|
|
35
|
+
* (rather than a snapshot) lets descendants react to changes the parent
|
|
36
|
+
* makes after mount.
|
|
37
|
+
*
|
|
38
|
+
* @param store Writable store holding the current component's effective `custom`.
|
|
39
|
+
*/
|
|
40
|
+
export declare const setCustomContext: (store: Writable<unknown>) => void;
|
|
41
|
+
/**
|
|
42
|
+
* Read the nearest ancestor's `custom` store (if any).
|
|
43
|
+
*
|
|
44
|
+
* @returns The ancestor's writable store, or `undefined` when no motion
|
|
45
|
+
* ancestor has set one.
|
|
46
|
+
*/
|
|
47
|
+
export declare const getCustomContext: () => Writable<unknown> | undefined;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getContext, setContext } from 'svelte';
|
|
2
2
|
const VARIANT_CONTEXT_KEY = Symbol('variant-context');
|
|
3
3
|
const INITIAL_FALSE_CONTEXT_KEY = Symbol('initial-false-context');
|
|
4
|
+
const CUSTOM_CONTEXT_KEY = Symbol('custom-context');
|
|
4
5
|
/**
|
|
5
6
|
* Provide a writable store for the current variant key so children can
|
|
6
7
|
* react to changes over time (true inheritance like Framer Motion).
|
|
@@ -35,3 +36,27 @@ export const setInitialFalseContext = (value) => {
|
|
|
35
36
|
export const getInitialFalseContext = () => {
|
|
36
37
|
return getContext(INITIAL_FALSE_CONTEXT_KEY) ?? false;
|
|
37
38
|
};
|
|
39
|
+
/**
|
|
40
|
+
* Provide a writable store carrying the current motion component's
|
|
41
|
+
* `custom` value so descendant motion components without their own
|
|
42
|
+
* `custom` prop can inherit it — and re-resolve their variants when the
|
|
43
|
+
* parent's `custom` changes.
|
|
44
|
+
*
|
|
45
|
+
* Mirrors framer-motion's variant-tree custom propagation. A store
|
|
46
|
+
* (rather than a snapshot) lets descendants react to changes the parent
|
|
47
|
+
* makes after mount.
|
|
48
|
+
*
|
|
49
|
+
* @param store Writable store holding the current component's effective `custom`.
|
|
50
|
+
*/
|
|
51
|
+
export const setCustomContext = (store) => {
|
|
52
|
+
setContext(CUSTOM_CONTEXT_KEY, store);
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Read the nearest ancestor's `custom` store (if any).
|
|
56
|
+
*
|
|
57
|
+
* @returns The ancestor's writable store, or `undefined` when no motion
|
|
58
|
+
* ancestor has set one.
|
|
59
|
+
*/
|
|
60
|
+
export const getCustomContext = () => {
|
|
61
|
+
return getContext(CUSTOM_CONTEXT_KEY);
|
|
62
|
+
};
|
|
@@ -53,7 +53,9 @@
|
|
|
53
53
|
setVariantContext,
|
|
54
54
|
getVariantContext,
|
|
55
55
|
setInitialFalseContext,
|
|
56
|
-
getInitialFalseContext
|
|
56
|
+
getInitialFalseContext,
|
|
57
|
+
setCustomContext,
|
|
58
|
+
getCustomContext
|
|
57
59
|
} from '../components/variantContext.context'
|
|
58
60
|
import { get, writable } from 'svelte/store'
|
|
59
61
|
import {
|
|
@@ -63,6 +65,10 @@
|
|
|
63
65
|
SVG_NAMESPACE
|
|
64
66
|
} from '../utils/svg'
|
|
65
67
|
import { getLayoutIdRegistry } from '../utils/layoutId'
|
|
68
|
+
import {
|
|
69
|
+
getLayoutScrollContainerRef,
|
|
70
|
+
setLayoutScrollContainer
|
|
71
|
+
} from '../components/layoutScroll.context'
|
|
66
72
|
|
|
67
73
|
type Props = MotionProps & {
|
|
68
74
|
children?: Snippet
|
|
@@ -75,6 +81,7 @@
|
|
|
75
81
|
tag = 'div',
|
|
76
82
|
key: keyProp,
|
|
77
83
|
variants: variantsProp,
|
|
84
|
+
custom: customProp,
|
|
78
85
|
initial: initialProp,
|
|
79
86
|
animate: animateProp,
|
|
80
87
|
exit: exitProp,
|
|
@@ -115,6 +122,7 @@
|
|
|
115
122
|
dragControls: dragControlsProp,
|
|
116
123
|
layout: layoutProp,
|
|
117
124
|
layoutId: layoutIdProp,
|
|
125
|
+
layoutScroll: layoutScrollProp,
|
|
118
126
|
ref: element = $bindable(null),
|
|
119
127
|
...rest
|
|
120
128
|
}: Props = $props()
|
|
@@ -139,6 +147,30 @@
|
|
|
139
147
|
// Get layoutId registry (provided by AnimatePresence or a parent LayoutGroup)
|
|
140
148
|
const layoutIdRegistry = getLayoutIdRegistry()
|
|
141
149
|
|
|
150
|
+
// Capture the ancestor `layoutScroll` chain BEFORE we potentially shadow
|
|
151
|
+
// the context with ourselves below — this element's own FLIP measurements
|
|
152
|
+
// must resolve against the *ancestors*' scroll containers, not against
|
|
153
|
+
// itself.
|
|
154
|
+
//
|
|
155
|
+
// We walk the full chain (not just the nearest) so a `layoutScroll`
|
|
156
|
+
// outside another `layoutScroll` still contributes to descendant
|
|
157
|
+
// measurements — matches framer-motion's `removeElementScroll` walking
|
|
158
|
+
// `this.path`.
|
|
159
|
+
const ancestorScrollContainerRef = getLayoutScrollContainerRef()
|
|
160
|
+
if (layoutScrollProp) {
|
|
161
|
+
// Publish [...ancestorChain, ownElement]. The chain is collected
|
|
162
|
+
// lazily because element refs bind after mount.
|
|
163
|
+
setLayoutScrollContainer(() => {
|
|
164
|
+
const inherited = ancestorScrollContainerRef?.() ?? []
|
|
165
|
+
return element ? [...inherited, element] : inherited
|
|
166
|
+
})
|
|
167
|
+
}
|
|
168
|
+
const resolveLayoutScrollAncestors = (): HTMLElement[] => {
|
|
169
|
+
const refs = ancestorScrollContainerRef?.() ?? []
|
|
170
|
+
// Filter out unbound refs (HTMLElement | null | undefined → HTMLElement[]).
|
|
171
|
+
return refs.filter((el): el is HTMLElement => Boolean(el))
|
|
172
|
+
}
|
|
173
|
+
|
|
142
174
|
// Get current presence depth (0 = direct child of AnimatePresence, undefined = not in AnimatePresence)
|
|
143
175
|
const presenceDepth = getPresenceDepth()
|
|
144
176
|
|
|
@@ -210,11 +242,14 @@
|
|
|
210
242
|
$effect(() => {
|
|
211
243
|
if (!(element && layoutIdProp && layoutIdRegistry)) return
|
|
212
244
|
|
|
213
|
-
// Capture rect on every frame while mounted
|
|
245
|
+
// Capture rect on every frame while mounted. Re-express in the
|
|
246
|
+
// nearest layoutScroll ancestor's coordinate space so the FLIP-from
|
|
247
|
+
// rect stored at unmount stays correct even if the scroll container
|
|
248
|
+
// moved between the snapshot and the next element's mount.
|
|
214
249
|
let rafId: number
|
|
215
250
|
const captureRect = () => {
|
|
216
251
|
if (element) {
|
|
217
|
-
layoutIdLastRect = element
|
|
252
|
+
layoutIdLastRect = measureRect(element, resolveLayoutScrollAncestors())
|
|
218
253
|
}
|
|
219
254
|
rafId = requestAnimationFrame(captureRect)
|
|
220
255
|
}
|
|
@@ -360,6 +395,32 @@
|
|
|
360
395
|
// Provide context immediately during initialization so children can inherit
|
|
361
396
|
setVariantContext(localVariantStore)
|
|
362
397
|
|
|
398
|
+
// Custom-value inheritance. Children with no `custom` prop adopt the
|
|
399
|
+
// nearest motion ancestor's value. Reactive via a writable store so a
|
|
400
|
+
// parent updating `custom` re-fires descendants' variant resolution.
|
|
401
|
+
const parentCustomStore = getCustomContext()
|
|
402
|
+
let inheritedCustom: unknown = undefined
|
|
403
|
+
if (parentCustomStore) {
|
|
404
|
+
parentCustomStore.subscribe((v) => (inheritedCustom = v))()
|
|
405
|
+
}
|
|
406
|
+
const initialCustomValue = customProp !== undefined ? customProp : inheritedCustom
|
|
407
|
+
const localCustomStore = writable<unknown>(initialCustomValue)
|
|
408
|
+
setCustomContext(localCustomStore)
|
|
409
|
+
|
|
410
|
+
let parentInheritedCustom = $state<unknown>(inheritedCustom)
|
|
411
|
+
$effect(() => {
|
|
412
|
+
if (!parentCustomStore) {
|
|
413
|
+
parentInheritedCustom = undefined
|
|
414
|
+
return
|
|
415
|
+
}
|
|
416
|
+
const unsubscribe = parentCustomStore.subscribe((v) => (parentInheritedCustom = v))
|
|
417
|
+
return () => unsubscribe()
|
|
418
|
+
})
|
|
419
|
+
const effectiveCustom = $derived(customProp !== undefined ? customProp : parentInheritedCustom)
|
|
420
|
+
$effect(() => {
|
|
421
|
+
localCustomStore.set(effectiveCustom)
|
|
422
|
+
})
|
|
423
|
+
|
|
363
424
|
$effect(() => {
|
|
364
425
|
if (!variantsProp) return localVariantStore.set(undefined)
|
|
365
426
|
if (typeof animateProp === 'string') return localVariantStore.set(animateProp)
|
|
@@ -367,9 +428,13 @@
|
|
|
367
428
|
localVariantStore.set(undefined)
|
|
368
429
|
})
|
|
369
430
|
|
|
370
|
-
const resolvedInitial = $derived(
|
|
371
|
-
|
|
372
|
-
|
|
431
|
+
const resolvedInitial = $derived(
|
|
432
|
+
resolveInitial(effectiveInitialProp, variantsProp, effectiveCustom)
|
|
433
|
+
)
|
|
434
|
+
const resolvedAnimate = $derived(
|
|
435
|
+
resolveAnimate(effectiveAnimate, variantsProp, effectiveCustom)
|
|
436
|
+
)
|
|
437
|
+
const resolvedExit = $derived(resolveExit(exitProp, variantsProp, effectiveCustom))
|
|
373
438
|
|
|
374
439
|
// Extract keyframes from resolved initial, handling initial={false}
|
|
375
440
|
const initialKeyframes = $derived(
|
|
@@ -639,6 +704,12 @@
|
|
|
639
704
|
|
|
640
705
|
// Track the last variant key we ran to avoid re-running on mount
|
|
641
706
|
let lastRanVariantKey = $state<string | undefined>(undefined)
|
|
707
|
+
// Companion to `lastRanVariantKey`: the JSON-serialized resolved
|
|
708
|
+
// keyframes for that variant. Lets us detect when a function-form
|
|
709
|
+
// variant produces new keyframes (because `custom` changed) while
|
|
710
|
+
// the variant key stayed the same — otherwise the animate effect
|
|
711
|
+
// would short-circuit and the element would never re-animate.
|
|
712
|
+
let lastRanResolvedJson = $state<string | undefined>(undefined)
|
|
642
713
|
let mountedWithInitialFalse = $state(false)
|
|
643
714
|
// Track if the initial->animate transition has already been triggered by main effect
|
|
644
715
|
let initialAnimationTriggered = $state(false)
|
|
@@ -662,17 +733,18 @@
|
|
|
662
733
|
if (!(element && layoutProp && isLoaded === 'ready')) return
|
|
663
734
|
|
|
664
735
|
// Initialize last rect on first ready frame
|
|
665
|
-
lastRect = measureRect(element
|
|
736
|
+
lastRect = measureRect(element!, resolveLayoutScrollAncestors())
|
|
666
737
|
// Hint compositor for smoother FLIP transforms
|
|
667
738
|
setCompositorHints(element!, true)
|
|
668
739
|
|
|
669
740
|
let rafId: number | null = null
|
|
670
741
|
const runFlip = () => {
|
|
742
|
+
const scrollContainers = resolveLayoutScrollAncestors()
|
|
671
743
|
if (!lastRect) {
|
|
672
|
-
lastRect = measureRect(element
|
|
744
|
+
lastRect = measureRect(element!, scrollContainers)
|
|
673
745
|
return
|
|
674
746
|
}
|
|
675
|
-
const next = measureRect(element
|
|
747
|
+
const next = measureRect(element!, scrollContainers)
|
|
676
748
|
const transforms = computeFlipTransforms(lastRect, next, layoutProp ?? false)
|
|
677
749
|
runFlipAnimation(element!, transforms, (mergedTransition ?? {}) as AnimationOptions)
|
|
678
750
|
lastRect = next
|
|
@@ -706,7 +778,7 @@
|
|
|
706
778
|
const prev = layoutIdRegistry.consume(layoutIdProp)
|
|
707
779
|
if (!prev) return // First appearance, no animation needed
|
|
708
780
|
|
|
709
|
-
const next = measureRect(element)
|
|
781
|
+
const next = measureRect(element, resolveLayoutScrollAncestors())
|
|
710
782
|
const transforms = computeFlipTransforms(prev.rect, next, true)
|
|
711
783
|
|
|
712
784
|
setCompositorHints(element, true)
|
|
@@ -916,8 +988,14 @@
|
|
|
916
988
|
return
|
|
917
989
|
}
|
|
918
990
|
if (typeof animateProp === 'string') {
|
|
919
|
-
|
|
991
|
+
// Compare BOTH the variant key and the resolved keyframes JSON.
|
|
992
|
+
// For static variants the JSON is constant per key; for
|
|
993
|
+
// function-form variants the JSON changes when `custom`
|
|
994
|
+
// changes, which we must treat as a new animation target.
|
|
995
|
+
const resolvedJson = resolvedAnimate ? JSON.stringify(resolvedAnimate) : undefined
|
|
996
|
+
if (lastRanVariantKey !== animateProp || lastRanResolvedJson !== resolvedJson) {
|
|
920
997
|
lastRanVariantKey = animateProp
|
|
998
|
+
lastRanResolvedJson = resolvedJson
|
|
921
999
|
runAnimation()
|
|
922
1000
|
}
|
|
923
1001
|
} else if (animateProp) {
|
|
@@ -956,8 +1034,10 @@
|
|
|
956
1034
|
mountedWithInitialFalse = false
|
|
957
1035
|
}
|
|
958
1036
|
if (typeof currentAnimateKey === 'string') {
|
|
959
|
-
|
|
1037
|
+
const resolvedJson = resolvedAnimate ? JSON.stringify(resolvedAnimate) : undefined
|
|
1038
|
+
if (lastRanVariantKey !== currentAnimateKey || lastRanResolvedJson !== resolvedJson) {
|
|
960
1039
|
lastRanVariantKey = currentAnimateKey
|
|
1040
|
+
lastRanResolvedJson = resolvedJson
|
|
961
1041
|
runAnimation()
|
|
962
1042
|
}
|
|
963
1043
|
} else {
|
|
@@ -989,6 +1069,9 @@
|
|
|
989
1069
|
mountedWithInitialFalse = true
|
|
990
1070
|
if (typeof currentAnimateKey === 'string') {
|
|
991
1071
|
lastRanVariantKey = currentAnimateKey
|
|
1072
|
+
lastRanResolvedJson = resolvedAnimate
|
|
1073
|
+
? JSON.stringify(resolvedAnimate)
|
|
1074
|
+
: undefined
|
|
992
1075
|
}
|
|
993
1076
|
dataPath = 5
|
|
994
1077
|
isLoaded = 'ready'
|
|
@@ -1081,6 +1164,9 @@
|
|
|
1081
1164
|
snapshot = transformSVGPathProperties(element!, snapshot)
|
|
1082
1165
|
animate(element!, snapshot as DOMKeyframesDefinition, { duration: 0 })
|
|
1083
1166
|
lastRanVariantKey = currentAnimateKey
|
|
1167
|
+
lastRanResolvedJson = resolvedAnimate
|
|
1168
|
+
? JSON.stringify(resolvedAnimate)
|
|
1169
|
+
: undefined
|
|
1084
1170
|
} else {
|
|
1085
1171
|
runAnimation()
|
|
1086
1172
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,8 +1,32 @@
|
|
|
1
1
|
import type { AnimationOptions, DOMKeyframesDefinition } from 'motion';
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
|
+
/**
|
|
4
|
+
* A variant value: either a static keyframes object, or a factory function
|
|
5
|
+
* that receives the consumer-provided `custom` value and returns keyframes.
|
|
6
|
+
*
|
|
7
|
+
* Dynamic (function-form) variants let a single variants object emit
|
|
8
|
+
* per-instance keyframes — common for staggered lists where each child
|
|
9
|
+
* needs its own offset or delay.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```svelte
|
|
13
|
+
* <motion.div
|
|
14
|
+
* custom={index}
|
|
15
|
+
* variants={{
|
|
16
|
+
* visible: (i) => ({ opacity: 1, x: i * 50 }),
|
|
17
|
+
* hidden: { opacity: 0 }
|
|
18
|
+
* }}
|
|
19
|
+
* animate="visible"
|
|
20
|
+
* />
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export type Variant = DOMKeyframesDefinition | ((custom: unknown) => DOMKeyframesDefinition) | undefined;
|
|
3
24
|
/**
|
|
4
25
|
* Variants define named animation states that can be referenced by string keys.
|
|
5
26
|
*
|
|
27
|
+
* Each entry can be a static keyframes object or a `(custom) => keyframes`
|
|
28
|
+
* factory function (see {@link Variant}).
|
|
29
|
+
*
|
|
6
30
|
* @example
|
|
7
31
|
* ```svelte
|
|
8
32
|
* <script>
|
|
@@ -15,7 +39,7 @@ import type { Snippet } from 'svelte';
|
|
|
15
39
|
* <motion.div variants={variants} animate="open" />
|
|
16
40
|
* ```
|
|
17
41
|
*/
|
|
18
|
-
export type Variants = Record<string,
|
|
42
|
+
export type Variants = Record<string, Variant>;
|
|
19
43
|
/**
|
|
20
44
|
* Initial animation properties for a motion component.
|
|
21
45
|
*
|
|
@@ -245,6 +269,12 @@ export type MotionProps = {
|
|
|
245
269
|
key?: string;
|
|
246
270
|
/** Variants define named animation states */
|
|
247
271
|
variants?: Variants;
|
|
272
|
+
/**
|
|
273
|
+
* Value passed into function-form variants. Children without their own
|
|
274
|
+
* `custom` prop inherit this from the nearest motion ancestor — matching
|
|
275
|
+
* framer-motion's variant-tree custom propagation.
|
|
276
|
+
*/
|
|
277
|
+
custom?: unknown;
|
|
248
278
|
/** Initial state of the animation (object or variant key) */
|
|
249
279
|
initial?: MotionInitial;
|
|
250
280
|
/** Target state of the animation (object or variant key) */
|
|
@@ -305,6 +335,22 @@ export type MotionProps = {
|
|
|
305
335
|
layout?: boolean | 'position';
|
|
306
336
|
/** Shared layout animation identifier. Elements with matching layoutId animate between positions. */
|
|
307
337
|
layoutId?: string;
|
|
338
|
+
/**
|
|
339
|
+
* Mark this element as a scroll container so descendant `layout` animations
|
|
340
|
+
* measure rects in this container's coordinate space. Without it, scrolling
|
|
341
|
+
* mid-animation makes the FLIP transform fight the scroll and the layout
|
|
342
|
+
* animation drifts.
|
|
343
|
+
*
|
|
344
|
+
* Apply on the same element as `overflow: scroll` / `overflow: auto`.
|
|
345
|
+
*
|
|
346
|
+
* @example
|
|
347
|
+
* ```svelte
|
|
348
|
+
* <motion.div layoutScroll style="overflow: auto">
|
|
349
|
+
* <motion.div layout />
|
|
350
|
+
* </motion.div>
|
|
351
|
+
* ```
|
|
352
|
+
*/
|
|
353
|
+
layoutScroll?: boolean;
|
|
308
354
|
/** Ref to the element */
|
|
309
355
|
ref?: HTMLElement | null;
|
|
310
356
|
/** Enable drag gestures. true for both axes, or lock to 'x'/'y'. */
|
package/dist/utils/layout.d.ts
CHANGED
|
@@ -5,10 +5,32 @@ import { type AnimationOptions } from 'motion';
|
|
|
5
5
|
* Temporarily clears `transform` to avoid skewing measurements, restoring it
|
|
6
6
|
* immediately after reading the rect.
|
|
7
7
|
*
|
|
8
|
+
* When `scrollContainers` are provided, the returned rect is shifted by the
|
|
9
|
+
* **sum** of each container's `scrollLeft` / `scrollTop`. FLIP deltas
|
|
10
|
+
* computed from two such measures stay correct even when the user scrolls
|
|
11
|
+
* any of the containers between measurements — including a nested
|
|
12
|
+
* `layoutScroll` inside another `layoutScroll`. Mirrors framer-motion's
|
|
13
|
+
* `removeElementScroll`, which walks every ancestor in the path.
|
|
14
|
+
*
|
|
15
|
+
* Pass an empty array (or omit) for viewport-relative behaviour.
|
|
16
|
+
*
|
|
8
17
|
* @param el Element to measure.
|
|
9
|
-
* @
|
|
18
|
+
* @param scrollContainers Optional ancestor chain with `layoutScroll` enabled.
|
|
19
|
+
* @returns DOMRect snapshot of the element.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* // No scroll containers — viewport-relative rect.
|
|
24
|
+
* const rect = measureRect(node)
|
|
25
|
+
*
|
|
26
|
+
* // Single ancestor scroll container (one `layoutScroll`).
|
|
27
|
+
* const rect = measureRect(node, [scrollPanel])
|
|
28
|
+
*
|
|
29
|
+
* // Nested `layoutScroll` ancestors — sums offsets from every container.
|
|
30
|
+
* const rect = measureRect(node, [innerScroll, outerScroll])
|
|
31
|
+
* ```
|
|
10
32
|
*/
|
|
11
|
-
export declare const measureRect: (el: HTMLElement) => DOMRect;
|
|
33
|
+
export declare const measureRect: (el: HTMLElement, scrollContainers?: HTMLElement[]) => DOMRect;
|
|
12
34
|
/**
|
|
13
35
|
* Compute FLIP transform deltas between two rects.
|
|
14
36
|
*
|
package/dist/utils/layout.js
CHANGED
|
@@ -5,14 +5,49 @@ import { animate } from 'motion';
|
|
|
5
5
|
* Temporarily clears `transform` to avoid skewing measurements, restoring it
|
|
6
6
|
* immediately after reading the rect.
|
|
7
7
|
*
|
|
8
|
+
* When `scrollContainers` are provided, the returned rect is shifted by the
|
|
9
|
+
* **sum** of each container's `scrollLeft` / `scrollTop`. FLIP deltas
|
|
10
|
+
* computed from two such measures stay correct even when the user scrolls
|
|
11
|
+
* any of the containers between measurements — including a nested
|
|
12
|
+
* `layoutScroll` inside another `layoutScroll`. Mirrors framer-motion's
|
|
13
|
+
* `removeElementScroll`, which walks every ancestor in the path.
|
|
14
|
+
*
|
|
15
|
+
* Pass an empty array (or omit) for viewport-relative behaviour.
|
|
16
|
+
*
|
|
8
17
|
* @param el Element to measure.
|
|
9
|
-
* @
|
|
18
|
+
* @param scrollContainers Optional ancestor chain with `layoutScroll` enabled.
|
|
19
|
+
* @returns DOMRect snapshot of the element.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* // No scroll containers — viewport-relative rect.
|
|
24
|
+
* const rect = measureRect(node)
|
|
25
|
+
*
|
|
26
|
+
* // Single ancestor scroll container (one `layoutScroll`).
|
|
27
|
+
* const rect = measureRect(node, [scrollPanel])
|
|
28
|
+
*
|
|
29
|
+
* // Nested `layoutScroll` ancestors — sums offsets from every container.
|
|
30
|
+
* const rect = measureRect(node, [innerScroll, outerScroll])
|
|
31
|
+
* ```
|
|
10
32
|
*/
|
|
11
|
-
export const measureRect = (el) => {
|
|
33
|
+
export const measureRect = (el, scrollContainers) => {
|
|
12
34
|
const prev = el.style.transform;
|
|
13
35
|
try {
|
|
14
36
|
el.style.transform = 'none';
|
|
15
|
-
|
|
37
|
+
const rect = el.getBoundingClientRect();
|
|
38
|
+
if (!scrollContainers || scrollContainers.length === 0)
|
|
39
|
+
return rect;
|
|
40
|
+
// Re-express the rect in the *combined* scroll-container coordinate
|
|
41
|
+
// space so a subsequent scroll on any of them doesn't show up as
|
|
42
|
+
// movement. DOMRect's left/top are read-only, so allocate a fresh
|
|
43
|
+
// one with the summed offsets applied.
|
|
44
|
+
let offsetLeft = 0;
|
|
45
|
+
let offsetTop = 0;
|
|
46
|
+
for (const container of scrollContainers) {
|
|
47
|
+
offsetLeft += container.scrollLeft;
|
|
48
|
+
offsetTop += container.scrollTop;
|
|
49
|
+
}
|
|
50
|
+
return new DOMRect(rect.left + offsetLeft, rect.top + offsetTop, rect.width, rect.height);
|
|
16
51
|
}
|
|
17
52
|
finally {
|
|
18
53
|
el.style.transform = prev;
|
package/dist/utils/variants.d.ts
CHANGED
|
@@ -3,80 +3,74 @@ import type { DOMKeyframesDefinition } from 'motion';
|
|
|
3
3
|
/**
|
|
4
4
|
* Resolves a variant key to its keyframes definition.
|
|
5
5
|
*
|
|
6
|
-
* Looks up
|
|
7
|
-
*
|
|
6
|
+
* Looks up `key` in `variants`. When the entry is a function (dynamic
|
|
7
|
+
* variant), it's invoked with `custom` to produce keyframes — matching
|
|
8
|
+
* framer-motion's per-instance variant pattern.
|
|
8
9
|
*
|
|
9
10
|
* @param variants - The variants object containing named animation states.
|
|
10
11
|
* @param key - The variant key to look up.
|
|
11
|
-
* @
|
|
12
|
+
* @param custom - Value forwarded to function-form variants. Pass-through
|
|
13
|
+
* `undefined` when no `custom` is in scope; the dynamic variant itself
|
|
14
|
+
* decides how to handle the absent input.
|
|
15
|
+
* @returns The keyframes definition for the variant, or `undefined` if the
|
|
16
|
+
* key is missing.
|
|
12
17
|
*
|
|
13
18
|
* @example
|
|
14
|
-
* ```
|
|
19
|
+
* ```ts
|
|
15
20
|
* const variants = {
|
|
16
|
-
* visible: {
|
|
17
|
-
* hidden:
|
|
21
|
+
* visible: (i: number) => ({ x: i * 50 }),
|
|
22
|
+
* hidden: { opacity: 0 }
|
|
18
23
|
* }
|
|
19
|
-
* resolveVariant(variants, 'visible') // {
|
|
20
|
-
* resolveVariant(variants, '
|
|
21
|
-
* resolveVariant(undefined, 'visible')
|
|
24
|
+
* resolveVariant(variants, 'visible', 3) // { x: 150 }
|
|
25
|
+
* resolveVariant(variants, 'hidden') // { opacity: 0 }
|
|
26
|
+
* resolveVariant(undefined, 'visible') // undefined
|
|
22
27
|
* ```
|
|
23
28
|
*/
|
|
24
|
-
export declare const resolveVariant: (variants: Variants | undefined, key: string | undefined) => DOMKeyframesDefinition | undefined;
|
|
29
|
+
export declare const resolveVariant: (variants: Variants | undefined, key: string | undefined, custom?: unknown) => DOMKeyframesDefinition | undefined;
|
|
25
30
|
/**
|
|
26
31
|
* Resolves the initial prop to keyframes, handling variant keys and `initial={false}`.
|
|
27
32
|
*
|
|
28
|
-
* When `initial` is a string, looks it up in the variants object
|
|
29
|
-
*
|
|
33
|
+
* When `initial` is a string, looks it up in the variants object (invoking
|
|
34
|
+
* dynamic variants with `custom`). When `initial={false}`, returns `false` to
|
|
35
|
+
* skip the initial animation. Otherwise returns the keyframes directly.
|
|
30
36
|
*
|
|
31
37
|
* @param initial - The initial prop value (keyframes, variant key, false, or undefined).
|
|
32
38
|
* @param variants - The variants object for resolving string keys.
|
|
39
|
+
* @param custom - Forwarded to function-form variants.
|
|
33
40
|
* @returns Keyframes definition, `false` to skip animation, or undefined.
|
|
34
41
|
*
|
|
35
42
|
* @example
|
|
36
|
-
* ```
|
|
37
|
-
* const variants = { hidden: {
|
|
38
|
-
* resolveInitial('hidden', variants)
|
|
39
|
-
* resolveInitial({ x: 0 }, variants)
|
|
40
|
-
* resolveInitial(false, variants)
|
|
41
|
-
* resolveInitial(undefined, variants)
|
|
43
|
+
* ```ts
|
|
44
|
+
* const variants = { hidden: (i: number) => ({ x: -i * 100 }) }
|
|
45
|
+
* resolveInitial('hidden', variants, 2) // { x: -200 }
|
|
46
|
+
* resolveInitial({ x: 0 }, variants) // { x: 0 }
|
|
47
|
+
* resolveInitial(false, variants) // false
|
|
48
|
+
* resolveInitial(undefined, variants) // undefined
|
|
42
49
|
* ```
|
|
43
50
|
*/
|
|
44
|
-
export declare const resolveInitial: (initial: MotionInitial, variants: Variants | undefined) => DOMKeyframesDefinition | false | undefined;
|
|
51
|
+
export declare const resolveInitial: (initial: MotionInitial, variants: Variants | undefined, custom?: unknown) => DOMKeyframesDefinition | false | undefined;
|
|
45
52
|
/**
|
|
46
53
|
* Resolves the animate prop to keyframes, handling variant keys.
|
|
47
54
|
*
|
|
48
|
-
* When `animate` is a string, looks it up in the variants object
|
|
49
|
-
* Otherwise returns the keyframes directly.
|
|
55
|
+
* When `animate` is a string, looks it up in the variants object (invoking
|
|
56
|
+
* dynamic variants with `custom`). Otherwise returns the keyframes directly.
|
|
50
57
|
*
|
|
51
58
|
* @param animate - The animate prop value (keyframes, variant key, or undefined).
|
|
52
59
|
* @param variants - The variants object for resolving string keys.
|
|
60
|
+
* @param custom - Forwarded to function-form variants.
|
|
53
61
|
* @returns Keyframes definition or undefined.
|
|
54
|
-
*
|
|
55
|
-
* @example
|
|
56
|
-
* ```typescript
|
|
57
|
-
* const variants = { visible: { opacity: 1 } }
|
|
58
|
-
* resolveAnimate('visible', variants) // { opacity: 1 }
|
|
59
|
-
* resolveAnimate({ scale: 1.2 }, variants) // { scale: 1.2 }
|
|
60
|
-
* resolveAnimate(undefined, variants) // undefined
|
|
61
|
-
* ```
|
|
62
62
|
*/
|
|
63
|
-
export declare const resolveAnimate: (animate: MotionAnimate, variants: Variants | undefined) => DOMKeyframesDefinition | undefined;
|
|
63
|
+
export declare const resolveAnimate: (animate: MotionAnimate, variants: Variants | undefined, custom?: unknown) => DOMKeyframesDefinition | undefined;
|
|
64
64
|
/**
|
|
65
65
|
* Resolves the exit prop to keyframes, handling variant keys.
|
|
66
66
|
*
|
|
67
|
-
* When `exit` is a string, looks it up in the variants object
|
|
68
|
-
* Otherwise returns the keyframes directly.
|
|
67
|
+
* When `exit` is a string, looks it up in the variants object (invoking
|
|
68
|
+
* dynamic variants with `custom`). Otherwise returns the keyframes directly.
|
|
69
|
+
* Used by AnimatePresence for exit animations.
|
|
69
70
|
*
|
|
70
71
|
* @param exit - The exit prop value (keyframes, variant key, or undefined).
|
|
71
72
|
* @param variants - The variants object for resolving string keys.
|
|
73
|
+
* @param custom - Forwarded to function-form variants.
|
|
72
74
|
* @returns Keyframes definition or undefined.
|
|
73
|
-
*
|
|
74
|
-
* @example
|
|
75
|
-
* ```typescript
|
|
76
|
-
* const variants = { hidden: { opacity: 0 } }
|
|
77
|
-
* resolveExit('hidden', variants) // { opacity: 0 }
|
|
78
|
-
* resolveExit({ y: -100 }, variants) // { y: -100 }
|
|
79
|
-
* resolveExit(undefined, variants) // undefined
|
|
80
|
-
* ```
|
|
81
75
|
*/
|
|
82
|
-
export declare const resolveExit: (exit: MotionExit, variants: Variants | undefined) => DOMKeyframesDefinition | undefined;
|
|
76
|
+
export declare const resolveExit: (exit: MotionExit, variants: Variants | undefined, custom?: unknown) => DOMKeyframesDefinition | undefined;
|
package/dist/utils/variants.js
CHANGED
|
@@ -1,104 +1,101 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Resolves a variant key to its keyframes definition.
|
|
3
3
|
*
|
|
4
|
-
* Looks up
|
|
5
|
-
*
|
|
4
|
+
* Looks up `key` in `variants`. When the entry is a function (dynamic
|
|
5
|
+
* variant), it's invoked with `custom` to produce keyframes — matching
|
|
6
|
+
* framer-motion's per-instance variant pattern.
|
|
6
7
|
*
|
|
7
8
|
* @param variants - The variants object containing named animation states.
|
|
8
9
|
* @param key - The variant key to look up.
|
|
9
|
-
* @
|
|
10
|
+
* @param custom - Value forwarded to function-form variants. Pass-through
|
|
11
|
+
* `undefined` when no `custom` is in scope; the dynamic variant itself
|
|
12
|
+
* decides how to handle the absent input.
|
|
13
|
+
* @returns The keyframes definition for the variant, or `undefined` if the
|
|
14
|
+
* key is missing.
|
|
10
15
|
*
|
|
11
16
|
* @example
|
|
12
|
-
* ```
|
|
17
|
+
* ```ts
|
|
13
18
|
* const variants = {
|
|
14
|
-
* visible: {
|
|
15
|
-
* hidden:
|
|
19
|
+
* visible: (i: number) => ({ x: i * 50 }),
|
|
20
|
+
* hidden: { opacity: 0 }
|
|
16
21
|
* }
|
|
17
|
-
* resolveVariant(variants, 'visible') // {
|
|
18
|
-
* resolveVariant(variants, '
|
|
19
|
-
* resolveVariant(undefined, 'visible')
|
|
22
|
+
* resolveVariant(variants, 'visible', 3) // { x: 150 }
|
|
23
|
+
* resolveVariant(variants, 'hidden') // { opacity: 0 }
|
|
24
|
+
* resolveVariant(undefined, 'visible') // undefined
|
|
20
25
|
* ```
|
|
21
26
|
*/
|
|
22
|
-
export const resolveVariant = (variants, key) => {
|
|
27
|
+
export const resolveVariant = (variants, key, custom) => {
|
|
23
28
|
if (!variants || !key)
|
|
24
29
|
return undefined;
|
|
25
|
-
|
|
30
|
+
const entry = variants[key];
|
|
31
|
+
if (typeof entry === 'function')
|
|
32
|
+
return entry(custom);
|
|
33
|
+
return entry;
|
|
26
34
|
};
|
|
27
35
|
/**
|
|
28
36
|
* Resolves the initial prop to keyframes, handling variant keys and `initial={false}`.
|
|
29
37
|
*
|
|
30
|
-
* When `initial` is a string, looks it up in the variants object
|
|
31
|
-
*
|
|
38
|
+
* When `initial` is a string, looks it up in the variants object (invoking
|
|
39
|
+
* dynamic variants with `custom`). When `initial={false}`, returns `false` to
|
|
40
|
+
* skip the initial animation. Otherwise returns the keyframes directly.
|
|
32
41
|
*
|
|
33
42
|
* @param initial - The initial prop value (keyframes, variant key, false, or undefined).
|
|
34
43
|
* @param variants - The variants object for resolving string keys.
|
|
44
|
+
* @param custom - Forwarded to function-form variants.
|
|
35
45
|
* @returns Keyframes definition, `false` to skip animation, or undefined.
|
|
36
46
|
*
|
|
37
47
|
* @example
|
|
38
|
-
* ```
|
|
39
|
-
* const variants = { hidden: {
|
|
40
|
-
* resolveInitial('hidden', variants)
|
|
41
|
-
* resolveInitial({ x: 0 }, variants)
|
|
42
|
-
* resolveInitial(false, variants)
|
|
43
|
-
* resolveInitial(undefined, variants)
|
|
48
|
+
* ```ts
|
|
49
|
+
* const variants = { hidden: (i: number) => ({ x: -i * 100 }) }
|
|
50
|
+
* resolveInitial('hidden', variants, 2) // { x: -200 }
|
|
51
|
+
* resolveInitial({ x: 0 }, variants) // { x: 0 }
|
|
52
|
+
* resolveInitial(false, variants) // false
|
|
53
|
+
* resolveInitial(undefined, variants) // undefined
|
|
44
54
|
* ```
|
|
45
55
|
*/
|
|
46
|
-
export const resolveInitial = (initial, variants) => {
|
|
56
|
+
export const resolveInitial = (initial, variants, custom) => {
|
|
47
57
|
if (initial === false)
|
|
48
58
|
return false;
|
|
49
59
|
if (initial === undefined)
|
|
50
60
|
return undefined;
|
|
51
61
|
if (typeof initial === 'string')
|
|
52
|
-
return resolveVariant(variants, initial);
|
|
62
|
+
return resolveVariant(variants, initial, custom);
|
|
53
63
|
return initial;
|
|
54
64
|
};
|
|
55
65
|
/**
|
|
56
66
|
* Resolves the animate prop to keyframes, handling variant keys.
|
|
57
67
|
*
|
|
58
|
-
* When `animate` is a string, looks it up in the variants object
|
|
59
|
-
* Otherwise returns the keyframes directly.
|
|
68
|
+
* When `animate` is a string, looks it up in the variants object (invoking
|
|
69
|
+
* dynamic variants with `custom`). Otherwise returns the keyframes directly.
|
|
60
70
|
*
|
|
61
71
|
* @param animate - The animate prop value (keyframes, variant key, or undefined).
|
|
62
72
|
* @param variants - The variants object for resolving string keys.
|
|
73
|
+
* @param custom - Forwarded to function-form variants.
|
|
63
74
|
* @returns Keyframes definition or undefined.
|
|
64
|
-
*
|
|
65
|
-
* @example
|
|
66
|
-
* ```typescript
|
|
67
|
-
* const variants = { visible: { opacity: 1 } }
|
|
68
|
-
* resolveAnimate('visible', variants) // { opacity: 1 }
|
|
69
|
-
* resolveAnimate({ scale: 1.2 }, variants) // { scale: 1.2 }
|
|
70
|
-
* resolveAnimate(undefined, variants) // undefined
|
|
71
|
-
* ```
|
|
72
75
|
*/
|
|
73
|
-
export const resolveAnimate = (animate, variants) => {
|
|
76
|
+
export const resolveAnimate = (animate, variants, custom) => {
|
|
74
77
|
if (animate === undefined)
|
|
75
78
|
return undefined;
|
|
76
79
|
if (typeof animate === 'string')
|
|
77
|
-
return resolveVariant(variants, animate);
|
|
80
|
+
return resolveVariant(variants, animate, custom);
|
|
78
81
|
return animate;
|
|
79
82
|
};
|
|
80
83
|
/**
|
|
81
84
|
* Resolves the exit prop to keyframes, handling variant keys.
|
|
82
85
|
*
|
|
83
|
-
* When `exit` is a string, looks it up in the variants object
|
|
84
|
-
* Otherwise returns the keyframes directly.
|
|
86
|
+
* When `exit` is a string, looks it up in the variants object (invoking
|
|
87
|
+
* dynamic variants with `custom`). Otherwise returns the keyframes directly.
|
|
88
|
+
* Used by AnimatePresence for exit animations.
|
|
85
89
|
*
|
|
86
90
|
* @param exit - The exit prop value (keyframes, variant key, or undefined).
|
|
87
91
|
* @param variants - The variants object for resolving string keys.
|
|
92
|
+
* @param custom - Forwarded to function-form variants.
|
|
88
93
|
* @returns Keyframes definition or undefined.
|
|
89
|
-
*
|
|
90
|
-
* @example
|
|
91
|
-
* ```typescript
|
|
92
|
-
* const variants = { hidden: { opacity: 0 } }
|
|
93
|
-
* resolveExit('hidden', variants) // { opacity: 0 }
|
|
94
|
-
* resolveExit({ y: -100 }, variants) // { y: -100 }
|
|
95
|
-
* resolveExit(undefined, variants) // undefined
|
|
96
|
-
* ```
|
|
97
94
|
*/
|
|
98
|
-
export const resolveExit = (exit, variants) => {
|
|
95
|
+
export const resolveExit = (exit, variants, custom) => {
|
|
99
96
|
if (exit === undefined)
|
|
100
97
|
return undefined;
|
|
101
98
|
if (typeof exit === 'string')
|
|
102
|
-
return resolveVariant(variants, exit);
|
|
99
|
+
return resolveVariant(variants, exit, custom);
|
|
103
100
|
return exit;
|
|
104
101
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@humanspeak/svelte-motion",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
4
4
|
"description": "Framer Motion for Svelte 5. Declarative motion.<tag> components with AnimatePresence exit animations, gestures (hover, tap, drag, focus, in-view), variants, FLIP layout animations, shared-layout transitions, spring physics, and scroll-linked motion values. The drop-in Framer Motion alternative for Svelte and SvelteKit.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"svelte",
|