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