react-native-reanimated 3.18.0 → 3.18.2
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/Fabric/ReanimatedCommitHook.cpp +14 -2
- package/Common/cpp/reanimated/Fabric/ReanimatedCommitHook.h +6 -1
- package/Common/cpp/reanimated/Fabric/ReanimatedMountHook.cpp +6 -1
- package/Common/cpp/reanimated/Fabric/ReanimatedMountHook.h +6 -1
- package/Common/cpp/reanimated/Fabric/ShadowTreeCloner.cpp +3 -2
- package/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy.cpp +86 -24
- package/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy.h +29 -4
- package/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsUtils.h +4 -5
- package/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxy.cpp +45 -15
- package/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxy.h +4 -1
- package/Common/cpp/reanimated/Tools/ReanimatedSystraceSection.h +1 -1
- package/README.md +1 -13
- package/RNReanimated.podspec +1 -1
- package/android/src/main/cpp/reanimated/android/NativeProxy.cpp +25 -21
- package/android/src/main/cpp/reanimated/android/NativeProxy.h +5 -3
- package/apple/reanimated/apple/LayoutReanimation/REASharedTransitionManager.m +1 -2
- package/apple/reanimated/apple/LayoutReanimation/REASwizzledUIManager.mm +8 -7
- package/lib/module/PlatformChecker.js +6 -0
- package/lib/module/PlatformChecker.js.map +1 -1
- package/lib/module/animation/util.js +7 -4
- package/lib/module/animation/util.js.map +1 -1
- package/lib/module/component/FlatList.js +9 -3
- package/lib/module/component/FlatList.js.map +1 -1
- package/lib/module/core.js +0 -2
- package/lib/module/core.js.map +1 -1
- package/lib/module/createAnimatedComponent/NativeEventsManager.js +1 -1
- package/lib/module/createAnimatedComponent/NativeEventsManager.js.map +1 -1
- package/lib/module/createAnimatedComponent/createAnimatedComponent.js +24 -37
- package/lib/module/createAnimatedComponent/createAnimatedComponent.js.map +1 -1
- package/lib/module/hook/useAnimatedRef.js +70 -35
- package/lib/module/hook/useAnimatedRef.js.map +1 -1
- package/lib/module/hook/useHandler.js +7 -0
- package/lib/module/hook/useHandler.js.map +1 -1
- package/lib/module/hook/useScrollViewOffset.js +28 -26
- package/lib/module/hook/useScrollViewOffset.js.map +1 -1
- package/lib/module/hook/utils.js +20 -9
- package/lib/module/hook/utils.js.map +1 -1
- package/lib/module/index.js +3 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/platform-specific/jsVersion.js +1 -1
- package/lib/module/platformFunctions/setNativeProps.js +1 -1
- package/lib/module/platformFunctions/setNativeProps.js.map +1 -1
- package/lib/module/processBoxShadow.js.map +1 -1
- package/lib/typescript/PlatformChecker.d.ts +2 -0
- package/lib/typescript/PlatformChecker.d.ts.map +1 -1
- package/lib/typescript/animation/util.d.ts.map +1 -1
- package/lib/typescript/component/FlatList.d.ts +10 -2
- package/lib/typescript/component/FlatList.d.ts.map +1 -1
- package/lib/typescript/core.d.ts.map +1 -1
- package/lib/typescript/createAnimatedComponent/commonTypes.d.ts +1 -0
- package/lib/typescript/createAnimatedComponent/commonTypes.d.ts.map +1 -1
- package/lib/typescript/createAnimatedComponent/createAnimatedComponent.d.ts.map +1 -1
- package/lib/typescript/helperTypes.d.ts +1 -3
- package/lib/typescript/helperTypes.d.ts.map +1 -1
- package/lib/typescript/hook/commonTypes.d.ts +7 -4
- package/lib/typescript/hook/commonTypes.d.ts.map +1 -1
- package/lib/typescript/hook/useAnimatedRef.d.ts +3 -1
- package/lib/typescript/hook/useAnimatedRef.d.ts.map +1 -1
- package/lib/typescript/hook/useHandler.d.ts.map +1 -1
- package/lib/typescript/hook/useScrollViewOffset.d.ts.map +1 -1
- package/lib/typescript/hook/utils.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +1 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/platform-specific/jsVersion.d.ts +1 -1
- package/lib/typescript/processBoxShadow.d.ts +6 -3
- package/lib/typescript/processBoxShadow.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/PlatformChecker.ts +8 -0
- package/src/animation/util.ts +7 -4
- package/src/component/FlatList.tsx +44 -6
- package/src/core.ts +0 -3
- package/src/createAnimatedComponent/NativeEventsManager.ts +1 -1
- package/src/createAnimatedComponent/commonTypes.ts +9 -0
- package/src/createAnimatedComponent/createAnimatedComponent.tsx +61 -73
- package/src/helperTypes.ts +1 -6
- package/src/hook/commonTypes.ts +9 -4
- package/src/hook/useAnimatedRef.ts +107 -48
- package/src/hook/useHandler.ts +10 -0
- package/src/hook/useScrollViewOffset.ts +34 -29
- package/src/hook/utils.ts +34 -9
- package/src/index.ts +4 -1
- package/src/platform-specific/jsVersion.ts +1 -1
- package/src/platformFunctions/setNativeProps.ts +1 -1
- package/src/processBoxShadow.ts +8 -4
|
@@ -58,6 +58,7 @@ import type {
|
|
|
58
58
|
IAnimatedComponentInternal,
|
|
59
59
|
INativeEventsManager,
|
|
60
60
|
InitialComponentProps,
|
|
61
|
+
LayoutAnimationOrBuilder,
|
|
61
62
|
NestedArray,
|
|
62
63
|
ViewInfo,
|
|
63
64
|
} from './commonTypes';
|
|
@@ -169,22 +170,13 @@ export function createAnimatedComponent(
|
|
|
169
170
|
this.jestAnimatedProps = { value: {} };
|
|
170
171
|
}
|
|
171
172
|
|
|
172
|
-
const entering = this.props.entering;
|
|
173
173
|
const skipEntering = this.context?.current;
|
|
174
|
-
if (
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
) {
|
|
180
|
-
return;
|
|
174
|
+
if (isFabric() && !skipEntering) {
|
|
175
|
+
this._configureLayoutAnimation(
|
|
176
|
+
LayoutAnimationType.ENTERING,
|
|
177
|
+
this.props.entering
|
|
178
|
+
);
|
|
181
179
|
}
|
|
182
|
-
// This call is responsible for configuring entering animations on Fabric.
|
|
183
|
-
updateLayoutAnimations(
|
|
184
|
-
this.reanimatedID,
|
|
185
|
-
LayoutAnimationType.ENTERING,
|
|
186
|
-
maybeBuild(entering, this.props?.style, AnimatedComponent.displayName)
|
|
187
|
-
);
|
|
188
180
|
}
|
|
189
181
|
|
|
190
182
|
componentDidMount() {
|
|
@@ -197,10 +189,14 @@ export function createAnimatedComponent(
|
|
|
197
189
|
this._attachAnimatedStyles();
|
|
198
190
|
this._InlinePropManager.attachInlineProps(this, this._getViewInfo());
|
|
199
191
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
this.
|
|
203
|
-
|
|
192
|
+
this._configureLayoutAnimation(
|
|
193
|
+
LayoutAnimationType.LAYOUT,
|
|
194
|
+
this.props.layout
|
|
195
|
+
);
|
|
196
|
+
this._configureLayoutAnimation(
|
|
197
|
+
LayoutAnimationType.EXITING,
|
|
198
|
+
this.props.exiting
|
|
199
|
+
);
|
|
204
200
|
|
|
205
201
|
if (IS_WEB) {
|
|
206
202
|
if (this.props.exiting && this._componentDOMRef) {
|
|
@@ -276,15 +272,7 @@ export function createAnimatedComponent(
|
|
|
276
272
|
? getReduceMotionFromConfig(exiting.getReduceMotion())
|
|
277
273
|
: getReduceMotionFromConfig();
|
|
278
274
|
if (!reduceMotionInExiting) {
|
|
279
|
-
|
|
280
|
-
this.getComponentViewTag(),
|
|
281
|
-
LayoutAnimationType.EXITING,
|
|
282
|
-
maybeBuild(
|
|
283
|
-
exiting,
|
|
284
|
-
this.props?.style,
|
|
285
|
-
AnimatedComponent.displayName
|
|
286
|
-
)
|
|
287
|
-
);
|
|
275
|
+
this._configureLayoutAnimation(LayoutAnimationType.EXITING, exiting);
|
|
288
276
|
}
|
|
289
277
|
}
|
|
290
278
|
|
|
@@ -465,15 +453,19 @@ export function createAnimatedComponent(
|
|
|
465
453
|
componentDidUpdate(
|
|
466
454
|
prevProps: AnimatedComponentProps<InitialComponentProps>,
|
|
467
455
|
_prevState: Readonly<unknown>,
|
|
468
|
-
// This type comes straight from React
|
|
469
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
470
456
|
snapshot: DOMRect | null
|
|
471
457
|
) {
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
458
|
+
this._configureLayoutAnimation(
|
|
459
|
+
LayoutAnimationType.LAYOUT,
|
|
460
|
+
this.props.layout,
|
|
461
|
+
prevProps.layout
|
|
462
|
+
);
|
|
463
|
+
this._configureLayoutAnimation(
|
|
464
|
+
LayoutAnimationType.EXITING,
|
|
465
|
+
this.props.exiting,
|
|
466
|
+
prevProps.exiting
|
|
467
|
+
);
|
|
468
|
+
|
|
477
469
|
if (
|
|
478
470
|
this.props.sharedTransitionTag !== undefined ||
|
|
479
471
|
prevProps.sharedTransitionTag !== undefined
|
|
@@ -488,10 +480,9 @@ export function createAnimatedComponent(
|
|
|
488
480
|
saveSnapshot(this._componentDOMRef);
|
|
489
481
|
}
|
|
490
482
|
|
|
491
|
-
// Snapshot won't be undefined because it comes from getSnapshotBeforeUpdate method
|
|
492
483
|
if (
|
|
493
484
|
IS_WEB &&
|
|
494
|
-
snapshot
|
|
485
|
+
snapshot &&
|
|
495
486
|
this.props.layout &&
|
|
496
487
|
!getReducedMotionFromConfig(this.props.layout as CustomConfig)
|
|
497
488
|
) {
|
|
@@ -503,22 +494,33 @@ export function createAnimatedComponent(
|
|
|
503
494
|
}
|
|
504
495
|
}
|
|
505
496
|
|
|
506
|
-
|
|
507
|
-
|
|
497
|
+
_configureLayoutAnimation(
|
|
498
|
+
type: LayoutAnimationType,
|
|
499
|
+
currentConfig: LayoutAnimationOrBuilder | undefined,
|
|
500
|
+
previousConfig?: LayoutAnimationOrBuilder
|
|
501
|
+
) {
|
|
502
|
+
if (IS_WEB || currentConfig === previousConfig) {
|
|
508
503
|
return;
|
|
509
504
|
}
|
|
510
505
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
506
|
+
if (this._isReducedMotion(currentConfig)) {
|
|
507
|
+
if (!previousConfig) {
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
currentConfig = undefined;
|
|
514
511
|
}
|
|
512
|
+
|
|
515
513
|
updateLayoutAnimations(
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
514
|
+
isFabric() && type === LayoutAnimationType.ENTERING
|
|
515
|
+
? this.reanimatedID
|
|
516
|
+
: this.getComponentViewTag(),
|
|
517
|
+
type,
|
|
518
|
+
currentConfig &&
|
|
519
519
|
maybeBuild(
|
|
520
|
-
|
|
521
|
-
|
|
520
|
+
currentConfig,
|
|
521
|
+
type === LayoutAnimationType.LAYOUT
|
|
522
|
+
? undefined /* We don't have to warn user if style has common properties with animation for LAYOUT */
|
|
523
|
+
: this.props?.style,
|
|
522
524
|
AnimatedComponent.displayName
|
|
523
525
|
)
|
|
524
526
|
);
|
|
@@ -584,7 +586,6 @@ export function createAnimatedComponent(
|
|
|
584
586
|
// if ref is changed, reset viewInfo
|
|
585
587
|
this._viewInfo = undefined;
|
|
586
588
|
}
|
|
587
|
-
const tag = this.getComponentViewTag();
|
|
588
589
|
|
|
589
590
|
const { layout, entering, exiting, sharedTransitionTag } = this.props;
|
|
590
591
|
if (layout || entering || exiting || sharedTransitionTag) {
|
|
@@ -595,52 +596,39 @@ export function createAnimatedComponent(
|
|
|
595
596
|
if (sharedTransitionTag) {
|
|
596
597
|
this._configureSharedTransition();
|
|
597
598
|
}
|
|
598
|
-
if (exiting && isFabric()) {
|
|
599
|
-
const reduceMotionInExiting =
|
|
600
|
-
'getReduceMotion' in exiting &&
|
|
601
|
-
typeof exiting.getReduceMotion === 'function'
|
|
602
|
-
? getReduceMotionFromConfig(exiting.getReduceMotion())
|
|
603
|
-
: getReduceMotionFromConfig();
|
|
604
|
-
if (!reduceMotionInExiting) {
|
|
605
|
-
updateLayoutAnimations(
|
|
606
|
-
tag,
|
|
607
|
-
LayoutAnimationType.EXITING,
|
|
608
|
-
maybeBuild(
|
|
609
|
-
exiting,
|
|
610
|
-
this.props?.style,
|
|
611
|
-
AnimatedComponent.displayName
|
|
612
|
-
)
|
|
613
|
-
);
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
599
|
|
|
617
600
|
const skipEntering = this.context?.current;
|
|
618
601
|
if (entering && !isFabric() && !skipEntering && !IS_WEB) {
|
|
619
|
-
|
|
620
|
-
tag,
|
|
602
|
+
this._configureLayoutAnimation(
|
|
621
603
|
LayoutAnimationType.ENTERING,
|
|
622
|
-
|
|
623
|
-
entering,
|
|
624
|
-
this.props?.style,
|
|
625
|
-
AnimatedComponent.displayName
|
|
626
|
-
)
|
|
604
|
+
this.props.entering
|
|
627
605
|
);
|
|
628
606
|
}
|
|
629
607
|
}
|
|
630
608
|
},
|
|
631
609
|
});
|
|
632
610
|
|
|
611
|
+
_isReducedMotion(config?: LayoutAnimationOrBuilder): boolean {
|
|
612
|
+
return config &&
|
|
613
|
+
'getReduceMotion' in config &&
|
|
614
|
+
typeof config.getReduceMotion === 'function'
|
|
615
|
+
? getReduceMotionFromConfig(config.getReduceMotion())
|
|
616
|
+
: getReduceMotionFromConfig();
|
|
617
|
+
}
|
|
618
|
+
|
|
633
619
|
// This is a component lifecycle method from React, therefore we are not calling it directly.
|
|
634
620
|
// It is called before the component gets rerendered. This way we can access components' position before it changed
|
|
635
621
|
// and later on, in componentDidUpdate, calculate translation for layout transition.
|
|
636
622
|
getSnapshotBeforeUpdate() {
|
|
637
623
|
if (
|
|
638
624
|
IS_WEB &&
|
|
639
|
-
this.
|
|
625
|
+
this.props.layout &&
|
|
626
|
+
this._componentDOMRef?.getBoundingClientRect
|
|
640
627
|
) {
|
|
641
628
|
return this._componentDOMRef.getBoundingClientRect();
|
|
642
629
|
}
|
|
643
630
|
|
|
631
|
+
// `getSnapshotBeforeUpdate` has to return value which is not `undefined`.
|
|
644
632
|
return null;
|
|
645
633
|
}
|
|
646
634
|
|
package/src/helperTypes.ts
CHANGED
|
@@ -7,7 +7,7 @@ until time comes to refactor the code and get necessary types right.
|
|
|
7
7
|
This will not be easy though!
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import type {
|
|
10
|
+
import type { StyleProp } from 'react-native';
|
|
11
11
|
|
|
12
12
|
import type {
|
|
13
13
|
AnimatedStyle,
|
|
@@ -144,10 +144,5 @@ export type AdaptTransforms<T> = {
|
|
|
144
144
|
/** @deprecated Please use {@link TransformArrayItem} type instead. */
|
|
145
145
|
export type TransformStyleTypes = TransformArrayItem;
|
|
146
146
|
|
|
147
|
-
/** @deprecated This type is no longer relevant. */
|
|
148
|
-
export type AnimatedStyleProp<T> =
|
|
149
|
-
| AnimatedStyle<T>
|
|
150
|
-
| RegisteredStyle<AnimatedStyle<T>>;
|
|
151
|
-
|
|
152
147
|
/** @deprecated Please use {@link AnimatedProps} type instead. */
|
|
153
148
|
export type AnimateProps<Props extends object> = AnimatedProps<Props>;
|
package/src/hook/commonTypes.ts
CHANGED
|
@@ -27,13 +27,18 @@ export interface Descriptor {
|
|
|
27
27
|
shadowNodeWrapper: ShadowNodeWrapper;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
export type MaybeObserverCleanup = (() => void) | undefined;
|
|
31
|
+
|
|
32
|
+
export type AnimatedRefObserver = (tag: number | null) => MaybeObserverCleanup;
|
|
33
|
+
|
|
30
34
|
export interface AnimatedRef<T extends Component> {
|
|
31
35
|
(component?: T):
|
|
32
36
|
| number // Paper
|
|
33
37
|
| ShadowNodeWrapper // Fabric
|
|
34
38
|
| HTMLElement; // web
|
|
35
39
|
current: T | null;
|
|
36
|
-
|
|
40
|
+
observe: (observer: AnimatedRefObserver) => void;
|
|
41
|
+
getTag?: () => number | null;
|
|
37
42
|
}
|
|
38
43
|
|
|
39
44
|
// Might make that type generic if it's ever needed.
|
|
@@ -44,10 +49,10 @@ export type AnimatedRefOnUI = {
|
|
|
44
49
|
(): number | ShadowNodeWrapper | null;
|
|
45
50
|
/**
|
|
46
51
|
* @remarks
|
|
47
|
-
* `viewName` is required only on iOS with Paper and
|
|
48
|
-
* other platforms
|
|
52
|
+
* `viewName` is required only on iOS/macOS with Paper and is undefined on
|
|
53
|
+
* other platforms
|
|
49
54
|
*/
|
|
50
|
-
viewName
|
|
55
|
+
viewName?: SharedValue<string | null>;
|
|
51
56
|
};
|
|
52
57
|
|
|
53
58
|
type ReanimatedPayload = {
|
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
import type { Component } from 'react';
|
|
3
|
-
import { useRef } from 'react';
|
|
3
|
+
import { useRef, useState } from 'react';
|
|
4
4
|
import type { FlatList, ScrollView } from 'react-native';
|
|
5
|
-
import { Platform } from 'react-native';
|
|
6
5
|
|
|
7
6
|
import type { ShadowNodeWrapper } from '../commonTypes';
|
|
8
7
|
import { getShadowNodeWrapperFromRef } from '../fabricUtils';
|
|
9
|
-
import {
|
|
8
|
+
import { makeMutable } from '../mutables';
|
|
9
|
+
import { isFabric, isIOS, isMacOS, shouldBeUseWeb } from '../PlatformChecker';
|
|
10
10
|
import { findNodeHandle } from '../platformFunctions/findNodeHandle';
|
|
11
11
|
import { shareableMappingCache } from '../shareableMappingCache';
|
|
12
12
|
import { makeShareableCloneRecursive } from '../shareables';
|
|
13
|
-
import type {
|
|
14
|
-
|
|
13
|
+
import type {
|
|
14
|
+
AnimatedRef,
|
|
15
|
+
AnimatedRefObserver,
|
|
16
|
+
AnimatedRefOnUI,
|
|
17
|
+
MaybeObserverCleanup,
|
|
18
|
+
} from './commonTypes';
|
|
15
19
|
|
|
16
|
-
const
|
|
20
|
+
const SHOULD_BE_USE_WEB = shouldBeUseWeb();
|
|
17
21
|
|
|
18
22
|
interface MaybeScrollableComponent extends Component {
|
|
19
23
|
getNativeScrollRef?: FlatList['getNativeScrollRef'];
|
|
@@ -26,26 +30,22 @@ interface MaybeScrollableComponent extends Component {
|
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
function getComponentOrScrollable(component: MaybeScrollableComponent) {
|
|
29
|
-
if (
|
|
33
|
+
if (component.getNativeScrollRef) {
|
|
30
34
|
return component.getNativeScrollRef();
|
|
31
|
-
}
|
|
35
|
+
}
|
|
36
|
+
if (component.getScrollableNode) {
|
|
32
37
|
return component.getScrollableNode();
|
|
33
38
|
}
|
|
34
39
|
return component;
|
|
35
40
|
}
|
|
36
41
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
export function useAnimatedRef<
|
|
45
|
-
TComponent extends Component,
|
|
46
|
-
>(): AnimatedRef<TComponent> {
|
|
47
|
-
const tag = useSharedValue<number | ShadowNodeWrapper | null>(-1);
|
|
48
|
-
const viewName = useSharedValue<string | null>(null);
|
|
42
|
+
function useAnimatedRefBase<TComponent extends Component>(
|
|
43
|
+
getWrapper: (component: TComponent) => ShadowNodeWrapper | number | null
|
|
44
|
+
): AnimatedRef<TComponent> {
|
|
45
|
+
const observers = useRef<Map<AnimatedRefObserver, MaybeObserverCleanup>>(
|
|
46
|
+
new Map()
|
|
47
|
+
).current;
|
|
48
|
+
const tagOrWrapperRef = useRef<ShadowNodeWrapper | number | null>(-1);
|
|
49
49
|
|
|
50
50
|
const ref = useRef<AnimatedRef<TComponent> | null>(null);
|
|
51
51
|
|
|
@@ -53,49 +53,108 @@ export function useAnimatedRef<
|
|
|
53
53
|
const fun: AnimatedRef<TComponent> = <AnimatedRef<TComponent>>((
|
|
54
54
|
component
|
|
55
55
|
) => {
|
|
56
|
-
// enters when ref is set by attaching to a component
|
|
57
56
|
if (component) {
|
|
58
|
-
|
|
59
|
-
? getShadowNodeWrapperFromRef
|
|
60
|
-
: findNodeHandle;
|
|
61
|
-
|
|
62
|
-
const getTagOrShadowNodeWrapper = () => {
|
|
63
|
-
return IS_WEB
|
|
64
|
-
? getComponentOrScrollable(component)
|
|
65
|
-
: getTagValueFunction(getComponentOrScrollable(component));
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
tag.value = getTagOrShadowNodeWrapper();
|
|
69
|
-
|
|
70
|
-
// On Fabric we have to unwrap the tag from the shadow node wrapper
|
|
71
|
-
fun.getTag = isFabric()
|
|
72
|
-
? () => findNodeHandle(getComponentOrScrollable(component))
|
|
73
|
-
: getTagOrShadowNodeWrapper;
|
|
57
|
+
tagOrWrapperRef.current = getWrapper(component);
|
|
74
58
|
|
|
59
|
+
// We have to unwrap the tag from the shadow node wrapper.
|
|
60
|
+
fun.getTag = () => findNodeHandle(getComponentOrScrollable(component));
|
|
75
61
|
fun.current = component;
|
|
76
|
-
|
|
77
|
-
if (
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
62
|
+
|
|
63
|
+
if (observers.size) {
|
|
64
|
+
const currentTag = fun?.getTag?.() ?? null;
|
|
65
|
+
observers.forEach((cleanup, observer) => {
|
|
66
|
+
// Perform the cleanup before calling the observer again.
|
|
67
|
+
// This ensures that all events that were set up in the observer
|
|
68
|
+
// are cleaned up before the observer sets up new events during
|
|
69
|
+
// the next call.
|
|
70
|
+
cleanup?.();
|
|
71
|
+
observers.set(observer, observer(currentTag));
|
|
72
|
+
});
|
|
81
73
|
}
|
|
82
74
|
}
|
|
83
|
-
|
|
75
|
+
|
|
76
|
+
return tagOrWrapperRef.current;
|
|
84
77
|
});
|
|
85
78
|
|
|
79
|
+
fun.observe = (observer: AnimatedRefObserver) => {
|
|
80
|
+
// Call observer immediately to get the initial value
|
|
81
|
+
const cleanup = observer(fun?.getTag?.() ?? null);
|
|
82
|
+
observers.set(observer, cleanup);
|
|
83
|
+
|
|
84
|
+
return () => {
|
|
85
|
+
observers.get(observer)?.();
|
|
86
|
+
observers.delete(observer);
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
|
|
86
90
|
fun.current = null;
|
|
91
|
+
ref.current = fun;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return ref.current;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const IS_APPLE = isIOS() || isMacOS();
|
|
87
98
|
|
|
99
|
+
function useAnimatedRefNative<
|
|
100
|
+
TComponent extends Component,
|
|
101
|
+
>(): AnimatedRef<TComponent> {
|
|
102
|
+
const [viewName] = useState(() =>
|
|
103
|
+
// viewName is required only on iOS/MacOS with Paper
|
|
104
|
+
!isFabric() && IS_APPLE ? makeMutable<string | null>(null) : null
|
|
105
|
+
);
|
|
106
|
+
const [tagOrWrapper] = useState(() =>
|
|
107
|
+
makeMutable<ShadowNodeWrapper | number | null>(null)
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
const ref = useAnimatedRefBase<TComponent>((component) => {
|
|
111
|
+
const getTagOrWrapper = isFabric()
|
|
112
|
+
? getShadowNodeWrapperFromRef
|
|
113
|
+
: findNodeHandle;
|
|
114
|
+
|
|
115
|
+
tagOrWrapper.value = getTagOrWrapper(getComponentOrScrollable(component));
|
|
116
|
+
|
|
117
|
+
if (viewName) {
|
|
118
|
+
viewName.value =
|
|
119
|
+
(component as MaybeScrollableComponent)?.viewConfig?.uiViewClassName ||
|
|
120
|
+
'RCTView';
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return tagOrWrapper.value;
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
if (!shareableMappingCache.get(ref)) {
|
|
88
127
|
const animatedRefShareableHandle = makeShareableCloneRecursive({
|
|
89
128
|
__init: () => {
|
|
90
129
|
'worklet';
|
|
91
|
-
const f: AnimatedRefOnUI = () =>
|
|
92
|
-
|
|
130
|
+
const f: AnimatedRefOnUI = () => tagOrWrapper.value;
|
|
131
|
+
if (viewName) {
|
|
132
|
+
f.viewName = viewName;
|
|
133
|
+
}
|
|
93
134
|
return f;
|
|
94
135
|
},
|
|
95
136
|
});
|
|
96
|
-
shareableMappingCache.set(
|
|
97
|
-
ref.current = fun;
|
|
137
|
+
shareableMappingCache.set(ref, animatedRefShareableHandle);
|
|
98
138
|
}
|
|
99
139
|
|
|
100
|
-
return ref
|
|
140
|
+
return ref;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function useAnimatedRefWeb<
|
|
144
|
+
TComponent extends Component,
|
|
145
|
+
>(): AnimatedRef<TComponent> {
|
|
146
|
+
return useAnimatedRefBase<TComponent>((component) =>
|
|
147
|
+
getComponentOrScrollable(component)
|
|
148
|
+
);
|
|
101
149
|
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Lets you get a reference of a view that you can use inside a worklet.
|
|
153
|
+
*
|
|
154
|
+
* @returns An object with a `.current` property which contains an instance of a
|
|
155
|
+
* component.
|
|
156
|
+
* @see https://docs.swmansion.com/react-native-reanimated/docs/core/useAnimatedRef
|
|
157
|
+
*/
|
|
158
|
+
export const useAnimatedRef = SHOULD_BE_USE_WEB
|
|
159
|
+
? useAnimatedRefWeb
|
|
160
|
+
: useAnimatedRefNative;
|
package/src/hook/useHandler.ts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import { useEffect, useRef } from 'react';
|
|
3
3
|
|
|
4
4
|
import type { WorkletFunction } from '../commonTypes';
|
|
5
|
+
import { isWorkletFunction } from '../commonTypes';
|
|
6
|
+
import { ReanimatedError } from '../errors';
|
|
5
7
|
import { isJest, isWeb } from '../PlatformChecker';
|
|
6
8
|
import { makeShareable } from '../shareables';
|
|
7
9
|
import type { DependencyList, ReanimatedEvent } from './commonTypes';
|
|
@@ -83,6 +85,14 @@ export function useHandler<
|
|
|
83
85
|
|
|
84
86
|
const { context, savedDependencies } = initRef.current;
|
|
85
87
|
|
|
88
|
+
for (const handlerName in handlers) {
|
|
89
|
+
if (!isWorkletFunction(handlers[handlerName])) {
|
|
90
|
+
throw new ReanimatedError(
|
|
91
|
+
'Passed a function that is not a worklet. Please provide a worklet function.'
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
86
96
|
dependencies = buildDependencies(
|
|
87
97
|
dependencies,
|
|
88
98
|
handlers as Record<string, WorkletFunction | undefined>
|
|
@@ -3,6 +3,7 @@ import { useCallback, useEffect, useRef } from 'react';
|
|
|
3
3
|
|
|
4
4
|
import type { SharedValue } from '../commonTypes';
|
|
5
5
|
import type { AnimatedScrollView } from '../component/ScrollView';
|
|
6
|
+
import { logger } from '../logger';
|
|
6
7
|
import { isWeb } from '../PlatformChecker';
|
|
7
8
|
import type {
|
|
8
9
|
AnimatedRef,
|
|
@@ -15,6 +16,9 @@ import { useSharedValue } from './useSharedValue';
|
|
|
15
16
|
|
|
16
17
|
const IS_WEB = isWeb();
|
|
17
18
|
|
|
19
|
+
const NOT_INITIALIZED_WARNING =
|
|
20
|
+
'animatedRef is not initialized in useScrollViewOffset. Make sure to pass the animated ref to the scrollable component to get scroll offset updates.';
|
|
21
|
+
|
|
18
22
|
/**
|
|
19
23
|
* Lets you synchronously get the current offset of a `ScrollView`.
|
|
20
24
|
*
|
|
@@ -43,27 +47,27 @@ function useScrollViewOffsetWeb(
|
|
|
43
47
|
offset.value =
|
|
44
48
|
element.scrollLeft === 0 ? element.scrollTop : element.scrollLeft;
|
|
45
49
|
}
|
|
46
|
-
|
|
47
|
-
}, [animatedRef, animatedRef?.current]);
|
|
50
|
+
}, [animatedRef, offset]);
|
|
48
51
|
|
|
49
52
|
useEffect(() => {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
if (!animatedRef) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return animatedRef.observe((tag) => {
|
|
58
|
+
if (!tag) {
|
|
59
|
+
logger.warn(NOT_INITIALIZED_WARNING);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
53
62
|
|
|
54
|
-
|
|
63
|
+
const element = getWebScrollableElement(animatedRef.current);
|
|
55
64
|
element.addEventListener('scroll', eventHandler);
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
if (element) {
|
|
65
|
+
|
|
66
|
+
return () => {
|
|
59
67
|
element.removeEventListener('scroll', eventHandler);
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
// field shouldn't be used as a dependency. However, in this case we have
|
|
64
|
-
// to do it this way.
|
|
65
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
66
|
-
}, [animatedRef, animatedRef?.current, eventHandler]);
|
|
68
|
+
};
|
|
69
|
+
});
|
|
70
|
+
}, [animatedRef, eventHandler]);
|
|
67
71
|
|
|
68
72
|
return offset;
|
|
69
73
|
}
|
|
@@ -89,21 +93,22 @@ function useScrollViewOffsetNative(
|
|
|
89
93
|
) as unknown as EventHandlerInternal<ReanimatedScrollEvent>;
|
|
90
94
|
|
|
91
95
|
useEffect(() => {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if (elementTag) {
|
|
95
|
-
eventHandler.workletEventHandler.registerForEvents(elementTag);
|
|
96
|
+
if (!animatedRef) {
|
|
97
|
+
return;
|
|
96
98
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
99
|
+
|
|
100
|
+
return animatedRef.observe((tag) => {
|
|
101
|
+
if (!tag) {
|
|
102
|
+
logger.warn(NOT_INITIALIZED_WARNING);
|
|
103
|
+
return;
|
|
100
104
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
|
|
106
|
+
eventHandler.workletEventHandler.registerForEvents(tag);
|
|
107
|
+
return () => {
|
|
108
|
+
eventHandler.workletEventHandler.unregisterFromEvents(tag);
|
|
109
|
+
};
|
|
110
|
+
});
|
|
111
|
+
}, [animatedRef, eventHandler]);
|
|
107
112
|
|
|
108
113
|
return offset;
|
|
109
114
|
}
|
package/src/hook/utils.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
import type { WorkletFunction } from '../commonTypes';
|
|
3
|
+
import { isWorkletFunction } from '../commonTypes';
|
|
3
4
|
import { ReanimatedError } from '../errors';
|
|
4
5
|
import type { DependencyList } from './commonTypes';
|
|
5
6
|
|
|
@@ -27,19 +28,34 @@ export function buildDependencies(
|
|
|
27
28
|
(handler) => handler !== undefined
|
|
28
29
|
) as NonNullable<Handler>[];
|
|
29
30
|
if (!dependencies) {
|
|
30
|
-
|
|
31
|
-
return {
|
|
32
|
-
workletHash: handler.__workletHash,
|
|
33
|
-
closure: handler.__closure,
|
|
34
|
-
};
|
|
35
|
-
});
|
|
36
|
-
} else {
|
|
37
|
-
dependencies.push(buildWorkletsHash(handlersList));
|
|
31
|
+
return handlersList;
|
|
38
32
|
}
|
|
39
33
|
|
|
34
|
+
dependencies.push(buildWorkletsHash(handlersList));
|
|
40
35
|
return dependencies;
|
|
41
36
|
}
|
|
42
37
|
|
|
38
|
+
function areWorkletsEqual(
|
|
39
|
+
worklet1: WorkletFunction,
|
|
40
|
+
worklet2: WorkletFunction
|
|
41
|
+
) {
|
|
42
|
+
if (worklet1.__workletHash === worklet2.__workletHash) {
|
|
43
|
+
const closure1Keys = Object.keys(worklet1.__closure);
|
|
44
|
+
const closure2Keys = Object.keys(worklet2.__closure);
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
closure1Keys.length === closure2Keys.length &&
|
|
48
|
+
closure1Keys.every(
|
|
49
|
+
(key) =>
|
|
50
|
+
key in worklet2.__closure &&
|
|
51
|
+
worklet1.__closure[key] === worklet2.__closure[key]
|
|
52
|
+
)
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
|
|
43
59
|
// This is supposed to work as useEffect comparison.
|
|
44
60
|
export function areDependenciesEqual(
|
|
45
61
|
nextDependencies: DependencyList,
|
|
@@ -61,8 +77,17 @@ export function areDependenciesEqual(
|
|
|
61
77
|
if (!nextDeps || !prevDeps || prevDeps.length !== nextDeps.length) {
|
|
62
78
|
return false;
|
|
63
79
|
}
|
|
80
|
+
|
|
64
81
|
for (let i = 0; i < prevDeps.length; ++i) {
|
|
65
|
-
|
|
82
|
+
const nextDep = nextDeps[i];
|
|
83
|
+
const prevDep = prevDeps[i];
|
|
84
|
+
if (objectIs(nextDep, prevDep)) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (!isWorkletFunction(nextDep) || !isWorkletFunction(prevDep)) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
if (!areWorkletsEqual(nextDep, prevDep)) {
|
|
66
91
|
return false;
|
|
67
92
|
}
|
|
68
93
|
}
|