@onlynative/inertia 0.0.1-alpha.6 → 0.0.1-alpha.8
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.
- package/README.md +1 -1
- package/dist/gestureLayer/index.d.mts +119 -0
- package/dist/gestureLayer/index.d.ts +119 -0
- package/dist/gestureLayer/index.js +1745 -0
- package/dist/gestureLayer/index.js.map +1 -0
- package/dist/gestureLayer/index.mjs +1743 -0
- package/dist/gestureLayer/index.mjs.map +1 -0
- package/dist/index.d.mts +114 -74
- package/dist/index.d.ts +114 -74
- package/dist/index.js +279 -41
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +279 -44
- package/dist/index.mjs.map +1 -1
- package/dist/motion/Image.d.mts +1 -1
- package/dist/motion/Image.d.ts +1 -1
- package/dist/motion/Image.js +178 -4
- package/dist/motion/Image.js.map +1 -1
- package/dist/motion/Image.mjs +180 -6
- package/dist/motion/Image.mjs.map +1 -1
- package/dist/motion/Pressable.d.mts +1 -1
- package/dist/motion/Pressable.d.ts +1 -1
- package/dist/motion/Pressable.js +178 -4
- package/dist/motion/Pressable.js.map +1 -1
- package/dist/motion/Pressable.mjs +180 -6
- package/dist/motion/Pressable.mjs.map +1 -1
- package/dist/motion/ScrollView.d.mts +1 -1
- package/dist/motion/ScrollView.d.ts +1 -1
- package/dist/motion/ScrollView.js +178 -4
- package/dist/motion/ScrollView.js.map +1 -1
- package/dist/motion/ScrollView.mjs +180 -6
- package/dist/motion/ScrollView.mjs.map +1 -1
- package/dist/motion/Text.d.mts +1 -1
- package/dist/motion/Text.d.ts +1 -1
- package/dist/motion/Text.js +178 -4
- package/dist/motion/Text.js.map +1 -1
- package/dist/motion/Text.mjs +180 -6
- package/dist/motion/Text.mjs.map +1 -1
- package/dist/motion/View.d.mts +1 -1
- package/dist/motion/View.d.ts +1 -1
- package/dist/motion/View.js +178 -4
- package/dist/motion/View.js.map +1 -1
- package/dist/motion/View.mjs +180 -6
- package/dist/motion/View.mjs.map +1 -1
- package/dist/touch/index.d.mts +146 -0
- package/dist/touch/index.d.ts +146 -0
- package/dist/touch/index.js +166 -0
- package/dist/touch/index.js.map +1 -0
- package/dist/touch/index.mjs +164 -0
- package/dist/touch/index.mjs.map +1 -0
- package/dist/{types-NmNeJjo1.d.mts → types-BwyvoH2V.d.mts} +24 -4
- package/dist/{types-NmNeJjo1.d.ts → types-BwyvoH2V.d.ts} +24 -4
- package/dist/useGesture-BPPp9LhV.d.ts +84 -0
- package/dist/useGesture-BnBF4OtT.d.mts +84 -0
- package/llms.txt +19 -7
- package/package.json +15 -1
- package/src/gestureLayer/index.ts +21 -0
- package/src/gestureLayer/useGestureLayer.ts +285 -0
- package/src/index.ts +7 -0
- package/src/layout/index.ts +15 -0
- package/src/layout/sharedRegistry.ts +108 -0
- package/src/layout/useSharedLayout.ts +289 -0
- package/src/motion/createMotionComponent.tsx +60 -4
- package/src/touch/index.ts +18 -0
- package/src/touch/useTouchDrag.ts +289 -0
- package/src/types.ts +23 -3
- package/src/values/index.ts +11 -0
- package/src/values/useBooleanSpring.ts +33 -0
- package/src/values/useColorTransition.ts +72 -0
- 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"]}
|
|
@@ -269,11 +269,31 @@ interface MotionProps<C> {
|
|
|
269
269
|
* — decay is downgraded to spring (no clear target). Reduced motion gates
|
|
270
270
|
* the prop the same way it gates `animate`.
|
|
271
271
|
*
|
|
272
|
-
* `layoutId`
|
|
273
|
-
*
|
|
274
|
-
*
|
|
272
|
+
* `layoutId` (below) is a related but distinct mechanism for shared
|
|
273
|
+
* element transitions across screens — `layout` animates this element's
|
|
274
|
+
* own layout changes, `layoutId` animates from a different element's
|
|
275
|
+
* last measured rect to this element's current rect.
|
|
275
276
|
*/
|
|
276
277
|
layout?: boolean | TransitionConfig;
|
|
278
|
+
/**
|
|
279
|
+
* Shared-element transition id. When a Motion primitive with `layoutId`
|
|
280
|
+
* unmounts, its last on-screen rect is recorded under that id; the next
|
|
281
|
+
* mount of any Motion primitive with the same id animates from the
|
|
282
|
+
* recorded rect to its natural position via a FLIP transform stack.
|
|
283
|
+
*
|
|
284
|
+
* Reanimated 4 removed the `sharedTransitionTag` API — `layoutId` is the
|
|
285
|
+
* Inertia-side measure-based replacement. Rects are stored in window
|
|
286
|
+
* coordinates so the source and target can live on different screens.
|
|
287
|
+
*
|
|
288
|
+
* The same `transition` prop drives the FLIP animation (spring by
|
|
289
|
+
* default; `'timing'` honored; `'decay'` downgrades to spring; reduced
|
|
290
|
+
* motion skips the transition). Out of scope for the first iteration:
|
|
291
|
+
* style-prop interpolation (border radius, colors, etc.) — only the
|
|
292
|
+
* rect-to-rect transform is animated. Two simultaneously-mounted
|
|
293
|
+
* primitives sharing the same `layoutId` are undefined behavior; pick a
|
|
294
|
+
* primitive per id at a time.
|
|
295
|
+
*/
|
|
296
|
+
layoutId?: string;
|
|
277
297
|
/**
|
|
278
298
|
* Fired once per logical animation completion. See `AnimationCallbackInfo`
|
|
279
299
|
* for the payload shape — transform parents fire once, not per axis.
|
|
@@ -289,4 +309,4 @@ type MotionComponent<C extends ComponentType<any>> = ComponentType<Omit<React.Co
|
|
|
289
309
|
style?: React.ComponentProps<C>['style'];
|
|
290
310
|
}>;
|
|
291
311
|
|
|
292
|
-
export type { AnimatableValue as A, DecayTransition as D, EasingInput as E,
|
|
312
|
+
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 };
|
|
@@ -269,11 +269,31 @@ interface MotionProps<C> {
|
|
|
269
269
|
* — decay is downgraded to spring (no clear target). Reduced motion gates
|
|
270
270
|
* the prop the same way it gates `animate`.
|
|
271
271
|
*
|
|
272
|
-
* `layoutId`
|
|
273
|
-
*
|
|
274
|
-
*
|
|
272
|
+
* `layoutId` (below) is a related but distinct mechanism for shared
|
|
273
|
+
* element transitions across screens — `layout` animates this element's
|
|
274
|
+
* own layout changes, `layoutId` animates from a different element's
|
|
275
|
+
* last measured rect to this element's current rect.
|
|
275
276
|
*/
|
|
276
277
|
layout?: boolean | TransitionConfig;
|
|
278
|
+
/**
|
|
279
|
+
* Shared-element transition id. When a Motion primitive with `layoutId`
|
|
280
|
+
* unmounts, its last on-screen rect is recorded under that id; the next
|
|
281
|
+
* mount of any Motion primitive with the same id animates from the
|
|
282
|
+
* recorded rect to its natural position via a FLIP transform stack.
|
|
283
|
+
*
|
|
284
|
+
* Reanimated 4 removed the `sharedTransitionTag` API — `layoutId` is the
|
|
285
|
+
* Inertia-side measure-based replacement. Rects are stored in window
|
|
286
|
+
* coordinates so the source and target can live on different screens.
|
|
287
|
+
*
|
|
288
|
+
* The same `transition` prop drives the FLIP animation (spring by
|
|
289
|
+
* default; `'timing'` honored; `'decay'` downgrades to spring; reduced
|
|
290
|
+
* motion skips the transition). Out of scope for the first iteration:
|
|
291
|
+
* style-prop interpolation (border radius, colors, etc.) — only the
|
|
292
|
+
* rect-to-rect transform is animated. Two simultaneously-mounted
|
|
293
|
+
* primitives sharing the same `layoutId` are undefined behavior; pick a
|
|
294
|
+
* primitive per id at a time.
|
|
295
|
+
*/
|
|
296
|
+
layoutId?: string;
|
|
277
297
|
/**
|
|
278
298
|
* Fired once per logical animation completion. See `AnimationCallbackInfo`
|
|
279
299
|
* for the payload shape — transform parents fire once, not per axis.
|
|
@@ -289,4 +309,4 @@ type MotionComponent<C extends ComponentType<any>> = ComponentType<Omit<React.Co
|
|
|
289
309
|
style?: React.ComponentProps<C>['style'];
|
|
290
310
|
}>;
|
|
291
311
|
|
|
292
|
-
export type { AnimatableValue as A, DecayTransition as D, EasingInput as E,
|
|
312
|
+
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-BwyvoH2V.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-BwyvoH2V.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/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
|
-
//
|
|
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,13 +44,18 @@ 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`.
|
|
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 })`.
|
|
49
59
|
|
|
50
60
|
## Motion props
|
|
51
61
|
|
|
@@ -58,7 +68,7 @@ import { MotionScrollView } from '@onlynative/inertia/scroll-view'
|
|
|
58
68
|
| `type` | Public config | Default? |
|
|
59
69
|
| ---------------- | ---------------------------------------------------------------- | -------- |
|
|
60
70
|
| `'spring'` | `tension`, `friction`, `mass`, `velocity`, `delay`, `repeat` | yes |
|
|
61
|
-
| `'timing'` | `duration`, `easing
|
|
71
|
+
| `'timing'` | `duration`, `easing` (`EasingFunction` or Reanimated 4 `EasingFunctionFactory` — `Easing.bezier(...)` works directly, no `.factory()` call needed), `delay`, `repeat` | |
|
|
62
72
|
| `'decay'` | `velocity`, `deceleration`, `clamp`, `delay` | |
|
|
63
73
|
| `'no-animation'` | — | |
|
|
64
74
|
|
|
@@ -106,22 +116,24 @@ transition={{
|
|
|
106
116
|
|
|
107
117
|
## Caveats
|
|
108
118
|
|
|
109
|
-
- `Motion
|
|
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).
|
|
110
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.
|
|
111
121
|
|
|
112
122
|
## Animatable properties (alpha)
|
|
113
123
|
|
|
114
|
-
Numeric: `opacity`, `translateX`, `translateY`, `scale`, `scaleX`, `scaleY`, `rotate`, `rotateX`, `rotateY`, `width`, `height`, `borderRadius`. Rotation values are degrees; the factory wraps them as `'${value}deg'`. `rotateX` / `rotateY` need a sibling `perspective` style entry to render in 3D.
|
|
124
|
+
Numeric: `opacity`, `translateX`, `translateY`, `scale`, `scaleX`, `scaleY`, `rotate`, `rotateX`, `rotateY`, `width`, `height`, `borderRadius`, `shadowOpacity`, `shadowRadius`, `elevation`. Rotation values are degrees; the factory wraps them as `'${value}deg'`. `rotateX` / `rotateY` need a sibling `perspective` style entry to render in 3D.
|
|
115
125
|
|
|
116
|
-
Color: `backgroundColor`, `borderColor`, `color`, `tintColor` (Image only)
|
|
126
|
+
Color: `backgroundColor`, `borderColor`, `color`, `tintColor` (Image only), `shadowColor`. Hex, `rgb()` / `rgba()`, `hsl()` / `hsla()`, and named colors all work; the target string is forwarded straight through `withSpring` / `withTiming` and Reanimated handles RGBA interpolation natively.
|
|
117
127
|
|
|
118
|
-
|
|
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.
|
|
129
|
+
|
|
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).
|
|
119
131
|
|
|
120
132
|
## Optional adapter packages
|
|
121
133
|
|
|
122
134
|
- `@onlynative/inertia-gradients` — `MotionLinearGradient` over `expo-linear-gradient`. Animatable: `colors`, `start`, `end`, `locations`.
|
|
123
135
|
- `@onlynative/inertia-svg` — `MotionPath` over `react-native-svg`. 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.
|
|
124
|
-
- `@onlynative/inertia-gestures` — `useDrag`, `useSwipe`, `usePan` over `react-native-gesture-handler`.
|
|
136
|
+
- `@onlynative/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.
|
|
125
137
|
|
|
126
138
|
## Docs
|
|
127
139
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onlynative/inertia",
|
|
3
|
-
"version": "0.0.1-alpha.
|
|
3
|
+
"version": "0.0.1-alpha.8",
|
|
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"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Opt-in subpath: `@onlynative/inertia/gesture-layer`.
|
|
3
|
+
*
|
|
4
|
+
* `useGestureLayer` is a generic interactive-feedback primitive that sits one
|
|
5
|
+
* step above `useGesture()` — consumer supplies per-state target values; the
|
|
6
|
+
* hook handles "strongest active layer wins" composition (clamped-max for
|
|
7
|
+
* numerics, priority cascade for colors), the worklet, and the transition.
|
|
8
|
+
*
|
|
9
|
+
* Reach for it when MD3 state-layer haloes, iOS-translucent overlays, or
|
|
10
|
+
* any "highest engaged state controls the overlay" pattern shows up. For
|
|
11
|
+
* composition models this hook doesn't express (additive, multiply, custom
|
|
12
|
+
* per-key blends), drop to `useGesture()` and write a `useAnimatedStyle`
|
|
13
|
+
* block by hand.
|
|
14
|
+
*/
|
|
15
|
+
export { useGestureLayer } from './useGestureLayer'
|
|
16
|
+
export type {
|
|
17
|
+
GestureLayerStates,
|
|
18
|
+
GestureLayerStyle,
|
|
19
|
+
UseGestureLayerOptions,
|
|
20
|
+
UseGestureLayerResult,
|
|
21
|
+
} from './useGestureLayer'
|