react-native-windows 0.0.0-canary.508 → 0.0.0-canary.511

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 (42) hide show
  1. package/.flowconfig +3 -1
  2. package/Libraries/Animated/NativeAnimatedHelper.js +212 -93
  3. package/Libraries/Animated/NativeAnimatedModule.js +3 -0
  4. package/Libraries/Animated/NativeAnimatedTurboModule.js +3 -0
  5. package/Libraries/Animated/nodes/AnimatedColor.js +49 -28
  6. package/Libraries/Animated/nodes/AnimatedProps.js +1 -5
  7. package/Libraries/Animated/nodes/AnimatedStyle.js +1 -5
  8. package/Libraries/Animated/nodes/AnimatedValue.js +11 -4
  9. package/Libraries/Animated/nodes/AnimatedValueXY.js +27 -0
  10. package/Libraries/Animated/useAnimatedProps.js +1 -0
  11. package/Libraries/BatchedBridge/MessageQueue.js +16 -9
  12. package/Libraries/Blob/FileReader.js +0 -6
  13. package/Libraries/Components/ScrollView/ScrollView.js +2 -2
  14. package/Libraries/Components/TextInput/TextInput.js +1 -1
  15. package/Libraries/Components/TextInput/TextInput.windows.js +1 -1
  16. package/Libraries/Core/ReactNativeVersion.js +1 -1
  17. package/Libraries/Lists/VirtualizeUtils.js +27 -18
  18. package/Libraries/Lists/VirtualizedList.js +3 -2
  19. package/Libraries/Lists/__tests__/VirtualizeUtils-test.js +14 -13
  20. package/Libraries/LogBox/UI/LogBoxInspectorCodeFrame.js +3 -0
  21. package/Libraries/Performance/PureComponentDebug.js +1 -0
  22. package/Libraries/PermissionsAndroid/NativePermissionsAndroid.js +7 -1
  23. package/Libraries/PermissionsAndroid/PermissionsAndroid.js +12 -0
  24. package/Libraries/Pressability/Pressability.js +3 -4
  25. package/Libraries/Pressability/Pressability.windows.js +3 -4
  26. package/Libraries/ReactNative/ReactNativeFeatureFlags.js +12 -0
  27. package/Libraries/StyleSheet/splitLayoutProps.js +2 -0
  28. package/Libraries/Types/CoreEventTypes.js +128 -11
  29. package/Libraries/Types/CoreEventTypes.windows.js +138 -22
  30. package/Libraries/Utilities/codegenNativeCommands.js +10 -1
  31. package/Microsoft.ReactNative.Managed/packages.lock.json +4 -4
  32. package/PropertySheets/Generated/PackageVersion.g.props +1 -1
  33. package/PropertySheets/JSEngine.props +1 -1
  34. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/graphics/RectangleEdges.h +100 -0
  35. package/ReactCommon/TEMP_UntilReactCommonUpdate/yoga/yoga/YGValue.h +94 -0
  36. package/Shared/InspectorPackagerConnection.cpp +2 -2
  37. package/Shared/OInstance.cpp +15 -11
  38. package/codegen/NativeAnimatedModuleSpec.g.h +6 -0
  39. package/codegen/NativeAnimatedTurboModuleSpec.g.h +6 -0
  40. package/package.json +8 -8
  41. package/stubs/double-conversion/double-conversion.h +18 -9
  42. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/nativemodule/core/ReactCommon/TurboModule.h +0 -87
package/.flowconfig CHANGED
@@ -98,6 +98,8 @@ suppress_type=$FlowFixMeProps
98
98
  suppress_type=$FlowFixMeState
99
99
  suppress_type=$FlowFixMeEmpty
100
100
 
101
+ experimental.env_mode=ssa
102
+
101
103
  [lints]
102
104
  sketchy-null-number=warn
103
105
  sketchy-null-mixed=warn
@@ -118,4 +120,4 @@ untyped-import
118
120
  untyped-type-import
119
121
 
120
122
  [version]
121
- ^0.178.0
123
+ ^0.179.0
@@ -20,7 +20,10 @@ import type {
20
20
  } from './NativeAnimatedModule';
21
21
  import type {AnimationConfig, EndCallback} from './animations/Animation';
22
22
  import type {InterpolationConfigType} from './nodes/AnimatedInterpolation';
23
+ import ReactNativeFeatureFlags from '../ReactNative/ReactNativeFeatureFlags';
23
24
  import invariant from 'invariant';
