@rootnative/inertia 0.0.10 → 0.0.11
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 +28 -1
- package/README.md +2 -2
- package/dist/{chunk-6FCATUMY.mjs → chunk-2Q6JMDYZ.mjs} +1 -1
- package/dist/chunk-2UREDR4Z.js +8 -0
- package/dist/{chunk-3ZNHPT5Z.js → chunk-3PB27UIE.js} +2 -2
- package/dist/{chunk-JENYDTXH.mjs → chunk-5EYIZG72.mjs} +10 -3
- package/dist/{chunk-Z23AMUSW.mjs → chunk-7RMSLKQQ.mjs} +1 -1
- package/dist/{chunk-7BH3CAO5.mjs → chunk-DT2KVAAO.mjs} +1 -1
- package/dist/{chunk-F4HMCXAX.mjs → chunk-FKJLPYGY.mjs} +2 -2
- package/dist/{chunk-2UGWAB6N.js → chunk-HBURWGCZ.js} +43 -36
- package/dist/chunk-JAJHKJC5.js +8 -0
- package/dist/chunk-JBMTTICC.js +8 -0
- package/dist/{chunk-QXKPIENP.mjs → chunk-JGQ6YRDN.mjs} +1 -1
- package/dist/{chunk-DRA2K53O.mjs → chunk-LHW4VNWD.mjs} +1 -1
- package/dist/{chunk-4EZ5DBL3.js → chunk-NTG6PSGZ.js} +8 -8
- package/dist/{chunk-KXU6VH2Y.js → chunk-QDMSFRQR.js} +4 -4
- package/dist/{chunk-HEAWMZEM.mjs → chunk-QIRKPDXA.mjs} +13 -2
- package/dist/{chunk-N33GSDNQ.js → chunk-QX5JHRZ2.js} +12 -1
- package/dist/{chunk-VKXSL3ZL.js → chunk-R7YD6L3D.js} +2 -2
- package/dist/{chunk-CUHOCONB.mjs → chunk-RO4XFTQ6.mjs} +1 -1
- package/dist/{chunk-OLOSU2BD.mjs → chunk-UGYBFAVY.mjs} +1 -1
- package/dist/{chunk-46766TBM.js → chunk-XLKI2MSD.js} +2 -2
- package/dist/gestureLayer/index.d.mts +2 -2
- package/dist/gestureLayer/index.d.ts +2 -2
- package/dist/gestureLayer/index.js +11 -11
- package/dist/gestureLayer/index.mjs +3 -3
- package/dist/index.d.mts +49 -32
- package/dist/index.d.ts +49 -32
- package/dist/index.js +62 -62
- package/dist/index.mjs +19 -19
- package/dist/motion/FlatList.d.mts +2 -1
- package/dist/motion/FlatList.d.ts +2 -1
- package/dist/motion/FlatList.js +5 -5
- package/dist/motion/FlatList.mjs +4 -4
- package/dist/motion/Image.d.mts +2 -1
- package/dist/motion/Image.d.ts +2 -1
- package/dist/motion/Image.js +5 -5
- package/dist/motion/Image.mjs +4 -4
- package/dist/motion/Pressable.d.mts +2 -1
- package/dist/motion/Pressable.d.ts +2 -1
- package/dist/motion/Pressable.js +5 -5
- package/dist/motion/Pressable.mjs +4 -4
- package/dist/motion/ScrollView.d.mts +2 -1
- package/dist/motion/ScrollView.d.ts +2 -1
- package/dist/motion/ScrollView.js +5 -5
- package/dist/motion/ScrollView.mjs +4 -4
- package/dist/motion/Text.d.mts +2 -1
- package/dist/motion/Text.d.ts +2 -1
- package/dist/motion/Text.js +5 -5
- package/dist/motion/Text.mjs +4 -4
- package/dist/motion/View.d.mts +2 -1
- package/dist/motion/View.d.ts +2 -1
- package/dist/motion/View.js +5 -5
- package/dist/motion/View.mjs +4 -4
- package/dist/touch/index.d.mts +5 -4
- package/dist/touch/index.d.ts +5 -4
- package/dist/touch/index.js +3 -3
- package/dist/touch/index.mjs +1 -1
- package/dist/{types-08mG8fNk.d.mts → types-C5Zbs9MC.d.mts} +12 -1
- package/dist/{types-08mG8fNk.d.ts → types-C5Zbs9MC.d.ts} +12 -1
- package/dist/{useGesture-D1lHeQQ6.d.ts → useGesture-Be0ZhCWj.d.ts} +1 -1
- package/dist/{useGesture-DjszaHWz.d.mts → useGesture-Ve8EGjTr.d.mts} +1 -1
- package/dist/useTranslateStyle-BDrOD97O.d.mts +58 -0
- package/dist/useTranslateStyle-BDrOD97O.d.ts +58 -0
- package/jest-preset.js +31 -2
- package/llms.txt +2 -1
- package/package.json +13 -12
- package/src/index.ts +3 -0
- package/src/internal/boxShadow.ts +24 -2
- package/src/touch/useTouchDrag.ts +5 -3
- package/src/transitions/resolveSequence.ts +42 -2
- package/src/types.ts +14 -1
- package/src/values/index.ts +3 -1
- package/src/values/useColorCascade.ts +3 -3
- package/src/values/useColorTransition.ts +17 -2
- package/src/values/useInterpolatedStyle.ts +8 -1
- package/src/values/useShadow.ts +18 -2
- package/src/values/useTranslateStyle.ts +18 -2
- package/dist/applyBounds-BYGiHrYO.d.mts +0 -18
- package/dist/applyBounds-BYGiHrYO.d.ts +0 -18
- package/dist/chunk-PLKXCJIB.js +0 -8
- package/dist/chunk-UBHQJFUW.js +0 -8
- package/dist/chunk-XKNEQDAT.js +0 -8
package/jest-preset.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Jest preset for projects consuming `@rootnative/inertia` and its sibling
|
|
2
2
|
// adapter packages (`@rootnative/inertia-gestures`, `-gradients`, `-svg`).
|
|
3
3
|
//
|
|
4
|
-
// Layered on top of
|
|
4
|
+
// Layered on top of `@react-native/jest-preset`. Adds:
|
|
5
5
|
// - the `react-native-worklets` + Reanimated mock surface Inertia exercises
|
|
6
6
|
// (worklet stubs, animation primitives, color/layout utilities)
|
|
7
7
|
// - `transformIgnorePatterns` widened so Jest transforms the published
|
|
@@ -19,7 +19,36 @@
|
|
|
19
19
|
// If you need to allowlist additional packages for transformation, extend
|
|
20
20
|
// `transformIgnorePatterns` in your own config — Jest merges over the preset.
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
// This package is deliberately **not** declared as a peer dependency of
|
|
23
|
+
// `@rootnative/inertia`. React Native pins it to an exact version (RN 0.86.3
|
|
24
|
+
// requires exactly `@react-native/jest-preset@0.86.3`), so any range we
|
|
25
|
+
// declared would advertise versions that cannot install — the sdk-compat range
|
|
26
|
+
// audit fails on it — and an exact pin would break on every RN patch. The
|
|
27
|
+
// version relationship belongs to `react-native`, which already declares it.
|
|
28
|
+
//
|
|
29
|
+
// Resolve `@react-native/jest-preset` directly rather than through the
|
|
30
|
+
// `react-native/jest-preset` shim. RN 0.86 moved the preset into its own
|
|
31
|
+
// package and left the old path as a shim that re-exports it — but it declares
|
|
32
|
+
// the new package as an **optional** peer, and no package manager installs an
|
|
33
|
+
// optional peer. So on RN 0.86 the shim throws a migration error for any
|
|
34
|
+
// consumer who has not installed it by hand, which is what a consumer of this
|
|
35
|
+
// preset would have hit. Requiring it here means the failure names this
|
|
36
|
+
// package's requirement instead.
|
|
37
|
+
let rnPreset
|
|
38
|
+
try {
|
|
39
|
+
rnPreset = require('@react-native/jest-preset')
|
|
40
|
+
} catch (error) {
|
|
41
|
+
if (error.code === 'MODULE_NOT_FOUND') {
|
|
42
|
+
throw new Error(
|
|
43
|
+
'[inertia] `@rootnative/inertia/jest-preset` needs `@react-native/jest-preset`.\n' +
|
|
44
|
+
'React Native 0.86 moved its Jest preset into that package and declares\n' +
|
|
45
|
+
'it as an optional peer, so it is not installed for you. Add it as a\n' +
|
|
46
|
+
'devDependency at the version matching your react-native:\n\n' +
|
|
47
|
+
' npm install --save-dev @react-native/jest-preset\n',
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
throw error
|
|
51
|
+
}
|
|
23
52
|
|
|
24
53
|
module.exports = {
|
|
25
54
|
...rnPreset,
|
package/llms.txt
CHANGED
|
@@ -88,7 +88,8 @@ import { MotionFlatList } from '@rootnative/inertia/flat-list'
|
|
|
88
88
|
- `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.
|
|
89
89
|
- `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).
|
|
90
90
|
- `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.
|
|
91
|
-
- `TRANSPARENT` — `'rgba(0, 0, 0, 0)'`, the value to seed a colour shared value with when a custom component has no other source.
|
|
91
|
+
- `TRANSPARENT` — `'rgba(0, 0, 0, 0)'`, the value to seed a colour shared value with when a custom component has no other source. It exists because Reanimated up to 4.4 mapped the CSS keyword `'transparent'` to `undefined` in its colour table, making it the one name `isColor()` rejected: a slot resting at it could not be animated away from, and under `withSpring` (the default) the animation never settled. **Reanimated 4.5 fixed that** — the keyword now maps to a real packed colour — so within the supported peer band (`>=4.5.0 <4.6.0`) either spelling animates. The constant stays exported as an explicit, unambiguous seed and as the safe choice for code that may run against an older Reanimated.
|
|
92
|
+
- `TranslateStyle` / `ColorStyle` / `ShadowStyle` (types) — what `useTranslateStyle`, `useColorTransition` / `useColorCascade`, and `useShadow` return. Plain style objects, **not** Reanimated's branded `AnimatedStyleHandle`: Reanimated 4.5 brands the value `useAnimatedStyle` returns, and a branded value is rejected inside a `StyleProp` array, so stating the plain shape is what keeps a style-array call site cast-free. Same reasoning as `InterpolatedStyle<K>` above. The brand is compile-time only — the value is still the animated style Reanimated produced.
|
|
92
93
|
- `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`.
|
|
93
94
|
- `@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`.
|
|
94
95
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rootnative/inertia",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.11",
|
|
4
4
|
"description": "Declarative animation primitives for React Native, built on react-native-reanimated.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "RootNative",
|
|
@@ -126,10 +126,10 @@
|
|
|
126
126
|
],
|
|
127
127
|
"peerDependencies": {
|
|
128
128
|
"@testing-library/react-native": ">=13.0.0",
|
|
129
|
-
"react": ">=19.0.0",
|
|
130
|
-
"react-native": ">=0.
|
|
131
|
-
"react-native-reanimated": ">=4.0.0",
|
|
132
|
-
"react-native-worklets": ">=0.
|
|
129
|
+
"react": ">=19.2.3 <20.0.0",
|
|
130
|
+
"react-native": ">=0.83.0 <0.87.0",
|
|
131
|
+
"react-native-reanimated": ">=4.5.0 <4.6.0",
|
|
132
|
+
"react-native-worklets": ">=0.10.0 <0.11.0"
|
|
133
133
|
},
|
|
134
134
|
"peerDependenciesMeta": {
|
|
135
135
|
"@testing-library/react-native": {
|
|
@@ -137,17 +137,18 @@
|
|
|
137
137
|
}
|
|
138
138
|
},
|
|
139
139
|
"devDependencies": {
|
|
140
|
-
"@react-native/babel-preset": "^0.
|
|
140
|
+
"@react-native/babel-preset": "^0.86.3",
|
|
141
|
+
"@react-native/jest-preset": "^0.86.3",
|
|
141
142
|
"@size-limit/preset-small-lib": "^11.1.0",
|
|
142
143
|
"@testing-library/react-native": "^13.3.3",
|
|
143
144
|
"@types/jest": "^29.5.14",
|
|
144
|
-
"@types/react": "^19.
|
|
145
|
+
"@types/react": "^19.2.0",
|
|
145
146
|
"jest": "^29.7.0",
|
|
146
|
-
"react": "19.
|
|
147
|
-
"react-native": "0.
|
|
148
|
-
"react-native-reanimated": "
|
|
149
|
-
"react-native-worklets": "
|
|
150
|
-
"react-test-renderer": "19.
|
|
147
|
+
"react": "19.2.3",
|
|
148
|
+
"react-native": "0.86.3",
|
|
149
|
+
"react-native-reanimated": "4.5.1",
|
|
150
|
+
"react-native-worklets": "0.10.1",
|
|
151
|
+
"react-test-renderer": "19.2.3",
|
|
151
152
|
"size-limit": "^11.1.0",
|
|
152
153
|
"tsup": "^8.3.5",
|
|
153
154
|
"typescript": "^5.7.3"
|
package/src/index.ts
CHANGED
|
@@ -79,12 +79,15 @@ export type {
|
|
|
79
79
|
Animator,
|
|
80
80
|
BoxShadowLayer,
|
|
81
81
|
ColorCascadeLayer,
|
|
82
|
+
ColorStyle,
|
|
82
83
|
ColorStyleKey,
|
|
83
84
|
ExtrapolationMode,
|
|
84
85
|
InterpolatedStyle,
|
|
85
86
|
InterpolatedStyleMap,
|
|
87
|
+
TranslateStyle,
|
|
86
88
|
NumericStyleKey,
|
|
87
89
|
ShadowConfig,
|
|
90
|
+
ShadowStyle,
|
|
88
91
|
TransformKey,
|
|
89
92
|
UseColorCascadeOptions,
|
|
90
93
|
UseColorTransitionOptions,
|
|
@@ -164,7 +164,7 @@ export function resolveBoxShadowInput(
|
|
|
164
164
|
offsetY: coerceLength(layer.offsetY, 'offsetY'),
|
|
165
165
|
blurRadius: coerceLength(layer.blurRadius, 'blurRadius'),
|
|
166
166
|
spreadDistance: coerceLength(layer.spreadDistance, 'spreadDistance'),
|
|
167
|
-
color: layer.color
|
|
167
|
+
color: coerceColor(layer.color),
|
|
168
168
|
inset: layer.inset ?? false,
|
|
169
169
|
}))
|
|
170
170
|
}
|
|
@@ -273,7 +273,10 @@ export type BoxShadowInput =
|
|
|
273
273
|
// rejected) by `coerceLength` like every other length.
|
|
274
274
|
blurRadius?: unknown
|
|
275
275
|
spreadDistance?: number | string | undefined
|
|
276
|
-
|
|
276
|
+
// `unknown` because RN 0.86 widened this from `string` to `ColorValue`,
|
|
277
|
+
// which includes the opaque handle `PlatformColor()` returns. Coerced
|
|
278
|
+
// (and rejected) by `coerceColor`.
|
|
279
|
+
color?: unknown
|
|
277
280
|
inset?: boolean | undefined
|
|
278
281
|
}>
|
|
279
282
|
|
|
@@ -284,6 +287,25 @@ export type BoxShadowInput =
|
|
|
284
287
|
* `parseBoxShadow` — px and unitless only, and anything else throws rather
|
|
285
288
|
* than silently animating from a `NaN`.
|
|
286
289
|
*/
|
|
290
|
+
/**
|
|
291
|
+
* Coerce one RN colour field to a string.
|
|
292
|
+
*
|
|
293
|
+
* RN 0.86 widened `BoxShadowValue.color` from `string` to `ColorValue`, which
|
|
294
|
+
* admits the opaque handle `PlatformColor()` and `DynamicColorIOS()` return.
|
|
295
|
+
* That handle is a platform reference, not a colour this code can read, so it
|
|
296
|
+
* cannot be interpolated. Reject it here with a message that names the cause,
|
|
297
|
+
* rather than letting it reach the worklet and animate to `NaN`.
|
|
298
|
+
*/
|
|
299
|
+
function coerceColor(value: unknown): string {
|
|
300
|
+
if (value === undefined) return 'black'
|
|
301
|
+
if (typeof value === 'string') return value
|
|
302
|
+
throw new Error(
|
|
303
|
+
'[inertia] boxShadow: color must be a colour string, got ' +
|
|
304
|
+
`${typeof value}. PlatformColor and DynamicColorIOS values cannot be ` +
|
|
305
|
+
'interpolated — pass a string colour on an animated shadow.',
|
|
306
|
+
)
|
|
307
|
+
}
|
|
308
|
+
|
|
287
309
|
function coerceLength(value: unknown, field: string): number {
|
|
288
310
|
if (value === undefined) return 0
|
|
289
311
|
if (typeof value === 'number') return value
|
|
@@ -5,9 +5,11 @@ import {
|
|
|
5
5
|
type PanResponderInstance,
|
|
6
6
|
} from 'react-native'
|
|
7
7
|
import { useSharedValue, type SharedValue } from 'react-native-reanimated'
|
|
8
|
-
import type { useAnimatedStyle } from 'react-native-reanimated'
|
|
9
8
|
import { buildReleaseAnimation } from '../transitions'
|
|
10
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
useTranslateStyle,
|
|
11
|
+
type TranslateStyle,
|
|
12
|
+
} from '../values/useTranslateStyle'
|
|
11
13
|
import { applyBounds } from './applyBounds'
|
|
12
14
|
import type { TransitionConfig } from '../types'
|
|
13
15
|
|
|
@@ -22,7 +24,7 @@ export interface UseTouchDragResult {
|
|
|
22
24
|
/** Spread onto a `View` / `Pressable` to install the pan responder. */
|
|
23
25
|
panHandlers: PanResponderInstance['panHandlers']
|
|
24
26
|
/** Stable animated `transform` style. */
|
|
25
|
-
animatedStyle:
|
|
27
|
+
animatedStyle: TranslateStyle
|
|
26
28
|
/** Live x translation, persistent across gestures. */
|
|
27
29
|
dragX: SharedValue<number>
|
|
28
30
|
/** Live y translation, persistent across gestures. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { withSequence } from 'react-native-reanimated'
|
|
1
|
+
import { withSequence, withTiming } from 'react-native-reanimated'
|
|
2
2
|
import {
|
|
3
3
|
applyRepeat,
|
|
4
4
|
repeatOf,
|
|
@@ -13,6 +13,18 @@ import {
|
|
|
13
13
|
type TransitionConfig,
|
|
14
14
|
} from '../types'
|
|
15
15
|
|
|
16
|
+
/** A zero-length timing, for a snapped step inside an animated sequence. */
|
|
17
|
+
const INSTANT = { duration: 0 } as const
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* True when a resolved step is a bare target rather than a Reanimated
|
|
21
|
+
* animation object. `buildOne` returns the target itself for `no-animation`,
|
|
22
|
+
* which is what the reduced-motion gate collapses every step to.
|
|
23
|
+
*/
|
|
24
|
+
function isSnapped(step: unknown): step is number | string {
|
|
25
|
+
return typeof step === 'number' || typeof step === 'string'
|
|
26
|
+
}
|
|
27
|
+
|
|
16
28
|
/**
|
|
17
29
|
* True when the value is a `{ to, ...transitionOverride }` sequence step.
|
|
18
30
|
* Plain numbers and plain transition objects fail this check.
|
|
@@ -37,6 +49,12 @@ function isStepObject<V>(
|
|
|
37
49
|
* 3. array of either → `withSequence` of resolved steps, with the
|
|
38
50
|
* top-level `repeat` applied at the **sequence level** (not per step).
|
|
39
51
|
* Per-step `repeat` overrides remain step-local.
|
|
52
|
+
*
|
|
53
|
+
* `withSequence` writes a `finished` flag onto each argument it is handed, so
|
|
54
|
+
* a bare target throws `Cannot create property 'finished' on number` and takes
|
|
55
|
+
* the whole render down with it. Two paths produce bare targets, and both are
|
|
56
|
+
* handled below rather than at the call site: reduced motion (every step) and
|
|
57
|
+
* a per-step `{ type: 'no-animation' }` override (some steps).
|
|
40
58
|
*/
|
|
41
59
|
export function resolveAnimatableValue<V extends number | string>(
|
|
42
60
|
value: AnimatableValue<V>,
|
|
@@ -49,7 +67,29 @@ export function resolveAnimatableValue<V extends number | string>(
|
|
|
49
67
|
const animations = steps.map((step, i) =>
|
|
50
68
|
resolveStep(step, stepBase, factory?.('step', i)),
|
|
51
69
|
)
|
|
52
|
-
|
|
70
|
+
// The reduced-motion gate. `mergeTransition` hands a `no-animation` base
|
|
71
|
+
// back untouched for every step, so the whole sequence is a snap and there
|
|
72
|
+
// is nothing to sequence. Settle on the last step — where the sequence
|
|
73
|
+
// would have ended. `repeat` and `delay` are already dropped for
|
|
74
|
+
// `no-animation` (`repeatOf` and `delayOf` both return `undefined`), so
|
|
75
|
+
// nothing needs to wrap this.
|
|
76
|
+
//
|
|
77
|
+
// Read off the config rather than sniffing the resolved values: under the
|
|
78
|
+
// Jest mock `withSpring` and `withTiming` also return bare targets, so a
|
|
79
|
+
// shape test reports every sequence as snapped and the gate stops being
|
|
80
|
+
// observable in either direction.
|
|
81
|
+
if (stepBase?.type === 'no-animation' && animations.length > 0) {
|
|
82
|
+
return animations[animations.length - 1]
|
|
83
|
+
}
|
|
84
|
+
// A step that declares `{ type: 'no-animation' }` inside a sequence that
|
|
85
|
+
// otherwise animates resolves to a bare target of its own. The step still
|
|
86
|
+
// owns its slot in the order, so it becomes an instant timing rather than
|
|
87
|
+
// being dropped.
|
|
88
|
+
const seq = withSequence(
|
|
89
|
+
...(animations.map((a) =>
|
|
90
|
+
isSnapped(a) ? withTiming(a as number, INSTANT) : a,
|
|
91
|
+
) as never[]),
|
|
92
|
+
)
|
|
53
93
|
return applyRepeat(seq, base ? repeatOf(base) : undefined, {
|
|
54
94
|
sequence: true,
|
|
55
95
|
})
|
package/src/types.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
type Ref,
|
|
6
6
|
} from 'react'
|
|
7
7
|
import { type BoxShadowValue, type StyleProp } from 'react-native'
|
|
8
|
+
import { type AnimatedProps } from 'react-native-reanimated'
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* A single animation step's destination, optionally overriding the transition
|
|
@@ -555,6 +556,14 @@ export interface MotionProps<C, V extends VariantsMap<C> = VariantsMap<C>> {
|
|
|
555
556
|
* Props of a Motion primitive for a given underlying component `C` and a
|
|
556
557
|
* concrete variants map `V`: the component's own props (minus `style`, which
|
|
557
558
|
* we replace with an animated style) intersected with the Motion props.
|
|
559
|
+
*
|
|
560
|
+
* `style` is taken from `AnimatedProps<…>`, not from `C` directly, because a
|
|
561
|
+
* Motion primitive renders `Animated.createAnimatedComponent(C)` — so the
|
|
562
|
+
* styles it accepts are the ones that animated component accepts. Reanimated
|
|
563
|
+
* 4.5 brands what `useAnimatedStyle` returns, and `ComponentProps<C>['style']`
|
|
564
|
+
* rejects a branded value, which would have made the sanctioned escape hatch
|
|
565
|
+
* (Principle 2: own your `useAnimatedStyle` over Inertia-driven shared values,
|
|
566
|
+
* then pass it to a `Motion.*` primitive) require a cast at every call site.
|
|
558
567
|
*/
|
|
559
568
|
export type MotionComponentProps<
|
|
560
569
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -562,7 +571,11 @@ export type MotionComponentProps<
|
|
|
562
571
|
V extends VariantsMap<ComponentProps<C>> = VariantsMap<ComponentProps<C>>,
|
|
563
572
|
> = Omit<ComponentProps<C>, 'style'> &
|
|
564
573
|
MotionProps<ComponentProps<C>, V> & {
|
|
565
|
-
style?: ComponentProps<C
|
|
574
|
+
style?: AnimatedProps<ComponentProps<C>> extends {
|
|
575
|
+
style?: infer S
|
|
576
|
+
}
|
|
577
|
+
? S
|
|
578
|
+
: ComponentProps<C>['style']
|
|
566
579
|
ref?: Ref<unknown>
|
|
567
580
|
}
|
|
568
581
|
|
package/src/values/index.ts
CHANGED
|
@@ -8,6 +8,7 @@ export {
|
|
|
8
8
|
} from './useColorCascade'
|
|
9
9
|
export {
|
|
10
10
|
useColorTransition,
|
|
11
|
+
type ColorStyle,
|
|
11
12
|
type ColorStyleKey,
|
|
12
13
|
type UseColorTransitionOptions,
|
|
13
14
|
} from './useColorTransition'
|
|
@@ -36,7 +37,8 @@ export {
|
|
|
36
37
|
useShadow,
|
|
37
38
|
type BoxShadowLayer,
|
|
38
39
|
type ShadowConfig,
|
|
40
|
+
type ShadowStyle,
|
|
39
41
|
type UseShadowOptions,
|
|
40
42
|
} from './useShadow'
|
|
41
|
-
export { useTranslateStyle } from './useTranslateStyle'
|
|
43
|
+
export { useTranslateStyle, type TranslateStyle } from './useTranslateStyle'
|
|
42
44
|
export { useVariants } from './useVariants'
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
useAnimatedStyle,
|
|
5
5
|
type SharedValue,
|
|
6
6
|
} from 'react-native-reanimated'
|
|
7
|
-
import type { ColorStyleKey } from './useColorTransition'
|
|
7
|
+
import type { ColorStyle, ColorStyleKey } from './useColorTransition'
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* One layer in a color cascade: its own `progress` shared value (0→1) and the
|
|
@@ -70,7 +70,7 @@ export function useColorCascade(
|
|
|
70
70
|
rest: string,
|
|
71
71
|
layers: readonly ColorCascadeLayer[],
|
|
72
72
|
options?: UseColorCascadeOptions,
|
|
73
|
-
):
|
|
73
|
+
): ColorStyle {
|
|
74
74
|
const key = options?.key ?? 'backgroundColor'
|
|
75
75
|
|
|
76
76
|
// Resolve the layer chain into two flat arrays the worklet closes over — the
|
|
@@ -121,5 +121,5 @@ export function useColorCascade(
|
|
|
121
121
|
)
|
|
122
122
|
}
|
|
123
123
|
return { [key]: acc }
|
|
124
|
-
})
|
|
124
|
+
}) as unknown as ColorStyle
|
|
125
125
|
}
|
|
@@ -20,6 +20,21 @@ export type ColorStyleKey =
|
|
|
20
20
|
| 'tintColor'
|
|
21
21
|
| 'shadowColor'
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* A one-key colour style fragment, as returned by {@link useColorTransition}
|
|
25
|
+
* and {@link useColorCascade}.
|
|
26
|
+
*
|
|
27
|
+
* Deliberately **not** `ReturnType<typeof useAnimatedStyle>`. Reanimated 4.5
|
|
28
|
+
* brands that value (`AnimatedStyleHandle`), and a branded type is rejected
|
|
29
|
+
* inside a `StyleProp` array — so every call site would need a cast, which is
|
|
30
|
+
* the defect `InterpolatedStyle` was introduced to remove in `0.0.9`. The brand
|
|
31
|
+
* is compile-time only, so the runtime value is unchanged.
|
|
32
|
+
*
|
|
33
|
+
* Optional per key because which slot is filled is chosen at run time from
|
|
34
|
+
* `options.key`; exactly one is ever present.
|
|
35
|
+
*/
|
|
36
|
+
export type ColorStyle = { [K in ColorStyleKey]?: string }
|
|
37
|
+
|
|
23
38
|
export interface UseColorTransitionOptions {
|
|
24
39
|
/**
|
|
25
40
|
* Which style slot the interpolated color is emitted under. Defaults to
|
|
@@ -56,7 +71,7 @@ export function useColorTransition(
|
|
|
56
71
|
progress: SharedValue<number>,
|
|
57
72
|
range: readonly [string, string],
|
|
58
73
|
options?: UseColorTransitionOptions,
|
|
59
|
-
):
|
|
74
|
+
): ColorStyle {
|
|
60
75
|
// Resolve the slot key once on the JS thread so the worklet body
|
|
61
76
|
// consumes a single string literal — consistent with the JS-thread
|
|
62
77
|
// resolver principle that keeps `Object.keys`-style walks off the UI
|
|
@@ -68,5 +83,5 @@ export function useColorTransition(
|
|
|
68
83
|
return useAnimatedStyle(() => {
|
|
69
84
|
'worklet'
|
|
70
85
|
return { [key]: interpolateColor(progress.value, [0, 1], [from, to]) }
|
|
71
|
-
})
|
|
86
|
+
}) as unknown as ColorStyle
|
|
72
87
|
}
|
|
@@ -308,6 +308,13 @@ export function useInterpolatedStyle<K extends keyof InterpolatedStyleMap>(
|
|
|
308
308
|
// The worklet builds a `Record<string, unknown>` by design — the emitted keys
|
|
309
309
|
// are only known from `entries` at run time. `InterpolatedStyle<K>` is the
|
|
310
310
|
// static statement of that same shape, so the cast is where the two meet.
|
|
311
|
+
//
|
|
312
|
+
// Through `unknown` because Reanimated 4.5 brands what `useAnimatedStyle`
|
|
313
|
+
// returns (`AnimatedStyleHandle`), and a branded type no longer overlaps a
|
|
314
|
+
// plain style object. Erasing the brand is the point of this hook: the
|
|
315
|
+
// returned value has to drop into a `StyleProp<ViewStyle>` array without the
|
|
316
|
+
// consumer casting. The brand is compile-time only, so the runtime value is
|
|
317
|
+
// unchanged — it is still the animated style Reanimated produced.
|
|
311
318
|
return useAnimatedStyle(() => {
|
|
312
319
|
'worklet'
|
|
313
320
|
const out: Record<string, unknown> = {}
|
|
@@ -338,5 +345,5 @@ export function useInterpolatedStyle<K extends keyof InterpolatedStyleMap>(
|
|
|
338
345
|
}
|
|
339
346
|
if (transform.length > 0) out.transform = transform
|
|
340
347
|
return out
|
|
341
|
-
}) as InterpolatedStyle<K>
|
|
348
|
+
}) as unknown as InterpolatedStyle<K>
|
|
342
349
|
}
|
package/src/values/useShadow.ts
CHANGED
|
@@ -43,6 +43,22 @@ export interface ShadowConfig {
|
|
|
43
43
|
boxShadow?: string | readonly BoxShadowLayer[]
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
/**
|
|
47
|
+
* The style fragment {@link useShadow} returns: the native shadow keys plus the
|
|
48
|
+
* CSS `boxShadow`, each present only when the paired configs drive it.
|
|
49
|
+
*
|
|
50
|
+
* Deliberately **not** `ReturnType<typeof useAnimatedStyle>` — see
|
|
51
|
+
* {@link ColorStyle} for why the brand is erased here.
|
|
52
|
+
*/
|
|
53
|
+
export type ShadowStyle = {
|
|
54
|
+
shadowColor?: string
|
|
55
|
+
shadowOffset?: { width: number; height: number }
|
|
56
|
+
shadowOpacity?: number
|
|
57
|
+
shadowRadius?: number
|
|
58
|
+
elevation?: number
|
|
59
|
+
boxShadow?: string
|
|
60
|
+
}
|
|
61
|
+
|
|
46
62
|
export interface UseShadowOptions {
|
|
47
63
|
/** Shadow state at `progress === 0`. */
|
|
48
64
|
from: ShadowConfig
|
|
@@ -97,7 +113,7 @@ export function useShadow({
|
|
|
97
113
|
from,
|
|
98
114
|
to,
|
|
99
115
|
progress,
|
|
100
|
-
}: UseShadowOptions):
|
|
116
|
+
}: UseShadowOptions): ShadowStyle {
|
|
101
117
|
// Resolve presence + endpoints once on the JS thread so the worklet body
|
|
102
118
|
// consumes flat literals — consistent with the JS-thread resolver
|
|
103
119
|
// principle that keeps `Object.keys`-style walks off the UI thread.
|
|
@@ -198,5 +214,5 @@ export function useShadow({
|
|
|
198
214
|
out.boxShadow = css
|
|
199
215
|
}
|
|
200
216
|
return out
|
|
201
|
-
})
|
|
217
|
+
}) as unknown as ShadowStyle
|
|
202
218
|
}
|
|
@@ -1,5 +1,21 @@
|
|
|
1
|
+
import type { ViewStyle } from 'react-native'
|
|
1
2
|
import { useAnimatedStyle, type SharedValue } from 'react-native-reanimated'
|
|
2
3
|
|
|
4
|
+
/**
|
|
5
|
+
* What {@link useTranslateStyle} returns: a plain style object that owns
|
|
6
|
+
* `transform`.
|
|
7
|
+
*
|
|
8
|
+
* Deliberately **not** `ReturnType<typeof useAnimatedStyle>`. Reanimated 4.5
|
|
9
|
+
* brands that value (`AnimatedStyleHandle`), and a branded type is rejected
|
|
10
|
+
* inside a `StyleProp<ViewStyle>` array — so every call site would need a cast,
|
|
11
|
+
* which is the exact defect `InterpolatedStyle` was introduced to remove in
|
|
12
|
+
* `0.0.9`. The brand is compile-time only, so the runtime value is unchanged:
|
|
13
|
+
* it is still the animated style Reanimated produced.
|
|
14
|
+
*/
|
|
15
|
+
export type TranslateStyle = {
|
|
16
|
+
transform: NonNullable<ViewStyle['transform']>
|
|
17
|
+
}
|
|
18
|
+
|
|
3
19
|
/**
|
|
4
20
|
* Animated style that translates by two shared values:
|
|
5
21
|
* `transform: [{ translateX: x }, { translateY: y }]`.
|
|
@@ -24,8 +40,8 @@ import { useAnimatedStyle, type SharedValue } from 'react-native-reanimated'
|
|
|
24
40
|
export function useTranslateStyle(
|
|
25
41
|
x: SharedValue<number>,
|
|
26
42
|
y: SharedValue<number>,
|
|
27
|
-
):
|
|
43
|
+
): TranslateStyle {
|
|
28
44
|
return useAnimatedStyle(() => ({
|
|
29
45
|
transform: [{ translateX: x.value }, { translateY: y.value }],
|
|
30
|
-
}))
|
|
46
|
+
})) as unknown as TranslateStyle
|
|
31
47
|
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Clamp `value` to `[min, max]`. When `elastic > 0` the overshoot past a
|
|
3
|
-
* bound is scaled by `elastic` instead of hard-clamped, giving a rubber-band
|
|
4
|
-
* feel. `min` / `max` may be `undefined` to leave that side unbounded.
|
|
5
|
-
*
|
|
6
|
-
* Worklet, so it runs both inside a gesture-handler pan handler on the UI
|
|
7
|
-
* thread (`useDrag`) and from a JS-thread `PanResponder` callback
|
|
8
|
-
* (`useTouchDrag`).
|
|
9
|
-
*
|
|
10
|
-
* ```ts
|
|
11
|
-
* applyBounds(120, -100, 100, 0) // 100
|
|
12
|
-
* applyBounds(120, -100, 100, 0.5) // 110
|
|
13
|
-
* applyBounds(50, undefined, 100, 0) // 50
|
|
14
|
-
* ```
|
|
15
|
-
*/
|
|
16
|
-
declare function applyBounds(value: number, min: number | undefined, max: number | undefined, elastic: number): number;
|
|
17
|
-
|
|
18
|
-
export { applyBounds as a };
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Clamp `value` to `[min, max]`. When `elastic > 0` the overshoot past a
|
|
3
|
-
* bound is scaled by `elastic` instead of hard-clamped, giving a rubber-band
|
|
4
|
-
* feel. `min` / `max` may be `undefined` to leave that side unbounded.
|
|
5
|
-
*
|
|
6
|
-
* Worklet, so it runs both inside a gesture-handler pan handler on the UI
|
|
7
|
-
* thread (`useDrag`) and from a JS-thread `PanResponder` callback
|
|
8
|
-
* (`useTouchDrag`).
|
|
9
|
-
*
|
|
10
|
-
* ```ts
|
|
11
|
-
* applyBounds(120, -100, 100, 0) // 100
|
|
12
|
-
* applyBounds(120, -100, 100, 0.5) // 110
|
|
13
|
-
* applyBounds(50, undefined, 100, 0) // 50
|
|
14
|
-
* ```
|
|
15
|
-
*/
|
|
16
|
-
declare function applyBounds(value: number, min: number | undefined, max: number | undefined, elastic: number): number;
|
|
17
|
-
|
|
18
|
-
export { applyBounds as a };
|
package/dist/chunk-PLKXCJIB.js
DELETED
package/dist/chunk-UBHQJFUW.js
DELETED
package/dist/chunk-XKNEQDAT.js
DELETED