@rootnative/inertia 0.0.1 → 0.0.3
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 +36 -2
- package/dist/{chunk-TDSO63CJ.js → chunk-3XTVY34H.js} +2 -2
- package/dist/{chunk-NXDJZD6A.mjs → chunk-46P57VMY.mjs} +1 -1
- package/dist/{chunk-7UDYEFBU.js → chunk-BP3Y2SHQ.js} +477 -298
- package/dist/{chunk-6SMPIOIC.mjs → chunk-BQQTHG2V.mjs} +1 -1
- package/dist/{chunk-DWCLIBYO.mjs → chunk-CSODMRJ7.mjs} +478 -299
- package/dist/chunk-FNVFV4EY.js +8 -0
- package/dist/chunk-FWQOXA43.js +8 -0
- package/dist/chunk-KBP4LR75.js +8 -0
- package/dist/{chunk-ALRHDFZE.mjs → chunk-O22NXXCZ.mjs} +1 -1
- package/dist/{chunk-CWLFUYIY.mjs → chunk-OQV66TBQ.mjs} +1 -1
- package/dist/{chunk-JVBXPF2G.mjs → chunk-SGUHE5CX.mjs} +1 -1
- package/dist/{chunk-2HYD2ZBK.js → chunk-W5MC3P4N.js} +2 -2
- package/dist/index.d.mts +231 -43
- package/dist/index.d.ts +231 -43
- package/dist/index.js +212 -23
- package/dist/index.mjs +204 -18
- package/dist/motion/Image.js +3 -3
- package/dist/motion/Image.mjs +2 -2
- package/dist/motion/Pressable.js +3 -3
- package/dist/motion/Pressable.mjs +2 -2
- package/dist/motion/ScrollView.js +3 -3
- package/dist/motion/ScrollView.mjs +2 -2
- package/dist/motion/Text.js +3 -3
- package/dist/motion/Text.mjs +2 -2
- package/dist/motion/View.js +3 -3
- package/dist/motion/View.mjs +2 -2
- package/llms.txt +5 -0
- package/package.json +1 -1
- package/src/index.ts +10 -0
- package/src/layout/index.ts +1 -0
- package/src/layout/sharedRegistry.ts +51 -2
- package/src/motion/createMotionComponent.tsx +781 -502
- package/src/presence/Presence.tsx +73 -10
- package/src/values/index.ts +13 -0
- package/src/values/useAnimation.ts +15 -1
- package/src/values/useAnimator.ts +83 -0
- package/src/values/useColorCascade.ts +125 -0
- package/src/values/useInterpolatedStyle.ts +319 -0
- package/src/values/useMotionValue.ts +20 -2
- package/src/values/useSpring.ts +12 -0
- package/dist/chunk-3UTJJ4A3.js +0 -8
- package/dist/chunk-4QGXK6TF.js +0 -8
- package/dist/chunk-Z7HIOFKQ.js +0 -8
package/dist/index.mjs
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
export { useGesture } from './chunk-RGNX6UZN.mjs';
|
|
2
|
-
import { MotionView } from './chunk-
|
|
3
|
-
export { MotionView } from './chunk-
|
|
4
|
-
import { MotionText } from './chunk-
|
|
5
|
-
export { MotionText } from './chunk-
|
|
6
|
-
import { MotionImage } from './chunk-
|
|
7
|
-
export { MotionImage } from './chunk-
|
|
8
|
-
import { MotionPressable } from './chunk-
|
|
9
|
-
export { MotionPressable } from './chunk-
|
|
10
|
-
import { MotionScrollView } from './chunk-
|
|
11
|
-
export { MotionScrollView } from './chunk-
|
|
12
|
-
export { Presence, createMotionComponent, usePresence } from './chunk-
|
|
2
|
+
import { MotionView } from './chunk-BQQTHG2V.mjs';
|
|
3
|
+
export { MotionView } from './chunk-BQQTHG2V.mjs';
|
|
4
|
+
import { MotionText } from './chunk-SGUHE5CX.mjs';
|
|
5
|
+
export { MotionText } from './chunk-SGUHE5CX.mjs';
|
|
6
|
+
import { MotionImage } from './chunk-O22NXXCZ.mjs';
|
|
7
|
+
export { MotionImage } from './chunk-O22NXXCZ.mjs';
|
|
8
|
+
import { MotionPressable } from './chunk-46P57VMY.mjs';
|
|
9
|
+
export { MotionPressable } from './chunk-46P57VMY.mjs';
|
|
10
|
+
import { MotionScrollView } from './chunk-OQV66TBQ.mjs';
|
|
11
|
+
export { MotionScrollView } from './chunk-OQV66TBQ.mjs';
|
|
12
|
+
export { Presence, createMotionComponent, usePresence } from './chunk-CSODMRJ7.mjs';
|
|
13
13
|
import { useShouldReduceMotion, resolveNamedTransition, useNamedTransitions, lookupNamedTransition } from './chunk-R63GIUNU.mjs';
|
|
14
14
|
export { MotionConfig, resolveNamedTransition, useMotionConfig, useNamedTransitions, useShouldReduceMotion } from './chunk-R63GIUNU.mjs';
|
|
15
15
|
import { stableSig, resolveTransition, springToReanimated, warnNonWorkletOnce } from './chunk-CY7Y64C3.mjs';
|
|
16
16
|
export { buildReleaseAnimation, cubicBezier, ensureWorkletEasing, resolveAnimatableValue, resolveTransition } from './chunk-CY7Y64C3.mjs';
|
|
17
|
-
import { useEffect,
|
|
18
|
-
import { useSharedValue, withSpring, useAnimatedReaction, useAnimatedStyle, interpolateColor, useDerivedValue, Extrapolation, useAnimatedScrollHandler
|
|
17
|
+
import { useEffect, useRef, useCallback, useMemo } from 'react';
|
|
18
|
+
import { useSharedValue, cancelAnimation, withSpring, useAnimatedReaction, useAnimatedStyle, interpolateColor, interpolate, useDerivedValue, Extrapolation, useAnimatedScrollHandler } from 'react-native-reanimated';
|
|
19
19
|
import { isWorkletFunction } from 'react-native-worklets';
|
|
20
20
|
|
|
21
21
|
// src/motion/index.ts
|
|
@@ -35,8 +35,27 @@ function useAnimation(target, transition) {
|
|
|
35
35
|
const cfg = shouldReduceMotion ? { type: "no-animation" } : resolved ?? { type: "spring" };
|
|
36
36
|
output.value = resolveTransition(cfg, target);
|
|
37
37
|
}, [target, cfgSig, shouldReduceMotion]);
|
|
38
|
+
useEffect(
|
|
39
|
+
() => () => cancelAnimation(output),
|
|
40
|
+
// `output` is identity-stable per hook instance (Reanimated guarantee).
|
|
41
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
42
|
+
[]
|
|
43
|
+
);
|
|
38
44
|
return output;
|
|
39
45
|
}
|
|
46
|
+
function useAnimator() {
|
|
47
|
+
const registry = useNamedTransitions();
|
|
48
|
+
const shouldReduceMotion = useShouldReduceMotion();
|
|
49
|
+
const registryRef = useRef(registry);
|
|
50
|
+
registryRef.current = registry;
|
|
51
|
+
const reduceMotionRef = useRef(shouldReduceMotion);
|
|
52
|
+
reduceMotionRef.current = shouldReduceMotion;
|
|
53
|
+
return useCallback((value, to, transition) => {
|
|
54
|
+
const resolved = resolveNamedTransition(transition, registryRef.current);
|
|
55
|
+
const cfg = reduceMotionRef.current ? { type: "no-animation" } : resolved ?? { type: "spring" };
|
|
56
|
+
value.value = resolveTransition(cfg, to);
|
|
57
|
+
}, []);
|
|
58
|
+
}
|
|
40
59
|
function useSpring(target, config) {
|
|
41
60
|
const spring = resolveSpringInput(config, useNamedTransitions());
|
|
42
61
|
const reanimConfig = useMemo(
|
|
@@ -75,6 +94,12 @@ function useSpring(target, config) {
|
|
|
75
94
|
},
|
|
76
95
|
[isSharedTarget, reanimConfig]
|
|
77
96
|
);
|
|
97
|
+
useEffect(
|
|
98
|
+
() => () => cancelAnimation(output),
|
|
99
|
+
// `output` is identity-stable per hook instance (Reanimated guarantee).
|
|
100
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
101
|
+
[]
|
|
102
|
+
);
|
|
78
103
|
return output;
|
|
79
104
|
}
|
|
80
105
|
function resolveSpringInput(config, registry) {
|
|
@@ -96,6 +121,36 @@ function isSharedValue(v) {
|
|
|
96
121
|
function useBooleanSpring(active, springConfig) {
|
|
97
122
|
return useSpring(active ? 1 : 0, springConfig);
|
|
98
123
|
}
|
|
124
|
+
function useColorCascade(rest, layers, options) {
|
|
125
|
+
const key = options?.key ?? "backgroundColor";
|
|
126
|
+
const sig = `${key}|${rest}|${layers.length}|${layers.map((l) => l.color).join(",")}`;
|
|
127
|
+
const colors = useMemo(() => layers.map((l) => l.color), [sig]);
|
|
128
|
+
const progressRef = useRef([]);
|
|
129
|
+
const prevProgress = progressRef.current;
|
|
130
|
+
let progressChanged = prevProgress.length !== layers.length;
|
|
131
|
+
if (!progressChanged) {
|
|
132
|
+
for (let i = 0; i < layers.length; i++) {
|
|
133
|
+
if (prevProgress[i] !== layers[i].progress) {
|
|
134
|
+
progressChanged = true;
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (progressChanged) progressRef.current = layers.map((l) => l.progress);
|
|
140
|
+
const progressValues = progressRef.current;
|
|
141
|
+
return useAnimatedStyle(() => {
|
|
142
|
+
"worklet";
|
|
143
|
+
let acc = rest;
|
|
144
|
+
for (let i = 0; i < colors.length; i++) {
|
|
145
|
+
acc = interpolateColor(
|
|
146
|
+
progressValues[i].value,
|
|
147
|
+
[0, 1],
|
|
148
|
+
[acc, colors[i]]
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
return { [key]: acc };
|
|
152
|
+
});
|
|
153
|
+
}
|
|
99
154
|
function useColorTransition(progress, range, options) {
|
|
100
155
|
const key = options?.key ?? "backgroundColor";
|
|
101
156
|
const from = range[0];
|
|
@@ -105,8 +160,139 @@ function useColorTransition(progress, range, options) {
|
|
|
105
160
|
return { [key]: interpolateColor(progress.value, [0, 1], [from, to]) };
|
|
106
161
|
});
|
|
107
162
|
}
|
|
163
|
+
var TRANSFORM_KEYS = /* @__PURE__ */ new Set([
|
|
164
|
+
"translateX",
|
|
165
|
+
"translateY",
|
|
166
|
+
"scale",
|
|
167
|
+
"scaleX",
|
|
168
|
+
"scaleY",
|
|
169
|
+
"rotate",
|
|
170
|
+
"rotateX",
|
|
171
|
+
"rotateY"
|
|
172
|
+
]);
|
|
173
|
+
var ROTATION_KEYS = /* @__PURE__ */ new Set(["rotate", "rotateX", "rotateY"]);
|
|
174
|
+
var COLOR_KEYS = /* @__PURE__ */ new Set([
|
|
175
|
+
"backgroundColor",
|
|
176
|
+
"color",
|
|
177
|
+
"borderColor",
|
|
178
|
+
"borderTopColor",
|
|
179
|
+
"borderRightColor",
|
|
180
|
+
"borderBottomColor",
|
|
181
|
+
"borderLeftColor",
|
|
182
|
+
"tintColor",
|
|
183
|
+
"shadowColor"
|
|
184
|
+
]);
|
|
185
|
+
function evenlySpaced(count) {
|
|
186
|
+
if (count <= 1) return [0];
|
|
187
|
+
const out = [];
|
|
188
|
+
for (let i = 0; i < count; i++) out.push(i / (count - 1));
|
|
189
|
+
return out;
|
|
190
|
+
}
|
|
191
|
+
function mapExtrapolation(mode) {
|
|
192
|
+
if (mode === "identity") return Extrapolation.IDENTITY;
|
|
193
|
+
if (mode === "extend") return Extrapolation.EXTEND;
|
|
194
|
+
return Extrapolation.CLAMP;
|
|
195
|
+
}
|
|
196
|
+
function buildSignature(map, options) {
|
|
197
|
+
let sig = "";
|
|
198
|
+
for (const key of Object.keys(map)) {
|
|
199
|
+
const output = map[key];
|
|
200
|
+
sig += `${key}:${JSON.stringify(output)}|`;
|
|
201
|
+
}
|
|
202
|
+
sig += `#ir:${JSON.stringify(options?.inputRange)}|ex:${options?.extrapolate ?? ""}`;
|
|
203
|
+
return sig;
|
|
204
|
+
}
|
|
205
|
+
function buildEntries(map, options) {
|
|
206
|
+
const explicitInput = options?.inputRange;
|
|
207
|
+
const entries = [];
|
|
208
|
+
for (const key of Object.keys(map)) {
|
|
209
|
+
const output = map[key];
|
|
210
|
+
if (output === void 0 || output.length === 0) continue;
|
|
211
|
+
const input = explicitInput ? explicitInput : output.length === 2 ? [0, 1] : evenlySpaced(output.length);
|
|
212
|
+
if (__DEV__ && explicitInput && explicitInput.length !== output.length) {
|
|
213
|
+
console.warn(
|
|
214
|
+
`[inertia] useInterpolatedStyle: inputRange has ${explicitInput.length} stops but the "${String(
|
|
215
|
+
key
|
|
216
|
+
)}" output has ${output.length}. They must match \u2014 interpolation results are undefined otherwise.`
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
const isColor = COLOR_KEYS.has(key) && typeof output[0] === "string";
|
|
220
|
+
if (isColor) {
|
|
221
|
+
entries.push({
|
|
222
|
+
kind: "color",
|
|
223
|
+
key,
|
|
224
|
+
input,
|
|
225
|
+
output
|
|
226
|
+
});
|
|
227
|
+
} else if (ROTATION_KEYS.has(key)) {
|
|
228
|
+
entries.push({
|
|
229
|
+
kind: "rotation",
|
|
230
|
+
key,
|
|
231
|
+
input,
|
|
232
|
+
output
|
|
233
|
+
});
|
|
234
|
+
} else if (TRANSFORM_KEYS.has(key)) {
|
|
235
|
+
entries.push({
|
|
236
|
+
kind: "transform-numeric",
|
|
237
|
+
key,
|
|
238
|
+
input,
|
|
239
|
+
output
|
|
240
|
+
});
|
|
241
|
+
} else {
|
|
242
|
+
entries.push({
|
|
243
|
+
kind: "numeric",
|
|
244
|
+
key,
|
|
245
|
+
input,
|
|
246
|
+
output
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return entries;
|
|
251
|
+
}
|
|
252
|
+
function useInterpolatedStyle(progress, map, options) {
|
|
253
|
+
const extrapolate = mapExtrapolation(options?.extrapolate);
|
|
254
|
+
const sig = buildSignature(map, options);
|
|
255
|
+
const entries = useMemo(() => buildEntries(map, options), [sig]);
|
|
256
|
+
return useAnimatedStyle(() => {
|
|
257
|
+
"worklet";
|
|
258
|
+
const out = {};
|
|
259
|
+
const transform = [];
|
|
260
|
+
for (const e of entries) {
|
|
261
|
+
if (e.kind === "color") {
|
|
262
|
+
out[e.key] = interpolateColor(progress.value, e.input, e.output);
|
|
263
|
+
} else if (e.kind === "numeric") {
|
|
264
|
+
out[e.key] = interpolate(progress.value, e.input, e.output, {
|
|
265
|
+
extrapolateLeft: extrapolate,
|
|
266
|
+
extrapolateRight: extrapolate
|
|
267
|
+
});
|
|
268
|
+
} else if (e.kind === "transform-numeric") {
|
|
269
|
+
transform.push({
|
|
270
|
+
[e.key]: interpolate(progress.value, e.input, e.output, {
|
|
271
|
+
extrapolateLeft: extrapolate,
|
|
272
|
+
extrapolateRight: extrapolate
|
|
273
|
+
})
|
|
274
|
+
});
|
|
275
|
+
} else {
|
|
276
|
+
const deg = interpolate(progress.value, e.input, e.output, {
|
|
277
|
+
extrapolateLeft: extrapolate,
|
|
278
|
+
extrapolateRight: extrapolate
|
|
279
|
+
});
|
|
280
|
+
transform.push({ [e.key]: `${deg}deg` });
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
if (transform.length > 0) out.transform = transform;
|
|
284
|
+
return out;
|
|
285
|
+
});
|
|
286
|
+
}
|
|
108
287
|
function useMotionValue(initial) {
|
|
109
|
-
|
|
288
|
+
const sv = useSharedValue(initial);
|
|
289
|
+
useEffect(
|
|
290
|
+
() => () => cancelAnimation(sv),
|
|
291
|
+
// `sv` is identity-stable per hook instance (Reanimated guarantee).
|
|
292
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
293
|
+
[]
|
|
294
|
+
);
|
|
295
|
+
return sv;
|
|
110
296
|
}
|
|
111
297
|
function useTransform(arg1, inputRange, outputRange, options) {
|
|
112
298
|
let producer;
|
|
@@ -129,8 +315,8 @@ function useTransform(arg1, inputRange, outputRange, options) {
|
|
|
129
315
|
const input = inputRange;
|
|
130
316
|
const output = outputRange;
|
|
131
317
|
const isColor = output.length > 0 && typeof output[0] === "string";
|
|
132
|
-
const extrapolateLeft =
|
|
133
|
-
const extrapolateRight =
|
|
318
|
+
const extrapolateLeft = mapExtrapolation2(options?.extrapolateLeft);
|
|
319
|
+
const extrapolateRight = mapExtrapolation2(options?.extrapolateRight);
|
|
134
320
|
producer = isColor ? () => {
|
|
135
321
|
"worklet";
|
|
136
322
|
return interpolateColor(
|
|
@@ -150,7 +336,7 @@ function useTransform(arg1, inputRange, outputRange, options) {
|
|
|
150
336
|
}
|
|
151
337
|
return useDerivedValue(producer);
|
|
152
338
|
}
|
|
153
|
-
function
|
|
339
|
+
function mapExtrapolation2(mode) {
|
|
154
340
|
if (mode === "identity") return Extrapolation.IDENTITY;
|
|
155
341
|
if (mode === "extend") return Extrapolation.EXTEND;
|
|
156
342
|
return Extrapolation.CLAMP;
|
|
@@ -401,4 +587,4 @@ function useVariants(variants, initial) {
|
|
|
401
587
|
}, []);
|
|
402
588
|
}
|
|
403
589
|
|
|
404
|
-
export { Motion, useAnimation, useBooleanSpring, useColorTransition, useMotionValue, useScroll, useShadow, useSpring, useTransform, useVariants };
|
|
590
|
+
export { Motion, useAnimation, useAnimator, useBooleanSpring, useColorCascade, useColorTransition, useInterpolatedStyle, useMotionValue, useScroll, useShadow, useSpring, useTransform, useVariants };
|
package/dist/motion/Image.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('../chunk-
|
|
3
|
+
var chunkKBP4LR75_js = require('../chunk-KBP4LR75.js');
|
|
4
|
+
require('../chunk-BP3Y2SHQ.js');
|
|
5
5
|
require('../chunk-7AOERN53.js');
|
|
6
6
|
require('../chunk-PTRF47DA.js');
|
|
7
7
|
|
|
@@ -9,5 +9,5 @@ require('../chunk-PTRF47DA.js');
|
|
|
9
9
|
|
|
10
10
|
Object.defineProperty(exports, "MotionImage", {
|
|
11
11
|
enumerable: true,
|
|
12
|
-
get: function () { return
|
|
12
|
+
get: function () { return chunkKBP4LR75_js.MotionImage; }
|
|
13
13
|
});
|
package/dist/motion/Image.mjs
CHANGED
package/dist/motion/Pressable.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('../chunk-
|
|
3
|
+
var chunk3XTVY34H_js = require('../chunk-3XTVY34H.js');
|
|
4
|
+
require('../chunk-BP3Y2SHQ.js');
|
|
5
5
|
require('../chunk-7AOERN53.js');
|
|
6
6
|
require('../chunk-PTRF47DA.js');
|
|
7
7
|
|
|
@@ -9,5 +9,5 @@ require('../chunk-PTRF47DA.js');
|
|
|
9
9
|
|
|
10
10
|
Object.defineProperty(exports, "MotionPressable", {
|
|
11
11
|
enumerable: true,
|
|
12
|
-
get: function () { return
|
|
12
|
+
get: function () { return chunk3XTVY34H_js.MotionPressable; }
|
|
13
13
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('../chunk-
|
|
3
|
+
var chunkW5MC3P4N_js = require('../chunk-W5MC3P4N.js');
|
|
4
|
+
require('../chunk-BP3Y2SHQ.js');
|
|
5
5
|
require('../chunk-7AOERN53.js');
|
|
6
6
|
require('../chunk-PTRF47DA.js');
|
|
7
7
|
|
|
@@ -9,5 +9,5 @@ require('../chunk-PTRF47DA.js');
|
|
|
9
9
|
|
|
10
10
|
Object.defineProperty(exports, "MotionScrollView", {
|
|
11
11
|
enumerable: true,
|
|
12
|
-
get: function () { return
|
|
12
|
+
get: function () { return chunkW5MC3P4N_js.MotionScrollView; }
|
|
13
13
|
});
|
package/dist/motion/Text.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('../chunk-
|
|
3
|
+
var chunkFWQOXA43_js = require('../chunk-FWQOXA43.js');
|
|
4
|
+
require('../chunk-BP3Y2SHQ.js');
|
|
5
5
|
require('../chunk-7AOERN53.js');
|
|
6
6
|
require('../chunk-PTRF47DA.js');
|
|
7
7
|
|
|
@@ -9,5 +9,5 @@ require('../chunk-PTRF47DA.js');
|
|
|
9
9
|
|
|
10
10
|
Object.defineProperty(exports, "MotionText", {
|
|
11
11
|
enumerable: true,
|
|
12
|
-
get: function () { return
|
|
12
|
+
get: function () { return chunkFWQOXA43_js.MotionText; }
|
|
13
13
|
});
|
package/dist/motion/Text.mjs
CHANGED
package/dist/motion/View.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('../chunk-
|
|
3
|
+
var chunkFNVFV4EY_js = require('../chunk-FNVFV4EY.js');
|
|
4
|
+
require('../chunk-BP3Y2SHQ.js');
|
|
5
5
|
require('../chunk-7AOERN53.js');
|
|
6
6
|
require('../chunk-PTRF47DA.js');
|
|
7
7
|
|
|
@@ -9,5 +9,5 @@ require('../chunk-PTRF47DA.js');
|
|
|
9
9
|
|
|
10
10
|
Object.defineProperty(exports, "MotionView", {
|
|
11
11
|
enumerable: true,
|
|
12
|
-
get: function () { return
|
|
12
|
+
get: function () { return chunkFNVFV4EY_js.MotionView; }
|
|
13
13
|
});
|
package/dist/motion/View.mjs
CHANGED
package/llms.txt
CHANGED
|
@@ -26,6 +26,8 @@ import {
|
|
|
26
26
|
useTransform,
|
|
27
27
|
useShadow,
|
|
28
28
|
useColorTransition,
|
|
29
|
+
useColorCascade,
|
|
30
|
+
useInterpolatedStyle,
|
|
29
31
|
useScroll,
|
|
30
32
|
} from '@rootnative/inertia'
|
|
31
33
|
// Opt-in MD3 / iOS state-layer overlay helper:
|
|
@@ -50,11 +52,14 @@ import { MotionScrollView } from '@rootnative/inertia/scroll-view'
|
|
|
50
52
|
- `useVariants(variants, initial?)` — returns `{ current, transitionTo }` controller for the `controller` prop.
|
|
51
53
|
- `useMotionValue(initial)` — thin pass-through over `useSharedValue<T>`. Returns a `SharedValue<T>` directly so it interops with every Reanimated API without unwrapping.
|
|
52
54
|
- `useAnimation(target, transition?)` — drive a `SharedValue<number>` toward `target` with any `TransitionConfig` (spring / timing / decay / no-animation, plus `repeat`) or a registered `TransitionName`. The general-purpose value-layer hook for boolean-state progress, indeterminate loops, and anywhere the same value needs to feed multiple `useAnimatedStyle` blocks.
|
|
55
|
+
- `useAnimator()` — the **imperative** counterpart to `useAnimation`. Returns an identity-stable `(value: SharedValue<number>, to: number, transition?: TransitionConfig | TransitionName) => void` setter to call from event handlers (hover-in, focus, press) rather than from an effect. Resolves registered `TransitionName`s through the nearest `<MotionConfig transitions>` and gates on `<MotionConfig reducedMotion>` (`'no-animation'` downgrade) — the two things a hand-rolled `resolveTransition` write in an event handler silently gets wrong. Default transition is the library spring. Not a new animation API — the hooks-layer equivalent of `useMotionValue` + `resolveTransition`, minus the footguns.
|
|
53
56
|
- `useSpring(target, config?)` — spring-only shorthand. Animates a `SharedValue<number>` toward `target` with react-spring vocab (or a spring-typed registered `TransitionName`; non-spring names warn and fall back to the default spring). `target` may be a plain number (effect-driven) or a `SharedValue<number>` (UI-thread reaction); the latter is the gesture-smoothing path.
|
|
54
57
|
- `useBooleanSpring(active, config?)` — sugar over `useSpring` for the recurring "spring 0↔1 progress from a boolean" shape (checkbox checks, accordion expansions, drawer open/closed). Identical mechanics to `useSpring(active ? 1 : 0, config)` — the named form so the call site reads as the boolean it represents.
|
|
55
58
|
- `useTransform(value, inputRange, outputRange, options?)` / `useTransform(transformer)` — interpolate a numeric shared value onto a number or color range, or derive any value from any number of shared values via a worklet. Non-worklet transformers are auto-wrapped.
|
|
56
59
|
- `useShadow({ from, to, progress })` — pure value-layer interpolator between two `ShadowConfig`s (`shadowOpacity` / `shadowRadius` / `shadowOffset` / `elevation` / `shadowColor`, plus `boxShadow` as a CSS string or `BoxShadowLayer[]` — the shadow surface on web and RN 0.76+ new-arch; multi-layer, CSS-transition padding semantics, malformed strings throw at setup) driven by a `SharedValue<number>` (0→1). Returns an animated style fragment to spread onto `style`; only emits keys present on either side, absent sides default to natural zero. The hook does not animate on its own — drive `progress` with a spring, a scroll-derived `useTransform`, or any other shared value source.
|
|
57
60
|
- `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
|
+
- `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
|
+
- `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`.
|
|
58
63
|
- `useScroll()` — returns `{ scrollX, scrollY, onScroll }` for use with `Motion.ScrollView`. Scroll events fire on the UI thread.
|
|
59
64
|
- `createMotionComponent<C>(C)` — wrap any component with the same Motion prop surface, inferring style from `C`.
|
|
60
65
|
- `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 })`.
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -41,9 +41,12 @@ export {
|
|
|
41
41
|
} from './transitions'
|
|
42
42
|
export {
|
|
43
43
|
useAnimation,
|
|
44
|
+
useAnimator,
|
|
44
45
|
useBooleanSpring,
|
|
46
|
+
useColorCascade,
|
|
45
47
|
useColorTransition,
|
|
46
48
|
useGesture,
|
|
49
|
+
useInterpolatedStyle,
|
|
47
50
|
useMotionValue,
|
|
48
51
|
useScroll,
|
|
49
52
|
useShadow,
|
|
@@ -57,13 +60,20 @@ export {
|
|
|
57
60
|
// Runtime render-layer interop lives in `@rootnative/inertia/reanimated`.
|
|
58
61
|
export type { SharedValue } from 'react-native-reanimated'
|
|
59
62
|
export type {
|
|
63
|
+
Animator,
|
|
60
64
|
BoxShadowLayer,
|
|
65
|
+
ColorCascadeLayer,
|
|
61
66
|
ColorStyleKey,
|
|
62
67
|
ExtrapolationMode,
|
|
68
|
+
InterpolatedStyleMap,
|
|
69
|
+
NumericStyleKey,
|
|
63
70
|
ShadowConfig,
|
|
71
|
+
TransformKey,
|
|
72
|
+
UseColorCascadeOptions,
|
|
64
73
|
UseColorTransitionOptions,
|
|
65
74
|
UseGestureHandlers,
|
|
66
75
|
UseGestureResult,
|
|
76
|
+
UseInterpolatedStyleOptions,
|
|
67
77
|
UseScrollResult,
|
|
68
78
|
UseShadowOptions,
|
|
69
79
|
UseTransformOptions,
|
package/src/layout/index.ts
CHANGED
|
@@ -51,6 +51,37 @@ export const SHARED_LAYOUT_TTL_MS = 1000
|
|
|
51
51
|
*/
|
|
52
52
|
let now = (): number => Date.now()
|
|
53
53
|
|
|
54
|
+
/**
|
|
55
|
+
* When the last expiry sweep ran, so the scan is amortized to at most once per
|
|
56
|
+
* TTL window rather than running on every write.
|
|
57
|
+
*/
|
|
58
|
+
let lastSweep = 0
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Drop every entry whose TTL has passed.
|
|
62
|
+
*
|
|
63
|
+
* Without this the map only ever shrank via `consumeLayout` / `peekSharedLayout`,
|
|
64
|
+
* so a `layoutId` that unmounted and was never remounted left its rect behind
|
|
65
|
+
* for the lifetime of the process. Bounded by distinct-id count, which is small
|
|
66
|
+
* for a handful of hero images but not for per-item ids in a long-lived list
|
|
67
|
+
* (`layoutId={`photo-${item.id}`}`).
|
|
68
|
+
*
|
|
69
|
+
* Sweeping a *live* element's entry is harmless: while mounted it re-registers
|
|
70
|
+
* on every `onLayout`, and on unmount `releaseLayout` re-adds it with a fresh
|
|
71
|
+
* TTL. So the only thing an over-eager sweep can cost is a FLIP source that was
|
|
72
|
+
* already too old to be used.
|
|
73
|
+
*
|
|
74
|
+
* Time-gated so a burst of layout events doesn't turn into a burst of full
|
|
75
|
+
* scans — worst case an expired entry survives one extra TTL window.
|
|
76
|
+
*/
|
|
77
|
+
function sweepExpired(at: number): void {
|
|
78
|
+
if (at - lastSweep < SHARED_LAYOUT_TTL_MS) return
|
|
79
|
+
lastSweep = at
|
|
80
|
+
for (const [id, entry] of REGISTRY) {
|
|
81
|
+
if (entry.expiresAt < at) REGISTRY.delete(id)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
54
85
|
/**
|
|
55
86
|
* Update the latest known rect for `id`. Called on every `onLayout` of a
|
|
56
87
|
* Motion primitive with `layoutId` set so the registry always holds a
|
|
@@ -58,7 +89,9 @@ let now = (): number => Date.now()
|
|
|
58
89
|
* transition. Resets the TTL each call.
|
|
59
90
|
*/
|
|
60
91
|
export function registerLayout(id: string, rect: SharedRect): void {
|
|
61
|
-
|
|
92
|
+
const at = now()
|
|
93
|
+
sweepExpired(at)
|
|
94
|
+
REGISTRY.set(id, { rect, expiresAt: at + SHARED_LAYOUT_TTL_MS })
|
|
62
95
|
}
|
|
63
96
|
|
|
64
97
|
/**
|
|
@@ -67,7 +100,9 @@ export function registerLayout(id: string, rect: SharedRect): void {
|
|
|
67
100
|
* is purely intent-documenting at the call site.
|
|
68
101
|
*/
|
|
69
102
|
export function releaseLayout(id: string, rect: SharedRect): void {
|
|
70
|
-
|
|
103
|
+
const at = now()
|
|
104
|
+
sweepExpired(at)
|
|
105
|
+
REGISTRY.set(id, { rect, expiresAt: at + SHARED_LAYOUT_TTL_MS })
|
|
71
106
|
}
|
|
72
107
|
|
|
73
108
|
/**
|
|
@@ -88,6 +123,7 @@ export function consumeLayout(id: string): SharedRect | undefined {
|
|
|
88
123
|
/** Drop all entries. Tests use this to isolate between cases. */
|
|
89
124
|
export function clearSharedRegistry(): void {
|
|
90
125
|
REGISTRY.clear()
|
|
126
|
+
lastSweep = 0
|
|
91
127
|
}
|
|
92
128
|
|
|
93
129
|
/**
|
|
@@ -108,4 +144,17 @@ export function peekSharedLayout(id: string): SharedRect | undefined {
|
|
|
108
144
|
*/
|
|
109
145
|
export function __setSharedLayoutClock(fn: (() => number) | undefined): void {
|
|
110
146
|
now = fn ?? Date.now
|
|
147
|
+
// Swapping the clock makes the previous sweep timestamp meaningless — a
|
|
148
|
+
// stubbed clock usually starts near 0, which would otherwise suppress every
|
|
149
|
+
// sweep until it caught up past the real-time value recorded earlier.
|
|
150
|
+
lastSweep = 0
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Test hook: how many entries the registry is holding, expired or not. Used to
|
|
155
|
+
* assert that released-but-never-consumed rects are actually evicted. Not
|
|
156
|
+
* exported from the package root — reachable only from inside the workspace.
|
|
157
|
+
*/
|
|
158
|
+
export function __sharedRegistrySize(): number {
|
|
159
|
+
return REGISTRY.size
|
|
111
160
|
}
|