@rootnative/inertia 0.0.0-alpha.7 → 0.0.2

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 (42) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +1 -1
  3. package/dist/{chunk-ALRHDFZE.mjs → chunk-2DHKV2XY.mjs} +1 -1
  4. package/dist/chunk-34Q4UM6V.js +8 -0
  5. package/dist/{chunk-CWLFUYIY.mjs → chunk-HFDZAHWP.mjs} +1 -1
  6. package/dist/{chunk-7UDYEFBU.js → chunk-IWLU3VDE.js} +361 -288
  7. package/dist/chunk-KYJROYCG.js +8 -0
  8. package/dist/{chunk-DWCLIBYO.mjs → chunk-LYMLQ6WQ.mjs} +362 -289
  9. package/dist/{chunk-TDSO63CJ.js → chunk-NKA6XR77.js} +2 -2
  10. package/dist/{chunk-6SMPIOIC.mjs → chunk-TUMNV4P7.mjs} +1 -1
  11. package/dist/{chunk-2HYD2ZBK.js → chunk-TUYHTHVV.js} +2 -2
  12. package/dist/{chunk-NXDJZD6A.mjs → chunk-V6BTXHZK.mjs} +1 -1
  13. package/dist/chunk-X5J5M3K3.js +8 -0
  14. package/dist/{chunk-JVBXPF2G.mjs → chunk-ZN3PNGHQ.mjs} +1 -1
  15. package/dist/index.d.mts +229 -43
  16. package/dist/index.d.ts +229 -43
  17. package/dist/index.js +199 -23
  18. package/dist/index.mjs +191 -18
  19. package/dist/motion/Image.js +3 -3
  20. package/dist/motion/Image.mjs +2 -2
  21. package/dist/motion/Pressable.js +3 -3
  22. package/dist/motion/Pressable.mjs +2 -2
  23. package/dist/motion/ScrollView.js +3 -3
  24. package/dist/motion/ScrollView.mjs +2 -2
  25. package/dist/motion/Text.js +3 -3
  26. package/dist/motion/Text.mjs +2 -2
  27. package/dist/motion/View.js +3 -3
  28. package/dist/motion/View.mjs +2 -2
  29. package/llms.txt +6 -1
  30. package/package.json +1 -1
  31. package/src/index.ts +10 -0
  32. package/src/motion/createMotionComponent.tsx +624 -501
  33. package/src/values/index.ts +13 -0
  34. package/src/values/useAnimation.ts +15 -1
  35. package/src/values/useAnimator.ts +72 -0
  36. package/src/values/useColorCascade.ts +107 -0
  37. package/src/values/useInterpolatedStyle.ts +319 -0
  38. package/src/values/useMotionValue.ts +20 -2
  39. package/src/values/useSpring.ts +12 -0
  40. package/dist/chunk-3UTJJ4A3.js +0 -8
  41. package/dist/chunk-4QGXK6TF.js +0 -8
  42. package/dist/chunk-Z7HIOFKQ.js +0 -8
@@ -2,7 +2,7 @@ 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
6
 
7
7
  var PresenceContext = createContext(null);
