@rootnative/inertia 0.0.0-alpha.1 → 0.0.0-alpha.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 (45) hide show
  1. package/dist/gestureLayer/index.d.mts +42 -2
  2. package/dist/gestureLayer/index.d.ts +42 -2
  3. package/dist/gestureLayer/index.js +18 -3
  4. package/dist/gestureLayer/index.mjs +18 -3
  5. package/dist/index.js +0 -2
  6. package/dist/index.mjs +0 -2
  7. package/dist/motion/Image.js +0 -2
  8. package/dist/motion/Image.mjs +0 -2
  9. package/dist/motion/Pressable.js +0 -2
  10. package/dist/motion/Pressable.mjs +0 -2
  11. package/dist/motion/ScrollView.js +0 -2
  12. package/dist/motion/ScrollView.mjs +0 -2
  13. package/dist/motion/Text.js +0 -2
  14. package/dist/motion/Text.mjs +0 -2
  15. package/dist/motion/View.js +0 -2
  16. package/dist/motion/View.mjs +0 -2
  17. package/dist/testing/index.js +0 -2
  18. package/dist/testing/index.mjs +0 -2
  19. package/dist/touch/index.js +0 -2
  20. package/dist/touch/index.mjs +0 -2
  21. package/llms.txt +2 -2
  22. package/package.json +2 -1
  23. package/src/gestureLayer/index.ts +1 -0
  24. package/src/gestureLayer/useGestureLayer.ts +60 -0
  25. package/dist/gestureLayer/index.js.map +0 -1
  26. package/dist/gestureLayer/index.mjs.map +0 -1
  27. package/dist/index.js.map +0 -1
  28. package/dist/index.mjs.map +0 -1
  29. package/dist/motion/Image.js.map +0 -1
  30. package/dist/motion/Image.mjs.map +0 -1
  31. package/dist/motion/Pressable.js.map +0 -1
  32. package/dist/motion/Pressable.mjs.map +0 -1
  33. package/dist/motion/ScrollView.js.map +0 -1
  34. package/dist/motion/ScrollView.mjs.map +0 -1
  35. package/dist/motion/Text.js.map +0 -1
  36. package/dist/motion/Text.mjs.map +0 -1
  37. package/dist/motion/View.js.map +0 -1
  38. package/dist/motion/View.mjs.map +0 -1
  39. package/dist/testing/index.js.map +0 -1
  40. package/dist/testing/index.mjs.map +0 -1
  41. package/dist/touch/index.js.map +0 -1
  42. package/dist/touch/index.mjs.map +0 -1
  43. package/src/__type-tests__/animate.test-d.tsx +0 -88
  44. package/src/__type-tests__/motion-value.test-d.ts +0 -39
  45. package/src/__type-tests__/variants.test-d.tsx +0 -67
@@ -1,4 +1,4 @@
1
- import { AnimatedStyle } from 'react-native-reanimated';
1
+ import { SharedValue, AnimatedStyle } from 'react-native-reanimated';
2
2
  import { U as UseGestureHandlers } from '../useGesture-C0GBS7d2.mjs';
3
3
  import { T as TransitionInput, n as GestureLayerTransitions } from '../types-BzEgiUdJ.mjs';
4
4
  import 'react';
@@ -55,6 +55,26 @@ interface UseGestureLayerOptions {
55
55
  */
56
56
  transition?: TransitionInput | GestureLayerTransitions;
57
57
  }
58
+ /**
59
+ * The per-state 0↔1 progress shared values behind a `useGestureLayer` call.
60
+ * The gesture entries are the same shared values `useGesture` owns; `disabled`
61
+ * is driven by `options.disabled`. All five are stable across renders — feed
62
+ * them into any `useAnimatedStyle` / `useDerivedValue` (or hooks like
63
+ * `useShadow({ progress })`) to derive extra styles from the same gesture
64
+ * wiring without a second `useGesture` call.
65
+ */
66
+ interface GestureLayerProgress {
67
+ /** 0↔1 progress for the hovered layer (web only — stays at 0 on native). */
68
+ hovered: SharedValue<number>;
69
+ /** 0↔1 progress for the focused layer (any focus modality). */
70
+ focused: SharedValue<number>;
71
+ /** 0↔1 progress for the focusVisible layer (keyboard focus only). */
72
+ focusVisible: SharedValue<number>;
73
+ /** 0↔1 progress for the pressed layer. */
74
+ pressed: SharedValue<number>;
75
+ /** 0↔1 progress for the disabled override (driven by `options.disabled`). */
76
+ disabled: SharedValue<number>;
77
+ }
58
78
  interface UseGestureLayerResult {
59
79
  /**
60
80
  * Animated style produced by `useAnimatedStyle` — spread on an
@@ -63,6 +83,12 @@ interface UseGestureLayerResult {
63
83
  style: AnimatedStyle<Record<string, unknown>>;
64
84
  /** Handlers to spread on the receiving `Pressable`. */
65
85
  handlers: UseGestureHandlers;
86
+ /**
87
+ * Per-state progress shared values — the inputs the composed `style` is
88
+ * derived from. Read-only by convention: writing to them fights the
89
+ * handlers.
90
+ */
91
+ states: GestureLayerProgress;
66
92
  }
67
93
  /**
68
94
  * A "strongest active layer wins" interactive-feedback primitive. Sits one
@@ -85,6 +111,13 @@ interface UseGestureLayerResult {
85
111
  * keys — when active, it lerps the composed value toward the `disabled`
86
112
  * target.
87
113
  *
114
+ * Alongside `style` and `handlers`, the hook returns `states` — the per-state
115
+ * 0↔1 progress shared values the style is derived from (the four gesture
116
+ * layers plus the disabled override). Feed them into other progress-driven
117
+ * hooks (`useShadow`, `useColorTransition`) or a custom `useAnimatedStyle`
118
+ * to derive extra styles from the same gesture wiring — no second
119
+ * `useGesture` call, no duplicated handlers.
120
+ *
88
121
  * Reach for this when you want MD3 / iOS-translucent state-layer overlays
89
122
  * without rewriting the worklet by hand for every consumer; reach for plain
90
123
  * `useGesture()` when you need a composition model this hook doesn't
@@ -114,7 +147,14 @@ interface UseGestureLayerResult {
114
147
  * )
115
148
  * }
116
149
  * ```
150
+ *
151
+ * @example Elevation crossfade driven by the hover progress
152
+ * ```tsx
153
+ * const { style, handlers, states } = useGestureLayer(layers, options)
154
+ * const shadow = useShadow({ from: restShadow, to: raisedShadow, progress: states.hovered })
155
+ * // <Animated.View style={[style, shadow]} />
156
+ * ```
117
157
  */
118
158
  declare function useGestureLayer(states: GestureLayerStates, options?: UseGestureLayerOptions): UseGestureLayerResult;
119
159
 
120
- export { type GestureLayerStates, type GestureLayerStyle, type UseGestureLayerOptions, type UseGestureLayerResult, useGestureLayer };
160
+ export { type GestureLayerProgress, type GestureLayerStates, type GestureLayerStyle, type UseGestureLayerOptions, type UseGestureLayerResult, useGestureLayer };
@@ -1,4 +1,4 @@
1
- import { AnimatedStyle } from 'react-native-reanimated';
1
+ import { SharedValue, AnimatedStyle } from 'react-native-reanimated';
2
2
  import { U as UseGestureHandlers } from '../useGesture-BRLgiNOC.js';
3
3
  import { T as TransitionInput, n as GestureLayerTransitions } from '../types-BzEgiUdJ.js';
4
4
  import 'react';
@@ -55,6 +55,26 @@ interface UseGestureLayerOptions {
55
55
  */
56
56
  transition?: TransitionInput | GestureLayerTransitions;
57
57
  }
