@rootnative/inertia 0.0.6 → 0.0.7
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 +34 -1
- package/README.md +7 -1
- package/dist/{chunk-C3EDC5ZW.mjs → chunk-52QSN2VQ.mjs} +1 -1
- package/dist/{chunk-767UKZXG.js → chunk-6V7MOBXO.js} +12 -0
- package/dist/{chunk-2ICQLWH2.mjs → chunk-HPJMIBBK.mjs} +12 -0
- package/dist/{chunk-PFPO7DX2.mjs → chunk-KBFN4TRO.mjs} +1 -1
- package/dist/chunk-NPJ46457.js +8 -0
- package/dist/chunk-QJYFTTM2.js +28 -0
- package/dist/{chunk-X7B5WR5A.js → chunk-QYR66E2G.js} +2 -2
- package/dist/{chunk-CMHVF6F4.mjs → chunk-RUIOM2YZ.mjs} +1 -1
- package/dist/{chunk-BAAQI37F.mjs → chunk-VSK2E35J.mjs} +1 -1
- package/dist/{chunk-5MGWHOSV.js → chunk-WGCF3WQG.js} +2 -2
- package/dist/{chunk-F7LJX56B.mjs → chunk-WMLS4TMX.mjs} +1 -1
- package/dist/chunk-YUTS6JRU.js +8 -0
- package/dist/chunk-ZOBOKLAS.mjs +22 -0
- package/dist/chunk-ZSOCRHU3.js +8 -0
- package/dist/gestureLayer/index.d.mts +2 -2
- package/dist/gestureLayer/index.d.ts +2 -2
- package/dist/index.d.mts +17 -9
- package/dist/index.d.ts +17 -9
- package/dist/index.js +29 -23
- package/dist/index.mjs +16 -13
- package/dist/motion/FlatList.d.mts +53 -0
- package/dist/motion/FlatList.d.ts +53 -0
- package/dist/motion/FlatList.js +13 -0
- package/dist/motion/FlatList.mjs +4 -0
- package/dist/motion/Image.d.mts +1 -1
- package/dist/motion/Image.d.ts +1 -1
- package/dist/motion/Image.js +3 -3
- package/dist/motion/Image.mjs +2 -2
- package/dist/motion/Pressable.d.mts +1 -1
- package/dist/motion/Pressable.d.ts +1 -1
- package/dist/motion/Pressable.js +3 -3
- package/dist/motion/Pressable.mjs +2 -2
- package/dist/motion/ScrollView.d.mts +1 -1
- package/dist/motion/ScrollView.d.ts +1 -1
- package/dist/motion/ScrollView.js +3 -3
- package/dist/motion/ScrollView.mjs +2 -2
- package/dist/motion/Text.d.mts +1 -1
- package/dist/motion/Text.d.ts +1 -1
- package/dist/motion/Text.js +3 -3
- package/dist/motion/Text.mjs +2 -2
- package/dist/motion/View.d.mts +1 -1
- package/dist/motion/View.d.ts +1 -1
- package/dist/motion/View.js +3 -3
- package/dist/motion/View.mjs +2 -2
- package/dist/touch/index.d.mts +1 -1
- package/dist/touch/index.d.ts +1 -1
- package/dist/{types-BQgLJeQG.d.mts → types-DyJpG64F.d.mts} +1 -1
- package/dist/{types-BQgLJeQG.d.ts → types-DyJpG64F.d.ts} +1 -1
- package/dist/{useGesture-DfaTx-3t.d.mts → useGesture-CnZQnYHH.d.mts} +1 -1
- package/dist/{useGesture-B0_CzOUz.d.ts → useGesture-DbH46EBp.d.ts} +1 -1
- package/jest-setup.js +7 -1
- package/llms.txt +7 -3
- package/package.json +8 -1
- package/src/index.ts +1 -0
- package/src/motion/FlatList.tsx +77 -0
- package/src/motion/createMotionComponent.tsx +23 -0
- package/src/motion/index.ts +3 -0
- package/src/values/useScroll.ts +9 -5
- package/dist/chunk-FWWVHLXB.js +0 -8
- package/dist/chunk-K5SI6VXS.js +0 -8
- package/dist/chunk-STARIT6W.js +0 -8
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { FlatListProps, FlatList } from 'react-native';
|
|
2
|
+
import { V as VariantsMap, a as MotionProps } from '../types-DyJpG64F.js';
|
|
3
|
+
import 'react';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Animatable, virtualized `FlatList`.
|
|
7
|
+
*
|
|
8
|
+
* Built on Reanimated's `Animated.FlatList` rather than RN's `FlatList`. That
|
|
9
|
+
* wrapper supplies two things this primitive would otherwise have to
|
|
10
|
+
* re-implement: the `CellRendererComponent` injection that powers per-row
|
|
11
|
+
* `itemLayoutAnimation`, and a `scrollEventThrottle` default of 1.
|
|
12
|
+
*
|
|
13
|
+
* A note on that throttle default, because the reasoning is easy to get wrong
|
|
14
|
+
* from Reanimated's own source comment: it says RN defaults FlatList's
|
|
15
|
+
* `scrollEventThrottle` to 50, which **is stale**. On RN 0.81
|
|
16
|
+
* (`@react-native/virtualized-lists`, `VirtualizedList.js`) the default is
|
|
17
|
+
* `props.scrollEventThrottle ?? 0.0001` — effectively every frame. So the
|
|
18
|
+
* patch is belt-and-braces on current RN rather than the load-bearing reason
|
|
19
|
+
* to use the wrapper. It is still worth inheriting: it costs nothing, and it
|
|
20
|
+
* pins the behaviour if RN's default changes again. **Do not restate the "50"
|
|
21
|
+
* figure as fact** — verify against the installed RN before relying on it.
|
|
22
|
+
*
|
|
23
|
+
* This is the primitive that lets one list both virtualize and animate. The
|
|
24
|
+
* `useScroll()` handler works because `Motion.*` components are Reanimated
|
|
25
|
+
* animated components — the same mechanism `Motion.ScrollView` relies on, and
|
|
26
|
+
* nothing about it was ever specific to `ScrollView`:
|
|
27
|
+
*
|
|
28
|
+
* ```tsx
|
|
29
|
+
* const { scrollY, onScroll } = useScroll()
|
|
30
|
+
*
|
|
31
|
+
* <Motion.FlatList
|
|
32
|
+
* data={items}
|
|
33
|
+
* renderItem={renderItem}
|
|
34
|
+
* onScroll={onScroll}
|
|
35
|
+
* initial={{ opacity: 0 }}
|
|
36
|
+
* animate={{ opacity: 1 }}
|
|
37
|
+
* />
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* Two scoping notes:
|
|
41
|
+
*
|
|
42
|
+
* - `animate` / `initial` / `gesture` apply to the **scroll container**, not to
|
|
43
|
+
* rows. Animate rows by using a `Motion.*` primitive inside `renderItem`.
|
|
44
|
+
* - The `layout` prop animates the list frame. Per-row layout animation is
|
|
45
|
+
* Reanimated's `itemLayoutAnimation`, which is forwarded through untouched.
|
|
46
|
+
* Note that row-level layout animation can fight the list's own measurement
|
|
47
|
+
* passes — measure before adopting it.
|
|
48
|
+
*/
|
|
49
|
+
declare const MotionFlatList: <ItemT = any, V extends VariantsMap<FlatListProps<ItemT>> = VariantsMap<FlatListProps<ItemT>>>(props: FlatListProps<ItemT> & MotionProps<FlatListProps<ItemT>, V> & {
|
|
50
|
+
ref?: React.Ref<FlatList<ItemT>>;
|
|
51
|
+
}) => React.ReactElement;
|
|
52
|
+
|
|
53
|
+
export { MotionFlatList };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkQJYFTTM2_js = require('../chunk-QJYFTTM2.js');
|
|
4
|
+
require('../chunk-6V7MOBXO.js');
|
|
5
|
+
require('../chunk-OBRGJAST.js');
|
|
6
|
+
require('../chunk-PM6CVGXJ.js');
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
Object.defineProperty(exports, "MotionFlatList", {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: function () { return chunkQJYFTTM2_js.MotionFlatList; }
|
|
13
|
+
});
|
package/dist/motion/Image.d.mts
CHANGED
package/dist/motion/Image.d.ts
CHANGED
package/dist/motion/Image.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('../chunk-
|
|
3
|
+
var chunkYUTS6JRU_js = require('../chunk-YUTS6JRU.js');
|
|
4
|
+
require('../chunk-6V7MOBXO.js');
|
|
5
5
|
require('../chunk-OBRGJAST.js');
|
|
6
6
|
require('../chunk-PM6CVGXJ.js');
|
|
7
7
|
|
|
@@ -9,5 +9,5 @@ require('../chunk-PM6CVGXJ.js');
|
|
|
9
9
|
|
|
10
10
|
Object.defineProperty(exports, "MotionImage", {
|
|
11
11
|
enumerable: true,
|
|
12
|
-
get: function () { return
|
|
12
|
+
get: function () { return chunkYUTS6JRU_js.MotionImage; }
|
|
13
13
|
});
|
package/dist/motion/Image.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import * as react_native from 'react-native';
|
|
3
|
-
import { M as MotionComponent } from '../types-
|
|
3
|
+
import { M as MotionComponent } from '../types-DyJpG64F.mjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Animatable `Pressable`. The `gesture` prop's `pressed` sub-state hooks into
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import * as react_native from 'react-native';
|
|
3
|
-
import { M as MotionComponent } from '../types-
|
|
3
|
+
import { M as MotionComponent } from '../types-DyJpG64F.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Animatable `Pressable`. The `gesture` prop's `pressed` sub-state hooks into
|
package/dist/motion/Pressable.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('../chunk-
|
|
3
|
+
var chunkWGCF3WQG_js = require('../chunk-WGCF3WQG.js');
|
|
4
|
+
require('../chunk-6V7MOBXO.js');
|
|
5
5
|
require('../chunk-OBRGJAST.js');
|
|
6
6
|
require('../chunk-PM6CVGXJ.js');
|
|
7
7
|
|
|
@@ -9,5 +9,5 @@ require('../chunk-PM6CVGXJ.js');
|
|
|
9
9
|
|
|
10
10
|
Object.defineProperty(exports, "MotionPressable", {
|
|
11
11
|
enumerable: true,
|
|
12
|
-
get: function () { return
|
|
12
|
+
get: function () { return chunkWGCF3WQG_js.MotionPressable; }
|
|
13
13
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('../chunk-
|
|
3
|
+
var chunkQYR66E2G_js = require('../chunk-QYR66E2G.js');
|
|
4
|
+
require('../chunk-6V7MOBXO.js');
|
|
5
5
|
require('../chunk-OBRGJAST.js');
|
|
6
6
|
require('../chunk-PM6CVGXJ.js');
|
|
7
7
|
|
|
@@ -9,5 +9,5 @@ require('../chunk-PM6CVGXJ.js');
|
|
|
9
9
|
|
|
10
10
|
Object.defineProperty(exports, "MotionScrollView", {
|
|
11
11
|
enumerable: true,
|
|
12
|
-
get: function () { return
|
|
12
|
+
get: function () { return chunkQYR66E2G_js.MotionScrollView; }
|
|
13
13
|
});
|
package/dist/motion/Text.d.mts
CHANGED
package/dist/motion/Text.d.ts
CHANGED
package/dist/motion/Text.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('../chunk-
|
|
3
|
+
var chunkZSOCRHU3_js = require('../chunk-ZSOCRHU3.js');
|
|
4
|
+
require('../chunk-6V7MOBXO.js');
|
|
5
5
|
require('../chunk-OBRGJAST.js');
|
|
6
6
|
require('../chunk-PM6CVGXJ.js');
|
|
7
7
|
|
|
@@ -9,5 +9,5 @@ require('../chunk-PM6CVGXJ.js');
|
|
|
9
9
|
|
|
10
10
|
Object.defineProperty(exports, "MotionText", {
|
|
11
11
|
enumerable: true,
|
|
12
|
-
get: function () { return
|
|
12
|
+
get: function () { return chunkZSOCRHU3_js.MotionText; }
|
|
13
13
|
});
|
package/dist/motion/Text.mjs
CHANGED
package/dist/motion/View.d.mts
CHANGED
package/dist/motion/View.d.ts
CHANGED
package/dist/motion/View.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('../chunk-
|
|
3
|
+
var chunkNPJ46457_js = require('../chunk-NPJ46457.js');
|
|
4
|
+
require('../chunk-6V7MOBXO.js');
|
|
5
5
|
require('../chunk-OBRGJAST.js');
|
|
6
6
|
require('../chunk-PM6CVGXJ.js');
|
|
7
7
|
|
|
@@ -9,5 +9,5 @@ require('../chunk-PM6CVGXJ.js');
|
|
|
9
9
|
|
|
10
10
|
Object.defineProperty(exports, "MotionView", {
|
|
11
11
|
enumerable: true,
|
|
12
|
-
get: function () { return
|
|
12
|
+
get: function () { return chunkNPJ46457_js.MotionView; }
|
|
13
13
|
});
|
package/dist/motion/View.mjs
CHANGED
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-DyJpG64F.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-DyJpG64F.js';
|
|
4
4
|
import 'react';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -456,4 +456,4 @@ interface MotionComponent<C extends ComponentType<any>> {
|
|
|
456
456
|
displayName?: string;
|
|
457
457
|
}
|
|
458
458
|
|
|
459
|
-
export type { AnimatableValue as A, BoxShadowInput as B, DecayTransition as D, EasingInput as E, GestureLayerTransitions as G, MotionComponent as M, NamedTransitions as N, PerPropertyTransition as P, RegisteredTransitions as R, SpringTransition as S, TransitionConfig as T,
|
|
459
|
+
export type { AnimatableValue as A, BoxShadowInput as B, DecayTransition as D, EasingInput as E, GestureLayerTransitions as G, MotionComponent as M, NamedTransitions as N, PerPropertyTransition as P, RegisteredTransitions as R, SpringTransition as S, TransitionConfig as T, VariantsMap as V, MotionProps as a, TransitionInput as b, TransitionName as c, VariantController as d, AnimateStyle as e, AnimationCallbackInfo as f, EasingFunction as g, EasingFunctionFactory as h, GestureSubStates as i, NoAnimationTransition as j, RepeatConfig as k, SequenceStep as l, TimingTransition as m, Transition as n };
|
|
@@ -456,4 +456,4 @@ interface MotionComponent<C extends ComponentType<any>> {
|
|
|
456
456
|
displayName?: string;
|
|
457
457
|
}
|
|
458
458
|
|
|
459
|
-
export type { AnimatableValue as A, BoxShadowInput as B, DecayTransition as D, EasingInput as E, GestureLayerTransitions as G, MotionComponent as M, NamedTransitions as N, PerPropertyTransition as P, RegisteredTransitions as R, SpringTransition as S, TransitionConfig as T,
|
|
459
|
+
export type { AnimatableValue as A, BoxShadowInput as B, DecayTransition as D, EasingInput as E, GestureLayerTransitions as G, MotionComponent as M, NamedTransitions as N, PerPropertyTransition as P, RegisteredTransitions as R, SpringTransition as S, TransitionConfig as T, VariantsMap as V, MotionProps as a, TransitionInput as b, TransitionName as c, VariantController as d, AnimateStyle as e, AnimationCallbackInfo as f, EasingFunction as g, EasingFunctionFactory as h, GestureSubStates as i, NoAnimationTransition as j, RepeatConfig as k, SequenceStep as l, TimingTransition as m, Transition as n };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SharedValue } from 'react-native-reanimated';
|
|
2
|
-
import {
|
|
2
|
+
import { b as TransitionInput, G as GestureLayerTransitions } from './types-DyJpG64F.mjs';
|
|
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 {
|
|
2
|
+
import { b as TransitionInput, G as GestureLayerTransitions } from './types-DyJpG64F.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Handler bag returned by `useGesture`. Spread on a `Pressable` to drive the
|
package/jest-setup.js
CHANGED
|
@@ -45,7 +45,7 @@ jest.mock('react-native/Libraries/Text/Text', () => {
|
|
|
45
45
|
// run; targets snap in one step.
|
|
46
46
|
jest.mock('react-native-reanimated', () => {
|
|
47
47
|
const React = require('react')
|
|
48
|
-
const { Image, ScrollView, Text, View } = require('react-native')
|
|
48
|
+
const { FlatList, Image, ScrollView, Text, View } = require('react-native')
|
|
49
49
|
|
|
50
50
|
const wrap = (Component, displayName) => {
|
|
51
51
|
const Wrapped = React.forwardRef((props, ref) =>
|
|
@@ -59,6 +59,10 @@ jest.mock('react-native-reanimated', () => {
|
|
|
59
59
|
const AnimatedText = wrap(Text, 'Animated.Text')
|
|
60
60
|
const AnimatedImage = wrap(Image, 'Animated.Image')
|
|
61
61
|
const AnimatedScrollView = wrap(ScrollView, 'Animated.ScrollView')
|
|
62
|
+
// Reanimated's real `Animated.FlatList` also defaults `scrollEventThrottle`
|
|
63
|
+
// to 1 and injects a `CellRendererComponent`; neither is observable in this
|
|
64
|
+
// mock, so the wrapper is a plain pass-through like the others.
|
|
65
|
+
const AnimatedFlatList = wrap(FlatList, 'Animated.FlatList')
|
|
62
66
|
|
|
63
67
|
return {
|
|
64
68
|
__esModule: true,
|
|
@@ -67,6 +71,7 @@ jest.mock('react-native-reanimated', () => {
|
|
|
67
71
|
Text: AnimatedText,
|
|
68
72
|
Image: AnimatedImage,
|
|
69
73
|
ScrollView: AnimatedScrollView,
|
|
74
|
+
FlatList: AnimatedFlatList,
|
|
70
75
|
createAnimatedComponent: (c) =>
|
|
71
76
|
wrap(c, `Animated(${c.displayName ?? c.name ?? 'Component'})`),
|
|
72
77
|
},
|
|
@@ -74,6 +79,7 @@ jest.mock('react-native-reanimated', () => {
|
|
|
74
79
|
Text: AnimatedText,
|
|
75
80
|
Image: AnimatedImage,
|
|
76
81
|
ScrollView: AnimatedScrollView,
|
|
82
|
+
FlatList: AnimatedFlatList,
|
|
77
83
|
useSharedValue: (initial) => {
|
|
78
84
|
const ref = React.useRef(null)
|
|
79
85
|
if (ref.current === null) ref.current = { value: initial }
|
package/llms.txt
CHANGED
|
@@ -34,17 +34,21 @@ import {
|
|
|
34
34
|
import { useGestureLayer } from '@rootnative/inertia/gesture-layer'
|
|
35
35
|
// Render-layer Reanimated interop for custom animated components:
|
|
36
36
|
import { Animated, useAnimatedStyle } from '@rootnative/inertia/reanimated'
|
|
37
|
-
// or for tree-shaking the primitives:
|
|
37
|
+
// or for tree-shaking the primitives. NOTE: these subpaths export a
|
|
38
|
+
// differently NAMED symbol — `MotionScrollView`, not `Motion.ScrollView`.
|
|
39
|
+
// `Motion` itself is only exported from the package root above, and there
|
|
40
|
+
// is no '@rootnative/inertia/motion' subpath.
|
|
38
41
|
import { MotionView } from '@rootnative/inertia/view'
|
|
39
42
|
import { MotionText } from '@rootnative/inertia/text'
|
|
40
43
|
import { MotionImage } from '@rootnative/inertia/image'
|
|
41
44
|
import { MotionPressable } from '@rootnative/inertia/pressable'
|
|
42
45
|
import { MotionScrollView } from '@rootnative/inertia/scroll-view'
|
|
46
|
+
import { MotionFlatList } from '@rootnative/inertia/flat-list'
|
|
43
47
|
```
|
|
44
48
|
|
|
45
49
|
## Public API
|
|
46
50
|
|
|
47
|
-
- `Motion.View` / `Motion.Text` / `Motion.Image` / `Motion.Pressable` / `Motion.ScrollView` — animatable primitives. Per-primitive style inference (no shared `ViewStyle & TextStyle & ImageStyle` fallback).
|
|
51
|
+
- `Motion.View` / `Motion.Text` / `Motion.Image` / `Motion.Pressable` / `Motion.ScrollView` / `Motion.FlatList` — animatable primitives. Per-primitive style inference (no shared `ViewStyle & TextStyle & ImageStyle` fallback). `Motion.FlatList` is the **virtualized** animated scroller: it takes `useScroll`'s `onScroll` handler and keeps `data` / `renderItem` item-type inference, so a long list can virtualize and animate at once. Animation props apply to the scroll container; animate rows with a `Motion.*` inside `renderItem`.
|
|
48
52
|
- `<Presence>` — mount / unmount transitions; children need explicit `key`s. Exiting children get `pointerEvents: 'none'` automatically.
|
|
49
53
|
- `<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)`.
|
|
50
54
|
- `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).
|
|
@@ -60,7 +64,7 @@ import { MotionScrollView } from '@rootnative/inertia/scroll-view'
|
|
|
60
64
|
- `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.
|
|
61
65
|
- `useColorCascade(rest, layers, options?)` — pure value-layer interpolator compositing a **priority-ordered** stack of color layers over a base `rest` color; each `layers` entry is `{ progress: SharedValue<number>, color: string }`, later entries win as their progress rises (equivalent to the nested `focus(error(hover(rest)))` `interpolateColor` chain). `options.key` reuses `ColorStyleKey` (default `backgroundColor`). Returns a spreadable animated style fragment; memoized on a colors+key signature. Color-only by design — cascade a numeric key separately via `useInterpolatedStyle` + `useTransform` max. `useColorTransition` stays the single-layer fast path.
|
|
62
66
|
- `useInterpolatedStyle(progress, map, options?)` — pure value-layer interpolator mapping one `SharedValue<number>` onto **N** style props at once, returned as a spreadable animated style fragment (the multi-key, style-fragment counterpart to `useTransform`'s output-range form). Numeric keys (`opacity` / `height` / `fontSize` / …) route through `interpolate`; transform keys (`translateX` / `scale` / `rotate` / …) lift into a `transform` array in map key-order (`rotate*` emit `'<n>deg'`); color keys (`backgroundColor` / `borderColor` / …) route through `interpolateColor` (a multi-stop `useColorTransition`). Stop types are compile-checked. `options.inputRange` (default `[0,1]` / evenly-spaced) and `options.extrapolate` (default `'clamp'`) apply to every key. Memoized on an order-preserving signature. For function-valued or multi-source composition, drop to `useTransform`'s worklet form or a hand-rolled `useAnimatedStyle`.
|
|
63
|
-
- `useScroll()` — returns `{ scrollX, scrollY, onScroll }` for use with `Motion.ScrollView`. Scroll events fire on the UI thread.
|
|
67
|
+
- `useScroll()` — returns `{ scrollX, scrollY, onScroll }` for use with `Motion.ScrollView` or `Motion.FlatList`. Scroll events fire on the UI thread. Set `scrollEventThrottle={16}` on a `Motion.ScrollView`; `Motion.FlatList` defaults it to 1.
|
|
64
68
|
- `createMotionComponent<C>(C)` — wrap any component with the same Motion prop surface, inferring style from `C`.
|
|
65
69
|
- `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 })`.
|
|
66
70
|
- `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.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rootnative/inertia",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"description": "Declarative animation primitives for React Native, built on react-native-reanimated.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "RootNative",
|
|
@@ -72,6 +72,13 @@
|
|
|
72
72
|
"import": "./dist/motion/ScrollView.mjs",
|
|
73
73
|
"require": "./dist/motion/ScrollView.js"
|
|
74
74
|
},
|
|
75
|
+
"./flat-list": {
|
|
76
|
+
"types": "./dist/motion/FlatList.d.ts",
|
|
77
|
+
"react-native": "./src/motion/FlatList.tsx",
|
|
78
|
+
"source": "./src/motion/FlatList.tsx",
|
|
79
|
+
"import": "./dist/motion/FlatList.mjs",
|
|
80
|
+
"require": "./dist/motion/FlatList.js"
|
|
81
|
+
},
|
|
75
82
|
"./testing": {
|
|
76
83
|
"types": "./dist/testing/index.d.ts",
|
|
77
84
|
"react-native": "./src/testing/index.ts",
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { FlatList as RNFlatList, FlatListProps } from 'react-native'
|
|
2
|
+
import Animated from 'react-native-reanimated'
|
|
3
|
+
import type { MotionProps, VariantsMap } from '../types'
|
|
4
|
+
import { createMotionComponent } from './createMotionComponent'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Animatable, virtualized `FlatList`.
|
|
8
|
+
*
|
|
9
|
+
* Built on Reanimated's `Animated.FlatList` rather than RN's `FlatList`. That
|
|
10
|
+
* wrapper supplies two things this primitive would otherwise have to
|
|
11
|
+
* re-implement: the `CellRendererComponent` injection that powers per-row
|
|
12
|
+
* `itemLayoutAnimation`, and a `scrollEventThrottle` default of 1.
|
|
13
|
+
*
|
|
14
|
+
* A note on that throttle default, because the reasoning is easy to get wrong
|
|
15
|
+
* from Reanimated's own source comment: it says RN defaults FlatList's
|
|
16
|
+
* `scrollEventThrottle` to 50, which **is stale**. On RN 0.81
|
|
17
|
+
* (`@react-native/virtualized-lists`, `VirtualizedList.js`) the default is
|
|
18
|
+
* `props.scrollEventThrottle ?? 0.0001` — effectively every frame. So the
|
|
19
|
+
* patch is belt-and-braces on current RN rather than the load-bearing reason
|
|
20
|
+
* to use the wrapper. It is still worth inheriting: it costs nothing, and it
|
|
21
|
+
* pins the behaviour if RN's default changes again. **Do not restate the "50"
|
|
22
|
+
* figure as fact** — verify against the installed RN before relying on it.
|
|
23
|
+
*
|
|
24
|
+
* This is the primitive that lets one list both virtualize and animate. The
|
|
25
|
+
* `useScroll()` handler works because `Motion.*` components are Reanimated
|
|
26
|
+
* animated components — the same mechanism `Motion.ScrollView` relies on, and
|
|
27
|
+
* nothing about it was ever specific to `ScrollView`:
|
|
28
|
+
*
|
|
29
|
+
* ```tsx
|
|
30
|
+
* const { scrollY, onScroll } = useScroll()
|
|
31
|
+
*
|
|
32
|
+
* <Motion.FlatList
|
|
33
|
+
* data={items}
|
|
34
|
+
* renderItem={renderItem}
|
|
35
|
+
* onScroll={onScroll}
|
|
36
|
+
* initial={{ opacity: 0 }}
|
|
37
|
+
* animate={{ opacity: 1 }}
|
|
38
|
+
* />
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* Two scoping notes:
|
|
42
|
+
*
|
|
43
|
+
* - `animate` / `initial` / `gesture` apply to the **scroll container**, not to
|
|
44
|
+
* rows. Animate rows by using a `Motion.*` primitive inside `renderItem`.
|
|
45
|
+
* - The `layout` prop animates the list frame. Per-row layout animation is
|
|
46
|
+
* Reanimated's `itemLayoutAnimation`, which is forwarded through untouched.
|
|
47
|
+
* Note that row-level layout animation can fight the list's own measurement
|
|
48
|
+
* passes — measure before adopting it.
|
|
49
|
+
*/
|
|
50
|
+
export const MotionFlatList = createMotionComponent(
|
|
51
|
+
Animated.FlatList as never,
|
|
52
|
+
// `createMotionComponent<C>` returns a non-generic `MotionComponent<C>`, so
|
|
53
|
+
// `data` / `renderItem` would collapse to `any` and lose `ItemT` inference.
|
|
54
|
+
// Restore it with the same call-signature cast Reanimated itself uses for
|
|
55
|
+
// this exact problem (see its `ReanimatedFlatList` export, and the
|
|
56
|
+
// `@ts-expect-error` above `AnimatedFlatList` explaining that
|
|
57
|
+
// `createAnimatedComponent` cannot create generic components).
|
|
58
|
+
//
|
|
59
|
+
// **Both** generics live on the one call signature, and that is deliberate:
|
|
60
|
+
// `ItemT` infers from `data` while `V` infers from `variants`, independently.
|
|
61
|
+
// Declaring only `ItemT` (the obvious first cut) silently drops the
|
|
62
|
+
// variant-key narrowing that `MotionComponent` provides on every other
|
|
63
|
+
// primitive — `animate="typo"` would stop being a compile error here and
|
|
64
|
+
// nowhere else. Both directions are pinned in
|
|
65
|
+
// `__type-tests__/flat-list.test-d.tsx`.
|
|
66
|
+
) as unknown as <
|
|
67
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
68
|
+
ItemT = any,
|
|
69
|
+
V extends VariantsMap<FlatListProps<ItemT>> = VariantsMap<
|
|
70
|
+
FlatListProps<ItemT>
|
|
71
|
+
>,
|
|
72
|
+
>(
|
|
73
|
+
props: FlatListProps<ItemT> &
|
|
74
|
+
MotionProps<FlatListProps<ItemT>, V> & {
|
|
75
|
+
ref?: React.Ref<RNFlatList<ItemT>>
|
|
76
|
+
},
|
|
77
|
+
) => React.ReactElement
|
|
@@ -2025,6 +2025,26 @@ function useGestureHandlers(
|
|
|
2025
2025
|
// forward to those when present so wrapping consumers stay consistent.
|
|
2026
2026
|
handlers.onPressIn = compose(rest.onPressIn, () => setPressed(true))
|
|
2027
2027
|
handlers.onPressOut = compose(rest.onPressOut, () => setPressed(false))
|
|
2028
|
+
// Web pointer events. `onTouchStart` reaches the DOM as a real
|
|
2029
|
+
// `touchstart` listener under react-native-web, which a mouse never
|
|
2030
|
+
// fires — so without these a plain `Motion.View` (anything that isn't a
|
|
2031
|
+
// Pressable, i.e. has no `onPressIn` path) was inert under a desktop
|
|
2032
|
+
// click while `Motion.Pressable` worked. Pointer events cover mouse, pen
|
|
2033
|
+
// and touch, so `pressed` means "any pointer" on every platform.
|
|
2034
|
+
//
|
|
2035
|
+
// A web touch fires `touchstart` *and* `pointerdown`; both set the same
|
|
2036
|
+
// boolean to the same value, so the overlap is idempotent, not a
|
|
2037
|
+
// double-toggle. React Native has no pointer props, so these are inert
|
|
2038
|
+
// on native and cost nothing there.
|
|
2039
|
+
handlers.onPointerDown = compose(rest.onPointerDown, () =>
|
|
2040
|
+
setPressed(true),
|
|
2041
|
+
)
|
|
2042
|
+
handlers.onPointerUp = compose(rest.onPointerUp, () => setPressed(false))
|
|
2043
|
+
// Fires when the browser takes over the gesture (scroll, drag start) —
|
|
2044
|
+
// without it the pressed layer would stick on after the pointer is gone.
|
|
2045
|
+
handlers.onPointerCancel = compose(rest.onPointerCancel, () =>
|
|
2046
|
+
setPressed(false),
|
|
2047
|
+
)
|
|
2028
2048
|
}
|
|
2029
2049
|
// Mount onFocus/onBlur if either focus sub-state is declared. The two flags
|
|
2030
2050
|
// are independent: `focused` always tracks focus; `focusVisible` only
|
|
@@ -2061,6 +2081,9 @@ function useGestureHandlers(
|
|
|
2061
2081
|
rest.onTouchCancel,
|
|
2062
2082
|
rest.onPressIn,
|
|
2063
2083
|
rest.onPressOut,
|
|
2084
|
+
rest.onPointerDown,
|
|
2085
|
+
rest.onPointerUp,
|
|
2086
|
+
rest.onPointerCancel,
|
|
2064
2087
|
rest.onFocus,
|
|
2065
2088
|
rest.onBlur,
|
|
2066
2089
|
rest.onMouseEnter,
|
package/src/motion/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { MotionFlatList } from './FlatList'
|
|
1
2
|
import { MotionImage } from './Image'
|
|
2
3
|
import { MotionPressable } from './Pressable'
|
|
3
4
|
import { MotionScrollView } from './ScrollView'
|
|
@@ -11,6 +12,7 @@ export {
|
|
|
11
12
|
MotionImage,
|
|
12
13
|
MotionPressable,
|
|
13
14
|
MotionScrollView,
|
|
15
|
+
MotionFlatList,
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
/**
|
|
@@ -23,4 +25,5 @@ export const Motion = {
|
|
|
23
25
|
Image: MotionImage,
|
|
24
26
|
Pressable: MotionPressable,
|
|
25
27
|
ScrollView: MotionScrollView,
|
|
28
|
+
FlatList: MotionFlatList,
|
|
26
29
|
} as const
|
package/src/values/useScroll.ts
CHANGED
|
@@ -11,10 +11,10 @@ export interface UseScrollResult {
|
|
|
11
11
|
/** Vertical scroll offset in points. */
|
|
12
12
|
scrollY: SharedValue<number>
|
|
13
13
|
/**
|
|
14
|
-
* Handler to pass to
|
|
15
|
-
*
|
|
16
|
-
* as a worklet — but the type narrows to the same
|
|
17
|
-
* `onScroll` prop expects so it composes cleanly.
|
|
14
|
+
* Handler to pass to the `onScroll` prop of `Motion.ScrollView` or
|
|
15
|
+
* `Motion.FlatList` (or any other Reanimated animated scroller). The handler
|
|
16
|
+
* is opaque to JS — it runs as a worklet — but the type narrows to the same
|
|
17
|
+
* shape RN's native `onScroll` prop expects so it composes cleanly.
|
|
18
18
|
*/
|
|
19
19
|
onScroll: (event: NativeSyntheticEvent<NativeScrollEvent>) => void
|
|
20
20
|
}
|
|
@@ -47,9 +47,13 @@ export interface UseScrollResult {
|
|
|
47
47
|
* read from any worklet (`useAnimatedStyle`, `useDerivedValue`,
|
|
48
48
|
* `useTransform`) without a JS-thread bounce.
|
|
49
49
|
*
|
|
50
|
-
* Remember to set `scrollEventThrottle={16}` on
|
|
50
|
+
* Remember to set `scrollEventThrottle={16}` on a `Motion.ScrollView` for 60Hz
|
|
51
51
|
* updates — RN's default is to dispatch on every event, which on iOS still
|
|
52
52
|
* means one per frame, but Android benefits from the explicit cap.
|
|
53
|
+
*
|
|
54
|
+
* `Motion.FlatList` needs no such setting — it defaults `scrollEventThrottle`
|
|
55
|
+
* to 1 for you. Prefer it over `Motion.ScrollView` for long or unbounded lists:
|
|
56
|
+
* it virtualizes, and both accept this handler.
|
|
53
57
|
*/
|
|
54
58
|
export function useScroll(): UseScrollResult {
|
|
55
59
|
const scrollX = useSharedValue(0)
|
package/dist/chunk-FWWVHLXB.js
DELETED
package/dist/chunk-K5SI6VXS.js
DELETED