8
8
  function usePresence() {
@@ -389,28 +389,8 @@ function createMotionComponent(Component) {
389
389
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
390
390
  Component
391
391
  );
392
- const Motion = forwardRef(function Motion2(props, ref) {
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;
392
+ const PlainHost = forwardRef(function PlainHost2(props, ref) {
393
+ const { style, ...rest } = props;
414
394
  if (__DEV__ && typeof style === "function") {
415
395
  throw new Error(
416
396
  "[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 +398,375 @@ function createMotionComponent(Component) {
418
398
  }
419
399
  const presence = usePresence();
420
400
  const isExiting = presence !== null && presence.isPresent === false;
421
- const shouldReduceMotion = useShouldReduceMotion();
422
- const onAnimationEndRef = useRef(onAnimationEnd);
423
- onAnimationEndRef.current = onAnimationEnd;
424
- const variantKey = useControllerKey(controller);
425
- const resolvedAnimate = resolveAnimateInput(
426
- animate,
427
- variants,
428
- variantKey
429
- );
430
- const animateRecord = resolvedAnimate ?? {};
431
- const initialRecord = initial && initial !== false ? initial : void 0;
432
- const exitRecord = exit ? exit : void 0;
433
- const [pressed, setPressed] = useState(false);
434
- const [focused, setFocused] = useState(false);
435
- const [focusVisible, setFocusVisible] = useState(false);
436
- const [hovered, setHovered] = useState(false);
437
- const touched = /* @__PURE__ */ new Set();
438
- collectTouchedKeys(touched, animateRecord);
439
- if (initialRecord) collectTouchedKeys(touched, initialRecord);
440
- if (variants) {
441
- for (const variant of Object.values(variants)) {
442
- if (!variant) continue;
443
- collectTouchedKeys(touched, variant);
444
- }
445
- }
446
- if (gesture) {
447
- for (const subState of [
448
- gesture.pressed,
449
- gesture.focused,
450
- gesture.focusVisible,
451
- gesture.hovered
452
- ]) {
453
- if (!subState) continue;
454
- collectTouchedKeys(touched, subState);
455
- }
456
- }
457
- if (exitRecord) collectTouchedKeys(touched, exitRecord);
458
- const activeKeysRef = useRef(null);
459
- const hasTransformRef = useRef(false);
460
- const hasShadowOffsetRef = useRef(false);
461
- const prevActive = activeKeysRef.current;
462
- let grew = prevActive === null;
463
- if (!grew && prevActive) {
464
- for (const k of touched) {
465
- if (!prevActive.includes(k)) {
466
- grew = true;
467
- break;
468
- }
401
+ const safeToRemoveRef = useRef(void 0);
402
+ safeToRemoveRef.current = presence?.safeToRemove;
403
+ useEffect(() => {
404
+ if (isExiting) safeToRemoveRef.current?.();
405
+ }, [isExiting]);
406
+ return /* @__PURE__ */ jsx(
407
+ AnimatedComponent,
408
+ {
409
+ ref,
410
+ ...rest,
411
+ style
469
412
  }
470
- }
471
- if (grew) {
472
- const merged = new Set(prevActive ?? []);
473
- for (const k of touched) merged.add(k);
474
- activeKeysRef.current = ALL_KEYS.filter((k) => merged.has(k));
475
- hasTransformRef.current = activeKeysRef.current.some(
476
- (k) => TRANSFORM_KEY_SET.has(k)
413
+ );
414
+ });
415
+ PlainHost.displayName = `MotionPlain(${Component.displayName ?? Component.name ?? "Component"})`;
416
+ const MotionAnimated = forwardRef(
417
+ function MotionAnimated2(props, ref) {
418
+ const {
419
+ initial,
420
+ animate,
421
+ exit,
422
+ transition: transitionProp,
423
+ variants,
424
+ controller,
425
+ gesture,
426
+ layout: layoutProp,
427
+ layoutId,
428
+ onAnimationEnd,
429
+ style,
430
+ onLayout: userOnLayout,
431
+ ...rest
432
+ } = props;
433
+ const namedTransitions = useNamedTransitions();
434
+ const transition = resolveNamedTransitionProp(
435
+ transitionProp,
436
+ namedTransitions
477
437
  );
478
- hasShadowOffsetRef.current = activeKeysRef.current.some(
479
- (k) => SHADOW_OFFSET_KEY_SET.has(k)
438
+ const layout = typeof layoutProp === "string" ? lookupNamedTransition(layoutProp, namedTransitions) : layoutProp;
439
+ if (__DEV__ && typeof style === "function") {
440
+ throw new Error(
441
+ "[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."
442
+ );
443
+ }
444
+ const presence = usePresence();
445
+ const isExiting = presence !== null && presence.isPresent === false;
446
+ const shouldReduceMotion = useShouldReduceMotion();
447
+ const onAnimationEndRef = useRef(onAnimationEnd);
448
+ onAnimationEndRef.current = onAnimationEnd;
449
+ const variantKey = useControllerKey(controller);
450
+ const resolvedAnimate = resolveAnimateInput(
451
+ animate,
452
+ variants,
453
+ variantKey
480
454
  );
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];
455
+ const animateRecord = resolvedAnimate ?? {};
456
+ const initialRecord = initial && initial !== false ? initial : void 0;
457
+ const exitRecord = exit ? exit : void 0;
458
+ const [pressed, setPressed] = useState(false);
459
+ const [focused, setFocused] = useState(false);
460
+ const [focusVisible, setFocusVisible] = useState(false);
461
+ const [hovered, setHovered] = useState(false);
462
+ const touched = /* @__PURE__ */ new Set();
463
+ collectTouchedKeys(touched, animateRecord);
464
+ if (initialRecord) collectTouchedKeys(touched, initialRecord);
465
+ if (variants) {
466
+ for (const variant of Object.values(variants)) {
467
+ if (!variant) continue;
468
+ collectTouchedKeys(touched, variant);
487
469
  }
488
- return shadowOffsetAxisValue(
489
- initialRecord?.shadowOffset,
490
- axis
491
- ) ?? shadowOffsetAxisValue(animateRecord.shadowOffset, axis) ?? DEFAULT_RESTING[key];
492
- }
493
- if (initial === false) {
494
- const a = animateRecord[key];
495
- return restValue(a) ?? DEFAULT_RESTING[key];
496
- }
497
- return initialRecord?.[key] ?? restValue(animateRecord[key]) ?? DEFAULT_RESTING[key];
498
- });
499
- const pressedProgress = useSharedValue(0);
500
- const focusedProgress = useSharedValue(0);
501
- const focusVisibleProgress = useSharedValue(0);
502
- const hoveredProgress = useSharedValue(0);
503
- const gestureSV = useSharedValue(
504
- resolveGestureLayers(gesture)
505
- );
506
- const gestureTargetsSig = stableSig(gesture);
507
- useEffect(() => {
508
- gestureSV.value = resolveGestureLayers(gesture);
509
- }, [gestureTargetsSig]);
510
- const baseRecord = isExiting && exitRecord ? { ...animateRecord, ...exitRecord } : animateRecord;
511
- const baseSig = stableSig(baseRecord) + (isExiting ? "|exit" : "") + (shouldReduceMotion ? "|rm" : "");
512
- const transitionSig = stableSig(transition);
513
- const safeToRemoveRef = useRef(void 0);
514
- safeToRemoveRef.current = presence?.safeToRemove;
515
- useEffect(() => {
516
- if (isExiting && (!exitRecord || Object.keys(exitRecord).length === 0)) {
517
- safeToRemoveRef.current?.();
518
- return;
519
470
  }
520
- let pending = 0;
521
- let done = false;
522
- const onSettle = () => {
523
- if (done) return;
524
- pending--;
525
- if (pending <= 0) {
526
- done = true;
527
- if (isExiting) safeToRemoveRef.current?.();
471
+ if (gesture) {
472
+ for (const subState of [
473
+ gesture.pressed,
474
+ gesture.focused,
475
+ gesture.focusVisible,
476
+ gesture.hovered
477
+ ]) {
478
+ if (!subState) continue;
479
+ collectTouchedKeys(touched, subState);
528
480
  }
529
- };
530
- let transformPending = 0;
531
- for (const k of ALL_KEYS) {
532
- if (TRANSFORM_KEY_SET.has(k) && baseRecord[k] !== void 0) {
533
- transformPending++;
481
+ }
482
+ if (exitRecord) collectTouchedKeys(touched, exitRecord);
483
+ const activeKeysRef = useRef(null);
484
+ const hasTransformRef = useRef(false);
485
+ const hasShadowOffsetRef = useRef(false);
486
+ const prevActive = activeKeysRef.current;
487
+ let grew = prevActive === null;
488
+ if (!grew && prevActive) {
489
+ for (const k of touched) {
490
+ if (!prevActive.includes(k)) {
491
+ grew = true;
492
+ break;
493
+ }
534
494
  }
535
495
  }
536
- const transformGroup = transformPending > 0 ? { remaining: transformPending } : void 0;
537
- for (const key of ALL_KEYS) {
538
- const target = SHADOW_OFFSET_KEY_SET.has(key) ? shadowOffsetAxisValue(
539
- baseRecord.shadowOffset,
540
- shadowOffsetAxisFor(key)
541
- ) : baseRecord[key];
542
- if (target === void 0) continue;
543
- const cfg = shouldReduceMotion ? { type: "no-animation" } : transitionFor(
544
- SHADOW_OFFSET_KEY_SET.has(key) ? "shadowOffset" : key,
545
- transition
546
- );
547
- if (isExiting) pending++;
548
- const factory = makeKeyCallbackFactory(
549
- key,
550
- sharedValues[key],
551
- targetEndValue(target),
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
496
+ if (grew) {
497
+ const merged = new Set(prevActive ?? []);
498
+ for (const k of touched) merged.add(k);
499
+ activeKeysRef.current = ALL_KEYS.filter((k) => merged.has(k));
500
+ hasTransformRef.current = activeKeysRef.current.some(
501
+ (k) => TRANSFORM_KEY_SET.has(k)
559
502
  );
560
- sharedValues[key].value = resolveAnimatableValue(
561
- target,
562
- cfg,
563
- factory
503
+ hasShadowOffsetRef.current = activeKeysRef.current.some(
504
+ (k) => SHADOW_OFFSET_KEY_SET.has(k)
564
505
  );
565
506
  }
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;
507
+ const sharedValues = useAnimatableSharedValues((key) => {
508
+ if (SHADOW_OFFSET_KEY_SET.has(key)) {
509
+ const axis = shadowOffsetAxisFor(key);
510
+ if (initial === false) {
511
+ return shadowOffsetAxisValue(animateRecord.shadowOffset, axis) ?? DEFAULT_RESTING[key];
512
+ }
513
+ return shadowOffsetAxisValue(
514
+ initialRecord?.shadowOffset,
515
+ axis
516
+ ) ?? shadowOffsetAxisValue(animateRecord.shadowOffset, axis) ?? DEFAULT_RESTING[key];
638
517
  }
639
- if (focusedLayer && pf > 0 && focusedLayer[key] !== void 0) {
640
- const t = focusedLayer[key];
641
- v = isColor ? interpolateColor(pf, [0, 1], [v, t]) : v + (t - v) * pf;
518
+ if (initial === false) {
519
+ const a = animateRecord[key];
520
+ return restValue(a) ?? DEFAULT_RESTING[key];
642
521
  }
643
- if (focusVisibleLayer && pfv > 0 && focusVisibleLayer[key] !== void 0) {
644
- const t = focusVisibleLayer[key];
645
- v = isColor ? interpolateColor(pfv, [0, 1], [v, t]) : v + (t - v) * pfv;
522
+ return initialRecord?.[key] ?? restValue(animateRecord[key]) ?? DEFAULT_RESTING[key];
523
+ });
524
+ const pressedProgress = useSharedValue(0);
525
+ const focusedProgress = useSharedValue(0);
526
+ const focusVisibleProgress = useSharedValue(0);
527
+ const hoveredProgress = useSharedValue(0);
528
+ useEffect(
529
+ () => () => {
530
+ cancelAnimation(pressedProgress);
531
+ cancelAnimation(focusedProgress);
532
+ cancelAnimation(focusVisibleProgress);
533
+ cancelAnimation(hoveredProgress);
534
+ },
535
+ // The progress SVs are identity-stable per hook instance.
536
+ // eslint-disable-next-line react-hooks/exhaustive-deps
537
+ []
538
+ );
539
+ const gestureSV = useSharedValue(
540
+ resolveGestureLayers(gesture)
541
+ );
542
+ const gestureTargetsSig = stableSig(gesture);
543
+ useEffect(() => {
544
+ gestureSV.value = resolveGestureLayers(gesture);
545
+ }, [gestureTargetsSig]);
546
+ const baseRecord = isExiting && exitRecord ? { ...animateRecord, ...exitRecord } : animateRecord;
547
+ const baseSig = stableSig(baseRecord) + (isExiting ? "|exit" : "") + (shouldReduceMotion ? "|rm" : "");
548
+ const transitionSig = stableSig(transition);
549
+ const safeToRemoveRef = useRef(void 0);
550
+ safeToRemoveRef.current = presence?.safeToRemove;
551
+ useEffect(() => {
552
+ if (isExiting && (!exitRecord || Object.keys(exitRecord).length === 0)) {
553
+ safeToRemoveRef.current?.();
554
+ return;
646
555
  }
647
- if (pressedLayer && pp > 0 && pressedLayer[key] !== void 0) {
648
- const t = pressedLayer[key];
649
- v = isColor ? interpolateColor(pp, [0, 1], [v, t]) : v + (t - v) * pp;
556
+ let pending = 0;
557
+ let done = false;
558
+ const onSettle = () => {
559
+ if (done) return;
560
+ pending--;
561
+ if (pending <= 0) {
562
+ done = true;
563
+ if (isExiting) safeToRemoveRef.current?.();
564
+ }
565
+ };
566
+ let transformPending = 0;
567
+ for (const k of ALL_KEYS) {
568
+ if (TRANSFORM_KEY_SET.has(k) && baseRecord[k] !== void 0) {
569
+ transformPending++;
570
+ }
650
571
  }
651
- if (TRANSFORM_KEY_SET.has(key)) {
652
- transform.push(
653
- ROTATION_KEYS.has(key) ? { [key]: `${v}deg` } : { [key]: v }
572
+ const transformGroup = transformPending > 0 ? { remaining: transformPending } : void 0;
573
+ for (const key of ALL_KEYS) {
574
+ const target = SHADOW_OFFSET_KEY_SET.has(key) ? shadowOffsetAxisValue(
575
+ baseRecord.shadowOffset,
576
+ shadowOffsetAxisFor(key)
577
+ ) : baseRecord[key];
578
+ if (target === void 0) continue;
579
+ const cfg = shouldReduceMotion ? { type: "no-animation" } : transitionFor(
580
+ SHADOW_OFFSET_KEY_SET.has(key) ? "shadowOffset" : key,
581
+ transition
582
+ );
583
+ if (isExiting) pending++;
584
+ const factory = makeKeyCallbackFactory(
585
+ key,
586
+ sharedValues[key],
587
+ targetEndValue(target),
588
+ onAnimationEndRef,
589
+ {
590
+ stepCount: stepCountOf(target),
591
+ totalIterations: totalIterationsOf(cfg)
592
+ },
593
+ isExiting ? onSettle : void 0,
594
+ TRANSFORM_KEY_SET.has(key) ? transformGroup : void 0
595
+ );
596
+ sharedValues[key].value = resolveAnimatableValue(
597
+ target,
598
+ cfg,
599
+ factory
654
600
  );
655
- } else if (key === "shadowOffsetWidth") {
656
- shadowOffsetW = v;
657
- } else if (key === "shadowOffsetHeight") {
658
- shadowOffsetH = v;
659
- } else {
660
- out[key] = v;
661
601
  }
662
- }
663
- if (hasLayoutId) {
664
- transform.push({ translateX: flip.dx.value });
665
- transform.push({ translateY: flip.dy.value });
666
- transform.push({ scaleX: flip.sx.value });
667
- transform.push({ scaleY: flip.sy.value });
668
- }
669
- if (hasTransform || hasLayoutId) out.transform = transform;
670
- if (hasShadowOffset) {
671
- out.shadowOffset = { width: shadowOffsetW, height: shadowOffsetH };
672
- }
673
- return out;
674
- });
675
- const mergedStyle = useMemo(
676
- () => isExiting ? [style, animatedStyle, EXITING_POINTER_EVENTS_STYLE] : [style, animatedStyle],
677
- [style, animatedStyle, isExiting]
678
- );
679
- const gestureHandlers = useGestureHandlers(
680
- gesture,
681
- rest,
682
- setPressed,
683
- setFocused,
684
- setFocusVisible,
685
- setHovered
686
- );
687
- const layoutSig = stableSig(layout);
688
- const layoutTransition = useMemo(
689
- () => shouldReduceMotion ? void 0 : resolveLayoutTransition(layout),
690
- // eslint-disable-next-line react-hooks/exhaustive-deps
691
- [layoutSig, shouldReduceMotion]
692
- );
693
- return /* @__PURE__ */ jsx(
694
- AnimatedComponent,
695
- {
696
- ref: sharedLayout.setRef,
697
- ...rest,
698
- ...gestureHandlers,
699
- onLayout: sharedLayout.onLayout,
700
- layout: layoutTransition,
701
- style: mergedStyle
702
- }
703
- );
602
+ if (isExiting && pending === 0) {
603
+ safeToRemoveRef.current?.();
604
+ }
605
+ }, [baseSig, transitionSig]);
606
+ useGestureLayerProgress(
607
+ pressedProgress,
608
+ pressed,
609
+ gesture?.pressed != null,
610
+ "pressed",
611
+ transition,
612
+ isExiting,
613
+ shouldReduceMotion
614
+ );
615
+ useGestureLayerProgress(
616
+ focusedProgress,
617
+ focused,
618
+ gesture?.focused != null,
619
+ "focused",
620
+ transition,
621
+ isExiting,
622
+ shouldReduceMotion
623
+ );
624
+ useGestureLayerProgress(
625
+ focusVisibleProgress,
626
+ focusVisible,
627
+ gesture?.focusVisible != null,
628
+ "focusVisible",
629
+ transition,
630
+ isExiting,
631
+ shouldReduceMotion
632
+ );
633
+ useGestureLayerProgress(
634
+ hoveredProgress,
635
+ hovered,
636
+ gesture?.hovered != null,
637
+ "hovered",
638
+ transition,
639
+ isExiting,
640
+ shouldReduceMotion
641
+ );
642
+ const sharedLayout = useSharedLayout({
643
+ layoutId,
644
+ userRef: ref,
645
+ transition: isTopLevelTransition(transition) ? transition : void 0,
646
+ shouldReduceMotion,
647
+ userOnLayout
648
+ });
649
+ const flip = sharedLayout.flip;
650
+ const hasLayoutId = layoutId !== void 0;
651
+ const animatedStyle = useAnimatedStyle(() => {
652
+ const activeKeys = activeKeysRef.current;
653
+ const hasTransform = hasTransformRef.current;
654
+ const hasShadowOffset = hasShadowOffsetRef.current;
655
+ const out = {};
656
+ const transform = [];
657
+ let shadowOffsetW = 0;
658
+ let shadowOffsetH = 0;
659
+ const ph = hoveredProgress.value;
660
+ const pf = focusedProgress.value;
661
+ const pfv = focusVisibleProgress.value;
662
+ const pp = pressedProgress.value;
663
+ const layers = gestureSV.value;
664
+ const hoveredLayer = layers ? layers.hovered : null;
665
+ const focusedLayer = layers ? layers.focused : null;
666
+ const focusVisibleLayer = layers ? layers.focusVisible : null;
667
+ const pressedLayer = layers ? layers.pressed : null;
668
+ for (const key of activeKeys) {
669
+ let v = sharedValues[key].value;
670
+ const isColor = COLOR_KEY_SET.has(key);
671
+ if (hoveredLayer && ph > 0 && hoveredLayer[key] !== void 0) {
672
+ const t = hoveredLayer[key];
673
+ v = isColor ? interpolateColor(ph, [0, 1], [v, t]) : v + (t - v) * ph;
674
+ }
675
+ if (focusedLayer && pf > 0 && focusedLayer[key] !== void 0) {
676
+ const t = focusedLayer[key];
677
+ v = isColor ? interpolateColor(pf, [0, 1], [v, t]) : v + (t - v) * pf;
678
+ }
679
+ if (focusVisibleLayer && pfv > 0 && focusVisibleLayer[key] !== void 0) {
680
+ const t = focusVisibleLayer[key];
681
+ v = isColor ? interpolateColor(pfv, [0, 1], [v, t]) : v + (t - v) * pfv;
682
+ }
683
+ if (pressedLayer && pp > 0 && pressedLayer[key] !== void 0) {
684
+ const t = pressedLayer[key];
685
+ v = isColor ? interpolateColor(pp, [0, 1], [v, t]) : v + (t - v) * pp;
686
+ }
687
+ if (TRANSFORM_KEY_SET.has(key)) {
688
+ transform.push(
689
+ ROTATION_KEYS.has(key) ? { [key]: `${v}deg` } : { [key]: v }
690
+ );
691
+ } else if (key === "shadowOffsetWidth") {
692
+ shadowOffsetW = v;
693
+ } else if (key === "shadowOffsetHeight") {
694
+ shadowOffsetH = v;
695
+ } else {
696
+ out[key] = v;
697
+ }
698
+ }
699
+ if (hasLayoutId) {
700
+ transform.push({ translateX: flip.dx.value });
701
+ transform.push({ translateY: flip.dy.value });
702
+ transform.push({ scaleX: flip.sx.value });
703
+ transform.push({ scaleY: flip.sy.value });
704
+ }
705
+ if (hasTransform || hasLayoutId) out.transform = transform;
706
+ if (hasShadowOffset) {
707
+ out.shadowOffset = { width: shadowOffsetW, height: shadowOffsetH };
708
+ }
709
+ return out;
710
+ });
711
+ const mergedStyle = useMemo(
712
+ () => isExiting ? [style, animatedStyle, EXITING_POINTER_EVENTS_STYLE] : [style, animatedStyle],
713
+ [style, animatedStyle, isExiting]
714
+ );
715
+ const gestureHandlers = useGestureHandlers(
716
+ gesture,
717
+ rest,
718
+ setPressed,
719
+ setFocused,
720
+ setFocusVisible,
721
+ setHovered
722
+ );
723
+ const layoutSig = stableSig(layout);
724
+ const layoutTransition = useMemo(
725
+ () => shouldReduceMotion ? void 0 : resolveLayoutTransition(layout),
726
+ // eslint-disable-next-line react-hooks/exhaustive-deps
727
+ [layoutSig, shouldReduceMotion]
728
+ );
729
+ return /* @__PURE__ */ jsx(
730
+ AnimatedComponent,
731
+ {
732
+ ref: sharedLayout.setRef,
733
+ ...rest,
734
+ ...gestureHandlers,
735
+ onLayout: sharedLayout.onLayout,
736
+ layout: layoutTransition,
737
+ style: mergedStyle
738
+ }
739
+ );
740
+ }
741
+ );
742
+ MotionAnimated.displayName = `Motion(${Component.displayName ?? Component.name ?? "Component"})`;
743
+ const Motion = forwardRef(function Motion2(props, ref) {
744
+ if (hasMotionProps(props)) {
745
+ return /* @__PURE__ */ jsx(MotionAnimated, { ref, ...props });
746
+ }
747
+ return /* @__PURE__ */ jsx(PlainHost, { ref, ...props });
704
748
  });
705
749
  Motion.displayName = `Motion(${Component.displayName ?? Component.name ?? "Component"})`;
706
750
  return Motion;
707
751
  }
752
+ var MOTION_PROP_KEYS = [
753
+ "initial",
754
+ "animate",
755
+ "exit",
756
+ "transition",
757
+ "variants",
758
+ "controller",
759
+ "gesture",
760
+ "layout",
761
+ "layoutId",
762
+ "onAnimationEnd"
763
+ ];
764
+ function hasMotionProps(props) {
765
+ for (const key of MOTION_PROP_KEYS) {
766
+ if (props[key] !== void 0) return true;
767
+ }
768
+ return false;
769
+ }
708
770
  function useAnimatableSharedValues(init) {
709
771
  const translateX = useSharedValue(init("translateX"));
710
772
  const translateY = useSharedValue(init("translateY"));
@@ -761,6 +823,17 @@ function useAnimatableSharedValues(init) {
761
823
  shadowOffsetHeight
762
824
  };
763
825
  }
826
+ const map = ref.current;
827
+ useEffect(
828
+ () => () => {
829
+ for (const key in map) {
830
+ cancelAnimation(map[key]);
831
+ }
832
+ },
833
+ // `map` is identity-stable per hook instance.
834
+ // eslint-disable-next-line react-hooks/exhaustive-deps
835
+ []
836
+ );
764
837
  return ref.current;
765
838
  }
766
839
  function makeKeyCallbackFactory(key, sharedValue, target, onAnimationEndRef, meta, onSettle, transformGroup) {