@onlynative/inertia 0.0.1-alpha.2 → 0.0.1-alpha.4

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 (61) hide show
  1. package/README.md +44 -3
  2. package/dist/index.d.mts +259 -3
  3. package/dist/index.d.ts +259 -3
  4. package/dist/index.js +1866 -161
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +1864 -165
  7. package/dist/index.mjs.map +1 -1
  8. package/dist/motion/Image.d.mts +1 -1
  9. package/dist/motion/Image.d.ts +1 -1
  10. package/dist/motion/Image.js +1696 -146
  11. package/dist/motion/Image.js.map +1 -1
  12. package/dist/motion/Image.mjs +1698 -148
  13. package/dist/motion/Image.mjs.map +1 -1
  14. package/dist/motion/Pressable.d.mts +1 -1
  15. package/dist/motion/Pressable.d.ts +1 -1
  16. package/dist/motion/Pressable.js +1696 -146
  17. package/dist/motion/Pressable.js.map +1 -1
  18. package/dist/motion/Pressable.mjs +1698 -148
  19. package/dist/motion/Pressable.mjs.map +1 -1
  20. package/dist/motion/ScrollView.d.mts +1 -1
  21. package/dist/motion/ScrollView.d.ts +1 -1
  22. package/dist/motion/ScrollView.js +1696 -146
  23. package/dist/motion/ScrollView.js.map +1 -1
  24. package/dist/motion/ScrollView.mjs +1698 -148
  25. package/dist/motion/ScrollView.mjs.map +1 -1
  26. package/dist/motion/Text.d.mts +1 -1
  27. package/dist/motion/Text.d.ts +1 -1
  28. package/dist/motion/Text.js +1696 -146
  29. package/dist/motion/Text.js.map +1 -1
  30. package/dist/motion/Text.mjs +1698 -148
  31. package/dist/motion/Text.mjs.map +1 -1
  32. package/dist/motion/View.d.mts +1 -1
  33. package/dist/motion/View.d.ts +1 -1
  34. package/dist/motion/View.js +1696 -146
  35. package/dist/motion/View.js.map +1 -1
  36. package/dist/motion/View.mjs +1698 -148
  37. package/dist/motion/View.mjs.map +1 -1
  38. package/dist/{types-DeZZzE_e.d.mts → types-CjztO3RW.d.mts} +89 -20
  39. package/dist/{types-DeZZzE_e.d.ts → types-CjztO3RW.d.ts} +89 -20
  40. package/llms.txt +54 -6
  41. package/package.json +1 -1
  42. package/src/__type-tests__/animate.test-d.tsx +88 -0
  43. package/src/index.ts +16 -1
  44. package/src/layout/index.ts +1 -0
  45. package/src/layout/resolveLayout.ts +54 -0
  46. package/src/motion/createMotionComponent.tsx +292 -153
  47. package/src/motion/installCheck.ts +69 -0
  48. package/src/transitions/easing.ts +3 -1
  49. package/src/transitions/index.ts +3 -0
  50. package/src/transitions/keys.ts +32 -0
  51. package/src/transitions/resolve.ts +1 -24
  52. package/src/transitions/sig.ts +40 -0
  53. package/src/transitions/spring.ts +41 -0
  54. package/src/types.ts +96 -18
  55. package/src/values/index.ts +14 -0
  56. package/src/values/useAnimation.ts +69 -0
  57. package/src/values/useGesture.ts +144 -0
  58. package/src/values/useMotionValue.ts +33 -0
  59. package/src/values/useScroll.ts +72 -0
  60. package/src/values/useSpring.ts +93 -0
  61. package/src/values/useTransform.ts +132 -0
