Add spec for AnimatedModule (#24911)
Summary: Part of #24875. Added `strict-local` to the NativeModuleHelper btw. ## Changelog [General] [Added] - TM add spec for AnimatedModule Pull Request resolved: https://github.com/facebook/react-native/pull/24911 Reviewed By: rickhanlonii Differential Revision: D15434114 Pulled By: fkgozali fbshipit-source-id: ea9215306ebf969795ce755270b8fdc14c52da9c
This commit is contained in:
Родитель
f80a1c2146
Коммит
116ac65fea
|
@ -4,30 +4,27 @@
|
|||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
* @flow strict-local
|
||||
* @format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const NativeAnimatedModule = require('../../BatchedBridge/NativeModules')
|
||||
.NativeAnimatedModule;
|
||||
const NativeEventEmitter = require('../../EventEmitter/NativeEventEmitter');
|
||||
import NativeEventEmitter from '../../EventEmitter/NativeEventEmitter';
|
||||
import type {
|
||||
EventMapping,
|
||||
AnimatedNodeConfig,
|
||||
AnimatingNodeConfig,
|
||||
} from './NativeAnimatedModule';
|
||||
import NativeAnimatedModule from './NativeAnimatedModule';
|
||||
import invariant from 'invariant';
|
||||
|
||||
const invariant = require('invariant');
|
||||
|
||||
import type {AnimationConfig} from './animations/Animation';
|
||||
import type {AnimationConfig, EndCallback} from './animations/Animation';
|
||||
import type {InterpolationConfigType} from './nodes/AnimatedInterpolation';
|
||||
import type {EventConfig} from './AnimatedEvent';
|
||||
|
||||
let __nativeAnimatedNodeTagCount = 1; /* used for animated nodes */
|
||||
let __nativeAnimationIdCount = 1; /* used for started animations */
|
||||
|
||||
type EndResult = {finished: boolean};
|
||||
type EndCallback = (result: EndResult) => void;
|
||||
type EventMapping = {
|
||||
nativeEventPath: Array<string>,
|
||||
animatedValueTag: ?number,
|
||||
};
|
||||
|
||||
let nativeEventEmitter;
|
||||
|
||||
/**
|
||||
|
@ -35,36 +32,36 @@ let nativeEventEmitter;
|
|||
* the native module methods
|
||||
*/
|
||||
const API = {
|
||||
createAnimatedNode: function(tag: ?number, config: Object): void {
|
||||
assertNativeAnimatedModule();
|
||||
createAnimatedNode: function(tag: ?number, config: AnimatedNodeConfig): void {
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.createAnimatedNode(tag, config);
|
||||
},
|
||||
startListeningToAnimatedNodeValue: function(tag: ?number) {
|
||||
assertNativeAnimatedModule();
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.startListeningToAnimatedNodeValue(tag);
|
||||
},
|
||||
stopListeningToAnimatedNodeValue: function(tag: ?number) {
|
||||
assertNativeAnimatedModule();
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.stopListeningToAnimatedNodeValue(tag);
|
||||
},
|
||||
connectAnimatedNodes: function(parentTag: ?number, childTag: ?number): void {
|
||||
assertNativeAnimatedModule();
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.connectAnimatedNodes(parentTag, childTag);
|
||||
},
|
||||
disconnectAnimatedNodes: function(
|
||||
parentTag: ?number,
|
||||
childTag: ?number,
|
||||
): void {
|
||||
assertNativeAnimatedModule();
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.disconnectAnimatedNodes(parentTag, childTag);
|
||||
},
|
||||
startAnimatingNode: function(
|
||||
animationId: ?number,
|
||||
nodeTag: ?number,
|
||||
config: Object,
|
||||
config: AnimatingNodeConfig,
|
||||
endCallback: EndCallback,
|
||||
): void {
|
||||
assertNativeAnimatedModule();
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.startAnimatingNode(
|
||||
animationId,
|
||||
nodeTag,
|
||||
|
@ -73,41 +70,41 @@ const API = {
|
|||
);
|
||||
},
|
||||
stopAnimation: function(animationId: ?number) {
|
||||
assertNativeAnimatedModule();
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.stopAnimation(animationId);
|
||||
},
|
||||
setAnimatedNodeValue: function(nodeTag: ?number, value: ?number): void {
|
||||
assertNativeAnimatedModule();
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.setAnimatedNodeValue(nodeTag, value);
|
||||
},
|
||||
setAnimatedNodeOffset: function(nodeTag: ?number, offset: ?number): void {
|
||||
assertNativeAnimatedModule();
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.setAnimatedNodeOffset(nodeTag, offset);
|
||||
},
|
||||
flattenAnimatedNodeOffset: function(nodeTag: ?number): void {
|
||||
assertNativeAnimatedModule();
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.flattenAnimatedNodeOffset(nodeTag);
|
||||
},
|
||||
extractAnimatedNodeOffset: function(nodeTag: ?number): void {
|
||||
assertNativeAnimatedModule();
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.extractAnimatedNodeOffset(nodeTag);
|
||||
},
|
||||
connectAnimatedNodeToView: function(
|
||||
nodeTag: ?number,
|
||||
viewTag: ?number,
|
||||
): void {
|
||||
assertNativeAnimatedModule();
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.connectAnimatedNodeToView(nodeTag, viewTag);
|
||||
},
|
||||
disconnectAnimatedNodeFromView: function(
|
||||
nodeTag: ?number,
|
||||
viewTag: ?number,
|
||||
): void {
|
||||
assertNativeAnimatedModule();
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.disconnectAnimatedNodeFromView(nodeTag, viewTag);
|
||||
},
|
||||
dropAnimatedNode: function(tag: ?number): void {
|
||||
assertNativeAnimatedModule();
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.dropAnimatedNode(tag);
|
||||
},
|
||||
addAnimatedEventToView: function(
|
||||
|
@ -115,7 +112,7 @@ const API = {
|
|||
eventName: string,
|
||||
eventMapping: EventMapping,
|
||||
) {
|
||||
assertNativeAnimatedModule();
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.addAnimatedEventToView(
|
||||
viewTag,
|
||||
eventName,
|
||||
|
@ -127,7 +124,7 @@ const API = {
|
|||
eventName: string,
|
||||
animatedNodeTag: ?number,
|
||||
) {
|
||||
assertNativeAnimatedModule();
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.removeAnimatedEventFromView(
|
||||
viewTag,
|
||||
eventName,
|
||||
|
@ -197,7 +194,12 @@ function addWhitelistedInterpolationParam(param: string): void {
|
|||
SUPPORTED_INTERPOLATION_PARAMS[param] = true;
|
||||
}
|
||||
|
||||
function validateTransform(configs: Array<Object>): void {
|
||||
function validateTransform(
|
||||
configs: Array<
|
||||
| {type: 'animated', property: string, nodeTag: ?number}
|
||||
| {type: 'static', property: string, value: number},
|
||||
>,
|
||||
): void {
|
||||
configs.forEach(config => {
|
||||
if (!TRANSFORM_WHITELIST.hasOwnProperty(config.property)) {
|
||||
throw new Error(
|
||||
|
@ -209,7 +211,7 @@ function validateTransform(configs: Array<Object>): void {
|
|||
});
|
||||
}
|
||||
|
||||
function validateStyles(styles: Object): void {
|
||||
function validateStyles(styles: {[key: string]: ?number}): void {
|
||||
for (const key in styles) {
|
||||
if (!STYLES_WHITELIST.hasOwnProperty(key)) {
|
||||
throw new Error(
|
||||
|
@ -219,7 +221,7 @@ function validateStyles(styles: Object): void {
|
|||
}
|
||||
}
|
||||
|
||||
function validateInterpolation(config: Object): void {
|
||||
function validateInterpolation(config: InterpolationConfigType): void {
|
||||
for (const key in config) {
|
||||
if (!SUPPORTED_INTERPOLATION_PARAMS.hasOwnProperty(key)) {
|
||||
throw new Error(
|
||||
|
@ -244,7 +246,7 @@ function assertNativeAnimatedModule(): void {
|
|||
let _warnedMissingNativeAnimated = false;
|
||||
|
||||
function shouldUseNativeDriver(config: AnimationConfig | EventConfig): boolean {
|
||||
if (config.useNativeDriver && !NativeAnimatedModule) {
|
||||
if (config.useNativeDriver === true && !NativeAnimatedModule) {
|
||||
if (!_warnedMissingNativeAnimated) {
|
||||
console.warn(
|
||||
'Animated: `useNativeDriver` is not supported because the native ' +
|
||||
|
@ -261,7 +263,7 @@ function shouldUseNativeDriver(config: AnimationConfig | EventConfig): boolean {
|
|||
return config.useNativeDriver || false;
|
||||
}
|
||||
|
||||
function transformDataType(value: any): number {
|
||||
function transformDataType(value: number | string): number {
|
||||
// Change the string type to number type so we can reuse the same logic in
|
||||
// iOS and Android platform
|
||||
if (typeof value !== 'string') {
|
||||
|
@ -290,6 +292,7 @@ module.exports = {
|
|||
assertNativeAnimatedModule,
|
||||
shouldUseNativeDriver,
|
||||
transformDataType,
|
||||
// $FlowExpectedError - unsafe getter lint suppresion
|
||||
get nativeEventEmitter() {
|
||||
if (!nativeEventEmitter) {
|
||||
nativeEventEmitter = new NativeEventEmitter(NativeAnimatedModule);
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {TurboModule} from 'RCTExport';
|
||||
import * as TurboModuleRegistry from 'TurboModuleRegistry';
|
||||
|
||||
type EndResult = {finished: boolean};
|
||||
type EndCallback = (result: EndResult) => void;
|
||||
|
||||
export type EventMapping = {|
|
||||
nativeEventPath: Array<string>,
|
||||
animatedValueTag: ?number,
|
||||
|};
|
||||
|
||||
export type AnimatedNodeConfig = {|
|
||||
// TODO: Type this with better enums.
|
||||
type: string,
|
||||
|};
|
||||
|
||||
export type AnimatingNodeConfig = {|
|
||||
// TODO: Type this with better enums.
|
||||
type: string,
|
||||
|};
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
+createAnimatedNode: (tag: ?number, config: AnimatedNodeConfig) => void;
|
||||
+startListeningToAnimatedNodeValue: (tag: ?number) => void;
|
||||
+stopListeningToAnimatedNodeValue: (tag: ?number) => void;
|
||||
+connectAnimatedNodes: (parentTag: ?number, childTag: ?number) => void;
|
||||
+disconnectAnimatedNodes: (parentTag: ?number, childTag: ?number) => void;
|
||||
+startAnimatingNode: (
|
||||
animationId: ?number,
|
||||
nodeTag: ?number,
|
||||
config: AnimatingNodeConfig,
|
||||
endCallback: EndCallback,
|
||||
) => void;
|
||||
+stopAnimation: (animationId: ?number) => void;
|
||||
+setAnimatedNodeValue: (nodeTag: ?number, value: ?number) => void;
|
||||
+setAnimatedNodeOffset: (nodeTag: ?number, offset: ?number) => void;
|
||||
+flattenAnimatedNodeOffset: (nodeTag: ?number) => void;
|
||||
+extractAnimatedNodeOffset: (nodeTag: ?number) => void;
|
||||
+connectAnimatedNodeToView: (nodeTag: ?number, viewTag: ?number) => void;
|
||||
+disconnectAnimatedNodeFromView: (nodeTag: ?number, viewTag: ?number) => void;
|
||||
+dropAnimatedNode: (tag: ?number) => void;
|
||||
+addAnimatedEventToView: (
|
||||
viewTag: ?number,
|
||||
eventName: string,
|
||||
eventMapping: EventMapping,
|
||||
) => void;
|
||||
+removeAnimatedEventFromView: (
|
||||
viewTag: ?number,
|
||||
eventName: string,
|
||||
animatedNodeTag: ?number,
|
||||
) => void;
|
||||
|
||||
// Events
|
||||
+addListener: (eventName: string) => void;
|
||||
+removeListeners: (count: number) => void;
|
||||
}
|
||||
|
||||
export default TurboModuleRegistry.get<Spec>('NativeAnimatedModule');
|
|
@ -10,6 +10,10 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
jest.mock('../../../BatchedBridge/NativeModules', () => ({
|
||||
NativeAnimatedModule: {},
|
||||
}));
|
||||
|
||||
let Animated = require('../Animated');
|
||||
describe('Animated tests', () => {
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -22,9 +22,10 @@ jest
|
|||
.setMock('../../../Lists/FlatList', ClassComponentMock)
|
||||
.setMock('../../../Lists/SectionList', ClassComponentMock)
|
||||
.setMock('react', {Component: class {}})
|
||||
.setMock('../../../BatchedBridge/NativeModules', {
|
||||
.mock('../../../BatchedBridge/NativeModules', () => ({
|
||||
NativeAnimatedModule: {},
|
||||
})
|
||||
}))
|
||||
.mock('../NativeAnimatedModule')
|
||||
.mock('../../../EventEmitter/NativeEventEmitter')
|
||||
// findNodeHandle is imported from ReactNative so mock that whole module.
|
||||
.setMock('../../../Renderer/shims/ReactNative', {findNodeHandle: () => 1});
|
||||
|
@ -43,8 +44,7 @@ function createAndMountComponent(ComponentClass, props) {
|
|||
}
|
||||
|
||||
describe('Native Animated', () => {
|
||||
const nativeAnimatedModule = require('../../../BatchedBridge/NativeModules')
|
||||
.NativeAnimatedModule;
|
||||
const nativeAnimatedModule = require('../NativeAnimatedModule').default;
|
||||
|
||||
beforeEach(() => {
|
||||
nativeAnimatedModule.addAnimatedEventToView = jest.fn();
|
||||
|
|
Загрузка…
Ссылка в новой задаче