@rootnative/inertia 0.0.0-alpha.0 → 0.0.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/README.md +2 -0
- package/dist/gestureLayer/index.d.mts +48 -7
- package/dist/gestureLayer/index.d.ts +48 -7
- package/dist/gestureLayer/index.js +107 -30
- package/dist/gestureLayer/index.mjs +107 -30
- package/dist/index.d.mts +127 -16
- package/dist/index.d.ts +127 -16
- package/dist/index.js +177 -62
- package/dist/index.mjs +175 -63
- package/dist/motion/Image.d.mts +1 -1
- package/dist/motion/Image.d.ts +1 -1
- package/dist/motion/Image.js +90 -50
- package/dist/motion/Image.mjs +90 -50
- package/dist/motion/Pressable.d.mts +1 -1
- package/dist/motion/Pressable.d.ts +1 -1
- package/dist/motion/Pressable.js +90 -50
- package/dist/motion/Pressable.mjs +90 -50
- package/dist/motion/ScrollView.d.mts +1 -1
- package/dist/motion/ScrollView.d.ts +1 -1
- package/dist/motion/ScrollView.js +90 -50
- package/dist/motion/ScrollView.mjs +90 -50
- package/dist/motion/Text.d.mts +1 -1
- package/dist/motion/Text.d.ts +1 -1
- package/dist/motion/Text.js +90 -50
- package/dist/motion/Text.mjs +90 -50
- package/dist/motion/View.d.mts +1 -1
- package/dist/motion/View.d.ts +1 -1
- package/dist/motion/View.js +90 -50
- package/dist/motion/View.mjs +90 -50
- package/dist/testing/index.js +0 -2
- package/dist/testing/index.mjs +0 -2
- package/dist/touch/index.d.mts +1 -1
- package/dist/touch/index.d.ts +1 -1
- package/dist/touch/index.js +0 -2
- package/dist/touch/index.mjs +0 -2
- package/dist/{types-cU43dEmH.d.mts → types-BzEgiUdJ.d.mts} +58 -9
- package/dist/{types-cU43dEmH.d.ts → types-BzEgiUdJ.d.ts} +58 -9
- package/dist/{useGesture-BnY65PlQ.d.ts → useGesture-BRLgiNOC.d.ts} +6 -4
- package/dist/{useGesture-DxtXdz-K.d.mts → useGesture-C0GBS7d2.d.mts} +6 -4
- package/llms.txt +9 -5
- package/package.json +2 -1
- package/src/config/MotionConfig.tsx +55 -9
- package/src/config/MotionConfigContext.ts +21 -1
- package/src/config/index.ts +7 -1
- package/src/config/namedTransitions.ts +80 -0
- package/src/gestureLayer/index.ts +1 -0
- package/src/gestureLayer/useGestureLayer.ts +92 -8
- package/src/index.ts +20 -2
- package/src/motion/createMotionComponent.tsx +36 -6
- package/src/transitions/cubicBezier.ts +126 -0
- package/src/transitions/index.ts +1 -0
- package/src/types.ts +63 -8
- package/src/values/useAnimation.ts +12 -6
- package/src/values/useBooleanSpring.ts +5 -3
- package/src/values/useGesture.ts +25 -7
- package/src/values/useMotionValue.ts +11 -0
- package/src/values/useScroll.ts +8 -1
- package/src/values/useSpring.ts +46 -9
- package/dist/gestureLayer/index.js.map +0 -1
- package/dist/gestureLayer/index.mjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/motion/Image.js.map +0 -1
- package/dist/motion/Image.mjs.map +0 -1
- package/dist/motion/Pressable.js.map +0 -1
- package/dist/motion/Pressable.mjs.map +0 -1
- package/dist/motion/ScrollView.js.map +0 -1
- package/dist/motion/ScrollView.mjs.map +0 -1
- package/dist/motion/Text.js.map +0 -1
- package/dist/motion/Text.mjs.map +0 -1
- package/dist/motion/View.js.map +0 -1
- package/dist/motion/View.mjs.map +0 -1
- package/dist/testing/index.js.map +0 -1
- package/dist/testing/index.mjs.map +0 -1
- package/dist/touch/index.js.map +0 -1
- package/dist/touch/index.mjs.map +0 -1
- package/src/__type-tests__/animate.test-d.tsx +0 -88
- package/src/__type-tests__/variants.test-d.tsx +0 -67
|
@@ -60,6 +60,51 @@ interface NoAnimationTransition {
|
|
|
60
60
|
type: 'no-animation';
|
|
61
61
|
}
|
|
62
62
|
type TransitionConfig = SpringTransition | TimingTransition | DecayTransition | NoAnimationTransition;
|
|
63
|
+
/**
|
|
64
|
+
* Augmentation point for typed named transitions. Empty by default — the
|
|
65
|
+
* registry is data fed to `<MotionConfig transitions={...}>` at runtime, so
|
|
66
|
+
* out of the box any string is accepted wherever a `TransitionName` is.
|
|
67
|
+
*
|
|
68
|
+
* Consumers who want their registered names to autocomplete (and typos to be
|
|
69
|
+
* compile errors) augment this interface with their design system's names:
|
|
70
|
+
*
|
|
71
|
+
* ```ts
|
|
72
|
+
* declare module '@rootnative/inertia' {
|
|
73
|
+
* interface RegisteredTransitions {
|
|
74
|
+
* 'state-hover': TransitionConfig
|
|
75
|
+
* 'selection': TransitionConfig
|
|
76
|
+
* }
|
|
77
|
+
* }
|
|
78
|
+
* ```
|
|
79
|
+
*
|
|
80
|
+
* The value type is ignored — only the keys matter. Inertia itself never
|
|
81
|
+
* declares a name here: presets are consumer data, not library surface.
|
|
82
|
+
*/
|
|
83
|
+
interface RegisteredTransitions {
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* A named transition registered on the nearest `<MotionConfig transitions>`.
|
|
87
|
+
* Accepted anywhere a `TransitionConfig` is: the `transition` prop (top-level
|
|
88
|
+
* and per-property), the `layout` prop, and the value-layer hooks. Resolution
|
|
89
|
+
* happens on the JS thread against the nearest provider; unknown names warn
|
|
90
|
+
* in dev and fall back to the library default spring.
|
|
91
|
+
*
|
|
92
|
+
* Plain `string` until `RegisteredTransitions` is augmented; with an
|
|
93
|
+
* augmentation in place it narrows to the registered keys.
|
|
94
|
+
*/
|
|
95
|
+
type TransitionName = keyof RegisteredTransitions extends never ? string : keyof RegisteredTransitions & string;
|
|
96
|
+
/**
|
|
97
|
+
* The registry shape accepted by `<MotionConfig transitions={...}>`: named
|
|
98
|
+
* `TransitionConfig`s. Names are consumer vocabulary (design tokens, semantic
|
|
99
|
+
* roles); Inertia ships no presets.
|
|
100
|
+
*/
|
|
101
|
+
type NamedTransitions = Partial<Record<TransitionName, TransitionConfig>>;
|
|
102
|
+
/**
|
|
103
|
+
* A transition given either inline (`TransitionConfig`) or by registered name
|
|
104
|
+
* (`TransitionName`). This is the input type everywhere the public surface
|
|
105
|
+
* accepts a single transition.
|
|
106
|
+
*/
|
|
107
|
+
type TransitionInput = TransitionConfig | TransitionName;
|
|
63
108
|
/**
|
|
64
109
|
* Repeat config — one shape, not three flags. Default `alternate: true`.
|
|
65
110
|
*/
|
|
@@ -73,7 +118,7 @@ type RepeatConfig = number | 'infinite' | {
|
|
|
73
118
|
* here.
|
|
74
119
|
*/
|
|
75
120
|
type PerPropertyTransition<S> = {
|
|
76
|
-
[K in keyof S]?:
|
|
121
|
+
[K in keyof S]?: TransitionInput;
|
|
77
122
|
};
|
|
78
123
|
/**
|
|
79
124
|
* Per-gesture-layer transition map. Each `gesture` sub-state animates a
|
|
@@ -85,12 +130,12 @@ type PerPropertyTransition<S> = {
|
|
|
85
130
|
* collide with the primitive's inferred style keys.
|
|
86
131
|
*/
|
|
87
132
|
interface GestureLayerTransitions {
|
|
88
|
-
pressed?:
|
|
89
|
-
focused?:
|
|
90
|
-
focusVisible?:
|
|
91
|
-
hovered?:
|
|
133
|
+
pressed?: TransitionInput;
|
|
134
|
+
focused?: TransitionInput;
|
|
135
|
+
focusVisible?: TransitionInput;
|
|
136
|
+
hovered?: TransitionInput;
|
|
92
137
|
}
|
|
93
|
-
type Transition<S> =
|
|
138
|
+
type Transition<S> = TransitionInput | (PerPropertyTransition<S> & GestureLayerTransitions);
|
|
94
139
|
/**
|
|
95
140
|
* Transform shorthands that Inertia exposes on `animate` but that don't
|
|
96
141
|
* appear on RN's typed ViewStyle as top-level keys. RN keeps `scale`,
|
|
@@ -259,7 +304,9 @@ interface MotionProps<C, V extends VariantsMap<C> = VariantsMap<C>> {
|
|
|
259
304
|
gesture?: GestureSubStates<C>;
|
|
260
305
|
/**
|
|
261
306
|
* Per-property or top-level transition config. Per-property entries take
|
|
262
|
-
* precedence over the top-level transition.
|
|
307
|
+
* precedence over the top-level transition. Anywhere a config object is
|
|
308
|
+
* accepted (top-level, per-property, per gesture layer) a `TransitionName`
|
|
309
|
+
* registered on the nearest `<MotionConfig transitions>` is accepted too.
|
|
263
310
|
*/
|
|
264
311
|
transition?: Transition<AnimateStyle<C>>;
|
|
265
312
|
/**
|
|
@@ -271,6 +318,8 @@ interface MotionProps<C, V extends VariantsMap<C> = VariantsMap<C>> {
|
|
|
271
318
|
* - `true` — animate with the library's default spring.
|
|
272
319
|
* - `TransitionConfig` — spring (react-spring vocab) or timing config; the
|
|
273
320
|
* resolver bridges to Reanimated's `LinearTransition` builder.
|
|
321
|
+
* - `TransitionName` — a name registered on the nearest
|
|
322
|
+
* `<MotionConfig transitions>`.
|
|
274
323
|
* - omitted / `false` — no layout animation (default).
|
|
275
324
|
*
|
|
276
325
|
* Only `'spring'` / `'timing'` / `'no-animation'` map to layout transitions
|
|
@@ -282,7 +331,7 @@ interface MotionProps<C, V extends VariantsMap<C> = VariantsMap<C>> {
|
|
|
282
331
|
* own layout changes, `layoutId` animates from a different element's
|
|
283
332
|
* last measured rect to this element's current rect.
|
|
284
333
|
*/
|
|
285
|
-
layout?: boolean |
|
|
334
|
+
layout?: boolean | TransitionInput;
|
|
286
335
|
/**
|
|
287
336
|
* Shared-element transition id. When a Motion primitive with `layoutId`
|
|
288
337
|
* unmounts, its last on-screen rect is recorded under that id; the next
|
|
@@ -336,4 +385,4 @@ interface MotionComponent<C extends ComponentType<any>> {
|
|
|
336
385
|
displayName?: string;
|
|
337
386
|
}
|
|
338
387
|
|
|
339
|
-
export type { AnimatableValue as A, DecayTransition as D, EasingInput as E, GestureSubStates as G, MotionComponent as M,
|
|
388
|
+
export type { AnimatableValue as A, DecayTransition as D, EasingInput as E, GestureSubStates as G, MotionComponent as M, NamedTransitions as N, PerPropertyTransition as P, RegisteredTransitions as R, SpringTransition as S, TransitionInput as T, VariantController as V, TransitionConfig as a, TransitionName as b, AnimateStyle as c, AnimationCallbackInfo as d, EasingFunction as e, EasingFunctionFactory as f, MotionProps as g, NoAnimationTransition as h, RepeatConfig as i, SequenceStep as j, TimingTransition as k, Transition as l, VariantsMap as m, GestureLayerTransitions as n };
|
|
@@ -60,6 +60,51 @@ interface NoAnimationTransition {
|
|
|
60
60
|
type: 'no-animation';
|
|
61
61
|
}
|
|
62
62
|
type TransitionConfig = SpringTransition | TimingTransition | DecayTransition | NoAnimationTransition;
|
|
63
|
+
/**
|
|
64
|
+
* Augmentation point for typed named transitions. Empty by default — the
|
|
65
|
+
* registry is data fed to `<MotionConfig transitions={...}>` at runtime, so
|
|
66
|
+
* out of the box any string is accepted wherever a `TransitionName` is.
|
|
67
|
+
*
|
|
68
|
+
* Consumers who want their registered names to autocomplete (and typos to be
|
|
69
|
+
* compile errors) augment this interface with their design system's names:
|
|
70
|
+
*
|
|
71
|
+
* ```ts
|
|
72
|
+
* declare module '@rootnative/inertia' {
|
|
73
|
+
* interface RegisteredTransitions {
|
|
74
|
+
* 'state-hover': TransitionConfig
|
|
75
|
+
* 'selection': TransitionConfig
|
|
76
|
+
* }
|
|
77
|
+
* }
|
|
78
|
+
* ```
|
|
79
|
+
*
|
|
80
|
+
* The value type is ignored — only the keys matter. Inertia itself never
|
|
81
|
+
* declares a name here: presets are consumer data, not library surface.
|
|
82
|
+
*/
|
|
83
|
+
interface RegisteredTransitions {
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* A named transition registered on the nearest `<MotionConfig transitions>`.
|
|
87
|
+
* Accepted anywhere a `TransitionConfig` is: the `transition` prop (top-level
|
|
88
|
+
* and per-property), the `layout` prop, and the value-layer hooks. Resolution
|
|
89
|
+
* happens on the JS thread against the nearest provider; unknown names warn
|
|
90
|
+
* in dev and fall back to the library default spring.
|
|
91
|
+
*
|
|
92
|
+
* Plain `string` until `RegisteredTransitions` is augmented; with an
|
|
93
|
+
* augmentation in place it narrows to the registered keys.
|
|
94
|
+
*/
|
|
95
|
+
type TransitionName = keyof RegisteredTransitions extends never ? string : keyof RegisteredTransitions & string;
|
|
96
|
+
/**
|
|
97
|
+
* The registry shape accepted by `<MotionConfig transitions={...}>`: named
|
|
98
|
+
* `TransitionConfig`s. Names are consumer vocabulary (design tokens, semantic
|
|
99
|
+
* roles); Inertia ships no presets.
|
|
100
|
+
*/
|
|
101
|
+
type NamedTransitions = Partial<Record<TransitionName, TransitionConfig>>;
|
|
102
|
+
/**
|
|
103
|
+
* A transition given either inline (`TransitionConfig`) or by registered name
|
|
104
|
+
* (`TransitionName`). This is the input type everywhere the public surface
|
|
105
|
+
* accepts a single transition.
|
|
106
|
+
*/
|
|
107
|
+
type TransitionInput = TransitionConfig | TransitionName;
|
|
63
108
|
/**
|
|
64
109
|
* Repeat config — one shape, not three flags. Default `alternate: true`.
|
|
65
110
|
*/
|
|
@@ -73,7 +118,7 @@ type RepeatConfig = number | 'infinite' | {
|
|
|
73
118
|
* here.
|
|
74
119
|
*/
|
|
75
120
|
type PerPropertyTransition<S> = {
|
|
76
|
-
[K in keyof S]?:
|
|
121
|
+
[K in keyof S]?: TransitionInput;
|
|
77
122
|
};
|
|
78
123
|
/**
|
|
79
124
|
* Per-gesture-layer transition map. Each `gesture` sub-state animates a
|
|
@@ -85,12 +130,12 @@ type PerPropertyTransition<S> = {
|
|
|
85
130
|
* collide with the primitive's inferred style keys.
|
|
86
131
|
*/
|
|
87
132
|
interface GestureLayerTransitions {
|
|
88
|
-
pressed?:
|
|
89
|
-
focused?:
|
|
90
|
-
focusVisible?:
|
|
91
|
-
hovered?:
|
|
133
|
+
pressed?: TransitionInput;
|
|
134
|
+
focused?: TransitionInput;
|
|
135
|
+
focusVisible?: TransitionInput;
|
|
136
|
+
hovered?: TransitionInput;
|
|
92
137
|
}
|
|
93
|
-
type Transition<S> =
|
|
138
|
+
type Transition<S> = TransitionInput | (PerPropertyTransition<S> & GestureLayerTransitions);
|
|
94
139
|
/**
|
|
95
140
|
* Transform shorthands that Inertia exposes on `animate` but that don't
|
|
96
141
|
* appear on RN's typed ViewStyle as top-level keys. RN keeps `scale`,
|
|
@@ -259,7 +304,9 @@ interface MotionProps<C, V extends VariantsMap<C> = VariantsMap<C>> {
|
|
|
259
304
|
gesture?: GestureSubStates<C>;
|
|
260
305
|
/**
|
|
261
306
|
* Per-property or top-level transition config. Per-property entries take
|
|
262
|
-
* precedence over the top-level transition.
|
|
307
|
+
* precedence over the top-level transition. Anywhere a config object is
|
|
308
|
+
* accepted (top-level, per-property, per gesture layer) a `TransitionName`
|
|
309
|
+
* registered on the nearest `<MotionConfig transitions>` is accepted too.
|
|
263
310
|
*/
|
|
264
311
|
transition?: Transition<AnimateStyle<C>>;
|
|
265
312
|
/**
|
|
@@ -271,6 +318,8 @@ interface MotionProps<C, V extends VariantsMap<C> = VariantsMap<C>> {
|
|
|
271
318
|
* - `true` — animate with the library's default spring.
|
|
272
319
|
* - `TransitionConfig` — spring (react-spring vocab) or timing config; the
|
|
273
320
|
* resolver bridges to Reanimated's `LinearTransition` builder.
|
|
321
|
+
* - `TransitionName` — a name registered on the nearest
|
|
322
|
+
* `<MotionConfig transitions>`.
|
|
274
323
|
* - omitted / `false` — no layout animation (default).
|
|
275
324
|
*
|
|
276
325
|
* Only `'spring'` / `'timing'` / `'no-animation'` map to layout transitions
|
|
@@ -282,7 +331,7 @@ interface MotionProps<C, V extends VariantsMap<C> = VariantsMap<C>> {
|
|
|
282
331
|
* own layout changes, `layoutId` animates from a different element's
|
|
283
332
|
* last measured rect to this element's current rect.
|
|
284
333
|
*/
|
|
285
|
-
layout?: boolean |
|
|
334
|
+
layout?: boolean | TransitionInput;
|
|
286
335
|
/**
|
|
287
336
|
* Shared-element transition id. When a Motion primitive with `layoutId`
|
|
288
337
|
* unmounts, its last on-screen rect is recorded under that id; the next
|
|
@@ -336,4 +385,4 @@ interface MotionComponent<C extends ComponentType<any>> {
|
|
|
336
385
|
displayName?: string;
|
|
337
386
|
}
|
|
338
387
|
|
|
339
|
-
export type { AnimatableValue as A, DecayTransition as D, EasingInput as E, GestureSubStates as G, MotionComponent as M,
|
|
388
|
+
export type { AnimatableValue as A, DecayTransition as D, EasingInput as E, GestureSubStates as G, MotionComponent as M, NamedTransitions as N, PerPropertyTransition as P, RegisteredTransitions as R, SpringTransition as S, TransitionInput as T, VariantController as V, TransitionConfig as a, TransitionName as b, AnimateStyle as c, AnimationCallbackInfo as d, EasingFunction as e, EasingFunctionFactory as f, MotionProps as g, NoAnimationTransition as h, RepeatConfig as i, SequenceStep as j, TimingTransition as k, Transition as l, VariantsMap as m, GestureLayerTransitions as n };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SharedValue } from 'react-native-reanimated';
|
|
2
|
-
import { T as
|
|
2
|
+
import { T as TransitionInput, n as GestureLayerTransitions } from './types-BzEgiUdJ.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Handler bag returned by `useGesture`. Spread on a `Pressable` to drive the
|
|
@@ -42,8 +42,10 @@ interface UseGestureResult {
|
|
|
42
42
|
*
|
|
43
43
|
* Transitions follow the same shape as the `gesture` prop's accompanying
|
|
44
44
|
* `transition`: pass a single `TransitionConfig` to use for every layer, or a
|
|
45
|
-
* `GestureLayerTransitions` map to give each layer its own.
|
|
46
|
-
*
|
|
45
|
+
* `GestureLayerTransitions` map to give each layer its own. A `TransitionName`
|
|
46
|
+
* registered on the nearest `<MotionConfig transitions>` is accepted in both
|
|
47
|
+
* positions (top-level and per-layer). Layers without an explicit transition
|
|
48
|
+
* fall back to the library default spring.
|
|
47
49
|
*
|
|
48
50
|
* Reduced motion (via `<MotionConfig reducedMotion>`) collapses every
|
|
49
51
|
* transition to `no-animation` so state changes snap instead of interpolating
|
|
@@ -79,6 +81,6 @@ interface UseGestureResult {
|
|
|
79
81
|
* }
|
|
80
82
|
* ```
|
|
81
83
|
*/
|
|
82
|
-
declare function useGesture(transition?:
|
|
84
|
+
declare function useGesture(transition?: TransitionInput | GestureLayerTransitions): UseGestureResult;
|
|
83
85
|
|
|
84
86
|
export { type UseGestureHandlers as U, type UseGestureResult as a, useGesture as u };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SharedValue } from 'react-native-reanimated';
|
|
2
|
-
import { T as
|
|
2
|
+
import { T as TransitionInput, n as GestureLayerTransitions } from './types-BzEgiUdJ.mjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Handler bag returned by `useGesture`. Spread on a `Pressable` to drive the
|
|
@@ -42,8 +42,10 @@ interface UseGestureResult {
|
|
|
42
42
|
*
|
|
43
43
|
* Transitions follow the same shape as the `gesture` prop's accompanying
|
|
44
44
|
* `transition`: pass a single `TransitionConfig` to use for every layer, or a
|
|
45
|
-
* `GestureLayerTransitions` map to give each layer its own.
|
|
46
|
-
*
|
|
45
|
+
* `GestureLayerTransitions` map to give each layer its own. A `TransitionName`
|
|
46
|
+
* registered on the nearest `<MotionConfig transitions>` is accepted in both
|
|
47
|
+
* positions (top-level and per-layer). Layers without an explicit transition
|
|
48
|
+
* fall back to the library default spring.
|
|
47
49
|
*
|
|
48
50
|
* Reduced motion (via `<MotionConfig reducedMotion>`) collapses every
|
|
49
51
|
* transition to `no-animation` so state changes snap instead of interpolating
|
|
@@ -79,6 +81,6 @@ interface UseGestureResult {
|
|
|
79
81
|
* }
|
|
80
82
|
* ```
|
|
81
83
|
*/
|
|
82
|
-
declare function useGesture(transition?:
|
|
84
|
+
declare function useGesture(transition?: TransitionInput | GestureLayerTransitions): UseGestureResult;
|
|
83
85
|
|
|
84
86
|
export { type UseGestureHandlers as U, type UseGestureResult as a, useGesture as u };
|
package/llms.txt
CHANGED
|
@@ -42,13 +42,13 @@ import { MotionScrollView } from '@rootnative/inertia/scroll-view'
|
|
|
42
42
|
|
|
43
43
|
- `Motion.View` / `Motion.Text` / `Motion.Image` / `Motion.Pressable` / `Motion.ScrollView` — animatable primitives. Per-primitive style inference (no shared `ViewStyle & TextStyle & ImageStyle` fallback).
|
|
44
44
|
- `<Presence>` — mount / unmount transitions; children need explicit `key`s. Exiting children get `pointerEvents: 'none'` automatically.
|
|
45
|
-
- `<MotionConfig reducedMotion="user" | "never" | "always">` — gates motion against the OS reduce-motion setting (default `"user"`).
|
|
45
|
+
- `<MotionConfig reducedMotion="user" | "never" | "always" transitions={{ name: TransitionConfig }}>` — gates motion against the OS reduce-motion setting (default `"user"`) and registers named transitions for the subtree. A registered name is accepted anywhere a `TransitionConfig` is: the `transition` prop (top-level and per-property/per-layer), the `layout` prop, and the value-layer hooks (`transition="selection"`, `useBooleanSpring(checked, 'selection')`). Nested providers merge (child overrides per name); unknown names warn in dev and fall back to the default spring. Names are consumer vocabulary — no presets ship with the library. Optional compile-time narrowing via `declare module '@rootnative/inertia' { interface RegisteredTransitions { ... } }`. Custom components join the registry with `useNamedTransitions()` + `resolveNamedTransition(input, registry)`.
|
|
46
46
|
- `useGesture(transition?)` — hook-form of the `gesture` prop. Returns 0↔1 progress shared values (`pressed`, `focused`, `focusVisible`, `hovered`) plus a `handlers` bag to spread on a `Pressable`. Use when one gesture needs to drive multiple animated siblings (focus rings, MD3 state-layer halos, multi-element compositions).
|
|
47
|
-
- `useGestureLayer(states, options?)` — opt-in helper at `@rootnative/inertia/gesture-layer` for the **strongest-active-layer-wins** composition (MD3 state-layer haloes, iOS-translucent overlays). Supply per-state target maps (`rest` / `hovered` / `focused` / `focusVisible` / `pressed` / `disabled`); the hook owns the worklet. Numeric keys compose via clamped-max with `rest` as the floor; color keys compose via priority cascade with `interpolateColor`; `disabled` (JS-side flag) overrides every gesture layer. Returns `{ style, handlers }
|
|
47
|
+
- `useGestureLayer(states, options?)` — opt-in helper at `@rootnative/inertia/gesture-layer` for the **strongest-active-layer-wins** composition (MD3 state-layer haloes, iOS-translucent overlays). Supply per-state target maps (`rest` / `hovered` / `focused` / `focusVisible` / `pressed` / `disabled`); the hook owns the worklet. Numeric keys compose via clamped-max with `rest` as the floor; color keys compose via priority cascade with `interpolateColor`; `disabled` (JS-side flag) overrides every gesture layer. Returns `{ style, handlers, states }` — `states` is the per-state 0↔1 progress shared values (`hovered` / `focused` / `focusVisible` / `pressed` / `disabled`) behind the composed style, for deriving extra styles (e.g. `useShadow({ progress: states.hovered })`) from the same gesture wiring. Reach for plain `useGesture` for additive blends or per-key custom rules.
|
|
48
48
|
- `useVariants(variants, initial?)` — returns `{ current, transitionTo }` controller for the `controller` prop.
|
|
49
49
|
- `useMotionValue(initial)` — thin pass-through over `useSharedValue<T>`. Returns a `SharedValue<T>` directly so it interops with every Reanimated API without unwrapping.
|
|
50
|
-
- `useAnimation(target, transition?)` — drive a `SharedValue<number>` toward `target` with any `TransitionConfig` (spring / timing / decay / no-animation, plus `repeat`)
|
|
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.
|
|
50
|
+
- `useAnimation(target, transition?)` — drive a `SharedValue<number>` toward `target` with any `TransitionConfig` (spring / timing / decay / no-animation, plus `repeat`) or a registered `TransitionName`. The general-purpose value-layer hook for boolean-state progress, indeterminate loops, and anywhere the same value needs to feed multiple `useAnimatedStyle` blocks.
|
|
51
|
+
- `useSpring(target, config?)` — spring-only shorthand. Animates a `SharedValue<number>` toward `target` with react-spring vocab (or a spring-typed registered `TransitionName`; non-spring names warn and fall back to the default spring). `target` may be a plain number (effect-driven) or a `SharedValue<number>` (UI-thread reaction); the latter is the gesture-smoothing path.
|
|
52
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.
|
|
53
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
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.
|
|
@@ -56,6 +56,10 @@ import { MotionScrollView } from '@rootnative/inertia/scroll-view'
|
|
|
56
56
|
- `useScroll()` — returns `{ scrollX, scrollY, onScroll }` for use with `Motion.ScrollView`. Scroll events fire on the UI thread.
|
|
57
57
|
- `createMotionComponent<C>(C)` — wrap any component with the same Motion prop surface, inferring style from `C`.
|
|
58
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 `@rootnative/inertia-gestures`'s `useDrag({ onRelease })`.
|
|
59
|
+
- `resolveTransition(config, toValue, callback?)` — JS-thread resolver: bakes a `TransitionConfig` + target into a Reanimated animation (`withSpring` / `withTiming` / `withDecay`, plus `delay` / `repeat` wrapping) ready to assign to a shared value. The building block for custom animated components that accept Inertia's `transition` shape; this is what the gradient and SVG adapter packages use.
|
|
60
|
+
- `resolveAnimatableValue(value, base, factory?)` — one level up: resolves a full per-property `animate` value (plain target, `{ to, ...override }` step, or keyframe array → `withSequence` with sequence-level `repeat`) into one animation. Gives custom components the complete `animate` grammar.
|
|
61
|
+
- `cubicBezier(x1, y1, x2, y2)` / `cubicBezier(css)` — builds a `timing.easing` value from cubic-bezier control points: four numbers, a W3C CSS `cubic-bezier(0.2, 0, 0, 1)` string (design-token form), or a CSS keyword (`'linear'` | `'ease'` | `'ease-in'` | `'ease-out'` | `'ease-in-out'`). Makes CSS-format easing tokens directly consumable — pair with named transitions to feed a theme's motion tokens into the registry. Invalid input throws (`x1`/`x2` must be within [0, 1]; `step-*` and `linear(...)` unsupported).
|
|
62
|
+
- `ensureWorkletEasing(easing)` — normalizes any accepted easing input (plain function, worklet, or Reanimated 4 `EasingFunctionFactory`) into a worklet `withTiming` can consume. Only needed for manual `withTiming` calls — the resolvers and primitives apply it automatically.
|
|
59
63
|
|
|
60
64
|
## Motion props
|
|
61
65
|
|
|
@@ -132,7 +136,7 @@ Auto-layout transitions ship via the `layout` prop (`true` / `TransitionConfig`)
|
|
|
132
136
|
## Optional adapter packages
|
|
133
137
|
|
|
134
138
|
- `@rootnative/inertia-gradients` — `MotionLinearGradient` over `expo-linear-gradient`. Animatable: `colors`, `start`, `end`, `locations`.
|
|
135
|
-
- `@rootnative/inertia-svg` —
|
|
139
|
+
- `@rootnative/inertia-svg` — animatable SVG primitives over `react-native-svg`, all under the `MotionSvg` namespace (`MotionSvg.Path` / `.Circle` / `.Rect` / `.Line`) or as direct imports. `MotionPath` animates `d` (path morphing on structurally-compatible paths — same command sequence after implicit-repeat expansion; remount with `key` to switch shape), `fill`, `stroke`, `strokeWidth`, opacities, `strokeDashoffset`. `MotionCircle` / `MotionRect` / `MotionLine` animate their geometry props, paints, and `strokeDasharray` (element-wise; array length locked at mount). `createMotionSvgComponent(Component, { animatableProps, colorProps, arrayProps })` — the factory behind the prebuilt shapes — wraps any other `react-native-svg` element with the same `initial` / `animate` / `transition` surface; `transition` accepts named transitions from the nearest `<MotionConfig transitions>` (top-level and per-property).
|
|
136
140
|
- `@rootnative/inertia-gestures` — `useDrag`, `useSwipe`, `usePan` over `react-native-gesture-handler`. `useDrag` accepts an `onRelease` worklet that returns per-axis Inertia release transitions (snap-to-tick spring, decay with bounds, etc.) — the release velocity stays on the UI thread, no JS round-trip.
|
|
137
141
|
|
|
138
142
|
## Docs
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rootnative/inertia",
|
|
3
|
-
"version": "0.0.0-alpha.
|
|
3
|
+
"version": "0.0.0-alpha.2",
|
|
4
4
|
"description": "Declarative animation primitives for React Native, built on react-native-reanimated.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "RootNative",
|
|
@@ -107,6 +107,7 @@
|
|
|
107
107
|
"LICENSE",
|
|
108
108
|
"CHANGELOG.md",
|
|
109
109
|
"!**/__tests__",
|
|
110
|
+
"!**/__type-tests__",
|
|
110
111
|
"!**/*.test.*"
|
|
111
112
|
],
|
|
112
113
|
"peerDependencies": {
|
|
@@ -1,26 +1,72 @@
|
|
|
1
1
|
import { type ReactNode, useMemo } from 'react'
|
|
2
|
+
import { stableSig } from '../transitions/sig'
|
|
3
|
+
import { type NamedTransitions } from '../types'
|
|
2
4
|
import {
|
|
3
5
|
MotionConfigContext,
|
|
4
6
|
type MotionConfigValue,
|
|
5
7
|
type ReducedMotion,
|
|
8
|
+
useMotionConfig,
|
|
6
9
|
} from './MotionConfigContext'
|
|
7
10
|
|
|
11
|
+
export interface MotionConfigProps {
|
|
12
|
+
/**
|
|
13
|
+
* How descendants respond to reduced-motion preferences. Inherits from the
|
|
14
|
+
* nearest ancestor `<MotionConfig>` when omitted (the root default is
|
|
15
|
+
* `'user'` — respect the OS accessibility setting).
|
|
16
|
+
*/
|
|
17
|
+
reducedMotion?: ReducedMotion
|
|
18
|
+
/**
|
|
19
|
+
* Named transitions available to every descendant wherever a
|
|
20
|
+
* `TransitionConfig` is accepted — the `transition` prop (top-level and
|
|
21
|
+
* per-property), the `layout` prop, and the value-layer hooks:
|
|
22
|
+
*
|
|
23
|
+
* ```tsx
|
|
24
|
+
* <MotionConfig
|
|
25
|
+
* transitions={{
|
|
26
|
+
* 'state-press': { type: 'timing', duration: 100 },
|
|
27
|
+
* selection: { type: 'spring', tension: 380, friction: 33 },
|
|
28
|
+
* }}
|
|
29
|
+
* >
|
|
30
|
+
* <Motion.View animate={{ scale: 1 }} transition="selection" />
|
|
31
|
+
* </MotionConfig>
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* Names resolve at the nearest provider; nested providers merge with the
|
|
35
|
+
* ancestor registry, child entries overriding same-named ancestor entries.
|
|
36
|
+
* Unknown names warn in dev and fall back to the library default spring.
|
|
37
|
+
* Names are consumer vocabulary — Inertia ships no presets.
|
|
38
|
+
*/
|
|
39
|
+
transitions?: NamedTransitions
|
|
40
|
+
children: ReactNode
|
|
41
|
+
}
|
|
42
|
+
|
|
8
43
|
/**
|
|
9
|
-
* Provider
|
|
10
|
-
*
|
|
44
|
+
* Provider for subtree-wide animation config: reduced-motion behaviour and
|
|
45
|
+
* the named-transition registry. Wrap the root of your app once with the
|
|
11
46
|
* default (`reducedMotion="user"`) to respect the OS accessibility setting,
|
|
12
47
|
* or scope a subtree with `'always'` / `'never'` for specific use cases.
|
|
48
|
+
* Nested providers inherit from their ancestor: an omitted prop keeps the
|
|
49
|
+
* ancestor's value, and `transitions` maps merge per name (child wins).
|
|
13
50
|
*/
|
|
14
51
|
export function MotionConfig({
|
|
15
|
-
reducedMotion
|
|
52
|
+
reducedMotion,
|
|
53
|
+
transitions,
|
|
16
54
|
children,
|
|
17
|
-
}: {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
55
|
+
}: MotionConfigProps) {
|
|
56
|
+
const parent = useMotionConfig()
|
|
57
|
+
// Keyed on the structural signature, not object identity — consumers
|
|
58
|
+
// routinely pass a fresh `transitions={{ ... }}` literal each render and
|
|
59
|
+
// must not re-render every Motion descendant for it.
|
|
60
|
+
const transitionsSig = stableSig(transitions)
|
|
21
61
|
const value = useMemo<MotionConfigValue>(
|
|
22
|
-
() => ({
|
|
23
|
-
|
|
62
|
+
() => ({
|
|
63
|
+
reducedMotion: reducedMotion ?? parent.reducedMotion,
|
|
64
|
+
transitions: transitions
|
|
65
|
+
? { ...parent.transitions, ...transitions }
|
|
66
|
+
: parent.transitions,
|
|
67
|
+
}),
|
|
68
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
69
|
+
[reducedMotion, transitionsSig, parent],
|
|
24
70
|
)
|
|
25
71
|
return (
|
|
26
72
|
<MotionConfigContext.Provider value={value}>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createContext, useContext } from 'react'
|
|
2
2
|
import { useReducedMotion } from 'react-native-reanimated'
|
|
3
|
+
import { type NamedTransitions } from '../types'
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* How descendant Motion primitives should treat reduced-motion preferences.
|
|
@@ -16,14 +17,22 @@ export type ReducedMotion = 'user' | 'never' | 'always'
|
|
|
16
17
|
|
|
17
18
|
export interface MotionConfigValue {
|
|
18
19
|
reducedMotion: ReducedMotion
|
|
20
|
+
/**
|
|
21
|
+
* Named transitions registered by ancestor `<MotionConfig transitions>`
|
|
22
|
+
* providers, already merged (nearest provider wins per name). Empty with no
|
|
23
|
+
* provider — every name then resolves to the unknown-name fallback.
|
|
24
|
+
*/
|
|
25
|
+
transitions: NamedTransitions
|
|
19
26
|
}
|
|
20
27
|
|
|
21
28
|
/**
|
|
22
29
|
* Default config used when a Motion primitive is rendered without a
|
|
23
|
-
* `<MotionConfig>` ancestor. `'user'` means respect the OS setting
|
|
30
|
+
* `<MotionConfig>` ancestor. `'user'` means respect the OS setting; no
|
|
31
|
+
* transitions are registered.
|
|
24
32
|
*/
|
|
25
33
|
export const DEFAULT_MOTION_CONFIG: MotionConfigValue = {
|
|
26
34
|
reducedMotion: 'user',
|
|
35
|
+
transitions: {},
|
|
27
36
|
}
|
|
28
37
|
|
|
29
38
|
export const MotionConfigContext = createContext<MotionConfigValue>(
|
|
@@ -44,6 +53,17 @@ export function useMotionConfig(): MotionConfigValue {
|
|
|
44
53
|
* primitives call this to decide whether to swap transitions for
|
|
45
54
|
* `no-animation`.
|
|
46
55
|
*/
|
|
56
|
+
/**
|
|
57
|
+
* Read the merged named-transition registry from the nearest `<MotionConfig>`
|
|
58
|
+
* ancestors. This is what the Motion primitives and value-layer hooks consult
|
|
59
|
+
* when a `TransitionName` string is passed where a `TransitionConfig` is
|
|
60
|
+
* accepted; custom animated components (and adapter packages) use it together
|
|
61
|
+
* with `resolveNamedTransition` to support names on their own surface.
|
|
62
|
+
*/
|
|
63
|
+
export function useNamedTransitions(): NamedTransitions {
|
|
64
|
+
return useMotionConfig().transitions
|
|
65
|
+
}
|
|
66
|
+
|
|
47
67
|
export function useShouldReduceMotion(): boolean {
|
|
48
68
|
const { reducedMotion } = useMotionConfig()
|
|
49
69
|
const osReduced = useReducedMotion()
|
package/src/config/index.ts
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
export { MotionConfig } from './MotionConfig'
|
|
1
|
+
export { MotionConfig, type MotionConfigProps } from './MotionConfig'
|
|
2
2
|
export {
|
|
3
3
|
MotionConfigContext,
|
|
4
4
|
DEFAULT_MOTION_CONFIG,
|
|
5
5
|
useMotionConfig,
|
|
6
|
+
useNamedTransitions,
|
|
6
7
|
useShouldReduceMotion,
|
|
7
8
|
type MotionConfigValue,
|
|
8
9
|
type ReducedMotion,
|
|
9
10
|
} from './MotionConfigContext'
|
|
11
|
+
export {
|
|
12
|
+
lookupNamedTransition,
|
|
13
|
+
resolveNamedTransition,
|
|
14
|
+
resolveNamedTransitionProp,
|
|
15
|
+
} from './namedTransitions'
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { isTopLevelTransition } from '../transitions/keys'
|
|
2
|
+
import {
|
|
3
|
+
type NamedTransitions,
|
|
4
|
+
type Transition,
|
|
5
|
+
type TransitionConfig,
|
|
6
|
+
type TransitionInput,
|
|
7
|
+
} from '../types'
|
|
8
|
+
|
|
9
|
+
declare const __DEV__: boolean
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Fallback used when a name isn't found in the registry: the library default
|
|
13
|
+
* spring, matching what an omitted transition resolves to everywhere else.
|
|
14
|
+
*/
|
|
15
|
+
const UNKNOWN_NAME_FALLBACK: TransitionConfig = { type: 'spring' }
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Look a registered transition name up in a registry. Unknown names warn in
|
|
19
|
+
* dev and fall back to the library default spring — the animation still runs,
|
|
20
|
+
* it just isn't the one the token intended, which is the same failure
|
|
21
|
+
* softness the web platform gives an unknown CSS keyword.
|
|
22
|
+
*/
|
|
23
|
+
export function lookupNamedTransition(
|
|
24
|
+
name: string,
|
|
25
|
+
registry: NamedTransitions,
|
|
26
|
+
): TransitionConfig {
|
|
27
|
+
const cfg = registry[name]
|
|
28
|
+
if (cfg) return cfg
|
|
29
|
+
if (__DEV__) {
|
|
30
|
+
console.warn(
|
|
31
|
+
`[inertia] Unknown transition name "${name}" — falling back to the ` +
|
|
32
|
+
`default spring. Register it on a provider: ` +
|
|
33
|
+
`<MotionConfig transitions={{ '${name}': { ... } }}>.`,
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
return UNKNOWN_NAME_FALLBACK
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Resolve a single transition input — a `TransitionConfig` passes through
|
|
41
|
+
* untouched, a `TransitionName` is looked up in `registry`. This is the
|
|
42
|
+
* building block adapter packages use to accept names wherever they accept a
|
|
43
|
+
* config (pair it with `useNamedTransitions()` for the registry).
|
|
44
|
+
*/
|
|
45
|
+
export function resolveNamedTransition(
|
|
46
|
+
input: TransitionInput | undefined,
|
|
47
|
+
registry: NamedTransitions,
|
|
48
|
+
): TransitionConfig | undefined {
|
|
49
|
+
if (input === undefined) return undefined
|
|
50
|
+
if (typeof input === 'string') return lookupNamedTransition(input, registry)
|
|
51
|
+
return input
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Resolve every name inside a `transition` prop value — the top-level string
|
|
56
|
+
* form, and string values on the per-property / gesture-layer map form.
|
|
57
|
+
* Identity-preserving: when the input contains no names it is returned
|
|
58
|
+
* unchanged, so signature- and identity-keyed memoization downstream is
|
|
59
|
+
* unaffected for the config-object path.
|
|
60
|
+
*/
|
|
61
|
+
export function resolveNamedTransitionProp<S>(
|
|
62
|
+
transition: Transition<S> | undefined,
|
|
63
|
+
registry: NamedTransitions,
|
|
64
|
+
): Exclude<Transition<S>, string> | undefined {
|
|
65
|
+
if (transition === undefined) return undefined
|
|
66
|
+
if (typeof transition === 'string') {
|
|
67
|
+
return lookupNamedTransition(transition, registry)
|
|
68
|
+
}
|
|
69
|
+
if (isTopLevelTransition(transition)) return transition
|
|
70
|
+
const map = transition as Record<string, unknown>
|
|
71
|
+
let out: Record<string, unknown> | null = null
|
|
72
|
+
for (const key in map) {
|
|
73
|
+
const value = map[key]
|
|
74
|
+
if (typeof value === 'string') {
|
|
75
|
+
if (out === null) out = { ...map }
|
|
76
|
+
out[key] = lookupNamedTransition(value, registry)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return (out ?? transition) as Exclude<Transition<S>, string>
|
|
80
|
+
}
|