react-native-reanimated 4.1.2 → 4.1.4
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/Common/cpp/reanimated/RuntimeDecorators/RNRuntimeDecorator.cpp +24 -4
- package/Common/cpp/reanimated/RuntimeDecorators/RNRuntimeDecorator.h +7 -0
- package/android/build.gradle +1 -0
- package/compatibility.json +2 -2
- package/lib/module/Colors.js +5 -8
- package/lib/module/Colors.js.map +1 -1
- package/lib/module/ConfigHelper.js +5 -3
- package/lib/module/ConfigHelper.js.map +1 -1
- package/lib/module/ReanimatedModule/NativeReanimated.js +1 -1
- package/lib/module/ReanimatedModule/NativeReanimated.js.map +1 -1
- package/lib/module/ReanimatedModule/js-reanimated/index.js.map +1 -1
- package/lib/module/ViewDescriptorsSet.js +5 -1
- package/lib/module/ViewDescriptorsSet.js.map +1 -1
- package/lib/module/animation/spring/spring.js +3 -4
- package/lib/module/animation/spring/spring.js.map +1 -1
- package/lib/module/animation/spring/springUtils.js +12 -0
- package/lib/module/animation/spring/springUtils.js.map +1 -1
- package/lib/module/common/logger.js +15 -11
- package/lib/module/common/logger.js.map +1 -1
- package/lib/module/common/processors/colors.js +1 -4
- package/lib/module/common/processors/colors.js.map +1 -1
- package/lib/module/createAnimatedComponent/AnimatedComponent.js +19 -7
- package/lib/module/createAnimatedComponent/AnimatedComponent.js.map +1 -1
- package/lib/module/createAnimatedComponent/InlinePropManager.js +13 -14
- package/lib/module/createAnimatedComponent/InlinePropManager.js.map +1 -1
- package/lib/module/css/index.js +1 -1
- package/lib/module/css/index.js.map +1 -1
- package/lib/module/css/native/normalization/common/settings.js +2 -12
- package/lib/module/css/native/normalization/common/settings.js.map +1 -1
- package/lib/module/css/native/style/config.js +2 -2
- package/lib/module/css/native/style/config.js.map +1 -1
- package/lib/module/css/utils/parsers.js +11 -0
- package/lib/module/css/utils/parsers.js.map +1 -1
- package/lib/module/css/utils/props.js +0 -5
- package/lib/module/css/utils/props.js.map +1 -1
- package/lib/module/css/web/managers/CSSAnimationsManager.js +68 -42
- package/lib/module/css/web/managers/CSSAnimationsManager.js.map +1 -1
- package/lib/module/fabricUtils.js +9 -11
- package/lib/module/fabricUtils.js.map +1 -1
- package/lib/module/hook/useAnimatedRef.js +12 -6
- package/lib/module/hook/useAnimatedRef.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/initializers.js +1 -3
- package/lib/module/initializers.js.map +1 -1
- package/lib/module/interpolateColor.js +75 -24
- package/lib/module/interpolateColor.js.map +1 -1
- package/lib/module/layoutReanimation/web/Easing.web.js +3 -0
- package/lib/module/layoutReanimation/web/Easing.web.js.map +1 -1
- package/lib/module/layoutReanimation/web/componentUtils.js +4 -3
- package/lib/module/layoutReanimation/web/componentUtils.js.map +1 -1
- package/lib/module/layoutReanimation/web/domUtils.js +1 -1
- package/lib/module/layoutReanimation/web/domUtils.js.map +1 -1
- package/lib/module/layoutReanimation/web/transition/Curved.web.js +1 -1
- package/lib/module/layoutReanimation/web/transition/Curved.web.js.map +1 -1
- package/lib/module/platform-specific/jsVersion.js +1 -1
- package/lib/module/platformFunctions/dispatchCommand.js +6 -0
- package/lib/module/platformFunctions/dispatchCommand.js.map +1 -1
- package/lib/module/platformFunctions/scrollTo.web.js +12 -8
- package/lib/module/platformFunctions/scrollTo.web.js.map +1 -1
- package/lib/typescript/Colors.d.ts +1 -1
- package/lib/typescript/Colors.d.ts.map +1 -1
- package/lib/typescript/ConfigHelper.d.ts.map +1 -1
- package/lib/typescript/ReanimatedModule/js-reanimated/index.d.ts +2 -1
- package/lib/typescript/ReanimatedModule/js-reanimated/index.d.ts.map +1 -1
- package/lib/typescript/ViewDescriptorsSet.d.ts +1 -0
- package/lib/typescript/ViewDescriptorsSet.d.ts.map +1 -1
- package/lib/typescript/animation/spring/spring.d.ts.map +1 -1
- package/lib/typescript/animation/spring/springUtils.d.ts +1 -0
- package/lib/typescript/animation/spring/springUtils.d.ts.map +1 -1
- package/lib/typescript/common/logger.d.ts +5 -5
- package/lib/typescript/common/logger.d.ts.map +1 -1
- package/lib/typescript/common/processors/colors.d.ts.map +1 -1
- package/lib/typescript/commonTypes.d.ts +1 -1
- package/lib/typescript/commonTypes.d.ts.map +1 -1
- package/lib/typescript/createAnimatedComponent/AnimatedComponent.d.ts.map +1 -1
- package/lib/typescript/createAnimatedComponent/InlinePropManager.d.ts.map +1 -1
- package/lib/typescript/css/index.d.ts +1 -1
- package/lib/typescript/css/index.d.ts.map +1 -1
- package/lib/typescript/css/native/normalization/common/settings.d.ts.map +1 -1
- package/lib/typescript/css/native/style/config.d.ts.map +1 -1
- package/lib/typescript/css/utils/parsers.d.ts +2 -1
- package/lib/typescript/css/utils/parsers.d.ts.map +1 -1
- package/lib/typescript/css/web/managers/CSSAnimationsManager.d.ts +2 -0
- package/lib/typescript/css/web/managers/CSSAnimationsManager.d.ts.map +1 -1
- package/lib/typescript/fabricUtils.d.ts.map +1 -1
- package/lib/typescript/hook/useAnimatedRef.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +1 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/initializers.d.ts.map +1 -1
- package/lib/typescript/interpolateColor.d.ts.map +1 -1
- package/lib/typescript/layoutReanimation/web/Easing.web.d.ts.map +1 -1
- package/lib/typescript/layoutReanimation/web/componentUtils.d.ts +1 -1
- package/lib/typescript/layoutReanimation/web/componentUtils.d.ts.map +1 -1
- package/lib/typescript/platform-specific/jsVersion.d.ts +1 -1
- package/lib/typescript/platformFunctions/scrollTo.web.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/Colors.ts +7 -10
- package/src/ConfigHelper.ts +9 -3
- package/src/ReanimatedModule/NativeReanimated.ts +1 -1
- package/src/ReanimatedModule/js-reanimated/index.ts +2 -1
- package/src/ViewDescriptorsSet.ts +8 -0
- package/src/animation/spring/spring.ts +11 -6
- package/src/animation/spring/springUtils.ts +19 -0
- package/src/common/logger.ts +18 -11
- package/src/common/processors/colors.ts +1 -4
- package/src/commonTypes.ts +1 -1
- package/src/createAnimatedComponent/AnimatedComponent.tsx +23 -7
- package/src/createAnimatedComponent/InlinePropManager.ts +14 -15
- package/src/css/index.ts +1 -1
- package/src/css/native/normalization/common/settings.ts +2 -17
- package/src/css/native/style/config.ts +1 -1
- package/src/css/utils/parsers.ts +13 -1
- package/src/css/utils/props.ts +0 -8
- package/src/css/web/managers/CSSAnimationsManager.ts +85 -40
- package/src/fabricUtils.ts +12 -26
- package/src/hook/useAnimatedRef.ts +12 -9
- package/src/index.ts +1 -0
- package/src/initializers.ts +1 -9
- package/src/interpolateColor.ts +112 -43
- package/src/layoutReanimation/web/Easing.web.ts +4 -0
- package/src/layoutReanimation/web/componentUtils.ts +6 -4
- package/src/layoutReanimation/web/domUtils.ts +1 -1
- package/src/layoutReanimation/web/transition/Curved.web.ts +1 -1
- package/src/platform-specific/jsVersion.ts +1 -1
- package/src/platformFunctions/dispatchCommand.ts +15 -2
- package/src/platformFunctions/scrollTo.web.ts +10 -4
- package/src/privateGlobals.d.ts +1 -1
|
@@ -66,6 +66,25 @@ export function checkIfConfigIsValid(config: DefaultSpringConfig): boolean {
|
|
|
66
66
|
return errorMessage === '';
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
export function safeMergeConfigs<TConfig extends object>(
|
|
70
|
+
defaults: TConfig,
|
|
71
|
+
userConfig?: Partial<TConfig>
|
|
72
|
+
): TConfig {
|
|
73
|
+
'worklet';
|
|
74
|
+
if (!userConfig) {
|
|
75
|
+
return defaults;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const filtered = Object.fromEntries(
|
|
79
|
+
Object.entries(userConfig).filter(([, v]) => v !== undefined)
|
|
80
|
+
) as Partial<TConfig>;
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
...defaults,
|
|
84
|
+
...filtered,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
69
88
|
function bisectRoot({
|
|
70
89
|
min,
|
|
71
90
|
max,
|
package/src/common/logger.ts
CHANGED
|
@@ -39,39 +39,46 @@ function logToConsole(data: LogData) {
|
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
const DEFAULT_LOGGER_CONFIG: LoggerConfigInternal = {
|
|
43
43
|
logFunction: logToConsole,
|
|
44
44
|
level: ReanimatedLogLevel.warn,
|
|
45
45
|
strict: true,
|
|
46
46
|
};
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
|
-
*
|
|
49
|
+
* Current logger config getter.
|
|
50
50
|
*
|
|
51
|
-
* @
|
|
51
|
+
* @returns The current logger configuration object.
|
|
52
52
|
*/
|
|
53
|
-
export function
|
|
53
|
+
export function getLoggerConfig() {
|
|
54
54
|
'worklet';
|
|
55
|
-
global.__reanimatedLoggerConfig
|
|
55
|
+
if (!global.__reanimatedLoggerConfig) {
|
|
56
|
+
global.__reanimatedLoggerConfig = DEFAULT_LOGGER_CONFIG;
|
|
57
|
+
}
|
|
58
|
+
return global.__reanimatedLoggerConfig;
|
|
56
59
|
}
|
|
57
60
|
|
|
58
61
|
/**
|
|
59
62
|
* Updates logger configuration.
|
|
60
63
|
*
|
|
64
|
+
* @param currentConfig - The current logger configuration object.
|
|
61
65
|
* @param options - The new logger configuration to apply.
|
|
62
66
|
*
|
|
63
67
|
* - Level: The minimum log level to display.
|
|
64
68
|
* - Strict: Whether to log warnings and errors that are not strict. Defaults to
|
|
65
69
|
* false.
|
|
66
70
|
*/
|
|
67
|
-
export function updateLoggerConfig(
|
|
71
|
+
export function updateLoggerConfig(
|
|
72
|
+
currentConfig: LoggerConfigInternal,
|
|
73
|
+
options?: Partial<LoggerConfig>
|
|
74
|
+
) {
|
|
68
75
|
'worklet';
|
|
69
|
-
|
|
70
|
-
...
|
|
71
|
-
// Don't reuse previous level and strict values from the
|
|
76
|
+
global.__reanimatedLoggerConfig = {
|
|
77
|
+
...currentConfig,
|
|
78
|
+
// Don't reuse previous level and strict values from the current config
|
|
72
79
|
level: options?.level ?? DEFAULT_LOGGER_CONFIG.level,
|
|
73
80
|
strict: options?.strict ?? DEFAULT_LOGGER_CONFIG.strict,
|
|
74
|
-
}
|
|
81
|
+
};
|
|
75
82
|
}
|
|
76
83
|
|
|
77
84
|
type LogOptions = {
|
|
@@ -84,7 +91,7 @@ function handleLog(
|
|
|
84
91
|
options: LogOptions
|
|
85
92
|
) {
|
|
86
93
|
'worklet';
|
|
87
|
-
const config =
|
|
94
|
+
const config = getLoggerConfig();
|
|
88
95
|
if (
|
|
89
96
|
// Don't log if the log is marked as strict-only and the config doesn't
|
|
90
97
|
// enable strict logging
|
|
@@ -6,12 +6,9 @@ import { IS_ANDROID } from '../constants';
|
|
|
6
6
|
|
|
7
7
|
export function processColor(color: unknown): number | null | undefined {
|
|
8
8
|
let normalizedColor = processColorInitially(color);
|
|
9
|
-
if (normalizedColor === null || normalizedColor === undefined) {
|
|
10
|
-
return undefined;
|
|
11
|
-
}
|
|
12
9
|
|
|
13
10
|
if (typeof normalizedColor !== 'number') {
|
|
14
|
-
return
|
|
11
|
+
return normalizedColor;
|
|
15
12
|
}
|
|
16
13
|
|
|
17
14
|
if (IS_ANDROID) {
|
package/src/commonTypes.ts
CHANGED
|
@@ -120,8 +120,20 @@ export default class AnimatedComponent
|
|
|
120
120
|
);
|
|
121
121
|
|
|
122
122
|
if (IS_WEB) {
|
|
123
|
-
|
|
124
|
-
|
|
123
|
+
const element = this._componentDOMRef as ReanimatedHTMLElement;
|
|
124
|
+
|
|
125
|
+
// If the element was cloned (because of the exiting animation), we need bring it
|
|
126
|
+
// back to the DOM
|
|
127
|
+
if (element.dummyClone) {
|
|
128
|
+
const dummyClone = element.dummyClone;
|
|
129
|
+
while (dummyClone.firstChild) {
|
|
130
|
+
element.appendChild(dummyClone.firstChild);
|
|
131
|
+
}
|
|
132
|
+
delete element.dummyClone;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (this.props.exiting) {
|
|
136
|
+
saveSnapshot(element);
|
|
125
137
|
}
|
|
126
138
|
|
|
127
139
|
if (
|
|
@@ -137,11 +149,11 @@ export default class AnimatedComponent
|
|
|
137
149
|
if (!skipEntering) {
|
|
138
150
|
startWebLayoutAnimation(
|
|
139
151
|
this.props,
|
|
140
|
-
|
|
152
|
+
element,
|
|
141
153
|
LayoutAnimationType.ENTERING
|
|
142
154
|
);
|
|
143
|
-
} else
|
|
144
|
-
|
|
155
|
+
} else {
|
|
156
|
+
element.style.visibility = 'initial';
|
|
145
157
|
}
|
|
146
158
|
}
|
|
147
159
|
|
|
@@ -207,6 +219,9 @@ export default class AnimatedComponent
|
|
|
207
219
|
const { viewTag, shadowNodeWrapper } = this._getViewInfo();
|
|
208
220
|
const newStyles = new Set<StyleProps>(currentStyles);
|
|
209
221
|
|
|
222
|
+
const isStyleAttached = (style: StyleProps) =>
|
|
223
|
+
style.viewDescriptors.has(viewTag);
|
|
224
|
+
|
|
210
225
|
// remove old styles
|
|
211
226
|
if (prevStyles) {
|
|
212
227
|
// in most of the cases, views have only a single animated style and it remains unchanged
|
|
@@ -215,14 +230,14 @@ export default class AnimatedComponent
|
|
|
215
230
|
prevStyles.length === 1 &&
|
|
216
231
|
currentStyles[0] === prevStyles[0];
|
|
217
232
|
|
|
218
|
-
if (hasOneSameStyle) {
|
|
233
|
+
if (hasOneSameStyle && isStyleAttached(prevStyles[0])) {
|
|
219
234
|
return;
|
|
220
235
|
}
|
|
221
236
|
|
|
222
237
|
// otherwise, remove each style that is not present in new styles
|
|
223
238
|
for (const prevStyle of prevStyles) {
|
|
224
239
|
const isPresent = currentStyles.some((style) => {
|
|
225
|
-
if (style === prevStyle) {
|
|
240
|
+
if (style === prevStyle && isStyleAttached(style)) {
|
|
226
241
|
newStyles.delete(style);
|
|
227
242
|
return true;
|
|
228
243
|
}
|
|
@@ -233,6 +248,7 @@ export default class AnimatedComponent
|
|
|
233
248
|
}
|
|
234
249
|
}
|
|
235
250
|
}
|
|
251
|
+
|
|
236
252
|
newStyles.forEach((style) => {
|
|
237
253
|
style.viewDescriptors.add(
|
|
238
254
|
{
|
|
@@ -38,23 +38,22 @@ function inlinePropsHasChanged(
|
|
|
38
38
|
return false;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
function getInlinePropsUpdate(
|
|
41
|
+
function getInlinePropsUpdate(styleValue: StyleProps): unknown {
|
|
42
42
|
'worklet';
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
update[key] = getInlinePropsUpdate(
|
|
53
|
-
} else {
|
|
54
|
-
update[key] = styleValue;
|
|
43
|
+
if (isSharedValue(styleValue)) {
|
|
44
|
+
return styleValue.value;
|
|
45
|
+
}
|
|
46
|
+
if (Array.isArray(styleValue)) {
|
|
47
|
+
return styleValue.map(getInlinePropsUpdate);
|
|
48
|
+
}
|
|
49
|
+
if (styleValue && typeof styleValue === 'object') {
|
|
50
|
+
const update: Record<string, unknown> = {};
|
|
51
|
+
for (const [key, value] of Object.entries(styleValue)) {
|
|
52
|
+
update[key] = getInlinePropsUpdate(value);
|
|
55
53
|
}
|
|
54
|
+
return update;
|
|
56
55
|
}
|
|
57
|
-
return
|
|
56
|
+
return styleValue;
|
|
58
57
|
}
|
|
59
58
|
|
|
60
59
|
function extractSharedValuesMapFromProps(
|
|
@@ -109,7 +108,7 @@ export function getInlineStyle(
|
|
|
109
108
|
isFirstRender: boolean
|
|
110
109
|
) {
|
|
111
110
|
if (isFirstRender) {
|
|
112
|
-
return getInlinePropsUpdate(style)
|
|
111
|
+
return getInlinePropsUpdate(style) as Record<string, unknown>;
|
|
113
112
|
}
|
|
114
113
|
const newStyle: StyleProps = {};
|
|
115
114
|
for (const [key, styleValue] of Object.entries(style)) {
|
package/src/css/index.ts
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
import { ReanimatedError } from '../../../../common';
|
|
3
|
-
import {
|
|
4
|
-
MILLISECONDS_REGEX,
|
|
5
|
-
SECONDS_REGEX,
|
|
6
|
-
VALID_PREDEFINED_TIMING_FUNCTIONS,
|
|
7
|
-
} from '../../../constants';
|
|
3
|
+
import { VALID_PREDEFINED_TIMING_FUNCTIONS } from '../../../constants';
|
|
8
4
|
import type {
|
|
9
5
|
CSSTimingFunction,
|
|
10
6
|
NormalizedCSSTimingFunction,
|
|
11
7
|
PredefinedTimingFunction,
|
|
12
8
|
} from '../../../easing';
|
|
13
9
|
import type { TimeUnit } from '../../../types';
|
|
14
|
-
import { isPredefinedTimingFunction } from '../../../utils';
|
|
10
|
+
import { isPredefinedTimingFunction, normalizeTimeUnit } from '../../../utils';
|
|
15
11
|
|
|
16
12
|
export const ERROR_MESSAGES = {
|
|
17
13
|
invalidDelay: (timeUnit: TimeUnit) =>
|
|
@@ -26,17 +22,6 @@ export const ERROR_MESSAGES = {
|
|
|
26
22
|
`Invalid parametrized timing function "${timingFunction?.toString()}".`,
|
|
27
23
|
};
|
|
28
24
|
|
|
29
|
-
function normalizeTimeUnit(timeUnit: TimeUnit): number | null {
|
|
30
|
-
if (typeof timeUnit === 'number') {
|
|
31
|
-
return timeUnit;
|
|
32
|
-
} else if (MILLISECONDS_REGEX.test(timeUnit)) {
|
|
33
|
-
return parseInt(timeUnit, 10);
|
|
34
|
-
} else if (SECONDS_REGEX.test(timeUnit)) {
|
|
35
|
-
return parseFloat(timeUnit) * 1000;
|
|
36
|
-
}
|
|
37
|
-
return null;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
25
|
export function normalizeDelay(delay: TimeUnit = 0): number {
|
|
41
26
|
const delayMs = normalizeTimeUnit(delay);
|
|
42
27
|
if (delayMs === null) {
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
import {
|
|
3
3
|
IS_ANDROID,
|
|
4
4
|
processBoxShadowNative,
|
|
5
|
-
processColor,
|
|
6
5
|
processTransformOrigin,
|
|
7
6
|
} from '../../../common';
|
|
8
7
|
import type { PlainStyle } from '../../types';
|
|
9
8
|
import {
|
|
10
9
|
processAspectRatio,
|
|
10
|
+
processColor,
|
|
11
11
|
processFontWeight,
|
|
12
12
|
processGap,
|
|
13
13
|
processInset,
|
package/src/css/utils/parsers.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
import { ReanimatedError } from '../../common';
|
|
4
|
-
import
|
|
4
|
+
import { MILLISECONDS_REGEX, SECONDS_REGEX } from '../constants';
|
|
5
|
+
import type { SingleCSSTransitionConfig, TimeUnit } from '../types';
|
|
5
6
|
import { isTimeUnit, smellsLikeTimingFunction } from './guards';
|
|
6
7
|
|
|
7
8
|
export function splitByComma(str: string) {
|
|
@@ -80,3 +81,14 @@ export function parseSingleTransitionShorthand(
|
|
|
80
81
|
|
|
81
82
|
return result;
|
|
82
83
|
}
|
|
84
|
+
|
|
85
|
+
export function normalizeTimeUnit(timeUnit: TimeUnit): number | null {
|
|
86
|
+
if (typeof timeUnit === 'number') {
|
|
87
|
+
return timeUnit;
|
|
88
|
+
} else if (MILLISECONDS_REGEX.test(timeUnit)) {
|
|
89
|
+
return parseInt(timeUnit, 10);
|
|
90
|
+
} else if (SECONDS_REGEX.test(timeUnit)) {
|
|
91
|
+
return parseFloat(timeUnit) * 1000;
|
|
92
|
+
}
|
|
93
|
+
return null;
|
|
94
|
+
}
|
package/src/css/utils/props.ts
CHANGED
|
@@ -78,14 +78,6 @@ export function filterCSSAndStyleProperties<S extends AnyRecord>(
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
function validateCSSAnimationProps(props: Partial<CSSAnimationProperties>) {
|
|
81
|
-
// Check if any animation properties are present but animationName is missing
|
|
82
|
-
if (!('animationName' in props) && Object.keys(props).length > 0) {
|
|
83
|
-
logger.warn(
|
|
84
|
-
'CSS animation properties were provided without specifying animationName.\n' +
|
|
85
|
-
'If unintended, add animationName or remove unnecessary animation properties.'
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
81
|
// Check if animationDuration is missing when animationName is present
|
|
90
82
|
if (!('animationDuration' in props) && 'animationName' in props) {
|
|
91
83
|
logger.warn(
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
import { maybeAddSuffix } from '../../../common';
|
|
2
3
|
import type { ReanimatedHTMLElement } from '../../../ReanimatedModule/js-reanimated';
|
|
3
4
|
import type {
|
|
4
5
|
ConvertValuesToArrays,
|
|
@@ -7,7 +8,11 @@ import type {
|
|
|
7
8
|
ExistingCSSAnimationProperties,
|
|
8
9
|
ICSSAnimationsManager,
|
|
9
10
|
} from '../../types';
|
|
10
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
convertPropertiesToArrays,
|
|
13
|
+
kebabizeCamelCase,
|
|
14
|
+
normalizeTimeUnit,
|
|
15
|
+
} from '../../utils';
|
|
11
16
|
import { processKeyframeDefinitions } from '../animationParser';
|
|
12
17
|
import {
|
|
13
18
|
configureWebCSSAnimations,
|
|
@@ -25,6 +30,8 @@ const isCSSKeyframesRuleImpl = (
|
|
|
25
30
|
type ProcessedAnimation = {
|
|
26
31
|
keyframesRule: CSSKeyframesRuleImpl;
|
|
27
32
|
removable: boolean;
|
|
33
|
+
creationTimestamp: number;
|
|
34
|
+
elapsedTime?: number;
|
|
28
35
|
};
|
|
29
36
|
|
|
30
37
|
type ProcessedSettings = ConvertValuesToArrays<CSSAnimationSettings>;
|
|
@@ -34,6 +41,7 @@ export default class CSSAnimationsManager implements ICSSAnimationsManager {
|
|
|
34
41
|
|
|
35
42
|
// Keys are processed keyframes
|
|
36
43
|
private attachedAnimations: Record<string, ProcessedAnimation> = {};
|
|
44
|
+
private unmountCleanupCalled = false;
|
|
37
45
|
|
|
38
46
|
constructor(element: ReanimatedHTMLElement) {
|
|
39
47
|
configureWebCSSAnimations();
|
|
@@ -55,44 +63,67 @@ export default class CSSAnimationsManager implements ICSSAnimationsManager {
|
|
|
55
63
|
return;
|
|
56
64
|
}
|
|
57
65
|
|
|
66
|
+
const timestamp = Date.now();
|
|
58
67
|
const processedAnimations = definitions.map((definition) => {
|
|
68
|
+
let processedAnimation: ProcessedAnimation;
|
|
69
|
+
|
|
59
70
|
// If the CSSKeyframesRule instance was provided, we can just use it
|
|
60
71
|
if (isCSSKeyframesRuleImpl(definition)) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
72
|
+
processedAnimation = this.attachedAnimations[
|
|
73
|
+
definition.processedKeyframes
|
|
74
|
+
] ?? {
|
|
75
|
+
keyframesRule: definition,
|
|
76
|
+
removable: false,
|
|
77
|
+
creationTimestamp: timestamp,
|
|
78
|
+
};
|
|
79
|
+
} else {
|
|
80
|
+
// If keyframes was defined as an object, the additional processing is needed
|
|
81
|
+
const keyframes = definition as CSSAnimationKeyframes;
|
|
82
|
+
const processedKeyframes = processKeyframeDefinitions(keyframes);
|
|
83
|
+
|
|
84
|
+
// If the animation with the same keyframes was already attached, we can reuse it
|
|
85
|
+
// Otherwise, we need to create a new CSSKeyframesRule object
|
|
86
|
+
processedAnimation = this.attachedAnimations[processedKeyframes] ?? {
|
|
87
|
+
keyframesRule: new CSSKeyframesRuleImpl(
|
|
88
|
+
keyframes,
|
|
89
|
+
processedKeyframes
|
|
90
|
+
),
|
|
73
91
|
removable: true,
|
|
92
|
+
creationTimestamp: timestamp,
|
|
74
93
|
};
|
|
75
94
|
}
|
|
76
95
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
96
|
+
if (this.unmountCleanupCalled) {
|
|
97
|
+
// unmountCleanup is called not only when the component truly unmounts, but also
|
|
98
|
+
// when display property is set to 'none' (e.g. during navigation between screens)
|
|
99
|
+
// In such a case, we don't want to restart the animation after re-entering the
|
|
100
|
+
// screen so we have to shift its delay by the time elapsed since the animation
|
|
101
|
+
// was started for the first time.
|
|
102
|
+
processedAnimation.elapsedTime =
|
|
103
|
+
timestamp - processedAnimation.creationTimestamp;
|
|
104
|
+
}
|
|
83
105
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
);
|
|
106
|
+
return processedAnimation;
|
|
107
|
+
});
|
|
87
108
|
|
|
109
|
+
this.unmountCleanupCalled = false;
|
|
88
110
|
this.updateAttachedAnimations(processedAnimations);
|
|
89
|
-
this.setElementAnimations(
|
|
111
|
+
this.setElementAnimations(processedAnimations, animationSettings);
|
|
90
112
|
}
|
|
91
113
|
|
|
92
114
|
unmountCleanup(): void {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
115
|
+
if (!this.unmountCleanupCalled) {
|
|
116
|
+
this.unmountCleanupCalled = true;
|
|
117
|
+
// We use setTimeout to ensure that the animation is removed after the
|
|
118
|
+
// component is unmounted (it puts the detach call at the end of the event loop)
|
|
119
|
+
// We just remove the animation definition from the style sheet as there is no
|
|
120
|
+
// need to clean up view props if it is removed from the DOM.
|
|
121
|
+
setTimeout(() => {
|
|
122
|
+
this.removeAnimationsFromStyleSheet(
|
|
123
|
+
Object.values(this.attachedAnimations)
|
|
124
|
+
);
|
|
125
|
+
});
|
|
126
|
+
}
|
|
96
127
|
}
|
|
97
128
|
|
|
98
129
|
private detach() {
|
|
@@ -109,13 +140,8 @@ export default class CSSAnimationsManager implements ICSSAnimationsManager {
|
|
|
109
140
|
this.element.style.animationPlayState = '';
|
|
110
141
|
this.element.style.animationTimingFunction = '';
|
|
111
142
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
if (removable && processedKeyframes) {
|
|
115
|
-
removeCSSAnimation(name);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
);
|
|
143
|
+
this.removeAnimationsFromStyleSheet(attachedAnimations);
|
|
144
|
+
this.unmountCleanupCalled = false;
|
|
119
145
|
this.attachedAnimations = {};
|
|
120
146
|
}
|
|
121
147
|
|
|
@@ -147,10 +173,12 @@ export default class CSSAnimationsManager implements ICSSAnimationsManager {
|
|
|
147
173
|
}
|
|
148
174
|
|
|
149
175
|
private setElementAnimations(
|
|
150
|
-
|
|
176
|
+
processedAnimations: ProcessedAnimation[],
|
|
151
177
|
animationSettings: ProcessedSettings
|
|
152
178
|
) {
|
|
153
|
-
this.element.style.animationName =
|
|
179
|
+
this.element.style.animationName = processedAnimations
|
|
180
|
+
.map(({ keyframesRule: { name } }) => name)
|
|
181
|
+
.join(',');
|
|
154
182
|
|
|
155
183
|
this.element.style.animationDuration = maybeAddSuffixes(
|
|
156
184
|
animationSettings,
|
|
@@ -158,11 +186,18 @@ export default class CSSAnimationsManager implements ICSSAnimationsManager {
|
|
|
158
186
|
'ms'
|
|
159
187
|
).join(',');
|
|
160
188
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
189
|
+
const animationDelays = animationSettings.animationDelay ?? [];
|
|
190
|
+
this.element.style.animationDelay = processedAnimations
|
|
191
|
+
.map(({ elapsedTime }, i) => {
|
|
192
|
+
const providedDelay = animationDelays[i] ?? 0;
|
|
193
|
+
return maybeAddSuffix(
|
|
194
|
+
elapsedTime
|
|
195
|
+
? (normalizeTimeUnit(providedDelay) ?? 0) - elapsedTime
|
|
196
|
+
: providedDelay,
|
|
197
|
+
'ms'
|
|
198
|
+
);
|
|
199
|
+
})
|
|
200
|
+
.join(',');
|
|
166
201
|
|
|
167
202
|
if (animationSettings.animationIterationCount) {
|
|
168
203
|
this.element.style.animationIterationCount =
|
|
@@ -190,4 +225,14 @@ export default class CSSAnimationsManager implements ICSSAnimationsManager {
|
|
|
190
225
|
);
|
|
191
226
|
}
|
|
192
227
|
}
|
|
228
|
+
|
|
229
|
+
private removeAnimationsFromStyleSheet(animations: ProcessedAnimation[]) {
|
|
230
|
+
animations.forEach(
|
|
231
|
+
({ keyframesRule: { name, processedKeyframes }, removable }) => {
|
|
232
|
+
if (removable && processedKeyframes) {
|
|
233
|
+
removeCSSAnimation(name);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
);
|
|
237
|
+
}
|
|
193
238
|
}
|
package/src/fabricUtils.ts
CHANGED
|
@@ -4,37 +4,23 @@ import type { ShadowNodeWrapper, WrapperRef } from './commonTypes';
|
|
|
4
4
|
import type { HostInstance } from './platform-specific/findHostInstance';
|
|
5
5
|
import { findHostInstance } from './platform-specific/findHostInstance';
|
|
6
6
|
|
|
7
|
-
let getInternalInstanceHandleFromPublicInstance: (ref: unknown) => {
|
|
8
|
-
stateNode: { node: unknown };
|
|
9
|
-
};
|
|
10
|
-
|
|
11
7
|
export function getShadowNodeWrapperFromRef(
|
|
12
8
|
ref: WrapperRef,
|
|
13
9
|
hostInstance?: HostInstance
|
|
14
10
|
): ShadowNodeWrapper {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
|
|
11
|
+
let resolvedInstance =
|
|
12
|
+
hostInstance?.__internalInstanceHandle ?? ref?.__internalInstanceHandle;
|
|
13
|
+
|
|
14
|
+
if (!resolvedInstance) {
|
|
15
|
+
if (ref.getNativeScrollRef) {
|
|
16
|
+
resolvedInstance = (ref.getNativeScrollRef() as any)
|
|
17
|
+
.__internalInstanceHandle;
|
|
18
|
+
} else if ((ref as any)._reactInternals) {
|
|
19
|
+
resolvedInstance = findHostInstance(ref).__internalInstanceHandle;
|
|
20
|
+
} else {
|
|
21
|
+
throw new ReanimatedError(`Failed to find host instance for a ref.}`);
|
|
25
22
|
}
|
|
26
23
|
}
|
|
27
24
|
|
|
28
|
-
|
|
29
|
-
ref.getScrollResponder?.()?.getNativeScrollRef?.() ??
|
|
30
|
-
ref.getNativeScrollRef?.() ??
|
|
31
|
-
ref;
|
|
32
|
-
|
|
33
|
-
const resolvedInstance =
|
|
34
|
-
ref?.__internalInstanceHandle ??
|
|
35
|
-
getInternalInstanceHandleFromPublicInstance(
|
|
36
|
-
hostInstance ?? findHostInstance(resolvedRef)
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
return resolvedInstance?.stateNode?.node;
|
|
25
|
+
return resolvedInstance!.stateNode.node as ShadowNodeWrapper;
|
|
40
26
|
}
|
|
@@ -17,10 +17,6 @@ import type {
|
|
|
17
17
|
MaybeObserverCleanup,
|
|
18
18
|
} from './commonTypes';
|
|
19
19
|
|
|
20
|
-
function getComponentOrScrollable(ref: WrapperRef) {
|
|
21
|
-
return ref.getNativeScrollRef?.() ?? ref.getScrollableNode?.() ?? ref;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
20
|
function useAnimatedRefBase<TRef extends WrapperRef>(
|
|
25
21
|
getWrapper: (ref: TRef) => ShadowNodeWrapper
|
|
26
22
|
): AnimatedRef<TRef> {
|
|
@@ -36,7 +32,8 @@ function useAnimatedRefBase<TRef extends WrapperRef>(
|
|
|
36
32
|
wrapperRef.current = getWrapper(ref);
|
|
37
33
|
|
|
38
34
|
// We have to unwrap the tag from the shadow node wrapper.
|
|
39
|
-
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
36
|
+
fun.getTag = () => findNodeHandle(ref as any);
|
|
40
37
|
fun.current = ref;
|
|
41
38
|
|
|
42
39
|
if (observers.size) {
|
|
@@ -81,9 +78,7 @@ function useAnimatedRefNative<
|
|
|
81
78
|
);
|
|
82
79
|
|
|
83
80
|
const resultRef = useAnimatedRefBase<TRef>((ref) => {
|
|
84
|
-
const currentWrapper = getShadowNodeWrapperFromRef(
|
|
85
|
-
getComponentOrScrollable(ref)
|
|
86
|
-
);
|
|
81
|
+
const currentWrapper = getShadowNodeWrapperFromRef(ref);
|
|
87
82
|
|
|
88
83
|
sharedWrapper.value = currentWrapper;
|
|
89
84
|
|
|
@@ -106,7 +101,15 @@ function useAnimatedRefNative<
|
|
|
106
101
|
function useAnimatedRefWeb<
|
|
107
102
|
TRef extends WrapperRef = React.Component,
|
|
108
103
|
>(): AnimatedRef<TRef> {
|
|
109
|
-
return useAnimatedRefBase<TRef>((ref) =>
|
|
104
|
+
return useAnimatedRefBase<TRef>((ref) => {
|
|
105
|
+
if (ref.getScrollableNode) {
|
|
106
|
+
return ref.getScrollableNode();
|
|
107
|
+
}
|
|
108
|
+
if (ref.getNativeScrollRef) {
|
|
109
|
+
return ref.getNativeScrollRef();
|
|
110
|
+
}
|
|
111
|
+
return ref;
|
|
112
|
+
});
|
|
110
113
|
}
|
|
111
114
|
|
|
112
115
|
/**
|
package/src/index.ts
CHANGED
package/src/initializers.ts
CHANGED
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
import { executeOnUIRuntimeSync } from 'react-native-worklets';
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
DEFAULT_LOGGER_CONFIG,
|
|
6
|
-
IS_WEB,
|
|
7
|
-
ReanimatedError,
|
|
8
|
-
registerLoggerConfig,
|
|
9
|
-
SHOULD_BE_USE_WEB,
|
|
10
|
-
} from './common';
|
|
4
|
+
import { IS_WEB, ReanimatedError, SHOULD_BE_USE_WEB } from './common';
|
|
11
5
|
import { initSvgCssSupport } from './css/svg';
|
|
12
6
|
import { getStaticFeatureFlag } from './featureFlags';
|
|
13
7
|
import type { IReanimatedModule } from './ReanimatedModule';
|
|
@@ -25,11 +19,9 @@ export function initializeReanimatedModule(
|
|
|
25
19
|
}
|
|
26
20
|
}
|
|
27
21
|
|
|
28
|
-
registerLoggerConfig(DEFAULT_LOGGER_CONFIG);
|
|
29
22
|
if (!SHOULD_BE_USE_WEB) {
|
|
30
23
|
executeOnUIRuntimeSync(() => {
|
|
31
24
|
'worklet';
|
|
32
25
|
global._tagToJSPropNamesMapping = {};
|
|
33
|
-
registerLoggerConfig(DEFAULT_LOGGER_CONFIG);
|
|
34
26
|
})();
|
|
35
27
|
}
|