react-native-reanimated 4.3.0-rc.0 → 4.3.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/Common/cpp/reanimated/AnimatedSensor/AnimatedSensorModule.cpp +8 -5
- package/Common/cpp/reanimated/AnimatedSensor/AnimatedSensorModule.h +3 -5
- package/Common/cpp/reanimated/CSS/common/values/CSSValueVariant.cpp +2 -3
- package/Common/cpp/reanimated/CSS/interpolation/PropertyInterpolator.cpp +2 -3
- package/Common/cpp/reanimated/CSS/utils/DelayedItemsManager.cpp +2 -2
- package/Common/cpp/reanimated/CSS/utils/DelayedItemsManager.h +2 -2
- package/Common/cpp/reanimated/Compat/WorkletsApi.h +13 -0
- package/Common/cpp/reanimated/Events/UIEventHandler.cpp +1 -1
- package/Common/cpp/reanimated/Events/UIEventHandler.h +3 -4
- package/Common/cpp/reanimated/Events/UIEventHandlerRegistry.cpp +3 -2
- package/Common/cpp/reanimated/Events/UIEventHandlerRegistry.h +1 -1
- package/Common/cpp/reanimated/Fabric/ReanimatedCommitHook.cpp +2 -8
- package/Common/cpp/reanimated/Fabric/ReanimatedCommitHook.h +2 -6
- package/Common/cpp/reanimated/Fabric/ReanimatedMountHook.cpp +1 -6
- package/Common/cpp/reanimated/Fabric/ReanimatedMountHook.h +1 -8
- package/Common/cpp/reanimated/Fabric/updates/AnimatedPropsRegistry.cpp +0 -2
- package/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsManager.h +1 -2
- package/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxyCommon.h +1 -1
- package/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Experimental.cpp +9 -9
- package/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Experimental.h +2 -3
- package/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Legacy.cpp +21 -21
- package/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Legacy.h +3 -3
- package/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsUtils.h +3 -3
- package/Common/cpp/reanimated/LayoutAnimations/SharedTransitions.cpp +24 -20
- package/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxy.cpp +25 -25
- package/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxy.h +1 -2
- package/Common/cpp/reanimated/RuntimeDecorators/UIRuntimeDecorator.cpp +22 -22
- package/Common/cpp/reanimated/RuntimeDecorators/UIRuntimeDecorator.h +10 -10
- package/Common/cpp/reanimated/Tools/ReaJSIUtils.h +5 -5
- package/android/build.gradle +0 -21
- package/android/src/main/cpp/reanimated/android/NativeProxy.cpp +6 -10
- package/android/src/main/cpp/reanimated/android/NativeProxy.h +1 -2
- package/android/src/main/java/com/swmansion/reanimated/CopiedEvent.java +66 -9
- package/android/src/main/java/com/swmansion/reanimated/NodesManager.java +16 -11
- package/android/src/main/java/com/swmansion/reanimated/nativeProxy/EventHandler.java +34 -8
- package/android/src/main/java/com/swmansion/reanimated/nativeProxy/NoopEventHandler.java +27 -6
- package/apple/reanimated/apple/REANodesManager.mm +0 -8
- package/apple/reanimated/apple/ReanimatedModule.mm +6 -12
- package/apple/reanimated/apple/native/NativeProxy.h +1 -2
- package/apple/reanimated/apple/native/NativeProxy.mm +1 -1
- package/compatibility.json +7 -29
- package/lib/module/PropsRegistryGarbageCollector.js +3 -0
- package/lib/module/PropsRegistryGarbageCollector.js.map +1 -1
- package/lib/module/common/style/processors/colors.js +31 -4
- package/lib/module/common/style/processors/colors.js.map +1 -1
- package/lib/module/common/style/processors/filter.js +103 -61
- package/lib/module/common/style/processors/filter.js.map +1 -1
- package/lib/module/common/style/processors/font.js +7 -1
- package/lib/module/common/style/processors/font.js.map +1 -1
- package/lib/module/common/style/processors/insets.js +26 -14
- package/lib/module/common/style/processors/insets.js.map +1 -1
- package/lib/module/common/style/processors/others.js +15 -5
- package/lib/module/common/style/processors/others.js.map +1 -1
- package/lib/module/common/style/processors/shadows.js +14 -3
- package/lib/module/common/style/processors/shadows.js.map +1 -1
- package/lib/module/common/style/processors/transform.js +30 -1
- package/lib/module/common/style/processors/transform.js.map +1 -1
- package/lib/module/common/style/processors/transformOrigin.js +20 -3
- package/lib/module/common/style/processors/transformOrigin.js.map +1 -1
- package/lib/module/common/utils/guards.js +27 -7
- package/lib/module/common/utils/guards.js.map +1 -1
- package/lib/module/common/utils/parsers.js +2 -1
- package/lib/module/common/utils/parsers.js.map +1 -1
- package/lib/module/css/native/managers/CSSManager.js +5 -13
- package/lib/module/css/native/managers/CSSManager.js.map +1 -1
- package/lib/module/css/native/managers/CSSTransitionsManager.js +47 -44
- package/lib/module/css/native/managers/CSSTransitionsManager.js.map +1 -1
- package/lib/module/css/native/normalization/transition/config.js +35 -17
- package/lib/module/css/native/normalization/transition/config.js.map +1 -1
- package/lib/module/featureFlags/index.js +1 -1
- package/lib/module/featureFlags/staticFlags.json +1 -1
- package/lib/module/hook/useAnimatedStyle.js +7 -1
- package/lib/module/hook/useAnimatedStyle.js.map +1 -1
- package/lib/module/hook/useHandler.js +82 -28
- package/lib/module/hook/useHandler.js.map +1 -1
- package/lib/module/hook/utils.js +1 -74
- package/lib/module/hook/utils.js.map +1 -1
- package/lib/module/initializers.js +2 -0
- package/lib/module/initializers.js.map +1 -1
- package/lib/module/jestUtils/common.js +10 -0
- package/lib/module/jestUtils/common.js.map +1 -1
- package/lib/module/jestUtils/index.js +2 -5
- package/lib/module/jestUtils/index.js.map +1 -1
- package/lib/module/jestUtils/index.web.js +1 -1
- package/lib/module/jestUtils/index.web.js.map +1 -1
- package/lib/module/platform-specific/jsVersion.js +1 -1
- package/lib/module/platform-specific/jsVersion.js.map +1 -1
- package/lib/typescript/PropsRegistryGarbageCollector.d.ts.map +1 -1
- package/lib/typescript/common/style/processors/colors.d.ts +3 -3
- package/lib/typescript/common/style/processors/colors.d.ts.map +1 -1
- package/lib/typescript/common/style/processors/filter.d.ts +0 -4
- package/lib/typescript/common/style/processors/filter.d.ts.map +1 -1
- package/lib/typescript/common/style/processors/font.d.ts +1 -1
- package/lib/typescript/common/style/processors/font.d.ts.map +1 -1
- package/lib/typescript/common/style/processors/insets.d.ts.map +1 -1
- package/lib/typescript/common/style/processors/others.d.ts +1 -1
- package/lib/typescript/common/style/processors/others.d.ts.map +1 -1
- package/lib/typescript/common/style/processors/shadows.d.ts.map +1 -1
- package/lib/typescript/common/style/processors/transform.d.ts.map +1 -1
- package/lib/typescript/common/style/processors/transformOrigin.d.ts +2 -2
- package/lib/typescript/common/style/processors/transformOrigin.d.ts.map +1 -1
- package/lib/typescript/common/utils/guards.d.ts +0 -1
- package/lib/typescript/common/utils/guards.d.ts.map +1 -1
- package/lib/typescript/common/utils/parsers.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/css/native/managers/CSSManager.d.ts +0 -1
- package/lib/typescript/css/native/managers/CSSManager.d.ts.map +1 -1
- package/lib/typescript/css/native/managers/CSSTransitionsManager.d.ts +5 -4
- package/lib/typescript/css/native/managers/CSSTransitionsManager.d.ts.map +1 -1
- package/lib/typescript/css/native/normalization/transition/config.d.ts.map +1 -1
- package/lib/typescript/css/native/types/transition.d.ts +15 -1
- package/lib/typescript/css/native/types/transition.d.ts.map +1 -1
- package/lib/typescript/featureFlags/index.d.ts +1 -1
- package/lib/typescript/hook/useAnimatedStyle.d.ts.map +1 -1
- package/lib/typescript/hook/useHandler.d.ts +8 -9
- package/lib/typescript/hook/useHandler.d.ts.map +1 -1
- package/lib/typescript/hook/utils.d.ts +0 -5
- package/lib/typescript/hook/utils.d.ts.map +1 -1
- package/lib/typescript/jestUtils/common.d.ts +2 -0
- package/lib/typescript/jestUtils/common.d.ts.map +1 -1
- package/lib/typescript/jestUtils/index.d.ts +4 -3
- package/lib/typescript/jestUtils/index.d.ts.map +1 -1
- package/lib/typescript/platform-specific/jsVersion.d.ts +1 -1
- package/lib/typescript/platform-specific/jsVersion.d.ts.map +1 -1
- package/package.json +10 -9
- package/src/PropsRegistryGarbageCollector.ts +3 -0
- package/src/common/style/processors/colors.ts +20 -7
- package/src/common/style/processors/filter.ts +95 -70
- package/src/common/style/processors/font.ts +5 -2
- package/src/common/style/processors/insets.ts +23 -14
- package/src/common/style/processors/others.ts +12 -6
- package/src/common/style/processors/shadows.ts +10 -6
- package/src/common/style/processors/transform.ts +15 -1
- package/src/common/style/processors/transformOrigin.ts +40 -11
- package/src/common/utils/guards.ts +21 -16
- package/src/common/utils/parsers.ts +1 -1
- package/src/commonTypes.ts +1 -1
- package/src/css/native/managers/CSSManager.ts +8 -14
- package/src/css/native/managers/CSSTransitionsManager.ts +52 -54
- package/src/css/native/normalization/transition/config.ts +35 -27
- package/src/css/native/types/transition.ts +15 -1
- package/src/featureFlags/index.ts +1 -1
- package/src/featureFlags/staticFlags.json +1 -1
- package/src/hook/useAnimatedStyle.ts +15 -6
- package/src/hook/useHandler.ts +150 -64
- package/src/hook/utils.ts +1 -127
- package/src/initializers.ts +1 -0
- package/src/jestUtils/common.ts +10 -0
- package/src/jestUtils/index.ts +5 -8
- package/src/jestUtils/index.web.ts +1 -1
- package/src/platform-specific/jsVersion.ts +1 -1
- package/src/privateGlobals.d.ts +4 -0
|
@@ -79,9 +79,10 @@ export function normalizeCSSTransitionProperties(
|
|
|
79
79
|
transitionDelay,
|
|
80
80
|
transitionBehavior,
|
|
81
81
|
} = expandedProperties;
|
|
82
|
-
const specificProperties: string[] = [];
|
|
83
82
|
let allPropertiesTransition = false;
|
|
84
83
|
const settings: Record<string, NormalizedSingleCSSTransitionSettings> = {};
|
|
84
|
+
const specificProperties = new Set<string>();
|
|
85
|
+
const processedProperties = new Set<string>();
|
|
85
86
|
|
|
86
87
|
if (!transitionProperty.length) {
|
|
87
88
|
// For cases when transition property hasn't been explicitly specified
|
|
@@ -95,42 +96,49 @@ export function normalizeCSSTransitionProperties(
|
|
|
95
96
|
// occurrence and ignore remaining ones)
|
|
96
97
|
for (let i = transitionProperty.length - 1; i >= 0; i--) {
|
|
97
98
|
const property = transitionProperty[i];
|
|
98
|
-
//
|
|
99
|
-
//
|
|
100
|
-
if (
|
|
99
|
+
// We always respect the last occurrence of a property, even if it gets
|
|
100
|
+
// pruned as inactive. That means earlier occurrences must be ignored.
|
|
101
|
+
if (processedProperties.has(property)) {
|
|
101
102
|
continue;
|
|
102
103
|
}
|
|
104
|
+
processedProperties.add(property);
|
|
103
105
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
const duration = normalizeDuration(
|
|
107
|
+
transitionDuration[i % transitionDuration.length]
|
|
108
|
+
);
|
|
109
|
+
const delay = normalizeDelay(transitionDelay[i % transitionDelay.length]);
|
|
110
|
+
|
|
111
|
+
// Skip if effective duration is 0 (the transition would be immediate so there is no need
|
|
112
|
+
// to apply it and we can just treat it as a plain render without a transition)
|
|
113
|
+
if (duration + delay <= 0) {
|
|
114
|
+
continue;
|
|
108
115
|
}
|
|
109
116
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
allowDiscrete: normalizeTransitionBehavior(
|
|
119
|
-
transitionBehavior[i % transitionBehavior.length]
|
|
120
|
-
),
|
|
121
|
-
};
|
|
117
|
+
const timingFunction = normalizeTimingFunction(
|
|
118
|
+
transitionTimingFunction[i % transitionTimingFunction.length]
|
|
119
|
+
);
|
|
120
|
+
const allowDiscrete = normalizeTransitionBehavior(
|
|
121
|
+
transitionBehavior[i % transitionBehavior.length]
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
settings[property] = { duration, timingFunction, delay, allowDiscrete };
|
|
122
125
|
|
|
123
126
|
// 'all' transition property overrides all properties before it,
|
|
124
127
|
// so we don't need to process them
|
|
125
|
-
if (
|
|
128
|
+
if (property === 'all') {
|
|
129
|
+
allPropertiesTransition = true;
|
|
126
130
|
break;
|
|
127
131
|
}
|
|
132
|
+
|
|
133
|
+
specificProperties.add(property);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (allPropertiesTransition) {
|
|
137
|
+
return { specificProperties: undefined, settings };
|
|
138
|
+
}
|
|
139
|
+
if (specificProperties.size) {
|
|
140
|
+
return { specificProperties, settings };
|
|
128
141
|
}
|
|
129
142
|
|
|
130
|
-
return
|
|
131
|
-
properties: allPropertiesTransition
|
|
132
|
-
? undefined
|
|
133
|
-
: specificProperties.reverse(),
|
|
134
|
-
settings,
|
|
135
|
-
};
|
|
143
|
+
return null;
|
|
136
144
|
}
|
|
@@ -13,7 +13,21 @@ export type CSSTransitionConfig = Record<
|
|
|
13
13
|
(NormalizedSingleCSSTransitionSettings & { value: [unknown, unknown] }) | null
|
|
14
14
|
>;
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* `specificProperties`
|
|
18
|
+
*
|
|
19
|
+
* - `undefined`: accept all props (equivalent to `transition-property: all`)
|
|
20
|
+
* - `Set<string>`: accept only props present in the set
|
|
21
|
+
*
|
|
22
|
+
* `settings`
|
|
23
|
+
*
|
|
24
|
+
* - Keys are prop names, plus an optional `all` fallback key
|
|
25
|
+
* - How to read it for a prop `propName`:
|
|
26
|
+
*
|
|
27
|
+
* - Primary: `settings[propName]` (if present)
|
|
28
|
+
* - Fallback: `settings.all` (otherwise)
|
|
29
|
+
*/
|
|
16
30
|
export type NormalizedCSSTransitionConfig = {
|
|
17
|
-
|
|
31
|
+
specificProperties: Set<string> | undefined;
|
|
18
32
|
settings: Record<string, NormalizedSingleCSSTransitionSettings>;
|
|
19
33
|
};
|
|
@@ -80,7 +80,7 @@ const DefaultStaticFeatureFlags = {
|
|
|
80
80
|
USE_SYNCHRONIZABLE_FOR_MUTABLES: true,
|
|
81
81
|
USE_COMMIT_HOOK_ONLY_FOR_REACT_COMMITS: true,
|
|
82
82
|
ENABLE_SHARED_ELEMENT_TRANSITIONS: false,
|
|
83
|
-
FORCE_REACT_RENDER_FOR_SETTLED_ANIMATIONS:
|
|
83
|
+
FORCE_REACT_RENDER_FOR_SETTLED_ANIMATIONS: true,
|
|
84
84
|
} as const satisfies typeof StaticFeatureFlagsJSON;
|
|
85
85
|
|
|
86
86
|
type StaticFeatureFlagsSchema = {
|
|
@@ -30,12 +30,7 @@ import type {
|
|
|
30
30
|
JestAnimatedStyleHandle,
|
|
31
31
|
} from './commonTypes';
|
|
32
32
|
import { useSharedValue } from './useSharedValue';
|
|
33
|
-
import {
|
|
34
|
-
buildWorkletsHash,
|
|
35
|
-
isAnimated,
|
|
36
|
-
shallowEqual,
|
|
37
|
-
validateAnimatedStyles,
|
|
38
|
-
} from './utils';
|
|
33
|
+
import { isAnimated, shallowEqual, validateAnimatedStyles } from './utils';
|
|
39
34
|
|
|
40
35
|
interface AnimatedState {
|
|
41
36
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -450,6 +445,20 @@ function checkSharedValueUsage(
|
|
|
450
445
|
}
|
|
451
446
|
}
|
|
452
447
|
|
|
448
|
+
// Builds one big hash from multiple worklets' hashes.
|
|
449
|
+
function buildWorkletsHash<Args extends unknown[], ReturnValue>(
|
|
450
|
+
worklets:
|
|
451
|
+
| Record<string, WorkletFunction<Args, ReturnValue>>
|
|
452
|
+
| WorkletFunction<Args, ReturnValue>[]
|
|
453
|
+
) {
|
|
454
|
+
// For arrays `Object.values` returns the array itself.
|
|
455
|
+
return Object.values(worklets).reduce(
|
|
456
|
+
(acc, worklet: WorkletFunction<Args, ReturnValue>) =>
|
|
457
|
+
acc + worklet.__workletHash.toString(),
|
|
458
|
+
''
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
|
|
453
462
|
/**
|
|
454
463
|
* Lets you create a styles object, similar to StyleSheet styles, which can be
|
|
455
464
|
* animated using shared values.
|
package/src/hook/useHandler.ts
CHANGED
|
@@ -1,43 +1,129 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
import { useEffect, useRef } from 'react';
|
|
3
3
|
import type { WorkletFunction } from 'react-native-worklets';
|
|
4
|
-
import { makeShareable } from 'react-native-worklets';
|
|
4
|
+
import { isWorkletFunction, makeShareable } from 'react-native-worklets';
|
|
5
|
+
import type { WorkletClosure } from 'react-native-worklets/lib/typescript/types';
|
|
5
6
|
|
|
6
|
-
import {
|
|
7
|
+
import type { UnknownRecord } from '../common';
|
|
8
|
+
import { IS_WEB, ReanimatedError } from '../common';
|
|
7
9
|
import type { DependencyList, ReanimatedEvent } from './commonTypes';
|
|
8
|
-
import { areDependenciesEqual, buildDependencies } from './utils';
|
|
9
10
|
|
|
10
11
|
interface GeneralHandler<
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
TEvent extends object,
|
|
13
|
+
TContext extends UnknownRecord,
|
|
13
14
|
> {
|
|
14
|
-
(event: ReanimatedEvent<
|
|
15
|
+
(event: ReanimatedEvent<TEvent>, context: TContext): void;
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
type GeneralWorkletHandler<
|
|
18
|
-
Event extends object,
|
|
19
|
-
Context extends Record<string, unknown>,
|
|
20
|
-
> = WorkletFunction<[event: ReanimatedEvent<Event>, context: Context]>;
|
|
21
|
-
|
|
22
18
|
type GeneralHandlers<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
> = Record<string, GeneralHandler<
|
|
26
|
-
|
|
27
|
-
type GeneralWorkletHandlers<
|
|
28
|
-
Event extends object,
|
|
29
|
-
Context extends Record<string, unknown>,
|
|
30
|
-
> = Record<string, GeneralWorkletHandler<Event, Context>>;
|
|
31
|
-
|
|
32
|
-
interface ContextWithDependencies<Context extends Record<string, unknown>> {
|
|
33
|
-
context: Context;
|
|
34
|
-
savedDependencies: DependencyList;
|
|
35
|
-
}
|
|
19
|
+
TEvent extends object,
|
|
20
|
+
TContext extends UnknownRecord,
|
|
21
|
+
> = Record<string, GeneralHandler<TEvent, TContext> | undefined>;
|
|
36
22
|
|
|
37
|
-
export interface UseHandlerContext<
|
|
38
|
-
context:
|
|
23
|
+
export interface UseHandlerContext<TContext extends UnknownRecord> {
|
|
24
|
+
context: TContext;
|
|
39
25
|
doDependenciesDiffer: boolean;
|
|
40
|
-
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function isBabelPluginEnabled(handlers: UnknownRecord): boolean {
|
|
29
|
+
if (!IS_WEB) {
|
|
30
|
+
// Babel plugin must be enabled in all non-web environments.
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const handlerFunctions = Object.values(handlers);
|
|
35
|
+
// If there is no function provided, we assume that the Babel plugin is enabled.
|
|
36
|
+
return (
|
|
37
|
+
handlerFunctions.length === 0 || handlerFunctions.some(isWorkletFunction)
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function ensureWorkletHandlers(handlers: UnknownRecord) {
|
|
42
|
+
const nonWorkletNames = Object.entries(handlers).reduce<string[]>(
|
|
43
|
+
(acc, [name, handler]) => {
|
|
44
|
+
if (!isWorkletFunction(handler)) acc.push(name);
|
|
45
|
+
return acc;
|
|
46
|
+
},
|
|
47
|
+
[]
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
if (nonWorkletNames.length > 0) {
|
|
51
|
+
throw new ReanimatedError(
|
|
52
|
+
`Passed handlers that are not worklets. Only worklet functions are allowed. Handlers "${nonWorkletNames.join(', ')}" are not worklets.`
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const objectIs: (a: unknown, b: unknown) => boolean =
|
|
58
|
+
typeof Object.is === 'function'
|
|
59
|
+
? Object.is
|
|
60
|
+
: (x, y) =>
|
|
61
|
+
(x === y && (x !== 0 || 1 / (x as number) === 1 / (y as number))) ||
|
|
62
|
+
(Number.isNaN(x as number) && Number.isNaN(y as number));
|
|
63
|
+
|
|
64
|
+
function areWorkletClosuresEqual(
|
|
65
|
+
next: WorkletClosure,
|
|
66
|
+
prev: WorkletClosure
|
|
67
|
+
): boolean {
|
|
68
|
+
const nextKeys = Object.keys(next);
|
|
69
|
+
const prevKeys = Object.keys(prev);
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
prevKeys.length === nextKeys.length &&
|
|
73
|
+
prevKeys.every((key) => key in next && objectIs(next[key], prev[key]))
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function areWorkletsEqual(
|
|
78
|
+
next: WorkletFunction,
|
|
79
|
+
prev: WorkletFunction
|
|
80
|
+
): boolean {
|
|
81
|
+
if (objectIs(next, prev)) {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
next.__workletHash === prev.__workletHash &&
|
|
87
|
+
areWorkletClosuresEqual(next.__closure, prev.__closure)
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function areWorkletHandlersEqual(
|
|
92
|
+
next: Partial<Record<string, WorkletFunction>> | undefined,
|
|
93
|
+
prev: Partial<Record<string, WorkletFunction>> | undefined
|
|
94
|
+
) {
|
|
95
|
+
if (!next || !prev) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const nextKeys = Object.keys(next);
|
|
100
|
+
const prevKeys = Object.keys(prev);
|
|
101
|
+
|
|
102
|
+
if (nextKeys.length !== prevKeys.length) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return nextKeys.every((key) => {
|
|
107
|
+
const nextValue = next[key];
|
|
108
|
+
const prevValue = prev[key];
|
|
109
|
+
|
|
110
|
+
if (!nextValue || !prevValue) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return areWorkletsEqual(nextValue, prevValue);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function areDependenciesEqual(
|
|
119
|
+
next: Array<unknown> | undefined,
|
|
120
|
+
prev: Array<unknown> | undefined
|
|
121
|
+
): boolean {
|
|
122
|
+
if (!next || !prev || next.length !== prev.length) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return next.every((value, index) => objectIs(value, prev[index]));
|
|
41
127
|
}
|
|
42
128
|
|
|
43
129
|
/**
|
|
@@ -46,52 +132,52 @@ export interface UseHandlerContext<Context extends Record<string, unknown>> {
|
|
|
46
132
|
* @param handlers - An object of event handlers.
|
|
47
133
|
* @param dependencies - An optional array of dependencies.
|
|
48
134
|
* @returns An object containing a boolean indicating whether the dependencies
|
|
49
|
-
* have changed
|
|
50
|
-
* web.
|
|
135
|
+
* have changed.
|
|
51
136
|
* @see https://docs.swmansion.com/react-native-reanimated/docs/advanced/useHandler
|
|
52
137
|
*/
|
|
53
|
-
|
|
54
|
-
export function useHandler<
|
|
55
|
-
Event extends object,
|
|
56
|
-
Context extends Record<string, unknown>,
|
|
57
|
-
>(
|
|
138
|
+
export function useHandler<Event extends object, Context extends UnknownRecord>(
|
|
58
139
|
handlers: GeneralHandlers<Event, Context>,
|
|
59
140
|
dependencies?: DependencyList
|
|
60
|
-
): UseHandlerContext<Context>;
|
|
61
|
-
|
|
62
|
-
export function useHandler<
|
|
63
|
-
Event extends object,
|
|
64
|
-
Context extends Record<string, unknown>,
|
|
65
|
-
>(
|
|
66
|
-
handlers: GeneralWorkletHandlers<Event, Context>,
|
|
67
|
-
dependencies?: DependencyList
|
|
68
141
|
): UseHandlerContext<Context> {
|
|
69
|
-
|
|
70
|
-
if (initRef.current === null) {
|
|
71
|
-
const context = makeShareable({} as Context);
|
|
72
|
-
initRef.current = {
|
|
73
|
-
context,
|
|
74
|
-
savedDependencies: [],
|
|
75
|
-
};
|
|
76
|
-
}
|
|
142
|
+
'use no memo';
|
|
77
143
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
144
|
+
const stateRef = useRef<{
|
|
145
|
+
context: Context;
|
|
146
|
+
prevHandlers: GeneralHandlers<Event, Context> | undefined;
|
|
147
|
+
prevDependencies: DependencyList;
|
|
148
|
+
} | null>(null);
|
|
149
|
+
|
|
150
|
+
if (stateRef.current === null) {
|
|
151
|
+
stateRef.current = {
|
|
152
|
+
context: makeShareable({} as Context),
|
|
153
|
+
prevHandlers: undefined,
|
|
154
|
+
prevDependencies: [],
|
|
81
155
|
};
|
|
82
|
-
}
|
|
156
|
+
}
|
|
83
157
|
|
|
84
|
-
const
|
|
158
|
+
const state = stateRef.current;
|
|
159
|
+
let doDependenciesDiffer = true;
|
|
85
160
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
161
|
+
if (isBabelPluginEnabled(handlers)) {
|
|
162
|
+
if (__DEV__) {
|
|
163
|
+
ensureWorkletHandlers(handlers);
|
|
164
|
+
}
|
|
165
|
+
doDependenciesDiffer = !areWorkletHandlersEqual(
|
|
166
|
+
handlers as Record<string, WorkletFunction>,
|
|
167
|
+
state.prevHandlers as Record<string, WorkletFunction>
|
|
168
|
+
);
|
|
169
|
+
} else if (dependencies) {
|
|
170
|
+
doDependenciesDiffer = !areDependenciesEqual(
|
|
171
|
+
dependencies,
|
|
172
|
+
state.prevDependencies
|
|
173
|
+
);
|
|
174
|
+
}
|
|
90
175
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
176
|
+
// Write after commit to avoid corruption from interrupted renders (in case of concurrent mode).
|
|
177
|
+
useEffect(() => {
|
|
178
|
+
state.prevHandlers = handlers;
|
|
179
|
+
state.prevDependencies = dependencies;
|
|
180
|
+
});
|
|
95
181
|
|
|
96
|
-
return { context, doDependenciesDiffer
|
|
182
|
+
return { context: state.context, doDependenciesDiffer };
|
|
97
183
|
}
|
package/src/hook/utils.ts
CHANGED
|
@@ -1,131 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
import
|
|
3
|
-
import { isWorkletFunction } from 'react-native-worklets';
|
|
4
|
-
|
|
5
|
-
import { IS_WEB, logger, ReanimatedError } from '../common';
|
|
6
|
-
import type { DependencyList } from './commonTypes';
|
|
7
|
-
|
|
8
|
-
// Builds one big hash from multiple worklets' hashes.
|
|
9
|
-
export function buildWorkletsHash<Args extends unknown[], ReturnValue>(
|
|
10
|
-
worklets:
|
|
11
|
-
| Record<string, WorkletFunction<Args, ReturnValue>>
|
|
12
|
-
| WorkletFunction<Args, ReturnValue>[]
|
|
13
|
-
) {
|
|
14
|
-
// For arrays `Object.values` returns the array itself.
|
|
15
|
-
return Object.values(worklets).reduce(
|
|
16
|
-
(acc, worklet: WorkletFunction<Args, ReturnValue>) =>
|
|
17
|
-
acc + worklet.__workletHash.toString(),
|
|
18
|
-
''
|
|
19
|
-
);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// Builds dependencies array for useEvent handlers.
|
|
23
|
-
export function buildDependencies(
|
|
24
|
-
dependencies: DependencyList | undefined,
|
|
25
|
-
handlers: Record<string, WorkletFunction>
|
|
26
|
-
) {
|
|
27
|
-
const result = dependencies ?? [];
|
|
28
|
-
|
|
29
|
-
const nonWorkletHandlerNames = Object.entries(handlers).reduce<string[]>(
|
|
30
|
-
(acc, [name, handler]) => {
|
|
31
|
-
if (!isWorkletFunction(handler)) {
|
|
32
|
-
acc.push(name);
|
|
33
|
-
}
|
|
34
|
-
return acc;
|
|
35
|
-
},
|
|
36
|
-
[]
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
if (nonWorkletHandlerNames.length === 0) {
|
|
40
|
-
result.push(buildWorkletsHash(handlers));
|
|
41
|
-
return result;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (!__DEV__) {
|
|
45
|
-
return result;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const handlerNames = nonWorkletHandlerNames.join(', ');
|
|
49
|
-
|
|
50
|
-
// On native, only worklets are allowed
|
|
51
|
-
if (!IS_WEB) {
|
|
52
|
-
throw new ReanimatedError(
|
|
53
|
-
`Passed handlers that are not worklets. Only worklet functions are allowed. Handlers "${handlerNames}" are not worklets.`
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// On web, non-worklets are allowed only when dependencies are provided
|
|
58
|
-
if (__DEV__ && !dependencies) {
|
|
59
|
-
logger.warn(
|
|
60
|
-
`Non-worklet handlers ("${handlerNames}") were passed without a dependency array. This will cause the hook to update on every render. Please provide a dependency array or use only worklet functions instead.`
|
|
61
|
-
);
|
|
62
|
-
return undefined;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return result;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function areWorkletsEqual(
|
|
69
|
-
worklet1: WorkletFunction,
|
|
70
|
-
worklet2: WorkletFunction
|
|
71
|
-
) {
|
|
72
|
-
if (worklet1.__workletHash === worklet2.__workletHash) {
|
|
73
|
-
const closure1Keys = Object.keys(worklet1.__closure);
|
|
74
|
-
const closure2Keys = Object.keys(worklet2.__closure);
|
|
75
|
-
|
|
76
|
-
return (
|
|
77
|
-
closure1Keys.length === closure2Keys.length &&
|
|
78
|
-
closure1Keys.every(
|
|
79
|
-
(key) =>
|
|
80
|
-
key in worklet2.__closure &&
|
|
81
|
-
worklet1.__closure[key] === worklet2.__closure[key]
|
|
82
|
-
)
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return false;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// This is supposed to work as useEffect comparison.
|
|
90
|
-
export function areDependenciesEqual(
|
|
91
|
-
nextDependencies: DependencyList,
|
|
92
|
-
prevDependencies: DependencyList
|
|
93
|
-
) {
|
|
94
|
-
function is(x: number, y: number) {
|
|
95
|
-
return (
|
|
96
|
-
(x === y && (x !== 0 || 1 / x === 1 / y)) ||
|
|
97
|
-
(Number.isNaN(x) && Number.isNaN(y))
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
const objectIs: (nextDeps: unknown, prevDeps: unknown) => boolean =
|
|
101
|
-
typeof Object.is === 'function' ? Object.is : is;
|
|
102
|
-
|
|
103
|
-
function areHookInputsEqual(
|
|
104
|
-
nextDeps: DependencyList,
|
|
105
|
-
prevDeps: DependencyList
|
|
106
|
-
) {
|
|
107
|
-
if (!nextDeps || !prevDeps || prevDeps.length !== nextDeps.length) {
|
|
108
|
-
return false;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
for (let i = 0; i < prevDeps.length; ++i) {
|
|
112
|
-
const nextDep = nextDeps[i];
|
|
113
|
-
const prevDep = prevDeps[i];
|
|
114
|
-
if (objectIs(nextDep, prevDep)) {
|
|
115
|
-
continue;
|
|
116
|
-
}
|
|
117
|
-
if (!isWorkletFunction(nextDep) || !isWorkletFunction(prevDep)) {
|
|
118
|
-
return false;
|
|
119
|
-
}
|
|
120
|
-
if (!areWorkletsEqual(nextDep, prevDep)) {
|
|
121
|
-
return false;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
return true;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return areHookInputsEqual(nextDependencies, prevDependencies);
|
|
128
|
-
}
|
|
2
|
+
import { ReanimatedError } from '../common';
|
|
129
3
|
|
|
130
4
|
export function isAnimated(prop: unknown) {
|
|
131
5
|
'worklet';
|
package/src/initializers.ts
CHANGED
package/src/jestUtils/common.ts
CHANGED
|
@@ -22,3 +22,13 @@ export const worklet = <Args extends unknown[] = [], ReturnValue = void>(
|
|
|
22
22
|
fn.__closure = {};
|
|
23
23
|
return fn;
|
|
24
24
|
};
|
|
25
|
+
|
|
26
|
+
/** Creates a new worklet with the same hash and closure as the original. */
|
|
27
|
+
export const cloneWorklet = <Args extends unknown[] = [], ReturnValue = void>(
|
|
28
|
+
original: WorkletFunction<Args, ReturnValue>
|
|
29
|
+
): WorkletFunction<Args, ReturnValue> => {
|
|
30
|
+
const w = worklet<Args, ReturnValue>();
|
|
31
|
+
w.__workletHash = original.__workletHash;
|
|
32
|
+
w.__closure = { ...original.__closure };
|
|
33
|
+
return w;
|
|
34
|
+
};
|
package/src/jestUtils/index.ts
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
import type React from 'react';
|
|
5
|
-
import type { ReactTestInstance } from 'react-test-renderer';
|
|
6
5
|
|
|
7
6
|
import { IS_JEST, logger, ReanimatedError } from '../common';
|
|
8
7
|
import type {
|
|
@@ -347,12 +346,10 @@ type TestComponent = React.Component<
|
|
|
347
346
|
}
|
|
348
347
|
>;
|
|
349
348
|
|
|
350
|
-
export const getAnimatedStyle = (component:
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
component as unknown as TestComponent
|
|
355
|
-
);
|
|
349
|
+
export const getAnimatedStyle = (component: {
|
|
350
|
+
props: Record<string, unknown>;
|
|
351
|
+
}) => {
|
|
352
|
+
return getCurrentStyle(component as unknown as TestComponent);
|
|
356
353
|
};
|
|
357
354
|
|
|
358
|
-
export { worklet } from './common';
|
|
355
|
+
export { cloneWorklet, worklet } from './common';
|
package/src/privateGlobals.d.ts
CHANGED
|
@@ -24,6 +24,10 @@ declare global {
|
|
|
24
24
|
var _REANIMATED_VERSION_JS: string | undefined;
|
|
25
25
|
var __reanimatedModuleProxy: ReanimatedModuleProxy | undefined;
|
|
26
26
|
var _log: (value: unknown) => void;
|
|
27
|
+
var _startProfiling: (meanHzFreq?: number) => void;
|
|
28
|
+
var _stopProfiling: () => string;
|
|
29
|
+
var _beginSection: (name: string) => void;
|
|
30
|
+
var _endSection: () => void;
|
|
27
31
|
var _notifyAboutProgress: (
|
|
28
32
|
tag: number,
|
|
29
33
|
value: Record<string, unknown>
|