58
+ /**
59
+ * The per-state 0↔1 progress shared values behind a `useGestureLayer` call.
60
+ * The gesture entries are the same shared values `useGesture` owns; `disabled`
61
+ * is driven by `options.disabled`. All five are stable across renders — feed
62
+ * them into any `useAnimatedStyle` / `useDerivedValue` (or hooks like
63
+ * `useShadow({ progress })`) to derive extra styles from the same gesture
64
+ * wiring without a second `useGesture` call.
65
+ */
66
+ interface GestureLayerProgress {
67
+ /** 0↔1 progress for the hovered layer (web only — stays at 0 on native). */
68
+ hovered: SharedValue<number>;
69
+ /** 0↔1 progress for the focused layer (any focus modality). */
70
+ focused: SharedValue<number>;
71
+ /** 0↔1 progress for the focusVisible layer (keyboard focus only). */
72
+ focusVisible: SharedValue<number>;
73
+ /** 0↔1 progress for the pressed layer. */
74
+ pressed: SharedValue<number>;
75
+ /** 0↔1 progress for the disabled override (driven by `options.disabled`). */
76
+ disabled: SharedValue<number>;
77
+ }
58
78
  interface UseGestureLayerResult {
59
79
  /**
60
80
  * Animated style produced by `useAnimatedStyle` — spread on an
@@ -63,6 +83,12 @@ interface UseGestureLayerResult {
63
83
  style: AnimatedStyle<Record<string, unknown>>;
64
84
  /** Handlers to spread on the receiving `Pressable`. */
65
85
  handlers: UseGestureHandlers;
86
+ /**
87
+ * Per-state progress shared values — the inputs the composed `style` is
88
+ * derived from. Read-only by convention: writing to them fights the
89
+ * handlers.
90
+ */
91
+ states: GestureLayerProgress;
66
92
  }
67
93
  /**
68
94
  * A "strongest active layer wins" interactive-feedback primitive. Sits one
@@ -85,6 +111,13 @@ interface UseGestureLayerResult {
85
111
  * keys — when active, it lerps the composed value toward the `disabled`
86
112
  * target.
87
113
  *
114
+ * Alongside `style` and `handlers`, the hook returns `states` — the per-state
115
+ * 0↔1 progress shared values the style is derived from (the four gesture
116
+ * layers plus the disabled override). Feed them into other progress-driven
117
+ * hooks (`useShadow`, `useColorTransition`) or a custom `useAnimatedStyle`
118
+ * to derive extra styles from the same gesture wiring — no second
119
+ * `useGesture` call, no duplicated handlers.
120
+ *
88
121
  * Reach for this when you want MD3 / iOS-translucent state-layer overlays
89
122
  * without rewriting the worklet by hand for every consumer; reach for plain
90
123
  * `useGesture()` when you need a composition model this hook doesn't
@@ -114,7 +147,14 @@ interface UseGestureLayerResult {
114
147
  * )
115
148
  * }
116
149
  * ```
150
+ *
151
+ * @example Elevation crossfade driven by the hover progress
152
+ * ```tsx
153
+ * const { style, handlers, states } = useGestureLayer(layers, options)
154
+ * const shadow = useShadow({ from: restShadow, to: raisedShadow, progress: states.hovered })
155
+ * // <Animated.View style={[style, shadow]} />
156
+ * ```
117
157
  */
118
158
  declare function useGestureLayer(states: GestureLayerStates, options?: UseGestureLayerOptions): UseGestureLayerResult;
119
159
 
120
- export { type GestureLayerStates, type GestureLayerStyle, type UseGestureLayerOptions, type UseGestureLayerResult, useGestureLayer };
160
+ export { type GestureLayerProgress, type GestureLayerStates, type GestureLayerStyle, type UseGestureLayerOptions, type UseGestureLayerResult, useGestureLayer };
@@ -392,9 +392,26 @@ function useGestureLayer(states, options = {}) {
392
392
  }
393
393
  return out;
394
394
  });
395
+ const progress = react.useMemo(
396
+ () => ({
397
+ hovered: gesture.hovered,
398
+ focused: gesture.focused,
399
+ focusVisible: gesture.focusVisible,
400
+ pressed: gesture.pressed,
401
+ disabled: disabledProgress
402
+ }),
403
+ [
404
+ gesture.hovered,
405
+ gesture.focused,
406
+ gesture.focusVisible,
407
+ gesture.pressed,
408
+ disabledProgress
409
+ ]
410
+ );
395
411
  return {
396
412
  style,
397
- handlers: gesture.handlers
413
+ handlers: gesture.handlers,
414
+ states: progress
398
415
  };
399
416
  }
400
417
  function disabledTransition(transition) {
@@ -404,5 +421,3 @@ function disabledTransition(transition) {
404
421
  }
405
422
 
406
423
  exports.useGestureLayer = useGestureLayer;
407
- //# sourceMappingURL=index.js.map
408
- //# sourceMappingURL=index.js.map
@@ -390,9 +390,26 @@ function useGestureLayer(states, options = {}) {
390
390
  }
391
391
  return out;
392
392
  });
393
+ const progress = useMemo(
394
+ () => ({
395
+ hovered: gesture.hovered,
396
+ focused: gesture.focused,
397
+ focusVisible: gesture.focusVisible,
398
+ pressed: gesture.pressed,
399
+ disabled: disabledProgress
400
+ }),
401
+ [
402
+ gesture.hovered,
403
+ gesture.focused,
404
+ gesture.focusVisible,
405
+ gesture.pressed,
406
+ disabledProgress
407
+ ]
408
+ );
393
409
  return {
394
410
  style,
395
- handlers: gesture.handlers
411
+ handlers: gesture.handlers,
412
+ states: progress
396
413
  };
397
414
  }