25
+ import RCTDeviceEventEmitter from '../EventEmitter/RCTDeviceEventEmitter';
26
+ import type {EventSubscription} from '../vendor/emitter/EventEmitter';
24
27
 
25
28
  // TODO T69437152 @petetheheat - Delete this fork when Fabric ships to 100%.
26
29
  const NativeAnimatedModule =
@@ -36,24 +39,82 @@ let nativeEventEmitter;
36
39
  let waitingForQueuedOperations = new Set();
37
40
  let queueOperations = false;
38
41
  let queue: Array<() => void> = [];
42
+ // $FlowFixMe
43
+ let singleOpQueue: Array<any> = [];
44
+
45
+ const useSingleOpBatching =
46
+ Platform.OS === 'android' &&
47
+ !!NativeAnimatedModule?.queueAndExecuteBatchedOperations &&
48
+ ReactNativeFeatureFlags.animatedShouldUseSingleOp();
49
+ let flushQueueTimeout = null;
50
+
51
+ const eventListenerGetValueCallbacks = {};
52
+ const eventListenerAnimationFinishedCallbacks = {};
53
+ let globalEventEmitterGetValueListener: ?EventSubscription = null;
54
+ let globalEventEmitterAnimationFinishedListener: ?EventSubscription = null;
55
+
56
+ const nativeOps: ?typeof NativeAnimatedModule = useSingleOpBatching
57
+ ? ((function () {
58
+ const apis = [
59
+ 'createAnimatedNode', // 1
60
+ 'updateAnimatedNodeConfig', // 2
61
+ 'getValue', // 3
62
+ 'startListeningToAnimatedNodeValue', // 4
63
+ 'stopListeningToAnimatedNodeValue', // 5
64
+ 'connectAnimatedNodes', // 6
65
+ 'disconnectAnimatedNodes', // 7
66
+ 'startAnimatingNode', // 8
67
+ 'stopAnimation', // 9
68
+ 'setAnimatedNodeValue', // 10
69
+ 'setAnimatedNodeOffset', // 11
70
+ 'flattenAnimatedNodeOffset', // 12
71
+ 'extractAnimatedNodeOffset', // 13
72
+ 'connectAnimatedNodeToView', // 14
73
+ 'disconnectAnimatedNodeFromView', // 15
74
+ 'restoreDefaultValues', // 16
75
+ 'dropAnimatedNode', // 17
76
+ 'addAnimatedEventToView', // 18
77
+ 'removeAnimatedEventFromView', // 19
78
+ 'addListener', // 20
79
+ 'removeListener', // 21
80
+ ];
81
+ return apis.reduce((acc, functionName, i) => {
82
+ // These indices need to be kept in sync with the indices in native (see NativeAnimatedModule in Java, or the equivalent for any other native platform).
83
+ acc[functionName] = i + 1;
84
+ return acc;
85
+ }, {});
86
+ })(): $FlowFixMe)
87
+ : NativeAnimatedModule;
39
88
 
40
89
  /**
41
- * Simple wrappers around NativeAnimatedModule to provide flow and autocomplete support for
42
- * the native module methods
90
+ * Wrappers around NativeAnimatedModule to provide flow and autocomplete support for
91
+ * the native module methods, and automatic queue management on Android
43
92
  */
