@office-iss/react-native-win32 0.75.2 → 0.76.0-preview.1

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.
Files changed (174) hide show
  1. package/.eslintrc.js +11 -0
  2. package/.flowconfig +5 -4
  3. package/CHANGELOG.json +164 -47
  4. package/CHANGELOG.md +53 -28
  5. package/Libraries/Alert/Alert.js +3 -0
  6. package/Libraries/Animated/AnimatedEvent.js +1 -1
  7. package/Libraries/Animated/AnimatedImplementation.js +7 -7
  8. package/Libraries/Animated/NativeAnimatedAllowlist.js +111 -0
  9. package/Libraries/Animated/animations/Animation.js +11 -1
  10. package/Libraries/Animated/animations/DecayAnimation.js +1 -1
  11. package/Libraries/Animated/animations/SpringAnimation.js +1 -1
  12. package/Libraries/Animated/animations/TimingAnimation.js +2 -1
  13. package/Libraries/Animated/components/AnimatedScrollView.js +3 -2
  14. package/Libraries/Animated/createAnimatedComponent.js +10 -9
  15. package/Libraries/Animated/nodes/AnimatedColor.js +1 -1
  16. package/Libraries/Animated/nodes/AnimatedInterpolation.js +3 -2
  17. package/Libraries/Animated/nodes/AnimatedNode.js +42 -33
  18. package/Libraries/Animated/nodes/AnimatedObject.js +56 -50
  19. package/Libraries/Animated/nodes/AnimatedProps.js +77 -40
  20. package/Libraries/Animated/nodes/AnimatedStyle.js +103 -59
  21. package/Libraries/Animated/nodes/AnimatedTracking.js +1 -1
  22. package/Libraries/Animated/nodes/AnimatedTransform.js +102 -67
  23. package/Libraries/Animated/nodes/AnimatedValue.js +2 -1
  24. package/Libraries/Animated/nodes/AnimatedWithChildren.js +21 -22
  25. package/Libraries/Animated/useAnimatedProps.js +142 -7
  26. package/Libraries/BatchedBridge/NativeModules.js +2 -0
  27. package/Libraries/Blob/FileReader.js +1 -1
  28. package/Libraries/Blob/URL.js +2 -62
  29. package/Libraries/Blob/URLSearchParams.js +71 -0
  30. package/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js +1 -1
  31. package/Libraries/Components/RefreshControl/__mocks__/RefreshControlMock.js +1 -1
  32. package/Libraries/Components/ScrollView/ScrollView.js +131 -169
  33. package/Libraries/Components/ScrollView/ScrollViewStickyHeader.js +1 -1
  34. package/Libraries/Components/StatusBar/StatusBar.js +3 -1
  35. package/Libraries/Components/TextInput/TextInput.d.ts +32 -2
  36. package/Libraries/Components/TextInput/TextInput.js +230 -94
  37. package/Libraries/Components/TextInput/TextInput.win32.js +230 -100
  38. package/Libraries/Components/View/ReactNativeStyleAttributes.js +22 -0
  39. package/Libraries/Components/View/ReactNativeViewAttributes.js +2 -0
  40. package/Libraries/Components/View/ReactNativeViewAttributes.win32.js +2 -0
  41. package/Libraries/Components/View/ViewAccessibility.d.ts +15 -0
  42. package/Libraries/Components/View/ViewNativeComponent.js +0 -1
  43. package/Libraries/Components/View/ViewPropTypes.js +14 -0
  44. package/Libraries/Components/View/ViewPropTypes.win32.js +14 -0
  45. package/Libraries/Core/ExceptionsManager.js +2 -0
  46. package/Libraries/Core/InitializeCore.js +3 -1
  47. package/Libraries/Core/ReactFiberErrorDialog.js +3 -0
  48. package/Libraries/Core/ReactNativeVersion.js +4 -4
  49. package/Libraries/Core/ReactNativeVersionCheck.win32.js +1 -1
  50. package/Libraries/Core/setUpErrorHandling.js +7 -1
  51. package/Libraries/Core/setUpGlobals.js +1 -0
  52. package/Libraries/Core/setUpReactRefresh.js +0 -4
  53. package/Libraries/Image/AssetSourceResolver.js +28 -1
  54. package/Libraries/Image/Image.android.js +9 -14
  55. package/Libraries/Image/Image.ios.js +11 -22
  56. package/Libraries/Image/Image.win32.js +11 -24
  57. package/Libraries/Image/ImageBackground.js +1 -8
  58. package/Libraries/Image/ImageUtils.js +9 -9
  59. package/Libraries/Image/ImageViewNativeComponent.js +1 -0
  60. package/Libraries/Inspector/Inspector.js +3 -2
  61. package/Libraries/Inspector/Inspector.win32.js +3 -2
  62. package/Libraries/Inspector/InspectorPanel.js +16 -10
  63. package/Libraries/Inspector/NetworkOverlay.js +1 -1
  64. package/Libraries/Interaction/TaskQueue.js +1 -0
  65. package/Libraries/Lists/FlatList.js +1 -1
  66. package/Libraries/Lists/SectionList.js +2 -2
  67. package/Libraries/Lists/SectionListModern.js +3 -3
  68. package/Libraries/LogBox/Data/LogBoxData.js +24 -3
  69. package/Libraries/LogBox/LogBoxNotificationContainer.js +3 -2
  70. package/Libraries/LogBox/UI/LogBoxInspectorHeader.js +9 -8
  71. package/Libraries/LogBox/UI/LogBoxInspectorHeader.win32.js +9 -29
  72. package/Libraries/Modal/Modal.js +0 -1
  73. package/Libraries/NativeComponent/BaseViewConfig.android.js +8 -0
  74. package/Libraries/NativeComponent/BaseViewConfig.ios.js +7 -0
  75. package/Libraries/NativeComponent/BaseViewConfig.win32.js +7 -0
  76. package/Libraries/NativeComponent/NativeComponentRegistry.js +22 -22
  77. package/Libraries/NativeComponent/StaticViewConfigValidator.js +0 -21
  78. package/Libraries/Network/XMLHttpRequest.js +4 -2
  79. package/Libraries/ReactNative/AppContainer-dev.js +1 -5
  80. package/Libraries/ReactNative/AppContainer-prod.js +1 -5
  81. package/Libraries/ReactNative/AppContainer.js +0 -1
  82. package/Libraries/ReactNative/AppRegistry.js +0 -6
  83. package/Libraries/ReactNative/BridgelessUIManager.js +1 -0
  84. package/Libraries/ReactNative/ReactFabricPublicInstance/ReactFabricHostComponent.js +1 -1
  85. package/Libraries/ReactNative/ReactFabricPublicInstance/ReactFabricPublicInstance.js +5 -5
  86. package/Libraries/ReactNative/RendererImplementation.js +26 -4
  87. package/Libraries/ReactNative/getNativeComponentAttributes.js +8 -0
  88. package/Libraries/ReactNative/renderApplication.js +0 -2
  89. package/Libraries/Renderer/shims/ReactNativeTypes.js +11 -4
  90. package/Libraries/StyleSheet/StyleSheet.js +1 -1
  91. package/Libraries/StyleSheet/StyleSheet.win32.js +1 -1
  92. package/Libraries/StyleSheet/StyleSheetTypes.d.ts +57 -0
  93. package/Libraries/StyleSheet/StyleSheetTypes.js +60 -5
  94. package/Libraries/StyleSheet/processBackgroundImage.js +384 -0
  95. package/Libraries/StyleSheet/processBoxShadow.js +211 -0
  96. package/Libraries/StyleSheet/processFilter.js +231 -42
  97. package/Libraries/Text/Text.js +394 -196
  98. package/Libraries/Text/Text.win32.js +442 -229
  99. package/Libraries/Text/TextNativeComponent.js +2 -1
  100. package/Libraries/Text/TextNativeComponent.win32.js +1 -1
  101. package/Libraries/TurboModule/TurboModuleRegistry.js +13 -50
  102. package/Libraries/Types/CodegenTypes.js +3 -1
  103. package/Libraries/Utilities/Appearance.js +108 -84
  104. package/Libraries/Utilities/DevLoadingView.js +2 -4
  105. package/Libraries/Utilities/HMRClient.js +2 -1
  106. package/Libraries/Utilities/ReactNativeTestTools.js +1 -1
  107. package/Libraries/Utilities/createPerformanceLogger.js +0 -9
  108. package/Libraries/Utilities/stringifyViewConfig.js +22 -0
  109. package/Libraries/Utilities/useColorScheme.js +3 -3
  110. package/Libraries/WebSocket/WebSocket.js +1 -1
  111. package/Libraries/promiseRejectionTrackingOptions.js +1 -1
  112. package/Libraries/vendor/emitter/EventEmitter.js +6 -5
  113. package/flow/jest.js +2 -2
  114. package/index.js +3 -1
  115. package/index.win32.js +3 -1
  116. package/jest/mockComponent.js +4 -1
  117. package/jest/mockModal.js +1 -3
  118. package/jest/mockScrollView.js +1 -1
  119. package/jest/renderer.js +2 -2
  120. package/jest/setup.js +16 -13
  121. package/jest.config.js +1 -2
  122. package/overrides.json +22 -22
  123. package/package.json +30 -30
  124. package/src/private/animated/NativeAnimatedHelper.js +438 -0
  125. package/src/private/animated/NativeAnimatedHelper.win32.js +440 -0
  126. package/src/private/animated/NativeAnimatedValidation.js +64 -0
  127. package/src/private/components/HScrollViewNativeComponents.js +56 -0
  128. package/src/private/components/SafeAreaView_INTERNAL_DO_NOT_USE.js +27 -0
  129. package/src/private/components/VScrollViewNativeComponents.js +48 -0
  130. package/src/private/components/useSyncOnScroll.js +48 -0
  131. package/src/private/featureflags/ReactNativeFeatureFlags.js +166 -16
  132. package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +29 -5
  133. package/src/private/fusebox/FuseboxSessionObserver.js +42 -0
  134. package/{Libraries/Core → src/private/renderer/errorhandling}/ErrorHandlers.js +14 -4
  135. package/src/private/setup/setUpDOM.js +28 -0
  136. package/src/private/setup/setUpIntersectionObserver.js +27 -0
  137. package/src/private/setup/setUpMutationObserver.js +26 -0
  138. package/src/private/setup/setUpPerformanceObserver.js +64 -0
  139. package/src/private/specs/modules/NativeAppearance.js +3 -3
  140. package/src/private/specs/modules/NativeLinkingManager.js +1 -1
  141. package/src/private/specs/modules/NativePlatformConstantsWin.js +7 -0
  142. package/src/private/specs/modules/NativeSampleTurboModule.js +14 -1
  143. package/src/private/webapis/dom/nodes/ReadOnlyNode.js +6 -4
  144. package/{Libraries/IntersectionObserver → src/private/webapis/intersectionobserver}/IntersectionObserver.js +5 -3
  145. package/{Libraries/IntersectionObserver → src/private/webapis/intersectionobserver}/IntersectionObserverEntry.js +3 -3
  146. package/{Libraries/IntersectionObserver → src/private/webapis/intersectionobserver}/IntersectionObserverManager.js +14 -17
  147. package/src/private/{specs/modules → webapis/intersectionobserver/specs}/NativeIntersectionObserver.js +2 -2
  148. package/{Libraries/IntersectionObserver → src/private/webapis/intersectionobserver/specs}/__mocks__/NativeIntersectionObserver.js +4 -4
  149. package/{Libraries/MutationObserver → src/private/webapis/mutationobserver}/MutationObserver.js +5 -3
  150. package/{Libraries/MutationObserver → src/private/webapis/mutationobserver}/MutationObserverManager.js +24 -15
  151. package/{Libraries/MutationObserver → src/private/webapis/mutationobserver}/MutationRecord.js +4 -6
  152. package/src/private/{specs/modules → webapis/mutationobserver/specs}/NativeMutationObserver.js +2 -2
  153. package/{Libraries/MutationObserver → src/private/webapis/mutationobserver/specs}/__mocks__/NativeMutationObserver.js +5 -5
  154. package/src/private/webapis/performance/{EventCounts.js → EventTiming.js} +65 -3
  155. package/src/private/webapis/performance/LongTasks.js +39 -0
  156. package/src/private/webapis/performance/Performance.js +22 -9
  157. package/src/private/webapis/performance/PerformanceEntry.js +36 -18
  158. package/src/private/webapis/performance/PerformanceObserver.js +29 -43
  159. package/src/private/webapis/performance/RawPerformanceEntry.js +24 -1
  160. package/src/private/webapis/performance/UserTiming.js +17 -12
  161. package/src/private/webapis/performance/specs/NativePerformanceObserver.js +1 -1
  162. package/src-win/Libraries/Components/View/ViewAccessibility.d.ts +15 -0
  163. package/types/experimental.d.ts +20 -1
  164. package/Libraries/Animated/NativeAnimatedHelper.js +0 -615
  165. package/Libraries/Animated/NativeAnimatedHelper.win32.js +0 -617
  166. package/Libraries/Core/setUpIntersectionObserver.js +0 -16
  167. package/Libraries/Core/setUpMutationObserver.js +0 -16
  168. package/Libraries/Core/setUpPerformanceObserver.js +0 -18
  169. package/Libraries/IntersectionObserver/NativeIntersectionObserver.js +0 -13
  170. package/Libraries/MutationObserver/NativeMutationObserver.js +0 -13
  171. package/Libraries/Utilities/verifyComponentAttributeEquivalence.js +0 -135
  172. package/src/private/core/setUpDOM.js +0 -18
  173. package/src/private/webapis/performance/PerformanceEventTiming.js +0 -55
  174. /package/src/private/{core → styles}/composeStyles.js +0 -0
