@rootnative/inertia 0.0.3 → 0.0.5
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 +92 -5
- package/README.md +9 -3
- package/dist/{chunk-OQV66TBQ.mjs → chunk-27MKBTSG.mjs} +1 -1
- package/dist/{chunk-3XTVY34H.js → chunk-27U6766G.js} +2 -2
- package/dist/{chunk-4PEHWDAZ.js → chunk-4NAMD62I.js} +7 -7
- package/dist/chunk-67GHRCF6.js +8 -0
- package/dist/{chunk-SGUHE5CX.mjs → chunk-COEJVWRZ.mjs} +1 -1
- package/dist/chunk-GPOMFIIU.js +8 -0
- package/dist/{chunk-BQQTHG2V.mjs → chunk-GTJ6VAH5.mjs} +1 -1
- package/dist/chunk-K63LXGKS.js +8 -0
- package/dist/{chunk-46P57VMY.mjs → chunk-OAUWLPQH.mjs} +1 -1
- package/dist/{chunk-7AOERN53.js → chunk-OBRGJAST.js} +3 -3
- package/dist/{chunk-RGNX6UZN.mjs → chunk-OW5XTGVN.mjs} +2 -2
- package/dist/{chunk-PTRF47DA.js → chunk-PM6CVGXJ.js} +11 -3
- package/dist/{chunk-W5MC3P4N.js → chunk-QQVDZKSD.js} +2 -2
- package/dist/{chunk-CY7Y64C3.mjs → chunk-REYL77RE.mjs} +11 -4
- package/dist/{chunk-CSODMRJ7.mjs → chunk-RIVVBABB.mjs} +597 -134
- package/dist/{chunk-BP3Y2SHQ.js → chunk-VQ5D35UA.js} +617 -152
- package/dist/{chunk-O22NXXCZ.mjs → chunk-XSK5MNUH.mjs} +1 -1
- package/dist/{chunk-R63GIUNU.mjs → chunk-Z3HCJ43H.mjs} +1 -1
- package/dist/gestureLayer/index.d.mts +2 -2
- package/dist/gestureLayer/index.d.ts +2 -2
- package/dist/gestureLayer/index.js +10 -10
- package/dist/gestureLayer/index.mjs +3 -3
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +48 -169
- package/dist/index.mjs +17 -137
- package/dist/motion/Image.d.mts +1 -1
- package/dist/motion/Image.d.ts +1 -1
- package/dist/motion/Image.js +5 -5
- package/dist/motion/Image.mjs +4 -4
- package/dist/motion/Pressable.d.mts +1 -1
- package/dist/motion/Pressable.d.ts +1 -1
- package/dist/motion/Pressable.js +5 -5
- package/dist/motion/Pressable.mjs +4 -4
- package/dist/motion/ScrollView.d.mts +1 -1
- package/dist/motion/ScrollView.d.ts +1 -1
- package/dist/motion/ScrollView.js +5 -5
- package/dist/motion/ScrollView.mjs +4 -4
- package/dist/motion/Text.d.mts +1 -1
- package/dist/motion/Text.d.ts +1 -1
- package/dist/motion/Text.js +5 -5
- package/dist/motion/Text.mjs +4 -4
- package/dist/motion/View.d.mts +1 -1
- package/dist/motion/View.d.ts +1 -1
- package/dist/motion/View.js +5 -5
- package/dist/motion/View.mjs +4 -4
- package/dist/touch/index.d.mts +1 -1
- package/dist/touch/index.d.ts +1 -1
- package/dist/touch/index.js +3 -3
- package/dist/touch/index.mjs +1 -1
- package/dist/{types-G1dBU2IQ.d.mts → types-BQgLJeQG.d.mts} +85 -14
- package/dist/{types-G1dBU2IQ.d.ts → types-BQgLJeQG.d.ts} +85 -14
- package/dist/{useGesture-D1e4ixJo.d.ts → useGesture-B0_CzOUz.d.ts} +1 -1
- package/dist/{useGesture-RFY6kTL3.d.mts → useGesture-DfaTx-3t.d.mts} +1 -1
- package/llms.txt +3 -1
- package/package.json +1 -1
- package/src/index.ts +2 -1
- package/src/internal/boxShadow.ts +177 -6
- package/src/internal/nonWorkletWarning.ts +4 -6
- package/src/internal/warnOnce.ts +28 -0
- package/src/layout/index.ts +10 -0
- package/src/layout/measureWindow.ts +135 -0
- package/src/layout/sharedRegistry.ts +107 -18
- package/src/layout/useSharedLayout.ts +256 -91
- package/src/motion/createMotionComponent.tsx +497 -74
- package/src/motion/installCheck.ts +1 -1
- package/src/transitions/index.ts +1 -1
- package/src/transitions/resolveSequence.ts +12 -0
- package/src/types.ts +155 -12
- package/src/values/useColorTransition.ts +1 -1
- package/dist/chunk-FNVFV4EY.js +0 -8
- package/dist/chunk-FWQOXA43.js +0 -8
- package/dist/chunk-KBP4LR75.js +0 -8
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { useNamedTransitions, resolveNamedTransitionProp, lookupNamedTransition, useShouldReduceMotion, isFocusVisible } from './chunk-
|
|
2
|
-
import { stableSig, resolveAnimatableValue, isTopLevelTransition, resolveTransition, ensureWorkletEasing, springToReanimated, DEFAULT_SPRING } from './chunk-
|
|
1
|
+
import { useNamedTransitions, resolveNamedTransitionProp, lookupNamedTransition, useShouldReduceMotion, isFocusVisible } from './chunk-Z3HCJ43H.mjs';
|
|
2
|
+
import { warnOnce, stableSig, resolveAnimatableValue, isTopLevelTransition, resolveTransition, ensureWorkletEasing, springToReanimated, DEFAULT_SPRING } from './chunk-REYL77RE.mjs';
|
|
3
3
|
import { createContext, useContext, useMemo, Children, isValidElement, useState, useRef, useCallback, forwardRef, useEffect } from 'react';
|
|
4
4
|
import { jsx, Fragment } from 'react/jsx-runtime';
|
|
5
5
|
import Animated, { useSharedValue, cancelAnimation, useAnimatedStyle, interpolateColor, reanimatedVersion, runOnJS, LinearTransition, withSequence, withTiming, withSpring } from 'react-native-reanimated';
|
|
@@ -129,6 +129,175 @@ function PresenceItem({
|
|
|
129
129
|
);
|
|
130
130
|
return /* @__PURE__ */ jsx(PresenceContext.Provider, { value, children });
|
|
131
131
|
}
|
|
132
|
+
|
|
133
|
+
// src/internal/boxShadow.ts
|
|
134
|
+
var LENGTH = /^[+-]?(\d+\.?\d*|\.\d+)(px)?$/i;
|
|
135
|
+
var UNIT_LIKE = /^[+-]?(\d+\.?\d*|\.\d+)[a-z%]+$/i;
|
|
136
|
+
function invalid(input, reason) {
|
|
137
|
+
return new Error(
|
|
138
|
+
`[inertia] parseBoxShadow: ${reason} in ${JSON.stringify(input)}. Expected CSS box-shadow syntax with px lengths: '[inset] <offset-x> <offset-y> [blur] [spread] [color], ...'`
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
function splitLayers(input) {
|
|
142
|
+
const layers = [];
|
|
143
|
+
let depth = 0;
|
|
144
|
+
let start = 0;
|
|
145
|
+
for (let i = 0; i < input.length; i++) {
|
|
146
|
+
const ch = input[i];
|
|
147
|
+
if (ch === "(") depth++;
|
|
148
|
+
else if (ch === ")") depth--;
|
|
149
|
+
else if (ch === "," && depth === 0) {
|
|
150
|
+
layers.push(input.slice(start, i));
|
|
151
|
+
start = i + 1;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
layers.push(input.slice(start));
|
|
155
|
+
return layers;
|
|
156
|
+
}
|
|
157
|
+
function tokenize(layer) {
|
|
158
|
+
const tokens = [];
|
|
159
|
+
let depth = 0;
|
|
160
|
+
let current = "";
|
|
161
|
+
for (const ch of layer) {
|
|
162
|
+
if (ch === "(") depth++;
|
|
163
|
+
else if (ch === ")") depth--;
|
|
164
|
+
if (depth === 0 && /\s/.test(ch)) {
|
|
165
|
+
if (current) tokens.push(current);
|
|
166
|
+
current = "";
|
|
167
|
+
} else {
|
|
168
|
+
current += ch;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (current) tokens.push(current);
|
|
172
|
+
return tokens;
|
|
173
|
+
}
|
|
174
|
+
function parseBoxShadow(input) {
|
|
175
|
+
const trimmed = input.trim();
|
|
176
|
+
if (trimmed === "") throw invalid(input, "empty string");
|
|
177
|
+
if (trimmed.toLowerCase() === "none") return [];
|
|
178
|
+
return splitLayers(trimmed).map((layerString) => {
|
|
179
|
+
const tokens = tokenize(layerString.trim());
|
|
180
|
+
if (tokens.length === 0) throw invalid(input, "empty layer");
|
|
181
|
+
const lengths = [];
|
|
182
|
+
let color;
|
|
183
|
+
let inset = false;
|
|
184
|
+
for (const token of tokens) {
|
|
185
|
+
if (token.toLowerCase() === "inset") {
|
|
186
|
+
if (inset) throw invalid(input, "duplicate 'inset'");
|
|
187
|
+
inset = true;
|
|
188
|
+
} else if (LENGTH.test(token)) {
|
|
189
|
+
lengths.push(parseFloat(token));
|
|
190
|
+
} else if (UNIT_LIKE.test(token)) {
|
|
191
|
+
throw invalid(input, `unsupported unit in ${JSON.stringify(token)}`);
|
|
192
|
+
} else {
|
|
193
|
+
if (color !== void 0) throw invalid(input, "multiple colors");
|
|
194
|
+
color = token;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (lengths.length < 2 || lengths.length > 4) {
|
|
198
|
+
throw invalid(input, `expected 2-4 lengths, got ${lengths.length}`);
|
|
199
|
+
}
|
|
200
|
+
const [offsetX = 0, offsetY = 0, blurRadius = 0, spreadDistance = 0] = lengths;
|
|
201
|
+
if (blurRadius < 0) throw invalid(input, "negative blur radius");
|
|
202
|
+
return {
|
|
203
|
+
offsetX,
|
|
204
|
+
offsetY,
|
|
205
|
+
blurRadius,
|
|
206
|
+
spreadDistance,
|
|
207
|
+
color: color ?? "black",
|
|
208
|
+
inset
|
|
209
|
+
};
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
function resolveBoxShadowInput(input) {
|
|
213
|
+
if (input === void 0) return [];
|
|
214
|
+
if (typeof input === "string") return parseBoxShadow(input);
|
|
215
|
+
return input.map((layer) => ({
|
|
216
|
+
offsetX: coerceLength(layer.offsetX, "offsetX"),
|
|
217
|
+
offsetY: coerceLength(layer.offsetY, "offsetY"),
|
|
218
|
+
blurRadius: coerceLength(layer.blurRadius, "blurRadius"),
|
|
219
|
+
spreadDistance: coerceLength(layer.spreadDistance, "spreadDistance"),
|
|
220
|
+
color: layer.color ?? "black",
|
|
221
|
+
inset: layer.inset ?? false
|
|
222
|
+
}));
|
|
223
|
+
}
|
|
224
|
+
function pairBoxShadowLayers(from, to) {
|
|
225
|
+
const count = Math.max(from.length, to.length);
|
|
226
|
+
const pairs = [];
|
|
227
|
+
for (let i = 0; i < count; i++) {
|
|
228
|
+
const a = from[i];
|
|
229
|
+
const b = to[i];
|
|
230
|
+
const fromLayer = a ?? invisibleLayer(b.inset);
|
|
231
|
+
const toLayer = b ?? invisibleLayer(a.inset);
|
|
232
|
+
if (fromLayer.inset !== toLayer.inset) {
|
|
233
|
+
throw new Error(
|
|
234
|
+
`[inertia] useShadow: boxShadow layer ${i} is 'inset' on one side but not the other \u2014 inset cannot be interpolated. Give both sides the same inset-ness (pad with a transparent layer if needed).`
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
pairs.push({ from: fromLayer, to: toLayer });
|
|
238
|
+
}
|
|
239
|
+
return pairs;
|
|
240
|
+
}
|
|
241
|
+
function invisibleLayer(inset) {
|
|
242
|
+
return {
|
|
243
|
+
offsetX: 0,
|
|
244
|
+
offsetY: 0,
|
|
245
|
+
blurRadius: 0,
|
|
246
|
+
spreadDistance: 0,
|
|
247
|
+
color: "transparent",
|
|
248
|
+
inset
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
function coerceLength(value, field) {
|
|
252
|
+
if (value === void 0) return 0;
|
|
253
|
+
if (typeof value === "number") return value;
|
|
254
|
+
const trimmed = typeof value === "string" ? value.trim() : "";
|
|
255
|
+
if (!LENGTH.test(trimmed)) {
|
|
256
|
+
throw new Error(
|
|
257
|
+
`[inertia] boxShadow: ${field} must be a number or a px length, got ${JSON.stringify(value)}.`
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
return parseFloat(trimmed);
|
|
261
|
+
}
|
|
262
|
+
function strip(layer) {
|
|
263
|
+
const { inset: _inset, ...rest } = layer;
|
|
264
|
+
return rest;
|
|
265
|
+
}
|
|
266
|
+
function markInset(insets, i, count) {
|
|
267
|
+
const list = insets ?? new Array(count).fill(false);
|
|
268
|
+
list[i] = true;
|
|
269
|
+
return list;
|
|
270
|
+
}
|
|
271
|
+
function normalizeBoxShadow(input) {
|
|
272
|
+
const resolved = resolveBoxShadowInput(input);
|
|
273
|
+
const layers = [];
|
|
274
|
+
let insets = null;
|
|
275
|
+
for (let i = 0; i < resolved.length; i++) {
|
|
276
|
+
const layer = resolved[i];
|
|
277
|
+
layers.push(strip(layer));
|
|
278
|
+
if (layer.inset) insets = markInset(insets, i, resolved.length);
|
|
279
|
+
}
|
|
280
|
+
return { layers, insets };
|
|
281
|
+
}
|
|
282
|
+
function prepareBoxShadowAnimation(current, target) {
|
|
283
|
+
const pairs = pairBoxShadowLayers(
|
|
284
|
+
current.layers.map((layer, i) => ({
|
|
285
|
+
...layer,
|
|
286
|
+
inset: current.insets?.[i] ?? false
|
|
287
|
+
})),
|
|
288
|
+
resolveBoxShadowInput(target)
|
|
289
|
+
);
|
|
290
|
+
const from = [];
|
|
291
|
+
const to = [];
|
|
292
|
+
let insets = null;
|
|
293
|
+
for (let i = 0; i < pairs.length; i++) {
|
|
294
|
+
const pair = pairs[i];
|
|
295
|
+
from.push(strip(pair.from));
|
|
296
|
+
to.push(strip(pair.to));
|
|
297
|
+
if (pair.to.inset) insets = markInset(insets, i, pairs.length);
|
|
298
|
+
}
|
|
299
|
+
return { from, to, insets };
|
|
300
|
+
}
|
|
132
301
|
function resolveLayoutTransition(layout) {
|
|
133
302
|
if (!layout) return void 0;
|
|
134
303
|
const cfg = layout === true ? { type: "spring" } : layout;
|
|
@@ -162,72 +331,138 @@ function sweepExpired(at) {
|
|
|
162
331
|
if (entry.expiresAt < at) REGISTRY.delete(id);
|
|
163
332
|
}
|
|
164
333
|
}
|
|
165
|
-
function registerLayout(id, rect) {
|
|
334
|
+
function registerLayout(id, rect, remeasure, readStyles) {
|
|
166
335
|
const at = now();
|
|
167
336
|
sweepExpired(at);
|
|
168
|
-
REGISTRY.set(id, {
|
|
337
|
+
REGISTRY.set(id, {
|
|
338
|
+
rect,
|
|
339
|
+
expiresAt: at + SHARED_LAYOUT_TTL_MS,
|
|
340
|
+
remeasure,
|
|
341
|
+
readStyles
|
|
342
|
+
});
|
|
169
343
|
}
|
|
170
|
-
function releaseLayout(id, rect) {
|
|
344
|
+
function releaseLayout(id, rect, styles) {
|
|
171
345
|
const at = now();
|
|
172
346
|
sweepExpired(at);
|
|
173
|
-
REGISTRY.set(id, { rect, expiresAt: at + SHARED_LAYOUT_TTL_MS });
|
|
347
|
+
REGISTRY.set(id, { rect, expiresAt: at + SHARED_LAYOUT_TTL_MS, styles });
|
|
174
348
|
}
|
|
175
349
|
function consumeLayout(id) {
|
|
176
350
|
const entry = REGISTRY.get(id);
|
|
177
351
|
if (!entry) return void 0;
|
|
178
352
|
REGISTRY.delete(id);
|
|
179
353
|
if (entry.expiresAt < now()) return void 0;
|
|
180
|
-
return
|
|
354
|
+
return {
|
|
355
|
+
rect: entry.rect,
|
|
356
|
+
remeasure: entry.remeasure,
|
|
357
|
+
styles: entry.styles,
|
|
358
|
+
readStyles: entry.readStyles
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// src/layout/measureWindow.ts
|
|
363
|
+
var defaultMeasurer = (node) => {
|
|
364
|
+
const measure = node?.measureInWindow;
|
|
365
|
+
if (typeof measure !== "function") return void 0;
|
|
366
|
+
let result;
|
|
367
|
+
let returned = false;
|
|
368
|
+
try {
|
|
369
|
+
measure.call(node, (x, y, width, height) => {
|
|
370
|
+
if (returned) return;
|
|
371
|
+
result = { x, y, width, height };
|
|
372
|
+
});
|
|
373
|
+
} catch {
|
|
374
|
+
returned = true;
|
|
375
|
+
return void 0;
|
|
376
|
+
}
|
|
377
|
+
returned = true;
|
|
378
|
+
return result;
|
|
379
|
+
};
|
|
380
|
+
var measurer = defaultMeasurer;
|
|
381
|
+
function usable(rect) {
|
|
382
|
+
const { x, y, width, height } = rect;
|
|
383
|
+
for (const v of [x, y, width, height]) {
|
|
384
|
+
if (typeof v !== "number" || !Number.isFinite(v)) return false;
|
|
385
|
+
}
|
|
386
|
+
return width !== 0 || height !== 0;
|
|
387
|
+
}
|
|
388
|
+
function measureWindowRect(node) {
|
|
389
|
+
const measured = measurer(node);
|
|
390
|
+
if (!measured || !usable(measured)) return void 0;
|
|
391
|
+
return toSharedRect(measured, "window");
|
|
392
|
+
}
|
|
393
|
+
function toSharedRect(rect, space) {
|
|
394
|
+
return { ...rect, space };
|
|
181
395
|
}
|
|
182
396
|
function useSharedLayout(options) {
|
|
183
|
-
const {
|
|
397
|
+
const {
|
|
398
|
+
layoutId,
|
|
399
|
+
userRef,
|
|
400
|
+
transition,
|
|
401
|
+
shouldReduceMotion,
|
|
402
|
+
userOnLayout,
|
|
403
|
+
readStyles
|
|
404
|
+
} = options;
|
|
184
405
|
const dx = useSharedValue(0);
|
|
185
406
|
const dy = useSharedValue(0);
|
|
186
407
|
const sx = useSharedValue(1);
|
|
187
408
|
const sy = useSharedValue(1);
|
|
409
|
+
const snapshot = useSharedValue(null);
|
|
410
|
+
const carryProgress = useSharedValue(0);
|
|
188
411
|
const lastRectRef = useRef(null);
|
|
189
412
|
const consumedRef = useRef(false);
|
|
413
|
+
const nodeRef = useRef(null);
|
|
190
414
|
const transitionRef = useRef(transition);
|
|
191
415
|
transitionRef.current = transition;
|
|
192
416
|
const reducedMotionRef = useRef(shouldReduceMotion);
|
|
193
417
|
reducedMotionRef.current = shouldReduceMotion;
|
|
418
|
+
const readStylesRef = useRef(readStyles);
|
|
419
|
+
readStylesRef.current = readStyles;
|
|
194
420
|
const setRef = useCallback(
|
|
195
421
|
(node) => {
|
|
422
|
+
nodeRef.current = node;
|
|
196
423
|
if (typeof userRef === "function") userRef(node);
|
|
197
424
|
else if (userRef) userRef.current = node;
|
|
198
425
|
},
|
|
199
426
|
[userRef]
|
|
200
427
|
);
|
|
428
|
+
const remeasure = useCallback(() => measureWindowRect(nodeRef.current), []);
|
|
429
|
+
const snapshotStyles = useCallback(() => readStylesRef.current?.(), []);
|
|
430
|
+
const startTransition = useCallback(
|
|
431
|
+
(source, sourceRect, target) => {
|
|
432
|
+
if (sourceRect.space !== target.space) return;
|
|
433
|
+
const shared = {
|
|
434
|
+
transition: transitionRef.current,
|
|
435
|
+
shouldReduceMotion: reducedMotionRef.current
|
|
436
|
+
};
|
|
437
|
+
applyFlip({ source: sourceRect, target, dx, dy, sx, sy, ...shared });
|
|
438
|
+
applyStyleCarry({
|
|
439
|
+
snapshot,
|
|
440
|
+
progress: carryProgress,
|
|
441
|
+
// Prefer a live read for the same reason the rect is re-measured: a
|
|
442
|
+
// still-mounted source may have moved on since its last layout.
|
|
443
|
+
styles: source.readStyles?.() ?? source.styles,
|
|
444
|
+
...shared
|
|
445
|
+
});
|
|
446
|
+
},
|
|
447
|
+
[dx, dy, sx, sy, snapshot, carryProgress]
|
|
448
|
+
);
|
|
201
449
|
const onLayout = useCallback(
|
|
202
450
|
(event) => {
|
|
203
451
|
userOnLayout?.(event);
|
|
204
452
|
if (!layoutId) return;
|
|
205
453
|
const { x, y, width, height } = event.nativeEvent.layout;
|
|
206
|
-
const rect = { x, y, width, height };
|
|
207
|
-
lastRectRef.current = rect;
|
|
208
454
|
let source;
|
|
209
455
|
if (!consumedRef.current) {
|
|
210
456
|
consumedRef.current = true;
|
|
211
457
|
source = consumeLayout(layoutId);
|
|
212
458
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
dx,
|
|
219
|
-
dy,
|
|
220
|
-
sx,
|
|
221
|
-
sy,
|
|
222
|
-
transition: transitionRef.current,
|
|
223
|
-
shouldReduceMotion: reducedMotionRef.current
|
|
224
|
-
});
|
|
225
|
-
}
|
|
459
|
+
const rect = measureWindowRect(nodeRef.current) ?? { x, y, width, height, space: "parent" };
|
|
460
|
+
lastRectRef.current = rect;
|
|
461
|
+
registerLayout(layoutId, rect, remeasure, snapshotStyles);
|
|
462
|
+
if (!source) return;
|
|
463
|
+
startTransition(source, source.remeasure?.() ?? source.rect, rect);
|
|
226
464
|
},
|
|
227
|
-
|
|
228
|
-
// exhaustive-deps would flag them — including them is harmless and
|
|
229
|
-
// silences the warning.
|
|
230
|
-
[layoutId, userOnLayout, dx, dy, sx, sy]
|
|
465
|
+
[layoutId, userOnLayout, remeasure, snapshotStyles, startTransition]
|
|
231
466
|
);
|
|
232
467
|
useEffect(() => {
|
|
233
468
|
consumedRef.current = false;
|
|
@@ -237,18 +472,49 @@ function useSharedLayout(options) {
|
|
|
237
472
|
if (!layoutId) return;
|
|
238
473
|
const rect = lastRectRef.current;
|
|
239
474
|
if (!rect) return;
|
|
240
|
-
releaseLayout(layoutId, rect);
|
|
475
|
+
releaseLayout(layoutId, rect, snapshotStyles());
|
|
241
476
|
};
|
|
242
|
-
}, [layoutId]);
|
|
477
|
+
}, [layoutId, snapshotStyles]);
|
|
478
|
+
useEffect(
|
|
479
|
+
() => () => {
|
|
480
|
+
cancelAnimation(dx);
|
|
481
|
+
cancelAnimation(dy);
|
|
482
|
+
cancelAnimation(sx);
|
|
483
|
+
cancelAnimation(sy);
|
|
484
|
+
cancelAnimation(carryProgress);
|
|
485
|
+
},
|
|
486
|
+
// The FLIP shared values are identity-stable per hook instance.
|
|
487
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
488
|
+
[]
|
|
489
|
+
);
|
|
243
490
|
return useMemo(
|
|
244
491
|
() => ({
|
|
245
492
|
flip: { dx, dy, sx, sy },
|
|
493
|
+
carry: { snapshot, progress: carryProgress },
|
|
246
494
|
setRef,
|
|
247
495
|
onLayout
|
|
248
496
|
}),
|
|
249
|
-
[dx, dy, sx, sy, setRef, onLayout]
|
|
497
|
+
[dx, dy, sx, sy, snapshot, carryProgress, setRef, onLayout]
|
|
250
498
|
);
|
|
251
499
|
}
|
|
500
|
+
function legBuilder(transition) {
|
|
501
|
+
if (transition?.type === "timing") {
|
|
502
|
+
const duration = transition.duration ?? 300;
|
|
503
|
+
return (from, to) => withSequence(
|
|
504
|
+
withTiming(from, { duration: 0 }),
|
|
505
|
+
withTiming(to, { duration })
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
const springCfg = transition?.type === "spring" ? { ...DEFAULT_SPRING, ...transition } : { type: "spring", ...DEFAULT_SPRING };
|
|
509
|
+
const springParams = springToReanimated(springCfg);
|
|
510
|
+
return (from, to) => withSequence(
|
|
511
|
+
withTiming(from, { duration: 0 }),
|
|
512
|
+
withSpring(to, springParams)
|
|
513
|
+
);
|
|
514
|
+
}
|
|
515
|
+
function shouldSnap(transition, shouldReduceMotion) {
|
|
516
|
+
return shouldReduceMotion || transition?.type === "no-animation";
|
|
517
|
+
}
|
|
252
518
|
function applyFlip(args) {
|
|
253
519
|
const { source, target, dx, dy, sx, sy, transition, shouldReduceMotion } = args;
|
|
254
520
|
const sourceCenterX = source.x + source.width / 2;
|
|
@@ -259,58 +525,29 @@ function applyFlip(args) {
|
|
|
259
525
|
const deltaY = sourceCenterY - targetCenterY;
|
|
260
526
|
const scaleX = target.width > 0 ? source.width / target.width : 1;
|
|
261
527
|
const scaleY = target.height > 0 ? source.height / target.height : 1;
|
|
262
|
-
if (shouldReduceMotion) {
|
|
263
|
-
dx.value = 0;
|
|
264
|
-
dy.value = 0;
|
|
265
|
-
sx.value = 1;
|
|
266
|
-
sy.value = 1;
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
if (transition?.type === "no-animation") {
|
|
528
|
+
if (shouldSnap(transition, shouldReduceMotion)) {
|
|
270
529
|
dx.value = 0;
|
|
271
530
|
dy.value = 0;
|
|
272
531
|
sx.value = 1;
|
|
273
532
|
sy.value = 1;
|
|
274
533
|
return;
|
|
275
534
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
withTiming(1, { duration })
|
|
289
|
-
);
|
|
290
|
-
sy.value = withSequence(
|
|
291
|
-
withTiming(scaleY, { duration: 0 }),
|
|
292
|
-
withTiming(1, { duration })
|
|
293
|
-
);
|
|
535
|
+
const leg = legBuilder(transition);
|
|
536
|
+
dx.value = leg(deltaX, 0);
|
|
537
|
+
dy.value = leg(deltaY, 0);
|
|
538
|
+
sx.value = leg(scaleX, 1);
|
|
539
|
+
sy.value = leg(scaleY, 1);
|
|
540
|
+
}
|
|
541
|
+
function applyStyleCarry(args) {
|
|
542
|
+
const { snapshot, progress, styles, transition, shouldReduceMotion } = args;
|
|
543
|
+
if (!styles) return;
|
|
544
|
+
if (shouldSnap(transition, shouldReduceMotion)) {
|
|
545
|
+
snapshot.value = null;
|
|
546
|
+
progress.value = 0;
|
|
294
547
|
return;
|
|
295
548
|
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
dx.value = withSequence(
|
|
299
|
-
withTiming(deltaX, { duration: 0 }),
|
|
300
|
-
withSpring(0, springParams)
|
|
301
|
-
);
|
|
302
|
-
dy.value = withSequence(
|
|
303
|
-
withTiming(deltaY, { duration: 0 }),
|
|
304
|
-
withSpring(0, springParams)
|
|
305
|
-
);
|
|
306
|
-
sx.value = withSequence(
|
|
307
|
-
withTiming(scaleX, { duration: 0 }),
|
|
308
|
-
withSpring(1, springParams)
|
|
309
|
-
);
|
|
310
|
-
sy.value = withSequence(
|
|
311
|
-
withTiming(scaleY, { duration: 0 }),
|
|
312
|
-
withSpring(1, springParams)
|
|
313
|
-
);
|
|
549
|
+
snapshot.value = styles;
|
|
550
|
+
progress.value = legBuilder(transition)(1, 0);
|
|
314
551
|
}
|
|
315
552
|
var alreadyChecked = false;
|
|
316
553
|
function ensureReanimatedInstalled() {
|
|
@@ -324,7 +561,7 @@ function ensureReanimatedInstalled() {
|
|
|
324
561
|
const major = parseInt(version.split(".")[0] ?? "0", 10);
|
|
325
562
|
if (major < 4) {
|
|
326
563
|
console.error(
|
|
327
|
-
`[inertia] react-native-reanimated
|
|
564
|
+
`[inertia] react-native-reanimated ${version} is installed, but @rootnative/inertia requires 4.0.0 or later. Upgrade with \`pnpm add react-native-reanimated@^4\` (or your package manager's equivalent).`
|
|
328
565
|
);
|
|
329
566
|
return;
|
|
330
567
|
}
|
|
@@ -357,7 +594,79 @@ var NUMERIC_TOP_LEVEL_KEYS = [
|
|
|
357
594
|
"borderRadius",
|
|
358
595
|
"shadowOpacity",
|
|
359
596
|
"shadowRadius",
|
|
360
|
-
"elevation"
|
|
597
|
+
"elevation",
|
|
598
|
+
// ─── Added in 0.0.5 ──────────────────────────────────────────────────────
|
|
599
|
+
//
|
|
600
|
+
// Every key below rides the generic numeric path: one shared value, resolved
|
|
601
|
+
// on the JS thread, emitted by the worklet through the same `out[key] = v`
|
|
602
|
+
// branch as `opacity`. None needs a new interpolation mode, so the cost is
|
|
603
|
+
// the shared value plus a `DEFAULT_RESTING` entry.
|
|
604
|
+
//
|
|
605
|
+
// The load-bearing constraint is the resting default, not the plumbing. A
|
|
606
|
+
// key declared only in `gesture` / `exit` / a non-active variant rests at
|
|
607
|
+
// `DEFAULT_RESTING` unless the static `style` names it, and the animated
|
|
608
|
+
// style merges *after* `style` — so a non-identity default silently stomps
|
|
609
|
+
// the layout. That is the `0.0.3` P0 class, and it is why the sizing and
|
|
610
|
+
// spacing keys below default to `0` only in the sense RN itself does (an
|
|
611
|
+
// unset `padding` *is* 0); `minWidth`/`maxWidth`/`aspectRatio` are
|
|
612
|
+
// deliberately excluded — their "unset" is not a number, so no default can
|
|
613
|
+
// stand in for it without changing layout on activation.
|
|
614
|
+
//
|
|
615
|
+
// Per-corner radii. Animating one corner is common (a card expanding into a
|
|
616
|
+
// sheet keeps its top corners and squares off the bottom); `borderRadius`
|
|
617
|
+
// alone can't express it.
|
|
618
|
+
"borderTopLeftRadius",
|
|
619
|
+
"borderTopRightRadius",
|
|
620
|
+
"borderBottomLeftRadius",
|
|
621
|
+
"borderBottomRightRadius",
|
|
622
|
+
// Border widths. `borderWidth` is the common case; the per-edge keys matter
|
|
623
|
+
// for underline-style focus affordances (`borderBottomWidth` on a field).
|
|
624
|
+
"borderWidth",
|
|
625
|
+
"borderTopWidth",
|
|
626
|
+
"borderRightWidth",
|
|
627
|
+
"borderBottomWidth",
|
|
628
|
+
"borderLeftWidth",
|
|
629
|
+
// Absolute-position insets. Bread-and-butter for drawers, tooltips, and
|
|
630
|
+
// anything pinned to an edge that slides in.
|
|
631
|
+
"top",
|
|
632
|
+
"right",
|
|
633
|
+
"bottom",
|
|
634
|
+
"left",
|
|
635
|
+
// Spacing. Padding animates the box from the inside (a button growing its
|
|
636
|
+
// hit area on press); margin shifts it within its parent's flow.
|
|
637
|
+
"padding",
|
|
638
|
+
"paddingTop",
|
|
639
|
+
"paddingRight",
|
|
640
|
+
"paddingBottom",
|
|
641
|
+
"paddingLeft",
|
|
642
|
+
"paddingHorizontal",
|
|
643
|
+
"paddingVertical",
|
|
644
|
+
"margin",
|
|
645
|
+
"marginTop",
|
|
646
|
+
"marginRight",
|
|
647
|
+
"marginBottom",
|
|
648
|
+
"marginLeft",
|
|
649
|
+
"marginHorizontal",
|
|
650
|
+
"marginVertical",
|
|
651
|
+
// Flex sizing. `flex` / `flexGrow` interpolate the split between siblings —
|
|
652
|
+
// the idiomatic RN way to animate a pane resize without measuring.
|
|
653
|
+
"flex",
|
|
654
|
+
"flexGrow",
|
|
655
|
+
"flexShrink",
|
|
656
|
+
// Text metrics. `TextStyle`-only at the type level (`AnimateStyle<C>` gates
|
|
657
|
+
// them per primitive), but the runtime table is shared across primitives —
|
|
658
|
+
// an unused slot is one ref, same as `tintColor` has always been.
|
|
659
|
+
"fontSize",
|
|
660
|
+
"letterSpacing",
|
|
661
|
+
"lineHeight",
|
|
662
|
+
// Stacking. Integer-valued in practice, and interpolating it mid-flight is
|
|
663
|
+
// rarely what you want, but a `no-animation` transition on `zIndex` is the
|
|
664
|
+
// clean way to reorder at a step boundary in a sequence.
|
|
665
|
+
"zIndex",
|
|
666
|
+
// Gap. Row/column gaps animate a list's density without touching children.
|
|
667
|
+
"gap",
|
|
668
|
+
"rowGap",
|
|
669
|
+
"columnGap"
|
|
361
670
|
];
|
|
362
671
|
var COLOR_KEYS = [
|
|
363
672
|
"backgroundColor",
|
|
@@ -367,15 +676,28 @@ var COLOR_KEYS = [
|
|
|
367
676
|
"shadowColor"
|
|
368
677
|
];
|
|
369
678
|
var SHADOW_OFFSET_KEYS = ["shadowOffsetWidth", "shadowOffsetHeight"];
|
|
679
|
+
var STRUCTURED_KEYS = ["boxShadow"];
|
|
680
|
+
var SHARED_STYLE_KEYS = [
|
|
681
|
+
"opacity",
|
|
682
|
+
"borderRadius",
|
|
683
|
+
"backgroundColor",
|
|
684
|
+
"borderColor",
|
|
685
|
+
"color",
|
|
686
|
+
"tintColor"
|
|
687
|
+
];
|
|
370
688
|
var ALL_KEYS = [
|
|
371
689
|
...TRANSFORM_KEYS,
|
|
372
690
|
...NUMERIC_TOP_LEVEL_KEYS,
|
|
373
691
|
...COLOR_KEYS,
|
|
374
|
-
...SHADOW_OFFSET_KEYS
|
|
692
|
+
...SHADOW_OFFSET_KEYS,
|
|
693
|
+
...STRUCTURED_KEYS
|
|
375
694
|
];
|
|
376
695
|
var TRANSFORM_KEY_SET = new Set(TRANSFORM_KEYS);
|
|
377
696
|
var COLOR_KEY_SET = new Set(COLOR_KEYS);
|
|
378
697
|
var SHADOW_OFFSET_KEY_SET = new Set(SHADOW_OFFSET_KEYS);
|
|
698
|
+
var STRUCTURED_KEY_SET = new Set(STRUCTURED_KEYS);
|
|
699
|
+
var SHARED_STYLE_KEY_SET = new Set(SHARED_STYLE_KEYS);
|
|
700
|
+
var NO_BOX_SHADOW = Object.freeze([]);
|
|
379
701
|
var GESTURE_LAYER_NAMES = [
|
|
380
702
|
"hovered",
|
|
381
703
|
"focused",
|
|
@@ -400,6 +722,54 @@ var DEFAULT_RESTING = {
|
|
|
400
722
|
shadowOpacity: 0,
|
|
401
723
|
shadowRadius: 0,
|
|
402
724
|
elevation: 0,
|
|
725
|
+
// 0.0.5 keys. Every one of these is 0 because that is RN's own unset value
|
|
726
|
+
// for it — an element with no `paddingTop` has 0 padding, no `borderWidth`
|
|
727
|
+
// has none, no `top` is unpinned at 0 within its positioning context. So a
|
|
728
|
+
// key that reaches its resting default lands where the element already was.
|
|
729
|
+
//
|
|
730
|
+
// The exception worth naming: `flex` / `flexGrow` / `flexShrink` do NOT have
|
|
731
|
+
// 0 as a universal identity (`flexShrink` defaults to 1 on the web, and RN's
|
|
732
|
+
// own default differs by axis). They are still 0 here, because the style-scan
|
|
733
|
+
// in the resting pass reads the real value off the static `style` whenever it
|
|
734
|
+
// is declared — and a consumer animating flex without declaring it is asking
|
|
735
|
+
// for the from-0 growth, which is the readable interpretation.
|
|
736
|
+
borderTopLeftRadius: 0,
|
|
737
|
+
borderTopRightRadius: 0,
|
|
738
|
+
borderBottomLeftRadius: 0,
|
|
739
|
+
borderBottomRightRadius: 0,
|
|
740
|
+
borderWidth: 0,
|
|
741
|
+
borderTopWidth: 0,
|
|
742
|
+
borderRightWidth: 0,
|
|
743
|
+
borderBottomWidth: 0,
|
|
744
|
+
borderLeftWidth: 0,
|
|
745
|
+
top: 0,
|
|
746
|
+
right: 0,
|
|
747
|
+
bottom: 0,
|
|
748
|
+
left: 0,
|
|
749
|
+
padding: 0,
|
|
750
|
+
paddingTop: 0,
|
|
751
|
+
paddingRight: 0,
|
|
752
|
+
paddingBottom: 0,
|
|
753
|
+
paddingLeft: 0,
|
|
754
|
+
paddingHorizontal: 0,
|
|
755
|
+
paddingVertical: 0,
|
|
756
|
+
margin: 0,
|
|
757
|
+
marginTop: 0,
|
|
758
|
+
marginRight: 0,
|
|
759
|
+
marginBottom: 0,
|
|
760
|
+
marginLeft: 0,
|
|
761
|
+
marginHorizontal: 0,
|
|
762
|
+
marginVertical: 0,
|
|
763
|
+
flex: 0,
|
|
764
|
+
flexGrow: 0,
|
|
765
|
+
flexShrink: 0,
|
|
766
|
+
fontSize: 0,
|
|
767
|
+
letterSpacing: 0,
|
|
768
|
+
lineHeight: 0,
|
|
769
|
+
zIndex: 0,
|
|
770
|
+
gap: 0,
|
|
771
|
+
rowGap: 0,
|
|
772
|
+
columnGap: 0,
|
|
403
773
|
// 'transparent' is the only safe universal default for colors: it works as
|
|
404
774
|
// an initial seed for any color animation (no jarring opaque flash on mount
|
|
405
775
|
// when `initial` is omitted) and rgba(0,0,0,0) interpolates cleanly into
|
|
@@ -410,7 +780,8 @@ var DEFAULT_RESTING = {
|
|
|
410
780
|
tintColor: "transparent",
|
|
411
781
|
shadowColor: "transparent",
|
|
412
782
|
shadowOffsetWidth: 0,
|
|
413
|
-
shadowOffsetHeight: 0
|
|
783
|
+
shadowOffsetHeight: 0,
|
|
784
|
+
boxShadow: NO_BOX_SHADOW
|
|
414
785
|
};
|
|
415
786
|
function transitionFor(prop, transition) {
|
|
416
787
|
if (!transition) return void 0;
|
|
@@ -501,6 +872,16 @@ function createMotionComponent(Component) {
|
|
|
501
872
|
const [focused, setFocused] = useState(false);
|
|
502
873
|
const [focusVisible, setFocusVisible] = useState(false);
|
|
503
874
|
const [hovered, setHovered] = useState(false);
|
|
875
|
+
const hasLayoutId = layoutId !== void 0;
|
|
876
|
+
let flatStyle;
|
|
877
|
+
let flatStyleRead = false;
|
|
878
|
+
const getFlatStyle = () => {
|
|
879
|
+
if (!flatStyleRead) {
|
|
880
|
+
flatStyleRead = true;
|
|
881
|
+
flatStyle = StyleSheet.flatten(style);
|
|
882
|
+
}
|
|
883
|
+
return flatStyle;
|
|
884
|
+
};
|
|
504
885
|
const touched = /* @__PURE__ */ new Set();
|
|
505
886
|
collectTouchedKeys(touched, animateRecord);
|
|
506
887
|
if (initialRecord) collectTouchedKeys(touched, initialRecord);
|
|
@@ -522,9 +903,19 @@ function createMotionComponent(Component) {
|
|
|
522
903
|
}
|
|
523
904
|
}
|
|
524
905
|
if (exitRecord) collectTouchedKeys(touched, exitRecord);
|
|
906
|
+
if (hasLayoutId) {
|
|
907
|
+
const flat = getFlatStyle();
|
|
908
|
+
if (flat) {
|
|
909
|
+
for (const key of SHARED_STYLE_KEYS) {
|
|
910
|
+
if (touched.has(key)) continue;
|
|
911
|
+
if (styleValueFor(flat, key) !== void 0) touched.add(key);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
}
|
|
525
915
|
const activeKeysRef = useRef(null);
|
|
526
916
|
const hasTransformRef = useRef(false);
|
|
527
917
|
const hasShadowOffsetRef = useRef(false);
|
|
918
|
+
const hasBoxShadowRef = useRef(false);
|
|
528
919
|
const prevActive = activeKeysRef.current;
|
|
529
920
|
let grew = prevActive === null;
|
|
530
921
|
if (!grew && prevActive) {
|
|
@@ -545,6 +936,15 @@ function createMotionComponent(Component) {
|
|
|
545
936
|
hasShadowOffsetRef.current = activeKeysRef.current.some(
|
|
546
937
|
(k) => SHADOW_OFFSET_KEY_SET.has(k)
|
|
547
938
|
);
|
|
939
|
+
hasBoxShadowRef.current = activeKeysRef.current.includes("boxShadow");
|
|
940
|
+
if (__DEV__ && hasBoxShadowRef.current && activeKeysRef.current.some(
|
|
941
|
+
(k) => k !== "boxShadow" && k.startsWith("shadow")
|
|
942
|
+
)) {
|
|
943
|
+
warnOnce(
|
|
944
|
+
"boxShadow-with-native-shadow",
|
|
945
|
+
"[inertia] `boxShadow` is animated alongside the native `shadow*` keys on the same element, which applies two shadow systems at once. Pick one: `boxShadow` for the cross-platform CSS form, or the native `shadow*` keys."
|
|
946
|
+
);
|
|
947
|
+
}
|
|
548
948
|
}
|
|
549
949
|
const drivenNow = /* @__PURE__ */ new Set();
|
|
550
950
|
collectTouchedKeys(drivenNow, animateRecord);
|
|
@@ -555,17 +955,35 @@ function createMotionComponent(Component) {
|
|
|
555
955
|
const activeKeys = activeKeysRef.current;
|
|
556
956
|
const everDriven = everDrivenRef.current;
|
|
557
957
|
const styleResting = {};
|
|
958
|
+
let styleRestingShadow = null;
|
|
558
959
|
if (activeKeys.some((k) => !everDriven.has(k))) {
|
|
559
|
-
const flat =
|
|
960
|
+
const flat = getFlatStyle();
|
|
560
961
|
if (flat) {
|
|
561
962
|
for (const key of activeKeys) {
|
|
562
963
|
if (everDriven.has(key)) continue;
|
|
964
|
+
if (key === "boxShadow") {
|
|
965
|
+
const raw = flat.boxShadow;
|
|
966
|
+
if (raw !== void 0) {
|
|
967
|
+
styleRestingShadow = normalizeBoxShadow(raw);
|
|
968
|
+
styleResting.boxShadow = styleRestingShadow.layers;
|
|
969
|
+
}
|
|
970
|
+
continue;
|
|
971
|
+
}
|
|
563
972
|
const v = styleValueFor(flat, key);
|
|
564
973
|
if (v !== void 0) styleResting[key] = v;
|
|
565
974
|
}
|
|
566
975
|
}
|
|
567
976
|
}
|
|
977
|
+
const boxShadowSeedRef = useRef(null);
|
|
978
|
+
if (boxShadowSeedRef.current === null) {
|
|
979
|
+
const source = initial === false ? animateRecord.boxShadow : initialRecord?.boxShadow ?? animateRecord.boxShadow;
|
|
980
|
+
boxShadowSeedRef.current = source !== void 0 ? normalizeBoxShadow(source) : styleRestingShadow ?? {
|
|
981
|
+
layers: [...NO_BOX_SHADOW],
|
|
982
|
+
insets: null
|
|
983
|
+
};
|
|
984
|
+
}
|
|
568
985
|
const sharedValues = useAnimatableSharedValues((key) => {
|
|
986
|
+
if (key === "boxShadow") return boxShadowSeedRef.current.layers;
|
|
569
987
|
if (SHADOW_OFFSET_KEY_SET.has(key)) {
|
|
570
988
|
const axis = shadowOffsetAxisFor(key);
|
|
571
989
|
if (initial === false) {
|
|
@@ -582,11 +1000,17 @@ function createMotionComponent(Component) {
|
|
|
582
1000
|
}
|
|
583
1001
|
return initialRecord?.[key] ?? restValue(animateRecord[key]) ?? styleResting[key] ?? DEFAULT_RESTING[key];
|
|
584
1002
|
});
|
|
1003
|
+
const boxShadowInsets = useSharedValue(
|
|
1004
|
+
boxShadowSeedRef.current.insets
|
|
1005
|
+
);
|
|
585
1006
|
const styleRestingSig = stableSig(styleResting);
|
|
586
1007
|
useEffect(() => {
|
|
587
1008
|
for (const key of activeKeysRef.current) {
|
|
588
1009
|
if (everDrivenRef.current.has(key)) continue;
|
|
589
1010
|
sharedValues[key].value = styleResting[key] ?? DEFAULT_RESTING[key];
|
|
1011
|
+
if (key === "boxShadow") {
|
|
1012
|
+
boxShadowInsets.value = styleRestingShadow?.insets ?? null;
|
|
1013
|
+
}
|
|
590
1014
|
}
|
|
591
1015
|
}, [styleRestingSig]);
|
|
592
1016
|
const pressedProgress = useSharedValue(0);
|
|
@@ -643,6 +1067,30 @@ function createMotionComponent(Component) {
|
|
|
643
1067
|
}
|
|
644
1068
|
const transformGroup = transformPending > 0 ? { remaining: transformPending } : void 0;
|
|
645
1069
|
for (const key of ALL_KEYS) {
|
|
1070
|
+
if (key === "boxShadow") {
|
|
1071
|
+
const shadowTarget = baseRecord.boxShadow;
|
|
1072
|
+
if (shadowTarget === void 0) continue;
|
|
1073
|
+
const cfg2 = configFor("boxShadow");
|
|
1074
|
+
if (isExiting && reachesTerminalPhase(cfg2)) pending++;
|
|
1075
|
+
driveBoxShadow(
|
|
1076
|
+
sharedValues.boxShadow,
|
|
1077
|
+
boxShadowInsets,
|
|
1078
|
+
shadowTarget,
|
|
1079
|
+
cfg2,
|
|
1080
|
+
makeKeyCallbackFactory(
|
|
1081
|
+
"boxShadow",
|
|
1082
|
+
sharedValues.boxShadow,
|
|
1083
|
+
// The declared target, not the padded one — the padding is an
|
|
1084
|
+
// implementation detail of getting Reanimated to interpolate.
|
|
1085
|
+
shadowTarget,
|
|
1086
|
+
onAnimationEndRef,
|
|
1087
|
+
{ stepCount: 1, totalIterations: totalIterationsOf(cfg2) },
|
|
1088
|
+
isExiting ? onSettle : void 0,
|
|
1089
|
+
void 0
|
|
1090
|
+
)
|
|
1091
|
+
);
|
|
1092
|
+
continue;
|
|
1093
|
+
}
|
|
646
1094
|
const target = SHADOW_OFFSET_KEY_SET.has(key) ? shadowOffsetAxisValue(
|
|
647
1095
|
baseRecord.shadowOffset,
|
|
648
1096
|
shadowOffsetAxisFor(key)
|
|
@@ -708,19 +1156,34 @@ function createMotionComponent(Component) {
|
|
|
708
1156
|
isExiting,
|
|
709
1157
|
shouldReduceMotion
|
|
710
1158
|
);
|
|
1159
|
+
const readSharedStyles = () => {
|
|
1160
|
+
if (!hasLayoutId) return void 0;
|
|
1161
|
+
const out = {};
|
|
1162
|
+
let any = false;
|
|
1163
|
+
for (const key of activeKeysRef.current) {
|
|
1164
|
+
if (!SHARED_STYLE_KEY_SET.has(key)) continue;
|
|
1165
|
+
const v = sharedValues[key].value;
|
|
1166
|
+
if (typeof v !== "number" && typeof v !== "string") continue;
|
|
1167
|
+
out[key] = v;
|
|
1168
|
+
any = true;
|
|
1169
|
+
}
|
|
1170
|
+
return any ? out : void 0;
|
|
1171
|
+
};
|
|
711
1172
|
const sharedLayout = useSharedLayout({
|
|
712
1173
|
layoutId,
|
|
713
1174
|
userRef: ref,
|
|
714
1175
|
transition: isTopLevelTransition(transition) ? transition : void 0,
|
|
715
1176
|
shouldReduceMotion,
|
|
716
|
-
userOnLayout
|
|
1177
|
+
userOnLayout,
|
|
1178
|
+
readStyles: readSharedStyles
|
|
717
1179
|
});
|
|
718
1180
|
const flip = sharedLayout.flip;
|
|
719
|
-
const
|
|
1181
|
+
const carry = sharedLayout.carry;
|
|
720
1182
|
const animatedStyle = useAnimatedStyle(() => {
|
|
721
1183
|
const activeKeys2 = activeKeysRef.current;
|
|
722
1184
|
const hasTransform = hasTransformRef.current;
|
|
723
1185
|
const hasShadowOffset = hasShadowOffsetRef.current;
|
|
1186
|
+
const hasBoxShadow = hasBoxShadowRef.current;
|
|
724
1187
|
const out = {};
|
|
725
1188
|
const transform = [];
|
|
726
1189
|
let shadowOffsetW = 0;
|
|
@@ -729,12 +1192,15 @@ function createMotionComponent(Component) {
|
|
|
729
1192
|
const pf = focusedProgress.value;
|
|
730
1193
|
const pfv = focusVisibleProgress.value;
|
|
731
1194
|
const pp = pressedProgress.value;
|
|
1195
|
+
const carried = carry.snapshot.value;
|
|
1196
|
+
const pc = carry.progress.value;
|
|
732
1197
|
const layers = gestureSV.value;
|
|
733
1198
|
const hoveredLayer = layers ? layers.hovered : null;
|
|
734
1199
|
const focusedLayer = layers ? layers.focused : null;
|
|
735
1200
|
const focusVisibleLayer = layers ? layers.focusVisible : null;
|
|
736
1201
|
const pressedLayer = layers ? layers.pressed : null;
|
|
737
1202
|
for (const key of activeKeys2) {
|
|
1203
|
+
if (key === "boxShadow") continue;
|
|
738
1204
|
let v = sharedValues[key].value;
|
|
739
1205
|
const isColor = COLOR_KEY_SET.has(key);
|
|
740
1206
|
if (hoveredLayer && ph > 0 && hoveredLayer[key] !== void 0) {
|
|
@@ -753,6 +1219,12 @@ function createMotionComponent(Component) {
|
|
|
753
1219
|
const t = pressedLayer[key];
|
|
754
1220
|
v = isColor ? interpolateColor(pp, [0, 1], [v, t]) : v + (t - v) * pp;
|
|
755
1221
|
}
|
|
1222
|
+
if (carried !== null && pc > 0) {
|
|
1223
|
+
const s = carried[key];
|
|
1224
|
+
if (s !== void 0) {
|
|
1225
|
+
v = isColor ? interpolateColor(pc, [0, 1], [v, s]) : v + (s - v) * pc;
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
756
1228
|
if (TRANSFORM_KEY_SET.has(key)) {
|
|
757
1229
|
transform.push(
|
|
758
1230
|
ROTATION_KEYS.has(key) ? { [key]: `${v}deg` } : { [key]: v }
|
|
@@ -775,6 +1247,19 @@ function createMotionComponent(Component) {
|
|
|
775
1247
|
if (hasShadowOffset) {
|
|
776
1248
|
out.shadowOffset = { width: shadowOffsetW, height: shadowOffsetH };
|
|
777
1249
|
}
|
|
1250
|
+
if (hasBoxShadow) {
|
|
1251
|
+
const layers2 = sharedValues.boxShadow.value;
|
|
1252
|
+
const insets = boxShadowInsets.value;
|
|
1253
|
+
if (insets === null) {
|
|
1254
|
+
out.boxShadow = layers2;
|
|
1255
|
+
} else {
|
|
1256
|
+
const withInset = [];
|
|
1257
|
+
for (let i = 0; i < layers2.length; i++) {
|
|
1258
|
+
withInset.push({ ...layers2[i], inset: insets[i] });
|
|
1259
|
+
}
|
|
1260
|
+
out.boxShadow = withInset;
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
778
1263
|
return out;
|
|
779
1264
|
});
|
|
780
1265
|
const mergedStyle = useMemo(
|
|
@@ -837,60 +1322,15 @@ function hasMotionProps(props) {
|
|
|
837
1322
|
return false;
|
|
838
1323
|
}
|
|
839
1324
|
function useAnimatableSharedValues(init) {
|
|
840
|
-
const
|
|
841
|
-
const
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
const scaleY = useSharedValue(init("scaleY"));
|
|
845
|
-
const rotate = useSharedValue(init("rotate"));
|
|
846
|
-
const rotateX = useSharedValue(init("rotateX"));
|
|
847
|
-
const rotateY = useSharedValue(init("rotateY"));
|
|
848
|
-
const opacity = useSharedValue(init("opacity"));
|
|
849
|
-
const width = useSharedValue(init("width"));
|
|
850
|
-
const height = useSharedValue(init("height"));
|
|
851
|
-
const borderRadius = useSharedValue(init("borderRadius"));
|
|
852
|
-
const shadowOpacity = useSharedValue(init("shadowOpacity"));
|
|
853
|
-
const shadowRadius = useSharedValue(init("shadowRadius"));
|
|
854
|
-
const elevation = useSharedValue(init("elevation"));
|
|
855
|
-
const backgroundColor = useSharedValue(
|
|
856
|
-
init("backgroundColor")
|
|
857
|
-
);
|
|
858
|
-
const borderColor = useSharedValue(init("borderColor"));
|
|
859
|
-
const color = useSharedValue(init("color"));
|
|
860
|
-
const tintColor = useSharedValue(init("tintColor"));
|
|
861
|
-
const shadowColor = useSharedValue(init("shadowColor"));
|
|
862
|
-
const shadowOffsetWidth = useSharedValue(
|
|
863
|
-
init("shadowOffsetWidth")
|
|
864
|
-
);
|
|
865
|
-
const shadowOffsetHeight = useSharedValue(
|
|
866
|
-
init("shadowOffsetHeight")
|
|
867
|
-
);
|
|
1325
|
+
const entries = [];
|
|
1326
|
+
for (const key of ALL_KEYS) {
|
|
1327
|
+
entries.push([key, useSharedValue(init(key))]);
|
|
1328
|
+
}
|
|
868
1329
|
const ref = useRef(null);
|
|
869
1330
|
if (ref.current === null) {
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
scale,
|
|
874
|
-
scaleX,
|
|
875
|
-
scaleY,
|
|
876
|
-
rotate,
|
|
877
|
-
rotateX,
|
|
878
|
-
rotateY,
|
|
879
|
-
opacity,
|
|
880
|
-
width,
|
|
881
|
-
height,
|
|
882
|
-
borderRadius,
|
|
883
|
-
shadowOpacity,
|
|
884
|
-
shadowRadius,
|
|
885
|
-
elevation,
|
|
886
|
-
backgroundColor,
|
|
887
|
-
borderColor,
|
|
888
|
-
color,
|
|
889
|
-
tintColor,
|
|
890
|
-
shadowColor,
|
|
891
|
-
shadowOffsetWidth,
|
|
892
|
-
shadowOffsetHeight
|
|
893
|
-
};
|
|
1331
|
+
const map2 = {};
|
|
1332
|
+
for (const [key, sv] of entries) map2[key] = sv;
|
|
1333
|
+
ref.current = map2;
|
|
894
1334
|
}
|
|
895
1335
|
const map = ref.current;
|
|
896
1336
|
useEffect(
|
|
@@ -974,6 +1414,20 @@ function shadowOffsetAxisFor(key) {
|
|
|
974
1414
|
function shadowOffsetAxisValue(source, axis) {
|
|
975
1415
|
return source?.[axis];
|
|
976
1416
|
}
|
|
1417
|
+
function driveBoxShadow(slot, insetSlot, target, cfg, factory) {
|
|
1418
|
+
const currentLayers = Array.isArray(slot.value) ? slot.value : NO_BOX_SHADOW;
|
|
1419
|
+
const { from, to, insets } = prepareBoxShadowAnimation(
|
|
1420
|
+
{ layers: [...currentLayers], insets: insetSlot.value },
|
|
1421
|
+
target
|
|
1422
|
+
);
|
|
1423
|
+
insetSlot.value = insets;
|
|
1424
|
+
if (from.length !== currentLayers.length) slot.value = from;
|
|
1425
|
+
slot.value = resolveTransition(
|
|
1426
|
+
cfg,
|
|
1427
|
+
to,
|
|
1428
|
+
factory?.("animation", void 0)
|
|
1429
|
+
);
|
|
1430
|
+
}
|
|
977
1431
|
function styleValueFor(flat, key) {
|
|
978
1432
|
if (SHADOW_OFFSET_KEY_SET.has(key)) {
|
|
979
1433
|
return shadowOffsetAxisValue(
|
|
@@ -1090,6 +1544,15 @@ function resolveGestureLayers(gesture) {
|
|
|
1090
1544
|
if (!subState) continue;
|
|
1091
1545
|
const resolved = {};
|
|
1092
1546
|
for (const key of ALL_KEYS) {
|
|
1547
|
+
if (STRUCTURED_KEY_SET.has(key)) {
|
|
1548
|
+
if (__DEV__ && subState[key] !== void 0) {
|
|
1549
|
+
warnOnce(
|
|
1550
|
+
`gesture-structured-${layer}-${key}`,
|
|
1551
|
+
`[inertia] \`${key}\` is not supported inside \`gesture.${layer}\` and will be ignored. Drive it from \`animate\` (optionally via a variant keyed off the same state), or interpolate it yourself with \`useShadow\`.`
|
|
1552
|
+
);
|
|
1553
|
+
}
|
|
1554
|
+
continue;
|
|
1555
|
+
}
|
|
1093
1556
|
if (SHADOW_OFFSET_KEY_SET.has(key)) {
|
|
1094
1557
|
const axis = shadowOffsetAxisFor(key);
|
|
1095
1558
|
const so = subState.shadowOffset;
|
|
@@ -1179,4 +1642,4 @@ function compose(user, ours) {
|
|
|
1179
1642
|
};
|
|
1180
1643
|
}
|
|
1181
1644
|
|
|
1182
|
-
export { Presence, createMotionComponent, usePresence };
|
|
1645
|
+
export { Presence, createMotionComponent, pairBoxShadowLayers, resolveBoxShadowInput, usePresence };
|