@rootnative/inertia 0.0.5 → 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 +69 -1
- package/README.md +7 -1
- package/dist/{chunk-OAUWLPQH.mjs → chunk-52QSN2VQ.mjs} +1 -1
- package/dist/{chunk-VQ5D35UA.js → chunk-6V7MOBXO.js} +93 -33
- package/dist/{chunk-RIVVBABB.mjs → chunk-HPJMIBBK.mjs} +93 -34
- package/dist/{chunk-XSK5MNUH.mjs → chunk-KBFN4TRO.mjs} +1 -1
- package/dist/chunk-NPJ46457.js +8 -0
- package/dist/chunk-QJYFTTM2.js +28 -0
- package/dist/{chunk-QQVDZKSD.js → chunk-QYR66E2G.js} +2 -2
- package/dist/{chunk-GTJ6VAH5.mjs → chunk-RUIOM2YZ.mjs} +1 -1
- package/dist/{chunk-27MKBTSG.mjs → chunk-VSK2E35J.mjs} +1 -1
- package/dist/{chunk-27U6766G.js → chunk-WGCF3WQG.js} +2 -2
- package/dist/{chunk-COEJVWRZ.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 +45 -9
- package/dist/index.d.ts +45 -9
- package/dist/index.js +32 -22
- 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 +8 -3
- package/package.json +8 -1
- package/src/index.ts +5 -0
- package/src/internal/boxShadow.ts +71 -9
- package/src/internal/color.ts +70 -0
- package/src/motion/FlatList.tsx +77 -0
- package/src/motion/createMotionComponent.tsx +116 -47
- package/src/motion/index.ts +3 -0
- package/src/values/useScroll.ts +9 -5
- package/dist/chunk-67GHRCF6.js +0 -8
- package/dist/chunk-GPOMFIIU.js +0 -8
- package/dist/chunk-K63LXGKS.js +0 -8
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,13 +64,14 @@ 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.
|
|
67
71
|
- `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.
|
|
68
72
|
- `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).
|
|
69
73
|
- `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.
|
|
74
|
+
- `TRANSPARENT` — `'rgba(0, 0, 0, 0)'`, the value to seed a colour shared value with when a custom component has no other source. Not `'transparent'`: Reanimated's colour table maps that keyword to `undefined`, so it is the one CSS colour name `isColor()` rejects, and a slot resting at it cannot be animated away from — under `withTiming` the target still snaps in at the end, under `withSpring` (the default) the animation never settles. Only affects values passed to `withSpring` / `withTiming`; `interpolateColor` parses the keyword fine, so hooks that interpolate colours themselves are unaffected.
|
|
70
75
|
- `SharedValue<T>` (type) — re-exported from the root entry so props/refs that carry a value-layer hook result can be typed without importing from `react-native-reanimated`.
|
|
71
76
|
- `@rootnative/inertia/reanimated` — render-layer interop subpath: pure re-exports of `Animated`, `createAnimatedComponent`, `useAnimatedStyle`, `useAnimatedProps`, `useDerivedValue`, `interpolate`, `interpolateColor`, `Extrapolation`, `cancelAnimation` (plus `SharedValue` / `DerivedValue` / `AnimatedStyle` / `AnimatedProps` types) under their original Reanimated names, for components that own their own `useAnimatedStyle` worklet over Inertia-driven shared values. Names must stay original — the Reanimated Babel plugin auto-workletizes callbacks by callee name. The `with*` animation factories are deliberately not re-exported; start animations with `useAnimation` / `resolveTransition` / `buildReleaseAnimation`.
|
|
72
77
|
|
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
|
@@ -16,6 +16,7 @@ export {
|
|
|
16
16
|
MotionImage,
|
|
17
17
|
MotionPressable,
|
|
18
18
|
MotionScrollView,
|
|
19
|
+
MotionFlatList,
|
|
19
20
|
createMotionComponent,
|
|
20
21
|
} from './motion'
|
|
21
22
|
export {
|
|
@@ -39,6 +40,10 @@ export {
|
|
|
39
40
|
resolveAnimatableValue,
|
|
40
41
|
ensureWorkletEasing,
|
|
41
42
|
} from './transitions'
|
|
43
|
+
// Seed value for any color shared value a custom animated component drives
|
|
44
|
+
// through `resolveTransition`. Exported because the obvious choice —
|
|
45
|
+
// `'transparent'` — cannot be animated away from; see the symbol's own docs.
|
|
46
|
+
export { TRANSPARENT } from './internal/color'
|
|
42
47
|
export {
|
|
43
48
|
useAnimation,
|
|
44
49
|
useAnimator,
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
* loudly there, not silently render the wrong elevation.
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
+
import { normalizeAnimatableColor, TRANSPARENT } from './color'
|
|
16
|
+
|
|
15
17
|
/**
|
|
16
18
|
* One layer of a `box-shadow`, structurally mirroring React Native's
|
|
17
19
|
* `BoxShadowValue` (RN 0.76+ `boxShadow` style). Lengths are px numbers.
|
|
@@ -205,7 +207,7 @@ function invisibleLayer(inset: boolean): ResolvedBoxShadowLayer {
|
|
|
205
207
|
offsetY: 0,
|
|
206
208
|
blurRadius: 0,
|
|
207
209
|
spreadDistance: 0,
|
|
208
|
-
color:
|
|
210
|
+
color: TRANSPARENT,
|
|
209
211
|
inset,
|
|
210
212
|
}
|
|
211
213
|
}
|
|
@@ -225,10 +227,10 @@ function invisibleLayer(inset: boolean): ResolvedBoxShadowLayer {
|
|
|
225
227
|
* drive, and nothing it can't.
|
|
226
228
|
*
|
|
227
229
|
* `inset` is deliberately absent. `withTiming` / `withSpring` recurse into
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
*
|
|
231
|
-
*
|
|
230
|
+
* objects and animate each leaf, and a boolean leaf falls through to the plain
|
|
231
|
+
* numeric path — `false + (false - false) * p` evaluates to `0`, so an
|
|
232
|
+
* in-flight frame hands the native shadow a number where it expects a boolean.
|
|
233
|
+
* Inset is instead carried alongside as a static per-layer flag (see
|
|
232
234
|
* `SplitBoxShadow.insets`) and reattached when the style is emitted.
|
|
233
235
|
*/
|
|
234
236
|
export interface AnimatedBoxShadowLayer {
|
|
@@ -295,10 +297,16 @@ function coerceLength(value: unknown, field: string): number {
|
|
|
295
297
|
return parseFloat(trimmed)
|
|
296
298
|
}
|
|
297
299
|
|
|
298
|
-
/**
|
|
300
|
+
/**
|
|
301
|
+
* Drop `inset`, leaving only the fields Reanimated may drive, and rewrite a
|
|
302
|
+
* `'transparent'` colour to its RGBA spelling — see {@link TRANSPARENT} for
|
|
303
|
+
* why the CSS keyword cannot be animated. Done here rather than at parse time
|
|
304
|
+
* so the `useShadow` path, which interpolates colours itself and accepts the
|
|
305
|
+
* keyword happily, keeps the consumer's own spelling.
|
|
306
|
+
*/
|
|
299
307
|
function strip(layer: ResolvedBoxShadowLayer): AnimatedBoxShadowLayer {
|
|
300
|
-
const { inset: _inset, ...rest } = layer
|
|
301
|
-
return rest
|
|
308
|
+
const { inset: _inset, color, ...rest } = layer
|
|
309
|
+
return { ...rest, color: normalizeAnimatableColor(color) }
|
|
302
310
|
}
|
|
303
311
|
|
|
304
312
|
/**
|
|
@@ -335,7 +343,7 @@ export function normalizeBoxShadow(input: BoxShadowInput): SplitBoxShadow {
|
|
|
335
343
|
* Prepare a from/to pair for a Reanimated-driven `boxShadow` animation.
|
|
336
344
|
*
|
|
337
345
|
* Both sides come back padded to the same layer count, because Reanimated's
|
|
338
|
-
* `
|
|
346
|
+
* `objectOnStart` walks the **current** value's keys and reads `toValue[key]`
|
|
339
347
|
* for each — a target with fewer layers leaves the surplus leaves with
|
|
340
348
|
* `toValue: undefined`, and a target with more never animates the extras at
|
|
341
349
|
* all. `pairBoxShadowLayers` supplies the padding (a transparent zero layer,
|
|
@@ -373,3 +381,57 @@ export function prepareBoxShadowAnimation(
|
|
|
373
381
|
}
|
|
374
382
|
return { from, to, insets }
|
|
375
383
|
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* The shape a `boxShadow` shared value actually holds: layers keyed by their
|
|
387
|
+
* index (`{ 0: layer, 1: layer }`) rather than an array.
|
|
388
|
+
*
|
|
389
|
+
* **This is not cosmetic, and an array does not work here.** Reanimated's
|
|
390
|
+
* animation drivers walk a structured value by dispatching on each leaf's
|
|
391
|
+
* runtime shape, but the two container branches are not symmetrical
|
|
392
|
+
* (`animation/util.ts`):
|
|
393
|
+
*
|
|
394
|
+
* - `objectOnStart` re-assigns the **decorated** `onStart` onto each child
|
|
395
|
+
* (`animation[key].onStart = animation.onStart`), so a child that is itself
|
|
396
|
+
* an object or a colour is dispatched again, recursively.
|
|
397
|
+
* - `arrayOnStart` does not. Each element gets the **base** scalar `onStart`,
|
|
398
|
+
* so anything other than a number is handed straight to the spring/timing
|
|
399
|
+
* maths. A layer object yields `object - object` → `NaN`; a colour string
|
|
400
|
+
* yields the same.
|
|
401
|
+
*
|
|
402
|
+
* The failure is silent and total: `withTiming` still snaps to the target when
|
|
403
|
+
* its duration elapses, so an array *looks* like it works, while `withSpring`
|
|
404
|
+
* — Inertia's default — decides it has settled only when
|
|
405
|
+
* `isAnimationTerminatingCalculation` says so, and every comparison against
|
|
406
|
+
* `NaN` is false. The animation never finishes, the shared value holds
|
|
407
|
+
* `'[object Object]NaN'` forever, `onAnimationEnd` never fires, and the frame
|
|
408
|
+
* loop never stops.
|
|
409
|
+
*
|
|
410
|
+
* Keying by index sends the layer list down the object branch, where the
|
|
411
|
+
* recursion works and each layer's colour reaches the RGBA-channel path.
|
|
412
|
+
*/
|
|
413
|
+
export type BoxShadowPayload = Record<string, AnimatedBoxShadowLayer>
|
|
414
|
+
|
|
415
|
+
/** Index-key a layer list into the shape a shared value can animate. */
|
|
416
|
+
export function layersToPayload(
|
|
417
|
+
layers: readonly AnimatedBoxShadowLayer[],
|
|
418
|
+
): BoxShadowPayload {
|
|
419
|
+
const payload: BoxShadowPayload = {}
|
|
420
|
+
for (let i = 0; i < layers.length; i++) payload[i] = layers[i]!
|
|
421
|
+
return payload
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Read an index-keyed payload back out as a layer list.
|
|
426
|
+
*
|
|
427
|
+
* Callable from a worklet: the loop stops at the first missing index rather
|
|
428
|
+
* than asking for the key set, so no `Object.keys` runs at frame time.
|
|
429
|
+
*/
|
|
430
|
+
export function payloadToLayers(
|
|
431
|
+
payload: BoxShadowPayload,
|
|
432
|
+
): AnimatedBoxShadowLayer[] {
|
|
433
|
+
'worklet'
|
|
434
|
+
const layers: AnimatedBoxShadowLayer[] = []
|
|
435
|
+
for (let i = 0; payload[i] !== undefined; i++) layers.push(payload[i]!)
|
|
436
|
+
return layers
|
|
437
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one colour spelling Reanimated's animation drivers cannot accept.
|
|
3
|
+
*
|
|
4
|
+
* Reanimated dispatches an animation on the runtime shape of its **source**
|
|
5
|
+
* value, and `isColor()` is the gate for the RGBA-channel path. That gate is
|
|
6
|
+
* `processColorInitially(value) != null`, and Reanimated's colour-name table
|
|
7
|
+
* (`Colors.ts`) maps `transparent` to `undefined` — every other CSS colour
|
|
8
|
+
* name maps to a packed integer. So `'transparent'` is the single named colour
|
|
9
|
+
* that reports **false**.
|
|
10
|
+
*
|
|
11
|
+
* A value that fails the gate but is still a string falls to the
|
|
12
|
+
* prefix-number-suffix branch, which exists for values like `'100%'`. It runs
|
|
13
|
+
* `parseFloat('transparent')` → `NaN`, animates that, and re-attaches the
|
|
14
|
+
* prefix, so the slot fills with `'transparentNaN'`. Under `withTiming` the
|
|
15
|
+
* animation still snaps to its target when the duration elapses, which hides
|
|
16
|
+
* the fault; under `withSpring` — the library default — settling is decided by
|
|
17
|
+
* comparisons against `NaN`, which are all false, so the animation runs
|
|
18
|
+
* forever and the colour never appears.
|
|
19
|
+
*
|
|
20
|
+
* `'rgba(0, 0, 0, 0)'` is the same colour and passes the gate.
|
|
21
|
+
*
|
|
22
|
+
* This only applies to values handed to `withSpring` / `withTiming`.
|
|
23
|
+
* `interpolateColor` parses `'transparent'` correctly, which is why the
|
|
24
|
+
* gesture cascade, the shared-element carry, and `useShadow` are unaffected
|
|
25
|
+
* and keep the consumer's own spelling.
|
|
26
|
+
*/
|
|
27
|
+
export const TRANSPARENT = 'rgba(0, 0, 0, 0)'
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Rewrite `'transparent'` to a spelling Reanimated recognises. Any other value
|
|
31
|
+
* — a different colour, a number, a non-string — is returned untouched, by
|
|
32
|
+
* reference, so this costs nothing on the overwhelmingly common path.
|
|
33
|
+
*/
|
|
34
|
+
export function normalizeAnimatableColor<T>(value: T): T | string {
|
|
35
|
+
return value === 'transparent' ? TRANSPARENT : value
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Apply {@link normalizeAnimatableColor} across a whole `animate` target for a
|
|
40
|
+
* colour key, including the sequence forms — a keyframe array whose entries are
|
|
41
|
+
* either raw values or `{ to, ...transitionOverride }` step objects.
|
|
42
|
+
*
|
|
43
|
+
* Returns the input by reference when nothing needed rewriting, so an
|
|
44
|
+
* unaffected target neither allocates nor breaks any identity a caller relies
|
|
45
|
+
* on.
|
|
46
|
+
*/
|
|
47
|
+
export function normalizeAnimatableColorTarget<T>(target: T): T {
|
|
48
|
+
if (typeof target === 'string') {
|
|
49
|
+
return normalizeAnimatableColor(target) as T
|
|
50
|
+
}
|
|
51
|
+
if (!Array.isArray(target)) return target
|
|
52
|
+
|
|
53
|
+
let changed = false
|
|
54
|
+
const next = target.map((step) => {
|
|
55
|
+
if (step === 'transparent') {
|
|
56
|
+
changed = true
|
|
57
|
+
return TRANSPARENT
|
|
58
|
+
}
|
|
59
|
+
if (
|
|
60
|
+
step !== null &&
|
|
61
|
+
typeof step === 'object' &&
|
|
62
|
+
(step as { to?: unknown }).to === 'transparent'
|
|
63
|
+
) {
|
|
64
|
+
changed = true
|
|
65
|
+
return { ...(step as object), to: TRANSPARENT }
|
|
66
|
+
}
|
|
67
|
+
return step
|
|
68
|
+
})
|
|
69
|
+
return (changed ? next : target) as T
|
|
70
|
+
}
|