Skip to content

Commit 27dd2ec

Browse files
javachefacebook-github-bot
authored andcommitted
Fix validation of AnimatedEvent with AnimatedValueXY
Summary: Changelog: [General][Fixed] Support Animated.ValueXY when validating Animated.event Reviewed By: yungsters Differential Revision: D30779011 fbshipit-source-id: 56f4d9eb6a20200584e5429a1693d0703f8c1a37
1 parent b7c023a commit 27dd2ec

File tree

3 files changed

+54
-4
lines changed

3 files changed

+54
-4
lines changed

Libraries/Animated/AnimatedEvent.js

+23-4
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,18 @@
1111
'use strict';
1212

1313
const AnimatedValue = require('./nodes/AnimatedValue');
14+
const AnimatedValueXY = require('./nodes/AnimatedValueXY');
1415
const NativeAnimatedHelper = require('./NativeAnimatedHelper');
1516
const ReactNative = require('../Renderer/shims/ReactNative');
1617

1718
const invariant = require('invariant');
1819

1920
const {shouldUseNativeDriver} = require('./NativeAnimatedHelper');
2021

21-
export type Mapping = {[key: string]: Mapping, ...} | AnimatedValue;
22+
export type Mapping =
23+
| {[key: string]: Mapping, ...}
24+
| AnimatedValue
25+
| AnimatedValueXY;
2226
export type EventConfig = {
2327
listener?: ?Function,
2428
useNativeDriver: boolean,
@@ -41,6 +45,9 @@ function attachNativeEvent(
4145
nativeEventPath: path,
4246
animatedValueTag: value.__getNativeTag(),
4347
});
48+
} else if (value instanceof AnimatedValueXY) {
49+
traverse(value.x, path.concat('x'));
50+
traverse(value.y, path.concat('y'));
4451
} else if (typeof value === 'object') {
4552
for (const key in value) {
4653
traverse(value[key], path.concat(key));
@@ -95,6 +102,13 @@ function validateMapping(argMapping, args) {
95102
);
96103
return;
97104
}
105+
if (recMapping instanceof AnimatedValueXY) {
106+
invariant(
107+
typeof recEvt.x === 'number' && typeof recEvt.y === 'number',
108+
'Bad mapping of event key ' + key + ', should be XY but got ' + recEvt,
109+
);
110+
return;
111+
}
98112
if (typeof recEvt === 'number') {
99113
invariant(
100114
recMapping instanceof AnimatedValue,
@@ -204,22 +218,27 @@ class AnimatedEvent {
204218
validatedMapping = true;
205219
}
206220

207-
const traverse = (recMapping, recEvt, key) => {
221+
const traverse = (recMapping, recEvt) => {
208222
if (recMapping instanceof AnimatedValue) {
209223
if (typeof recEvt === 'number') {
210224
recMapping.setValue(recEvt);
211225
}
226+
} else if (recMapping instanceof AnimatedValueXY) {
227+
if (typeof recEvt === 'object') {
228+
traverse(recMapping.x, recEvt.x);
229+
traverse(recMapping.y, recEvt.y);
230+
}
212231
} else if (typeof recMapping === 'object') {
213232
for (const mappingKey in recMapping) {
214233
/* $FlowFixMe[prop-missing] (>=0.120.0) This comment suppresses an
215234
* error found when Flow v0.120 was deployed. To see the error,
216235
* delete this comment and run Flow. */
217-
traverse(recMapping[mappingKey], recEvt[mappingKey], mappingKey);
236+
traverse(recMapping[mappingKey], recEvt[mappingKey]);
218237
}
219238
}
220239
};
221240
this._argMapping.forEach((mapping, idx) => {
222-
traverse(mapping, args[idx], 'arg' + idx);
241+
traverse(mapping, args[idx]);
223242
});
224243

225244
this._callListeners(...args);

Libraries/Animated/__tests__/Animated-test.js

+13
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,16 @@ describe('Animated tests', () => {
638638
handler({bar: 'ignoreBar'}, {state: {baz: 'ignoreBaz', foo: 42}});
639639
expect(value.__getValue()).toBe(42);
640640
});
641+
642+
it('should validate AnimatedValueXY mappings', () => {
643+
const value = new Animated.ValueXY({x: 0, y: 0});
644+
const handler = Animated.event([{state: value}], {
645+
useNativeDriver: false,
646+
});
647+
handler({state: {x: 1, y: 2}});
648+
expect(value.__getValue()).toMatchObject({x: 1, y: 2});
649+
});
650+
641651
it('should call listeners', () => {
642652
const value = new Animated.Value(0);
643653
const listener = jest.fn();
@@ -650,6 +660,7 @@ describe('Animated tests', () => {
650660
expect(listener.mock.calls.length).toBe(1);
651661
expect(listener).toBeCalledWith({foo: 42});
652662
});
663+
653664
it('should call forked event listeners, with Animated.event() listener', () => {
654665
const value = new Animated.Value(0);
655666
const listener = jest.fn();
@@ -666,6 +677,7 @@ describe('Animated tests', () => {
666677
expect(listener2.mock.calls.length).toBe(1);
667678
expect(listener2).toBeCalledWith({foo: 42});
668679
});
680+
669681
it('should call forked event listeners, with js listener', () => {
670682
const listener = jest.fn();
671683
const listener2 = jest.fn();
@@ -676,6 +688,7 @@ describe('Animated tests', () => {
676688
expect(listener2.mock.calls.length).toBe(1);
677689
expect(listener2).toBeCalledWith({foo: 42});
678690
});
691+
679692
it('should call forked event listeners, with undefined listener', () => {
680693
const listener = undefined;
681694
const listener2 = jest.fn();

Libraries/Animated/__tests__/AnimatedNative-test.js

+18
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,24 @@ describe('Native Animated', () => {
248248
);
249249
});
250250

251+
it('shoud map AnimatedValueXY', () => {
252+
const value = new Animated.ValueXY({x: 0, y: 0});
253+
value.__makeNative();
254+
const event = Animated.event([{nativeEvent: {state: value}}], {
255+
useNativeDriver: true,
256+
});
257+
258+
TestRenderer.create(<Animated.View onTouchMove={event} />);
259+
['x', 'y'].forEach((key, idx) =>
260+
expect(
261+
NativeAnimatedModule.addAnimatedEventToView,
262+
).toHaveBeenNthCalledWith(idx + 1, expect.any(Number), 'onTouchMove', {
263+
nativeEventPath: ['state', key],
264+
animatedValueTag: value[key].__getNativeTag(),
265+
}),
266+
);
267+
});
268+
251269
it('should throw on invalid event path', () => {
252270
const value = new Animated.Value(0);
253271
value.__makeNative();

0 commit comments

Comments
 (0)