@tamagui/animations-reanimated 3.0.0-beta.924.1 → 3.0.0
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/dist/cjs/createAnimations.cjs +259 -98
- package/dist/cjs/createAnimations.native.cjs +368 -147
- package/dist/cjs/createAnimations.native.js +368 -147
- package/dist/cjs/createAnimations.native.js.map +1 -1
- package/dist/cjs/createAnimationsCompiler.native.cjs +1 -5
- package/dist/cjs/createAnimationsCompiler.native.js +1 -5
- package/dist/cjs/createAnimationsCompiler.native.js.map +1 -1
- package/dist/cjs/textInputHost.cjs +24 -0
- package/dist/cjs/textInputHost.native.cjs +26 -0
- package/dist/cjs/textInputHost.native.js +28 -0
- package/dist/cjs/textInputHost.native.js.map +1 -0
- package/dist/esm/createAnimations.mjs +261 -100
- package/dist/esm/createAnimations.mjs.map +1 -1
- package/dist/esm/createAnimations.native.js +370 -149
- package/dist/esm/createAnimations.native.js.map +1 -1
- package/dist/esm/createAnimationsCompiler.native.js +1 -5
- package/dist/esm/createAnimationsCompiler.native.js.map +1 -1
- package/dist/esm/textInputHost.mjs +4 -0
- package/dist/esm/textInputHost.mjs.map +1 -0
- package/dist/esm/textInputHost.native.js +3 -0
- package/package.json +10 -9
- package/src/createAnimations.tsx +572 -173
- package/src/textInputHost.native.ts +1 -0
- package/src/textInputHost.ts +4 -0
- package/types/createAnimations.d.ts +4 -4
- package/types/createAnimations.d.ts.map +2 -2
- package/types/textInputHost.d.ts +4 -0
- package/types/textInputHost.d.ts.map +11 -0
- package/types/textInputHost.native.d.ts +3 -0
- package/types/textInputHost.native.d.ts.map +11 -0
|
@@ -30,11 +30,13 @@ module.exports = __toCommonJS(createAnimations_exports);
|
|
|
30
30
|
var import_animation_helpers = require("@tamagui/animation-helpers");
|
|
31
31
|
var import_core = require("@tamagui/core");
|
|
32
32
|
var import_internal_runtime = require("@tamagui/web/internal-runtime");
|
|
33
|
+
var import_textInputHost = require("./textInputHost.cjs");
|
|
33
34
|
var import_use_presence = require("@tamagui/use-presence");
|
|
34
35
|
var import_normalize_colors = __toESM(require("@react-native/normalize-colors"), 1);
|
|
35
36
|
var import_react = __toESM(require("react"), 1);
|
|
36
37
|
var import_react_native_reanimated = __toESM(require("react-native-reanimated"), 1);
|
|
37
38
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
39
|
+
const NON_ANIMATABLE_VALUE = /^(auto|min-content|max-content|fit-content|stretch|inherit|initial|unset)\b|^calc\(/;
|
|
38
40
|
const getDefaultExport = (module2) => {
|
|
39
41
|
const mod = module2;
|
|
40
42
|
if (mod.__esModule || mod[Symbol.toStringTag] === "Module") {
|
|
@@ -60,13 +62,15 @@ const resolveDynamicValue = (value, isDark) => {
|
|
|
60
62
|
}
|
|
61
63
|
return value;
|
|
62
64
|
};
|
|
63
|
-
const updateMapperState = import_core.isWeb ? (state, emitted) => {
|
|
65
|
+
const updateMapperState = import_core.isWeb ? (state, emitted, ownedStatics) => {
|
|
64
66
|
state.value.emitted = emitted;
|
|
65
|
-
|
|
67
|
+
state.value.ownedStatics = ownedStatics;
|
|
68
|
+
} : (state, emitted, ownedStatics) => {
|
|
66
69
|
"worklet";
|
|
67
70
|
if (!globalThis._WORKLET) return;
|
|
68
71
|
state.modify((current) => {
|
|
69
72
|
current.emitted = emitted;
|
|
73
|
+
current.ownedStatics = ownedStatics;
|
|
70
74
|
return current;
|
|
71
75
|
}, false);
|
|
72
76
|
};
|
|
@@ -120,6 +124,11 @@ const getImplicitDefault = (key, targetValue) => {
|
|
|
120
124
|
}
|
|
121
125
|
return suffixIndex > 0 ? `${value}${targetValue.slice(suffixIndex)}` : value;
|
|
122
126
|
};
|
|
127
|
+
const getLeadingRatio = (metrics) => {
|
|
128
|
+
const ratio = metrics?.lineHeight;
|
|
129
|
+
return typeof ratio === "number" && Number.isFinite(ratio) && ratio >= 0 ? ratio : void 0;
|
|
130
|
+
};
|
|
131
|
+
const derivesLeadingProduct = (style, ratio, inheritsFontSize, resolved) => ratio !== void 0 && (inheritsFontSize || typeof style.lineHeight === "number" && typeof style.fontSize === "number" && (!!(0, import_animation_helpers.getTransitionForKey)(resolved, "fontSize") || !!(0, import_animation_helpers.getTransitionForKey)(resolved, "lineHeight")));
|
|
123
132
|
const COLOR_STYLE_KEYS = {
|
|
124
133
|
backgroundColor: true,
|
|
125
134
|
borderColor: true,
|
|
@@ -162,7 +171,7 @@ const normalizeAnimationColor = (value) => {
|
|
|
162
171
|
const alpha = (color & 255) / 255;
|
|
163
172
|
return `rgba(${red}, ${green}, ${blue}, ${alpha})`;
|
|
164
173
|
};
|
|
165
|
-
const buildSnapshot = (animated, statics, transforms, previousKeys, lastPainted) => {
|
|
174
|
+
const buildSnapshot = (animated, statics, transforms, previousKeys, lastPainted, derivesLeading = false) => {
|
|
166
175
|
const snapshotAnimated = {};
|
|
167
176
|
const snapshotStatics = cloneStyleRecord(statics);
|
|
168
177
|
for (const key in snapshotStatics) {
|
|
@@ -186,6 +195,7 @@ const buildSnapshot = (animated, statics, transforms, previousKeys, lastPainted)
|
|
|
186
195
|
}
|
|
187
196
|
const snapshotTransforms = transforms.map(cloneStyleRecord);
|
|
188
197
|
const keys = new Set(Object.keys(snapshotAnimated));
|
|
198
|
+
if (derivesLeading) keys.add("lineHeight");
|
|
189
199
|
for (const transform of snapshotTransforms) {
|
|
190
200
|
const key = Object.keys(transform)[0];
|
|
191
201
|
const value = key ? transform[key] : void 0;
|
|
@@ -194,10 +204,19 @@ const buildSnapshot = (animated, statics, transforms, previousKeys, lastPainted)
|
|
|
194
204
|
}
|
|
195
205
|
}
|
|
196
206
|
const seeds = {};
|
|
207
|
+
const staticTransforms = getAnimatedTransforms(snapshotStatics.transform);
|
|
208
|
+
for (const transform of staticTransforms) {
|
|
209
|
+
const key = Object.keys(transform)[0];
|
|
210
|
+
if (keys.has(`transform:${key}`) && previousKeys.has(`transform:${key}`)) seeds[`transform:${key}`] = transform[key];
|
|
211
|
+
}
|
|
197
212
|
for (const key of keys) {
|
|
198
|
-
let value = lastPainted[key];
|
|
199
|
-
if (typeof value !== "number" && typeof value !== "string")
|
|
200
|
-
|
|
213
|
+
let value = previousKeys.has(key) ? seeds[key] ?? snapshotStatics[key] ?? lastPainted[key] : lastPainted[key];
|
|
214
|
+
if (typeof value !== "number" && typeof value !== "string") {
|
|
215
|
+
delete seeds[key];
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
if (typeof value === "string" && NON_ANIMATABLE_VALUE.test(value)) {
|
|
219
|
+
delete seeds[key];
|
|
201
220
|
continue;
|
|
202
221
|
}
|
|
203
222
|
if (COLOR_STYLE_KEYS[key]) value = normalizeAnimationColor(value);
|
|
@@ -205,13 +224,13 @@ const buildSnapshot = (animated, statics, transforms, previousKeys, lastPainted)
|
|
|
205
224
|
}
|
|
206
225
|
const gatedKeys = {};
|
|
207
226
|
for (const key of keys) gatedKeys[key] = true;
|
|
227
|
+
if (derivesLeading) delete gatedKeys.lineHeight;
|
|
208
228
|
const removedKeys = getRemovedAnimatedKeys(keys, previousKeys);
|
|
209
229
|
const painted = {
|
|
210
230
|
...snapshotStatics,
|
|
211
231
|
...snapshotAnimated
|
|
212
232
|
};
|
|
213
|
-
|
|
214
|
-
delete painted.transform;
|
|
233
|
+
painted.transform = snapshotTransforms.length ? snapshotTransforms : staticTransforms;
|
|
215
234
|
for (const transform of staticTransforms) {
|
|
216
235
|
const key = Object.keys(transform)[0];
|
|
217
236
|
if (key) painted[`transform:${key}`] = transform[key];
|
|
@@ -226,6 +245,7 @@ const buildSnapshot = (animated, statics, transforms, previousKeys, lastPainted)
|
|
|
226
245
|
statics: snapshotStatics,
|
|
227
246
|
transforms: snapshotTransforms,
|
|
228
247
|
gatedKeys,
|
|
248
|
+
derivesLeading,
|
|
229
249
|
seeds,
|
|
230
250
|
removedKeys,
|
|
231
251
|
removeTransform: Object.keys(removedKeys).some((key) => key.startsWith("transform:")),
|
|
@@ -249,7 +269,7 @@ const createReanimatedConfig = (config) => {
|
|
|
249
269
|
}
|
|
250
270
|
return next;
|
|
251
271
|
};
|
|
252
|
-
const applyAnimation = (targetValue, config, callback, seedValue, validateStartAsColor = false) => {
|
|
272
|
+
const applyAnimation = (targetValue, config, callback, seedValue, validateStartAsColor = false, publishTo) => {
|
|
253
273
|
"worklet";
|
|
254
274
|
const delay = config.delay;
|
|
255
275
|
const reanimatedConfig = createReanimatedConfig(config);
|
|
@@ -264,7 +284,11 @@ const applyAnimation = (targetValue, config, callback, seedValue, validateStartA
|
|
|
264
284
|
return innerOnFrame(animation, now < animation.lastTimestamp ? animation.lastTimestamp : now);
|
|
265
285
|
};
|
|
266
286
|
}
|
|
267
|
-
|
|
287
|
+
const isAnimationDescriptor = animatedValue !== null && typeof animatedValue !== "number" && typeof animatedValue !== "string" && typeof animatedValue !== "boolean" && typeof animatedValue !== "undefined";
|
|
288
|
+
if (isAnimationDescriptor && delay && delay > 0) {
|
|
289
|
+
animatedValue = (0, import_react_native_reanimated.withDelay)(delay, animatedValue);
|
|
290
|
+
}
|
|
291
|
+
if (isAnimationDescriptor && (seedValue !== void 0 || validateStartAsColor)) {
|
|
268
292
|
const innerOnStart = animatedValue.onStart;
|
|
269
293
|
animatedValue.onStart = (animation, value, timestamp, previousAnimation) => {
|
|
270
294
|
"worklet";
|
|
@@ -272,15 +296,28 @@ const applyAnimation = (targetValue, config, callback, seedValue, validateStartA
|
|
|
272
296
|
innerOnStart(animation, startValue, timestamp, previousAnimation);
|
|
273
297
|
};
|
|
274
298
|
}
|
|
275
|
-
if (
|
|
276
|
-
|
|
299
|
+
if (isAnimationDescriptor && publishTo) {
|
|
300
|
+
const startedOn = animatedValue.onStart;
|
|
301
|
+
animatedValue.onStart = (animation, value, timestamp, previousAnimation) => {
|
|
302
|
+
"worklet";
|
|
303
|
+
startedOn(animation, value, timestamp, previousAnimation);
|
|
304
|
+
publishTo.value = animation.current;
|
|
305
|
+
};
|
|
306
|
+
const framedOn = animatedValue.onFrame;
|
|
307
|
+
animatedValue.onFrame = (animation, now) => {
|
|
308
|
+
"worklet";
|
|
309
|
+
const finished = framedOn(animation, now);
|
|
310
|
+
publishTo.value = animation.current;
|
|
311
|
+
return finished;
|
|
312
|
+
};
|
|
277
313
|
}
|
|
278
314
|
return animatedValue;
|
|
279
315
|
};
|
|
280
|
-
const animateSnapshotValue = (key, implicitKey, targetValue, config, previouslyEmitted, seedValue, gated, currentlyExiting, exitCycleId, currentlyCompletingEnter, enterCycleId, currentlyCompletingUpdate, updateCycleId, markExitKeyDone, markEnterKeyDone, markUpdateKeyDone, validateStartAsColor = false) => {
|
|
316
|
+
const animateSnapshotValue = (key, implicitKey, targetValue, config, previouslyEmitted, seedValue, gated, currentlyExiting, exitCycleId, currentlyCompletingEnter, enterCycleId, currentlyCompletingUpdate, updateCycleId, markExitKeyDone, markEnterKeyDone, markUpdateKeyDone, validateStartAsColor = false, publishTo) => {
|
|
281
317
|
"worklet";
|
|
282
318
|
const cycleGated = gated && (currentlyExiting || currentlyCompletingEnter || currentlyCompletingUpdate);
|
|
283
319
|
if (!previouslyEmitted && seedValue === void 0 && !cycleGated) {
|
|
320
|
+
if (publishTo && typeof targetValue === "number") publishTo.value = targetValue;
|
|
284
321
|
return targetValue;
|
|
285
322
|
}
|
|
286
323
|
let callback;
|
|
@@ -300,7 +337,7 @@ const animateSnapshotValue = (key, implicitKey, targetValue, config, previouslyE
|
|
|
300
337
|
(0, import_react_native_reanimated.runOnJS)(markUpdateKeyDone)(key, updateCycleId, finished ?? false);
|
|
301
338
|
};
|
|
302
339
|
}
|
|
303
|
-
return applyAnimation(targetValue, config, callback, previouslyEmitted ? void 0 : seedValue ?? getImplicitDefault(implicitKey, targetValue), validateStartAsColor);
|
|
340
|
+
return applyAnimation(targetValue, config, callback, previouslyEmitted ? void 0 : seedValue ?? getImplicitDefault(implicitKey, targetValue), validateStartAsColor, publishTo);
|
|
304
341
|
};
|
|
305
342
|
const ANIMATABLE_PROPERTIES = {
|
|
306
343
|
transform: true,
|
|
@@ -357,20 +394,18 @@ const ANIMATABLE_PROPERTIES = {
|
|
|
357
394
|
flexGrow: true,
|
|
358
395
|
flexShrink: true
|
|
359
396
|
};
|
|
360
|
-
const canAnimateProperty = (key, value
|
|
397
|
+
const canAnimateProperty = (key, value) => {
|
|
361
398
|
if (!ANIMATABLE_PROPERTIES[key]) return false;
|
|
362
|
-
if (value === "
|
|
363
|
-
if (typeof value === "string" && value.startsWith("calc")) return false;
|
|
364
|
-
if (animateOnly && !animateOnly.includes(key)) return false;
|
|
399
|
+
if (typeof value === "string" && NON_ANIMATABLE_VALUE.test(value)) return false;
|
|
365
400
|
return true;
|
|
366
401
|
};
|
|
367
|
-
const splitAnimationStyles = (style, isDark, disableAnimation
|
|
402
|
+
const splitAnimationStyles = (style, isDark, disableAnimation) => {
|
|
368
403
|
const animated = {};
|
|
369
404
|
const statics = {};
|
|
370
405
|
for (const key in style) {
|
|
371
406
|
const value = resolveDynamicValue(style[key], isDark);
|
|
372
407
|
if (value === void 0) continue;
|
|
373
|
-
if (!disableAnimation && canAnimateProperty(key, value
|
|
408
|
+
if (!disableAnimation && canAnimateProperty(key, value)) {
|
|
374
409
|
animated[key] = cloneAnimationValue(value);
|
|
375
410
|
} else {
|
|
376
411
|
statics[key] = cloneAnimationValue(value);
|
|
@@ -409,49 +444,72 @@ function createWebAnimatedComponent(defaultTag) {
|
|
|
409
444
|
}
|
|
410
445
|
const AnimatedView = createWebAnimatedComponent("div");
|
|
411
446
|
const AnimatedText = createWebAnimatedComponent("span");
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
if (
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
delay: normalized.delay
|
|
420
|
-
});
|
|
447
|
+
let animatedTextInput;
|
|
448
|
+
const defaultConfig = { type: "spring" };
|
|
449
|
+
const bezierEasings = /* @__PURE__ */ new Map();
|
|
450
|
+
function bezierEasing(easing) {
|
|
451
|
+
if (!bezierEasings.has(easing)) {
|
|
452
|
+
const bezier = (0, import_animation_helpers.easingToBezier)(easing);
|
|
453
|
+
bezierEasings.set(easing, bezier ? import_react_native_reanimated.Easing.bezier(bezier[0], bezier[1], bezier[2], bezier[3]) : void 0);
|
|
421
454
|
}
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
}
|
|
455
|
+
return bezierEasings.get(easing);
|
|
456
|
+
}
|
|
457
|
+
function entryToReanimated(entry) {
|
|
458
|
+
if (entry.timing.kind === "spring") {
|
|
459
|
+
return {
|
|
460
|
+
type: "spring",
|
|
461
|
+
stiffness: entry.timing.stiffness,
|
|
462
|
+
damping: entry.timing.damping,
|
|
463
|
+
mass: entry.timing.mass,
|
|
464
|
+
delay: entry.delayMs || void 0
|
|
465
|
+
};
|
|
433
466
|
}
|
|
467
|
+
return {
|
|
468
|
+
type: "timing",
|
|
469
|
+
duration: entry.timing.durationMs,
|
|
470
|
+
easing: bezierEasing(entry.timing.easing),
|
|
471
|
+
delay: entry.delayMs || void 0
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
function buildTransitionConfig(transition, animations, animationState, styleKeys) {
|
|
475
|
+
const resolved = (0, import_animation_helpers.forAnimationState)((0, import_animation_helpers.resolveTransition)(transition, { animations }), animationState);
|
|
476
|
+
const base = resolved.all ? entryToReanimated(resolved.all) : { ...defaultConfig };
|
|
434
477
|
const propertyConfigs = {};
|
|
435
478
|
for (const key of styleKeys) {
|
|
436
|
-
const
|
|
437
|
-
|
|
438
|
-
propertyConfigs[key] = cloneTransitionConfig(animations[propAnimation] ?? base);
|
|
439
|
-
} else if (propAnimation && typeof propAnimation === "object") {
|
|
440
|
-
const configType = propAnimation.type;
|
|
441
|
-
const baseForProp = configType ? animations[configType] ?? base : base;
|
|
442
|
-
propertyConfigs[key] = cloneTransitionConfig({
|
|
443
|
-
...baseForProp,
|
|
444
|
-
...propAnimation
|
|
445
|
-
});
|
|
446
|
-
} else {
|
|
447
|
-
propertyConfigs[key] = cloneTransitionConfig(base);
|
|
448
|
-
}
|
|
479
|
+
const entry = (0, import_animation_helpers.getTransitionForKey)(resolved, key);
|
|
480
|
+
propertyConfigs[key] = entry ? entryToReanimated(entry) : instantConfig();
|
|
449
481
|
}
|
|
450
482
|
return {
|
|
451
483
|
baseConfig: base,
|
|
452
|
-
propertyConfigs
|
|
484
|
+
propertyConfigs,
|
|
485
|
+
resolved
|
|
453
486
|
};
|
|
454
487
|
}
|
|
488
|
+
const instantConfig = () => ({
|
|
489
|
+
type: "timing",
|
|
490
|
+
duration: 0
|
|
491
|
+
});
|
|
492
|
+
function sameTransitionConfig(a, b) {
|
|
493
|
+
const aKeys = Object.keys(a);
|
|
494
|
+
if (aKeys.length !== Object.keys(b).length) return false;
|
|
495
|
+
for (const key of aKeys) {
|
|
496
|
+
if (a[key] !== b[key]) return false;
|
|
497
|
+
}
|
|
498
|
+
return true;
|
|
499
|
+
}
|
|
500
|
+
function sameDriverConfig(a, b) {
|
|
501
|
+
if (a.disableAnimation !== b.disableAnimation || a.isHydrating !== b.isHydrating) {
|
|
502
|
+
return false;
|
|
503
|
+
}
|
|
504
|
+
if (!sameTransitionConfig(a.baseConfig, b.baseConfig)) return false;
|
|
505
|
+
const aKeys = Object.keys(a.propertyConfigs);
|
|
506
|
+
if (aKeys.length !== Object.keys(b.propertyConfigs).length) return false;
|
|
507
|
+
for (const key of aKeys) {
|
|
508
|
+
const other = b.propertyConfigs[key];
|
|
509
|
+
if (!other || !sameTransitionConfig(a.propertyConfigs[key], other)) return false;
|
|
510
|
+
}
|
|
511
|
+
return true;
|
|
512
|
+
}
|
|
455
513
|
function getStyleKeys(style) {
|
|
456
514
|
const keys = new Set(Object.keys(style));
|
|
457
515
|
if (style.transform && Array.isArray(style.transform)) {
|
|
@@ -463,14 +521,7 @@ function getStyleKeys(style) {
|
|
|
463
521
|
}
|
|
464
522
|
return keys;
|
|
465
523
|
}
|
|
466
|
-
function createAnimations(
|
|
467
|
-
const animations = {};
|
|
468
|
-
for (const key in animationsConfig) {
|
|
469
|
-
animations[key] = cloneTransitionConfig({
|
|
470
|
-
type: "spring",
|
|
471
|
-
...animationsConfig[key]
|
|
472
|
-
});
|
|
473
|
-
}
|
|
524
|
+
function createAnimations(animations) {
|
|
474
525
|
return {
|
|
475
526
|
needsCustomComponent: true,
|
|
476
527
|
View: import_core.isWeb ? AnimatedView : Animated.View,
|
|
@@ -481,6 +532,31 @@ function createAnimations(animationsConfig) {
|
|
|
481
532
|
animations,
|
|
482
533
|
usePresence: import_use_presence.usePresence,
|
|
483
534
|
ResetPresence: import_use_presence.ResetPresence,
|
|
535
|
+
useTextMetrics: ({ inheritedText, lineHeight }) => {
|
|
536
|
+
const node = inheritedText?.driver === "reanimated" ? inheritedText.fontSize : null;
|
|
537
|
+
const ratio = typeof lineHeight === "number" ? lineHeight : null;
|
|
538
|
+
const animatedStyle = (0, import_react_native_reanimated.useAnimatedStyle)(() => {
|
|
539
|
+
"worklet";
|
|
540
|
+
if (!node) return {};
|
|
541
|
+
const fontSize = node.value;
|
|
542
|
+
return ratio === null ? { fontSize } : {
|
|
543
|
+
fontSize,
|
|
544
|
+
lineHeight: fontSize * ratio
|
|
545
|
+
};
|
|
546
|
+
}, [node, ratio]);
|
|
547
|
+
const textChannel = inheritedText ?? null;
|
|
548
|
+
if (!node || !import_textInputHost.TextInputHost) return {
|
|
549
|
+
style: null,
|
|
550
|
+
textChannel
|
|
551
|
+
};
|
|
552
|
+
animatedTextInput ||= Animated.createAnimatedComponent(import_textInputHost.TextInputHost);
|
|
553
|
+
return {
|
|
554
|
+
style: animatedStyle,
|
|
555
|
+
textChannel,
|
|
556
|
+
Text: import_core.isWeb ? AnimatedText : Animated.Text,
|
|
557
|
+
TextInput: animatedTextInput
|
|
558
|
+
};
|
|
559
|
+
},
|
|
484
560
|
useAnimatedNumber(initial) {
|
|
485
561
|
const sharedValue = (0, import_react_native_reanimated.useSharedValue)(initial);
|
|
486
562
|
return (0, import_react.useMemo)(() => ({
|
|
@@ -557,7 +633,7 @@ function createAnimations(animationsConfig) {
|
|
|
557
633
|
return animatedStyle;
|
|
558
634
|
},
|
|
559
635
|
useAnimations(animationProps) {
|
|
560
|
-
const { props, presence, style, componentState, useStyleEmitter, themeName, stateRef, styleState, onTransition } = animationProps;
|
|
636
|
+
const { props, presence, style, componentState, useStyleEmitter, themeName, stateRef, styleState, onTransition, inheritedText } = animationProps;
|
|
561
637
|
const isHydrating = componentState.unmounted === true;
|
|
562
638
|
const isMounting = componentState.unmounted === "should-enter";
|
|
563
639
|
const isEntering = !!componentState.unmounted;
|
|
@@ -568,10 +644,27 @@ function createAnimations(animationsConfig) {
|
|
|
568
644
|
wasEnteringRef.current = isEntering;
|
|
569
645
|
});
|
|
570
646
|
const effectiveTransition = styleState?.effectiveTransition ?? props.transition;
|
|
571
|
-
const
|
|
647
|
+
const leadingRatio = getLeadingRatio(styleState?.nativeTextMetrics);
|
|
572
648
|
const animationState = isExiting ? "exit" : isMounting || justFinishedEntering ? "enter" : "default";
|
|
573
|
-
const
|
|
574
|
-
const disableAnimation = isHydrating || !
|
|
649
|
+
const resolvedTransition = (0, import_animation_helpers.forAnimationState)((0, import_animation_helpers.resolveTransition)(effectiveTransition, { animations }), animationState);
|
|
650
|
+
const disableAnimation = isHydrating || !(0, import_animation_helpers.hasTransition)(resolvedTransition);
|
|
651
|
+
const fontSizeShared = (0, import_react_native_reanimated.useSharedValue)(typeof style.fontSize === "number" ? style.fontSize : 0);
|
|
652
|
+
const publishesFontSize = !disableAnimation && typeof style.fontSize === "number";
|
|
653
|
+
const ownTextChannel = (0, import_react.useMemo)(() => ({
|
|
654
|
+
fontSize: fontSizeShared,
|
|
655
|
+
driver: "reanimated"
|
|
656
|
+
}), [fontSizeShared]);
|
|
657
|
+
const inheritedFontSize = leadingRatio !== void 0 && typeof style.fontSize !== "number" && inheritedText?.driver === "reanimated" ? inheritedText.fontSize : null;
|
|
658
|
+
const leadingFontSize = inheritedFontSize ?? fontSizeShared;
|
|
659
|
+
const leadingRatioShared = (0, import_react_native_reanimated.useSharedValue)(leadingRatio ?? 0);
|
|
660
|
+
const paintedRatioRef = (0, import_react.useRef)(leadingRatio);
|
|
661
|
+
const applyLeadingRatio = (ratio, config) => {
|
|
662
|
+
const previous = paintedRatioRef.current;
|
|
663
|
+
if (previous === ratio) return;
|
|
664
|
+
paintedRatioRef.current = ratio;
|
|
665
|
+
if (ratio === void 0) return;
|
|
666
|
+
leadingRatioShared.value = previous === void 0 || disableAnimation ? ratio : applyAnimation(ratio, config);
|
|
667
|
+
};
|
|
575
668
|
const isDark = themeName?.startsWith("dark") || false;
|
|
576
669
|
const sendExitComplete = presence?.[1];
|
|
577
670
|
const onTransitionRef = (0, import_react.useRef)(onTransition);
|
|
@@ -596,16 +689,18 @@ function createAnimations(animationsConfig) {
|
|
|
596
689
|
const updateCompletedRef = (0, import_react.useRef)(false);
|
|
597
690
|
const isCompletingUpdateRef = (0, import_react_native_reanimated.useSharedValue)(false);
|
|
598
691
|
const updateCycleIdShared = (0, import_react_native_reanimated.useSharedValue)(0);
|
|
692
|
+
const updateInterruptedRef = (0, import_react.useRef)(false);
|
|
599
693
|
const markUpdateKeyDone = (0, import_core.useEvent)((key, cycleId, finished) => {
|
|
600
|
-
if (
|
|
694
|
+
if (cycleId !== updateCycleIdRef.current) return;
|
|
601
695
|
if (updateCompletedRef.current) return;
|
|
696
|
+
if (!finished) updateInterruptedRef.current = true;
|
|
602
697
|
pendingUpdateKeysRef.current.delete(key);
|
|
603
698
|
if (pendingUpdateKeysRef.current.size === 0) {
|
|
604
699
|
updateCompletedRef.current = true;
|
|
605
700
|
isCompletingUpdateRef.value = false;
|
|
606
701
|
if (updateStartedRef.current) {
|
|
607
702
|
updateStartedRef.current = false;
|
|
608
|
-
emit("end", "update",
|
|
703
|
+
emit("end", "update", !updateInterruptedRef.current);
|
|
609
704
|
}
|
|
610
705
|
}
|
|
611
706
|
});
|
|
@@ -690,16 +785,45 @@ function createAnimations(animationsConfig) {
|
|
|
690
785
|
const committedRenderKeysRef = (0, import_react.useRef)(/* @__PURE__ */ new Set());
|
|
691
786
|
const lastPaintedRef = (0, import_react.useRef)({});
|
|
692
787
|
const carryRef = (0, import_react.useRef)({});
|
|
788
|
+
const exitSeedRef = (0, import_react.useRef)(null);
|
|
789
|
+
const paintedPredecessor = isExiting ? exitSeedRef.current ?? lastPaintedRef.current : lastPaintedRef.current;
|
|
790
|
+
(0, import_core.useIsomorphicLayoutEffect)(() => {
|
|
791
|
+
exitSeedRef.current = isExiting ? paintedPredecessor : null;
|
|
792
|
+
}, [isExiting, paintedPredecessor]);
|
|
693
793
|
const { animatedStyles, staticStyles, nextCarry } = (0, import_react.useMemo)(() => {
|
|
694
|
-
const
|
|
695
|
-
|
|
794
|
+
const { animated, statics } = splitAnimationStyles(style, isDark, disableAnimation);
|
|
795
|
+
if (isExiting && animated.transform) {
|
|
796
|
+
const remaining = getAnimatedTransforms(animated.transform).map(cloneStyleRecord);
|
|
797
|
+
const previous = getAnimatedTransforms(paintedPredecessor.transform);
|
|
798
|
+
if (previous.length) {
|
|
799
|
+
animated.transform = previous.map((entry) => {
|
|
800
|
+
const key = Object.keys(entry)[0];
|
|
801
|
+
const index = remaining.findIndex((target) => key in target);
|
|
802
|
+
return index < 0 ? cloneStyleRecord(entry) : remaining.splice(index, 1)[0];
|
|
803
|
+
}).concat(remaining);
|
|
804
|
+
}
|
|
805
|
+
}
|
|
696
806
|
const nextCarry2 = cloneStyleRecord(carryRef.current);
|
|
697
807
|
for (const key in nextCarry2) {
|
|
698
808
|
if (!(key in animated)) delete nextCarry2[key];
|
|
699
809
|
}
|
|
700
810
|
for (const key in animated) {
|
|
701
811
|
if (!(key in nextCarry2)) {
|
|
702
|
-
|
|
812
|
+
const target = animated[key];
|
|
813
|
+
if (isExiting && key === "transform") {
|
|
814
|
+
nextCarry2[key] = getAnimatedTransforms(target).map((transform) => {
|
|
815
|
+
const initial = cloneStyleRecord(transform);
|
|
816
|
+
for (const part in initial) {
|
|
817
|
+
const value = initial[part];
|
|
818
|
+
if (typeof value === "number" || typeof value === "string") {
|
|
819
|
+
initial[part] = paintedPredecessor[`transform:${part}`] ?? getImplicitDefault(part, value);
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
return initial;
|
|
823
|
+
});
|
|
824
|
+
} else {
|
|
825
|
+
nextCarry2[key] = cloneAnimationValue(isExiting && (typeof target === "number" || typeof target === "string") ? paintedPredecessor[key] ?? getImplicitDefault(key, target) : target);
|
|
826
|
+
}
|
|
703
827
|
}
|
|
704
828
|
statics[key] = nextCarry2[key];
|
|
705
829
|
}
|
|
@@ -712,14 +836,22 @@ function createAnimations(animationsConfig) {
|
|
|
712
836
|
disableAnimation,
|
|
713
837
|
style,
|
|
714
838
|
isDark,
|
|
715
|
-
|
|
839
|
+
isExiting,
|
|
840
|
+
isExiting ? paintedPredecessor : null
|
|
841
|
+
]);
|
|
842
|
+
const derivesLeading = derivesLeadingProduct(animatedStyles, leadingRatio, !!inheritedFontSize, resolvedTransition);
|
|
843
|
+
const renderSnapshot = (0, import_react.useMemo)(() => buildSnapshot(animatedStyles, staticStyles, getAnimatedTransforms(animatedStyles.transform), committedRenderKeysRef.current, paintedPredecessor, derivesLeading), [
|
|
844
|
+
animatedStyles,
|
|
845
|
+
staticStyles,
|
|
846
|
+
isExiting ? paintedPredecessor : null,
|
|
847
|
+
derivesLeading
|
|
716
848
|
]);
|
|
717
|
-
const renderSnapshot = (0, import_react.useMemo)(() => buildSnapshot(animatedStyles, staticStyles, getAnimatedTransforms(animatedStyles.transform), committedRenderKeysRef.current, lastPaintedRef.current), [animatedStyles, staticStyles]);
|
|
718
849
|
const renderSnapshotRef = (0, import_react_native_reanimated.useSharedValue)({
|
|
719
850
|
animated: {},
|
|
720
851
|
statics: {},
|
|
721
852
|
transforms: [],
|
|
722
853
|
gatedKeys: {},
|
|
854
|
+
derivesLeading: false,
|
|
723
855
|
seeds: {},
|
|
724
856
|
removedKeys: {},
|
|
725
857
|
removeTransform: false,
|
|
@@ -772,40 +904,49 @@ function createAnimations(animationsConfig) {
|
|
|
772
904
|
animatedStyles,
|
|
773
905
|
animationState
|
|
774
906
|
]);
|
|
775
|
-
const
|
|
907
|
+
const renderConfig = {
|
|
776
908
|
baseConfig,
|
|
777
909
|
propertyConfigs,
|
|
778
910
|
disableAnimation,
|
|
779
911
|
isHydrating
|
|
780
|
-
}
|
|
912
|
+
};
|
|
913
|
+
const configRef = (0, import_react_native_reanimated.useSharedValue)(renderConfig);
|
|
914
|
+
const writtenConfigRef = (0, import_react.useRef)(renderConfig);
|
|
915
|
+
const writeConfig = (next) => {
|
|
916
|
+
if (sameDriverConfig(writtenConfigRef.current, next)) return;
|
|
917
|
+
writtenConfigRef.current = next;
|
|
918
|
+
configRef.value = next;
|
|
919
|
+
};
|
|
781
920
|
(0, import_core.useIsomorphicLayoutEffect)(() => {
|
|
782
|
-
|
|
783
|
-
baseConfig,
|
|
784
|
-
propertyConfigs,
|
|
785
|
-
disableAnimation,
|
|
786
|
-
isHydrating
|
|
787
|
-
};
|
|
921
|
+
writeConfig(renderConfig);
|
|
788
922
|
}, [
|
|
789
923
|
baseConfig,
|
|
790
924
|
propertyConfigs,
|
|
791
925
|
disableAnimation,
|
|
792
926
|
isHydrating
|
|
793
927
|
]);
|
|
794
|
-
|
|
928
|
+
(0, import_core.useIsomorphicLayoutEffect)(() => {
|
|
929
|
+
if (emitterSnapshotRef.value !== null) return;
|
|
930
|
+
applyLeadingRatio(leadingRatio, propertyConfigs.lineHeight ?? baseConfig);
|
|
931
|
+
});
|
|
932
|
+
const onEmittedStyle = (nextStyle, effectiveTransition2, pseudoActive, nextMetrics) => {
|
|
795
933
|
if (isExitingJSRef.current) return;
|
|
796
934
|
pseudoActiveRef.current = pseudoActive === true;
|
|
797
|
-
const animateOnly = props.animateOnly;
|
|
798
935
|
const transitionToUse = effectiveTransition2 ?? props.transition;
|
|
799
|
-
const
|
|
800
|
-
|
|
936
|
+
const emittedLeadingRatio = getLeadingRatio(nextMetrics);
|
|
937
|
+
const { baseConfig: newBase, propertyConfigs: newPropertyConfigs, resolved: emittedResolved } = buildTransitionConfig(transitionToUse, animations, animationState, getStyleKeys(nextStyle));
|
|
938
|
+
const written = writtenConfigRef.current;
|
|
939
|
+
writeConfig({
|
|
801
940
|
baseConfig: newBase,
|
|
802
941
|
propertyConfigs: newPropertyConfigs,
|
|
803
|
-
disableAnimation:
|
|
804
|
-
isHydrating:
|
|
805
|
-
};
|
|
942
|
+
disableAnimation: written.disableAnimation,
|
|
943
|
+
isHydrating: written.isHydrating
|
|
944
|
+
});
|
|
806
945
|
const previousKeys = emitterKeysRef.current ?? committedRenderKeysRef.current;
|
|
807
|
-
const { animated, statics } = splitAnimationStyles(nextStyle, isDark,
|
|
808
|
-
const
|
|
946
|
+
const { animated, statics } = splitAnimationStyles(nextStyle, isDark, written.disableAnimation);
|
|
947
|
+
const emittedDerivesLeading = derivesLeadingProduct(animated, emittedLeadingRatio, !!inheritedFontSize, emittedResolved);
|
|
948
|
+
applyLeadingRatio(emittedLeadingRatio, newPropertyConfigs.lineHeight ?? newBase);
|
|
949
|
+
const snapshot = buildSnapshot(animated, statics, getAnimatedTransforms(animated.transform), previousKeys, lastPaintedRef.current, emittedDerivesLeading);
|
|
809
950
|
emitterSnapshotRef.value = snapshot.value;
|
|
810
951
|
emitterKeysRef.current = snapshot.keys;
|
|
811
952
|
lastPaintedRef.current = snapshot.painted;
|
|
@@ -816,7 +957,8 @@ function createAnimations(animationsConfig) {
|
|
|
816
957
|
transforms: snapshot.value.transforms
|
|
817
958
|
});
|
|
818
959
|
}
|
|
819
|
-
}
|
|
960
|
+
};
|
|
961
|
+
useStyleEmitter?.(onEmittedStyle);
|
|
820
962
|
const exitKeysRegistered = (0, import_react.useRef)(false);
|
|
821
963
|
const enterKeysRegistered = (0, import_react.useRef)(false);
|
|
822
964
|
if (!isExiting && justFinishedEntering && onTransition) {
|
|
@@ -847,6 +989,7 @@ function createAnimations(animationsConfig) {
|
|
|
847
989
|
if (!shouldRegisterUpdate || !previousStyleStillCurrent) return;
|
|
848
990
|
const cycleId = ++updateCycleIdRef.current;
|
|
849
991
|
pendingUpdateKeysRef.current = new Set(updateKeys);
|
|
992
|
+
updateInterruptedRef.current = false;
|
|
850
993
|
updateCompletedRef.current = updateKeys.length === 0;
|
|
851
994
|
isCompletingUpdateRef.value = updateKeys.length > 0;
|
|
852
995
|
updateCycleIdShared.value = cycleId;
|
|
@@ -905,17 +1048,22 @@ function createAnimations(animationsConfig) {
|
|
|
905
1048
|
justFinishedEntering,
|
|
906
1049
|
onTransition
|
|
907
1050
|
]);
|
|
908
|
-
const mapperStateRef = (0, import_react_native_reanimated.useSharedValue)({
|
|
1051
|
+
const mapperStateRef = (0, import_react_native_reanimated.useSharedValue)({
|
|
1052
|
+
emitted: {},
|
|
1053
|
+
ownedStatics: {}
|
|
1054
|
+
});
|
|
909
1055
|
const animatedStyle = (0, import_react_native_reanimated.useAnimatedStyle)(() => {
|
|
910
1056
|
"worklet";
|
|
911
1057
|
const mapperState = mapperStateRef.value;
|
|
912
1058
|
const config = configRef.value;
|
|
913
1059
|
if (config.disableAnimation || config.isHydrating) {
|
|
914
|
-
updateMapperState(mapperStateRef, {});
|
|
1060
|
+
updateMapperState(mapperStateRef, {}, {});
|
|
915
1061
|
return {};
|
|
916
1062
|
}
|
|
917
1063
|
const previouslyEmitted = mapperState.emitted;
|
|
918
1064
|
const emitted = {};
|
|
1065
|
+
const previouslyOwned = mapperState.ownedStatics;
|
|
1066
|
+
const ownedStatics = {};
|
|
919
1067
|
const result = {};
|
|
920
1068
|
const emitterSnapshot = emitterSnapshotRef.value;
|
|
921
1069
|
const snapshot = emitterSnapshot ?? renderSnapshotRef.value;
|
|
@@ -928,6 +1076,8 @@ function createAnimations(animationsConfig) {
|
|
|
928
1076
|
const currentlyCompletingUpdate = isCompletingUpdateRef.value;
|
|
929
1077
|
const currentUpdateCycleId = updateCycleIdShared.value;
|
|
930
1078
|
for (const key in staticValues) {
|
|
1079
|
+
if (!emitterSnapshot && !previouslyOwned[key]) continue;
|
|
1080
|
+
ownedStatics[key] = true;
|
|
931
1081
|
result[key] = staticValues[key];
|
|
932
1082
|
}
|
|
933
1083
|
for (const key in snapshot.removedKeys) {
|
|
@@ -939,11 +1089,16 @@ function createAnimations(animationsConfig) {
|
|
|
939
1089
|
if (key === "transform") continue;
|
|
940
1090
|
const targetValue = animatedValues[key];
|
|
941
1091
|
emitted[key] = true;
|
|
1092
|
+
if (key === "lineHeight" && snapshot.derivesLeading) continue;
|
|
942
1093
|
if (typeof targetValue !== "number" && typeof targetValue !== "string") {
|
|
943
1094
|
result[key] = targetValue;
|
|
944
1095
|
continue;
|
|
945
1096
|
}
|
|
946
|
-
result[key] = animateSnapshotValue(key, key, targetValue, config.propertyConfigs[key] ?? config.baseConfig, !!previouslyEmitted[key], snapshot.seeds[key], !!snapshot.gatedKeys[key], currentlyExiting, currentCycleId, currentlyCompletingEnter, currentEnterCycleId, currentlyCompletingUpdate, currentUpdateCycleId, markExitKeyDone, markEnterKeyDone, markUpdateKeyDone, !!COLOR_STYLE_KEYS[key]);
|
|
1097
|
+
result[key] = animateSnapshotValue(key, key, targetValue, config.propertyConfigs[key] ?? config.baseConfig, !!previouslyEmitted[key], snapshot.seeds[key], !!snapshot.gatedKeys[key], currentlyExiting, currentCycleId, currentlyCompletingEnter, currentEnterCycleId, currentlyCompletingUpdate, currentUpdateCycleId, markExitKeyDone, markEnterKeyDone, markUpdateKeyDone, !!COLOR_STYLE_KEYS[key], key === "fontSize" ? fontSizeShared : void 0);
|
|
1098
|
+
}
|
|
1099
|
+
if (snapshot.derivesLeading) {
|
|
1100
|
+
emitted.lineHeight = true;
|
|
1101
|
+
result.lineHeight = leadingFontSize.value * leadingRatioShared.value;
|
|
947
1102
|
}
|
|
948
1103
|
const transforms = snapshot.transforms;
|
|
949
1104
|
if (transforms.length > 0 || snapshot.removeTransform) {
|
|
@@ -967,7 +1122,7 @@ function createAnimations(animationsConfig) {
|
|
|
967
1122
|
result.transform = validTransforms;
|
|
968
1123
|
}
|
|
969
1124
|
}
|
|
970
|
-
updateMapperState(mapperStateRef, emitted);
|
|
1125
|
+
updateMapperState(mapperStateRef, emitted, ownedStatics);
|
|
971
1126
|
return result;
|
|
972
1127
|
}, import_core.isWeb ? [
|
|
973
1128
|
renderSnapshotRef,
|
|
@@ -981,12 +1136,15 @@ function createAnimations(animationsConfig) {
|
|
|
981
1136
|
markEnterKeyDone,
|
|
982
1137
|
isCompletingUpdateRef,
|
|
983
1138
|
updateCycleIdShared,
|
|
984
|
-
markUpdateKeyDone
|
|
1139
|
+
markUpdateKeyDone,
|
|
1140
|
+
fontSizeShared,
|
|
1141
|
+
leadingRatioShared,
|
|
1142
|
+
inheritedFontSize
|
|
985
1143
|
] : void 0);
|
|
986
1144
|
silenceAnimatedComponentDevCheck(animatedStyle);
|
|
987
1145
|
if (process.env.NODE_ENV === "development" && props.debug && props.debug !== "profile") {
|
|
988
1146
|
console.info("[animations-reanimated] useAnimations", {
|
|
989
|
-
|
|
1147
|
+
resolvedTransition,
|
|
990
1148
|
componentState,
|
|
991
1149
|
isExiting,
|
|
992
1150
|
animatedStyles,
|
|
@@ -995,7 +1153,10 @@ function createAnimations(animationsConfig) {
|
|
|
995
1153
|
propertyConfigs
|
|
996
1154
|
});
|
|
997
1155
|
}
|
|
998
|
-
return {
|
|
1156
|
+
return {
|
|
1157
|
+
style: [staticStyles, animatedStyle],
|
|
1158
|
+
textChannel: publishesFontSize ? ownTextChannel : typeof style.fontSize === "number" ? null : inheritedText ?? null
|
|
1159
|
+
};
|
|
999
1160
|
}
|
|
1000
1161
|
};
|
|
1001
1162
|
}
|