@onlynative/inertia 0.0.1-alpha.8 → 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.
- package/dist/gestureLayer/index.d.mts +2 -2
- package/dist/gestureLayer/index.d.ts +2 -2
- package/dist/gestureLayer/index.js +3 -1402
- package/dist/gestureLayer/index.js.map +1 -1
- package/dist/gestureLayer/index.mjs +3 -1402
- package/dist/gestureLayer/index.mjs.map +1 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +69 -1461
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +70 -1462
- 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 +68 -1460
- package/dist/motion/Image.js.map +1 -1
- package/dist/motion/Image.mjs +70 -1462
- 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 +68 -1460
- package/dist/motion/Pressable.js.map +1 -1
- package/dist/motion/Pressable.mjs +70 -1462
- 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 +68 -1460
- package/dist/motion/ScrollView.js.map +1 -1
- package/dist/motion/ScrollView.mjs +70 -1462
- 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 +68 -1460
- package/dist/motion/Text.js.map +1 -1
- package/dist/motion/Text.mjs +70 -1462
- 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 +68 -1460
- package/dist/motion/View.js.map +1 -1
- package/dist/motion/View.mjs +70 -1462
- package/dist/motion/View.mjs.map +1 -1
- package/dist/touch/index.d.mts +1 -1
- package/dist/touch/index.d.ts +1 -1
- package/dist/{types-BwyvoH2V.d.mts → types-cU43dEmH.d.mts} +42 -15
- package/dist/{types-BwyvoH2V.d.ts → types-cU43dEmH.d.ts} +42 -15
- package/dist/{useGesture-BPPp9LhV.d.ts → useGesture-B7A_1DVg.d.ts} +1 -1
- package/dist/{useGesture-BnBF4OtT.d.mts → useGesture-cimMrzC1.d.mts} +1 -1
- package/jest-setup.js +4 -0
- package/package.json +8 -2
- package/src/__type-tests__/variants.test-d.tsx +67 -0
- package/src/layout/sharedRegistry.ts +7 -4
- package/src/motion/createMotionComponent.tsx +63 -33
- package/src/motion/installCheck.ts +7 -11
- package/src/types.ts +58 -19
package/dist/touch/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PanResponderInstance } from 'react-native';
|
|
2
2
|
import { useAnimatedStyle, SharedValue } from 'react-native-reanimated';
|
|
3
|
-
import { T as TransitionConfig } from '../types-
|
|
3
|
+
import { T as TransitionConfig } from '../types-cU43dEmH.mjs';
|
|
4
4
|
import 'react';
|
|
5
5
|
|
|
6
6
|
/**
|
package/dist/touch/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PanResponderInstance } from 'react-native';
|
|
2
2
|
import { useAnimatedStyle, SharedValue } from 'react-native-reanimated';
|
|
3
|
-
import { T as TransitionConfig } from '../types-
|
|
3
|
+
import { T as TransitionConfig } from '../types-cU43dEmH.js';
|
|
4
4
|
import 'react';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -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.
|
|
226
|
-
*
|
|
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?:
|
|
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
|
|
@@ -282,8 +290,11 @@ interface MotionProps<C> {
|
|
|
282
290
|
* recorded rect to its natural position via a FLIP transform stack.
|
|
283
291
|
*
|
|
284
292
|
* Reanimated 4 removed the `sharedTransitionTag` API — `layoutId` is the
|
|
285
|
-
* Inertia-side measure-based replacement. Rects are
|
|
286
|
-
* coordinates
|
|
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.
|
|
287
298
|
*
|
|
288
299
|
* The same `transition` prop drives the FLIP animation (spring by
|
|
289
300
|
* default; `'timing'` honored; `'decay'` downgrades to spring; reduced
|
|
@@ -301,12 +312,28 @@ interface MotionProps<C> {
|
|
|
301
312
|
onAnimationEnd?: (info: AnimationCallbackInfo<AnimateStyle<C>>) => void;
|
|
302
313
|
}
|
|
303
314
|
/**
|
|
304
|
-
*
|
|
305
|
-
*
|
|
306
|
-
* animated style) with the Motion
|
|
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.
|
|
318
|
+
*/
|
|
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.
|
|
307
333
|
*/
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
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
|
+
}
|
|
311
338
|
|
|
312
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.
|
|
226
|
-
*
|
|
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?:
|
|
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
|
|
@@ -282,8 +290,11 @@ interface MotionProps<C> {
|
|
|
282
290
|
* recorded rect to its natural position via a FLIP transform stack.
|
|
283
291
|
*
|
|
284
292
|
* Reanimated 4 removed the `sharedTransitionTag` API — `layoutId` is the
|
|
285
|
-
* Inertia-side measure-based replacement. Rects are
|
|
286
|
-
* coordinates
|
|
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.
|
|
287
298
|
*
|
|
288
299
|
* The same `transition` prop drives the FLIP animation (spring by
|
|
289
300
|
* default; `'timing'` honored; `'decay'` downgrades to spring; reduced
|
|
@@ -301,12 +312,28 @@ interface MotionProps<C> {
|
|
|
301
312
|
onAnimationEnd?: (info: AnimationCallbackInfo<AnimateStyle<C>>) => void;
|
|
302
313
|
}
|
|
303
314
|
/**
|
|
304
|
-
*
|
|
305
|
-
*
|
|
306
|
-
* animated style) with the Motion
|
|
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.
|
|
318
|
+
*/
|
|
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.
|
|
307
333
|
*/
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
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
|
+
}
|
|
311
338
|
|
|
312
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,5 +1,5 @@
|
|
|
1
1
|
import { SharedValue } from 'react-native-reanimated';
|
|
2
|
-
import { T as TransitionConfig, h as GestureLayerTransitions } from './types-
|
|
2
|
+
import { T as TransitionConfig, h as GestureLayerTransitions } from './types-cU43dEmH.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Handler bag returned by `useGesture`. Spread on a `Pressable` to drive the
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SharedValue } from 'react-native-reanimated';
|
|
2
|
-
import { T as TransitionConfig, h as GestureLayerTransitions } from './types-
|
|
2
|
+
import { T as TransitionConfig, h as GestureLayerTransitions } from './types-cU43dEmH.mjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Handler bag returned by `useGesture`. Spread on a `Pressable` to drive the
|
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/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.9",
|
|
4
4
|
"description": "Declarative animation primitives for React Native, built on react-native-reanimated.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "OnlyNative",
|
|
@@ -112,7 +112,13 @@
|
|
|
112
112
|
"peerDependencies": {
|
|
113
113
|
"react": ">=19.0.0",
|
|
114
114
|
"react-native": ">=0.81.0",
|
|
115
|
-
"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
|
+
}
|
|
116
122
|
},
|
|
117
123
|
"devDependencies": {
|
|
118
124
|
"@react-native/babel-preset": "^0.81.5",
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compile-time gate for variant-key narrowing on `animate`.
|
|
3
|
+
*
|
|
4
|
+
* CLAUDE.md Principle 5 / line 43: "Variant string keys must autocomplete on
|
|
5
|
+
* `animate`." That requires the `variants` map to be inferred at the JSX call
|
|
6
|
+
* site and `animate`'s string form to be narrowed to its keys — so a key typo
|
|
7
|
+
* is a type error, not a silent runtime no-op. These assertions run under
|
|
8
|
+
* `tsc --noEmit` (the typecheck CI step); if a `@ts-expect-error` here stops
|
|
9
|
+
* being an error, tsc fails with "Unused '@ts-expect-error' directive" and the
|
|
10
|
+
* differentiator has regressed.
|
|
11
|
+
*
|
|
12
|
+
* Unlike `animate.test-d.tsx`, these MUST mount JSX: the narrowing depends on
|
|
13
|
+
* `V` being inferred from the `variants` prop at the call site, which only
|
|
14
|
+
* happens through the generic component call signature.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { Motion } from '../motion'
|
|
18
|
+
|
|
19
|
+
const variants = {
|
|
20
|
+
open: { opacity: 1, translateY: 0 },
|
|
21
|
+
closed: { opacity: 0, translateY: 100 },
|
|
22
|
+
} as const
|
|
23
|
+
|
|
24
|
+
// ─── Variant key narrowing ──────────────────────────────────────────────────
|
|
25
|
+
|
|
26
|
+
// A declared key is accepted (and `open` / `closed` autocomplete here).
|
|
27
|
+
const _acceptsKnownKey = <Motion.View variants={variants} animate="open" />
|
|
28
|
+
const _acceptsOtherKey = <Motion.View variants={variants} animate="closed" />
|
|
29
|
+
|
|
30
|
+
// A typo'd key is a compile error rather than a silent no-op.
|
|
31
|
+
// @ts-expect-error 'opne' is not a key of `variants`
|
|
32
|
+
const _rejectsTypoKey = <Motion.View variants={variants} animate="opne" />
|
|
33
|
+
|
|
34
|
+
// The style-object form still works alongside `variants` (escape hatch for a
|
|
35
|
+
// one-off target that isn't a named state).
|
|
36
|
+
const _acceptsStyleObject = (
|
|
37
|
+
<Motion.View variants={variants} animate={{ opacity: 0.5 }} />
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
// `as const` is NOT required — an inline object literal narrows just as well.
|
|
41
|
+
const inlineVariants = { a: { opacity: 1 }, b: { opacity: 0 } }
|
|
42
|
+
const _inlineVariantsNarrow = (
|
|
43
|
+
<Motion.View variants={inlineVariants} animate="a" />
|
|
44
|
+
)
|
|
45
|
+
const _inlineVariantsReject = (
|
|
46
|
+
// @ts-expect-error 'c' is not a key of the inline variants map
|
|
47
|
+
<Motion.View variants={inlineVariants} animate="c" />
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
// ─── No variants → string stays open (back-compat) ──────────────────────────
|
|
51
|
+
|
|
52
|
+
// Without `variants`, the string form is unconstrained, so this must NOT error
|
|
53
|
+
// (the variant-less call site is unchanged by the narrowing machinery).
|
|
54
|
+
const _noVariantsAnyString = <Motion.View animate="whatever" />
|
|
55
|
+
const _noVariantsStyleObject = <Motion.View animate={{ translateX: 10 }} />
|
|
56
|
+
|
|
57
|
+
// Silence "declared but never read" — these exist purely as type assertions.
|
|
58
|
+
export type _VariantTypeAssertions = [
|
|
59
|
+
typeof _acceptsKnownKey,
|
|
60
|
+
typeof _acceptsOtherKey,
|
|
61
|
+
typeof _rejectsTypoKey,
|
|
62
|
+
typeof _acceptsStyleObject,
|
|
63
|
+
typeof _inlineVariantsNarrow,
|
|
64
|
+
typeof _inlineVariantsReject,
|
|
65
|
+
typeof _noVariantsAnyString,
|
|
66
|
+
typeof _noVariantsStyleObject,
|
|
67
|
+
]
|
|
@@ -14,12 +14,15 @@
|
|
|
14
14
|
* it becomes the FLIP source rect; the entry is removed so a third
|
|
15
15
|
* mount with the same id doesn't re-animate from a stale snapshot.
|
|
16
16
|
*
|
|
17
|
-
* Rects are stored in **
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* Rects are stored in **parent-relative coordinates** (what `onLayout`'s
|
|
18
|
+
* `nativeEvent.layout` reports). This composes for the common case where the
|
|
19
|
+
* source and target share an outer content container — e.g. a typical stack
|
|
20
|
+
* navigator. Nested-parent setups, where the two parents sit at different
|
|
21
|
+
* window offsets, need a window-coordinate path (`measureInWindow`); that is
|
|
22
|
+
* punted to v2 per the roadmap.
|
|
20
23
|
*/
|
|
21
24
|
|
|
22
|
-
/**
|
|
25
|
+
/** Parent-relative rect of a measured element (from `onLayout`). */
|
|
23
26
|
export interface SharedRect {
|
|
24
27
|
x: number
|
|
25
28
|
y: number
|
|
@@ -300,43 +300,73 @@ export function createMotionComponent<C extends ComponentType<any>>(
|
|
|
300
300
|
const [focusVisible, setFocusVisible] = useState(false)
|
|
301
301
|
const [hovered, setHovered] = useState(false)
|
|
302
302
|
|
|
303
|
-
// The set of keys this instance animates is
|
|
304
|
-
//
|
|
305
|
-
//
|
|
306
|
-
//
|
|
307
|
-
//
|
|
308
|
-
//
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
303
|
+
// The set of keys this instance animates is a *monotonically growing*
|
|
304
|
+
// union, recomputed every render and expanded when a render introduces a
|
|
305
|
+
// key not seen before. It never shrinks. Two requirements meet here:
|
|
306
|
+
//
|
|
307
|
+
// 1. Variants and gesture sub-states contribute the union across *all*
|
|
308
|
+
// their branches up front — a key touched by any variant must be
|
|
309
|
+
// active so the worklet picks it up when the controller transitions
|
|
310
|
+
// to a branch the base `animate` never mentions.
|
|
311
|
+
// 2. A literal `animate` object is reactive: a parent that changes
|
|
312
|
+
// `animate={{ opacity: 1 }}` to `animate={{ opacity: 1, scale: 2 }}`
|
|
313
|
+
// after mount must get `scale` animating. Freezing the set at first
|
|
314
|
+
// render silently dropped the new key (its SV updated, but the
|
|
315
|
+
// worklet — which iterates this set — never read it).
|
|
316
|
+
//
|
|
317
|
+
// Growing-only keeps the worklet stable: the `activeKeysRef.current` array
|
|
318
|
+
// identity only changes on the renders that actually add a key, so the
|
|
319
|
+
// `useAnimatedStyle` worklet (which reads `.current` each frame) sees the
|
|
320
|
+
// expansion without churning frame-to-frame.
|
|
321
|
+
const touched = new Set<AnimatableKey>()
|
|
322
|
+
collectTouchedKeys(touched, animateRecord)
|
|
323
|
+
if (initialRecord) collectTouchedKeys(touched, initialRecord)
|
|
324
|
+
if (variants) {
|
|
325
|
+
for (const variant of Object.values(variants) as object[]) {
|
|
326
|
+
if (!variant) continue
|
|
327
|
+
collectTouchedKeys(touched, variant as Record<string, unknown>)
|
|
319
328
|
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
+
}
|
|
330
|
+
if (gesture) {
|
|
331
|
+
for (const subState of [
|
|
332
|
+
gesture.pressed,
|
|
333
|
+
gesture.focused,
|
|
334
|
+
gesture.focusVisible,
|
|
335
|
+
gesture.hovered,
|
|
336
|
+
] as Array<object | undefined>) {
|
|
337
|
+
if (!subState) continue
|
|
338
|
+
collectTouchedKeys(touched, subState as Record<string, unknown>)
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
if (exitRecord) collectTouchedKeys(touched, exitRecord)
|
|
342
|
+
|
|
343
|
+
const activeKeysRef = useRef<readonly AnimatableKey[] | null>(null)
|
|
344
|
+
const hasTransformRef = useRef<boolean>(false)
|
|
345
|
+
const hasShadowOffsetRef = useRef<boolean>(false)
|
|
346
|
+
// Expand the active set only when this render touched a key we haven't
|
|
347
|
+
// recorded yet. When nothing new appears we keep the existing array
|
|
348
|
+
// identity so the worklet's captured ref doesn't see a fresh value.
|
|
349
|
+
const prevActive = activeKeysRef.current
|
|
350
|
+
let grew = prevActive === null
|
|
351
|
+
if (!grew && prevActive) {
|
|
352
|
+
for (const k of touched) {
|
|
353
|
+
if (!prevActive.includes(k)) {
|
|
354
|
+
grew = true
|
|
355
|
+
break
|
|
329
356
|
}
|
|
330
357
|
}
|
|
331
|
-
if (exitRecord) collectTouchedKeys(touched, exitRecord)
|
|
332
|
-
activeKeysRef.current = ALL_KEYS.filter((k) => touched.has(k))
|
|
333
358
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
activeKeysRef.current.some((k) =>
|
|
339
|
-
|
|
359
|
+
if (grew) {
|
|
360
|
+
const merged = new Set<AnimatableKey>(prevActive ?? [])
|
|
361
|
+
for (const k of touched) merged.add(k)
|
|
362
|
+
activeKeysRef.current = ALL_KEYS.filter((k) => merged.has(k))
|
|
363
|
+
hasTransformRef.current = activeKeysRef.current.some((k) =>
|
|
364
|
+
TRANSFORM_KEY_SET.has(k),
|
|
365
|
+
)
|
|
366
|
+
hasShadowOffsetRef.current = activeKeysRef.current.some((k) =>
|
|
367
|
+
SHADOW_OFFSET_KEY_SET.has(k),
|
|
368
|
+
)
|
|
369
|
+
}
|
|
340
370
|
|
|
341
371
|
const sharedValues = useAnimatableSharedValues((key) => {
|
|
342
372
|
// Shadow offset synthetics seed from the corresponding axis on the
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { reanimatedVersion } from 'react-native-reanimated'
|
|
2
|
+
|
|
1
3
|
declare const __DEV__: boolean
|
|
2
4
|
declare const process: { env?: Record<string, string | undefined> }
|
|
3
|
-
declare const require: (path: string) => unknown
|
|
4
5
|
|
|
5
6
|
let alreadyChecked = false
|
|
6
7
|
|
|
@@ -30,16 +31,11 @@ export function ensureReanimatedInstalled(): void {
|
|
|
30
31
|
}
|
|
31
32
|
alreadyChecked = true
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
version = pkg.version
|
|
39
|
-
} catch {
|
|
40
|
-
// package.json subpath blocked by `exports` field — skip the version
|
|
41
|
-
// probe rather than emit a misleading error.
|
|
42
|
-
}
|
|
34
|
+
// Read the version off Reanimated's own runtime export rather than reaching
|
|
35
|
+
// into its `package.json`. A `require('.../package.json')` here would make
|
|
36
|
+
// esbuild emit a `__require` shim that throws on web bundlers (Expo web), and
|
|
37
|
+
// Reanimated's `exports` field may block the subpath anyway.
|
|
38
|
+
const version: string | undefined = reanimatedVersion
|
|
43
39
|
|
|
44
40
|
if (version) {
|
|
45
41
|
const major = parseInt(version.split('.')[0] ?? '0', 10)
|
package/src/types.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type ComponentProps,
|
|
3
|
+
type ComponentType,
|
|
4
|
+
type ReactElement,
|
|
5
|
+
type Ref,
|
|
6
|
+
} from 'react'
|
|
2
7
|
import { type StyleProp } from 'react-native'
|
|
3
8
|
|
|
4
9
|
/**
|
|
@@ -239,8 +244,15 @@ export interface VariantController<K extends string = string> {
|
|
|
239
244
|
|
|
240
245
|
/**
|
|
241
246
|
* Props injected onto every Motion primitive.
|
|
247
|
+
*
|
|
248
|
+
* The second type parameter `V` is the concrete `variants` map. It is inferred
|
|
249
|
+
* from the `variants` prop at each JSX use (see `MotionComponent`), which is
|
|
250
|
+
* what lets `animate` narrow to the variant key union and reject typos. When
|
|
251
|
+
* no `variants` prop is passed, `V` falls back to `VariantsMap<C>` — whose key
|
|
252
|
+
* type is the open `string`, so `animate` still accepts any string and nothing
|
|
253
|
+
* regresses for the variant-less case.
|
|
242
254
|
*/
|
|
243
|
-
export interface MotionProps<C> {
|
|
255
|
+
export interface MotionProps<C, V extends VariantsMap<C> = VariantsMap<C>> {
|
|
244
256
|
/**
|
|
245
257
|
* Initial values applied on mount. Read once on mount and intentionally
|
|
246
258
|
* non-reactive — to reset after a state change, change the component `key`,
|
|
@@ -251,10 +263,11 @@ export interface MotionProps<C> {
|
|
|
251
263
|
initial?: AnimateStyle<C> | false
|
|
252
264
|
/**
|
|
253
265
|
* The animation target. A style object, a variant key (when `variants` is
|
|
254
|
-
* supplied), or an array of sequence steps.
|
|
255
|
-
*
|
|
266
|
+
* supplied), or an array of sequence steps. When `variants` is set, the
|
|
267
|
+
* string form is narrowed to the map's keys, so a key typo is a compile
|
|
268
|
+
* error and the keys autocomplete — no `as const` required.
|
|
256
269
|
*/
|
|
257
|
-
animate?: AnimateStyle<C> | string
|
|
270
|
+
animate?: AnimateStyle<C> | (keyof V & string)
|
|
258
271
|
/**
|
|
259
272
|
* Values applied while the component exits via `<Presence>`.
|
|
260
273
|
*/
|
|
@@ -263,13 +276,13 @@ export interface MotionProps<C> {
|
|
|
263
276
|
* Named animation states. With `variants` set, `animate` accepts a key from
|
|
264
277
|
* this map.
|
|
265
278
|
*/
|
|
266
|
-
variants?:
|
|
279
|
+
variants?: V
|
|
267
280
|
/**
|
|
268
281
|
* Imperative controller from `useVariants(...)`. When supplied, `animate`
|
|
269
282
|
* is read from `controller.current` and re-applied whenever the controller
|
|
270
283
|
* transitions. `animate` and `controller` should not both be set.
|
|
271
284
|
*/
|
|
272
|
-
controller?: VariantController
|
|
285
|
+
controller?: VariantController<keyof V & string>
|
|
273
286
|
/**
|
|
274
287
|
* Gesture-driven sub-states (`pressed`, `focused`, `focusVisible`,
|
|
275
288
|
* `hovered`). When omitted, no handlers are mounted on the underlying
|
|
@@ -311,8 +324,11 @@ export interface MotionProps<C> {
|
|
|
311
324
|
* recorded rect to its natural position via a FLIP transform stack.
|
|
312
325
|
*
|
|
313
326
|
* Reanimated 4 removed the `sharedTransitionTag` API — `layoutId` is the
|
|
314
|
-
* Inertia-side measure-based replacement. Rects are
|
|
315
|
-
* coordinates
|
|
327
|
+
* Inertia-side measure-based replacement. Rects are recorded in
|
|
328
|
+
* parent-relative coordinates (from `onLayout`), which composes when the
|
|
329
|
+
* source and target screens share an outer content container (the common
|
|
330
|
+
* stack-navigator case); nested-parent layouts need the v2
|
|
331
|
+
* window-coordinate path.
|
|
316
332
|
*
|
|
317
333
|
* The same `transition` prop drives the FLIP animation (spring by
|
|
318
334
|
* default; `'timing'` honored; `'decay'` downgrades to spring; reduced
|
|
@@ -331,14 +347,37 @@ export interface MotionProps<C> {
|
|
|
331
347
|
}
|
|
332
348
|
|
|
333
349
|
/**
|
|
334
|
-
*
|
|
335
|
-
*
|
|
336
|
-
* animated style) with the Motion
|
|
350
|
+
* Props of a Motion primitive for a given underlying component `C` and a
|
|
351
|
+
* concrete variants map `V`: the component's own props (minus `style`, which
|
|
352
|
+
* we replace with an animated style) intersected with the Motion props.
|
|
337
353
|
*/
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
>
|
|
354
|
+
export type MotionComponentProps<
|
|
355
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
356
|
+
C extends ComponentType<any>,
|
|
357
|
+
V extends VariantsMap<ComponentProps<C>> = VariantsMap<ComponentProps<C>>,
|
|
358
|
+
> = Omit<ComponentProps<C>, 'style'> &
|
|
359
|
+
MotionProps<ComponentProps<C>, V> & {
|
|
360
|
+
style?: ComponentProps<C>['style']
|
|
361
|
+
ref?: Ref<unknown>
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* The component type produced by `createMotionComponent`.
|
|
366
|
+
*
|
|
367
|
+
* It is a **generic call signature**, not a plain `ComponentType`: the variant
|
|
368
|
+
* map `V` is inferred from the `variants` prop at each JSX use. That inference
|
|
369
|
+
* is what narrows `animate`'s string form to the variant keys, so
|
|
370
|
+
* `<Motion.View variants={{ open, closed }} animate="opne" />` is a compile
|
|
371
|
+
* error and `open` / `closed` autocomplete. With no `variants` prop, `V` falls
|
|
372
|
+
* back to the open `VariantsMap`, so `animate` still accepts any string and the
|
|
373
|
+
* variant-less call site is unchanged.
|
|
374
|
+
*/
|
|
375
|
+
export interface MotionComponent<
|
|
376
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
377
|
+
C extends ComponentType<any>,
|
|
378
|
+
> {
|
|
379
|
+
<V extends VariantsMap<ComponentProps<C>> = VariantsMap<ComponentProps<C>>>(
|
|
380
|
+
props: MotionComponentProps<C, V>,
|
|
381
|
+
): ReactElement | null
|
|
382
|
+
displayName?: string
|
|
383
|
+
}
|