@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
package/dist/index.d.ts CHANGED
@@ -339,6 +339,52 @@ declare function buildReleaseAnimation(transition: TransitionConfig, toValue: nu
339
339
  */
340
340
  declare function useAnimation(target: number, transition?: TransitionInput): SharedValue<number>;
341
341
 
342
+ /**
343
+ * Imperative setter that drives a `SharedValue<number>` toward `to`, resolving
344
+ * the transition through the **same context** the declarative surface uses. It
345
+ * is the imperative escape hatch that closes the two footguns of writing
346
+ * `value.value = resolveTransition(config, to)` by hand from an event handler:
347
+ *
348
+ * 1. **Named transitions resolve.** A `TransitionName` registered on the
349
+ * nearest `<MotionConfig transitions>` works here just as it does on the
350
+ * `transition` prop or in `useAnimation`. Raw `resolveTransition` can't
351
+ * reach the registry (names resolve via context), so imperative call sites
352
+ * otherwise rebuild configs the provider already owns.
353
+ * 2. **Reduced motion is respected.** Writes route through the same
354
+ * `no-animation` downgrade `useAnimation` applies under
355
+ * `<MotionConfig reducedMotion>`. Hand-rolled `resolveTransition` writes
356
+ * silently bypass that setting — a correctness bug this hook fixes.
357
+ *
358
+ * The returned callback is identity-stable for the lifetime of the component —
359
+ * it reads the registry and the reduced-motion flag out of refs at call time,
360
+ * so neither a new `<MotionConfig transitions>` map nor a reduced-motion change
361
+ * gives it a new identity. Drop it straight into memoized handlers or a
362
+ * `useCallback` dependency list without churning them.
363
+ *
364
+ * This is not a new animation API — it starts animations in Inertia's existing
365
+ * transition vocabulary, so it does not conflict with the "no imperative-only
366
+ * APIs that bypass the declarative surface" scope rule. It is the hooks-layer
367
+ * equivalent of `useMotionValue` + `resolveTransition`, minus the footguns.
368
+ *
369
+ * @example
370
+ * ```tsx
371
+ * const hovered = useMotionValue(0)
372
+ * const animate = useAnimator()
373
+ *
374
+ * const onHoverIn = () => animate(hovered, 1, 'state-hover')
375
+ * const onHoverOut = () => animate(hovered, 0, 'state-hover')
376
+ * ```
377
+ *
378
+ * @example
379
+ * ```tsx
380
+ * // Inline config works too; default is spring when omitted.
381
+ * animate(progress, 1, { type: 'timing', duration: 150 })
382
+ * animate(progress, 0) // spring
383
+ * ```
384
+ */
385
+ type Animator = (value: SharedValue<number>, to: number, transition?: TransitionInput) => void;
386
+ declare function useAnimator(): Animator;
387
+
342
388
  /**
343
389
  * Toggle a 0↔1 progress value with a spring whenever `active` flips.
344
390
  *
@@ -406,56 +452,64 @@ interface UseColorTransitionOptions {
406
452
  declare function useColorTransition(progress: SharedValue<number>, range: readonly [string, string], options?: UseColorTransitionOptions): ReturnType<typeof useAnimatedStyle>;
407
453
 
408
454
  /**
409
- * Create an animatable value owned by JS but readable from worklets.
410
- *
411
- * This is the escape-hatch primitive that the rest of the value-layer hooks
412
- * (`useSpring`, `useTransform`, `useScroll`) compose against. It is a thin
413
- * pass-through over Reanimated's `useSharedValue`: a `SharedValue<T>` with
414
- * `.value` for direct reads/writes (UI-thread reads in worklets, JS-thread
415
- * writes from event handlers / effects).
455
+ * One layer in a color cascade: its own `progress` shared value (0→1) and the
456
+ * color it blends toward as that progress rises. Layers are ordered lowest
457
+ * priority first; a later layer wins over an earlier one at equal progress.
458
+ */
459
+ interface ColorCascadeLayer {
460
+ /** 0→1 driver for this layer. Drive it upstream (spring / boolean / gesture). */
461
+ progress: SharedValue<number>;
462
+ /** The color this layer blends toward as `progress` moves 0→1. */
463
+ color: string;
464
+ }
465
+ interface UseColorCascadeOptions {
466
+ /**
467
+ * Which style slot the composited color is emitted under. Defaults to
468
+ * `backgroundColor` — identical to `useColorTransition`. Override for ring
469
+ * colors (`borderColor`), text (`color`), image tints (`tintColor`), etc.
470
+ */
471
+ key?: ColorStyleKey;
472
+ }
473
+ /**
474
+ * Priority-ordered layered color crossfade: each layer owns an independent
475
+ * `progress` value and blends the accumulated color below it toward its own
476
+ * color as that progress moves 0→1. Later layers win over earlier ones — the
477
+ * array is priority order, **lowest first** (matching the `gesture` prop's
478
+ * fixed-priority cascade, Decision 5).
416
479
  *
417
- * We intentionally do not introduce a `MotionValue` wrapper class around the
418
- * shared value. The simplest object that interops with `useAnimatedStyle`,
419
- * `useDerivedValue`, and every other Reanimated API _is_ the shared value
420
- * itself; adding a `{ get, set, value }` shell would force consumers to
421
- * unwrap it at every Reanimated boundary and break worklet capture.
480
+ * Equivalent to the hand-chained nested-`interpolateColor` shape
481
+ * `focus(error(hover(rest)))`, collapsed into one hook and one worklet:
422
482
  *
423
- * Worklet read:
424
- * ```ts
425
- * const x = useMotionValue(0)
426
- * useAnimatedStyle(() => ({ transform: [{ translateX: x.value }] }))
427
- * ```
483
+ * ```tsx
484
+ * const borderStyle = useColorCascade(
485
+ * colors.border,
486
+ * [
487
+ * { progress: hovered, color: colors.borderHover },
488
+ * { progress: errored, color: colors.borderError },
489
+ * { progress: focused, color: colors.borderFocus },
490
+ * ],
491
+ * { key: 'borderColor' },
492
+ * )
428
493
  *
429
- * JS write:
430
- * ```ts
431
- * onPress={() => { x.value = 100 }}
494
+ * return <Motion.View style={[styles.field, borderStyle]} />
432
495
  * ```
433
- */
434
- declare function useMotionValue(initial: number): SharedValue<number>;
435
- declare function useMotionValue(initial: string): SharedValue<string>;
436
- declare function useMotionValue<T extends number | string>(initial: T): SharedValue<T>;
437
-
438
- /**
439
- * Animate a shared value toward `target` with spring physics, using the
440
- * library's react-spring vocabulary (`tension` / `friction` / `mass`).
441
496
  *
442
- * `target` may be a plain number or a `SharedValue<number>`. The plain-number
443
- * path drives the spring from a JS `useEffect`, so the animation re-runs on
444
- * every render where `target` changes. The shared-value path drives the
445
- * spring from a Reanimated reaction on the UI thread, so values produced by
446
- * gestures, scroll handlers, or other worklets flow through without bouncing
447
- * back to JS.
497
+ * This is a pure interpolator it does not animate on its own. Drive each
498
+ * layer's `progress` upstream with a `useSpring`, `useBooleanSpring`, gesture
499
+ * progress, or anything else producing a 0→1 shared value.
448
500
  *
449
- * Both call sites end up at the same `withSpring` invocation; the split is
450
- * just about which thread observes the source change.
501
+ * For the single-layer case (`rest` one active color), reach for
502
+ * [`useColorTransition`](./useColorTransition) it is the fast path and this
503
+ * hook is not a replacement for it. For a mixed numeric + color cascade, or
504
+ * function-valued layers, drop to a hand-rolled `useAnimatedStyle`.
451
505
  *
452
- * `config` also accepts a `TransitionName` registered on the nearest
453
- * `<MotionConfig transitions>`. Because this hook is spring-only, the name
454
- * must resolve to a spring config — a name registered as timing / decay /
455
- * no-animation warns in dev and falls back to the default spring (reach for
456
- * `useAnimation` when the named transition's type should be honored).
506
+ * The layer chain is resolved once on the JS thread and kept identity-stable,
507
+ * so a fresh-but-equal `layers` array each render produces no new UI-thread
508
+ * closure (CLAUDE.md principle 8). Changing a colour, the `key`, the base
509
+ * `rest`, the layer count, or **which shared value drives a layer** all rewire
510
+ * the worklet as you'd expect.
457
511
  */
458
- declare function useSpring(target: number | SharedValue<number>, config?: SpringTransition | TransitionName): SharedValue<number>;
512
+ declare function useColorCascade(rest: string, layers: readonly ColorCascadeLayer[], options?: UseColorCascadeOptions): ReturnType<typeof useAnimatedStyle>;
459
513
 
460
514
  /**
461
515
  * Extrapolation behavior at the edges of the input range. Mirrors
@@ -509,6 +563,140 @@ declare function useTransform<T>(transformer: () => T): SharedValue<T>;
509
563
  declare function useTransform(value: SharedValue<number>, inputRange: readonly number[], outputRange: readonly number[], options?: UseTransformOptions): SharedValue<number>;
510
564
  declare function useTransform(value: SharedValue<number>, inputRange: readonly number[], outputRange: readonly string[], options?: UseTransformOptions): SharedValue<string>;
511
565
 
566
+ /**
567
+ * Numeric style keys `useInterpolatedStyle` can emit directly (not lifted into
568
+ * the transform array). Mirrors the flat numeric surface of the `animate`
569
+ * prop.
570
+ */
571
+ type NumericStyleKey = 'opacity' | 'width' | 'height' | 'borderRadius' | 'shadowOpacity' | 'shadowRadius' | 'elevation' | 'top' | 'left' | 'right' | 'bottom' | 'fontSize' | 'lineHeight' | 'letterSpacing' | 'borderWidth';
572
+ /**
573
+ * Transform keys, lifted into a `transform: [...]` array in the order they
574
+ * appear in the map — the same key-order convention the `animate` prop uses.
575
+ * `rotate` / `rotateX` / `rotateY` take numeric degrees and emit
576
+ * `'<n>deg'` strings.
577
+ */
578
+ type TransformKey = 'translateX' | 'translateY' | 'scale' | 'scaleX' | 'scaleY' | 'rotate' | 'rotateX' | 'rotateY';
579
+ /**
580
+ * Interpolation map: each entry maps `progress` onto an output range for one
581
+ * style or transform key. Numeric / transform keys take number stops; color
582
+ * keys take color-string stops. Mixing stop types per key is a compile error.
583
+ */
584
+ type InterpolatedStyleMap = {
585
+ [K in NumericStyleKey | TransformKey]?: readonly number[];
586
+ } & {
587
+ [K in ColorStyleKey]?: readonly string[];
588
+ };
589
+ interface UseInterpolatedStyleOptions {
590
+ /**
591
+ * Input range mapped onto every key's output range. Defaults to `[0, 1]`
592
+ * for 2-stop outputs, and to evenly-spaced stops across `[0, 1]` for
593
+ * longer outputs. When provided, it applies to all keys; a key whose
594
+ * output length differs from `inputRange.length` throws in dev.
595
+ */
596
+ inputRange?: readonly number[];
597
+ /**
598
+ * Edge behavior outside the input range. Defaults to `'clamp'`, matching
599
+ * `useColorTransition`. Applies to numeric keys; color interpolation
600
+ * always clamps (Reanimated's `interpolateColor` has no extrapolation
601
+ * option).
602
+ */
603
+ extrapolate?: ExtrapolationMode;
604
+ }
605
+ /**
606
+ * Map one `progress` shared value onto N style props via `interpolate` /
607
+ * `interpolateColor`, returning an animated style fragment that composes in a
608
+ * style array on any Reanimated-aware host (`Motion.*`, a hand-rolled
609
+ * `Animated.View`). The style-fragment counterpart to `useTransform`'s
610
+ * output-range form, in the same family as `useColorTransition` / `useShadow`.
611
+ *
612
+ * ```tsx
613
+ * const collapseStyle = useInterpolatedStyle(collapseProgress, {
614
+ * height: [expandedHeight, collapsedHeight],
615
+ * fontSize: [expanded.fontSize, collapsed.fontSize],
616
+ * })
617
+ *
618
+ * const labelStyle = useInterpolatedStyle(floatProgress, {
619
+ * translateY: [restingOffset, 0],
620
+ * scale: [restingScale, 1],
621
+ * })
622
+ *
623
+ * return <Motion.View style={[base, collapseStyle, labelStyle]} />
624
+ * ```
625
+ *
626
+ * This is a pure interpolator — it does not animate on its own. Drive
627
+ * `progress` upstream with a `useSpring`, `useBooleanSpring`, gesture
628
+ * progress, or scroll-derived `useTransform`.
629
+ *
630
+ * - Numeric / transform keys route through `interpolate`; color-string stops
631
+ * on a color key route through `interpolateColor` (a multi-stop
632
+ * `useColorTransition` without touching that hook).
633
+ * - Transform keys (`translateX`, `scale`, `rotate`, …) are lifted into a
634
+ * single `transform` array in the order they appear in the map. `rotate*`
635
+ * keys take numeric degrees and emit `'<n>deg'` strings, consistent with
636
+ * the `animate` surface.
637
+ * - `options.inputRange` defaults to `[0, 1]` for 2-stop outputs and to
638
+ * evenly-spaced stops otherwise. `options.extrapolate` defaults to
639
+ * `'clamp'`.
640
+ *
641
+ * For function-valued entries or multi-source composition, drop to a
642
+ * hand-rolled `useAnimatedStyle` (or `useTransform`'s worklet form) — this
643
+ * hook stays fully declarative and hashable so unchanged maps produce zero
644
+ * new UI-thread closures.
645
+ */
646
+ declare function useInterpolatedStyle(progress: SharedValue<number>, map: InterpolatedStyleMap, options?: UseInterpolatedStyleOptions): ReturnType<typeof useAnimatedStyle>;
647
+
648
+ /**
649
+ * Create an animatable value owned by JS but readable from worklets.
650
+ *
651
+ * This is the escape-hatch primitive that the rest of the value-layer hooks
652
+ * (`useSpring`, `useTransform`, `useScroll`) compose against. It is a thin
653
+ * pass-through over Reanimated's `useSharedValue`: a `SharedValue<T>` with
654
+ * `.value` for direct reads/writes (UI-thread reads in worklets, JS-thread
655
+ * writes from event handlers / effects).
656
+ *
657
+ * We intentionally do not introduce a `MotionValue` wrapper class around the
658
+ * shared value. The simplest object that interops with `useAnimatedStyle`,
659
+ * `useDerivedValue`, and every other Reanimated API _is_ the shared value
660
+ * itself; adding a `{ get, set, value }` shell would force consumers to
661
+ * unwrap it at every Reanimated boundary and break worklet capture.
662
+ *
663
+ * Worklet read:
664
+ * ```ts
665
+ * const x = useMotionValue(0)
666
+ * useAnimatedStyle(() => ({ transform: [{ translateX: x.value }] }))
667
+ * ```
668
+ *
669
+ * JS write:
670
+ * ```ts
671
+ * onPress={() => { x.value = 100 }}
672
+ * ```
673
+ */
674
+ declare function useMotionValue(initial: number): SharedValue<number>;
675
+ declare function useMotionValue(initial: string): SharedValue<string>;
676
+ declare function useMotionValue<T extends number | string>(initial: T): SharedValue<T>;
677
+
678
+ /**
679
+ * Animate a shared value toward `target` with spring physics, using the
680
+ * library's react-spring vocabulary (`tension` / `friction` / `mass`).
681
+ *
682
+ * `target` may be a plain number or a `SharedValue<number>`. The plain-number
683
+ * path drives the spring from a JS `useEffect`, so the animation re-runs on
684
+ * every render where `target` changes. The shared-value path drives the
685
+ * spring from a Reanimated reaction on the UI thread, so values produced by
686
+ * gestures, scroll handlers, or other worklets flow through without bouncing
687
+ * back to JS.
688
+ *
689
+ * Both call sites end up at the same `withSpring` invocation; the split is
690
+ * just about which thread observes the source change.
691
+ *
692
+ * `config` also accepts a `TransitionName` registered on the nearest
693
+ * `<MotionConfig transitions>`. Because this hook is spring-only, the name
694
+ * must resolve to a spring config — a name registered as timing / decay /
695
+ * no-animation warns in dev and falls back to the default spring (reach for
696
+ * `useAnimation` when the named transition's type should be honored).
697
+ */
698
+ declare function useSpring(target: number | SharedValue<number>, config?: SpringTransition | TransitionName): SharedValue<number>;
699
+
512
700
  interface UseScrollResult {
513
701
  /** Horizontal scroll offset in points. */
514
702
  scrollX: SharedValue<number>;
@@ -681,4 +869,4 @@ declare function useShadow({ from, to, progress, }: UseShadowOptions): ReturnTyp
681
869
  */
682
870
  declare function useVariants<V extends Readonly<Record<string, object>>>(variants: V, initial?: keyof V & string): VariantController<keyof V & string>;
683
871
 
684
- export { AnimatableValue, type BoxShadowLayer, type ColorStyleKey, EasingInput, type ExtrapolationMode, Motion, MotionComponent, MotionConfig, type MotionConfigProps, type MotionConfigValue, NamedTransitions, Presence, type PresenceContextValue, type ReducedMotion, type ShadowConfig, SpringTransition, TransitionConfig, TransitionInput, TransitionName, type UseColorTransitionOptions, type UseScrollResult, type UseShadowOptions, type UseTransformOptions, VariantController, buildReleaseAnimation, createMotionComponent, cubicBezier, ensureWorkletEasing, resolveAnimatableValue, resolveNamedTransition, resolveTransition, useAnimation, useBooleanSpring, useColorTransition, useMotionConfig, useMotionValue, useNamedTransitions, usePresence, useScroll, useShadow, useShouldReduceMotion, useSpring, useTransform, useVariants };
872
+ export { AnimatableValue, type Animator, type BoxShadowLayer, type ColorCascadeLayer, type ColorStyleKey, EasingInput, type ExtrapolationMode, type InterpolatedStyleMap, Motion, MotionComponent, MotionConfig, type MotionConfigProps, type MotionConfigValue, NamedTransitions, type NumericStyleKey, Presence, type PresenceContextValue, type ReducedMotion, type ShadowConfig, SpringTransition, type TransformKey, TransitionConfig, TransitionInput, TransitionName, type UseColorCascadeOptions, type UseColorTransitionOptions, type UseInterpolatedStyleOptions, type UseScrollResult, type UseShadowOptions, type UseTransformOptions, VariantController, buildReleaseAnimation, createMotionComponent, cubicBezier, ensureWorkletEasing, resolveAnimatableValue, resolveNamedTransition, resolveTransition, useAnimation, useAnimator, useBooleanSpring, useColorCascade, useColorTransition, useInterpolatedStyle, useMotionConfig, useMotionValue, useNamedTransitions, usePresence, useScroll, useShadow, useShouldReduceMotion, useSpring, useTransform, useVariants };
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  'use strict';
2
2
 
3
3
  var chunk4PEHWDAZ_js = require('./chunk-4PEHWDAZ.js');
4
- var chunk4QGXK6TF_js = require('./chunk-4QGXK6TF.js');
5
- var chunkZ7HIOFKQ_js = require('./chunk-Z7HIOFKQ.js');
6
- var chunk3UTJJ4A3_js = require('./chunk-3UTJJ4A3.js');
7
- var chunkTDSO63CJ_js = require('./chunk-TDSO63CJ.js');
8
- var chunk2HYD2ZBK_js = require('./chunk-2HYD2ZBK.js');
9
- var chunk7UDYEFBU_js = require('./chunk-7UDYEFBU.js');
4
+ var chunkFNVFV4EY_js = require('./chunk-FNVFV4EY.js');
5
+ var chunkFWQOXA43_js = require('./chunk-FWQOXA43.js');
6
+ var chunkKBP4LR75_js = require('./chunk-KBP4LR75.js');
7
+ var chunk3XTVY34H_js = require('./chunk-3XTVY34H.js');
8
+ var chunkW5MC3P4N_js = require('./chunk-W5MC3P4N.js');
9
+ var chunkBP3Y2SHQ_js = require('./chunk-BP3Y2SHQ.js');
10
10
  var chunk7AOERN53_js = require('./chunk-7AOERN53.js');
11
11
  var chunkPTRF47DA_js = require('./chunk-PTRF47DA.js');
12
12
  var react = require('react');
@@ -15,11 +15,11 @@ var reactNativeWorklets = require('react-native-worklets');
15
15
 
16
16
  // src/motion/index.ts
17
17
  var Motion = {
18
- View: chunk4QGXK6TF_js.MotionView,
19
- Text: chunkZ7HIOFKQ_js.MotionText,
20
- Image: chunk3UTJJ4A3_js.MotionImage,
21
- Pressable: chunkTDSO63CJ_js.MotionPressable,
22
- ScrollView: chunk2HYD2ZBK_js.MotionScrollView
18
+ View: chunkFNVFV4EY_js.MotionView,
19
+ Text: chunkFWQOXA43_js.MotionText,
20
+ Image: chunkKBP4LR75_js.MotionImage,
21
+ Pressable: chunk3XTVY34H_js.MotionPressable,
22
+ ScrollView: chunkW5MC3P4N_js.MotionScrollView
23
23
  };
24
24
  function useAnimation(target, transition) {
25
25
  const output = reactNativeReanimated.useSharedValue(target);
@@ -30,8 +30,27 @@ function useAnimation(target, transition) {
30
30
  const cfg = shouldReduceMotion ? { type: "no-animation" } : resolved ?? { type: "spring" };
31
31
  output.value = chunkPTRF47DA_js.resolveTransition(cfg, target);
32
32
  }, [target, cfgSig, shouldReduceMotion]);
33
+ react.useEffect(
34
+ () => () => reactNativeReanimated.cancelAnimation(output),
35
+ // `output` is identity-stable per hook instance (Reanimated guarantee).
36
+ // eslint-disable-next-line react-hooks/exhaustive-deps
37
+ []
38
+ );
33
39
  return output;
34
40
  }
41
+ function useAnimator() {
42
+ const registry = chunk7AOERN53_js.useNamedTransitions();
43
+ const shouldReduceMotion = chunk7AOERN53_js.useShouldReduceMotion();
44
+ const registryRef = react.useRef(registry);
45
+ registryRef.current = registry;
46
+ const reduceMotionRef = react.useRef(shouldReduceMotion);
47
+ reduceMotionRef.current = shouldReduceMotion;
48
+ return react.useCallback((value, to, transition) => {
49
+ const resolved = chunk7AOERN53_js.resolveNamedTransition(transition, registryRef.current);
50
+ const cfg = reduceMotionRef.current ? { type: "no-animation" } : resolved ?? { type: "spring" };
51
+ value.value = chunkPTRF47DA_js.resolveTransition(cfg, to);
52
+ }, []);
53
+ }
35
54
  function useSpring(target, config) {
36
55
  const spring = resolveSpringInput(config, chunk7AOERN53_js.useNamedTransitions());
37
56
  const reanimConfig = react.useMemo(
@@ -70,6 +89,12 @@ function useSpring(target, config) {
70
89
  },
71
90
  [isSharedTarget, reanimConfig]
72
91
  );
92
+ react.useEffect(
93
+ () => () => reactNativeReanimated.cancelAnimation(output),
94
+ // `output` is identity-stable per hook instance (Reanimated guarantee).
95
+ // eslint-disable-next-line react-hooks/exhaustive-deps
96
+ []
97
+ );
73
98
  return output;
74
99
  }
75
100
  function resolveSpringInput(config, registry) {
@@ -91,6 +116,36 @@ function isSharedValue(v) {
91
116
  function useBooleanSpring(active, springConfig) {
92
117
  return useSpring(active ? 1 : 0, springConfig);
93
118
  }
119
+ function useColorCascade(rest, layers, options) {
120
+ const key = options?.key ?? "backgroundColor";
121
+ const sig = `${key}|${rest}|${layers.length}|${layers.map((l) => l.color).join(",")}`;
122
+ const colors = react.useMemo(() => layers.map((l) => l.color), [sig]);
123
+ const progressRef = react.useRef([]);
124
+ const prevProgress = progressRef.current;
125
+ let progressChanged = prevProgress.length !== layers.length;
126
+ if (!progressChanged) {
127
+ for (let i = 0; i < layers.length; i++) {
128
+ if (prevProgress[i] !== layers[i].progress) {
129
+ progressChanged = true;
130
+ break;
131
+ }
132
+ }
133
+ }
134
+ if (progressChanged) progressRef.current = layers.map((l) => l.progress);
135
+ const progressValues = progressRef.current;
136
+ return reactNativeReanimated.useAnimatedStyle(() => {
137
+ "worklet";
138
+ let acc = rest;
139
+ for (let i = 0; i < colors.length; i++) {
140
+ acc = reactNativeReanimated.interpolateColor(
141
+ progressValues[i].value,
142
+ [0, 1],
143
+ [acc, colors[i]]
144
+ );
145
+ }
146
+ return { [key]: acc };
147
+ });
148
+ }
94
149
  function useColorTransition(progress, range, options) {
95
150
  const key = options?.key ?? "backgroundColor";
96
151
  const from = range[0];
@@ -100,8 +155,139 @@ function useColorTransition(progress, range, options) {
100
155
  return { [key]: reactNativeReanimated.interpolateColor(progress.value, [0, 1], [from, to]) };
101
156
  });
102
157
  }
158
+ var TRANSFORM_KEYS = /* @__PURE__ */ new Set([
159
+ "translateX",
160
+ "translateY",
161
+ "scale",
162
+ "scaleX",
163
+ "scaleY",
164
+ "rotate",
165
+ "rotateX",
166
+ "rotateY"
167
+ ]);
168
+ var ROTATION_KEYS = /* @__PURE__ */ new Set(["rotate", "rotateX", "rotateY"]);
169
+ var COLOR_KEYS = /* @__PURE__ */ new Set([
170
+ "backgroundColor",
171
+ "color",
172
+ "borderColor",
173
+ "borderTopColor",
174
+ "borderRightColor",
175
+ "borderBottomColor",
176
+ "borderLeftColor",
177
+ "tintColor",
178
+ "shadowColor"
179
+ ]);
180
+ function evenlySpaced(count) {
181
+ if (count <= 1) return [0];
182
+ const out = [];
183
+ for (let i = 0; i < count; i++) out.push(i / (count - 1));
184
+ return out;
185
+ }
186
+ function mapExtrapolation(mode) {
187
+ if (mode === "identity") return reactNativeReanimated.Extrapolation.IDENTITY;
188
+ if (mode === "extend") return reactNativeReanimated.Extrapolation.EXTEND;
189
+ return reactNativeReanimated.Extrapolation.CLAMP;
190
+ }
191
+ function buildSignature(map, options) {
192
+ let sig = "";
193
+ for (const key of Object.keys(map)) {
194
+ const output = map[key];
195
+ sig += `${key}:${JSON.stringify(output)}|`;
196
+ }
197
+ sig += `#ir:${JSON.stringify(options?.inputRange)}|ex:${options?.extrapolate ?? ""}`;
198
+ return sig;
199
+ }
200
+ function buildEntries(map, options) {
201
+ const explicitInput = options?.inputRange;
202
+ const entries = [];
203
+ for (const key of Object.keys(map)) {
204
+ const output = map[key];
205
+ if (output === void 0 || output.length === 0) continue;
206
+ const input = explicitInput ? explicitInput : output.length === 2 ? [0, 1] : evenlySpaced(output.length);
207
+ if (__DEV__ && explicitInput && explicitInput.length !== output.length) {
208
+ console.warn(
209
+ `[inertia] useInterpolatedStyle: inputRange has ${explicitInput.length} stops but the "${String(
210
+ key
211
+ )}" output has ${output.length}. They must match \u2014 interpolation results are undefined otherwise.`
212
+ );
213
+ }
214
+ const isColor = COLOR_KEYS.has(key) && typeof output[0] === "string";
215
+ if (isColor) {
216
+ entries.push({
217
+ kind: "color",
218
+ key,
219
+ input,
220
+ output
221
+ });
222
+ } else if (ROTATION_KEYS.has(key)) {
223
+ entries.push({
224
+ kind: "rotation",
225
+ key,
226
+ input,
227
+ output
228
+ });
229
+ } else if (TRANSFORM_KEYS.has(key)) {
230
+ entries.push({
231
+ kind: "transform-numeric",
232
+ key,
233
+ input,
234
+ output
235
+ });
236
+ } else {
237
+ entries.push({
238
+ kind: "numeric",
239
+ key,
240
+ input,
241
+ output
242
+ });
243
+ }
244
+ }
245
+ return entries;
246
+ }
247
+ function useInterpolatedStyle(progress, map, options) {
248
+ const extrapolate = mapExtrapolation(options?.extrapolate);
249
+ const sig = buildSignature(map, options);
250
+ const entries = react.useMemo(() => buildEntries(map, options), [sig]);
251
+ return reactNativeReanimated.useAnimatedStyle(() => {
252
+ "worklet";
253
+ const out = {};
254
+ const transform = [];
255
+ for (const e of entries) {
256
+ if (e.kind === "color") {
257
+ out[e.key] = reactNativeReanimated.interpolateColor(progress.value, e.input, e.output);
258
+ } else if (e.kind === "numeric") {
259
+ out[e.key] = reactNativeReanimated.interpolate(progress.value, e.input, e.output, {
260
+ extrapolateLeft: extrapolate,
261
+ extrapolateRight: extrapolate
262
+ });
263
+ } else if (e.kind === "transform-numeric") {
264
+ transform.push({
265
+ [e.key]: reactNativeReanimated.interpolate(progress.value, e.input, e.output, {
266
+ extrapolateLeft: extrapolate,
267
+ extrapolateRight: extrapolate
268
+ })
269
+ });
270
+ } else {
271
+ const deg = reactNativeReanimated.interpolate(progress.value, e.input, e.output, {
272
+ extrapolateLeft: extrapolate,
273
+ extrapolateRight: extrapolate
274
+ });
275
+ transform.push({ [e.key]: `${deg}deg` });
276
+ }
277
+ }
278
+ if (transform.length > 0) out.transform = transform;
279
+ return out;
280
+ });
281
+ }
103
282
  function useMotionValue(initial) {
104
- return reactNativeReanimated.useSharedValue(initial);
283
+ const sv = reactNativeReanimated.useSharedValue(initial);
284
+ react.useEffect(
285
+ () => () => reactNativeReanimated.cancelAnimation(sv),
286
+ // `sv` is identity-stable per hook instance (Reanimated guarantee).
287
+ // eslint-disable-next-line react-hooks/exhaustive-deps
288
+ []
289
+ );
290
+ return sv;
105
291
  }
106
292
  function useTransform(arg1, inputRange, outputRange, options) {
107
293
  let producer;
@@ -124,8 +310,8 @@ function useTransform(arg1, inputRange, outputRange, options) {
124
310
  const input = inputRange;
125
311
  const output = outputRange;
126
312
  const isColor = output.length > 0 && typeof output[0] === "string";
127
- const extrapolateLeft = mapExtrapolation(options?.extrapolateLeft);
128
- const extrapolateRight = mapExtrapolation(options?.extrapolateRight);
313
+ const extrapolateLeft = mapExtrapolation2(options?.extrapolateLeft);
314
+ const extrapolateRight = mapExtrapolation2(options?.extrapolateRight);
129
315
  producer = isColor ? () => {
130
316
  "worklet";
131
317
  return reactNativeReanimated.interpolateColor(
@@ -145,7 +331,7 @@ function useTransform(arg1, inputRange, outputRange, options) {
145
331
  }
146
332
  return reactNativeReanimated.useDerivedValue(producer);
147
333
  }
148
- function mapExtrapolation(mode) {
334
+ function mapExtrapolation2(mode) {
149
335
  if (mode === "identity") return reactNativeReanimated.Extrapolation.IDENTITY;
150
336
  if (mode === "extend") return reactNativeReanimated.Extrapolation.EXTEND;
151
337
  return reactNativeReanimated.Extrapolation.CLAMP;
@@ -402,35 +588,35 @@ Object.defineProperty(exports, "useGesture", {
402
588
  });
403
589
  Object.defineProperty(exports, "MotionView", {
404
590
  enumerable: true,
405
- get: function () { return chunk4QGXK6TF_js.MotionView; }
591
+ get: function () { return chunkFNVFV4EY_js.MotionView; }
406
592
  });
407
593
  Object.defineProperty(exports, "MotionText", {
408
594
  enumerable: true,
409
- get: function () { return chunkZ7HIOFKQ_js.MotionText; }
595
+ get: function () { return chunkFWQOXA43_js.MotionText; }
410
596
  });
411
597
  Object.defineProperty(exports, "MotionImage", {
412
598
  enumerable: true,
413
- get: function () { return chunk3UTJJ4A3_js.MotionImage; }
599
+ get: function () { return chunkKBP4LR75_js.MotionImage; }
414
600
  });
415
601
  Object.defineProperty(exports, "MotionPressable", {
416
602
  enumerable: true,
417
- get: function () { return chunkTDSO63CJ_js.MotionPressable; }
603
+ get: function () { return chunk3XTVY34H_js.MotionPressable; }
418
604
  });
419
605
  Object.defineProperty(exports, "MotionScrollView", {
420
606
  enumerable: true,
421
- get: function () { return chunk2HYD2ZBK_js.MotionScrollView; }
607
+ get: function () { return chunkW5MC3P4N_js.MotionScrollView; }
422
608
  });
423
609
  Object.defineProperty(exports, "Presence", {
424
610
  enumerable: true,
425
- get: function () { return chunk7UDYEFBU_js.Presence; }
611
+ get: function () { return chunkBP3Y2SHQ_js.Presence; }
426
612
  });
427
613
  Object.defineProperty(exports, "createMotionComponent", {
428
614
  enumerable: true,
429
- get: function () { return chunk7UDYEFBU_js.createMotionComponent; }
615
+ get: function () { return chunkBP3Y2SHQ_js.createMotionComponent; }
430
616
  });
431
617
  Object.defineProperty(exports, "usePresence", {
432
618
  enumerable: true,
433
- get: function () { return chunk7UDYEFBU_js.usePresence; }
619
+ get: function () { return chunkBP3Y2SHQ_js.usePresence; }
434
620
  });
435
621
  Object.defineProperty(exports, "MotionConfig", {
436
622
  enumerable: true,
@@ -474,8 +660,11 @@ Object.defineProperty(exports, "resolveTransition", {
474
660
  });
475
661
  exports.Motion = Motion;
476
662
  exports.useAnimation = useAnimation;
663
+ exports.useAnimator = useAnimator;
477
664
  exports.useBooleanSpring = useBooleanSpring;
665
+ exports.useColorCascade = useColorCascade;
478
666
  exports.useColorTransition = useColorTransition;
667
+ exports.useInterpolatedStyle = useInterpolatedStyle;
479
668
  exports.useMotionValue = useMotionValue;
480
669
  exports.useScroll = useScroll;
481
670
  exports.useShadow = useShadow;