@rootnative/inertia 0.0.1 → 0.0.3
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/CHANGELOG.md +36 -2
- package/dist/{chunk-TDSO63CJ.js → chunk-3XTVY34H.js} +2 -2
- package/dist/{chunk-NXDJZD6A.mjs → chunk-46P57VMY.mjs} +1 -1
- package/dist/{chunk-7UDYEFBU.js → chunk-BP3Y2SHQ.js} +477 -298
- package/dist/{chunk-6SMPIOIC.mjs → chunk-BQQTHG2V.mjs} +1 -1
- package/dist/{chunk-DWCLIBYO.mjs → chunk-CSODMRJ7.mjs} +478 -299
- package/dist/chunk-FNVFV4EY.js +8 -0
- package/dist/chunk-FWQOXA43.js +8 -0
- package/dist/chunk-KBP4LR75.js +8 -0
- package/dist/{chunk-ALRHDFZE.mjs → chunk-O22NXXCZ.mjs} +1 -1
- package/dist/{chunk-CWLFUYIY.mjs → chunk-OQV66TBQ.mjs} +1 -1
- package/dist/{chunk-JVBXPF2G.mjs → chunk-SGUHE5CX.mjs} +1 -1
- package/dist/{chunk-2HYD2ZBK.js → chunk-W5MC3P4N.js} +2 -2
- package/dist/index.d.mts +231 -43
- package/dist/index.d.ts +231 -43
- package/dist/index.js +212 -23
- package/dist/index.mjs +204 -18
- package/dist/motion/Image.js +3 -3
- package/dist/motion/Image.mjs +2 -2
- package/dist/motion/Pressable.js +3 -3
- package/dist/motion/Pressable.mjs +2 -2
- package/dist/motion/ScrollView.js +3 -3
- package/dist/motion/ScrollView.mjs +2 -2
- package/dist/motion/Text.js +3 -3
- package/dist/motion/Text.mjs +2 -2
- package/dist/motion/View.js +3 -3
- package/dist/motion/View.mjs +2 -2
- package/llms.txt +5 -0
- package/package.json +1 -1
- package/src/index.ts +10 -0
- package/src/layout/index.ts +1 -0
- package/src/layout/sharedRegistry.ts +51 -2
- package/src/motion/createMotionComponent.tsx +781 -502
- package/src/presence/Presence.tsx +73 -10
- package/src/values/index.ts +13 -0
- package/src/values/useAnimation.ts +15 -1
- package/src/values/useAnimator.ts +83 -0
- package/src/values/useColorCascade.ts +125 -0
- package/src/values/useInterpolatedStyle.ts +319 -0
- package/src/values/useMotionValue.ts +20 -2
- package/src/values/useSpring.ts +12 -0
- package/dist/chunk-3UTJJ4A3.js +0 -8
- package/dist/chunk-4QGXK6TF.js +0 -8
- package/dist/chunk-Z7HIOFKQ.js +0 -8
|
@@ -2,7 +2,8 @@ import { useNamedTransitions, resolveNamedTransitionProp, lookupNamedTransition,
|
|
|
2
2
|
import { stableSig, resolveAnimatableValue, isTopLevelTransition, resolveTransition, ensureWorkletEasing, springToReanimated, DEFAULT_SPRING } from './chunk-CY7Y64C3.mjs';
|
|
3
3
|
import { createContext, useContext, useMemo, Children, isValidElement, useState, useRef, useCallback, forwardRef, useEffect } from 'react';
|
|
4
4
|
import { jsx, Fragment } from 'react/jsx-runtime';
|
|
5
|
-
import Animated, { useSharedValue, useAnimatedStyle, interpolateColor, reanimatedVersion, runOnJS, LinearTransition, withSequence, withTiming, withSpring } from 'react-native-reanimated';
|
|
5
|
+
import Animated, { useSharedValue, cancelAnimation, useAnimatedStyle, interpolateColor, reanimatedVersion, runOnJS, LinearTransition, withSequence, withTiming, withSpring } from 'react-native-reanimated';
|
|
6
|
+
import { StyleSheet } from 'react-native';
|
|
6
7
|
|
|
7
8
|
var PresenceContext = createContext(null);
|
|
8
9
|
function usePresence() {
|
|
@@ -29,6 +30,8 @@ function Presence({ children }) {
|
|
|
29
30
|
() => /* @__PURE__ */ new Map()
|
|
30
31
|
);
|
|
31
32
|
const prevIncomingRef = useRef(incoming);
|
|
33
|
+
const orderRef = useRef([]);
|
|
34
|
+
let pendingExiting = null;
|
|
32
35
|
if (prevIncomingRef.current !== incoming) {
|
|
33
36
|
const prev = prevIncomingRef.current;
|
|
34
37
|
prevIncomingRef.current = incoming;
|
|
@@ -50,8 +53,12 @@ function Presence({ children }) {
|
|
|
50
53
|
ensureMutable().delete(key);
|
|
51
54
|
}
|
|
52
55
|
}
|
|
53
|
-
if (next)
|
|
56
|
+
if (next) {
|
|
57
|
+
pendingExiting = next;
|
|
58
|
+
setExiting(next);
|
|
59
|
+
}
|
|
54
60
|
}
|
|
61
|
+
const activeExiting = pendingExiting ?? exiting;
|
|
55
62
|
const handleRemove = useCallback((key) => {
|
|
56
63
|
setExiting((prev) => {
|
|
57
64
|
if (!prev.has(key)) return prev;
|
|
@@ -60,19 +67,42 @@ function Presence({ children }) {
|
|
|
60
67
|
return next;
|
|
61
68
|
});
|
|
62
69
|
}, []);
|
|
63
|
-
const
|
|
70
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
71
|
+
const presentKeys = /* @__PURE__ */ new Set();
|
|
72
|
+
const order = [];
|
|
64
73
|
for (const el of incoming) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
});
|
|
74
|
+
const key = el.key;
|
|
75
|
+
byKey.set(key, el);
|
|
76
|
+
presentKeys.add(key);
|
|
77
|
+
order.push(key);
|
|
70
78
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
79
|
+
const prevOrder = orderRef.current;
|
|
80
|
+
for (let i = 0; i < prevOrder.length; i++) {
|
|
81
|
+
const key = prevOrder[i];
|
|
82
|
+
const departing = activeExiting.get(key);
|
|
83
|
+
if (!departing || byKey.has(key)) continue;
|
|
84
|
+
let insertAt = 0;
|
|
85
|
+
for (let j = i - 1; j >= 0; j--) {
|
|
86
|
+
const anchor = order.indexOf(prevOrder[j]);
|
|
87
|
+
if (anchor !== -1) {
|
|
88
|
+
insertAt = anchor + 1;
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
74
91
|
}
|
|
92
|
+
byKey.set(key, departing);
|
|
93
|
+
order.splice(insertAt, 0, key);
|
|
94
|
+
}
|
|
95
|
+
for (const [key, el] of activeExiting) {
|
|
96
|
+
if (byKey.has(key)) continue;
|
|
97
|
+
byKey.set(key, el);
|
|
98
|
+
order.push(key);
|
|
75
99
|
}
|
|
100
|
+
orderRef.current = order;
|
|
101
|
+
const renderList = order.map((key) => ({
|
|
102
|
+
key,
|
|
103
|
+
element: byKey.get(key),
|
|
104
|
+
isPresent: presentKeys.has(key)
|
|
105
|
+
}));
|
|
76
106
|
return /* @__PURE__ */ jsx(Fragment, { children: renderList.map(({ key, element, isPresent }) => /* @__PURE__ */ jsx(
|
|
77
107
|
PresenceItem,
|
|
78
108
|
{
|
|
@@ -124,11 +154,23 @@ function resolveLayoutTransition(layout) {
|
|
|
124
154
|
var REGISTRY = /* @__PURE__ */ new Map();
|
|
125
155
|
var SHARED_LAYOUT_TTL_MS = 1e3;
|
|
126
156
|
var now = () => Date.now();
|
|
157
|
+
var lastSweep = 0;
|
|
158
|
+
function sweepExpired(at) {
|
|
159
|
+
if (at - lastSweep < SHARED_LAYOUT_TTL_MS) return;
|
|
160
|
+
lastSweep = at;
|
|
161
|
+
for (const [id, entry] of REGISTRY) {
|
|
162
|
+
if (entry.expiresAt < at) REGISTRY.delete(id);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
127
165
|
function registerLayout(id, rect) {
|
|
128
|
-
|
|
166
|
+
const at = now();
|
|
167
|
+
sweepExpired(at);
|
|
168
|
+
REGISTRY.set(id, { rect, expiresAt: at + SHARED_LAYOUT_TTL_MS });
|
|
129
169
|
}
|
|
130
170
|
function releaseLayout(id, rect) {
|
|
131
|
-
|
|
171
|
+
const at = now();
|
|
172
|
+
sweepExpired(at);
|
|
173
|
+
REGISTRY.set(id, { rect, expiresAt: at + SHARED_LAYOUT_TTL_MS });
|
|
132
174
|
}
|
|
133
175
|
function consumeLayout(id) {
|
|
134
176
|
const entry = REGISTRY.get(id);
|
|
@@ -389,28 +431,8 @@ function createMotionComponent(Component) {
|
|
|
389
431
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
390
432
|
Component
|
|
391
433
|
);
|
|
392
|
-
const
|
|
393
|
-
const {
|
|
394
|
-
initial,
|
|
395
|
-
animate,
|
|
396
|
-
exit,
|
|
397
|
-
transition: transitionProp,
|
|
398
|
-
variants,
|
|
399
|
-
controller,
|
|
400
|
-
gesture,
|
|
401
|
-
layout: layoutProp,
|
|
402
|
-
layoutId,
|
|
403
|
-
onAnimationEnd,
|
|
404
|
-
style,
|
|
405
|
-
onLayout: userOnLayout,
|
|
406
|
-
...rest
|
|
407
|
-
} = props;
|
|
408
|
-
const namedTransitions = useNamedTransitions();
|
|
409
|
-
const transition = resolveNamedTransitionProp(
|
|
410
|
-
transitionProp,
|
|
411
|
-
namedTransitions
|
|
412
|
-
);
|
|
413
|
-
const layout = typeof layoutProp === "string" ? lookupNamedTransition(layoutProp, namedTransitions) : layoutProp;
|
|
434
|
+
const PlainHost = forwardRef(function PlainHost2(props, ref) {
|
|
435
|
+
const { style, ...rest } = props;
|
|
414
436
|
if (__DEV__ && typeof style === "function") {
|
|
415
437
|
throw new Error(
|
|
416
438
|
"[inertia] `style` must be a style object or array of style objects, not a function. The function-form `style={(state) => ...}` Pressable API is not supported \u2014 use `gesture.pressed` (or `gesture.focused`, etc.) to drive state-dependent styling instead."
|
|
@@ -418,293 +440,402 @@ function createMotionComponent(Component) {
|
|
|
418
440
|
}
|
|
419
441
|
const presence = usePresence();
|
|
420
442
|
const isExiting = presence !== null && presence.isPresent === false;
|
|
421
|
-
const
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
443
|
+
const safeToRemoveRef = useRef(void 0);
|
|
444
|
+
safeToRemoveRef.current = presence?.safeToRemove;
|
|
445
|
+
useEffect(() => {
|
|
446
|
+
if (isExiting) safeToRemoveRef.current?.();
|
|
447
|
+
}, [isExiting]);
|
|
448
|
+
return /* @__PURE__ */ jsx(
|
|
449
|
+
AnimatedComponent,
|
|
450
|
+
{
|
|
451
|
+
ref,
|
|
452
|
+
...rest,
|
|
453
|
+
style
|
|
454
|
+
}
|
|
429
455
|
);
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
456
|
+
});
|
|
457
|
+
PlainHost.displayName = `MotionPlain(${Component.displayName ?? Component.name ?? "Component"})`;
|
|
458
|
+
const MotionAnimated = forwardRef(
|
|
459
|
+
function MotionAnimated2(props, ref) {
|
|
460
|
+
const {
|
|
461
|
+
initial,
|
|
462
|
+
animate,
|
|
463
|
+
exit,
|
|
464
|
+
transition: transitionProp,
|
|
465
|
+
variants,
|
|
466
|
+
controller,
|
|
467
|
+
gesture,
|
|
468
|
+
layout: layoutProp,
|
|
469
|
+
layoutId,
|
|
470
|
+
onAnimationEnd,
|
|
471
|
+
style,
|
|
472
|
+
onLayout: userOnLayout,
|
|
473
|
+
...rest
|
|
474
|
+
} = props;
|
|
475
|
+
const namedTransitions = useNamedTransitions();
|
|
476
|
+
const transition = resolveNamedTransitionProp(
|
|
477
|
+
transitionProp,
|
|
478
|
+
namedTransitions
|
|
479
|
+
);
|
|
480
|
+
const layout = typeof layoutProp === "string" ? lookupNamedTransition(layoutProp, namedTransitions) : layoutProp;
|
|
481
|
+
if (__DEV__ && typeof style === "function") {
|
|
482
|
+
throw new Error(
|
|
483
|
+
"[inertia] `style` must be a style object or array of style objects, not a function. The function-form `style={(state) => ...}` Pressable API is not supported \u2014 use `gesture.pressed` (or `gesture.focused`, etc.) to drive state-dependent styling instead."
|
|
484
|
+
);
|
|
444
485
|
}
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
486
|
+
const presence = usePresence();
|
|
487
|
+
const isExiting = presence !== null && presence.isPresent === false;
|
|
488
|
+
const shouldReduceMotion = useShouldReduceMotion();
|
|
489
|
+
const onAnimationEndRef = useRef(onAnimationEnd);
|
|
490
|
+
onAnimationEndRef.current = onAnimationEnd;
|
|
491
|
+
const variantKey = useControllerKey(controller);
|
|
492
|
+
const resolvedAnimate = resolveAnimateInput(
|
|
493
|
+
animate,
|
|
494
|
+
variants,
|
|
495
|
+
variantKey
|
|
496
|
+
);
|
|
497
|
+
const animateRecord = resolvedAnimate ?? {};
|
|
498
|
+
const initialRecord = initial && initial !== false ? initial : void 0;
|
|
499
|
+
const exitRecord = exit ? exit : void 0;
|
|
500
|
+
const [pressed, setPressed] = useState(false);
|
|
501
|
+
const [focused, setFocused] = useState(false);
|
|
502
|
+
const [focusVisible, setFocusVisible] = useState(false);
|
|
503
|
+
const [hovered, setHovered] = useState(false);
|
|
504
|
+
const touched = /* @__PURE__ */ new Set();
|
|
505
|
+
collectTouchedKeys(touched, animateRecord);
|
|
506
|
+
if (initialRecord) collectTouchedKeys(touched, initialRecord);
|
|
507
|
+
if (variants) {
|
|
508
|
+
for (const variant of Object.values(variants)) {
|
|
509
|
+
if (!variant) continue;
|
|
510
|
+
collectTouchedKeys(touched, variant);
|
|
511
|
+
}
|
|
455
512
|
}
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
if (!prevActive.includes(k)) {
|
|
466
|
-
grew = true;
|
|
467
|
-
break;
|
|
513
|
+
if (gesture) {
|
|
514
|
+
for (const subState of [
|
|
515
|
+
gesture.pressed,
|
|
516
|
+
gesture.focused,
|
|
517
|
+
gesture.focusVisible,
|
|
518
|
+
gesture.hovered
|
|
519
|
+
]) {
|
|
520
|
+
if (!subState) continue;
|
|
521
|
+
collectTouchedKeys(touched, subState);
|
|
468
522
|
}
|
|
469
523
|
}
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
const
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
const sharedValues = useAnimatableSharedValues((key) => {
|
|
483
|
-
if (SHADOW_OFFSET_KEY_SET.has(key)) {
|
|
484
|
-
const axis = shadowOffsetAxisFor(key);
|
|
485
|
-
if (initial === false) {
|
|
486
|
-
return shadowOffsetAxisValue(animateRecord.shadowOffset, axis) ?? DEFAULT_RESTING[key];
|
|
524
|
+
if (exitRecord) collectTouchedKeys(touched, exitRecord);
|
|
525
|
+
const activeKeysRef = useRef(null);
|
|
526
|
+
const hasTransformRef = useRef(false);
|
|
527
|
+
const hasShadowOffsetRef = useRef(false);
|
|
528
|
+
const prevActive = activeKeysRef.current;
|
|
529
|
+
let grew = prevActive === null;
|
|
530
|
+
if (!grew && prevActive) {
|
|
531
|
+
for (const k of touched) {
|
|
532
|
+
if (!prevActive.includes(k)) {
|
|
533
|
+
grew = true;
|
|
534
|
+
break;
|
|
535
|
+
}
|
|
487
536
|
}
|
|
488
|
-
return shadowOffsetAxisValue(
|
|
489
|
-
initialRecord?.shadowOffset,
|
|
490
|
-
axis
|
|
491
|
-
) ?? shadowOffsetAxisValue(animateRecord.shadowOffset, axis) ?? DEFAULT_RESTING[key];
|
|
492
537
|
}
|
|
493
|
-
if (
|
|
494
|
-
const
|
|
495
|
-
|
|
538
|
+
if (grew) {
|
|
539
|
+
const merged = new Set(prevActive ?? []);
|
|
540
|
+
for (const k of touched) merged.add(k);
|
|
541
|
+
activeKeysRef.current = ALL_KEYS.filter((k) => merged.has(k));
|
|
542
|
+
hasTransformRef.current = activeKeysRef.current.some(
|
|
543
|
+
(k) => TRANSFORM_KEY_SET.has(k)
|
|
544
|
+
);
|
|
545
|
+
hasShadowOffsetRef.current = activeKeysRef.current.some(
|
|
546
|
+
(k) => SHADOW_OFFSET_KEY_SET.has(k)
|
|
547
|
+
);
|
|
496
548
|
}
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
useEffect(() => {
|
|
516
|
-
if (isExiting && (!exitRecord || Object.keys(exitRecord).length === 0)) {
|
|
517
|
-
safeToRemoveRef.current?.();
|
|
518
|
-
return;
|
|
549
|
+
const drivenNow = /* @__PURE__ */ new Set();
|
|
550
|
+
collectTouchedKeys(drivenNow, animateRecord);
|
|
551
|
+
if (initialRecord) collectTouchedKeys(drivenNow, initialRecord);
|
|
552
|
+
if (isExiting && exitRecord) collectTouchedKeys(drivenNow, exitRecord);
|
|
553
|
+
const everDrivenRef = useRef(/* @__PURE__ */ new Set());
|
|
554
|
+
for (const k of drivenNow) everDrivenRef.current.add(k);
|
|
555
|
+
const activeKeys = activeKeysRef.current;
|
|
556
|
+
const everDriven = everDrivenRef.current;
|
|
557
|
+
const styleResting = {};
|
|
558
|
+
if (activeKeys.some((k) => !everDriven.has(k))) {
|
|
559
|
+
const flat = StyleSheet.flatten(style);
|
|
560
|
+
if (flat) {
|
|
561
|
+
for (const key of activeKeys) {
|
|
562
|
+
if (everDriven.has(key)) continue;
|
|
563
|
+
const v = styleValueFor(flat, key);
|
|
564
|
+
if (v !== void 0) styleResting[key] = v;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
519
567
|
}
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
568
|
+
const sharedValues = useAnimatableSharedValues((key) => {
|
|
569
|
+
if (SHADOW_OFFSET_KEY_SET.has(key)) {
|
|
570
|
+
const axis = shadowOffsetAxisFor(key);
|
|
571
|
+
if (initial === false) {
|
|
572
|
+
return shadowOffsetAxisValue(animateRecord.shadowOffset, axis) ?? styleResting[key] ?? DEFAULT_RESTING[key];
|
|
573
|
+
}
|
|
574
|
+
return shadowOffsetAxisValue(
|
|
575
|
+
initialRecord?.shadowOffset,
|
|
576
|
+
axis
|
|
577
|
+
) ?? shadowOffsetAxisValue(animateRecord.shadowOffset, axis) ?? styleResting[key] ?? DEFAULT_RESTING[key];
|
|
528
578
|
}
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
if (TRANSFORM_KEY_SET.has(k) && baseRecord[k] !== void 0) {
|
|
533
|
-
transformPending++;
|
|
579
|
+
if (initial === false) {
|
|
580
|
+
const a = animateRecord[key];
|
|
581
|
+
return restValue(a) ?? styleResting[key] ?? DEFAULT_RESTING[key];
|
|
534
582
|
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
583
|
+
return initialRecord?.[key] ?? restValue(animateRecord[key]) ?? styleResting[key] ?? DEFAULT_RESTING[key];
|
|
584
|
+
});
|
|
585
|
+
const styleRestingSig = stableSig(styleResting);
|
|
586
|
+
useEffect(() => {
|
|
587
|
+
for (const key of activeKeysRef.current) {
|
|
588
|
+
if (everDrivenRef.current.has(key)) continue;
|
|
589
|
+
sharedValues[key].value = styleResting[key] ?? DEFAULT_RESTING[key];
|
|
590
|
+
}
|
|
591
|
+
}, [styleRestingSig]);
|
|
592
|
+
const pressedProgress = useSharedValue(0);
|
|
593
|
+
const focusedProgress = useSharedValue(0);
|
|
594
|
+
const focusVisibleProgress = useSharedValue(0);
|
|
595
|
+
const hoveredProgress = useSharedValue(0);
|
|
596
|
+
useEffect(
|
|
597
|
+
() => () => {
|
|
598
|
+
cancelAnimation(pressedProgress);
|
|
599
|
+
cancelAnimation(focusedProgress);
|
|
600
|
+
cancelAnimation(focusVisibleProgress);
|
|
601
|
+
cancelAnimation(hoveredProgress);
|
|
602
|
+
},
|
|
603
|
+
// The progress SVs are identity-stable per hook instance.
|
|
604
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
605
|
+
[]
|
|
606
|
+
);
|
|
607
|
+
const gestureSV = useSharedValue(
|
|
608
|
+
resolveGestureLayers(gesture)
|
|
609
|
+
);
|
|
610
|
+
const gestureTargetsSig = stableSig(gesture);
|
|
611
|
+
useEffect(() => {
|
|
612
|
+
gestureSV.value = resolveGestureLayers(gesture);
|
|
613
|
+
}, [gestureTargetsSig]);
|
|
614
|
+
const baseRecord = isExiting && exitRecord ? { ...animateRecord, ...exitRecord } : animateRecord;
|
|
615
|
+
const baseSig = stableSig(baseRecord) + (isExiting ? "|exit" : "") + (shouldReduceMotion ? "|rm" : "");
|
|
616
|
+
const transitionSig = stableSig(transition);
|
|
617
|
+
const safeToRemoveRef = useRef(void 0);
|
|
618
|
+
safeToRemoveRef.current = presence?.safeToRemove;
|
|
619
|
+
useEffect(() => {
|
|
620
|
+
if (isExiting && (!exitRecord || Object.keys(exitRecord).length === 0)) {
|
|
621
|
+
safeToRemoveRef.current?.();
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
let pending = 0;
|
|
625
|
+
let done = false;
|
|
626
|
+
const onSettle = () => {
|
|
627
|
+
if (done) return;
|
|
628
|
+
pending--;
|
|
629
|
+
if (pending <= 0) {
|
|
630
|
+
done = true;
|
|
631
|
+
if (isExiting) safeToRemoveRef.current?.();
|
|
632
|
+
}
|
|
633
|
+
};
|
|
634
|
+
const configFor = (key) => shouldReduceMotion ? { type: "no-animation" } : transitionFor(
|
|
544
635
|
SHADOW_OFFSET_KEY_SET.has(key) ? "shadowOffset" : key,
|
|
545
636
|
transition
|
|
546
637
|
);
|
|
547
|
-
|
|
548
|
-
const
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
onAnimationEndRef,
|
|
553
|
-
{
|
|
554
|
-
stepCount: stepCountOf(target),
|
|
555
|
-
totalIterations: totalIterationsOf(cfg)
|
|
556
|
-
},
|
|
557
|
-
isExiting ? onSettle : void 0,
|
|
558
|
-
TRANSFORM_KEY_SET.has(key) ? transformGroup : void 0
|
|
559
|
-
);
|
|
560
|
-
sharedValues[key].value = resolveAnimatableValue(
|
|
561
|
-
target,
|
|
562
|
-
cfg,
|
|
563
|
-
factory
|
|
564
|
-
);
|
|
565
|
-
}
|
|
566
|
-
if (isExiting && pending === 0) {
|
|
567
|
-
safeToRemoveRef.current?.();
|
|
568
|
-
}
|
|
569
|
-
}, [baseSig, transitionSig]);
|
|
570
|
-
useGestureLayerProgress(
|
|
571
|
-
pressedProgress,
|
|
572
|
-
pressed,
|
|
573
|
-
gesture?.pressed != null,
|
|
574
|
-
"pressed",
|
|
575
|
-
transition,
|
|
576
|
-
isExiting,
|
|
577
|
-
shouldReduceMotion
|
|
578
|
-
);
|
|
579
|
-
useGestureLayerProgress(
|
|
580
|
-
focusedProgress,
|
|
581
|
-
focused,
|
|
582
|
-
gesture?.focused != null,
|
|
583
|
-
"focused",
|
|
584
|
-
transition,
|
|
585
|
-
isExiting,
|
|
586
|
-
shouldReduceMotion
|
|
587
|
-
);
|
|
588
|
-
useGestureLayerProgress(
|
|
589
|
-
focusVisibleProgress,
|
|
590
|
-
focusVisible,
|
|
591
|
-
gesture?.focusVisible != null,
|
|
592
|
-
"focusVisible",
|
|
593
|
-
transition,
|
|
594
|
-
isExiting,
|
|
595
|
-
shouldReduceMotion
|
|
596
|
-
);
|
|
597
|
-
useGestureLayerProgress(
|
|
598
|
-
hoveredProgress,
|
|
599
|
-
hovered,
|
|
600
|
-
gesture?.hovered != null,
|
|
601
|
-
"hovered",
|
|
602
|
-
transition,
|
|
603
|
-
isExiting,
|
|
604
|
-
shouldReduceMotion
|
|
605
|
-
);
|
|
606
|
-
const sharedLayout = useSharedLayout({
|
|
607
|
-
layoutId,
|
|
608
|
-
userRef: ref,
|
|
609
|
-
transition: isTopLevelTransition(transition) ? transition : void 0,
|
|
610
|
-
shouldReduceMotion,
|
|
611
|
-
userOnLayout
|
|
612
|
-
});
|
|
613
|
-
const flip = sharedLayout.flip;
|
|
614
|
-
const hasLayoutId = layoutId !== void 0;
|
|
615
|
-
const animatedStyle = useAnimatedStyle(() => {
|
|
616
|
-
const activeKeys = activeKeysRef.current;
|
|
617
|
-
const hasTransform = hasTransformRef.current;
|
|
618
|
-
const hasShadowOffset = hasShadowOffsetRef.current;
|
|
619
|
-
const out = {};
|
|
620
|
-
const transform = [];
|
|
621
|
-
let shadowOffsetW = 0;
|
|
622
|
-
let shadowOffsetH = 0;
|
|
623
|
-
const ph = hoveredProgress.value;
|
|
624
|
-
const pf = focusedProgress.value;
|
|
625
|
-
const pfv = focusVisibleProgress.value;
|
|
626
|
-
const pp = pressedProgress.value;
|
|
627
|
-
const layers = gestureSV.value;
|
|
628
|
-
const hoveredLayer = layers ? layers.hovered : null;
|
|
629
|
-
const focusedLayer = layers ? layers.focused : null;
|
|
630
|
-
const focusVisibleLayer = layers ? layers.focusVisible : null;
|
|
631
|
-
const pressedLayer = layers ? layers.pressed : null;
|
|
632
|
-
for (const key of activeKeys) {
|
|
633
|
-
let v = sharedValues[key].value;
|
|
634
|
-
const isColor = COLOR_KEY_SET.has(key);
|
|
635
|
-
if (hoveredLayer && ph > 0 && hoveredLayer[key] !== void 0) {
|
|
636
|
-
const t = hoveredLayer[key];
|
|
637
|
-
v = isColor ? interpolateColor(ph, [0, 1], [v, t]) : v + (t - v) * ph;
|
|
638
|
+
let transformPending = 0;
|
|
639
|
+
for (const k of ALL_KEYS) {
|
|
640
|
+
if (!TRANSFORM_KEY_SET.has(k) || baseRecord[k] === void 0) continue;
|
|
641
|
+
if (!reachesTerminalPhase(configFor(k))) continue;
|
|
642
|
+
transformPending++;
|
|
638
643
|
}
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
644
|
+
const transformGroup = transformPending > 0 ? { remaining: transformPending } : void 0;
|
|
645
|
+
for (const key of ALL_KEYS) {
|
|
646
|
+
const target = SHADOW_OFFSET_KEY_SET.has(key) ? shadowOffsetAxisValue(
|
|
647
|
+
baseRecord.shadowOffset,
|
|
648
|
+
shadowOffsetAxisFor(key)
|
|
649
|
+
) : baseRecord[key];
|
|
650
|
+
if (target === void 0) continue;
|
|
651
|
+
const cfg = configFor(key);
|
|
652
|
+
if (isExiting && reachesTerminalPhase(cfg)) pending++;
|
|
653
|
+
const factory = makeKeyCallbackFactory(
|
|
654
|
+
key,
|
|
655
|
+
sharedValues[key],
|
|
656
|
+
targetEndValue(target),
|
|
657
|
+
onAnimationEndRef,
|
|
658
|
+
{
|
|
659
|
+
stepCount: stepCountOf(target),
|
|
660
|
+
totalIterations: totalIterationsOf(cfg)
|
|
661
|
+
},
|
|
662
|
+
isExiting ? onSettle : void 0,
|
|
663
|
+
TRANSFORM_KEY_SET.has(key) ? transformGroup : void 0
|
|
664
|
+
);
|
|
665
|
+
sharedValues[key].value = resolveAnimatableValue(
|
|
666
|
+
target,
|
|
667
|
+
cfg,
|
|
668
|
+
factory
|
|
669
|
+
);
|
|
642
670
|
}
|
|
643
|
-
if (
|
|
644
|
-
|
|
645
|
-
v = isColor ? interpolateColor(pfv, [0, 1], [v, t]) : v + (t - v) * pfv;
|
|
671
|
+
if (isExiting && pending === 0) {
|
|
672
|
+
safeToRemoveRef.current?.();
|
|
646
673
|
}
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
674
|
+
}, [baseSig, transitionSig]);
|
|
675
|
+
useGestureLayerProgress(
|
|
676
|
+
pressedProgress,
|
|
677
|
+
pressed,
|
|
678
|
+
gesture?.pressed != null,
|
|
679
|
+
"pressed",
|
|
680
|
+
transition,
|
|
681
|
+
isExiting,
|
|
682
|
+
shouldReduceMotion
|
|
683
|
+
);
|
|
684
|
+
useGestureLayerProgress(
|
|
685
|
+
focusedProgress,
|
|
686
|
+
focused,
|
|
687
|
+
gesture?.focused != null,
|
|
688
|
+
"focused",
|
|
689
|
+
transition,
|
|
690
|
+
isExiting,
|
|
691
|
+
shouldReduceMotion
|
|
692
|
+
);
|
|
693
|
+
useGestureLayerProgress(
|
|
694
|
+
focusVisibleProgress,
|
|
695
|
+
focusVisible,
|
|
696
|
+
gesture?.focusVisible != null,
|
|
697
|
+
"focusVisible",
|
|
698
|
+
transition,
|
|
699
|
+
isExiting,
|
|
700
|
+
shouldReduceMotion
|
|
701
|
+
);
|
|
702
|
+
useGestureLayerProgress(
|
|
703
|
+
hoveredProgress,
|
|
704
|
+
hovered,
|
|
705
|
+
gesture?.hovered != null,
|
|
706
|
+
"hovered",
|
|
707
|
+
transition,
|
|
708
|
+
isExiting,
|
|
709
|
+
shouldReduceMotion
|
|
710
|
+
);
|
|
711
|
+
const sharedLayout = useSharedLayout({
|
|
712
|
+
layoutId,
|
|
713
|
+
userRef: ref,
|
|
714
|
+
transition: isTopLevelTransition(transition) ? transition : void 0,
|
|
715
|
+
shouldReduceMotion,
|
|
716
|
+
userOnLayout
|
|
717
|
+
});
|
|
718
|
+
const flip = sharedLayout.flip;
|
|
719
|
+
const hasLayoutId = layoutId !== void 0;
|
|
720
|
+
const animatedStyle = useAnimatedStyle(() => {
|
|
721
|
+
const activeKeys2 = activeKeysRef.current;
|
|
722
|
+
const hasTransform = hasTransformRef.current;
|
|
723
|
+
const hasShadowOffset = hasShadowOffsetRef.current;
|
|
724
|
+
const out = {};
|
|
725
|
+
const transform = [];
|
|
726
|
+
let shadowOffsetW = 0;
|
|
727
|
+
let shadowOffsetH = 0;
|
|
728
|
+
const ph = hoveredProgress.value;
|
|
729
|
+
const pf = focusedProgress.value;
|
|
730
|
+
const pfv = focusVisibleProgress.value;
|
|
731
|
+
const pp = pressedProgress.value;
|
|
732
|
+
const layers = gestureSV.value;
|
|
733
|
+
const hoveredLayer = layers ? layers.hovered : null;
|
|
734
|
+
const focusedLayer = layers ? layers.focused : null;
|
|
735
|
+
const focusVisibleLayer = layers ? layers.focusVisible : null;
|
|
736
|
+
const pressedLayer = layers ? layers.pressed : null;
|
|
737
|
+
for (const key of activeKeys2) {
|
|
738
|
+
let v = sharedValues[key].value;
|
|
739
|
+
const isColor = COLOR_KEY_SET.has(key);
|
|
740
|
+
if (hoveredLayer && ph > 0 && hoveredLayer[key] !== void 0) {
|
|
741
|
+
const t = hoveredLayer[key];
|
|
742
|
+
v = isColor ? interpolateColor(ph, [0, 1], [v, t]) : v + (t - v) * ph;
|
|
743
|
+
}
|
|
744
|
+
if (focusedLayer && pf > 0 && focusedLayer[key] !== void 0) {
|
|
745
|
+
const t = focusedLayer[key];
|
|
746
|
+
v = isColor ? interpolateColor(pf, [0, 1], [v, t]) : v + (t - v) * pf;
|
|
747
|
+
}
|
|
748
|
+
if (focusVisibleLayer && pfv > 0 && focusVisibleLayer[key] !== void 0) {
|
|
749
|
+
const t = focusVisibleLayer[key];
|
|
750
|
+
v = isColor ? interpolateColor(pfv, [0, 1], [v, t]) : v + (t - v) * pfv;
|
|
751
|
+
}
|
|
752
|
+
if (pressedLayer && pp > 0 && pressedLayer[key] !== void 0) {
|
|
753
|
+
const t = pressedLayer[key];
|
|
754
|
+
v = isColor ? interpolateColor(pp, [0, 1], [v, t]) : v + (t - v) * pp;
|
|
755
|
+
}
|
|
756
|
+
if (TRANSFORM_KEY_SET.has(key)) {
|
|
757
|
+
transform.push(
|
|
758
|
+
ROTATION_KEYS.has(key) ? { [key]: `${v}deg` } : { [key]: v }
|
|
759
|
+
);
|
|
760
|
+
} else if (key === "shadowOffsetWidth") {
|
|
761
|
+
shadowOffsetW = v;
|
|
762
|
+
} else if (key === "shadowOffsetHeight") {
|
|
763
|
+
shadowOffsetH = v;
|
|
764
|
+
} else {
|
|
765
|
+
out[key] = v;
|
|
766
|
+
}
|
|
650
767
|
}
|
|
651
|
-
if (
|
|
652
|
-
transform.push(
|
|
653
|
-
|
|
654
|
-
);
|
|
655
|
-
|
|
656
|
-
shadowOffsetW = v;
|
|
657
|
-
} else if (key === "shadowOffsetHeight") {
|
|
658
|
-
shadowOffsetH = v;
|
|
659
|
-
} else {
|
|
660
|
-
out[key] = v;
|
|
768
|
+
if (hasLayoutId) {
|
|
769
|
+
transform.push({ translateX: flip.dx.value });
|
|
770
|
+
transform.push({ translateY: flip.dy.value });
|
|
771
|
+
transform.push({ scaleX: flip.sx.value });
|
|
772
|
+
transform.push({ scaleY: flip.sy.value });
|
|
661
773
|
}
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
}
|
|
703
|
-
|
|
774
|
+
if (hasTransform || hasLayoutId) out.transform = transform;
|
|
775
|
+
if (hasShadowOffset) {
|
|
776
|
+
out.shadowOffset = { width: shadowOffsetW, height: shadowOffsetH };
|
|
777
|
+
}
|
|
778
|
+
return out;
|
|
779
|
+
});
|
|
780
|
+
const mergedStyle = useMemo(
|
|
781
|
+
() => isExiting ? [style, animatedStyle, EXITING_POINTER_EVENTS_STYLE] : [style, animatedStyle],
|
|
782
|
+
[style, animatedStyle, isExiting]
|
|
783
|
+
);
|
|
784
|
+
const gestureHandlers = useGestureHandlers(
|
|
785
|
+
gesture,
|
|
786
|
+
rest,
|
|
787
|
+
setPressed,
|
|
788
|
+
setFocused,
|
|
789
|
+
setFocusVisible,
|
|
790
|
+
setHovered
|
|
791
|
+
);
|
|
792
|
+
const layoutSig = stableSig(layout);
|
|
793
|
+
const layoutTransition = useMemo(
|
|
794
|
+
() => shouldReduceMotion ? void 0 : resolveLayoutTransition(layout),
|
|
795
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
796
|
+
[layoutSig, shouldReduceMotion]
|
|
797
|
+
);
|
|
798
|
+
return /* @__PURE__ */ jsx(
|
|
799
|
+
AnimatedComponent,
|
|
800
|
+
{
|
|
801
|
+
ref: sharedLayout.setRef,
|
|
802
|
+
...rest,
|
|
803
|
+
...gestureHandlers,
|
|
804
|
+
onLayout: sharedLayout.onLayout,
|
|
805
|
+
layout: layoutTransition,
|
|
806
|
+
style: mergedStyle
|
|
807
|
+
}
|
|
808
|
+
);
|
|
809
|
+
}
|
|
810
|
+
);
|
|
811
|
+
MotionAnimated.displayName = `Motion(${Component.displayName ?? Component.name ?? "Component"})`;
|
|
812
|
+
const Motion = forwardRef(function Motion2(props, ref) {
|
|
813
|
+
if (hasMotionProps(props)) {
|
|
814
|
+
return /* @__PURE__ */ jsx(MotionAnimated, { ref, ...props });
|
|
815
|
+
}
|
|
816
|
+
return /* @__PURE__ */ jsx(PlainHost, { ref, ...props });
|
|
704
817
|
});
|
|
705
818
|
Motion.displayName = `Motion(${Component.displayName ?? Component.name ?? "Component"})`;
|
|
706
819
|
return Motion;
|
|
707
820
|
}
|
|
821
|
+
var MOTION_PROP_KEYS = [
|
|
822
|
+
"initial",
|
|
823
|
+
"animate",
|
|
824
|
+
"exit",
|
|
825
|
+
"transition",
|
|
826
|
+
"variants",
|
|
827
|
+
"controller",
|
|
828
|
+
"gesture",
|
|
829
|
+
"layout",
|
|
830
|
+
"layoutId",
|
|
831
|
+
"onAnimationEnd"
|
|
832
|
+
];
|
|
833
|
+
function hasMotionProps(props) {
|
|
834
|
+
for (const key of MOTION_PROP_KEYS) {
|
|
835
|
+
if (props[key] !== void 0) return true;
|
|
836
|
+
}
|
|
837
|
+
return false;
|
|
838
|
+
}
|
|
708
839
|
function useAnimatableSharedValues(init) {
|
|
709
840
|
const translateX = useSharedValue(init("translateX"));
|
|
710
841
|
const translateY = useSharedValue(init("translateY"));
|
|
@@ -761,6 +892,17 @@ function useAnimatableSharedValues(init) {
|
|
|
761
892
|
shadowOffsetHeight
|
|
762
893
|
};
|
|
763
894
|
}
|
|
895
|
+
const map = ref.current;
|
|
896
|
+
useEffect(
|
|
897
|
+
() => () => {
|
|
898
|
+
for (const key in map) {
|
|
899
|
+
cancelAnimation(map[key]);
|
|
900
|
+
}
|
|
901
|
+
},
|
|
902
|
+
// `map` is identity-stable per hook instance.
|
|
903
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
904
|
+
[]
|
|
905
|
+
);
|
|
764
906
|
return ref.current;
|
|
765
907
|
}
|
|
766
908
|
function makeKeyCallbackFactory(key, sharedValue, target, onAnimationEndRef, meta, onSettle, transformGroup) {
|
|
@@ -832,6 +974,40 @@ function shadowOffsetAxisFor(key) {
|
|
|
832
974
|
function shadowOffsetAxisValue(source, axis) {
|
|
833
975
|
return source?.[axis];
|
|
834
976
|
}
|
|
977
|
+
function styleValueFor(flat, key) {
|
|
978
|
+
if (SHADOW_OFFSET_KEY_SET.has(key)) {
|
|
979
|
+
return shadowOffsetAxisValue(
|
|
980
|
+
flat.shadowOffset,
|
|
981
|
+
shadowOffsetAxisFor(key)
|
|
982
|
+
);
|
|
983
|
+
}
|
|
984
|
+
if (TRANSFORM_KEY_SET.has(key)) {
|
|
985
|
+
const list = flat.transform;
|
|
986
|
+
if (!Array.isArray(list)) return void 0;
|
|
987
|
+
for (const entry of list) {
|
|
988
|
+
if (!entry || typeof entry !== "object") continue;
|
|
989
|
+
const v2 = entry[key];
|
|
990
|
+
if (v2 === void 0) continue;
|
|
991
|
+
if (ROTATION_KEYS.has(key)) return parseAngleDegrees(v2);
|
|
992
|
+
return typeof v2 === "number" ? v2 : void 0;
|
|
993
|
+
}
|
|
994
|
+
return void 0;
|
|
995
|
+
}
|
|
996
|
+
const v = flat[key];
|
|
997
|
+
if (COLOR_KEY_SET.has(key)) {
|
|
998
|
+
return typeof v === "string" || typeof v === "number" ? v : void 0;
|
|
999
|
+
}
|
|
1000
|
+
return typeof v === "number" ? v : void 0;
|
|
1001
|
+
}
|
|
1002
|
+
function parseAngleDegrees(v) {
|
|
1003
|
+
if (typeof v === "number") return v;
|
|
1004
|
+
if (typeof v !== "string") return void 0;
|
|
1005
|
+
const deg = /^(-?\d*\.?\d+)deg$/.exec(v);
|
|
1006
|
+
if (deg) return Number(deg[1]);
|
|
1007
|
+
const rad = /^(-?\d*\.?\d+)rad$/.exec(v);
|
|
1008
|
+
if (rad) return Number(rad[1]) * 180 / Math.PI;
|
|
1009
|
+
return void 0;
|
|
1010
|
+
}
|
|
835
1011
|
function collectTouchedKeys(touched, record) {
|
|
836
1012
|
for (const k of ALL_KEYS) {
|
|
837
1013
|
if (k in record) touched.add(k);
|
|
@@ -855,6 +1031,9 @@ function totalIterationsOf(cfg) {
|
|
|
855
1031
|
if (r.count === "infinite") return Number.POSITIVE_INFINITY;
|
|
856
1032
|
return r.count;
|
|
857
1033
|
}
|
|
1034
|
+
function reachesTerminalPhase(cfg) {
|
|
1035
|
+
return Number.isFinite(totalIterationsOf(cfg));
|
|
1036
|
+
}
|
|
858
1037
|
function targetEndValue(v) {
|
|
859
1038
|
if (v === void 0) return void 0;
|
|
860
1039
|
if (typeof v === "number" || typeof v === "string") return v;
|