@rootnative/inertia 0.0.0-alpha.4 → 0.0.0-alpha.6
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 +22 -0
- package/dist/{chunk-5I3G43XA.js → chunk-2HYD2ZBK.js} +2 -2
- package/dist/chunk-3UTJJ4A3.js +8 -0
- package/dist/{chunk-Q6ZTMLTI.js → chunk-4PEHWDAZ.js} +7 -7
- package/dist/chunk-4QGXK6TF.js +8 -0
- package/dist/{chunk-WPPLZNM4.mjs → chunk-6SMPIOIC.mjs} +1 -1
- package/dist/{chunk-6EP3S2PN.js → chunk-7AOERN53.js} +3 -3
- package/dist/{chunk-6UQ4KA6V.js → chunk-7UDYEFBU.js} +22 -22
- package/dist/{chunk-K4KR5BIS.mjs → chunk-ALRHDFZE.mjs} +1 -1
- package/dist/{chunk-QQJSBIXV.mjs → chunk-CWLFUYIY.mjs} +1 -1
- package/dist/{chunk-6FENLMCA.mjs → chunk-CY7Y64C3.mjs} +17 -1
- package/dist/{chunk-I76OC6RX.mjs → chunk-DWCLIBYO.mjs} +2 -2
- package/dist/{chunk-IJNVUM5U.mjs → chunk-JVBXPF2G.mjs} +1 -1
- package/dist/{chunk-OBE7KTMK.mjs → chunk-NXDJZD6A.mjs} +1 -1
- package/dist/{chunk-SFRNO6AW.js → chunk-PTRF47DA.js} +17 -0
- package/dist/{chunk-L2EVRKSC.mjs → chunk-R63GIUNU.mjs} +1 -1
- package/dist/{chunk-ZQUCQRZT.mjs → chunk-RGNX6UZN.mjs} +2 -2
- package/dist/{chunk-OM5FXU4I.js → chunk-TDSO63CJ.js} +2 -2
- package/dist/chunk-Z7HIOFKQ.js +8 -0
- package/dist/gestureLayer/index.js +10 -10
- package/dist/gestureLayer/index.mjs +3 -3
- package/dist/index.d.mts +78 -13
- package/dist/index.d.ts +78 -13
- package/dist/index.js +202 -44
- package/dist/index.mjs +178 -20
- package/dist/motion/Image.js +5 -5
- package/dist/motion/Image.mjs +4 -4
- package/dist/motion/Pressable.js +5 -5
- package/dist/motion/Pressable.mjs +4 -4
- package/dist/motion/ScrollView.js +5 -5
- package/dist/motion/ScrollView.mjs +4 -4
- package/dist/motion/Text.js +5 -5
- package/dist/motion/Text.mjs +4 -4
- package/dist/motion/View.js +5 -5
- package/dist/motion/View.mjs +4 -4
- package/dist/touch/index.js +3 -3
- package/dist/touch/index.mjs +1 -1
- package/llms.txt +1 -1
- package/package.json +2 -2
- package/src/index.ts +1 -0
- package/src/internal/boxShadow.ts +204 -0
- package/src/internal/nonWorkletWarning.ts +41 -0
- package/src/layout/resolveLayout.ts +3 -2
- package/src/transitions/easing.ts +13 -8
- package/src/values/index.ts +1 -0
- package/src/values/useShadow.ts +76 -1
- package/src/values/useTransform.ts +28 -12
- package/dist/chunk-NDKVHL3N.js +0 -8
- package/dist/chunk-SCTX5Z7I.js +0 -8
- package/dist/chunk-WZGMAXKC.js +0 -8
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
declare const __DEV__: boolean
|
|
2
|
+
|
|
3
|
+
// The core package intentionally has no Node types — declare the minimal
|
|
4
|
+
// shape needed for the Jest detection below (guarded by a typeof check, so
|
|
5
|
+
// environments without `process` are fine).
|
|
6
|
+
declare const process: { env?: Record<string, string | undefined> } | undefined
|
|
7
|
+
|
|
8
|
+
const warned = new Set<string>()
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Dev-only, once-per-key warning for plain (non-worklet) functions handed to
|
|
12
|
+
* surfaces that need real worklets — `useTransform` transformers and custom
|
|
13
|
+
* `timing.easing` functions.
|
|
14
|
+
*
|
|
15
|
+
* Why this can't be papered over with an auto-wrap: wrapping a plain
|
|
16
|
+
* function in a `'worklet'`-directive closure captures the *function
|
|
17
|
+
* reference*, not the shared values it reads. Even when the consumer's
|
|
18
|
+
* Babel plugin workletizes the wrapper, its `__closure` contains only the
|
|
19
|
+
* opaque JS function — Reanimated cannot extract the shared values read
|
|
20
|
+
* inside it as dependencies (so derived values never refresh), and native
|
|
21
|
+
* builds reject the plain function when the closure is serialized to the UI
|
|
22
|
+
* thread. The only correct authoring is the `'worklet'` directive on the
|
|
23
|
+
* consumer's own function, where *their* Babel pass captures the real
|
|
24
|
+
* closure.
|
|
25
|
+
*
|
|
26
|
+
* Suppressed under Jest: the shared Reanimated/worklets test stubs report
|
|
27
|
+
* every function as non-worklet, which would turn the warning into noise in
|
|
28
|
+
* every consumer's test suite.
|
|
29
|
+
*/
|
|
30
|
+
export function warnNonWorkletOnce(key: string, message: string): void {
|
|
31
|
+
if (!__DEV__) return
|
|
32
|
+
if (typeof process !== 'undefined' && process.env?.JEST_WORKER_ID) return
|
|
33
|
+
if (warned.has(key)) return
|
|
34
|
+
warned.add(key)
|
|
35
|
+
console.warn(message)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** @internal — test-only hook to reset the once-per-key state. */
|
|
39
|
+
export function __resetNonWorkletWarningsForTests(): void {
|
|
40
|
+
warned.clear()
|
|
41
|
+
}
|
|
@@ -13,8 +13,9 @@ export type LayoutProp = boolean | TransitionConfig | undefined
|
|
|
13
13
|
* - `true` → default spring with the library's tuned tension / friction / mass.
|
|
14
14
|
* - `{ type: 'spring', ... }` → spring with react-spring vocabulary, bridged
|
|
15
15
|
* into `springify().damping().stiffness().mass()` via `springToReanimated`.
|
|
16
|
-
* - `{ type: 'timing', ... }` → `.duration().easing()`.
|
|
17
|
-
*
|
|
16
|
+
* - `{ type: 'timing', ... }` → `.duration().easing()`. Custom easing fns
|
|
17
|
+
* must be worklets (Reanimated 3.9+ validates this); plain functions
|
|
18
|
+
* dev-warn via `ensureWorkletEasing`.
|
|
18
19
|
* - `{ type: 'decay', ... }` → silently downgrades to spring; decay doesn't
|
|
19
20
|
* have a clear target for a layout transition.
|
|
20
21
|
*
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
// `isWorkletFunction` lives in `react-native-worklets` (the Reanimated 4 peer
|
|
2
2
|
// dep); Reanimated's own re-export is deprecated.
|
|
3
3
|
import { isWorkletFunction } from 'react-native-worklets'
|
|
4
|
+
import { warnNonWorkletOnce } from '../internal/nonWorkletWarning'
|
|
4
5
|
import { type EasingInput } from '../types'
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Reanimated 3.9+ validates that easing functions used in nested-transition
|
|
8
9
|
* contexts (variants, sequences, per-property maps) are worklets, and crashes
|
|
9
|
-
* with `[Reanimated] The easing function is not a worklet` otherwise.
|
|
10
|
-
* library accepts plain functions on the public surface; this helper wraps
|
|
11
|
-
* them so consumers don't have to think about the worklet boundary.
|
|
10
|
+
* with `[Reanimated] The easing function is not a worklet` otherwise.
|
|
12
11
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* wrapper
|
|
12
|
+
* Custom easing functions MUST therefore be worklets — put the `'worklet'`
|
|
13
|
+
* directive as the function's first statement (Reanimated's built-in
|
|
14
|
+
* `Easing.*` helpers and inertia's `cubicBezier()` already are). A plain
|
|
15
|
+
* function warns in dev and falls back to a directive-wrapped call-through;
|
|
16
|
+
* that wrapper works on web (single-threaded) but its closure holds the
|
|
17
|
+
* opaque plain function, which native builds reject when the transition's
|
|
18
|
+
* config is serialized to the UI thread.
|
|
18
19
|
*
|
|
19
20
|
* Reanimated 4 changed `Easing.bezier(...)` to return an
|
|
20
21
|
* `EasingFunctionFactory` (`{ factory: () => EasingFunction }`) rather than
|
|
@@ -34,6 +35,10 @@ export function ensureWorkletEasing(
|
|
|
34
35
|
// ends up in the transition config.
|
|
35
36
|
const fn = isEasingFactory(easing) ? easing.factory() : easing
|
|
36
37
|
if (isWorkletFunction(fn)) return fn
|
|
38
|
+
warnNonWorkletOnce(
|
|
39
|
+
'timing-easing',
|
|
40
|
+
"[inertia] timing easing: the provided easing function is not a worklet. The fallback wrapper works on web but native builds reject it when the transition runs on the UI thread. Add the 'worklet' directive as the first statement of the easing function, or use Reanimated's Easing.* helpers / inertia's cubicBezier(), which are already worklets.",
|
|
41
|
+
)
|
|
37
42
|
const wrapped = (t: number) => {
|
|
38
43
|
'worklet'
|
|
39
44
|
return fn(t)
|
package/src/values/index.ts
CHANGED
package/src/values/useShadow.ts
CHANGED
|
@@ -4,12 +4,20 @@ import {
|
|
|
4
4
|
useAnimatedStyle,
|
|
5
5
|
type SharedValue,
|
|
6
6
|
} from 'react-native-reanimated'
|
|
7
|
+
import {
|
|
8
|
+
pairBoxShadowLayers,
|
|
9
|
+
resolveBoxShadowInput,
|
|
10
|
+
type BoxShadowLayer,
|
|
11
|
+
} from '../internal/boxShadow'
|
|
12
|
+
|
|
13
|
+
export type { BoxShadowLayer }
|
|
7
14
|
|
|
8
15
|
/**
|
|
9
16
|
* Shape accepted on either end of a `useShadow` tween. Every field is
|
|
10
17
|
* optional — only keys present on at least one side participate in the
|
|
11
18
|
* output style. Mirrors the flat shadow keys on `Motion.View`'s `animate`
|
|
12
|
-
* surface, plus the nested `shadowOffset` source
|
|
19
|
+
* surface, plus the nested `shadowOffset` source and the CSS `boxShadow`
|
|
20
|
+
* surface.
|
|
13
21
|
*/
|
|
14
22
|
export interface ShadowConfig {
|
|
15
23
|
shadowOpacity?: number
|
|
@@ -18,6 +26,19 @@ export interface ShadowConfig {
|
|
|
18
26
|
/** Android elevation. iOS shadow consumers can leave this off. */
|
|
19
27
|
elevation?: number
|
|
20
28
|
shadowColor?: string
|
|
29
|
+
/**
|
|
30
|
+
* CSS `box-shadow` — the shadow surface on web (react-native-web passes
|
|
31
|
+
* it through as CSS) and on React Native 0.76+ new-architecture native.
|
|
32
|
+
* Accepts the CSS string form design systems store elevation tokens in
|
|
33
|
+
* (`'0px 1px 2px rgba(0,0,0,0.3), 0px 1px 3px 1px rgba(0,0,0,0.15)'`;
|
|
34
|
+
* px lengths only) or structured layers. Multi-layer shadows interpolate
|
|
35
|
+
* per layer; when one side has fewer layers, it is padded with invisible
|
|
36
|
+
* layers, CSS-transition style. A malformed string **throws** at render
|
|
37
|
+
* (like `cubicBezier` — token mistakes should fail loudly at setup).
|
|
38
|
+
* The classic `shadow*`/`elevation` keys don't reach the web renderer —
|
|
39
|
+
* provide `boxShadow` alongside them when the tween must show up there.
|
|
40
|
+
*/
|
|
41
|
+
boxShadow?: string | readonly BoxShadowLayer[]
|
|
21
42
|
}
|
|
22
43
|
|
|
23
44
|
export interface UseShadowOptions {
|
|
@@ -56,6 +77,19 @@ export interface UseShadowOptions {
|
|
|
56
77
|
* `shadowColor`, `{ width: 0, height: 0 }` for `shadowOffset`). This is a
|
|
57
78
|
* pure interpolator — to "animate" the shadow, drive `progress` with a
|
|
58
79
|
* spring, timing, or gesture upstream.
|
|
80
|
+
*
|
|
81
|
+
* The classic `shadow*`/`elevation` keys don't render on web. When the
|
|
82
|
+
* tween must show up there (or on RN 0.76+ new-arch native via the CSS
|
|
83
|
+
* shadow model), provide `boxShadow` on both ends — CSS string tokens or
|
|
84
|
+
* structured layers; multi-layer shadows interpolate per layer:
|
|
85
|
+
*
|
|
86
|
+
* ```tsx
|
|
87
|
+
* const shadowStyle = useShadow({
|
|
88
|
+
* from: { boxShadow: theme.elevation.level1 }, // '0px 1px 2px rgba(0,0,0,0.3), 0px 1px 3px 1px rgba(0,0,0,0.15)'
|
|
89
|
+
* to: { boxShadow: theme.elevation.level2 },
|
|
90
|
+
* progress,
|
|
91
|
+
* })
|
|
92
|
+
* ```
|
|
59
93
|
*/
|
|
60
94
|
export function useShadow({
|
|
61
95
|
from,
|
|
@@ -76,6 +110,17 @@ export function useShadow({
|
|
|
76
110
|
const hasOffset =
|
|
77
111
|
from.shadowOffset !== undefined || to.shadowOffset !== undefined
|
|
78
112
|
|
|
113
|
+
// boxShadow layers: parse/pair once on the JS thread into flat records so
|
|
114
|
+
// the worklet only interpolates numbers/colors and concatenates — no
|
|
115
|
+
// frame-time parsing. `[]` when neither side provides the key.
|
|
116
|
+
const boxShadowPairs =
|
|
117
|
+
from.boxShadow !== undefined || to.boxShadow !== undefined
|
|
118
|
+
? pairBoxShadowLayers(
|
|
119
|
+
resolveBoxShadowInput(from.boxShadow),
|
|
120
|
+
resolveBoxShadowInput(to.boxShadow),
|
|
121
|
+
)
|
|
122
|
+
: []
|
|
123
|
+
|
|
79
124
|
const opacityFrom = from.shadowOpacity ?? 0
|
|
80
125
|
const opacityTo = to.shadowOpacity ?? 0
|
|
81
126
|
const radiusFrom = from.shadowRadius ?? 0
|
|
@@ -111,6 +156,36 @@ export function useShadow({
|
|
|
111
156
|
height: interpolate(t, [0, 1], [offsetHFrom, offsetHTo]),
|
|
112
157
|
}
|
|
113
158
|
}
|
|
159
|
+
if (boxShadowPairs.length > 0) {
|
|
160
|
+
let css = ''
|
|
161
|
+
let first = true
|
|
162
|
+
for (const pair of boxShadowPairs) {
|
|
163
|
+
const x = interpolate(t, [0, 1], [pair.from.offsetX, pair.to.offsetX])
|
|
164
|
+
const y = interpolate(t, [0, 1], [pair.from.offsetY, pair.to.offsetY])
|
|
165
|
+
// Blur can't go negative (invalid CSS) even if a springy driver
|
|
166
|
+
// overshoots below 0.
|
|
167
|
+
const blur = Math.max(
|
|
168
|
+
0,
|
|
169
|
+
interpolate(t, [0, 1], [pair.from.blurRadius, pair.to.blurRadius]),
|
|
170
|
+
)
|
|
171
|
+
const spread = interpolate(
|
|
172
|
+
t,
|
|
173
|
+
[0, 1],
|
|
174
|
+
[pair.from.spreadDistance, pair.to.spreadDistance],
|
|
175
|
+
)
|
|
176
|
+
const color = interpolateColor(
|
|
177
|
+
t,
|
|
178
|
+
[0, 1],
|
|
179
|
+
[pair.from.color, pair.to.color],
|
|
180
|
+
)
|
|
181
|
+
css +=
|
|
182
|
+
(first ? '' : ', ') +
|
|
183
|
+
(pair.from.inset ? 'inset ' : '') +
|
|
184
|
+
`${x}px ${y}px ${blur}px ${spread}px ${color}`
|
|
185
|
+
first = false
|
|
186
|
+
}
|
|
187
|
+
out.boxShadow = css
|
|
188
|
+
}
|
|
114
189
|
return out
|
|
115
190
|
})
|
|
116
191
|
}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
// `react-native-worklets` is a required peer of Reanimated 4, so the direct
|
|
11
11
|
// import is always available wherever Inertia is.
|
|
12
12
|
import { isWorkletFunction } from 'react-native-worklets'
|
|
13
|
+
import { warnNonWorkletOnce } from '../internal/nonWorkletWarning'
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Extrapolation behavior at the edges of the input range. Mirrors
|
|
@@ -36,9 +37,17 @@ export interface UseTransformOptions {
|
|
|
36
37
|
* const distance = useTransform(() => Math.sqrt(x.value ** 2 + y.value ** 2))
|
|
37
38
|
* ```
|
|
38
39
|
*
|
|
39
|
-
* The transformer
|
|
40
|
-
*
|
|
41
|
-
*
|
|
40
|
+
* The transformer MUST be a worklet — put the `'worklet'` directive as its
|
|
41
|
+
* first statement so the consumer's Babel plugin captures the shared values
|
|
42
|
+
* it reads as its closure. It runs on the UI thread on every frame where
|
|
43
|
+
* any read shared value changes.
|
|
44
|
+
*
|
|
45
|
+
* A plain function cannot work here, and the hook warns in dev when it gets
|
|
46
|
+
* one: the best-effort wrapper it falls back to closes over the opaque
|
|
47
|
+
* function reference, not the shared values read inside it, so Reanimated
|
|
48
|
+
* can't track them as dependencies — the derived value only refreshes on
|
|
49
|
+
* React re-renders, and native builds reject the plain function when the
|
|
50
|
+
* closure crosses to the UI thread.
|
|
42
51
|
*/
|
|
43
52
|
export function useTransform<T>(transformer: () => T): SharedValue<T>
|
|
44
53
|
|
|
@@ -80,16 +89,23 @@ export function useTransform<T>(
|
|
|
80
89
|
// interpolation) is decided once at JS time, never at frame time.
|
|
81
90
|
let producer: () => unknown
|
|
82
91
|
if (typeof arg1 === 'function') {
|
|
83
|
-
// Transformer overload.
|
|
84
|
-
//
|
|
85
|
-
//
|
|
92
|
+
// Transformer overload. Must be a worklet — the directive-wrapped
|
|
93
|
+
// fallback below is best-effort only (its closure holds the opaque
|
|
94
|
+
// function, not the shared values read inside it, so dependency
|
|
95
|
+
// tracking cannot work — see `warnNonWorkletOnce`).
|
|
86
96
|
const userFn = arg1 as () => T
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
97
|
+
if (isWorkletFunction(userFn)) {
|
|
98
|
+
producer = userFn
|
|
99
|
+
} else {
|
|
100
|
+
warnNonWorkletOnce(
|
|
101
|
+
'useTransform-transformer',
|
|
102
|
+
"[inertia] useTransform: the transformer is not a worklet, so the shared values it reads can't be tracked as dependencies — the derived value will only refresh on React re-renders, and native builds reject plain functions on the UI thread. Add the 'worklet' directive as the first statement of the transformer.",
|
|
103
|
+
)
|
|
104
|
+
producer = () => {
|
|
105
|
+
'worklet'
|
|
106
|
+
return userFn()
|
|
107
|
+
}
|
|
108
|
+
}
|
|
93
109
|
} else {
|
|
94
110
|
// Interpolation overload. We pre-resolve everything JS-side so the
|
|
95
111
|
// worklet body only consumes flat values.
|
package/dist/chunk-NDKVHL3N.js
DELETED
package/dist/chunk-SCTX5Z7I.js
DELETED
package/dist/chunk-WZGMAXKC.js
DELETED