398
415
  function disabledTransition(transition) {
@@ -402,5 +419,3 @@ function disabledTransition(transition) {
402
419
  }
403
420
 
404
421
  export { useGestureLayer };
405
- //# sourceMappingURL=index.mjs.map
406
- //# sourceMappingURL=index.mjs.map
package/dist/index.js CHANGED
@@ -1659,5 +1659,3 @@ exports.useShouldReduceMotion = useShouldReduceMotion;
1659
1659
  exports.useSpring = useSpring;
1660
1660
  exports.useTransform = useTransform;
1661
1661
  exports.useVariants = useVariants;
1662
- //# sourceMappingURL=index.js.map
1663
- //# sourceMappingURL=index.js.map
package/dist/index.mjs CHANGED
@@ -1625,5 +1625,3 @@ function useVariants(variants, initial) {
1625
1625
  }
1626
1626
 
1627
1627
  export { Motion, MotionConfig, MotionImage, MotionPressable, MotionScrollView, MotionText, MotionView, Presence, buildReleaseAnimation, createMotionComponent, cubicBezier, ensureWorkletEasing, resolveAnimatableValue, resolveNamedTransition, resolveTransition, useAnimation, useBooleanSpring, useColorTransition, useGesture, useMotionConfig, useMotionValue, useNamedTransitions, usePresence, useScroll, useShadow, useShouldReduceMotion, useSpring, useTransform, useVariants };
1628
- //# sourceMappingURL=index.mjs.map
1629
- //# sourceMappingURL=index.mjs.map
@@ -1176,5 +1176,3 @@ function compose(user, ours) {
1176
1176
  var MotionImage = createMotionComponent(reactNative.Image);
1177
1177
 
1178
1178
  exports.MotionImage = MotionImage;
1179
- //# sourceMappingURL=Image.js.map
1180
- //# sourceMappingURL=Image.js.map
@@ -1170,5 +1170,3 @@ function compose(user, ours) {
1170
1170
  var MotionImage = createMotionComponent(Image);
1171
1171
 
1172
1172
  export { MotionImage };
1173
- //# sourceMappingURL=Image.mjs.map
1174
- //# sourceMappingURL=Image.mjs.map
@@ -1176,5 +1176,3 @@ function compose(user, ours) {
1176
1176
  var MotionPressable = createMotionComponent(reactNative.Pressable);
1177
1177
 
1178
1178
  exports.MotionPressable = MotionPressable;
1179
- //# sourceMappingURL=Pressable.js.map
1180
- //# sourceMappingURL=Pressable.js.map
@@ -1170,5 +1170,3 @@ function compose(user, ours) {
1170
1170
  var MotionPressable = createMotionComponent(Pressable);
1171
1171
 
1172
1172
  export { MotionPressable };
1173
- //# sourceMappingURL=Pressable.mjs.map
1174
- //# sourceMappingURL=Pressable.mjs.map
@@ -1176,5 +1176,3 @@ function compose(user, ours) {
1176
1176
  var MotionScrollView = createMotionComponent(reactNative.ScrollView);
1177
1177
 
1178
1178
  exports.MotionScrollView = MotionScrollView;
1179
- //# sourceMappingURL=ScrollView.js.map
1180
- //# sourceMappingURL=ScrollView.js.map
@@ -1170,5 +1170,3 @@ function compose(user, ours) {
1170
1170
  var MotionScrollView = createMotionComponent(ScrollView);
1171
1171
 
1172
1172
  export { MotionScrollView };
1173
- //# sourceMappingURL=ScrollView.mjs.map
1174
- //# sourceMappingURL=ScrollView.mjs.map
@@ -1176,5 +1176,3 @@ function compose(user, ours) {
1176
1176
  var MotionText = createMotionComponent(reactNative.Text);
1177
1177
 
1178
1178
  exports.MotionText = MotionText;
1179
- //# sourceMappingURL=Text.js.map
1180
- //# sourceMappingURL=Text.js.map
@@ -1170,5 +1170,3 @@ function compose(user, ours) {
1170
1170
  var MotionText = createMotionComponent(Text);
1171
1171
 
1172
1172
  export { MotionText };
1173
- //# sourceMappingURL=Text.mjs.map
1174
- //# sourceMappingURL=Text.mjs.map
@@ -1176,5 +1176,3 @@ function compose(user, ours) {
1176
1176
  var MotionView = createMotionComponent(reactNative.View);
1177
1177
 
1178
1178
  exports.MotionView = MotionView;
1179
- //# sourceMappingURL=View.js.map
1180
- //# sourceMappingURL=View.js.map
@@ -1170,5 +1170,3 @@ function compose(user, ours) {
1170
1170
  var MotionView = createMotionComponent(View);
1171
1171
 
1172
1172
  export { MotionView };
1173
- //# sourceMappingURL=View.mjs.map
1174
- //# sourceMappingURL=View.mjs.map
@@ -15,5 +15,3 @@ function flushMotion(rendered, ui) {
15
15
 
16
16
  exports.flushMotion = flushMotion;
17
17
  exports.renderWithMotion = renderWithMotion;
18
- //# sourceMappingURL=index.js.map
19
- //# sourceMappingURL=index.js.map
@@ -12,5 +12,3 @@ function flushMotion(rendered, ui) {
12
12
  }
13
13
 
14
14
  export { flushMotion, renderWithMotion };
15
- //# sourceMappingURL=index.mjs.map
16
- //# sourceMappingURL=index.mjs.map
@@ -162,5 +162,3 @@ function applyBounds(value, min, max, elastic) {
162
162
  }
163
163
 
164
164
  exports.useTouchDrag = useTouchDrag;
165
- //# sourceMappingURL=index.js.map
166
- //# sourceMappingURL=index.js.map
@@ -160,5 +160,3 @@ function applyBounds(value, min, max, elastic) {
160
160
  }
161
161
 
162
162
  export { useTouchDrag };
163
- //# sourceMappingURL=index.mjs.map
164
- //# sourceMappingURL=index.mjs.map
package/llms.txt CHANGED
@@ -44,7 +44,7 @@ import { MotionScrollView } from '@rootnative/inertia/scroll-view'
44
44
  - `<Presence>` — mount / unmount transitions; children need explicit `key`s. Exiting children get `pointerEvents: 'none'` automatically.
45
45
  - `<MotionConfig reducedMotion="user" | "never" | "always" transitions={{ name: TransitionConfig }}>` — gates motion against the OS reduce-motion setting (default `"user"`) and registers named transitions for the subtree. A registered name is accepted anywhere a `TransitionConfig` is: the `transition` prop (top-level and per-property/per-layer), the `layout` prop, and the value-layer hooks (`transition="selection"`, `useBooleanSpring(checked, 'selection')`). Nested providers merge (child overrides per name); unknown names warn in dev and fall back to the default spring. Names are consumer vocabulary — no presets ship with the library. Optional compile-time narrowing via `declare module '@rootnative/inertia' { interface RegisteredTransitions { ... } }`. Custom components join the registry with `useNamedTransitions()` + `resolveNamedTransition(input, registry)`.
46
46
  - `useGesture(transition?)` — hook-form of the `gesture` prop. Returns 0↔1 progress shared values (`pressed`, `focused`, `focusVisible`, `hovered`) plus a `handlers` bag to spread on a `Pressable`. Use when one gesture needs to drive multiple animated siblings (focus rings, MD3 state-layer halos, multi-element compositions).
47
- - `useGestureLayer(states, options?)` — opt-in helper at `@rootnative/inertia/gesture-layer` for the **strongest-active-layer-wins** composition (MD3 state-layer haloes, iOS-translucent overlays). Supply per-state target maps (`rest` / `hovered` / `focused` / `focusVisible` / `pressed` / `disabled`); the hook owns the worklet. Numeric keys compose via clamped-max with `rest` as the floor; color keys compose via priority cascade with `interpolateColor`; `disabled` (JS-side flag) overrides every gesture layer. Returns `{ style, handlers }`. Reach for plain `useGesture` for additive blends or per-key custom rules.
47
+ - `useGestureLayer(states, options?)` — opt-in helper at `@rootnative/inertia/gesture-layer` for the **strongest-active-layer-wins** composition (MD3 state-layer haloes, iOS-translucent overlays). Supply per-state target maps (`rest` / `hovered` / `focused` / `focusVisible` / `pressed` / `disabled`); the hook owns the worklet. Numeric keys compose via clamped-max with `rest` as the floor; color keys compose via priority cascade with `interpolateColor`; `disabled` (JS-side flag) overrides every gesture layer. Returns `{ style, handlers, states }` — `states` is the per-state 0↔1 progress shared values (`hovered` / `focused` / `focusVisible` / `pressed` / `disabled`) behind the composed style, for deriving extra styles (e.g. `useShadow({ progress: states.hovered })`) from the same gesture wiring. Reach for plain `useGesture` for additive blends or per-key custom rules.
48
48
  - `useVariants(variants, initial?)` — returns `{ current, transitionTo }` controller for the `controller` prop.
49
49
  - `useMotionValue(initial)` — thin pass-through over `useSharedValue<T>`. Returns a `SharedValue<T>` directly so it interops with every Reanimated API without unwrapping.
50
50
  - `useAnimation(target, transition?)` — drive a `SharedValue<number>` toward `target` with any `TransitionConfig` (spring / timing / decay / no-animation, plus `repeat`) or a registered `TransitionName`. The general-purpose value-layer hook for boolean-state progress, indeterminate loops, and anywhere the same value needs to feed multiple `useAnimatedStyle` blocks.
@@ -136,7 +136,7 @@ Auto-layout transitions ship via the `layout` prop (`true` / `TransitionConfig`)
136
136
  ## Optional adapter packages
137
137
 
138
138
  - `@rootnative/inertia-gradients` — `MotionLinearGradient` over `expo-linear-gradient`. Animatable: `colors`, `start`, `end`, `locations`.
139
- - `@rootnative/inertia-svg` — `MotionPath` over `react-native-svg` (also exported as `MotionSvg.Path` — a namespace that will grow `Circle` / `Rect` / `Line` / `Ellipse` in a follow-up). Animatable: `d` (path morphing on structurally-compatible paths), `fill`, `stroke`, `strokeWidth`, opacities, `strokeDashoffset`. Source and target paths must share the same command sequence after implicit-repeat expansion; remount with `key` to switch shape.
139
+ - `@rootnative/inertia-svg` — animatable SVG primitives over `react-native-svg`, all under the `MotionSvg` namespace (`MotionSvg.Path` / `.Circle` / `.Rect` / `.Line`) or as direct imports. `MotionPath` animates `d` (path morphing on structurally-compatible paths — same command sequence after implicit-repeat expansion; remount with `key` to switch shape), `fill`, `stroke`, `strokeWidth`, opacities, `strokeDashoffset`. `MotionCircle` / `MotionRect` / `MotionLine` animate their geometry props, paints, and `strokeDasharray` (element-wise; array length locked at mount). `createMotionSvgComponent(Component, { animatableProps, colorProps, arrayProps })` — the factory behind the prebuilt shapes — wraps any other `react-native-svg` element with the same `initial` / `animate` / `transition` surface; `transition` accepts named transitions from the nearest `<MotionConfig transitions>` (top-level and per-property).
140
140
  - `@rootnative/inertia-gestures` — `useDrag`, `useSwipe`, `usePan` over `react-native-gesture-handler`. `useDrag` accepts an `onRelease` worklet that returns per-axis Inertia release transitions (snap-to-tick spring, decay with bounds, etc.) — the release velocity stays on the UI thread, no JS round-trip.
141
141
 
142
142
  ## Docs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rootnative/inertia",
3
- "version": "0.0.0-alpha.1",
3
+ "version": "0.0.0-alpha.2",
4
4
  "description": "Declarative animation primitives for React Native, built on react-native-reanimated.",
5
5
  "license": "MIT",
6
6
  "author": "RootNative",
@@ -107,6 +107,7 @@
107
107
  "LICENSE",
108
108
  "CHANGELOG.md",
109
109
  "!**/__tests__",
110
+ "!**/__type-tests__",
110
111
  "!**/*.test.*"
111
112
  ],
112
113
  "peerDependencies": {
@@ -14,6 +14,7 @@
14
14
  */
15
15
  export { useGestureLayer } from './useGestureLayer'
16
16
  export type {
17
+ GestureLayerProgress,
17
18
  GestureLayerStates,
18
19
  GestureLayerStyle,
19
20
  UseGestureLayerOptions,
@@ -4,6 +4,7 @@ import {
4
4
  useAnimatedStyle,
5
5
  useSharedValue,
6
6
  type AnimatedStyle,
7
+ type SharedValue,
7
8
  } from 'react-native-reanimated'
8
9
  import {
9
10
  resolveNamedTransitionProp,
@@ -76,6 +77,27 @@ export interface UseGestureLayerOptions {
76
77
  transition?: TransitionInput | GestureLayerTransitions
77
78
  }
78
79
 
80
+ /**
81
+ * The per-state 0↔1 progress shared values behind a `useGestureLayer` call.
82
+ * The gesture entries are the same shared values `useGesture` owns; `disabled`
83
+ * is driven by `options.disabled`. All five are stable across renders — feed
84
+ * them into any `useAnimatedStyle` / `useDerivedValue` (or hooks like
85
+ * `useShadow({ progress })`) to derive extra styles from the same gesture
86
+ * wiring without a second `useGesture` call.
87
+ */
88
+ export interface GestureLayerProgress {
89
+ /** 0↔1 progress for the hovered layer (web only — stays at 0 on native). */
90
+ hovered: SharedValue<number>
91
+ /** 0↔1 progress for the focused layer (any focus modality). */
92
+ focused: SharedValue<number>
93
+ /** 0↔1 progress for the focusVisible layer (keyboard focus only). */
94
+ focusVisible: SharedValue<number>
95
+ /** 0↔1 progress for the pressed layer. */
96
+ pressed: SharedValue<number>
97
+ /** 0↔1 progress for the disabled override (driven by `options.disabled`). */
98
+ disabled: SharedValue<number>
99
+ }
100
+
79
101
  export interface UseGestureLayerResult {
80
102
  /**
81
103
  * Animated style produced by `useAnimatedStyle` — spread on an
@@ -84,6 +106,12 @@ export interface UseGestureLayerResult {
84
106
  style: AnimatedStyle<Record<string, unknown>>
85
107
  /** Handlers to spread on the receiving `Pressable`. */
86
108
  handlers: UseGestureHandlers
109
+ /**
110
+ * Per-state progress shared values — the inputs the composed `style` is
111
+ * derived from. Read-only by convention: writing to them fights the
112
+ * handlers.
113
+ */
114
+ states: GestureLayerProgress
87
115
  }
88
116
 
89
117
  /**
@@ -107,6 +135,13 @@ export interface UseGestureLayerResult {
107
135
  * keys — when active, it lerps the composed value toward the `disabled`
108
136
  * target.
109
137
  *
138
+ * Alongside `style` and `handlers`, the hook returns `states` — the per-state
139
+ * 0↔1 progress shared values the style is derived from (the four gesture
140
+ * layers plus the disabled override). Feed them into other progress-driven
141
+ * hooks (`useShadow`, `useColorTransition`) or a custom `useAnimatedStyle`
142
+ * to derive extra styles from the same gesture wiring — no second
143
+ * `useGesture` call, no duplicated handlers.
144
+ *
110
145
  * Reach for this when you want MD3 / iOS-translucent state-layer overlays
111
146
  * without rewriting the worklet by hand for every consumer; reach for plain
112
147
  * `useGesture()` when you need a composition model this hook doesn't
@@ -136,6 +171,13 @@ export interface UseGestureLayerResult {
136
171
  * )
137
172
  * }
138
173
  * ```
174
+ *
175
+ * @example Elevation crossfade driven by the hover progress
176
+ * ```tsx
177
+ * const { style, handlers, states } = useGestureLayer(layers, options)
178
+ * const shadow = useShadow({ from: restShadow, to: raisedShadow, progress: states.hovered })
179
+ * // <Animated.View style={[style, shadow]} />
180
+ * ```
139
181
  */
140
182
  export function useGestureLayer(
141
183
  states: GestureLayerStates,
@@ -294,9 +336,27 @@ export function useGestureLayer(
294
336
  return out
295
337
  })
296
338
 
339
+ const progress = useMemo<GestureLayerProgress>(
340
+ () => ({
341
+ hovered: gesture.hovered,
342
+ focused: gesture.focused,
343
+ focusVisible: gesture.focusVisible,
344
+ pressed: gesture.pressed,
345
+ disabled: disabledProgress,
346
+ }),
347
+ [
348
+ gesture.hovered,
349
+ gesture.focused,
350
+ gesture.focusVisible,
351
+ gesture.pressed,
352
+ disabledProgress,
353
+ ],
354
+ )
355
+
297
356
  return {
298
357
  style: style as AnimatedStyle<Record<string, unknown>>,
299
358
  handlers: gesture.handlers,
359
+ states: progress,
300
360
  }
301
361
  }
302
362
 
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/transitions/sig.ts","../../src/config/MotionConfigContext.ts","../../src/transitions/keys.ts","../../src/config/namedTransitions.ts","../../src/transitions/easing.ts","../../src/transitions/spring.ts","../../src/transitions/resolve.ts","../../src/gestures/focusVisibility.ts","../../src/values/useGesture.ts","../../src/gestureLayer/useGestureLayer.ts"],"names":["createContext","useContext","useReducedMotion","isWorkletFunction","withSpring","withTiming","Easing","withDecay","withRepeat","withDelay","Platform","useSharedValue","useCallback","useMemo","useEffect","useAnimatedStyle","interpolateColor"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Stable string signature for an arbitrary value — used as a dep-array\n * member so a fresh object literal each render doesn't re-fire an effect\n * unless something structurally changed. Functions serialize as `null`\n * (their identity isn't useful in a sig); `undefined` collapses to an empty\n * string so omitted props compare equal across renders.\n */\nexport function stableSig(value: unknown): string {\n if (value === undefined) return ''\n try {\n return stableStringify(value)\n } catch {\n return String(value)\n }\n}\n\n/**\n * JSON.stringify with keys sorted at every level so a sig is invariant under\n * property-declaration order. Functions and `undefined` both serialize as\n * `null` — we accept the latter's information loss (rare in practice) in\n * exchange for not crashing on circular function-bearing graphs.\n */\nfunction stableStringify(v: unknown): string {\n if (v === null || typeof v !== 'object') {\n if (typeof v === 'function' || v === undefined) return 'null'\n return JSON.stringify(v)\n }\n if (Array.isArray(v)) {\n return '[' + v.map(stableStringify).join(',') + ']'\n }\n const obj = v as Record<string, unknown>\n const keys = Object.keys(obj).sort()\n return (\n '{' +\n keys\n .map((k) => JSON.stringify(k) + ':' + stableStringify(obj[k]))\n .join(',') +\n '}'\n )\n}\n","import { createContext, useContext } from 'react'\nimport { useReducedMotion } from 'react-native-reanimated'\nimport { type NamedTransitions } from '../types'\n\n/**\n * How descendant Motion primitives should treat reduced-motion preferences.\n *\n * - `'user'` (default): defer to the OS accessibility setting via\n * Reanimated's `useReducedMotion()`. This is the only value that respects\n * user choice and is the right default for app-level wrappers.\n * - `'never'`: animate regardless of OS setting. Use sparingly — e.g. for\n * onboarding transitions you've decided are essential.\n * - `'always'`: never animate, regardless of OS setting. Useful for tests\n * and snapshots.\n */\nexport type ReducedMotion = 'user' | 'never' | 'always'\n\nexport interface MotionConfigValue {\n reducedMotion: ReducedMotion\n /**\n * Named transitions registered by ancestor `<MotionConfig transitions>`\n * providers, already merged (nearest provider wins per name). Empty with no\n * provider — every name then resolves to the unknown-name fallback.\n */\n transitions: NamedTransitions\n}\n\n/**\n * Default config used when a Motion primitive is rendered without a\n * `<MotionConfig>` ancestor. `'user'` means respect the OS setting; no\n * transitions are registered.\n */\nexport const DEFAULT_MOTION_CONFIG: MotionConfigValue = {\n reducedMotion: 'user',\n transitions: {},\n}\n\nexport const MotionConfigContext = createContext<MotionConfigValue>(\n DEFAULT_MOTION_CONFIG,\n)\n\n/**\n * Read the active `<MotionConfig>` from a descendant. Returns the default\n * (`'user'`) when no provider is present.\n */\nexport function useMotionConfig(): MotionConfigValue {\n return useContext(MotionConfigContext)\n}\n\n/**\n * Resolve the active reduced-motion mode to a boolean. `'user'` consults\n * Reanimated's OS-backed hook; `'always'` / `'never'` shortcut. Motion\n * primitives call this to decide whether to swap transitions for\n * `no-animation`.\n */\n/**\n * Read the merged named-transition registry from the nearest `<MotionConfig>`\n * ancestors. This is what the Motion primitives and value-layer hooks consult\n * when a `TransitionName` string is passed where a `TransitionConfig` is\n * accepted; custom animated components (and adapter packages) use it together\n * with `resolveNamedTransition` to support names on their own surface.\n */\nexport function useNamedTransitions(): NamedTransitions {\n return useMotionConfig().transitions\n}\n\nexport function useShouldReduceMotion(): boolean {\n const { reducedMotion } = useMotionConfig()\n const osReduced = useReducedMotion()\n if (reducedMotion === 'never') return false\n if (reducedMotion === 'always') return true\n return osReduced\n}\n","import { type TransitionConfig } from '../types'\n\n/**\n * Field names that may appear on a `TransitionConfig` (spring / timing /\n * decay / no-animation). Used as a structural discriminator: if every key on\n * an object is in this set, the object is treated as a top-level transition;\n * otherwise it's a per-property / per-layer transition map.\n *\n * Adding a new field to `TransitionConfig` requires adding the name here.\n */\nexport const TRANSITION_CONFIG_KEYS = new Set([\n 'type',\n 'tension',\n 'friction',\n 'mass',\n 'velocity',\n 'restSpeedThreshold',\n 'restDisplacementThreshold',\n 'duration',\n 'easing',\n 'delay',\n 'repeat',\n 'deceleration',\n 'clamp',\n])\n\nexport function isTopLevelTransition(t: unknown): t is TransitionConfig {\n if (t === null || typeof t !== 'object') return false\n const keys = Object.keys(t as object)\n if (keys.length === 0) return false\n return keys.every((k) => TRANSITION_CONFIG_KEYS.has(k))\n}\n","import { isTopLevelTransition } from '../transitions/keys'\nimport {\n type NamedTransitions,\n type Transition,\n type TransitionConfig,\n type TransitionInput,\n} from '../types'\n\ndeclare const __DEV__: boolean\n\n/**\n * Fallback used when a name isn't found in the registry: the library default\n * spring, matching what an omitted transition resolves to everywhere else.\n */\nconst UNKNOWN_NAME_FALLBACK: TransitionConfig = { type: 'spring' }\n\n/**\n * Look a registered transition name up in a registry. Unknown names warn in\n * dev and fall back to the library default spring — the animation still runs,\n * it just isn't the one the token intended, which is the same failure\n * softness the web platform gives an unknown CSS keyword.\n */\nexport function lookupNamedTransition(\n name: string,\n registry: NamedTransitions,\n): TransitionConfig {\n const cfg = registry[name]\n if (cfg) return cfg\n if (__DEV__) {\n console.warn(\n `[inertia] Unknown transition name \"${name}\" — falling back to the ` +\n `default spring. Register it on a provider: ` +\n `<MotionConfig transitions={{ '${name}': { ... } }}>.`,\n )\n }\n return UNKNOWN_NAME_FALLBACK\n}\n\n/**\n * Resolve a single transition input — a `TransitionConfig` passes through\n * untouched, a `TransitionName` is looked up in `registry`. This is the\n * building block adapter packages use to accept names wherever they accept a\n * config (pair it with `useNamedTransitions()` for the registry).\n */\nexport function resolveNamedTransition(\n input: TransitionInput | undefined,\n registry: NamedTransitions,\n): TransitionConfig | undefined {\n if (input === undefined) return undefined\n if (typeof input === 'string') return lookupNamedTransition(input, registry)\n return input\n}\n\n/**\n * Resolve every name inside a `transition` prop value — the top-level string\n * form, and string values on the per-property / gesture-layer map form.\n * Identity-preserving: when the input contains no names it is returned\n * unchanged, so signature- and identity-keyed memoization downstream is\n * unaffected for the config-object path.\n */\nexport function resolveNamedTransitionProp<S>(\n transition: Transition<S> | undefined,\n registry: NamedTransitions,\n): Exclude<Transition<S>, string> | undefined {\n if (transition === undefined) return undefined\n if (typeof transition === 'string') {\n return lookupNamedTransition(transition, registry)\n }\n if (isTopLevelTransition(transition)) return transition\n const map = transition as Record<string, unknown>\n let out: Record<string, unknown> | null = null\n for (const key in map) {\n const value = map[key]\n if (typeof value === 'string') {\n if (out === null) out = { ...map }\n out[key] = lookupNamedTransition(value, registry)\n }\n }\n return (out ?? transition) as Exclude<Transition<S>, string>\n}\n","// `isWorkletFunction` lives in `react-native-worklets` (the Reanimated 4 peer\n// dep); Reanimated's own re-export is deprecated.\nimport { isWorkletFunction } from 'react-native-worklets'\nimport { type EasingInput } from '../types'\n\n/**\n * Reanimated 3.9+ validates that easing functions used in nested-transition\n * contexts (variants, sequences, per-property maps) are worklets, and crashes\n * with `[Reanimated] The easing function is not a worklet` otherwise. The\n * library accepts plain functions on the public surface; this helper wraps\n * them so consumers don't have to think about the worklet boundary.\n *\n * If the input is already a worklet (has been processed by the worklets babel\n * plugin), it's returned as-is. Otherwise it's wrapped in a function whose\n * body declares the `'worklet'` directive — when our source is processed by\n * the consumer's worklets babel plugin (the default Expo/RN setup), the\n * wrapper becomes a real worklet that captures the user fn via closure.\n *\n * Reanimated 4 changed `Easing.bezier(...)` to return an\n * `EasingFunctionFactory` (`{ factory: () => EasingFunction }`) rather than\n * the function itself. The helper accepts both shapes — `EasingFunction` and\n * `EasingFunctionFactory` — and unwraps the factory automatically so\n * consumers don't have to call `.factory()` manually.\n *\n * The user fn must be pure: no JS-thread captured refs, no shared mutable\n * state, no calls to non-worklet APIs.\n */\nexport function ensureWorkletEasing(\n easing: EasingInput | undefined,\n): ((t: number) => number) | undefined {\n if (!easing) return undefined\n // Reanimated 4 `EasingFunctionFactory` — unwrap via `.factory()` before\n // checking worklet status, so the wrapped fn (not the factory wrapper)\n // ends up in the transition config.\n const fn = isEasingFactory(easing) ? easing.factory() : easing\n if (isWorkletFunction(fn)) return fn\n const wrapped = (t: number) => {\n 'worklet'\n return fn(t)\n }\n return wrapped\n}\n\nfunction isEasingFactory(\n value: EasingInput,\n): value is { factory: () => (t: number) => number } {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'factory' in value &&\n typeof (value as { factory: unknown }).factory === 'function'\n )\n}\n","import { type SpringTransition } from '../types'\n\n/**\n * Default spring physics, expressed in react-spring vocabulary.\n *\n * `tension: 170` / `friction: 26` / `mass: 1` was picked over Reanimated's\n * raw `stiffness: 100` / `damping: 10` default because the raw default\n * overshoots noticeably for the small (~100px) translates that dominate\n * UI work — buttons, sheets, popovers. These numbers settle in ~350ms with\n * a single, almost-imperceptible overshoot, which matches the perceptual\n * target the rest of the library is tuned against.\n */\nexport const DEFAULT_SPRING: Required<\n Pick<SpringTransition, 'tension' | 'friction' | 'mass'>\n> = {\n tension: 170,\n friction: 26,\n mass: 1,\n}\n\n/**\n * Convert public react-spring vocabulary (`tension` / `friction` / `mass`)\n * to Reanimated's raw `stiffness` / `damping` / `mass`. This is the single\n * place the mapping lives; resolvers, value hooks, and any future surface\n * that needs a Reanimated spring config import from here.\n *\n * The mapping is identity (tension ≡ stiffness, friction ≡ damping) — the\n * names differ but the underlying physics constants are the same. We don't\n * surface the raw names publicly because the react-spring vocabulary is\n * what designers and prior-art consumers expect.\n */\nexport function springToReanimated(t: SpringTransition) {\n 'worklet'\n return {\n stiffness: t.tension ?? DEFAULT_SPRING.tension,\n damping: t.friction ?? DEFAULT_SPRING.friction,\n mass: t.mass ?? DEFAULT_SPRING.mass,\n velocity: t.velocity,\n restSpeedThreshold: t.restSpeedThreshold,\n restDisplacementThreshold: t.restDisplacementThreshold,\n }\n}\n","import {\n Easing,\n withDecay,\n withDelay,\n withRepeat,\n withSpring,\n withTiming,\n} from 'react-native-reanimated'\nimport { ensureWorkletEasing } from './easing'\nimport { springToReanimated } from './spring'\nimport {\n type DecayTransition,\n type RepeatConfig,\n type SpringTransition,\n type TimingTransition,\n type TransitionConfig,\n} from '../types'\n\n/**\n * UI-thread callback Reanimated invokes when an animation settles. Must be a\n * worklet — callers either author one with `'worklet'` or build one via\n * `runOnJS(...)` to bridge to JS-thread code.\n */\nexport type AnimationCallback = (\n finished?: boolean,\n current?: number | string,\n) => void\n\n/**\n * Per-step callback factory. Resolvers call this with the step's phase and\n * sequence index (or `undefined` for non-sequence animations) and attach the\n * resulting callback to the underlying `withSpring` / `withTiming` /\n * `withDecay` call.\n */\nexport type CallbackFactory = (\n phase: 'step' | 'animation',\n step: number | undefined,\n) => AnimationCallback | undefined\n\nconst DEFAULT_TIMING_DURATION = 250\n\nfunction buildSpring(\n cfg: SpringTransition,\n toValue: number | string,\n cb?: AnimationCallback,\n) {\n return withSpring(toValue as number, springToReanimated(cfg), cb as never)\n}\n\nfunction buildTiming(\n cfg: TimingTransition,\n toValue: number | string,\n cb?: AnimationCallback,\n) {\n return withTiming(\n toValue as number,\n {\n duration: cfg.duration ?? DEFAULT_TIMING_DURATION,\n easing: ensureWorkletEasing(cfg.easing) ?? Easing.inOut(Easing.ease),\n },\n cb as never,\n )\n}\n\nfunction buildDecay(cfg: DecayTransition, cb?: AnimationCallback) {\n return withDecay(\n {\n velocity: cfg.velocity ?? 0,\n deceleration: cfg.deceleration,\n clamp: cfg.clamp,\n },\n cb as never,\n )\n}\n\n/**\n * Build a single-step animation (no repeat / no delay / no sequence) for a\n * given config + target. Pulled out so sequence steps can compose without\n * recursing into repeat/delay handling per step. The callback is forwarded\n * to Reanimated; for `no-animation` the callback is fired synchronously\n * since there's nothing to wait for.\n */\nfunction buildOne(\n cfg: TransitionConfig,\n toValue: number | string,\n cb?: AnimationCallback,\n): unknown {\n if (cfg.type === 'no-animation') {\n if (cb) cb(true, toValue)\n return toValue\n }\n if (cfg.type === 'decay') return buildDecay(cfg, cb)\n if (cfg.type === 'timing') return buildTiming(cfg, toValue, cb)\n return buildSpring(cfg as SpringTransition, toValue, cb)\n}\n\n/**\n * Wrap an animation in `withRepeat` per the unified `repeat` shape:\n * - `number` → finite count, alternating direction\n * - `'infinite'` → endless, alternating direction\n * - `{ count, alternate }`→ explicit; `alternate` defaults to `true`\n */\nexport function applyRepeat(\n animation: unknown,\n repeat: RepeatConfig | undefined,\n) {\n if (repeat === undefined) return animation\n if (repeat === 'infinite') {\n return withRepeat(animation as never, -1, true)\n }\n if (typeof repeat === 'number') {\n return withRepeat(animation as never, repeat, true)\n }\n const count = repeat.count === 'infinite' ? -1 : repeat.count\n const alternate = repeat.alternate ?? true\n return withRepeat(animation as never, count, alternate)\n}\n\nfunction applyDelay(animation: unknown, delay: number | undefined) {\n if (!delay || delay <= 0) return animation\n return withDelay(delay, animation as never)\n}\n\n/**\n * Build a Reanimated animation for a single property. Runs on the JS thread\n * once per change and produces a baked `withSpring` / `withTiming` /\n * `withDecay` (optionally wrapped in `withDelay` / `withRepeat`) call. The\n * worklet body only consumes the result.\n *\n * `callback`, when provided, fires once when the underlying single-shot\n * animation settles. Repeat-wrapped animations forward the callback to\n * `withRepeat`, so it fires once per iteration as Reanimated does.\n */\nexport function resolveTransition(\n config: TransitionConfig | undefined,\n toValue: number | string,\n callback?: AnimationCallback,\n): unknown {\n const cfg = config ?? ({ type: 'spring' } as SpringTransition)\n const base = buildOne(cfg, toValue, callback)\n const repeated = applyRepeat(base, repeatOf(cfg))\n return applyDelay(repeated, delayOf(cfg))\n}\n\nexport function repeatOf(cfg: TransitionConfig): RepeatConfig | undefined {\n if (cfg.type === 'no-animation' || cfg.type === 'decay') return undefined\n return cfg.repeat\n}\n\n/**\n * Return `cfg` minus its `repeat` field. Used when peeling top-level repeat\n * off a base transition before passing it down to per-sequence-step\n * resolution — the sequence as a whole is what should repeat, not each step.\n */\nexport function stripRepeat(\n cfg: TransitionConfig | undefined,\n): TransitionConfig | undefined {\n if (!cfg) return cfg\n if (cfg.type === 'no-animation' || cfg.type === 'decay') return cfg\n if (cfg.repeat === undefined) return cfg\n const next = { ...cfg }\n delete next.repeat\n return next\n}\n\nfunction delayOf(cfg: TransitionConfig): number | undefined {\n if (cfg.type === 'no-animation') return undefined\n return cfg.delay\n}\n","import { Platform } from 'react-native'\n\n/**\n * Input-modality tracker for the `focusVisible` gesture sub-state.\n *\n * Implements the W3C `:focus-visible` heuristic: a focus event counts as\n * \"visible\" only when the most recent user input was keyboard-driven. Mouse,\n * pointer, and touch events flip the modality to `'pointer'`; keyboard events\n * flip it back to `'keyboard'`.\n *\n * On native platforms there is no pointer-vs-keyboard distinction — focus\n * arrives via D-pad, screen reader, or hardware keyboard, all of which are\n * keyboard-equivalent — so `isFocusVisible()` is unconditionally `true`.\n *\n * The web listeners attach lazily on first call (capture phase, so they run\n * before the focus event reaches the focused element) and stay installed for\n * the lifetime of the document. They are passive and idle-cheap; the cost is\n * one boolean read per `onFocus` dispatch.\n */\n\ntype InputModality = 'keyboard' | 'pointer'\n\n// Default to `'keyboard'` so a programmatic / autofocus that happens before\n// any user input still draws a focus ring — matches the W3C polyfill default.\nlet modality: InputModality = 'keyboard'\nlet installed = false\n\nfunction setKeyboard() {\n modality = 'keyboard'\n}\n\nfunction setPointer() {\n modality = 'pointer'\n}\n\nfunction ensureInstalled(): void {\n if (installed) return\n if (Platform.OS !== 'web') return\n if (typeof document === 'undefined') return\n document.addEventListener('keydown', setKeyboard, true)\n document.addEventListener('mousedown', setPointer, true)\n document.addEventListener('pointerdown', setPointer, true)\n document.addEventListener('touchstart', setPointer, true)\n installed = true\n}\n\n/**\n * `true` if the next `onFocus` should be treated as \"focus-visible\" (keyboard\n * focus). On native, always `true`. On web, reflects the most recent user\n * input modality.\n */\nexport function isFocusVisible(): boolean {\n if (Platform.OS !== 'web') return true\n ensureInstalled()\n return modality === 'keyboard'\n}\n\n/** @internal — test-only hook to reset module state between cases. */\nexport function __resetFocusVisibilityForTests(next: InputModality): void {\n modality = next\n}\n","import { useCallback, useMemo } from 'react'\nimport { useSharedValue, type SharedValue } from 'react-native-reanimated'\nimport {\n resolveNamedTransitionProp,\n useNamedTransitions,\n useShouldReduceMotion,\n} from '../config'\nimport { isFocusVisible } from '../gestures'\nimport { isTopLevelTransition, resolveTransition } from '../transitions'\nimport {\n type GestureLayerTransitions,\n type TransitionConfig,\n type TransitionInput,\n} from '../types'\n\ntype LayerName = 'pressed' | 'focused' | 'focusVisible' | 'hovered'\n\n/**\n * Handler bag returned by `useGesture`. Spread on a `Pressable` to drive the\n * shared values returned alongside.\n *\n * Hover handlers use `Pressable`'s own `onHoverIn` / `onHoverOut` names (web\n * only — no-ops on native). `onFocus` consults `isFocusVisible()` before\n * raising the keyboard-only `focusVisible` layer; `focused` always raises.\n */\nexport interface UseGestureHandlers {\n onPressIn: () => void\n onPressOut: () => void\n onHoverIn: () => void\n onHoverOut: () => void\n onFocus: () => void\n onBlur: () => void\n}\n\nexport interface UseGestureResult {\n /** 0↔1 progress for the pressed layer. */\n pressed: SharedValue<number>\n /** 0↔1 progress for the focused layer (any focus modality). */\n focused: SharedValue<number>\n /** 0↔1 progress for the focusVisible layer (keyboard focus only). */\n focusVisible: SharedValue<number>\n /** 0↔1 progress for the hovered layer (web only — stays at 0 on native). */\n hovered: SharedValue<number>\n /** Handlers to spread on the receiving `Pressable`. */\n handlers: UseGestureHandlers\n}\n\n/**\n * Build a gesture-layer controller. The hook-form of the `gesture` prop —\n * reach for it when you need to drive multiple animated views from the same\n * gesture state (a focus ring + state-layer halo + content tint all on one\n * Pressable), which the prop-form's \"animate the receiver's own style\" model\n * can't express.\n *\n * Returns four 0↔1 shared values (one per layer) and a handler bag to spread\n * on a `Pressable`. The shared values are stable across renders — feed them\n * into any number of `useAnimatedStyle` blocks anywhere in the tree.\n *\n * Transitions follow the same shape as the `gesture` prop's accompanying\n * `transition`: pass a single `TransitionConfig` to use for every layer, or a\n * `GestureLayerTransitions` map to give each layer its own. A `TransitionName`\n * registered on the nearest `<MotionConfig transitions>` is accepted in both\n * positions (top-level and per-layer). Layers without an explicit transition\n * fall back to the library default spring.\n *\n * Reduced motion (via `<MotionConfig reducedMotion>`) collapses every\n * transition to `no-animation` so state changes snap instead of interpolating\n * — same behaviour the gesture prop applies.\n *\n * @example\n * ```tsx\n * import { useAnimatedStyle } from 'react-native-reanimated'\n * import { useGesture } from '@rootnative/inertia'\n *\n * function Card() {\n * const { pressed, focused, hovered, handlers } = useGesture({\n * pressed: { type: 'timing', duration: 100 },\n * hovered: { type: 'timing', duration: 150 },\n * focused: { type: 'timing', duration: 200 },\n * })\n *\n * const ringStyle = useAnimatedStyle(() => ({ opacity: focused.value }))\n * const haloStyle = useAnimatedStyle(() => ({\n * opacity: Math.max(\n * hovered.value * 0.08,\n * focused.value * 0.10,\n * pressed.value * 0.10,\n * ),\n * }))\n *\n * return (\n * <Pressable {...handlers}>\n * <Animated.View style={ringStyle} />\n * <Animated.View style={haloStyle} />\n * </Pressable>\n * )\n * }\n * ```\n */\nexport function useGesture(\n transition?: TransitionInput | GestureLayerTransitions,\n): UseGestureResult {\n const pressed = useSharedValue(0)\n const focused = useSharedValue(0)\n const focusVisible = useSharedValue(0)\n const hovered = useSharedValue(0)\n const shouldReduceMotion = useShouldReduceMotion()\n // Registered transition names (top-level string or per-layer string values)\n // resolve against the nearest <MotionConfig transitions> at render time, so\n // the callbacks below only ever see concrete configs.\n const resolved = resolveNamedTransitionProp(transition, useNamedTransitions())\n\n const setLayer = useCallback(\n (sv: SharedValue<number>, layer: LayerName, target: 0 | 1) => {\n const cfg = shouldReduceMotion\n ? ({ type: 'no-animation' } as const)\n : (layerTransition(layer, resolved) ?? ({ type: 'spring' } as const))\n sv.value = resolveTransition(cfg, target) as never\n },\n // The transition is intentionally read on every call rather than cooked\n // into the dep array — a fresh literal each render would otherwise\n // rebuild the handler bag and break composing consumers that key off\n // handler identity. `transition` is read inside the callback closure;\n // shared values are stable so the only dep that matters is the reduce-\n // motion flag.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [shouldReduceMotion],\n )\n\n const handlers = useMemo<UseGestureHandlers>(\n () => ({\n onPressIn: () => setLayer(pressed, 'pressed', 1),\n onPressOut: () => setLayer(pressed, 'pressed', 0),\n onHoverIn: () => setLayer(hovered, 'hovered', 1),\n onHoverOut: () => setLayer(hovered, 'hovered', 0),\n onFocus: () => {\n setLayer(focused, 'focused', 1)\n if (isFocusVisible()) setLayer(focusVisible, 'focusVisible', 1)\n },\n onBlur: () => {\n setLayer(focused, 'focused', 0)\n setLayer(focusVisible, 'focusVisible', 0)\n },\n }),\n [setLayer, pressed, focused, focusVisible, hovered],\n )\n\n return { pressed, focused, focusVisible, hovered, handlers }\n}\n\n// Runs after name resolution, so the `TransitionInput` values on the map form\n// are concrete configs by the time they're read — hence the return cast.\nfunction layerTransition(\n layer: LayerName,\n transition: TransitionConfig | GestureLayerTransitions | undefined,\n): TransitionConfig | undefined {\n if (!transition) return undefined\n if (isTopLevelTransition(transition)) return transition\n return (transition as GestureLayerTransitions)[layer] as\n | TransitionConfig\n | undefined\n}\n","import { useEffect, useMemo } from 'react'\nimport {\n interpolateColor,\n useAnimatedStyle,\n useSharedValue,\n type AnimatedStyle,\n} from 'react-native-reanimated'\nimport {\n resolveNamedTransitionProp,\n useNamedTransitions,\n useShouldReduceMotion,\n} from '../config'\nimport {\n isTopLevelTransition,\n resolveTransition,\n stableSig,\n} from '../transitions'\nimport { useGesture, type UseGestureHandlers } from '../values/useGesture'\nimport {\n type GestureLayerTransitions,\n type TransitionConfig,\n type TransitionInput,\n} from '../types'\n\n/**\n * A single gesture-layer style — a flat map of style keys to a value. Numeric\n * values participate in clamped-max composition (the \"strongest active layer\n * wins\" model used by MD3 state-layer haloes); string values are treated as\n * colors and composed via priority cascade with `interpolateColor`.\n *\n * The hook does not validate that string values are valid colors — passing\n * something like `borderStyle: 'solid'` will crash inside the worklet. Keep\n * string values to color strings.\n */\nexport type GestureLayerStyle = {\n [key: string]: number | string | undefined\n}\n\n/**\n * Per-state style maps. Every key is optional; missing layers default to\n * `rest` (or `0` / `'transparent'` if `rest` is also absent for that key).\n *\n * - `rest` — base values, applied when no other layer is active.\n * - `hovered` / `focused` / `focusVisible` / `pressed` — gesture-driven\n * states tracked via the underlying `useGesture` hook. Each owns an\n * independent 0↔1 progress that fades the layer in/out per the configured\n * transition.\n * - `disabled` — gated by the JS-side `options.disabled` flag rather than a\n * gesture. Sits at the top of the priority cascade and overrides every\n * gesture layer when active.\n */\nexport interface GestureLayerStates {\n rest?: GestureLayerStyle\n hovered?: GestureLayerStyle\n focused?: GestureLayerStyle\n focusVisible?: GestureLayerStyle\n pressed?: GestureLayerStyle\n disabled?: GestureLayerStyle\n}\n\nexport interface UseGestureLayerOptions {\n /**\n * When `true`, the `disabled` layer becomes active (or `rest` if `disabled`\n * is undefined). Animates via the top-level transition or the library\n * default spring; per-layer transitions (`GestureLayerTransitions`) do not\n * apply to `disabled`.\n */\n disabled?: boolean\n /**\n * Transition forwarded to the underlying `useGesture` hook. Either a single\n * `TransitionConfig` for every gesture layer, or a `GestureLayerTransitions`\n * map for per-layer fades. A `TransitionName` registered on the nearest\n * `<MotionConfig transitions>` is accepted in both positions. Reduced\n * motion collapses every transition to `no-animation`.\n */\n transition?: TransitionInput | GestureLayerTransitions\n}\n\nexport interface UseGestureLayerResult {\n /**\n * Animated style produced by `useAnimatedStyle` — spread on an\n * `Animated.View` or pass through `<Motion.View style={...} />`.\n */\n style: AnimatedStyle<Record<string, unknown>>\n /** Handlers to spread on the receiving `Pressable`. */\n handlers: UseGestureHandlers\n}\n\n/**\n * A \"strongest active layer wins\" interactive-feedback primitive. Sits one\n * step above `useGesture()` — the consumer supplies the per-state target\n * values, the hook handles the four gesture progress shared values, the\n * disabled override, the worklet, and the transition.\n *\n * Composition model:\n *\n * - **Numeric keys** (opacity, scale, borderWidth, etc.) compose via\n * clamped-max with `rest` as the floor:\n * `out = max(rest, ...for each active gesture layer: lerp(rest, layer, progress))`.\n * This matches the MD3 state-layer halo pattern — multiple states active\n * simultaneously raise the value to the strongest, not the sum.\n * - **Color keys** (any string value) compose via priority cascade with\n * `interpolateColor`, lowest priority first: `hovered → focused →\n * focusVisible → pressed`. Clamped-max doesn't apply to colors; this\n * matches the cascade used by the declarative `gesture` prop.\n * - **Disabled** sits at the top of the cascade for both numeric and color\n * keys — when active, it lerps the composed value toward the `disabled`\n * target.\n *\n * Reach for this when you want MD3 / iOS-translucent state-layer overlays\n * without rewriting the worklet by hand for every consumer; reach for plain\n * `useGesture()` when you need a composition model this hook doesn't\n * express (additive, multiply, per-key custom blends).\n *\n * @example MD3 state-layer halo\n * ```tsx\n * import { useGestureLayer } from '@rootnative/inertia/gesture-layer'\n * import Animated from 'react-native-reanimated'\n * import { Pressable } from 'react-native'\n *\n * function SwitchHalo({ disabled }: { disabled?: boolean }) {\n * const { style, handlers } = useGestureLayer(\n * {\n * rest: { opacity: 0, backgroundColor: 'transparent' },\n * hovered: { opacity: 0.08, backgroundColor: '#000' },\n * focused: { opacity: 0.10, backgroundColor: '#000' },\n * pressed: { opacity: 0.12, backgroundColor: '#000' },\n * },\n * { disabled, transition: { type: 'timing', duration: 150 } },\n * )\n *\n * return (\n * <Pressable {...handlers}>\n * <Animated.View style={style} />\n * </Pressable>\n * )\n * }\n * ```\n */\nexport function useGestureLayer(\n states: GestureLayerStates,\n options: UseGestureLayerOptions = {},\n): UseGestureLayerResult {\n const { disabled: isDisabled = false, transition: transitionInput } = options\n const shouldReduceMotion = useShouldReduceMotion()\n // Resolve registered names here (not just in useGesture) because the\n // `disabled` layer reads the top-level transition locally. Identity is\n // preserved when no names are present; when a name resolves, the effect\n // below keys on the structural signature so a per-render resolve of the\n // map form doesn't re-fire it.\n const transition = resolveNamedTransitionProp(\n transitionInput,\n useNamedTransitions(),\n )\n const gesture = useGesture(transition)\n const disabledProgress = useSharedValue(0)\n\n const transitionSig = stableSig(transition)\n useEffect(() => {\n const target = isDisabled ? 1 : 0\n const cfg = shouldReduceMotion\n ? ({ type: 'no-animation' } as const)\n : (disabledTransition(transition) ?? ({ type: 'spring' } as const))\n disabledProgress.value = resolveTransition(cfg, target) as never\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isDisabled, shouldReduceMotion, transitionSig, disabledProgress])\n\n // JS-thread precompute: union of keys across all layers, per-key type\n // (number vs color), and a rest-fallback table. The worklet body reads\n // from `meta` instead of probing each layer per frame — the type check\n // only runs when layer identities change.\n const meta = useMemo(() => {\n const layers = {\n rest: states.rest,\n hovered: states.hovered,\n focused: states.focused,\n focusVisible: states.focusVisible,\n pressed: states.pressed,\n disabled: states.disabled,\n }\n const sources = [\n layers.rest,\n layers.hovered,\n layers.focused,\n layers.focusVisible,\n layers.pressed,\n layers.disabled,\n ]\n const keySet = new Set<string>()\n for (const src of sources) {\n if (!src) continue\n for (const k in src) if (src[k] !== undefined) keySet.add(k)\n }\n const keys = Array.from(keySet)\n const types: Record<string, 'number' | 'color'> = {}\n const restValues: Record<string, number | string> = {}\n for (const k of keys) {\n let firstDefined: number | string | undefined\n for (const src of sources) {\n if (src && src[k] !== undefined) {\n firstDefined = src[k]\n break\n }\n }\n const isColor = typeof firstDefined === 'string'\n types[k] = isColor ? 'color' : 'number'\n const restRaw = layers.rest ? layers.rest[k] : undefined\n restValues[k] =\n restRaw !== undefined ? restRaw : isColor ? 'transparent' : 0\n }\n return { layers, keys, types, restValues }\n }, [\n states.rest,\n states.hovered,\n states.focused,\n states.focusVisible,\n states.pressed,\n states.disabled,\n ])\n\n const style = useAnimatedStyle(() => {\n const { layers, keys, types, restValues } = meta\n const ph = gesture.hovered.value\n const pf = gesture.focused.value\n const pfv = gesture.focusVisible.value\n const pp = gesture.pressed.value\n const pd = disabledProgress.value\n\n const hoveredLayer = layers.hovered\n const focusedLayer = layers.focused\n const focusVisibleLayer = layers.focusVisible\n const pressedLayer = layers.pressed\n const disabledLayer = layers.disabled\n\n const out: Record<string, unknown> = {}\n\n for (let i = 0; i < keys.length; i++) {\n const k = keys[i]!\n const isColor = types[k] === 'color'\n const rest = restValues[k]!\n\n if (isColor) {\n let v = rest as string\n if (hoveredLayer && ph > 0 && hoveredLayer[k] !== undefined) {\n v = interpolateColor(ph, [0, 1], [v, hoveredLayer[k] as string])\n }\n if (focusedLayer && pf > 0 && focusedLayer[k] !== undefined) {\n v = interpolateColor(pf, [0, 1], [v, focusedLayer[k] as string])\n }\n if (\n focusVisibleLayer &&\n pfv > 0 &&\n focusVisibleLayer[k] !== undefined\n ) {\n v = interpolateColor(pfv, [0, 1], [v, focusVisibleLayer[k] as string])\n }\n if (pressedLayer && pp > 0 && pressedLayer[k] !== undefined) {\n v = interpolateColor(pp, [0, 1], [v, pressedLayer[k] as string])\n }\n if (disabledLayer && pd > 0 && disabledLayer[k] !== undefined) {\n v = interpolateColor(pd, [0, 1], [v, disabledLayer[k] as string])\n }\n out[k] = v\n } else {\n const base = rest as number\n let m = base\n if (hoveredLayer && ph > 0 && hoveredLayer[k] !== undefined) {\n const c = base + ((hoveredLayer[k] as number) - base) * ph\n if (c > m) m = c\n }\n if (focusedLayer && pf > 0 && focusedLayer[k] !== undefined) {\n const c = base + ((focusedLayer[k] as number) - base) * pf\n if (c > m) m = c\n }\n if (\n focusVisibleLayer &&\n pfv > 0 &&\n focusVisibleLayer[k] !== undefined\n ) {\n const c = base + ((focusVisibleLayer[k] as number) - base) * pfv\n if (c > m) m = c\n }\n if (pressedLayer && pp > 0 && pressedLayer[k] !== undefined) {\n const c = base + ((pressedLayer[k] as number) - base) * pp\n if (c > m) m = c\n }\n if (disabledLayer && pd > 0 && disabledLayer[k] !== undefined) {\n m = m + ((disabledLayer[k] as number) - m) * pd\n }\n out[k] = m\n }\n }\n\n return out\n })\n\n return {\n style: style as AnimatedStyle<Record<string, unknown>>,\n handlers: gesture.handlers,\n }\n}\n\nfunction disabledTransition(\n transition: TransitionConfig | GestureLayerTransitions | undefined,\n): TransitionConfig | undefined {\n if (!transition) return undefined\n if (isTopLevelTransition(transition)) return transition\n return undefined\n}\n"]}