package/README.md CHANGED
@@ -42,9 +42,11 @@ export function FadeIn() {
42
42
  - **Primitives** — `Motion.View`, `Motion.Text`, `Motion.Image`, `Motion.Pressable`, `Motion.ScrollView`. Per-primitive style inference (no shared `ViewStyle & TextStyle & ImageStyle` fallback).
43
43
  - **Sequences and keyframes** — `animate={{ x: [0, 100, 0] }}` with per-step transitions; unified `repeat: number | 'infinite' | { count, alternate }`.
44
44
  - **Variants** — `variants={{ open, closed }}` with `animate="open"`. Programmatic control via `useVariants` + `controller={...}`.
45
- - **Gestures** — single `gesture` prop on every primitive: `gesture={{ pressed, focused, focusVisible, hovered }}`. `focusVisible` engages only on keyboard focus (W3C `:focus-visible`) so click-focus on web doesn't flash a ring; on native it tracks `focused`. Zero overhead when omitted.
45
+ - **Gestures** — single `gesture` prop on every primitive: `gesture={{ pressed, focused, focusVisible, hovered }}`. Sub-states layer **additively** in priority order (`hovered → focused → focusVisible → pressed`); each layer fades in/out on its own progress so MD3 release-while-hovered cross-fades correctly. Per-layer transitions via `transition.<stateName>`. `focusVisible` engages only on keyboard focus (W3C `:focus-visible`) so click-focus on web doesn't flash a ring; on native it tracks `focused`. Zero overhead when omitted.
46
46
  - **`<Presence>`** — mount/unmount transitions; exiting children automatically receive `pointerEvents: 'none'`.
47
47
  - **`<MotionConfig reducedMotion>`** — OS reduce-motion honored end-to-end (`'user' | 'never' | 'always'`).
48
+ - **`layout` prop** — auto-layout transitions on every primitive, bridging Reanimated's `LinearTransition` via the same react-spring vocab (`tension`/`friction`/`mass`). Accepts `boolean | TransitionConfig`.
49
+ - **Value-layer hooks** — `useMotionValue`, `useSpring`, `useAnimation`, `useTransform`, `useScroll`, `useVariants`, `useGesture`. The escape hatch for animations the prop surface can't express — sibling overlays driven by a parent gesture, indeterminate loops on standalone shared values, gesture-smoothed inputs, etc.
48
50
  - **Per-primitive subpath imports** — `@onlynative/inertia/view`, `/text`, `/image`, `/pressable`, `/scroll-view`.
49
51
  - **JS-thread resolver, memoized worklets** — animate/transition objects compile to baked `withSpring` / `withTiming` / `withDecay` calls on the JS thread; the worklet body never iterates `Object.keys(...)` at frame time.
50
52
 
@@ -58,7 +60,13 @@ import { MotionPressable } from '@onlynative/inertia/pressable'
58
60
  import { MotionScrollView } from '@onlynative/inertia/scroll-view'
59
61
  ```
60
62
 
61
- A `Motion.View`-only import currently bundles to ~3.2 kB brotlied (excluding peers).
63
+ Or the barrel same primitives, named imports tree-shake cleanly because the package is `sideEffects: false`:
64
+
65
+ ```ts
66
+ import { MotionView } from '@onlynative/inertia'
67
+ ```
68
+
69
+ Both forms land at ~4.1–4.2 kB brotlied for a single primitive (peers excluded). The full namespace (`import { Motion } from '@onlynative/inertia'`, then `Motion.View`) cannot tree-shake — accessing one property of a literal object holds the whole object live — and lands at ~4.8 kB. CI checks all three forms via `size-limit` so the gap doesn't drift.
62
70
 
63
71
  ## Transitions
64
72
 
@@ -71,11 +79,44 @@ A `Motion.View`-only import currently bundles to ~3.2 kB brotlied (excluding pee
71
79
 
72
80
  Plus, on any transition: `delay`, `repeat`. Per-property transitions take precedence over the top-level transition. Spring config uses **react-spring vocabulary** (`tension`/`friction`); Reanimated's raw `stiffness`/`damping` is never on the public surface.
73
81
 
82
+ ## Caveats
83
+
84
+ - **`Motion.Pressable` does not support function-form `style`.** RN's `Pressable` accepts `style={({ pressed }) => ...}` and re-runs it per state change; Inertia inherits Reanimated's `createAnimatedComponent` wrapper, which silently drops that form (no error, no warning). Drive press/focus/hover styling through `gesture` instead, or compute conditional styles once in render. See [primitives/pressable](https://onlynative.github.io/inertia/docs/primitives/pressable#style-must-be-a-value-not-a-function).
85
+ - **`initial` is read once on mount.** Mutating `initial` after first render does nothing — change the component `key`, remount via `<Presence>`, or drive the value through a controller. Pass `initial={false}` to skip the initial-mount animation entirely.
86
+
74
87
  ## Animatable properties
75
88
 
76
89
  Numeric: `opacity`, `translateX`, `translateY`, `scale`, `scaleX`, `scaleY`, `rotate`, `rotateX`, `rotateY`, `width`, `height`, `borderRadius`. Color: `backgroundColor`, `borderColor`, `color`, `tintColor` (Image only — `Motion.View` rejects it at compile time). Layout transforms via `transform: [...]`. Color targets are forwarded straight through `withSpring` / `withTiming`; Reanimated's value setter packs the string to RGBA and interpolates on the UI thread.
77
90
 
78
- Out of scope for `0.x`: SVG path morphing, gradient interpolation, shared-element transitions across screens.
91
+ SVG path morphing ships in the [`@onlynative/inertia-svg`](../svg) adapter (`MotionPath`). Out of scope for `0.x`: shared-element transitions across screens (Reanimated 4 dropped `sharedTransitionTag`; a measure-based replacement is in design).
92
+
93
+ ## When not to use the core package alone
94
+
95
+ Three sibling packages extend Inertia for capabilities that need extra peer dependencies. The core stays minimal so apps that don't need these don't pay for them.
96
+
97
+ **Continuous gestures** — the `gesture` prop in `@onlynative/inertia` covers `pressed` / `focused` / `focusVisible` / `hovered` (the Pressable-shaped sub-states). For drag, pan, or swipe, use [`@onlynative/inertia-gestures`](../gestures):
98
+
99
+ - `useDrag` — one- or two-axis drag with optional constraints and rubber-band elasticity
100
+ - `usePan` — camera-style pan with momentum on release
101
+ - `useSwipe` — directional commit-or-snap-back (distance + velocity thresholds)
102
+
103
+ ```sh
104
+ pnpm add @onlynative/inertia-gestures react-native-gesture-handler
105
+ ```
106
+
107
+ **Animated gradients** — colors / start / end / locations interpolation on a linear gradient lives in [`@onlynative/inertia-gradients`](../gradients), wrapping `expo-linear-gradient`:
108
+
109
+ ```sh
110
+ pnpm add @onlynative/inertia-gradients expo-linear-gradient
111
+ ```
112
+
113
+ **SVG path morphing** — `MotionPath` lives in [`@onlynative/inertia-svg`](../svg), wrapping `react-native-svg`. Animates path data (`d`) on structurally-compatible paths via element-wise scalar interpolation, plus `fill` / `stroke` / `strokeWidth` / opacities / `strokeDashoffset`:
114
+
115
+ ```sh
116
+ pnpm add @onlynative/inertia-svg react-native-svg
117
+ ```
118
+
119
+ Keeping `react-native-gesture-handler`, `expo-linear-gradient`, and `react-native-svg` out of the core peer set means apps that animate buttons, sheets, and basic styles don't pay for capabilities they never invoke.
79
120
 
80
121
  ## Documentation
81
122
 
package/dist/index.d.mts CHANGED
@@ -1,8 +1,10 @@
1
1
  import * as react from 'react';
2
2
  import { ComponentType, ReactNode } from 'react';
3
3
  import * as react_native from 'react-native';
4
- import { M as MotionComponent, A as AnimatableValue, T as TransitionConfig, V as VariantController } from './types-DeZZzE_e.mjs';
5
- export { a as AnimateStyle, b as AnimationCallbackInfo, D as DecayTransition, G as GestureSubStates, c as MotionProps, N as NoAnimationTransition, P as PerPropertyTransition, R as RepeatConfig, S as SequenceStep, d as SpringTransition, e as TimingTransition, f as Transition, g as VariantsMap } from './types-DeZZzE_e.mjs';
4
+ import { NativeSyntheticEvent, NativeScrollEvent } from 'react-native';
5
+ import { M as MotionComponent, A as AnimatableValue, T as TransitionConfig, G as GestureLayerTransitions, S as SpringTransition, V as VariantController } from './types-CjztO3RW.mjs';
6
+ export { a as AnimateStyle, b as AnimationCallbackInfo, D as DecayTransition, c as GestureSubStates, d as MotionProps, N as NoAnimationTransition, P as PerPropertyTransition, R as RepeatConfig, e as SequenceStep, f as TimingTransition, g as Transition, h as VariantsMap } from './types-CjztO3RW.mjs';
7
+ import { SharedValue } from 'react-native-reanimated';
6
8
  export { MotionImage } from './motion/Image.mjs';
7
9
  export { MotionPressable } from './motion/Pressable.mjs';
8
10
  export { MotionScrollView } from './motion/ScrollView.mjs';
@@ -168,6 +170,260 @@ declare function resolveAnimatableValue<V extends number | string>(value: Animat
168
170
  */
169
171
  declare function ensureWorkletEasing(easing: ((t: number) => number) | undefined): ((t: number) => number) | undefined;
170
172
 
173
+ /**
174
+ * Drive a `SharedValue<number>` toward `target` with **any** transition shape
175
+ * — spring, timing, decay, or no-animation. The general-purpose value-layer
176
+ * hook: reach for it when you need raw `useSharedValue + useEffect + withX`
177
+ * outside the declarative `animate` flow.
178
+ *
179
+ * Re-runs whenever `target` changes shape (`target` is in the dep array) or
180
+ * the transition signature changes (kept stable via JSON-style hashing).
181
+ * Reduced motion (via `<MotionConfig reducedMotion>`) collapses the
182
+ * transition to `no-animation` so the value snaps instead of interpolating.
183
+ *
184
+ * **Spring shorthand.** Prefer [`useSpring`](./useSpring) when you only want
185
+ * spring physics — it accepts the same `tension`/`friction`/`mass` config and
186
+ * also supports a `SharedValue<number>` as the target (UI-thread reactive
187
+ * source). `useAnimation` is JS-thread-driven only.
188
+ *
189
+ * **Loops.** Repeat is part of `TransitionConfig` and flows through
190
+ * untouched — `useAnimation(1, { type: 'timing', duration: 1800, repeat: {
191
+ * count: 'infinite', alternate: false } })` produces an indeterminate-style
192
+ * progress driver.
193
+ *
194
+ * @example
195
+ * ```ts
196
+ * // Toggle progress (Switch / Checkbox / Radio).
197
+ * const progress = useAnimation(isChecked ? 1 : 0, {
198
+ * type: 'spring',
199
+ * tension: 380,
200
+ * friction: 33,
201
+ * })
202
+ *
203
+ * // Float a TextField label when the value becomes non-empty.
204
+ * const floated = useAnimation(hasValue ? 1 : 0, {
205
+ * type: 'timing',
206
+ * duration: 150,
207
+ * })
208
+ *
209
+ * // Indeterminate progress slider (loops forever, snaps back).
210
+ * const slide = useAnimation(1, {
211
+ * type: 'timing',
212
+ * duration: 1800,
213
+ * repeat: { count: 'infinite', alternate: false },
214
+ * })
215
+ * ```
216
+ */
217
+ declare function useAnimation(target: number, transition?: TransitionConfig): SharedValue<number>;
218
+
219
+ /**
220
+ * Handler bag returned by `useGesture`. Spread on a `Pressable` to drive the
221
+ * shared values returned alongside.
222
+ *
223
+ * Hover handlers use `Pressable`'s own `onHoverIn` / `onHoverOut` names (web
224
+ * only — no-ops on native). `onFocus` consults `isFocusVisible()` before
225
+ * raising the keyboard-only `focusVisible` layer; `focused` always raises.
226
+ */
227
+ interface UseGestureHandlers {
228
+ onPressIn: () => void;
229
+ onPressOut: () => void;
230
+ onHoverIn: () => void;
231
+ onHoverOut: () => void;
232
+ onFocus: () => void;
233
+ onBlur: () => void;
234
+ }
235
+ interface UseGestureResult {
236
+ /** 0↔1 progress for the pressed layer. */
237
+ pressed: SharedValue<number>;
238
+ /** 0↔1 progress for the focused layer (any focus modality). */
239
+ focused: SharedValue<number>;
240
+ /** 0↔1 progress for the focusVisible layer (keyboard focus only). */
241
+ focusVisible: SharedValue<number>;
242
+ /** 0↔1 progress for the hovered layer (web only — stays at 0 on native). */
243
+ hovered: SharedValue<number>;
244
+ /** Handlers to spread on the receiving `Pressable`. */
245
+ handlers: UseGestureHandlers;
246
+ }
247
+ /**
248
+ * Build a gesture-layer controller. The hook-form of the `gesture` prop —
249
+ * reach for it when you need to drive multiple animated views from the same
250
+ * gesture state (a focus ring + state-layer halo + content tint all on one
251
+ * Pressable), which the prop-form's "animate the receiver's own style" model
252
+ * can't express.
253
+ *
254
+ * Returns four 0↔1 shared values (one per layer) and a handler bag to spread
255
+ * on a `Pressable`. The shared values are stable across renders — feed them
256
+ * into any number of `useAnimatedStyle` blocks anywhere in the tree.
257
+ *
258
+ * Transitions follow the same shape as the `gesture` prop's accompanying
259
+ * `transition`: pass a single `TransitionConfig` to use for every layer, or a
260
+ * `GestureLayerTransitions` map to give each layer its own. Layers without an
261
+ * explicit transition fall back to the library default spring.
262
+ *
263
+ * Reduced motion (via `<MotionConfig reducedMotion>`) collapses every
264
+ * transition to `no-animation` so state changes snap instead of interpolating
265
+ * — same behaviour the gesture prop applies.
266
+ *
267
+ * @example
268
+ * ```tsx
269
+ * import { useAnimatedStyle } from 'react-native-reanimated'
270
+ * import { useGesture } from '@onlynative/inertia'
271
+ *
272
+ * function Card() {
273
+ * const { pressed, focused, hovered, handlers } = useGesture({
274
+ * pressed: { type: 'timing', duration: 100 },
275
+ * hovered: { type: 'timing', duration: 150 },
276
+ * focused: { type: 'timing', duration: 200 },
277
+ * })
278
+ *
279
+ * const ringStyle = useAnimatedStyle(() => ({ opacity: focused.value }))
280
+ * const haloStyle = useAnimatedStyle(() => ({
281
+ * opacity: Math.max(
282
+ * hovered.value * 0.08,
283
+ * focused.value * 0.10,
284
+ * pressed.value * 0.10,
285
+ * ),
286
+ * }))
287
+ *
288
+ * return (
289
+ * <Pressable {...handlers}>
290
+ * <Animated.View style={ringStyle} />
291
+ * <Animated.View style={haloStyle} />
292
+ * </Pressable>
293
+ * )
294
+ * }
295
+ * ```
296
+ */
297
+ declare function useGesture(transition?: TransitionConfig | GestureLayerTransitions): UseGestureResult;
298
+
299
+ /**
300
+ * Create an animatable value owned by JS but readable from worklets.
301
+ *
302
+ * This is the escape-hatch primitive that the rest of the value-layer hooks
303
+ * (`useSpring`, `useTransform`, `useScroll`) compose against. It is a thin
304
+ * pass-through over Reanimated's `useSharedValue`: a `SharedValue<T>` with
305
+ * `.value` for direct reads/writes (UI-thread reads in worklets, JS-thread
306
+ * writes from event handlers / effects).
307
+ *
308
+ * We intentionally do not introduce a `MotionValue` wrapper class around the
309
+ * shared value. The simplest object that interops with `useAnimatedStyle`,
310
+ * `useDerivedValue`, and every other Reanimated API _is_ the shared value
311
+ * itself; adding a `{ get, set, value }` shell would force consumers to
312
+ * unwrap it at every Reanimated boundary and break worklet capture.
313
+ *
314
+ * Worklet read:
315
+ * ```ts
316
+ * const x = useMotionValue(0)
317
+ * useAnimatedStyle(() => ({ transform: [{ translateX: x.value }] }))
318
+ * ```
319
+ *
320
+ * JS write:
321
+ * ```ts
322
+ * onPress={() => { x.value = 100 }}
323
+ * ```
324
+ */
325
+ declare function useMotionValue<T extends number | string>(initial: T): SharedValue<T>;
326
+
327
+ /**
328
+ * Animate a shared value toward `target` with spring physics, using the
329
+ * library's react-spring vocabulary (`tension` / `friction` / `mass`).
330
+ *
331
+ * `target` may be a plain number or a `SharedValue<number>`. The plain-number
332
+ * path drives the spring from a JS `useEffect`, so the animation re-runs on
333
+ * every render where `target` changes. The shared-value path drives the
334
+ * spring from a Reanimated reaction on the UI thread, so values produced by
335
+ * gestures, scroll handlers, or other worklets flow through without bouncing
336
+ * back to JS.
337
+ *
338
+ * Both call sites end up at the same `withSpring` invocation; the split is
339
+ * just about which thread observes the source change.
340
+ */
341
+ declare function useSpring(target: number | SharedValue<number>, config?: SpringTransition): SharedValue<number>;
342
+
343
+ /**
344
+ * Extrapolation behavior at the edges of the input range. Mirrors
345
+ * Reanimated's enum so consumers don't need a separate import.
346
+ *
347
+ * - `'clamp'` (default) — output stays pinned at the first/last value
348
+ * outside the input range. Matches Framer Motion's default.
349
+ * - `'identity'` — return the input unchanged outside the range.
350
+ * - `'extend'` — continue the linear slope beyond the range.
351
+ */
352
+ type ExtrapolationMode = 'clamp' | 'identity' | 'extend';
353
+ interface UseTransformOptions {
354
+ extrapolateLeft?: ExtrapolationMode;
355
+ extrapolateRight?: ExtrapolationMode;
356
+ }
357
+ /**
358
+ * Derive a value from one or more shared values via a transformer worklet.
359
+ *
360
+ * ```ts
361
+ * const x = useMotionValue(0)
362
+ * const y = useMotionValue(0)
363
+ * const distance = useTransform(() => Math.sqrt(x.value ** 2 + y.value ** 2))
364
+ * ```
365
+ *
366
+ * The transformer must be a worklet (or a plain function we auto-wrap —
367
+ * see the easing wrapper for the rationale). It runs on the UI thread on
368
+ * every frame where any read shared value changes.
369
+ */
370
+ declare function useTransform<T>(transformer: () => T): SharedValue<T>;
371
+ /**
372
+ * Interpolate a numeric shared value onto a range of numbers or colors.
373
+ *
374
+ * ```ts
375
+ * const scroll = useMotionValue(0)
376
+ * const headerOpacity = useTransform(scroll, [0, 100], [1, 0])
377
+ * const headerColor = useTransform(scroll, [0, 100], ['#fff', '#000'])
378
+ * ```
379
+ *
380
+ * When `outputRange` is numeric, this maps to Reanimated's `interpolate`;
381
+ * when it's a tuple of color strings, it maps to `interpolateColor`. The
382
+ * input range must be monotonically increasing.
383
+ */
384
+ declare function useTransform(value: SharedValue<number>, inputRange: readonly number[], outputRange: readonly number[], options?: UseTransformOptions): SharedValue<number>;
385
+ declare function useTransform(value: SharedValue<number>, inputRange: readonly number[], outputRange: readonly string[], options?: UseTransformOptions): SharedValue<string>;
386
+
387
+ interface UseScrollResult {
388
+ /** Horizontal scroll offset in points. */
389
+ scrollX: SharedValue<number>;
390
+ /** Vertical scroll offset in points. */
391
+ scrollY: SharedValue<number>;
392
+ /**
393
+ * Handler to pass to a `Motion.ScrollView`'s `onScroll` prop (or any other
394
+ * Reanimated `Animated.ScrollView`). The handler is opaque to JS — it runs
395
+ * as a worklet — but the type narrows to the same shape RN's native
396
+ * `onScroll` prop expects so it composes cleanly.
397
+ */
398
+ onScroll: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
399
+ }
400
+ /**
401
+ * Track the scroll offset of a `Motion.ScrollView` as shared values.
402
+ *
403
+ * ```tsx
404
+ * const { scrollY, onScroll } = useScroll()
405
+ * const headerOpacity = useTransform(scrollY, [0, 100], [1, 0])
406
+ *
407
+ * return (
408
+ * <>
409
+ * <Motion.View animate={{ opacity: headerOpacity }} />
410
+ * <Motion.ScrollView onScroll={onScroll} scrollEventThrottle={16}>
411
+ * …
412
+ * </Motion.ScrollView>
413
+ * </>
414
+ * )
415
+ * ```
416
+ *
417
+ * Scroll events fire on the UI thread, so `scrollX` / `scrollY` are safe to
418
+ * read from any worklet (`useAnimatedStyle`, `useDerivedValue`,
419
+ * `useTransform`) without a JS-thread bounce.
420
+ *
421
+ * Remember to set `scrollEventThrottle={16}` on the `ScrollView` for 60Hz
422
+ * updates — RN's default is to dispatch on every event, which on iOS still
423
+ * means one per frame, but Android benefits from the explicit cap.
424
+ */
425
+ declare function useScroll(): UseScrollResult;
426
+
171
427
  /**
172
428
  * Build a controller for a variants map. The controller is the imperative
173
429
  * escape hatch — pass it to a Motion primitive via `controller={...}` and
@@ -181,4 +437,4 @@ declare function ensureWorkletEasing(easing: ((t: number) => number) | undefined
181
437
  */
182
438
  declare function useVariants<V extends Readonly<Record<string, object>>>(variants: V, initial?: keyof V & string): VariantController<keyof V & string>;
183
439
 
184
- export { AnimatableValue, Motion, MotionComponent, MotionConfig, type MotionConfigValue, Presence, type PresenceContextValue, type ReducedMotion, TransitionConfig, VariantController, createMotionComponent, ensureWorkletEasing, resolveAnimatableValue, resolveTransition, useMotionConfig, usePresence, useShouldReduceMotion, useVariants };
440
+ export { AnimatableValue, type ExtrapolationMode, Motion, MotionComponent, MotionConfig, type MotionConfigValue, Presence, type PresenceContextValue, type ReducedMotion, SpringTransition, TransitionConfig, type UseGestureHandlers, type UseGestureResult, type UseScrollResult, type UseTransformOptions, VariantController, createMotionComponent, ensureWorkletEasing, resolveAnimatableValue, resolveTransition, useAnimation, useGesture, useMotionConfig, useMotionValue, usePresence, useScroll, useShouldReduceMotion, useSpring, useTransform, useVariants };
package/dist/index.d.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  import * as react from 'react';
2
2
  import { ComponentType, ReactNode } from 'react';
3
3
  import * as react_native from 'react-native';
4
- import { M as MotionComponent, A as AnimatableValue, T as TransitionConfig, V as VariantController } from './types-DeZZzE_e.js';
5
- export { a as AnimateStyle, b as AnimationCallbackInfo, D as DecayTransition, G as GestureSubStates, c as MotionProps, N as NoAnimationTransition, P as PerPropertyTransition, R as RepeatConfig, S as SequenceStep, d as SpringTransition, e as TimingTransition, f as Transition, g as VariantsMap } from './types-DeZZzE_e.js';
4
+ import { NativeSyntheticEvent, NativeScrollEvent } from 'react-native';
5
+ import { M as MotionComponent, A as AnimatableValue, T as TransitionConfig, G as GestureLayerTransitions, S as SpringTransition, V as VariantController } from './types-CjztO3RW.js';
6
+ export { a as AnimateStyle, b as AnimationCallbackInfo, D as DecayTransition, c as GestureSubStates, d as MotionProps, N as NoAnimationTransition, P as PerPropertyTransition, R as RepeatConfig, e as SequenceStep, f as TimingTransition, g as Transition, h as VariantsMap } from './types-CjztO3RW.js';
7
+ import { SharedValue } from 'react-native-reanimated';
6
8
  export { MotionImage } from './motion/Image.js';
7
9
  export { MotionPressable } from './motion/Pressable.js';
8
10
  export { MotionScrollView } from './motion/ScrollView.js';
@@ -168,6 +170,260 @@ declare function resolveAnimatableValue<V extends number | string>(value: Animat
168
170
  */
169
171
  declare function ensureWorkletEasing(easing: ((t: number) => number) | undefined): ((t: number) => number) | undefined;
170
172
 
173
+ /**
174
+ * Drive a `SharedValue<number>` toward `target` with **any** transition shape
175
+ * — spring, timing, decay, or no-animation. The general-purpose value-layer
176
+ * hook: reach for it when you need raw `useSharedValue + useEffect + withX`
177
+ * outside the declarative `animate` flow.
178
+ *
179
+ * Re-runs whenever `target` changes shape (`target` is in the dep array) or
180
+ * the transition signature changes (kept stable via JSON-style hashing).
181
+ * Reduced motion (via `<MotionConfig reducedMotion>`) collapses the
182
+ * transition to `no-animation` so the value snaps instead of interpolating.
183
+ *
184
+ * **Spring shorthand.** Prefer [`useSpring`](./useSpring) when you only want
185
+ * spring physics — it accepts the same `tension`/`friction`/`mass` config and
186
+ * also supports a `SharedValue<number>` as the target (UI-thread reactive
187
+ * source). `useAnimation` is JS-thread-driven only.
188
+ *
189
+ * **Loops.** Repeat is part of `TransitionConfig` and flows through
190
+ * untouched — `useAnimation(1, { type: 'timing', duration: 1800, repeat: {
191
+ * count: 'infinite', alternate: false } })` produces an indeterminate-style
192
+ * progress driver.
193
+ *
194
+ * @example
195
+ * ```ts
196
+ * // Toggle progress (Switch / Checkbox / Radio).
197
+ * const progress = useAnimation(isChecked ? 1 : 0, {
198
+ * type: 'spring',
199
+ * tension: 380,
200
+ * friction: 33,
201
+ * })
202
+ *
203
+ * // Float a TextField label when the value becomes non-empty.
204
+ * const floated = useAnimation(hasValue ? 1 : 0, {
205
+ * type: 'timing',
206
+ * duration: 150,
207
+ * })
208
+ *
209
+ * // Indeterminate progress slider (loops forever, snaps back).
210
+ * const slide = useAnimation(1, {
211
+ * type: 'timing',
212
+ * duration: 1800,
213
+ * repeat: { count: 'infinite', alternate: false },
214
+ * })
215
+ * ```
216
+ */
217
+ declare function useAnimation(target: number, transition?: TransitionConfig): SharedValue<number>;
218
+
219
+ /**
220
+ * Handler bag returned by `useGesture`. Spread on a `Pressable` to drive the
221
+ * shared values returned alongside.
222
+ *
223
+ * Hover handlers use `Pressable`'s own `onHoverIn` / `onHoverOut` names (web
224
+ * only — no-ops on native). `onFocus` consults `isFocusVisible()` before
225
+ * raising the keyboard-only `focusVisible` layer; `focused` always raises.
226
+ */
227
+ interface UseGestureHandlers {
228
+ onPressIn: () => void;
229
+ onPressOut: () => void;
230
+ onHoverIn: () => void;
231
+ onHoverOut: () => void;
232
+ onFocus: () => void;
233
+ onBlur: () => void;
234
+ }
235
+ interface UseGestureResult {
236
+ /** 0↔1 progress for the pressed layer. */
237
+ pressed: SharedValue<number>;
238
+ /** 0↔1 progress for the focused layer (any focus modality). */
239
+ focused: SharedValue<number>;
240
+ /** 0↔1 progress for the focusVisible layer (keyboard focus only). */
241
+ focusVisible: SharedValue<number>;
242
+ /** 0↔1 progress for the hovered layer (web only — stays at 0 on native). */
243
+ hovered: SharedValue<number>;
244
+ /** Handlers to spread on the receiving `Pressable`. */
245
+ handlers: UseGestureHandlers;
246
+ }
247
+ /**
248
+ * Build a gesture-layer controller. The hook-form of the `gesture` prop —
249
+ * reach for it when you need to drive multiple animated views from the same
250
+ * gesture state (a focus ring + state-layer halo + content tint all on one
251
+ * Pressable), which the prop-form's "animate the receiver's own style" model
252
+ * can't express.
253
+ *
254
+ * Returns four 0↔1 shared values (one per layer) and a handler bag to spread
255
+ * on a `Pressable`. The shared values are stable across renders — feed them
256
+ * into any number of `useAnimatedStyle` blocks anywhere in the tree.
257
+ *
258
+ * Transitions follow the same shape as the `gesture` prop's accompanying
259
+ * `transition`: pass a single `TransitionConfig` to use for every layer, or a
260
+ * `GestureLayerTransitions` map to give each layer its own. Layers without an
261
+ * explicit transition fall back to the library default spring.
262
+ *
263
+ * Reduced motion (via `<MotionConfig reducedMotion>`) collapses every
264
+ * transition to `no-animation` so state changes snap instead of interpolating
265
+ * — same behaviour the gesture prop applies.
266
+ *
267
+ * @example
268
+ * ```tsx
269
+ * import { useAnimatedStyle } from 'react-native-reanimated'
270
+ * import { useGesture } from '@onlynative/inertia'
271
+ *
272
+ * function Card() {
273
+ * const { pressed, focused, hovered, handlers } = useGesture({
274
+ * pressed: { type: 'timing', duration: 100 },
275
+ * hovered: { type: 'timing', duration: 150 },
276
+ * focused: { type: 'timing', duration: 200 },
277
+ * })
278
+ *
279
+ * const ringStyle = useAnimatedStyle(() => ({ opacity: focused.value }))
280
+ * const haloStyle = useAnimatedStyle(() => ({
281
+ * opacity: Math.max(
282
+ * hovered.value * 0.08,
283
+ * focused.value * 0.10,
284
+ * pressed.value * 0.10,
285
+ * ),
286
+ * }))
287
+ *
288
+ * return (
289
+ * <Pressable {...handlers}>
290
+ * <Animated.View style={ringStyle} />
291
+ * <Animated.View style={haloStyle} />
292
+ * </Pressable>
293
+ * )
294
+ * }
295
+ * ```
296
+ */
297
+ declare function useGesture(transition?: TransitionConfig | GestureLayerTransitions): UseGestureResult;
298
+
299
+ /**
300
+ * Create an animatable value owned by JS but readable from worklets.
301
+ *
302
+ * This is the escape-hatch primitive that the rest of the value-layer hooks
303
+ * (`useSpring`, `useTransform`, `useScroll`) compose against. It is a thin
304
+ * pass-through over Reanimated's `useSharedValue`: a `SharedValue<T>` with
305
+ * `.value` for direct reads/writes (UI-thread reads in worklets, JS-thread
306
+ * writes from event handlers / effects).
307
+ *
308
+ * We intentionally do not introduce a `MotionValue` wrapper class around the
309
+ * shared value. The simplest object that interops with `useAnimatedStyle`,
310
+ * `useDerivedValue`, and every other Reanimated API _is_ the shared value
311
+ * itself; adding a `{ get, set, value }` shell would force consumers to
312
+ * unwrap it at every Reanimated boundary and break worklet capture.
313
+ *
314
+ * Worklet read:
315
+ * ```ts
316
+ * const x = useMotionValue(0)
317
+ * useAnimatedStyle(() => ({ transform: [{ translateX: x.value }] }))
318
+ * ```
319
+ *
320
+ * JS write:
321
+ * ```ts
322
+ * onPress={() => { x.value = 100 }}
323
+ * ```
324
+ */
325
+ declare function useMotionValue<T extends number | string>(initial: T): SharedValue<T>;
326
+
327
+ /**
328
+ * Animate a shared value toward `target` with spring physics, using the
329
+ * library's react-spring vocabulary (`tension` / `friction` / `mass`).
330
+ *
331
+ * `target` may be a plain number or a `SharedValue<number>`. The plain-number
332
+ * path drives the spring from a JS `useEffect`, so the animation re-runs on
333
+ * every render where `target` changes. The shared-value path drives the
334
+ * spring from a Reanimated reaction on the UI thread, so values produced by
335
+ * gestures, scroll handlers, or other worklets flow through without bouncing
336
+ * back to JS.
337
+ *
338
+ * Both call sites end up at the same `withSpring` invocation; the split is
339
+ * just about which thread observes the source change.
340
+ */
341
+ declare function useSpring(target: number | SharedValue<number>, config?: SpringTransition): SharedValue<number>;
342
+
343
+ /**
344
+ * Extrapolation behavior at the edges of the input range. Mirrors
345
+ * Reanimated's enum so consumers don't need a separate import.
346
+ *
347
+ * - `'clamp'` (default) — output stays pinned at the first/last value
348
+ * outside the input range. Matches Framer Motion's default.
349
+ * - `'identity'` — return the input unchanged outside the range.
350
+ * - `'extend'` — continue the linear slope beyond the range.
351
+ */
352
+ type ExtrapolationMode = 'clamp' | 'identity' | 'extend';
353
+ interface UseTransformOptions {
354
+ extrapolateLeft?: ExtrapolationMode;
355
+ extrapolateRight?: ExtrapolationMode;
356
+ }
357
+ /**
358
+ * Derive a value from one or more shared values via a transformer worklet.
359
+ *
360
+ * ```ts
361
+ * const x = useMotionValue(0)
362
+ * const y = useMotionValue(0)
363
+ * const distance = useTransform(() => Math.sqrt(x.value ** 2 + y.value ** 2))
364
+ * ```
365
+ *
366
+ * The transformer must be a worklet (or a plain function we auto-wrap —
367
+ * see the easing wrapper for the rationale). It runs on the UI thread on
368
+ * every frame where any read shared value changes.
369
+ */
370
+ declare function useTransform<T>(transformer: () => T): SharedValue<T>;
371
+ /**
372
+ * Interpolate a numeric shared value onto a range of numbers or colors.
373
+ *
374
+ * ```ts
375
+ * const scroll = useMotionValue(0)
376
+ * const headerOpacity = useTransform(scroll, [0, 100], [1, 0])
377
+ * const headerColor = useTransform(scroll, [0, 100], ['#fff', '#000'])
378
+ * ```
379
+ *
380
+ * When `outputRange` is numeric, this maps to Reanimated's `interpolate`;
381
+ * when it's a tuple of color strings, it maps to `interpolateColor`. The
382
+ * input range must be monotonically increasing.
383
+ */
384
+ declare function useTransform(value: SharedValue<number>, inputRange: readonly number[], outputRange: readonly number[], options?: UseTransformOptions): SharedValue<number>;
385
+ declare function useTransform(value: SharedValue<number>, inputRange: readonly number[], outputRange: readonly string[], options?: UseTransformOptions): SharedValue<string>;
386
+
387
+ interface UseScrollResult {
388
+ /** Horizontal scroll offset in points. */
389
+ scrollX: SharedValue<number>;
390
+ /** Vertical scroll offset in points. */
391
+ scrollY: SharedValue<number>;
392
+ /**
393
+ * Handler to pass to a `Motion.ScrollView`'s `onScroll` prop (or any other
394
+ * Reanimated `Animated.ScrollView`). The handler is opaque to JS — it runs
395
+ * as a worklet — but the type narrows to the same shape RN's native
396
+ * `onScroll` prop expects so it composes cleanly.
397
+ */
398
+ onScroll: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
399
+ }
400
+ /**
401
+ * Track the scroll offset of a `Motion.ScrollView` as shared values.
402
+ *
403
+ * ```tsx
404
+ * const { scrollY, onScroll } = useScroll()
405
+ * const headerOpacity = useTransform(scrollY, [0, 100], [1, 0])
406
+ *
407
+ * return (
408
+ * <>
409
+ * <Motion.View animate={{ opacity: headerOpacity }} />
410
+ * <Motion.ScrollView onScroll={onScroll} scrollEventThrottle={16}>
411
+ * …
412
+ * </Motion.ScrollView>
413
+ * </>
414
+ * )
415
+ * ```
416
+ *
417
+ * Scroll events fire on the UI thread, so `scrollX` / `scrollY` are safe to
418
+ * read from any worklet (`useAnimatedStyle`, `useDerivedValue`,
419
+ * `useTransform`) without a JS-thread bounce.
420
+ *
421
+ * Remember to set `scrollEventThrottle={16}` on the `ScrollView` for 60Hz
422
+ * updates — RN's default is to dispatch on every event, which on iOS still
423
+ * means one per frame, but Android benefits from the explicit cap.
424
+ */
425
+ declare function useScroll(): UseScrollResult;
426
+
171
427
  /**
172
428
  * Build a controller for a variants map. The controller is the imperative
173
429
  * escape hatch — pass it to a Motion primitive via `controller={...}` and
@@ -181,4 +437,4 @@ declare function ensureWorkletEasing(easing: ((t: number) => number) | undefined
181
437
  */
182
438
  declare function useVariants<V extends Readonly<Record<string, object>>>(variants: V, initial?: keyof V & string): VariantController<keyof V & string>;
183
439
 
184
- export { AnimatableValue, Motion, MotionComponent, MotionConfig, type MotionConfigValue, Presence, type PresenceContextValue, type ReducedMotion, TransitionConfig, VariantController, createMotionComponent, ensureWorkletEasing, resolveAnimatableValue, resolveTransition, useMotionConfig, usePresence, useShouldReduceMotion, useVariants };
440
+ export { AnimatableValue, type ExtrapolationMode, Motion, MotionComponent, MotionConfig, type MotionConfigValue, Presence, type PresenceContextValue, type ReducedMotion, SpringTransition, TransitionConfig, type UseGestureHandlers, type UseGestureResult, type UseScrollResult, type UseTransformOptions, VariantController, createMotionComponent, ensureWorkletEasing, resolveAnimatableValue, resolveTransition, useAnimation, useGesture, useMotionConfig, useMotionValue, usePresence, useScroll, useShouldReduceMotion, useSpring, useTransform, useVariants };