@onlynative/inertia 0.0.1-alpha.7 → 0.0.1-alpha.9

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 (72) hide show
  1. package/README.md +1 -1
  2. package/dist/gestureLayer/index.d.mts +119 -0
  3. package/dist/gestureLayer/index.d.ts +119 -0
  4. package/dist/gestureLayer/index.js +346 -0
  5. package/dist/gestureLayer/index.js.map +1 -0
  6. package/dist/gestureLayer/index.mjs +344 -0
  7. package/dist/gestureLayer/index.mjs.map +1 -0
  8. package/dist/index.d.mts +114 -74
  9. package/dist/index.d.ts +114 -74
  10. package/dist/index.js +388 -1542
  11. package/dist/index.js.map +1 -1
  12. package/dist/index.mjs +388 -1545
  13. package/dist/index.mjs.map +1 -1
  14. package/dist/motion/Image.d.mts +1 -1
  15. package/dist/motion/Image.d.ts +1 -1
  16. package/dist/motion/Image.js +244 -1462
  17. package/dist/motion/Image.js.map +1 -1
  18. package/dist/motion/Image.mjs +247 -1465
  19. package/dist/motion/Image.mjs.map +1 -1
  20. package/dist/motion/Pressable.d.mts +1 -1
  21. package/dist/motion/Pressable.d.ts +1 -1
  22. package/dist/motion/Pressable.js +244 -1462
  23. package/dist/motion/Pressable.js.map +1 -1
  24. package/dist/motion/Pressable.mjs +247 -1465
  25. package/dist/motion/Pressable.mjs.map +1 -1
  26. package/dist/motion/ScrollView.d.mts +1 -1
  27. package/dist/motion/ScrollView.d.ts +1 -1
  28. package/dist/motion/ScrollView.js +244 -1462
  29. package/dist/motion/ScrollView.js.map +1 -1
  30. package/dist/motion/ScrollView.mjs +247 -1465
  31. package/dist/motion/ScrollView.mjs.map +1 -1
  32. package/dist/motion/Text.d.mts +1 -1
  33. package/dist/motion/Text.d.ts +1 -1
  34. package/dist/motion/Text.js +244 -1462
  35. package/dist/motion/Text.js.map +1 -1
  36. package/dist/motion/Text.mjs +247 -1465
  37. package/dist/motion/Text.mjs.map +1 -1
  38. package/dist/motion/View.d.mts +1 -1
  39. package/dist/motion/View.d.ts +1 -1
  40. package/dist/motion/View.js +244 -1462
  41. package/dist/motion/View.js.map +1 -1
  42. package/dist/motion/View.mjs +247 -1465
  43. package/dist/motion/View.mjs.map +1 -1
  44. package/dist/touch/index.d.mts +146 -0
  45. package/dist/touch/index.d.ts +146 -0
  46. package/dist/touch/index.js +166 -0
  47. package/dist/touch/index.js.map +1 -0
  48. package/dist/touch/index.mjs +164 -0
  49. package/dist/touch/index.mjs.map +1 -0
  50. package/dist/{types-NmNeJjo1.d.mts → types-cU43dEmH.d.mts} +64 -17
  51. package/dist/{types-NmNeJjo1.d.ts → types-cU43dEmH.d.ts} +64 -17
  52. package/dist/useGesture-B7A_1DVg.d.ts +84 -0
  53. package/dist/useGesture-cimMrzC1.d.mts +84 -0
  54. package/jest-setup.js +4 -0
  55. package/llms.txt +12 -3
  56. package/package.json +22 -2
  57. package/src/__type-tests__/variants.test-d.tsx +67 -0
  58. package/src/gestureLayer/index.ts +21 -0
  59. package/src/gestureLayer/useGestureLayer.ts +285 -0
  60. package/src/index.ts +7 -0
  61. package/src/layout/index.ts +15 -0
  62. package/src/layout/sharedRegistry.ts +111 -0
  63. package/src/layout/useSharedLayout.ts +289 -0
  64. package/src/motion/createMotionComponent.tsx +123 -37
  65. package/src/motion/installCheck.ts +7 -11
  66. package/src/touch/index.ts +18 -0
  67. package/src/touch/useTouchDrag.ts +289 -0
  68. package/src/types.ts +79 -20
  69. package/src/values/index.ts +11 -0
  70. package/src/values/useBooleanSpring.ts +33 -0
  71. package/src/values/useColorTransition.ts +72 -0
  72. package/src/values/useShadow.ts +116 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/transitions/spring.ts","../../src/transitions/runtime.ts","../../src/touch/useTouchDrag.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["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 withSpring,\n withTiming,\n} from 'react-native-reanimated'\nimport { springToReanimated } from './spring'\nimport { type TransitionConfig } from '../types'\n\nconst DEFAULT_TIMING_DURATION = 250\n\n/**\n * Worklet-safe single-step animation builder. Mirrors a subset of\n * `resolveTransition` for the UI-thread path where the transition config is\n * picked at gesture-release time, not at render time.\n *\n * Supported: spring / timing / decay / no-animation, single-step only.\n * Not supported: sequences, top-level repeat, easing-function\n * auto-worklet-wrapping (pass an already-worklet easing if you need a custom\n * one — most release transitions don't).\n *\n * Use this from gesture worklets (`useDrag` / `usePan` release callbacks, or\n * any custom `Gesture.Pan().onEnd(() => ...)` worklet) to animate a shared\n * value with an Inertia transition without the JS round-trip that would lose\n * the release velocity.\n *\n * For decay transitions, `toValue` is ignored — decay decelerates from the\n * SV's current position via its own physics. Pass `0` if you don't have one.\n */\nexport function buildReleaseAnimation(\n transition: TransitionConfig,\n toValue: number,\n): unknown {\n 'worklet'\n if (transition.type === 'no-animation') return toValue\n if (transition.type === 'decay') {\n const cfg: {\n velocity: number\n deceleration?: number\n clamp?: [number, number]\n } = { velocity: transition.velocity ?? 0 }\n if (transition.deceleration !== undefined) {\n cfg.deceleration = transition.deceleration\n }\n if (transition.clamp !== undefined) cfg.clamp = transition.clamp\n return withDecay(cfg)\n }\n if (transition.type === 'timing') {\n // Reanimated 4's `Easing.bezier(...)` returns an `EasingFunctionFactory`\n // rather than the function itself. Unwrap inline so consumers calling\n // `buildReleaseAnimation` from a gesture worklet don't have to.\n const e = transition.easing\n const easingFn =\n e && typeof e === 'object' && 'factory' in e\n ? e.factory()\n : (e ?? Easing.inOut(Easing.ease))\n return withTiming(toValue, {\n duration: transition.duration ?? DEFAULT_TIMING_DURATION,\n easing: easingFn,\n })\n }\n return withSpring(toValue, springToReanimated(transition))\n}\n","import { useMemo } from 'react'\nimport {\n PanResponder,\n type PanResponderGestureState,\n type PanResponderInstance,\n} from 'react-native'\nimport {\n useAnimatedStyle,\n useSharedValue,\n type SharedValue,\n} from 'react-native-reanimated'\nimport { buildReleaseAnimation } from '../transitions'\nimport type { TransitionConfig } from '../types'\n\n/**\n * Same drag-result shape as `useDrag` from `@onlynative/inertia-gestures`,\n * minus the `gesture` field (PanResponder spreads handlers, no\n * `<GestureDetector>` wrapper). The shared values + animatedStyle are\n * interchangeable across both hooks; consumers can swap implementations\n * without touching their `useAnimatedStyle` consumers.\n */\nexport interface UseTouchDragResult {\n /** Spread onto a `View` / `Pressable` to install the pan responder. */\n panHandlers: PanResponderInstance['panHandlers']\n /** Stable animated `transform` style. */\n animatedStyle: ReturnType<typeof useAnimatedStyle>\n /** Live x translation, persistent across gestures. */\n dragX: SharedValue<number>\n /** Live y translation, persistent across gestures. */\n dragY: SharedValue<number>\n /** True while the gesture is active. */\n isDragging: SharedValue<boolean>\n}\n\n/**\n * Release transition shape for PanResponder's JS-thread `onRelease`. Mirrors\n * the gesture-handler adapter's `ReleaseTransition` but with `to` typed as\n * required for spring/timing/no-animation (decay omits it).\n */\nexport type TouchReleaseTransition =\n | (TransitionConfig & { type: 'spring'; to: number })\n | (TransitionConfig & { type: 'timing'; to: number })\n | (TransitionConfig & { type: 'decay' })\n | (TransitionConfig & { type: 'no-animation'; to: number })\n\nexport interface TouchReleaseInfo {\n x: number\n y: number\n velocity: { x: number; y: number }\n}\n\nexport interface TouchReleaseResult {\n x?: TouchReleaseTransition\n y?: TouchReleaseTransition\n}\n\nexport interface UseTouchDragOptions {\n /**\n * Restrict the drag to one axis. Defaults to `'both'`. When `'x'` is set\n * the y-axis shared value never updates (and vice versa); velocity is\n * still reported on both for `onDragEnd`.\n */\n axis?: 'x' | 'y' | 'both'\n /**\n * Travel bounds (px from resting). Each side is independently optional.\n * Out-of-bounds values clamp to the limit unless `elastic > 0`.\n */\n constraints?: {\n left?: number\n right?: number\n top?: number\n bottom?: number\n }\n /**\n * Rubber-band coefficient applied to overshoot past `constraints`. `0`\n * (default) hard-clamps; `0.2`-`0.4` is a typical Framer-Motion feel.\n */\n elastic?: number\n /**\n * Fires when the user starts dragging. JS thread.\n */\n onDragStart?: () => void\n /**\n * Fires when the user releases or the gesture terminates. JS thread.\n *\n * Velocity is in px/sec to match the `@onlynative/inertia-gestures` API\n * (PanResponder's native `vx` / `vy` are px/ms; the hook normalizes).\n */\n onDragEnd?: (info: TouchReleaseInfo) => void\n /**\n * Optional release-animation callback. Return per-axis release transitions\n * to animate the SVs to a settled position via Inertia's transition\n * resolver — spring snap-to-tick, decay with bounds, timing settle.\n *\n * Unlike the gesture-handler version, this callback runs on the **JS\n * thread** (PanResponder is JS-only). The returned transitions still drive\n * UI-thread animations via Reanimated — only the decision logic is JS-side.\n */\n onRelease?: (info: TouchReleaseInfo) => TouchReleaseResult | void\n}\n\n/**\n * PanResponder-backed drag hook. Pointer-equivalent of `useDrag` from\n * `@onlynative/inertia-gestures`, with two differences:\n *\n * 1. No `react-native-gesture-handler` peer dep required — PanResponder is\n * built into React Native, so this lives in core.\n * 2. Returns `panHandlers` to spread on a `View` / `Pressable` instead of\n * a `gesture` to plug into `<GestureDetector>`.\n *\n * Use this when:\n * - You need keyboard a11y alongside drag (a slider with arrow-key step,\n * a scrollbar with `PageUp` / `PageDown`). PanResponder composes\n * cleanly with `onKeyDown`; gesture-handler doesn't surface keyboard.\n * - You don't want to take `react-native-gesture-handler` as a dependency\n * (smaller bundle, simpler install).\n *\n * Skip this when:\n * - You're already using `react-native-gesture-handler` elsewhere (use\n * `useDrag` from `@onlynative/inertia-gestures` for consistency and\n * better worklet-thread fidelity on release velocity).\n * - You need momentum semantics like the gesture-handler `usePan` —\n * PanResponder's release velocity is JS-thread and slightly less precise.\n *\n * @example\n * ```tsx\n * import { useTouchDrag } from '@onlynative/inertia/touch'\n *\n * function Slider({ ticks }: { ticks: number[] }) {\n * const drag = useTouchDrag({\n * axis: 'x',\n * constraints: { left: 0, right: 280 },\n * onRelease: (e) => {\n * const snap = nearestTick(e.x, ticks)\n * return { x: { type: 'spring', to: snap, velocity: e.velocity.x } }\n * },\n * })\n *\n * return (\n * <Motion.View\n * style={[styles.thumb, drag.animatedStyle]}\n * {...drag.panHandlers}\n * />\n * )\n * }\n * ```\n */\nexport function useTouchDrag(\n options: UseTouchDragOptions = {},\n): UseTouchDragResult {\n const { axis = 'both', constraints, elastic = 0 } = options\n\n const dragX = useSharedValue(0)\n const dragY = useSharedValue(0)\n const startX = useSharedValue(0)\n const startY = useSharedValue(0)\n const isDragging = useSharedValue(false)\n\n // Snapshot scalars into local consts so the responder callbacks close over\n // primitives, not the `options` literal — a fresh `options` each render\n // would otherwise force the PanResponder identity to change.\n const lockX = axis !== 'y'\n const lockY = axis !== 'x'\n const left = constraints?.left\n const right = constraints?.right\n const top = constraints?.top\n const bottom = constraints?.bottom\n const elasticCoef = elastic\n const { onDragStart, onDragEnd, onRelease } = options\n\n const responder = useMemo(\n () => buildResponder(),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n lockX,\n lockY,\n left,\n right,\n top,\n bottom,\n elasticCoef,\n onDragStart,\n onDragEnd,\n onRelease,\n ],\n )\n\n // Hoisted out of the inline `useMemo` factory to keep the dep list readable\n // and avoid re-declaring closure helpers each render.\n function buildResponder(): PanResponderInstance {\n const handleEnd = (g: PanResponderGestureState) => {\n isDragging.value = false\n const x = dragX.value\n const y = dragY.value\n // PanResponder velocity is px/ms; multiply to match the\n // `@onlynative/inertia-gestures` API (px/sec from gesture-handler).\n const vx = g.vx * 1000\n const vy = g.vy * 1000\n if (onRelease) {\n const result = onRelease({ x, y, velocity: { x: vx, y: vy } })\n if (result) {\n if (result.x && lockX) {\n const toX = 'to' in result.x ? result.x.to : x\n dragX.value = buildReleaseAnimation(\n result.x,\n toX,\n ) as unknown as number\n }\n if (result.y && lockY) {\n const toY = 'to' in result.y ? result.y.to : y\n dragY.value = buildReleaseAnimation(\n result.y,\n toY,\n ) as unknown as number\n }\n }\n }\n if (onDragEnd) onDragEnd({ x, y, velocity: { x: vx, y: vy } })\n }\n\n return PanResponder.create({\n // Always claim the start so taps that turn into drags don't slip\n // through to a parent ScrollView. Consumers can compose their own\n // capture predicates by wrapping the returned `panHandlers`.\n onStartShouldSetPanResponder: () => true,\n onMoveShouldSetPanResponder: () => true,\n onPanResponderGrant: () => {\n startX.value = dragX.value\n startY.value = dragY.value\n isDragging.value = true\n if (onDragStart) onDragStart()\n },\n onPanResponderMove: (_e, g) => {\n if (lockX) {\n dragX.value = applyBounds(\n startX.value + g.dx,\n left,\n right,\n elasticCoef,\n )\n }\n if (lockY) {\n dragY.value = applyBounds(\n startY.value + g.dy,\n top,\n bottom,\n elasticCoef,\n )\n }\n },\n onPanResponderRelease: (_e, g) => handleEnd(g),\n onPanResponderTerminate: (_e, g) => handleEnd(g),\n })\n }\n\n const animatedStyle = useAnimatedStyle(() => ({\n transform: [{ translateX: dragX.value }, { translateY: dragY.value }],\n }))\n\n return {\n panHandlers: responder.panHandlers,\n animatedStyle,\n dragX,\n dragY,\n isDragging,\n }\n}\n\n/**\n * Clamp `value` to `[min, max]`. When `elastic > 0` the overshoot past a\n * bound is scaled by `elastic`, giving a rubber-band feel. `min` / `max`\n * may be `undefined` to leave that side unbounded.\n *\n * JS-thread (PanResponder callbacks are JS, not worklets).\n */\nfunction applyBounds(\n value: number,\n min: number | undefined,\n max: number | undefined,\n elastic: number,\n): number {\n if (min !== undefined && value < min) {\n return elastic > 0 ? min + (value - min) * elastic : min\n }\n if (max !== undefined && value > max) {\n return elastic > 0 ? max + (value - max) * elastic : max\n }\n return value\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { ComponentType } from 'react';
1
+ import { ComponentType, ComponentProps, Ref, ReactElement } from 'react';
2
2
  import { StyleProp } from 'react-native';
3
3
 
4
4
  /**
@@ -210,8 +210,15 @@ interface VariantController<K extends string = string> {
210
210
  }
211
211
  /**
212
212
  * Props injected onto every Motion primitive.
213
+ *
214
+ * The second type parameter `V` is the concrete `variants` map. It is inferred
215
+ * from the `variants` prop at each JSX use (see `MotionComponent`), which is
216
+ * what lets `animate` narrow to the variant key union and reject typos. When
217
+ * no `variants` prop is passed, `V` falls back to `VariantsMap<C>` — whose key
218
+ * type is the open `string`, so `animate` still accepts any string and nothing
219
+ * regresses for the variant-less case.
213
220
  */
214
- interface MotionProps<C> {
221
+ interface MotionProps<C, V extends VariantsMap<C> = VariantsMap<C>> {
215
222
  /**
216
223
  * Initial values applied on mount. Read once on mount and intentionally
217
224
  * non-reactive — to reset after a state change, change the component `key`,
@@ -222,10 +229,11 @@ interface MotionProps<C> {
222
229
  initial?: AnimateStyle<C> | false;
223
230
  /**
224
231
  * The animation target. A style object, a variant key (when `variants` is
225
- * supplied), or an array of sequence steps. Variant keys autocomplete when
226
- * `variants` is annotated `as const`.
232
+ * supplied), or an array of sequence steps. When `variants` is set, the
233
+ * string form is narrowed to the map's keys, so a key typo is a compile
234
+ * error and the keys autocomplete — no `as const` required.
227
235
  */
228
- animate?: AnimateStyle<C> | string;
236
+ animate?: AnimateStyle<C> | (keyof V & string);
229
237
  /**
230
238
  * Values applied while the component exits via `<Presence>`.
231
239
  */
@@ -234,13 +242,13 @@ interface MotionProps<C> {
234
242
  * Named animation states. With `variants` set, `animate` accepts a key from
235
243
  * this map.
236
244
  */
237
- variants?: VariantsMap<C>;
245
+ variants?: V;
238
246
  /**
239
247
  * Imperative controller from `useVariants(...)`. When supplied, `animate`
240
248
  * is read from `controller.current` and re-applied whenever the controller
241
249
  * transitions. `animate` and `controller` should not both be set.
242
250
  */
243
- controller?: VariantController;
251
+ controller?: VariantController<keyof V & string>;
244
252
  /**
245
253
  * Gesture-driven sub-states (`pressed`, `focused`, `focusVisible`,
246
254
  * `hovered`). When omitted, no handlers are mounted on the underlying
@@ -269,11 +277,34 @@ interface MotionProps<C> {
269
277
  * — decay is downgraded to spring (no clear target). Reduced motion gates
270
278
  * the prop the same way it gates `animate`.
271
279
  *
272
- * `layoutId` for shared element transitions across screens is deferred:
273
- * Reanimated 4 dropped the underlying `sharedTransitionTag` API and a
274
- * Inertia-side measure-based registry is the in-flight design.
280
+ * `layoutId` (below) is a related but distinct mechanism for shared
281
+ * element transitions across screens `layout` animates this element's
282
+ * own layout changes, `layoutId` animates from a different element's
283
+ * last measured rect to this element's current rect.
275
284
  */
276
285
  layout?: boolean | TransitionConfig;
286
+ /**
287
+ * Shared-element transition id. When a Motion primitive with `layoutId`
288
+ * unmounts, its last on-screen rect is recorded under that id; the next
289
+ * mount of any Motion primitive with the same id animates from the
290
+ * recorded rect to its natural position via a FLIP transform stack.
291
+ *
292
+ * Reanimated 4 removed the `sharedTransitionTag` API — `layoutId` is the
293
+ * Inertia-side measure-based replacement. Rects are recorded in
294
+ * parent-relative coordinates (from `onLayout`), which composes when the
295
+ * source and target screens share an outer content container (the common
296
+ * stack-navigator case); nested-parent layouts need the v2
297
+ * window-coordinate path.
298
+ *
299
+ * The same `transition` prop drives the FLIP animation (spring by
300
+ * default; `'timing'` honored; `'decay'` downgrades to spring; reduced
301
+ * motion skips the transition). Out of scope for the first iteration:
302
+ * style-prop interpolation (border radius, colors, etc.) — only the
303
+ * rect-to-rect transform is animated. Two simultaneously-mounted
304
+ * primitives sharing the same `layoutId` are undefined behavior; pick a
305
+ * primitive per id at a time.
306
+ */
307
+ layoutId?: string;
277
308
  /**
278
309
  * Fired once per logical animation completion. See `AnimationCallbackInfo`
279
310
  * for the payload shape — transform parents fire once, not per axis.
@@ -281,12 +312,28 @@ interface MotionProps<C> {
281
312
  onAnimationEnd?: (info: AnimationCallbackInfo<AnimateStyle<C>>) => void;
282
313
  }
283
314
  /**
284
- * The component type produced by `createMotionComponent`. Combines the
285
- * underlying component's props (minus `style`, which we replace with an
286
- * animated style) with the Motion-specific props above.
315
+ * Props of a Motion primitive for a given underlying component `C` and a
316
+ * concrete variants map `V`: the component's own props (minus `style`, which
317
+ * we replace with an animated style) intersected with the Motion props.
287
318
  */
288
- type MotionComponent<C extends ComponentType<any>> = ComponentType<Omit<React.ComponentProps<C>, 'style'> & MotionProps<React.ComponentProps<C>> & {
289
- style?: React.ComponentProps<C>['style'];
290
- }>;
319
+ type MotionComponentProps<C extends ComponentType<any>, V extends VariantsMap<ComponentProps<C>> = VariantsMap<ComponentProps<C>>> = Omit<ComponentProps<C>, 'style'> & MotionProps<ComponentProps<C>, V> & {
320
+ style?: ComponentProps<C>['style'];
321
+ ref?: Ref<unknown>;
322
+ };
323
+ /**
324
+ * The component type produced by `createMotionComponent`.
325
+ *
326
+ * It is a **generic call signature**, not a plain `ComponentType`: the variant
327
+ * map `V` is inferred from the `variants` prop at each JSX use. That inference
328
+ * is what narrows `animate`'s string form to the variant keys, so
329
+ * `<Motion.View variants={{ open, closed }} animate="opne" />` is a compile
330
+ * error and `open` / `closed` autocomplete. With no `variants` prop, `V` falls
331
+ * back to the open `VariantsMap`, so `animate` still accepts any string and the
332
+ * variant-less call site is unchanged.
333
+ */
334
+ interface MotionComponent<C extends ComponentType<any>> {
335
+ <V extends VariantsMap<ComponentProps<C>> = VariantsMap<ComponentProps<C>>>(props: MotionComponentProps<C, V>): ReactElement | null;
336
+ displayName?: string;
337
+ }
291
338
 
292
- export type { AnimatableValue as A, DecayTransition as D, EasingInput as E, GestureLayerTransitions as G, MotionComponent as M, NoAnimationTransition as N, PerPropertyTransition as P, RepeatConfig as R, SpringTransition as S, TransitionConfig as T, VariantController as V, AnimateStyle as a, AnimationCallbackInfo as b, GestureSubStates as c, MotionProps as d, SequenceStep as e, TimingTransition as f, Transition as g, VariantsMap as h };
339
+ export type { AnimatableValue as A, DecayTransition as D, EasingInput as E, GestureSubStates as G, MotionComponent as M, NoAnimationTransition as N, PerPropertyTransition as P, RepeatConfig as R, SpringTransition as S, TransitionConfig as T, VariantController as V, AnimateStyle as a, AnimationCallbackInfo as b, MotionProps as c, SequenceStep as d, TimingTransition as e, Transition as f, VariantsMap as g, GestureLayerTransitions as h };
@@ -1,4 +1,4 @@
1
- import { ComponentType } from 'react';
1
+ import { ComponentType, ComponentProps, Ref, ReactElement } from 'react';
2
2
  import { StyleProp } from 'react-native';
3
3
 
4
4
  /**
@@ -210,8 +210,15 @@ interface VariantController<K extends string = string> {
210
210
  }
211
211
  /**
212
212
  * Props injected onto every Motion primitive.
213
+ *
214
+ * The second type parameter `V` is the concrete `variants` map. It is inferred
215
+ * from the `variants` prop at each JSX use (see `MotionComponent`), which is
216
+ * what lets `animate` narrow to the variant key union and reject typos. When
217
+ * no `variants` prop is passed, `V` falls back to `VariantsMap<C>` — whose key
218
+ * type is the open `string`, so `animate` still accepts any string and nothing
219
+ * regresses for the variant-less case.
213
220
  */
214
- interface MotionProps<C> {
221
+ interface MotionProps<C, V extends VariantsMap<C> = VariantsMap<C>> {
215
222
  /**
216
223
  * Initial values applied on mount. Read once on mount and intentionally
217
224
  * non-reactive — to reset after a state change, change the component `key`,
@@ -222,10 +229,11 @@ interface MotionProps<C> {
222
229
  initial?: AnimateStyle<C> | false;
223
230
  /**
224
231
  * The animation target. A style object, a variant key (when `variants` is
225
- * supplied), or an array of sequence steps. Variant keys autocomplete when
226
- * `variants` is annotated `as const`.
232
+ * supplied), or an array of sequence steps. When `variants` is set, the
233
+ * string form is narrowed to the map's keys, so a key typo is a compile
234
+ * error and the keys autocomplete — no `as const` required.
227
235
  */
228
- animate?: AnimateStyle<C> | string;
236
+ animate?: AnimateStyle<C> | (keyof V & string);
229
237
  /**
230
238
  * Values applied while the component exits via `<Presence>`.
231
239
  */
@@ -234,13 +242,13 @@ interface MotionProps<C> {
234
242
  * Named animation states. With `variants` set, `animate` accepts a key from
235
243
  * this map.
236
244
  */
237
- variants?: VariantsMap<C>;
245
+ variants?: V;
238
246
  /**
239
247
  * Imperative controller from `useVariants(...)`. When supplied, `animate`
240
248
  * is read from `controller.current` and re-applied whenever the controller
241
249
  * transitions. `animate` and `controller` should not both be set.
242
250
  */
243
- controller?: VariantController;
251
+ controller?: VariantController<keyof V & string>;
244
252
  /**
245
253
  * Gesture-driven sub-states (`pressed`, `focused`, `focusVisible`,
246
254
  * `hovered`). When omitted, no handlers are mounted on the underlying
@@ -269,11 +277,34 @@ interface MotionProps<C> {
269
277
  * — decay is downgraded to spring (no clear target). Reduced motion gates
270
278
  * the prop the same way it gates `animate`.
271
279
  *
272
- * `layoutId` for shared element transitions across screens is deferred:
273
- * Reanimated 4 dropped the underlying `sharedTransitionTag` API and a
274
- * Inertia-side measure-based registry is the in-flight design.
280
+ * `layoutId` (below) is a related but distinct mechanism for shared
281
+ * element transitions across screens `layout` animates this element's
282
+ * own layout changes, `layoutId` animates from a different element's
283
+ * last measured rect to this element's current rect.
275
284
  */
276
285
  layout?: boolean | TransitionConfig;
286
+ /**
287
+ * Shared-element transition id. When a Motion primitive with `layoutId`
288
+ * unmounts, its last on-screen rect is recorded under that id; the next
289
+ * mount of any Motion primitive with the same id animates from the
290
+ * recorded rect to its natural position via a FLIP transform stack.
291
+ *
292
+ * Reanimated 4 removed the `sharedTransitionTag` API — `layoutId` is the
293
+ * Inertia-side measure-based replacement. Rects are recorded in
294
+ * parent-relative coordinates (from `onLayout`), which composes when the
295
+ * source and target screens share an outer content container (the common
296
+ * stack-navigator case); nested-parent layouts need the v2
297
+ * window-coordinate path.
298
+ *
299
+ * The same `transition` prop drives the FLIP animation (spring by
300
+ * default; `'timing'` honored; `'decay'` downgrades to spring; reduced
301
+ * motion skips the transition). Out of scope for the first iteration:
302
+ * style-prop interpolation (border radius, colors, etc.) — only the
303
+ * rect-to-rect transform is animated. Two simultaneously-mounted
304
+ * primitives sharing the same `layoutId` are undefined behavior; pick a
305
+ * primitive per id at a time.
306
+ */
307
+ layoutId?: string;
277
308
  /**
278
309
  * Fired once per logical animation completion. See `AnimationCallbackInfo`
279
310
  * for the payload shape — transform parents fire once, not per axis.
@@ -281,12 +312,28 @@ interface MotionProps<C> {
281
312
  onAnimationEnd?: (info: AnimationCallbackInfo<AnimateStyle<C>>) => void;
282
313
  }
283
314
  /**
284
- * The component type produced by `createMotionComponent`. Combines the
285
- * underlying component's props (minus `style`, which we replace with an
286
- * animated style) with the Motion-specific props above.
315
+ * Props of a Motion primitive for a given underlying component `C` and a
316
+ * concrete variants map `V`: the component's own props (minus `style`, which
317
+ * we replace with an animated style) intersected with the Motion props.
287
318
  */
288
- type MotionComponent<C extends ComponentType<any>> = ComponentType<Omit<React.ComponentProps<C>, 'style'> & MotionProps<React.ComponentProps<C>> & {
289
- style?: React.ComponentProps<C>['style'];
290
- }>;
319
+ type MotionComponentProps<C extends ComponentType<any>, V extends VariantsMap<ComponentProps<C>> = VariantsMap<ComponentProps<C>>> = Omit<ComponentProps<C>, 'style'> & MotionProps<ComponentProps<C>, V> & {
320
+ style?: ComponentProps<C>['style'];
321
+ ref?: Ref<unknown>;
322
+ };
323
+ /**
324
+ * The component type produced by `createMotionComponent`.
325
+ *
326
+ * It is a **generic call signature**, not a plain `ComponentType`: the variant
327
+ * map `V` is inferred from the `variants` prop at each JSX use. That inference
328
+ * is what narrows `animate`'s string form to the variant keys, so
329
+ * `<Motion.View variants={{ open, closed }} animate="opne" />` is a compile
330
+ * error and `open` / `closed` autocomplete. With no `variants` prop, `V` falls
331
+ * back to the open `VariantsMap`, so `animate` still accepts any string and the
332
+ * variant-less call site is unchanged.
333
+ */
334
+ interface MotionComponent<C extends ComponentType<any>> {
335
+ <V extends VariantsMap<ComponentProps<C>> = VariantsMap<ComponentProps<C>>>(props: MotionComponentProps<C, V>): ReactElement | null;
336
+ displayName?: string;
337
+ }
291
338
 
292
- export type { AnimatableValue as A, DecayTransition as D, EasingInput as E, GestureLayerTransitions as G, MotionComponent as M, NoAnimationTransition as N, PerPropertyTransition as P, RepeatConfig as R, SpringTransition as S, TransitionConfig as T, VariantController as V, AnimateStyle as a, AnimationCallbackInfo as b, GestureSubStates as c, MotionProps as d, SequenceStep as e, TimingTransition as f, Transition as g, VariantsMap as h };
339
+ export type { AnimatableValue as A, DecayTransition as D, EasingInput as E, GestureSubStates as G, MotionComponent as M, NoAnimationTransition as N, PerPropertyTransition as P, RepeatConfig as R, SpringTransition as S, TransitionConfig as T, VariantController as V, AnimateStyle as a, AnimationCallbackInfo as b, MotionProps as c, SequenceStep as d, TimingTransition as e, Transition as f, VariantsMap as g, GestureLayerTransitions as h };
@@ -0,0 +1,84 @@
1
+ import { SharedValue } from 'react-native-reanimated';
2
+ import { T as TransitionConfig, h as GestureLayerTransitions } from './types-cU43dEmH.js';
3
+
4
+ /**
5
+ * Handler bag returned by `useGesture`. Spread on a `Pressable` to drive the
6
+ * shared values returned alongside.
7
+ *
8
+ * Hover handlers use `Pressable`'s own `onHoverIn` / `onHoverOut` names (web
9
+ * only — no-ops on native). `onFocus` consults `isFocusVisible()` before
10
+ * raising the keyboard-only `focusVisible` layer; `focused` always raises.
11
+ */
12
+ interface UseGestureHandlers {
13
+ onPressIn: () => void;
14
+ onPressOut: () => void;
15
+ onHoverIn: () => void;
16
+ onHoverOut: () => void;
17
+ onFocus: () => void;
18
+ onBlur: () => void;
19
+ }
20
+ interface UseGestureResult {
21
+ /** 0↔1 progress for the pressed layer. */
22
+ pressed: SharedValue<number>;
23
+ /** 0↔1 progress for the focused layer (any focus modality). */
24
+ focused: SharedValue<number>;
25
+ /** 0↔1 progress for the focusVisible layer (keyboard focus only). */
26
+ focusVisible: SharedValue<number>;
27
+ /** 0↔1 progress for the hovered layer (web only — stays at 0 on native). */
28
+ hovered: SharedValue<number>;
29
+ /** Handlers to spread on the receiving `Pressable`. */
30
+ handlers: UseGestureHandlers;
31
+ }
32
+ /**
33
+ * Build a gesture-layer controller. The hook-form of the `gesture` prop —
34
+ * reach for it when you need to drive multiple animated views from the same
35
+ * gesture state (a focus ring + state-layer halo + content tint all on one
36
+ * Pressable), which the prop-form's "animate the receiver's own style" model
37
+ * can't express.
38
+ *
39
+ * Returns four 0↔1 shared values (one per layer) and a handler bag to spread
40
+ * on a `Pressable`. The shared values are stable across renders — feed them
41
+ * into any number of `useAnimatedStyle` blocks anywhere in the tree.
42
+ *
43
+ * Transitions follow the same shape as the `gesture` prop's accompanying
44
+ * `transition`: pass a single `TransitionConfig` to use for every layer, or a
45
+ * `GestureLayerTransitions` map to give each layer its own. Layers without an
46
+ * explicit transition fall back to the library default spring.
47
+ *
48
+ * Reduced motion (via `<MotionConfig reducedMotion>`) collapses every
49
+ * transition to `no-animation` so state changes snap instead of interpolating
50
+ * — same behaviour the gesture prop applies.
51
+ *
52
+ * @example
53
+ * ```tsx
54
+ * import { useAnimatedStyle } from 'react-native-reanimated'
55
+ * import { useGesture } from '@onlynative/inertia'
56
+ *
57
+ * function Card() {
58
+ * const { pressed, focused, hovered, handlers } = useGesture({
59
+ * pressed: { type: 'timing', duration: 100 },
60
+ * hovered: { type: 'timing', duration: 150 },
61
+ * focused: { type: 'timing', duration: 200 },
62
+ * })
63
+ *
64
+ * const ringStyle = useAnimatedStyle(() => ({ opacity: focused.value }))
65
+ * const haloStyle = useAnimatedStyle(() => ({
66
+ * opacity: Math.max(
67
+ * hovered.value * 0.08,
68
+ * focused.value * 0.10,
69
+ * pressed.value * 0.10,
70
+ * ),
71
+ * }))
72
+ *
73
+ * return (
74
+ * <Pressable {...handlers}>
75
+ * <Animated.View style={ringStyle} />
76
+ * <Animated.View style={haloStyle} />
77
+ * </Pressable>
78
+ * )
79
+ * }
80
+ * ```
81
+ */
82
+ declare function useGesture(transition?: TransitionConfig | GestureLayerTransitions): UseGestureResult;
83
+
84
+ export { type UseGestureHandlers as U, type UseGestureResult as a, useGesture as u };
@@ -0,0 +1,84 @@
1
+ import { SharedValue } from 'react-native-reanimated';
2
+ import { T as TransitionConfig, h as GestureLayerTransitions } from './types-cU43dEmH.mjs';
3
+
4
+ /**
5
+ * Handler bag returned by `useGesture`. Spread on a `Pressable` to drive the
6
+ * shared values returned alongside.
7
+ *
8
+ * Hover handlers use `Pressable`'s own `onHoverIn` / `onHoverOut` names (web
9
+ * only — no-ops on native). `onFocus` consults `isFocusVisible()` before
10
+ * raising the keyboard-only `focusVisible` layer; `focused` always raises.
11
+ */
12
+ interface UseGestureHandlers {
13
+ onPressIn: () => void;
14
+ onPressOut: () => void;
15
+ onHoverIn: () => void;
16
+ onHoverOut: () => void;
17
+ onFocus: () => void;
18
+ onBlur: () => void;
19
+ }
20
+ interface UseGestureResult {
21
+ /** 0↔1 progress for the pressed layer. */
22
+ pressed: SharedValue<number>;
23
+ /** 0↔1 progress for the focused layer (any focus modality). */
24
+ focused: SharedValue<number>;
25
+ /** 0↔1 progress for the focusVisible layer (keyboard focus only). */
26
+ focusVisible: SharedValue<number>;
27
+ /** 0↔1 progress for the hovered layer (web only — stays at 0 on native). */
28
+ hovered: SharedValue<number>;
29
+ /** Handlers to spread on the receiving `Pressable`. */
30
+ handlers: UseGestureHandlers;
31
+ }
32
+ /**
33
+ * Build a gesture-layer controller. The hook-form of the `gesture` prop —
34
+ * reach for it when you need to drive multiple animated views from the same
35
+ * gesture state (a focus ring + state-layer halo + content tint all on one
36
+ * Pressable), which the prop-form's "animate the receiver's own style" model
37
+ * can't express.
38
+ *
39
+ * Returns four 0↔1 shared values (one per layer) and a handler bag to spread
40
+ * on a `Pressable`. The shared values are stable across renders — feed them
41
+ * into any number of `useAnimatedStyle` blocks anywhere in the tree.
42
+ *
43
+ * Transitions follow the same shape as the `gesture` prop's accompanying
44
+ * `transition`: pass a single `TransitionConfig` to use for every layer, or a
45
+ * `GestureLayerTransitions` map to give each layer its own. Layers without an
46
+ * explicit transition fall back to the library default spring.
47
+ *
48
+ * Reduced motion (via `<MotionConfig reducedMotion>`) collapses every
49
+ * transition to `no-animation` so state changes snap instead of interpolating
50
+ * — same behaviour the gesture prop applies.
51
+ *
52
+ * @example
53
+ * ```tsx
54
+ * import { useAnimatedStyle } from 'react-native-reanimated'
55
+ * import { useGesture } from '@onlynative/inertia'
56
+ *
57
+ * function Card() {
58
+ * const { pressed, focused, hovered, handlers } = useGesture({
59
+ * pressed: { type: 'timing', duration: 100 },
60
+ * hovered: { type: 'timing', duration: 150 },
61
+ * focused: { type: 'timing', duration: 200 },
62
+ * })
63
+ *
64
+ * const ringStyle = useAnimatedStyle(() => ({ opacity: focused.value }))
65
+ * const haloStyle = useAnimatedStyle(() => ({
66
+ * opacity: Math.max(
67
+ * hovered.value * 0.08,
68
+ * focused.value * 0.10,
69
+ * pressed.value * 0.10,
70
+ * ),
71
+ * }))
72
+ *
73
+ * return (
74
+ * <Pressable {...handlers}>
75
+ * <Animated.View style={ringStyle} />
76
+ * <Animated.View style={haloStyle} />
77
+ * </Pressable>
78
+ * )
79
+ * }
80
+ * ```
81
+ */
82
+ declare function useGesture(transition?: TransitionConfig | GestureLayerTransitions): UseGestureResult;
83
+
84
+ export { type UseGestureHandlers as U, type UseGestureResult as a, useGesture as u };
package/jest-setup.js CHANGED
@@ -104,6 +104,10 @@ jest.mock('react-native-reanimated', () => {
104
104
  }
105
105
  },
106
106
  useReducedMotion: () => false,
107
+ // Inertia's dev-time install check reads this to detect a too-old
108
+ // Reanimated. The check is skipped under NODE_ENV=test, but the named
109
+ // import must still resolve for consumers' test suites.
110
+ reanimatedVersion: '4.0.0',
107
111
  isWorkletFunction: () => false,
108
112
  cancelAnimation: () => {},
109
113
  runOnJS: (fn) => fn,
package/llms.txt CHANGED
@@ -22,10 +22,15 @@ import {
22
22
  useMotionValue,
23
23
  useAnimation,
24
24
  useSpring,
25
+ useBooleanSpring,
25
26
  useTransform,
27
+ useShadow,
28
+ useColorTransition,
26
29
  useScroll,
27
30
  } from '@onlynative/inertia'
28
- // or for tree-shaking:
31
+ // Opt-in MD3 / iOS state-layer overlay helper:
32
+ import { useGestureLayer } from '@onlynative/inertia/gesture-layer'
33
+ // or for tree-shaking the primitives:
29
34
  import { MotionView } from '@onlynative/inertia/view'
30
35
  import { MotionText } from '@onlynative/inertia/text'
31
36
  import { MotionImage } from '@onlynative/inertia/image'
@@ -39,11 +44,15 @@ import { MotionScrollView } from '@onlynative/inertia/scroll-view'
39
44
  - `<Presence>` — mount / unmount transitions; children need explicit `key`s. Exiting children get `pointerEvents: 'none'` automatically.
40
45
  - `<MotionConfig reducedMotion="user" | "never" | "always">` — gates motion against the OS reduce-motion setting (default `"user"`).
41
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 `@onlynative/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.
42
48
  - `useVariants(variants, initial?)` — returns `{ current, transitionTo }` controller for the `controller` prop.
43
49
  - `useMotionValue(initial)` — thin pass-through over `useSharedValue<T>`. Returns a `SharedValue<T>` directly so it interops with every Reanimated API without unwrapping.
44
50
  - `useAnimation(target, transition?)` — drive a `SharedValue<number>` toward `target` with any `TransitionConfig` (spring / timing / decay / no-animation, plus `repeat`). The general-purpose value-layer hook for boolean-state progress, indeterminate loops, and anywhere the same value needs to feed multiple `useAnimatedStyle` blocks.
45
51
  - `useSpring(target, config?)` — spring-only shorthand. Animates a `SharedValue<number>` toward `target` with react-spring vocab. `target` may be a plain number (effect-driven) or a `SharedValue<number>` (UI-thread reaction); the latter is the gesture-smoothing path.
52
+ - `useBooleanSpring(active, config?)` — sugar over `useSpring` for the recurring "spring 0↔1 progress from a boolean" shape (checkbox checks, accordion expansions, drawer open/closed). Identical mechanics to `useSpring(active ? 1 : 0, config)` — the named form so the call site reads as the boolean it represents.
46
53
  - `useTransform(value, inputRange, outputRange, options?)` / `useTransform(transformer)` — interpolate a numeric shared value onto a number or color range, or derive any value from any number of shared values via a worklet. Non-worklet transformers are auto-wrapped.
54
+ - `useShadow({ from, to, progress })` — pure value-layer interpolator between two `ShadowConfig`s (`shadowOpacity` / `shadowRadius` / `shadowOffset` / `elevation` / `shadowColor`) driven by a `SharedValue<number>` (0→1). Returns an animated style fragment to spread onto `style`; only emits keys present on either side, absent sides default to natural zero. The hook does not animate on its own — drive `progress` with a spring, a scroll-derived `useTransform`, or any other shared value source.
55
+ - `useColorTransition(progress, [from, to], options?)` — pure value-layer interpolator for a single color channel, driven by a `SharedValue<number>` (0→1). Returns an animated style fragment with one color key (default `backgroundColor`; configurable via `options.key` to `color` / `borderColor` / `tintColor` / `shadowColor` / per-side border colors). For raw `SharedValue<string>` output, use `useTransform(progress, [0, 1], [from, to])` instead.
47
56
  - `useScroll()` — returns `{ scrollX, scrollY, onScroll }` for use with `Motion.ScrollView`. Scroll events fire on the UI thread.
48
57
  - `createMotionComponent<C>(C)` — wrap any component with the same Motion prop surface, inferring style from `C`.
49
58
  - `buildReleaseAnimation(transition, toValue)` — worklet-safe single-step animation builder (spring / timing / decay / no-animation). For assigning Inertia-resolved animations to shared values from inside a gesture worklet. Used internally by `@onlynative/inertia-gestures`'s `useDrag({ onRelease })`.
@@ -107,7 +116,7 @@ transition={{
107
116
 
108
117
  ## Caveats
109
118
 
110
- - `Motion.Pressable` does **not** support function-form `style={({ pressed }) => ...}`. Reanimated's animated-component wrapper silently drops it. Drive press/focus/hover styling through `gesture` instead, or compute conditional styles once in render.
119
+ - Every `Motion.*` primitive **throws in dev** when `style` is a function. Reanimated's animated-component wrapper would silently drop the function-form `style={({ pressed }) => ...}` that RN's `Pressable` accepts, so the throw catches the footgun at the source. Drive press/focus/hover styling through `gesture` instead, or compute conditional styles once in render. Production builds skip the check (the styles would still be dropped — catching it in dev is the safety net).
111
120
  - `initial` is read once on mount and intentionally non-reactive. To reset after a state change, change the component `key`, remount via `<Presence>`, or drive the value through a controller. Pass `initial={false}` to skip the initial-mount animation.
112
121
 
113
122
  ## Animatable properties (alpha)
@@ -118,7 +127,7 @@ Color: `backgroundColor`, `borderColor`, `color`, `tintColor` (Image only), `sha
118
127
 
119
128
  Nested object: `shadowOffset: { width, height }`. The only nested-object style on the surface — internally decomposes into two synthetic axis SVs that the worklet recomposes into a single `shadowOffset` prop. v0.1 supports the **single-value form only** (`{ width: 0, height: 4 }`); sequences / array keyframes / per-axis transition splits are out of scope, drop to `useMotionValue` for those.
120
129
 
121
- Auto-layout transitions ship via the `layout` prop (`true` / `TransitionConfig`) on every `Motion.*` primitive — see Layout. Shared element transitions (`layoutId`) are deferred: Reanimated 4 dropped the `sharedTransitionTag` API the previous design relied on.
130
+ Auto-layout transitions ship via the `layout` prop (`true` / `TransitionConfig`) on every `Motion.*` primitive — see Layout. Shared element transitions ship via the `layoutId` prop: pair the same id on a source and target `Motion.*` and Inertia FLIPs between them on mount (parent-relative coords, rect-only animation, 1s TTL).
122
131
 
123
132
  ## Optional adapter packages
124
133
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onlynative/inertia",
3
- "version": "0.0.1-alpha.7",
3
+ "version": "0.0.1-alpha.9",
4
4
  "description": "Declarative animation primitives for React Native, built on react-native-reanimated.",
5
5
  "license": "MIT",
6
6
  "author": "OnlyNative",
@@ -79,6 +79,20 @@
79
79
  "import": "./dist/testing/index.mjs",
80
80
  "require": "./dist/testing/index.js"
81
81
  },
82
+ "./touch": {
83
+ "types": "./dist/touch/index.d.ts",
84
+ "react-native": "./src/touch/index.ts",
85
+ "source": "./src/touch/index.ts",
86
+ "import": "./dist/touch/index.mjs",
87
+ "require": "./dist/touch/index.js"
88
+ },
89
+ "./gesture-layer": {
90
+ "types": "./dist/gestureLayer/index.d.ts",
91
+ "react-native": "./src/gestureLayer/index.ts",
92
+ "source": "./src/gestureLayer/index.ts",
93
+ "import": "./dist/gestureLayer/index.mjs",
94
+ "require": "./dist/gestureLayer/index.js"
95
+ },
82
96
  "./jest-preset": "./jest-preset.js",
83
97
  "./jest-setup": "./jest-setup.js",
84
98
  "./package.json": "./package.json"
@@ -98,7 +112,13 @@
98
112
  "peerDependencies": {
99
113
  "react": ">=19.0.0",
100
114
  "react-native": ">=0.81.0",
101
- "react-native-reanimated": ">=4.0.0"
115
+ "react-native-reanimated": ">=4.0.0",
116
+ "react-native-worklets": ">=0.5.0"
117
+ },
118
+ "peerDependenciesMeta": {
119
+ "react-native-worklets": {
120
+ "optional": true
121
+ }
102
122
  },
103
123
  "devDependencies": {
104
124
  "@react-native/babel-preset": "^0.81.5",