@@ -14,7 +14,8 @@ import type {PlatformConfig} from '../AnimatedPlatformConfig';
14
14
  import type AnimatedNode from '../nodes/AnimatedNode';
15
15
  import type AnimatedValue from '../nodes/AnimatedValue';
16
16
 
17
- import NativeAnimatedHelper from '../NativeAnimatedHelper';
17
+ import * as ReactNativeFeatureFlags from '../../../src/private/featureflags/ReactNativeFeatureFlags';
18
+ import NativeAnimatedHelper from '../../../src/private/animated/NativeAnimatedHelper';
18
19
  import AnimatedProps from '../nodes/AnimatedProps';
19
20
 
20
21
  export type EndResult = {finished: boolean, value?: number, ...};
@@ -26,6 +27,7 @@ export type AnimationConfig = {
26
27
  platformConfig?: PlatformConfig,
27
28
  onComplete?: ?EndCallback,
28
29
  iterations?: number,
30
+ isLooping?: boolean,
29
31
  };
30
32
 
31
33
  let startNativeAnimationNextId = 1;
@@ -38,6 +40,7 @@ export default class Animation {
38
40
  __isInteraction: boolean;
39
41
  __onEnd: ?EndCallback;
40
42
  __iterations: number;
43
+ __isLooping: ?boolean;
41
44
 
42
45
  _nativeId: number;
43
46
 
@@ -107,6 +110,13 @@ export default class Animation {
107
110
  if (value != null) {
108
111
  animatedValue.__onAnimatedValueUpdateReceived(value);
109
112
 
113
+ if (
114
+ ReactNativeFeatureFlags.shouldSkipStateUpdatesForLoopingAnimations() &&
115
+ this.__isLooping
116
+ ) {
117
+ return;
118
+ }
119
+
110
120
  // Once the JS side node is synced with the updated values, trigger an
111
121
  // update on the AnimatedProps nodes to call any registered callbacks.
112
122
  this.__findAnimatedPropsNodes(animatedValue).forEach(node =>
@@ -14,7 +14,7 @@ import type {PlatformConfig} from '../AnimatedPlatformConfig';
14
14
  import type AnimatedValue from '../nodes/AnimatedValue';
15
15
  import type {AnimationConfig, EndCallback} from './Animation';
16
16
 
17
- import NativeAnimatedHelper from '../NativeAnimatedHelper';
17
+ import NativeAnimatedHelper from '../../../src/private/animated/NativeAnimatedHelper';
18
18
  import Animation from './Animation';
19
19
 
20
20
  export type DecayAnimationConfig = {
@@ -16,7 +16,7 @@ import type AnimatedValue from '../nodes/AnimatedValue';
16
16
  import type AnimatedValueXY from '../nodes/AnimatedValueXY';
17
17
  import type {AnimationConfig, EndCallback} from './Animation';
18
18
 
19
- import NativeAnimatedHelper from '../NativeAnimatedHelper';
19
+ import NativeAnimatedHelper from '../../../src/private/animated/NativeAnimatedHelper';
20
20
  import AnimatedColor from '../nodes/AnimatedColor';
21
21
  import * as SpringConfig from '../SpringConfig';
22
22
  import Animation from './Animation';
@@ -17,7 +17,7 @@ import type AnimatedValue from '../nodes/AnimatedValue';
17
17
  import type AnimatedValueXY from '../nodes/AnimatedValueXY';
18
18
  import type {AnimationConfig, EndCallback} from './Animation';
19
19
 
20
- import NativeAnimatedHelper from '../NativeAnimatedHelper';
20
+ import NativeAnimatedHelper from '../../../src/private/animated/NativeAnimatedHelper';
21
21
  import AnimatedColor from '../nodes/AnimatedColor';
22
22
  import Animation from './Animation';
23
23
 
@@ -80,6 +80,7 @@ export default class TimingAnimation extends Animation {
80
80
  this._useNativeDriver = NativeAnimatedHelper.shouldUseNativeDriver(config);
81
81
  this._platformConfig = config.platformConfig;
82
82
  this.__isInteraction = config.isInteraction ?? !this._useNativeDriver;
83
+ this.__isLooping = config.isLooping;
83
84
  }
84
85
 
85
86
  __getNativeAnimationConfig(): any {
@@ -46,6 +46,7 @@ const AnimatedScrollView: AnimatedComponentType<Props, Instance> =
46
46
  props.style != null
47
47
  ) {
48
48
  return (
49
+ // $FlowFixMe[prop-missing]
49
50
  <AnimatedScrollViewWithInvertedRefreshControl
50
51
  scrollEventThrottle={0.0001}
51
52
  {...props}
@@ -71,7 +72,7 @@ const AnimatedScrollViewWithInvertedRefreshControl = React.forwardRef(
71
72
  props: {
72
73
  ...React.ElementConfig<typeof ScrollView>,
73
74
  // $FlowFixMe[unclear-type] Same Flow type as `refreshControl` in ScrollView
74
- refreshControl: React.Element<any>,
75
+ refreshControl: ExactReactElement_DEPRECATED<any>,
75
76
  },
76
77
  forwardedRef:
77
78
  | {current: Instance | null, ...}
@@ -97,7 +98,7 @@ const AnimatedScrollViewWithInvertedRefreshControl = React.forwardRef(
97
98
  >(intermediatePropsForRefreshControl);
98
99
  // NOTE: Assumes that refreshControl.ref` and `refreshControl.style` can be
99
100
  // safely clobbered.
100
- const refreshControl: React.Element<typeof RefreshControl> =
101
+ const refreshControl: ExactReactElement_DEPRECATED<typeof RefreshControl> =
101
102
  React.cloneElement(props.refreshControl, {
102
103
  ...refreshControlAnimatedProps,
103
104
  ref: refreshControlRef,
@@ -8,21 +8,22 @@
8
8
  * @format
9
9
  */
10
10
 
11
- import composeStyles from '../../src/private/core/composeStyles';
11
+ import composeStyles from '../../src/private/styles/composeStyles';
12
12
  import View from '../Components/View/View';
13
13
  import useMergeRefs from '../Utilities/useMergeRefs';
14
14
  import useAnimatedProps from './useAnimatedProps';
15
15
  import * as React from 'react';
16
16
  import {useMemo} from 'react';
17
17
 
18
- // $FlowFixMe[deprecated-type]
19
- export type AnimatedProps<Props: {...}> = $ObjMap<
20
- Props &
21
- $ReadOnly<{
22
- passthroughAnimatedPropExplicitValues?: React.ElementConfig<typeof View>,
23
- }>,
24
- () => any,
25
- >;
18
+ export type AnimatedProps<Props: {...}> = {
19
+ // eslint-disable-next-line no-unused-vars
20
+ +[_K in keyof (Props &
21
+ $ReadOnly<{
22
+ passthroughAnimatedPropExplicitValues?: React.ElementConfig<
23
+ typeof View,
24
+ >,
25
+ }>)]: any,
26
+ };
26
27
 
27
28
  export type AnimatedComponentType<
28
29
  Props: {...},
@@ -17,7 +17,7 @@ import type {PlatformConfig} from '../AnimatedPlatformConfig';
17
17
 
18
18
  import normalizeColor from '../../StyleSheet/normalizeColor';
19
19
  import {processColorObject} from '../../StyleSheet/PlatformColorValueTypes';
20
- import NativeAnimatedHelper from '../NativeAnimatedHelper';
20
+ import NativeAnimatedHelper from '../../../src/private/animated/NativeAnimatedHelper';
21
21
  import AnimatedValue, {flushValue} from './AnimatedValue';
22
22
  import AnimatedWithChildren from './AnimatedWithChildren';
23
23
 
@@ -15,10 +15,11 @@
15
15
  import type {PlatformConfig} from '../AnimatedPlatformConfig';
16
16
  import type AnimatedNode from './AnimatedNode';
17
17
 
18
+ import {validateInterpolation} from '../../../src/private/animated/NativeAnimatedValidation';
18
19
  import normalizeColor from '../../StyleSheet/normalizeColor';
19
20
  import processColor from '../../StyleSheet/processColor';
20
21
  import Easing from '../Easing';
21
- import NativeAnimatedHelper from '../NativeAnimatedHelper';
22
+ import NativeAnimatedHelper from '../../../src/private/animated/NativeAnimatedHelper';
22
23
  import AnimatedWithChildren from './AnimatedWithChildren';
23
24
  import invariant from 'invariant';
24
25
 
@@ -382,7 +383,7 @@ export default class AnimatedInterpolation<
382
383
 
383
384
  __getNativeConfig(): any {
384
385
  if (__DEV__) {
385
- NativeAnimatedHelper.validateInterpolation(this._config);
386
+ validateInterpolation(this._config);
386
387
  }
387
388
 
388
389
  // Only the `outputRange` can contain strings so we don't need to transform `inputRange` here
@@ -10,23 +10,31 @@
10
10
 
11
11
  'use strict';
12
12
 
13
+ import type {EventSubscription} from '../../vendor/emitter/EventEmitter';
13
14
  import type {PlatformConfig} from '../AnimatedPlatformConfig';
14
15
 
15
- import NativeAnimatedHelper from '../NativeAnimatedHelper';
16
+ import NativeAnimatedHelper from '../../../src/private/animated/NativeAnimatedHelper';
16
17
  import invariant from 'invariant';
17
18
 
18
- const NativeAnimatedAPI = NativeAnimatedHelper.API;
19
+ const {startListeningToAnimatedNodeValue, stopListeningToAnimatedNodeValue} =
20
+ NativeAnimatedHelper.API;
19
21
 
20
22
  type ValueListenerCallback = (state: {value: number, ...}) => mixed;
21
23
 
22
24
  let _uniqueId = 1;
25
+ let _assertNativeAnimatedModule: ?() => void = () => {
26
+ NativeAnimatedHelper.assertNativeAnimatedModule();
27
+ // We only have to assert that the module exists once. After we've asserted
28
+ // this, clear out the function so we know to skip it in the future.
29
+ _assertNativeAnimatedModule = null;
30
+ };
23
31
 
24
32
  // Note(vjeux): this would be better as an interface but flow doesn't
25
33
  // support them yet
26
34
  export default class AnimatedNode {
27
- _listeners: {[key: string]: ValueListenerCallback, ...};
28
- _platformConfig: ?PlatformConfig;
29
- __nativeAnimatedValueListener: ?any;
35
+ #listeners: Map<string, ValueListenerCallback> = new Map();
36
+ _platformConfig: ?PlatformConfig = undefined;
37
+ __nativeAnimatedValueListener: ?EventSubscription = null;
30
38
  __attach(): void {}
31
39
  __detach(): void {
32
40
  this.removeAllListeners();
@@ -46,13 +54,9 @@ export default class AnimatedNode {
46
54
  }
47
55
 
48
56
  /* Methods and props used by native Animated impl */
49
- __isNative: boolean;
50
- __nativeTag: ?number;
51
- __shouldUpdateListenersForNewNativeTag: boolean;
52
-
53
- constructor() {
54
- this._listeners = {};
55
- }
57
+ __isNative: boolean = false;
58
+ __nativeTag: ?number = undefined;
59
+ __shouldUpdateListenersForNewNativeTag: boolean = false;
56
60
 
57
61
  __makeNative(platformConfig: ?PlatformConfig): void {
58
62
  if (!this.__isNative) {
@@ -60,7 +64,7 @@ export default class AnimatedNode {
60
64
  }
61
65
 
62
66
  this._platformConfig = platformConfig;
63
- if (this.hasListeners()) {
67
+ if (this.#listeners.size > 0) {
64
68
  this._startListeningToNativeValueUpdates();
65
69
  }
66
70
  }
@@ -74,7 +78,7 @@ export default class AnimatedNode {
74
78
  */
75
79
  addListener(callback: (value: any) => mixed): string {
76
80
  const id = String(_uniqueId++);
77
- this._listeners[id] = callback;
81
+ this.#listeners.set(id, callback);
78
82
  if (this.__isNative) {
79
83
  this._startListeningToNativeValueUpdates();
80
84
  }
@@ -88,8 +92,8 @@ export default class AnimatedNode {
88
92
  * See https://reactnative.dev/docs/animatedvalue#removelistener
89
93
  */
90
94
  removeListener(id: string): void {
91
- delete this._listeners[id];
92
- if (this.__isNative && !this.hasListeners()) {
95
+ this.#listeners.delete(id);
96
+ if (this.__isNative && this.#listeners.size === 0) {
93
97
  this._stopListeningForNativeValueUpdates();
94
98
  }
95
99
  }
@@ -100,14 +104,14 @@ export default class AnimatedNode {
100
104
  * See https://reactnative.dev/docs/animatedvalue#removealllisteners
101
105
  */
102
106
  removeAllListeners(): void {
103
- this._listeners = {};
107
+ this.#listeners.clear();
104
108
  if (this.__isNative) {
105
109
  this._stopListeningForNativeValueUpdates();
106
110
  }
107
111
  }
108
112
 
109
113
  hasListeners(): boolean {
110
- return !!Object.keys(this._listeners).length;
114
+ return this.#listeners.size > 0;
111
115
  }
112
116
 
113
117
  _startListeningToNativeValueUpdates() {
@@ -123,7 +127,7 @@ export default class AnimatedNode {
123
127
  this._stopListeningForNativeValueUpdates();
124
128
  }
125
129
 
126
- NativeAnimatedAPI.startListeningToAnimatedNodeValue(this.__getNativeTag());
130
+ startListeningToAnimatedNodeValue(this.__getNativeTag());
127
131
  this.__nativeAnimatedValueListener =
128
132
  NativeAnimatedHelper.nativeEventEmitter.addListener(
129
133
  'onAnimatedValueUpdate',
@@ -141,9 +145,10 @@ export default class AnimatedNode {
141
145
  }
142
146
 
143
147
  __callListeners(value: number): void {
144
- for (const key in this._listeners) {
145
- this._listeners[key]({value});
146
- }
148
+ const event = {value};
149
+ this.#listeners.forEach(listener => {
150
+ listener(event);
151
+ });
147
152
  }
148
153
 
149
154
  _stopListeningForNativeValueUpdates() {
@@ -153,21 +158,24 @@ export default class AnimatedNode {
153
158
 
154
159
  this.__nativeAnimatedValueListener.remove();
155
160
  this.__nativeAnimatedValueListener = null;
156
- NativeAnimatedAPI.stopListeningToAnimatedNodeValue(this.__getNativeTag());
161
+ stopListeningToAnimatedNodeValue(this.__getNativeTag());
157
162
  }
158
163
 
159
164
  __getNativeTag(): number {
160
- NativeAnimatedHelper.assertNativeAnimatedModule();
161
- invariant(
162
- this.__isNative,
163
- 'Attempt to get native tag from node not marked as "native"',
164
- );
165
-
166
- const nativeTag =
167
- this.__nativeTag ?? NativeAnimatedHelper.generateNewNodeTag();
165
+ let nativeTag = this.__nativeTag;
166
+ if (nativeTag == null) {
167
+ _assertNativeAnimatedModule?.();
168
+
169
+ // `__isNative` is initialized as false and only ever set to true. So we
170
+ // only need to check it once here when initializing `__nativeTag`.
171
+ invariant(
172
+ this.__isNative,
173
+ 'Attempt to get native tag from node not marked as "native"',
174
+ );
168
175
 
169
- if (this.__nativeTag == null) {
176
+ nativeTag = NativeAnimatedHelper.generateNewNodeTag();
170
177
  this.__nativeTag = nativeTag;
178
+
171
179
  const config = this.__getNativeConfig();
172
180
  if (this._platformConfig) {
173
181
  config.platformConfig = this._platformConfig;
@@ -175,9 +183,9 @@ export default class AnimatedNode {
175
183
  NativeAnimatedHelper.API.createAnimatedNode(nativeTag, config);
176
184
  this.__shouldUpdateListenersForNewNativeTag = true;
177
185
  }
178
-
179
186
  return nativeTag;
180
187
  }
188
+
181
189
  __getNativeConfig(): Object {
182
190
  throw new Error(
183
191
  'This JS animated node type cannot be used as native animated node',
@@ -191,6 +199,7 @@ export default class AnimatedNode {
191
199
  __getPlatformConfig(): ?PlatformConfig {
192
200
  return this._platformConfig;
193
201
  }
202
+
194
203
  __setPlatformConfig(platformConfig: ?PlatformConfig) {
195
204
  this._platformConfig = platformConfig;
196
205
  }
@@ -19,31 +19,40 @@ import * as React from 'react';
19
19
 
20
20
  const MAX_DEPTH = 5;
21
21
 
22
- function isPlainObject(value: any): boolean {
22
+ /* $FlowIssue[incompatible-type-guard] - Flow does not know that the prototype
23
+ and ReactElement checks preserve the type refinement of `value`. */
24
+ function isPlainObject(value: mixed): value is $ReadOnly<{[string]: mixed}> {
23
25
  return (
24
26
  value !== null &&
25
27
  typeof value === 'object' &&
26
- Object.getPrototypeOf(value).isPrototypeOf(Object)
28
+ Object.getPrototypeOf(value).isPrototypeOf(Object) &&
29
+ !React.isValidElement(value)
27
30
  );
28
31
  }
29
32
 
30
- // Recurse through values, executing fn for any AnimatedNodes
31
- function visit(value: any, fn: any => void, depth: number = 0): void {
33
+ function flatAnimatedNodes(
34
+ value: mixed,
35
+ nodes: Array<AnimatedNode> = [],
36
+ depth: number = 0,
37
+ ): Array<AnimatedNode> {
32
38
  if (depth >= MAX_DEPTH) {
33
- return;
39
+ return nodes;
34
40
  }
35
-
36
41
  if (value instanceof AnimatedNode) {
37
- fn(value);
42
+ nodes.push(value);
38
43
  } else if (Array.isArray(value)) {
39
- value.forEach(element => {
40
- visit(element, fn, depth + 1);
41
- });
44
+ for (let ii = 0, length = value.length; ii < length; ii++) {
45
+ const element = value[ii];
46
+ flatAnimatedNodes(element, nodes, depth + 1);
47
+ }
42
48
  } else if (isPlainObject(value)) {
43
- Object.values(value).forEach(element => {
44
- visit(element, fn, depth + 1);
45
- });
49
+ const keys = Object.keys(value);
50
+ for (let ii = 0, length = keys.length; ii < length; ii++) {
51
+ const key = keys[ii];
52
+ flatAnimatedNodes(value[key], nodes, depth + 1);
53
+ }
46
54
  }
55
+ return nodes;
47
56
  }
48
57
 
49
58
  // Returns a copy of value with a transformation fn applied to any AnimatedNodes
@@ -58,7 +67,9 @@ function mapAnimatedNodes(value: any, fn: any => any, depth: number = 0): any {
58
67
  return value.map(element => mapAnimatedNodes(element, fn, depth + 1));
59
68
  } else if (isPlainObject(value)) {
60
69
  const result: {[string]: any} = {};
61
- for (const key in value) {
70
+ const keys = Object.keys(value);
71
+ for (let ii = 0, length = keys.length; ii < length; ii++) {
72
+ const key = keys[ii];
62
73
  result[key] = mapAnimatedNodes(value[key], fn, depth + 1);
63
74
  }
64
75
  return result;
@@ -67,38 +78,28 @@ function mapAnimatedNodes(value: any, fn: any => any, depth: number = 0): any {
67
78
  }
68
79
  }
69
80
 
70
- export function hasAnimatedNode(value: any, depth: number = 0): boolean {
71
- if (depth >= MAX_DEPTH) {
72
- return false;
73
- }
74
-
75
- if (value instanceof AnimatedNode) {
76
- return true;
77
- } else if (Array.isArray(value)) {
78
- for (const element of value) {
79
- if (hasAnimatedNode(element, depth + 1)) {
80
- return true;
81
- }
82
- }
83
- } else if (isPlainObject(value)) {
84
- // Don't consider React elements
85
- if (React.isValidElement(value)) {
86
- return false;
87
- }
88
- for (const key in value) {
89
- if (hasAnimatedNode(value[key], depth + 1)) {
90
- return true;
91
- }
81
+ export default class AnimatedObject extends AnimatedWithChildren {
82
+ #nodes: $ReadOnlyArray<AnimatedNode>;
83
+ _value: mixed;
84
+
85
+ /**
86
+ * Creates an `AnimatedObject` if `value` contains `AnimatedNode` instances.
87
+ * Otherwise, returns `null`.
88
+ */
89
+ static from(value: mixed): ?AnimatedObject {
90
+ const nodes = flatAnimatedNodes(value);
91
+ if (nodes.length === 0) {
92
+ return null;
92
93
  }
94
+ return new AnimatedObject(nodes, value);
93
95
  }
94
- return false;
95
- }
96
96
 
97
- export default class AnimatedObject extends AnimatedWithChildren {
98
- _value: any;
99
-
100
- constructor(value: any) {
97
+ /**
98
+ * Should only be called by `AnimatedObject.from`.
99
+ */
100
+ constructor(nodes: $ReadOnlyArray<AnimatedNode>, value: mixed) {
101
101
  super();
102
+ this.#nodes = nodes;
102
103
  this._value = value;
103
104
  }
104
105
 
@@ -115,23 +116,28 @@ export default class AnimatedObject extends AnimatedWithChildren {
115
116
  }
116
117
 
117
118
  __attach(): void {
118
- super.__attach();
119
- visit(this._value, node => {
119
+ const nodes = this.#nodes;
120
+ for (let ii = 0, length = nodes.length; ii < length; ii++) {
121
+ const node = nodes[ii];
120
122
  node.__addChild(this);
121
- });
123
+ }
122
124
  }
123
125
 
124
126
  __detach(): void {
125
- visit(this._value, node => {
127
+ const nodes = this.#nodes;
128
+ for (let ii = 0, length = nodes.length; ii < length; ii++) {
129
+ const node = nodes[ii];
126
130
  node.__removeChild(this);
127
- });
131
+ }
128
132
  super.__detach();
129
133
  }
130
134
 
131
135
  __makeNative(platformConfig: ?PlatformConfig): void {
132
- visit(this._value, value => {
133
- value.__makeNative(platformConfig);
134
- });
136
+ const nodes = this.#nodes;
137
+ for (let ii = 0, length = nodes.length; ii < length; ii++) {
138
+ const node = nodes[ii];
139
+ node.__makeNative(platformConfig);
140
+ }
135
141
  super.__makeNative(platformConfig);
136
142
  }
137
143