44
93
  const API = {
45
94
  getValue: function (
46
95
  tag: number,
47
96
  saveValueCallback: (value: number) => void,
48
97
  ): void {
49
- invariant(NativeAnimatedModule, 'Native animated module is not available');
50
- API.queueOperation(() => {
51
- NativeAnimatedModule.getValue(tag, saveValueCallback);
52
- });
98
+ invariant(nativeOps, 'Native animated module is not available');
99
+ if (useSingleOpBatching) {
100
+ if (saveValueCallback) {
101
+ eventListenerGetValueCallbacks[tag] = saveValueCallback;
102
+ }
103
+ // $FlowFixMe
104
+ API.queueOperation(nativeOps.getValue, tag);
105
+ } else {
106
+ API.queueOperation(nativeOps.getValue, tag, saveValueCallback);
107
+ }
53
108
  },
54
109
  setWaitingForIdentifier: function (id: string): void {
55
110
  waitingForQueuedOperations.add(id);
56
111
  queueOperations = true;
112
+ if (
113
+ ReactNativeFeatureFlags.animatedShouldDebounceQueueFlush() &&
114
+ flushQueueTimeout
115
+ ) {
116
+ clearTimeout(flushQueueTimeout);
117
+ }
57
118
  },
58
119
  unsetWaitingForIdentifier: function (id: string): void {
59
120
  waitingForQueuedOperations.delete(id);
@@ -64,73 +125,103 @@ const API = {
64
125
  }
65
126
  },
66
127
  disableQueue: function (): void {
128
+ invariant(nativeOps, 'Native animated module is not available');
129
+
130
+ if (ReactNativeFeatureFlags.animatedShouldDebounceQueueFlush()) {
131
+ const prevTimeout = flushQueueTimeout;
132
+ clearImmediate(prevTimeout);
133
+ flushQueueTimeout = setImmediate(API.flushQueue);
134
+ } else {
135
+ API.flushQueue();
136
+ }
137
+ },
138
+ flushQueue: function (): void {
67
139
  invariant(NativeAnimatedModule, 'Native animated module is not available');
140
+ flushQueueTimeout = null;
68
141
 
69
- if (Platform.OS === 'android') {
70
- NativeAnimatedModule.startOperationBatch();
142
+ // Early returns before calling any APIs
143
+ if (useSingleOpBatching && singleOpQueue.length === 0) {
144
+ return;
71
145
  }
72
- for (let q = 0, l = queue.length; q < l; q++) {
73
- queue[q]();
146
+ if (!useSingleOpBatching && queue.length === 0) {
147
+ return;
74
148
  }
75
- queue.length = 0;
76
- if (Platform.OS === 'android') {
77
- NativeAnimatedModule.finishOperationBatch();
149
+
150
+ if (useSingleOpBatching) {
151
+ // Set up event listener for callbacks if it's not set up
152
+ if (
153
+ !globalEventEmitterGetValueListener ||
154
+ !globalEventEmitterAnimationFinishedListener
155
+ ) {
156
+ setupGlobalEventEmitterListeners();
157
+ }
158
+ // Single op batching doesn't use callback functions, instead we
159
+ // use RCTDeviceEventEmitter. This reduces overhead of sending lots of
160
+ // JSI functions across to native code; but also, TM infrastructure currently
161
+ // does not support packing a function into native arrays.
162
+ NativeAnimatedModule.queueAndExecuteBatchedOperations?.(singleOpQueue);
163
+ singleOpQueue.length = 0;
164
+ } else {
165
+ Platform.OS === 'android' && NativeAnimatedModule.startOperationBatch?.();
166
+ for (let q = 0, l = queue.length; q < l; q++) {
167
+ queue[q]();
168
+ }
169
+ queue.length = 0;
170
+ Platform.OS === 'android' &&
171
+ NativeAnimatedModule.finishOperationBatch?.();
78
172
  }
79
173
  },
80
- queueOperation: (fn: () => void): void => {
174
+ queueOperation: <Args: $ReadOnlyArray<mixed>, Fn: (...Args) => void>(
175
+ fn: Fn,
176
+ ...args: Args
177
+ ): void => {
178
+ if (useSingleOpBatching) {
179
+ // Get the command ID from the queued function, and push that ID and any arguments needed to execute the operation
180
+ // $FlowFixMe: surprise, fn is actually a number
181
+ singleOpQueue.push(fn, ...args);
182
+ return;
183
+ }
184
+
81
185
  // If queueing is explicitly on, *or* the queue has not yet
82
186
  // been flushed, use the queue. This is to prevent operations
83
187
  // from being executed out of order.
84
188
  if (queueOperations || queue.length !== 0) {
85
- queue.push(fn);
189
+ queue.push(() => fn(...args));
86
190
  } else {
87
- fn();
191
+ fn(...args);
88
192
  }
89
193
  },
90
194
  createAnimatedNode: function (tag: number, config: AnimatedNodeConfig): void {
91
- invariant(NativeAnimatedModule, 'Native animated module is not available');
92
- API.queueOperation(() =>
93
- NativeAnimatedModule.createAnimatedNode(tag, config),
94
- );
195
+ invariant(nativeOps, 'Native animated module is not available');
196
+ API.queueOperation(nativeOps.createAnimatedNode, tag, config);
95
197
  },
96
198
  updateAnimatedNodeConfig: function (
97
199
  tag: number,
98
200
  config: AnimatedNodeConfig,
99
201
  ): void {
100
- invariant(NativeAnimatedModule, 'Native animated module is not available');
101
- if (typeof NativeAnimatedModule.updateAnimatedNodeConfig === 'function') {
102
- API.queueOperation(() =>
103
- // $FlowIgnore[not-a-function] - checked above
104
- NativeAnimatedModule.updateAnimatedNodeConfig(tag, config),
105
- );
202
+ invariant(nativeOps, 'Native animated module is not available');
203
+ if (nativeOps.updateAnimatedNodeConfig) {
204
+ API.queueOperation(nativeOps.updateAnimatedNodeConfig, tag, config);
106
205
  }
107
206
  },
108
207
  startListeningToAnimatedNodeValue: function (tag: number) {
109
- invariant(NativeAnimatedModule, 'Native animated module is not available');
110
- API.queueOperation(() =>
111
- NativeAnimatedModule.startListeningToAnimatedNodeValue(tag),
112
- );
208
+ invariant(nativeOps, 'Native animated module is not available');
209
+ API.queueOperation(nativeOps.startListeningToAnimatedNodeValue, tag);
113
210
  },
114
211
  stopListeningToAnimatedNodeValue: function (tag: number) {
115
- invariant(NativeAnimatedModule, 'Native animated module is not available');
116
- API.queueOperation(() =>
117
- NativeAnimatedModule.stopListeningToAnimatedNodeValue(tag),
118
- );
212
+ invariant(nativeOps, 'Native animated module is not available');
213
+ API.queueOperation(nativeOps.stopListeningToAnimatedNodeValue, tag);
119
214
  },
120
215
  connectAnimatedNodes: function (parentTag: number, childTag: number): void {
121
- invariant(NativeAnimatedModule, 'Native animated module is not available');
122
- API.queueOperation(() =>
123
- NativeAnimatedModule.connectAnimatedNodes(parentTag, childTag),
124
- );
216
+ invariant(nativeOps, 'Native animated module is not available');
217
+ API.queueOperation(nativeOps.connectAnimatedNodes, parentTag, childTag);
125
218
  },
126
219
  disconnectAnimatedNodes: function (
127
220
  parentTag: number,
128
221
  childTag: number,
129
222
  ): void {
130
- invariant(NativeAnimatedModule, 'Native animated module is not available');
131
- API.queueOperation(() =>
132
- NativeAnimatedModule.disconnectAnimatedNodes(parentTag, childTag),
133
- );
223
+ invariant(nativeOps, 'Native animated module is not available');
224
+ API.queueOperation(nativeOps.disconnectAnimatedNodes, parentTag, childTag);
134
225
  },
135
226
  startAnimatingNode: function (
136
227
  animationId: number,
@@ -138,84 +229,85 @@ const API = {
138
229
  config: AnimatingNodeConfig,
139
230
  endCallback: EndCallback,
140
231
  ): void {
141
- invariant(NativeAnimatedModule, 'Native animated module is not available');
142
- API.queueOperation(() =>
143
- NativeAnimatedModule.startAnimatingNode(
232
+ invariant(nativeOps, 'Native animated module is not available');
233
+ if (useSingleOpBatching) {
234
+ if (endCallback) {
235
+ eventListenerAnimationFinishedCallbacks[animationId] = endCallback;
236
+ }
237
+ // $FlowFixMe
238
+ API.queueOperation(
239
+ nativeOps.startAnimatingNode,
240
+ animationId,
241
+ nodeTag,
242
+ config,
243
+ );
244
+ } else {
245
+ API.queueOperation(
246
+ nativeOps.startAnimatingNode,
144
247
  animationId,
145
248
  nodeTag,
146
249
  config,
147
250
  endCallback,
148
- ),
149
- );
251
+ );
252
+ }
150
253
  },
151
254
  stopAnimation: function (animationId: number) {
152
- invariant(NativeAnimatedModule, 'Native animated module is not available');
153
- API.queueOperation(() => NativeAnimatedModule.stopAnimation(animationId));
255
+ invariant(nativeOps, 'Native animated module is not available');
256
+ API.queueOperation(nativeOps.stopAnimation, animationId);
154
257
  },
155
258
  setAnimatedNodeValue: function (nodeTag: number, value: number): void {
156
- invariant(NativeAnimatedModule, 'Native animated module is not available');
157
- API.queueOperation(() =>
158
- NativeAnimatedModule.setAnimatedNodeValue(nodeTag, value),
159
- );
259
+ invariant(nativeOps, 'Native animated module is not available');
260
+ API.queueOperation(nativeOps.setAnimatedNodeValue, nodeTag, value);
160
261
  },
161
262
  setAnimatedNodeOffset: function (nodeTag: number, offset: number): void {
162
- invariant(NativeAnimatedModule, 'Native animated module is not available');
163
- API.queueOperation(() =>
164
- NativeAnimatedModule.setAnimatedNodeOffset(nodeTag, offset),
165
- );
263
+ invariant(nativeOps, 'Native animated module is not available');
264
+ API.queueOperation(nativeOps.setAnimatedNodeOffset, nodeTag, offset);
166
265
  },
167
266
  flattenAnimatedNodeOffset: function (nodeTag: number): void {
168
- invariant(NativeAnimatedModule, 'Native animated module is not available');
169
- API.queueOperation(() =>
170
- NativeAnimatedModule.flattenAnimatedNodeOffset(nodeTag),
171
- );
267
+ invariant(nativeOps, 'Native animated module is not available');
268
+ API.queueOperation(nativeOps.flattenAnimatedNodeOffset, nodeTag);
172
269
  },
173
270
  extractAnimatedNodeOffset: function (nodeTag: number): void {
174
- invariant(NativeAnimatedModule, 'Native animated module is not available');
175
- API.queueOperation(() =>
176
- NativeAnimatedModule.extractAnimatedNodeOffset(nodeTag),
177
- );
271
+ invariant(nativeOps, 'Native animated module is not available');
272
+ API.queueOperation(nativeOps.extractAnimatedNodeOffset, nodeTag);
178
273
  },
179
274
  connectAnimatedNodeToView: function (nodeTag: number, viewTag: number): void {
180
- invariant(NativeAnimatedModule, 'Native animated module is not available');
181
- API.queueOperation(() =>
182
- NativeAnimatedModule.connectAnimatedNodeToView(nodeTag, viewTag),
183
- );
275
+ invariant(nativeOps, 'Native animated module is not available');
276
+ API.queueOperation(nativeOps.connectAnimatedNodeToView, nodeTag, viewTag);
184
277
  },
185
278
  disconnectAnimatedNodeFromView: function (
186
279
  nodeTag: number,
187
280
  viewTag: number,
188
281
  ): void {
189
- invariant(NativeAnimatedModule, 'Native animated module is not available');
190
- API.queueOperation(() =>
191
- NativeAnimatedModule.disconnectAnimatedNodeFromView(nodeTag, viewTag),
282
+ invariant(nativeOps, 'Native animated module is not available');
283
+ API.queueOperation(
284
+ nativeOps.disconnectAnimatedNodeFromView,
285
+ nodeTag,
286
+ viewTag,
192
287
  );
193
288
  },
194
289
  restoreDefaultValues: function (nodeTag: number): void {
195
- invariant(NativeAnimatedModule, 'Native animated module is not available');
290
+ invariant(nativeOps, 'Native animated module is not available');
196
291
  // Backwards compat with older native runtimes, can be removed later.
197
- if (NativeAnimatedModule.restoreDefaultValues != null) {
198
- API.queueOperation(() =>
199
- NativeAnimatedModule.restoreDefaultValues(nodeTag),
200
- );
292
+ if (nativeOps.restoreDefaultValues != null) {
293
+ API.queueOperation(nativeOps.restoreDefaultValues, nodeTag);
201
294
  }
202
295
  },
203
296
  dropAnimatedNode: function (tag: number): void {
204
- invariant(NativeAnimatedModule, 'Native animated module is not available');
205
- API.queueOperation(() => NativeAnimatedModule.dropAnimatedNode(tag));
297
+ invariant(nativeOps, 'Native animated module is not available');
298
+ API.queueOperation(nativeOps.dropAnimatedNode, tag);
206
299
  },
207
300
  addAnimatedEventToView: function (
208
301
  viewTag: number,
209
302
  eventName: string,
210
303
  eventMapping: EventMapping,
211
304
  ) {
212
- invariant(NativeAnimatedModule, 'Native animated module is not available');
213
- API.queueOperation(() =>
214
- NativeAnimatedModule.addAnimatedEventToView(
215
- viewTag,
216
- eventName,
217
- eventMapping,
218
- ),
305
+ invariant(nativeOps, 'Native animated module is not available');
306
+ API.queueOperation(
307
+ nativeOps.addAnimatedEventToView,
308
+ viewTag,
309
+ eventName,
310
+ eventMapping,
219
311
  );
220
312
  },
221
313
  removeAnimatedEventFromView(
@@ -223,17 +315,44 @@ const API = {
223
315
  eventName: string,
224
316
  animatedNodeTag: number,
225
317
  ) {
226
- invariant(NativeAnimatedModule, 'Native animated module is not available');
227
- API.queueOperation(() =>
228
- NativeAnimatedModule.removeAnimatedEventFromView(
229
- viewTag,
230
- eventName,
231
- animatedNodeTag,
232
- ),
318
+ invariant(nativeOps, 'Native animated module is not available');
319
+ API.queueOperation(
320
+ nativeOps.removeAnimatedEventFromView,
321
+ viewTag,
322
+ eventName,
323
+ animatedNodeTag,
233
324
  );
234
325
  },
235
326
  };
236
327
 
328
+ function setupGlobalEventEmitterListeners() {
329
+ globalEventEmitterGetValueListener = RCTDeviceEventEmitter.addListener(
330
+ 'onNativeAnimatedModuleGetValue',
331
+ function (params) {
332
+ const {tag} = params;
333
+ const callback = eventListenerGetValueCallbacks[tag];
334
+ if (!callback) {
335
+ return;
336
+ }
337
+ callback(params.value);
338
+ delete eventListenerGetValueCallbacks[tag];
339
+ },
340
+ );
341
+ globalEventEmitterAnimationFinishedListener =
342
+ RCTDeviceEventEmitter.addListener(
343
+ 'onNativeAnimatedModuleAnimationFinished',
344
+ function (params) {
345
+ const {animationId} = params;
346
+ const callback = eventListenerAnimationFinishedCallbacks[animationId];
347
+ if (!callback) {
348
+ return;
349
+ }
350
+ callback(params);
351
+ delete eventListenerAnimationFinishedCallbacks[animationId];
352
+ },
353
+ );
354
+ }
355
+
237
356
  /**
238
357
  * Styles allowed by the native animated implementation.
239
358
  *
@@ -64,6 +64,9 @@ export interface Spec extends TurboModule {
64
64
  // Events
65
65
  +addListener: (eventName: string) => void;
66
66
  +removeListeners: (count: number) => void;
67
+
68
+ // All of the above in a batched mode
69
+ +queueAndExecuteBatchedOperations?: (operationsAndArgs: Array<any>) => void;
67
70
  }
68
71
 
69
72
  export default (TurboModuleRegistry.get<Spec>('NativeAnimatedModule'): ?Spec);
@@ -64,6 +64,9 @@ export interface Spec extends TurboModule {
64
64
  // Events
65
65
  +addListener: (eventName: string) => void;
66
66
  +removeListeners: (count: number) => void;
67
+
68
+ // All of the above in a batched mode
69
+ +queueAndExecuteBatchedOperations?: (operationsAndArgs: Array<any>) => void;
67
70
  }
68
71
 
69
72
  export default (TurboModuleRegistry.get<Spec>(
@@ -21,7 +21,12 @@ import type {ColorValue} from '../../StyleSheet/StyleSheet';
21
21
  import type {NativeColorValue} from '../../StyleSheet/PlatformColorValueTypes';
22
22
  import type {ProcessedColorValue} from '../../StyleSheet/processColor';
23
23
 
24
- type ColorListenerCallback = (value: string) => mixed;
24
+ export type AnimatedColorConfig = $ReadOnly<{
25
+ useNativeDriver: boolean,
26
+ }>;
27
+
28
+ type ColorListenerCallback = (value: ColorValue) => mixed;
29
+
25
30
  export type RgbaValue = {
26
31
  +r: number,
27
32
  +g: number,
@@ -29,6 +34,7 @@ export type RgbaValue = {
29
34
  +a: number,
30
35
  ...
31
36
  };
37
+
32
38
  type RgbaAnimatedValue = {
33
39
  +r: AnimatedValue,
34
40
  +g: AnimatedValue,
@@ -37,6 +43,8 @@ type RgbaAnimatedValue = {
37
43
  ...
38
44
  };
39
45
 
46
+ const NativeAnimatedAPI = NativeAnimatedHelper.API;
47
+
40
48
  const defaultColor: RgbaValue = {r: 0, g: 0, b: 0, a: 1.0};
41
49
  let _uniqueId = 1;
42
50
 
@@ -116,7 +124,10 @@ export default class AnimatedColor extends AnimatedWithChildren {
116
124
  ...
117
125
  } = {};
118
126
 
119
- constructor(valueIn?: ?(RgbaValue | RgbaAnimatedValue | ColorValue)) {
127
+ constructor(
128
+ valueIn?: ?(RgbaValue | RgbaAnimatedValue | ColorValue),
129
+ config?: ?AnimatedColorConfig,
130
+ ) {
120
131
  super();
121
132
  let value: RgbaValue | RgbaAnimatedValue | ColorValue =
122
133
  valueIn ?? defaultColor;
@@ -144,12 +155,9 @@ export default class AnimatedColor extends AnimatedWithChildren {
144
155
  this.g = new AnimatedValue(initColor.g);
145
156
  this.b = new AnimatedValue(initColor.b);
146
157
  this.a = new AnimatedValue(initColor.a);
147
-
148
- if (this.nativeColor) {
149
- if (!this.__isNative) {
150
- this.__makeNative();
151
- }
152
- }
158
+ }
159
+ if (this.nativeColor || (config && config.useNativeDriver)) {
160
+ this.__makeNative();
153
161
  }
154
162
  }
155
163
 
@@ -158,34 +166,43 @@ export default class AnimatedColor extends AnimatedWithChildren {
158
166
  * and update all the bound properties.
159
167
  */
160
168
  setValue(value: RgbaValue | ColorValue): void {
161
- this.nativeColor = null;
169
+ let shouldUpdateNodeConfig = false;
170
+ if (this.__isNative) {
171
+ const nativeTag = this.__getNativeTag();
172
+ NativeAnimatedAPI.setWaitingForIdentifier(nativeTag.toString());
173
+ }
162
174
 
163
175
  const processedColor: RgbaValue | NativeColorValue =
164
176
  processColor(value) ?? defaultColor;
165
177
  if (isRgbaValue(processedColor)) {
166
- // $FlowIgnore[incompatible-cast] - Type is verified above
167
- const rgbaValue: RgbaValue = (processedColor: RgbaValue);
178
+ // $FlowIgnore[incompatible-type] - Type is verified above
179
+ const rgbaValue: RgbaValue = processedColor;
168
180
  this.r.setValue(rgbaValue.r);
169
181
  this.g.setValue(rgbaValue.g);
170
182
  this.b.setValue(rgbaValue.b);
171
183
  this.a.setValue(rgbaValue.a);
184
+ if (this.nativeColor != null) {
185
+ this.nativeColor = null;
186
+ shouldUpdateNodeConfig = true;
187
+ }
172
188
  } else {
173
- // $FlowIgnore[incompatible-cast] - Type is verified above
174
- this.nativeColor = (processedColor: NativeColorValue);
175
- }
176
-
177
- if (this.nativeColor) {
178
- if (!this.__isNative) {
179
- this.__makeNative();
189
+ // $FlowIgnore[incompatible-type] - Type is verified above
190
+ const nativeColor: NativeColorValue = processedColor;
191
+ if (this.nativeColor !== nativeColor) {
192
+ this.nativeColor = nativeColor;
193
+ shouldUpdateNodeConfig = true;
180
194
  }
195
+ }
181
196
 
197
+ if (this.__isNative) {
182
198
  const nativeTag = this.__getNativeTag();
183
- NativeAnimatedHelper.API.setWaitingForIdentifier(nativeTag.toString());
184
- NativeAnimatedHelper.API.updateAnimatedNodeConfig(
185
- nativeTag,
186
- this.__getNativeConfig(),
187
- );
188
- NativeAnimatedHelper.API.unsetWaitingForIdentifier(nativeTag.toString());
199
+ if (shouldUpdateNodeConfig) {
200
+ NativeAnimatedAPI.updateAnimatedNodeConfig(
201
+ nativeTag,
202
+ this.__getNativeConfig(),
203
+ );
204
+ }
205
+ NativeAnimatedAPI.unsetWaitingForIdentifier(nativeTag.toString());
189
206
  }
190
207
  }
191
208
 
@@ -272,7 +289,7 @@ export default class AnimatedColor extends AnimatedWithChildren {
272
289
  * final value after stopping the animation, which is useful for updating
273
290
  * state to match the animation position with layout.
274
291
  */
275
- stopAnimation(callback?: (value: string) => void): void {
292
+ stopAnimation(callback?: ColorListenerCallback): void {
276
293
  this.r.stopAnimation();
277
294
  this.g.stopAnimation();
278
295
  this.b.stopAnimation();
@@ -283,7 +300,7 @@ export default class AnimatedColor extends AnimatedWithChildren {
283
300
  /**
284
301
  * Stops any animation and resets the value to its original.
285
302
  */
286
- resetAnimation(callback?: (value: string) => void): void {
303
+ resetAnimation(callback?: ColorListenerCallback): void {
287
304
  this.r.resetAnimation();
288
305
  this.g.resetAnimation();
289
306
  this.b.resetAnimation();
@@ -291,8 +308,12 @@ export default class AnimatedColor extends AnimatedWithChildren {
291
308
  callback && callback(this.__getValue());
292
309
  }
293
310
 
294
- __getValue(): string {
295
- return `rgba(${this.r.__getValue()}, ${this.g.__getValue()}, ${this.b.__getValue()}, ${this.a.__getValue()})`;
311
+ __getValue(): ColorValue {
312
+ if (this.nativeColor != null) {
313
+ return this.nativeColor;
314
+ } else {
315
+ return `rgba(${this.r.__getValue()}, ${this.g.__getValue()}, ${this.b.__getValue()}, ${this.a.__getValue()})`;
316
+ }
296
317
  }
297
318
 
298
319
  __attach(): void {
@@ -41,11 +41,7 @@ class AnimatedProps extends AnimatedNode {
41
41
  for (const key in this._props) {
42
42
  const value = this._props[key];
43
43
  if (value instanceof AnimatedNode) {
44
- if (!value.__isNative || value instanceof AnimatedStyle) {
45
- // We cannot use value of natively driven nodes this way as the value we have access from
46
- // JS may not be up to date.
47
- props[key] = value.__getValue();
48
- }
44
+ props[key] = value.__getValue();
49
45
  } else if (value instanceof AnimatedEvent) {
50
46
  props[key] = value.__getHandler();
51
47
  } else {
@@ -39,11 +39,7 @@ class AnimatedStyle extends AnimatedWithChildren {
39
39
  for (const key in style) {
40
40
  const value = style[key];
41
41
  if (value instanceof AnimatedNode) {
42
- if (!value.__isNative) {
43
- // We cannot use value of natively driven nodes this way as the value we have access from
44
- // JS may not be up to date.
45
- updatedStyle[key] = value.__getValue();
46
- }
42
+ updatedStyle[key] = value.__getValue();
47
43
  } else if (value && !Array.isArray(value) && typeof value === 'object') {
48
44
  // Support animating nested values (for example: shadowOffset.height)
49
45
  updatedStyle[key] = this._walkStyleAndGetValues(value);
@@ -20,6 +20,10 @@ import type Animation, {EndCallback} from '../animations/Animation';
20
20
  import type {InterpolationConfigType} from './AnimatedInterpolation';
21
21
  import type AnimatedTracking from './AnimatedTracking';
22
22
 
23
+ export type AnimatedValueConfig = $ReadOnly<{
24
+ useNativeDriver: boolean,
25
+ }>;
26
+
23
27
  const NativeAnimatedAPI = NativeAnimatedHelper.API;
24
28
 
25
29
  /**
@@ -87,7 +91,7 @@ class AnimatedValue extends AnimatedWithChildren {
87
91
  _animation: ?Animation;
88
92
  _tracking: ?AnimatedTracking;
89
93
 
90
- constructor(value: number) {
94
+ constructor(value: number, config?: ?AnimatedValueConfig) {
91
95
  super();
92
96
  if (typeof value !== 'number') {
93
97
  throw new Error('AnimatedValue: Attempting to set value to undefined');
@@ -95,6 +99,9 @@ class AnimatedValue extends AnimatedWithChildren {
95
99
  this._startingValue = this._value = value;
96
100
  this._offset = 0;
97
101
  this._animation = null;
102
+ if (config && config.useNativeDriver) {
103
+ this.__makeNative();
104
+ }
98
105
  }
99
106
 
100
107
  __detach() {
@@ -127,9 +134,9 @@ class AnimatedValue extends AnimatedWithChildren {
127
134
  !this.__isNative /* don't perform a flush for natively driven values */,
128
135
  );
129
136
  if (this.__isNative) {
130
- _executeAsAnimatedBatch(this.__getNativeTag().toString(), () => {
131
- NativeAnimatedAPI.setAnimatedNodeValue(this.__getNativeTag(), value);
132
- });
137
+ _executeAsAnimatedBatch(this.__getNativeTag().toString(), () =>
138
+ NativeAnimatedAPI.setAnimatedNodeValue(this.__getNativeTag(), value),
139
+ );
133
140
  }
134
141
  }
135
142