├── index.js ├── dist ├── animation-model.js ├── immutableRenderDecorator.d.ts ├── animation-model.js.map ├── animation-model.d.ts ├── animation-view.d.ts ├── immutableRenderDecorator.js.map ├── immutableRenderDecorator.js ├── animation-view.js.map └── animation-view.js ├── index.d.ts ├── typings ├── index.d.ts └── globals │ ├── react │ ├── typings.json │ └── index.d.ts │ └── react-native │ └── typings.json ├── android ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── baidu │ │ └── wefan │ │ ├── AnimationModel.java │ │ ├── AnimationViewPackage.java │ │ ├── AnimationEvent.java │ │ ├── AnimationViewManager.java │ │ └── TBNAnimationView.java ├── build.gradle └── react-native-animation.iml ├── src ├── typings-fix.d.ts ├── animation-model.ts ├── immutableRenderDecorator.ts └── animation-view.tsx ├── typings.json ├── ios ├── TBNAnimationViewManager.h ├── TBNAnimationView.h ├── TBNAnimationViewManager.m └── TBNAnimationView.m ├── .gitignore ├── react-native-animation.podspec ├── package.json ├── tsconfig.json ├── LICENSE └── README.md /index.js: -------------------------------------------------------------------------------- 1 | export * from './dist/animation-view' -------------------------------------------------------------------------------- /dist/animation-model.js: -------------------------------------------------------------------------------- 1 | //# sourceMappingURL=animation-model.js.map -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | export * from './dist/animation-view' 2 | export * from './dist/animation-model' -------------------------------------------------------------------------------- /typings/index.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /dist/immutableRenderDecorator.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | export default function immutableRenderDecorator(Target: React.ComponentClass): any; 3 | -------------------------------------------------------------------------------- /dist/animation-model.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"animation-model.js","sourceRoot":"C:/WorkSpaces/Web/react-native-animation/src/","sources":["animation-model.ts"],"names":[],"mappings":""} -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /src/typings-fix.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace __React { 2 | export function findNodeHandle(element: any): any 3 | export var UIManager: any 4 | export function requireNativeComponent(name: string, component: any, data: any): any 5 | } -------------------------------------------------------------------------------- /typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-animation", 3 | "dependencies": {}, 4 | "globalDependencies": { 5 | "react": "registry:dt/react#0.14.0+20160805125551", 6 | "react-native": "registry:dt/react-native#0.29.0+20160728152643" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /ios/TBNAnimationViewManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // TBNAnimationView.h 3 | // TogetherHi 4 | // 5 | // Created by zzy@baidu on 16/7/12. 6 | // Copyright © 2016年 Baidu. All rights reserved. 7 | // 8 | 9 | #import "RCTViewManager.h" 10 | 11 | @interface TBNAnimationViewManager : RCTViewManager 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /ios/TBNAnimationView.h: -------------------------------------------------------------------------------- 1 | // 2 | // TBNAnimationView.h 3 | // TogetherHi 4 | // 5 | // Created by zzy@baidu on 16/7/12. 6 | // Copyright © 2016年 Baidu. All rights reserved. 7 | // 8 | #import 9 | #import "RCTView.h" 10 | #import "RCTEventDispatcher.h" 11 | 12 | @interface TBNAnimationView : RCTView 13 | 14 | - (void)add:data; 15 | - (void)start:data; 16 | - (void)clear; 17 | 18 | @end -------------------------------------------------------------------------------- /typings/globals/react/typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "resolution": "main", 3 | "tree": { 4 | "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/edcbaabb56bb0866df95dbfdf279f4a680051217/react/react.d.ts", 5 | "raw": "registry:dt/react#0.14.0+20160805125551", 6 | "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/edcbaabb56bb0866df95dbfdf279f4a680051217/react/react.d.ts" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /typings/globals/react-native/typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "resolution": "main", 3 | "tree": { 4 | "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/94fa3e9080c04024524307d8d1858b274176b470/react-native/react-native.d.ts", 5 | "raw": "registry:dt/react-native#0.29.0+20160728152643", 6 | "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/94fa3e9080c04024524307d8d1858b274176b470/react-native/react-native.d.ts" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | *.xcworkspacedata 24 | *.xcworkspace 25 | project.xcworkspace 26 | 27 | # Android/IJ 28 | # 29 | .idea 30 | .gradle 31 | local.properties 32 | android/build 33 | 34 | # node.js 35 | # 36 | node_modules -------------------------------------------------------------------------------- /react-native-animation.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "react-native-animation" 3 | s.version = "1.0.6" 4 | s.platform = :ios, "8.0" 5 | s.authors = { "Zhang Zhenyang" => "zhangzhenyang@baidu.com" } 6 | s.license = "MIT" 7 | s.summary = "A native animation UI component for react-native." 8 | s.homepage = "https://github.com/zhang740/react-native-animation" 9 | s.source = { :git => "https://github.com/zhang740/react-native-animation.git" } 10 | s.source_files = "ios/*.{h,m}" 11 | 12 | s.dependency 'React' 13 | end 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-animation", 3 | "version": "1.0.6", 4 | "description": "A native animation UI component for react-native", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/zhang740/react-native-animation.git" 12 | }, 13 | "keywords": [ 14 | "react-native", 15 | "animation" 16 | ], 17 | "author": "zhang740", 18 | "license": "MIT", 19 | "devDependencies": { 20 | "react-native": "0.33.0", 21 | "typescript": "2.0.6" 22 | } 23 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "jsx": "react", 5 | "module": "es2015", 6 | "moduleResolution": "node", 7 | "noImplicitAny": true, 8 | "experimentalDecorators": true, 9 | "preserveConstEnums": true, 10 | "removeComments": false, 11 | "sourceRoot": "src", 12 | "outDir": "dist", 13 | "sourceMap": true, 14 | "declaration": true 15 | }, 16 | "filesGlob": [ 17 | "src/**/*.ts", 18 | "src/**/*.tsx" 19 | ], 20 | "exclude": [ 21 | "node_modules", 22 | "dist" 23 | ], 24 | "compileOnSave": false 25 | } -------------------------------------------------------------------------------- /src/animation-model.ts: -------------------------------------------------------------------------------- 1 | export interface AnimationModel { 2 | /** 名称 */ 3 | name?: string 4 | /** 动画类型 */ 5 | type: 'Translate' | 'Rotate' | 'Scale' | 'Alpha' 6 | /** 起始值 */ 7 | from?: number 8 | /** 目标值 */ 9 | to?: number 10 | /** Y */ 11 | from2?: number 12 | to2?: number 13 | /** Z */ 14 | from3?: number 15 | to3?: number 16 | /** 动画时间 */ 17 | duration: number 18 | /** 延迟 */ 19 | startOffset?: number 20 | /** 值函数 */ 21 | interpolator?: 'Linear' 22 | interpolatorData?: number 23 | /** 重复次数 */ 24 | repeat?: number 25 | } 26 | 27 | export interface AnimationGroup { 28 | name: string 29 | data: AnimationModel[] 30 | repeat: number 31 | } -------------------------------------------------------------------------------- /android/src/main/java/com/baidu/wefan/AnimationModel.java: -------------------------------------------------------------------------------- 1 | package com.baidu.wefan; 2 | 3 | import android.support.annotation.Nullable; 4 | 5 | /** 6 | * Created by zzy on 2016/6/30. 7 | */ 8 | public class AnimationModel { 9 | public enum AnimationType { 10 | Translate, 11 | Rotate, 12 | Scale, 13 | Alpha 14 | } 15 | 16 | public AnimationType type; 17 | public Float from; 18 | public Float to; 19 | public Float from2; 20 | public Float to2; 21 | public Float from3; 22 | public Float to3; 23 | public int duration; 24 | public int startOffset; 25 | public String interpolator; // 'Linear' 26 | public float interpolatorData; 27 | public int repeat; 28 | } 29 | -------------------------------------------------------------------------------- /dist/animation-model.d.ts: -------------------------------------------------------------------------------- 1 | export interface AnimationModel { 2 | /** 名称 */ 3 | name?: string; 4 | /** 动画类型 */ 5 | type: 'Translate' | 'Rotate' | 'Scale' | 'Alpha'; 6 | /** 起始值 */ 7 | from?: number; 8 | /** 目标值 */ 9 | to?: number; 10 | /** Y */ 11 | from2?: number; 12 | to2?: number; 13 | /** Z */ 14 | from3?: number; 15 | to3?: number; 16 | /** 动画时间 */ 17 | duration: number; 18 | /** 延迟 */ 19 | startOffset?: number; 20 | /** 值函数 */ 21 | interpolator?: 'Linear'; 22 | interpolatorData?: number; 23 | /** 重复次数 */ 24 | repeat?: number; 25 | } 26 | export interface AnimationGroup { 27 | name: string; 28 | data: AnimationModel[]; 29 | repeat: number; 30 | } 31 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | } 5 | 6 | dependencies { 7 | classpath 'com.android.tools.build:gradle:1.1.3' 8 | } 9 | } 10 | 11 | apply plugin: 'com.android.library' 12 | 13 | android { 14 | compileSdkVersion 23 15 | buildToolsVersion "23.0.1" 16 | 17 | defaultConfig { 18 | minSdkVersion 16 19 | targetSdkVersion 22 20 | versionCode 1 21 | versionName "1.0" 22 | } 23 | lintOptions { 24 | abortOnError false 25 | } 26 | } 27 | 28 | repositories { 29 | mavenCentral() 30 | } 31 | 32 | repositories { 33 | } 34 | 35 | dependencies { 36 | compile "com.facebook.react:react-native:+" 37 | compile 'com.google.code.gson:gson:2.7' 38 | } -------------------------------------------------------------------------------- /android/src/main/java/com/baidu/wefan/AnimationViewPackage.java: -------------------------------------------------------------------------------- 1 | package com.baidu.wefan; 2 | 3 | import com.facebook.react.ReactPackage; 4 | import com.facebook.react.bridge.JavaScriptModule; 5 | import com.facebook.react.bridge.NativeModule; 6 | import com.facebook.react.bridge.ReactApplicationContext; 7 | import com.facebook.react.uimanager.ViewManager; 8 | 9 | import java.util.Arrays; 10 | import java.util.Collections; 11 | import java.util.List; 12 | 13 | /** 14 | * Created by zzy on 16/9/14. 15 | */ 16 | public class AnimationViewPackage implements ReactPackage { 17 | 18 | @Override 19 | public List createNativeModules(ReactApplicationContext reactContext) { 20 | return Collections.emptyList(); 21 | } 22 | 23 | @Override 24 | public List> createJSModules() { 25 | return Collections.emptyList(); 26 | } 27 | 28 | @Override 29 | public List createViewManagers(ReactApplicationContext reactContext) { 30 | return Arrays.asList(new AnimationViewManager()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 SuperEVO 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /dist/animation-view.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author : zhangzhenyang 3 | * @description : 动画基础组件 4 | * @update : 2016-07-24 17:35:49 5 | */ 6 | import * as React from 'react'; 7 | import { AnimationModel } from './animation-model'; 8 | export interface PropsDefine { 9 | /** 动画数据 */ 10 | data: AnimationModel[]; 11 | style?: React.ViewStyle; 12 | /** 是否自动播放 */ 13 | autoplay?: boolean; 14 | /** 是否数据变更时自动清除动画 */ 15 | autoclear?: boolean; 16 | /** 开始播放动画回调 */ 17 | onStart?: (view: AnimationView) => void; 18 | /** 结束播放动画回调 */ 19 | onEnd?: (view: AnimationView) => void; 20 | /** 取消播放动画回调 */ 21 | onCancel?: (view: AnimationView) => void; 22 | /** 动画循环回调 */ 23 | onRepeat?: (view: AnimationView) => void; 24 | } 25 | export declare class AnimationView extends React.Component { 26 | private _root; 27 | private _screen_scale; 28 | private isStart; 29 | private data; 30 | private isUnmount; 31 | constructor(props: PropsDefine, context: any); 32 | start(): boolean; 33 | clear(): void; 34 | add(data?: AnimationModel[]): void; 35 | componentWillMount(): void; 36 | componentDidMount(): void; 37 | componentWillUnmount(): void; 38 | componentWillReceiveProps(nextProps: PropsDefine): void; 39 | onAnimationStart(): void; 40 | onAnimationEnd(): void; 41 | onAnimationCancel(): void; 42 | onAnimationRepeat(): void; 43 | render(): JSX.Element; 44 | private _assignRoot(component); 45 | private setNativeProps(nativeProps); 46 | private processData(oriData); 47 | } 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-animation 2 | A native animation UI component for react-native. 3 | (Recently, we will refactor and optimize this.) 4 | 5 | ## Install 6 | 7 | ```sh 8 | npm i react-native-animation --save 9 | ``` 10 | 11 | ### iOS 12 | `Podfile` add 13 | ``` 14 | pod 'react-native-animation', :path => '../node_modules/react-native-animation' 15 | ``` 16 | 17 | ### Android 18 | `settings.gradle` add 19 | ``` 20 | include ':react-native-animation' 21 | project(':react-native-animation').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-animation/android') 22 | ``` 23 | 24 | ## Usage 25 | A simple example:(fade in) 26 | ``` jsx 27 | 34 | other views... 35 | 36 | ``` 37 | 38 | *Now support: 'Translate' | 'Rotate' | 'Scale' | 'Alpha' 39 | 40 | ## Props 41 | ``` typescript 42 | export interface PropsDefine { 43 | data: AnimationModel[] 44 | style?: React.ViewStyle 45 | autoplay?: boolean 46 | autoclear?: boolean 47 | onStart?: (view: AnimationView) => void 48 | onEnd?: (view: AnimationView) => void 49 | } 50 | ``` 51 | 52 | ## methods 53 | ``` 54 | start() 55 | clear() 56 | ``` 57 | 58 | ## AnimationModel 59 | ``` typescript 60 | export interface AnimationModel { 61 | name?: string 62 | type: 'Translate' | 'Rotate' | 'Scale' | 'Alpha' 63 | from?: number 64 | to?: number 65 | from2?: number 66 | to2?: number 67 | duration: number 68 | startOffset?: number 69 | interpolator?: 'Linear' 70 | interpolatorData?: number 71 | repeat?: number 72 | } 73 | ``` -------------------------------------------------------------------------------- /android/src/main/java/com/baidu/wefan/AnimationEvent.java: -------------------------------------------------------------------------------- 1 | package com.baidu.wefan; 2 | 3 | import android.support.annotation.IntDef; 4 | 5 | import com.facebook.react.bridge.WritableMap; 6 | import com.facebook.react.uimanager.events.Event; 7 | import com.facebook.react.uimanager.events.RCTEventEmitter; 8 | 9 | import java.lang.annotation.Retention; 10 | import java.lang.annotation.RetentionPolicy; 11 | 12 | /** 13 | * Created by zzy on 2016/11/3. 14 | */ 15 | 16 | public class AnimationEvent extends Event { 17 | @IntDef({ 18 | ON_ANIMATION_START, ON_ANIMATION_END, ON_ANIMATION_CANCEL, ON_ANIMATION_REPEAT 19 | }) 20 | @Retention(RetentionPolicy.SOURCE) 21 | @interface AnimationEventType { 22 | } 23 | 24 | public static final int ON_ANIMATION_START = 1; 25 | public static final int ON_ANIMATION_END = 2; 26 | public static final int ON_ANIMATION_CANCEL = 3; 27 | public static final int ON_ANIMATION_REPEAT = 4; 28 | 29 | private final int mEventType; 30 | 31 | public AnimationEvent(int viewTag, int eventType) { 32 | super(viewTag); 33 | this.mEventType = eventType; 34 | } 35 | 36 | public static String eventNameForType(@AnimationEventType int eventType) { 37 | switch (eventType) { 38 | case ON_ANIMATION_START: 39 | return "topAnimationStart"; 40 | case ON_ANIMATION_END: 41 | return "topAnimationEnd"; 42 | case ON_ANIMATION_CANCEL: 43 | return "topAnimationCancel"; 44 | case ON_ANIMATION_REPEAT: 45 | return "topAnimationRepeat"; 46 | default: 47 | throw new IllegalStateException("Invalid animation event:" + Integer.toString(eventType)); 48 | } 49 | } 50 | 51 | @Override 52 | public String getEventName() { 53 | return AnimationEvent.eventNameForType(mEventType); 54 | } 55 | 56 | @Override 57 | public void dispatch(RCTEventEmitter rctEventEmitter) { 58 | WritableMap eventData = null; 59 | rctEventEmitter.receiveEvent(getViewTag(), getEventName(), eventData); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /ios/TBNAnimationViewManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // TBNAnimationView.m 3 | // TogetherHi 4 | // 5 | // Created by zzy@baidu on 16/7/12. 6 | // Copyright © 2016年 Baidu. All rights reserved. 7 | // 8 | 9 | #import "TBNAnimationViewManager.h" 10 | #import "RCTBridge.h" 11 | #import 12 | #import "TBNAnimationView.h" 13 | #import "RCTUIManager.h" 14 | 15 | @implementation TBNAnimationViewManager 16 | 17 | RCT_EXPORT_MODULE(); 18 | 19 | RCT_EXPORT_VIEW_PROPERTY(onAnimationStart, RCTDirectEventBlock) 20 | RCT_EXPORT_VIEW_PROPERTY(onAnimationEnd, RCTDirectEventBlock) 21 | RCT_EXPORT_VIEW_PROPERTY(onAnimationCancel, RCTDirectEventBlock) 22 | RCT_EXPORT_VIEW_PROPERTY(onAnimationRepeat, RCTDirectEventBlock) 23 | 24 | @synthesize bridge = _bridge; 25 | 26 | - (UIView *)view 27 | { 28 | return [[TBNAnimationView alloc] init]; 29 | } 30 | 31 | - (NSArray *)customDirectEventTypes 32 | { 33 | return @[ 34 | @"onAnimationStart", 35 | @"onAnimationEnd", 36 | @"onAnimationRepeat", 37 | ]; 38 | } 39 | 40 | - (dispatch_queue_t)methodQueue 41 | { 42 | return dispatch_get_main_queue(); 43 | } 44 | 45 | 46 | RCT_EXPORT_METHOD(add:(nonnull NSNumber *)reactTag 47 | data:data) 48 | { 49 | [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) { 50 | TBNAnimationView *view = viewRegistry[reactTag]; 51 | if (![view isKindOfClass:[TBNAnimationView class]]) { 52 | // RCTLogError(@"Invalid view returned from registry, expecting TBNAnimationView, got: %@", view); 53 | } else { 54 | [view add:data]; 55 | } 56 | }]; 57 | } 58 | 59 | RCT_EXPORT_METHOD(clear:(nonnull NSNumber *)reactTag) 60 | { 61 | [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) { 62 | TBNAnimationView *view = viewRegistry[reactTag]; 63 | if (![view isKindOfClass:[TBNAnimationView class]]) { 64 | // RCTLogError(@"Invalid view returned from registry, expecting TBNAnimationView, got: %@", view); 65 | } else { 66 | [view clear]; 67 | } 68 | }]; 69 | } 70 | 71 | RCT_EXPORT_METHOD(start:(nonnull NSNumber *)reactTag 72 | data:data) 73 | { 74 | [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) { 75 | TBNAnimationView *view = viewRegistry[reactTag]; 76 | if (![view isKindOfClass:[TBNAnimationView class]]) { 77 | RCTLogError(@"Invalid view returned from registry, expecting TBNAnimationView, got: %@", view); 78 | } else { 79 | [view start:data]; 80 | } 81 | }]; 82 | } 83 | 84 | @end 85 | -------------------------------------------------------------------------------- /dist/immutableRenderDecorator.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"immutableRenderDecorator.js","sourceRoot":"C:/WorkSpaces/Web/react-native-animation/src/","sources":["immutableRenderDecorator.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/immutableRenderDecorator.js: -------------------------------------------------------------------------------- 1 | let whiteList = [ 2 | '[IndexPage]' 3 | ]; 4 | export default function immutableRenderDecorator(Target) { 5 | class ImmutableRenderDecorator extends Target { 6 | shallowEqualImmutable(preObj, nxtObj) { 7 | if (preObj === nxtObj) { 8 | return true; 9 | } 10 | // FIX: values may be null 11 | if (typeof preObj !== 'object' || preObj == void 0 || 12 | typeof nxtObj !== 'object' || nxtObj == void 0) { 13 | return false; 14 | } 15 | const preKey = Object.keys(preObj); 16 | const nxtKey = Object.keys(nxtObj); 17 | if (preKey.length !== nxtKey.length) { 18 | return false; 19 | } 20 | for (let i = 0; i < nxtKey.length; i++) { 21 | if (nxtObj[nxtKey[i]] instanceof Function && preObj[nxtKey[i]] instanceof Function) { 22 | continue; 23 | } 24 | if (nxtObj[nxtKey[i]] !== preObj[nxtKey[i]]) { 25 | return false; 26 | } 27 | } 28 | return true; 29 | } 30 | type() { 31 | return Target.toString().match(/\w+/g)[1]; 32 | } 33 | compare(preObj, nxtObj, before) { 34 | if (nxtObj instanceof Object || nxtObj instanceof Array) { 35 | for (let key in nxtObj) { 36 | if (nxtObj.hasOwnProperty(key)) { 37 | let iseq = !!preObj && !!nxtObj && preObj[key] === nxtObj[key]; 38 | if (preObj[key] instanceof Function && nxtObj[key] instanceof Function) { 39 | iseq = undefined; 40 | } 41 | let str = before + '.' + key; 42 | if (iseq) { 43 | console.log(str, iseq); 44 | } 45 | else { 46 | console.info(str, iseq); 47 | } 48 | } 49 | if (preObj instanceof Object || preObj instanceof Array) { 50 | this.compare(preObj[key], nxtObj[key], before + '.' + key); 51 | } 52 | } 53 | } 54 | } 55 | shouldComponentUpdate(nextProps, nextState, context) { 56 | if (super.shouldComponentUpdate) { 57 | return super.shouldComponentUpdate(nextProps, nextState, context); 58 | } 59 | let update = !this.shallowEqualImmutable(this.props, nextProps) || 60 | !this.shallowEqualImmutable(this.state, nextState); 61 | let type = this.type(); 62 | if (whiteList.length > 0 && whiteList.indexOf(type) > -1) { 63 | console.log('immutableRenderDecorator', type, 'update?', update); 64 | console.log('equle?:', 'props:', nextProps === this.props, 'state:', nextState === this.state, 'shallowEqualImmutable?:', 'props:', this.shallowEqualImmutable(this.props, nextProps), 'state:', this.shallowEqualImmutable(this.state, nextState)); 65 | this.compare(this.props, nextProps, 'props'); 66 | } 67 | return update; 68 | } 69 | } 70 | return ImmutableRenderDecorator; 71 | } 72 | //# sourceMappingURL=immutableRenderDecorator.js.map -------------------------------------------------------------------------------- /src/immutableRenderDecorator.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | let whiteList = [ 4 | '[IndexPage]' 5 | ] 6 | 7 | export default function immutableRenderDecorator(Target: React.ComponentClass): any { 8 | class ImmutableRenderDecorator extends Target { 9 | shallowEqualImmutable(preObj: any, nxtObj: any) { 10 | if (preObj === nxtObj) { 11 | return true 12 | } 13 | 14 | // FIX: values may be null 15 | if (typeof preObj !== 'object' || preObj == void 0 || 16 | typeof nxtObj !== 'object' || nxtObj == void 0) { 17 | return false 18 | } 19 | 20 | const preKey = Object.keys(preObj) 21 | const nxtKey = Object.keys(nxtObj) 22 | 23 | if (preKey.length !== nxtKey.length) { 24 | return false 25 | } 26 | 27 | for (let i = 0; i < nxtKey.length; i++) { 28 | if (nxtObj[nxtKey[i]] instanceof Function && preObj[nxtKey[i]] instanceof Function) { 29 | continue 30 | } 31 | if (nxtObj[nxtKey[i]] !== preObj[nxtKey[i]]) { 32 | return false 33 | } 34 | } 35 | return true 36 | } 37 | 38 | type() { 39 | return Target.toString().match(/\w+/g)[1] 40 | } 41 | 42 | compare(preObj: any, nxtObj: any, before: string) { 43 | if (nxtObj instanceof Object || nxtObj instanceof Array) { 44 | for (let key in nxtObj) { 45 | if (nxtObj.hasOwnProperty(key)) { 46 | let iseq = !!preObj && !!nxtObj && preObj[key] === nxtObj[key] 47 | if (preObj[key] instanceof Function && nxtObj[key] instanceof Function) { 48 | iseq = undefined 49 | } 50 | let str = before + '.' + key 51 | if (iseq) { 52 | console.log(str, iseq) 53 | } else { 54 | console.info(str, iseq) 55 | } 56 | } 57 | if (preObj instanceof Object || preObj instanceof Array) { 58 | this.compare(preObj[key], nxtObj[key], before + '.' + key) 59 | } 60 | } 61 | } 62 | } 63 | 64 | shouldComponentUpdate(nextProps: any, nextState: any, context: any) { 65 | if (super.shouldComponentUpdate) { 66 | return super.shouldComponentUpdate(nextProps, nextState, context) 67 | } 68 | let update = !this.shallowEqualImmutable(this.props, nextProps) || 69 | !this.shallowEqualImmutable(this.state, nextState) 70 | let type = this.type() 71 | if (whiteList.length > 0 && whiteList.indexOf(type) > -1) { 72 | console.log('immutableRenderDecorator', type, 'update?', update) 73 | console.log('equle?:', 74 | 'props:', nextProps === this.props, 75 | 'state:', nextState === this.state, 76 | 'shallowEqualImmutable?:', 77 | 'props:', this.shallowEqualImmutable(this.props, nextProps), 78 | 'state:', this.shallowEqualImmutable(this.state, nextState) 79 | ) 80 | this.compare(this.props, nextProps, 'props') 81 | } 82 | return update 83 | } 84 | } 85 | return ImmutableRenderDecorator 86 | } 87 | -------------------------------------------------------------------------------- /android/src/main/java/com/baidu/wefan/AnimationViewManager.java: -------------------------------------------------------------------------------- 1 | package com.baidu.wefan; 2 | 3 | import com.facebook.react.animation.Animation; 4 | import com.facebook.react.bridge.JSApplicationIllegalArgumentException; 5 | import com.facebook.react.bridge.ReadableArray; 6 | import com.facebook.react.common.MapBuilder; 7 | import com.facebook.react.uimanager.ThemedReactContext; 8 | import com.facebook.react.uimanager.ViewGroupManager; 9 | import com.google.gson.Gson; 10 | 11 | import java.util.Map; 12 | 13 | import javax.annotation.Nullable; 14 | 15 | /** 16 | * Created by zzy on 2016/6/28. 17 | */ 18 | public class AnimationViewManager extends ViewGroupManager { 19 | public static final int COMMAND_START = 1; 20 | public static final int COMMAND_CLEAR = 2; 21 | public static final int COMMAND_ADD = 3; 22 | 23 | public static final String REACT_CLASS = "TBNAnimationView"; 24 | 25 | public static final Gson GSON = new Gson(); 26 | 27 | @Override 28 | public Map getCommandsMap() { 29 | return MapBuilder.of( 30 | "start", 31 | COMMAND_START, 32 | "clear", 33 | COMMAND_CLEAR, 34 | "add", 35 | COMMAND_ADD 36 | ); 37 | } 38 | 39 | @Override 40 | public void receiveCommand(TBNAnimationView root, int commandId, @Nullable ReadableArray args) { 41 | // System.out.println("~~~~~~~~~TBNAnimationView~~~receiveCommand~~~~~~~~~~~~~"); 42 | switch (commandId) { 43 | case COMMAND_START: { 44 | if (args == null || args.size() != 1) { 45 | throw new JSApplicationIllegalArgumentException( 46 | "Illegal number of arguments for 'COMMAND_START' command"); 47 | } 48 | String data = args.getString(0); 49 | // System.out.println("START:" + data); 50 | root.addAnimators(GSON.fromJson(data, AnimationModel[].class)); 51 | // root.addAnimations(GSON.fromJson(data, AnimationModel[].class)); 52 | root.start(); 53 | break; 54 | } 55 | case COMMAND_CLEAR: { 56 | if (args == null || args.size() != 0) { 57 | throw new JSApplicationIllegalArgumentException( 58 | "Illegal number of arguments for 'COMMAND_CLEAR' command"); 59 | } 60 | root.clear(); 61 | break; 62 | } 63 | case COMMAND_ADD: { 64 | if (args == null || args.size() != 1) { 65 | throw new JSApplicationIllegalArgumentException( 66 | "Illegal number of arguments for 'COMMAND_ADD' command"); 67 | } 68 | String data = args.getString(0); 69 | root.addAnimators(GSON.fromJson(data, AnimationModel[].class)); 70 | // root.addAnimations(GSON.fromJson(data, AnimationModel[].class)); 71 | break; 72 | } 73 | } 74 | } 75 | 76 | @Nullable 77 | @Override 78 | public Map getExportedCustomDirectEventTypeConstants() { 79 | return MapBuilder.of( 80 | AnimationEvent.eventNameForType(AnimationEvent.ON_ANIMATION_START), 81 | MapBuilder.of("registrationName", "onAnimationStart"), 82 | AnimationEvent.eventNameForType(AnimationEvent.ON_ANIMATION_END), 83 | MapBuilder.of("registrationName", "onAnimationEnd"), 84 | AnimationEvent.eventNameForType(AnimationEvent.ON_ANIMATION_CANCEL), 85 | MapBuilder.of("registrationName", "onAnimationCancel"), 86 | AnimationEvent.eventNameForType(AnimationEvent.ON_ANIMATION_REPEAT), 87 | MapBuilder.of("registrationName", "onAnimationRepeat") 88 | ); 89 | } 90 | 91 | @Override 92 | public String getName() { 93 | return REACT_CLASS; 94 | } 95 | 96 | @Override 97 | protected TBNAnimationView createViewInstance(ThemedReactContext context) { 98 | return new TBNAnimationView(context); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /ios/TBNAnimationView.m: -------------------------------------------------------------------------------- 1 | // 2 | // TBNAnimationView.m 3 | // TogetherHi 4 | // 5 | // Created by zzy@baidu on 16/7/12. 6 | // Copyright © 2016年 Baidu. All rights reserved. 7 | // 8 | 9 | #import "RCTViewManager.h" 10 | #import "TBNAnimationView.h" 11 | 12 | @interface TBNAnimationView() 13 | 14 | @property (nonatomic, copy) RCTDirectEventBlock onAnimationStart; 15 | @property (nonatomic, copy) RCTDirectEventBlock onAnimationEnd; 16 | @property (nonatomic, copy) RCTDirectEventBlock onAnimationCancel; 17 | @property (nonatomic, copy) RCTDirectEventBlock onAnimationRepeat; 18 | 19 | @end 20 | 21 | @implementation TBNAnimationView 22 | 23 | id _data; 24 | 25 | 26 | - (UIView *)view 27 | { 28 | return [[UIView alloc] init]; 29 | } 30 | 31 | - (void)add:data 32 | { 33 | _data = data; 34 | } 35 | 36 | -(void)setAniValue :key :(float)startOffset :(float)duration :(float)repeat :from :to 37 | { 38 | // NSLog(@"%@", str); 39 | CABasicAnimation *theAnimation; 40 | theAnimation = [CABasicAnimation animationWithKeyPath:key]; 41 | theAnimation.fromValue = from; 42 | theAnimation.toValue = to; 43 | theAnimation.delegate = self; 44 | theAnimation.beginTime = startOffset; 45 | theAnimation.duration = duration; 46 | theAnimation.repeatCount = repeat; 47 | theAnimation.removedOnCompletion = FALSE; 48 | theAnimation.fillMode = kCAFillModeForwards; 49 | theAnimation.autoreverses = NO; 50 | theAnimation.cumulative = NO; 51 | theAnimation.timingFunction=[CAMediaTimingFunction functionWithName:kCAFilterLinear]; 52 | [self.layer addAnimation:theAnimation forKey:nil]; 53 | } 54 | 55 | - (void)start:data 56 | { 57 | id aniData = data ? data : _data; 58 | for (NSDictionary* str in aniData) { 59 | NSTimeInterval duration = [str[@"duration"] doubleValue] / 1000; 60 | NSTimeInterval repeat = [str[@"repeat"] integerValue]; 61 | NSTimeInterval startOffset = CACurrentMediaTime() + [str[@"startOffset"] doubleValue] / 1000; 62 | 63 | 64 | NSString *type = str[@"type"]; // 'translate' | 'Rotate' | 'Scale' | 'Alpha' 65 | 66 | if([type isEqual: @"Translate"]){ 67 | [self setAniValue:@"transform.translation.x" :startOffset :duration :repeat :str[@"from"] :str[@"to"]]; 68 | [self setAniValue:@"transform.translation.y" :startOffset :duration :repeat :str[@"from2"] :str[@"to2"]]; 69 | [self setAniValue:@"transform.translation.z" :startOffset :duration :repeat :str[@"from3"] :str[@"to3"]]; 70 | } 71 | 72 | if([type isEqual: @"Rotate"]){ 73 | [self setAniValue:@"transform.rotation.x" :startOffset :duration :repeat :str[@"from"] :str[@"to"]]; 74 | [self setAniValue:@"transform.rotation.y" :startOffset :duration :repeat :str[@"from2"] :str[@"to2"]]; 75 | [self setAniValue:@"transform.rotation.z" :startOffset :duration :repeat :str[@"from3"] :str[@"to3"]]; 76 | } 77 | 78 | if([type isEqual: @"Scale"]){ 79 | [self setAniValue:@"transform.scale.x" :startOffset :duration :repeat :str[@"from"] :str[@"to"]]; 80 | [self setAniValue:@"transform.scale.y" :startOffset :duration :repeat :str[@"from2"] :str[@"to2"]]; 81 | [self setAniValue:@"transform.scale.z" :startOffset :duration :repeat :str[@"from3"] :str[@"to3"]]; 82 | } 83 | 84 | if([type isEqual: @"Alpha"]){ 85 | [self setAniValue:@"opacity" :startOffset :duration :repeat :str[@"from"] :str[@"to"]]; 86 | } 87 | } 88 | } 89 | 90 | /* Called when the animation begins its active duration. */ 91 | 92 | - (void)animationDidStart:(CAAnimation *)anim 93 | { 94 | if(_onAnimationStart){ 95 | _onAnimationStart(nil); 96 | } 97 | } 98 | 99 | /* Called when the animation either completes its active duration or 100 | * is removed from the object it is attached to (i.e. the layer). 'flag' 101 | * is true if the animation reached the end of its active duration 102 | * without being removed. */ 103 | 104 | - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag 105 | { 106 | if(flag){ 107 | if(_onAnimationEnd){ 108 | _onAnimationEnd(nil); 109 | } 110 | }else{ 111 | if(_onAnimationCancel){ 112 | _onAnimationCancel(nil); 113 | } 114 | } 115 | } 116 | 117 | - (void)clear 118 | { 119 | [self.layer removeAllAnimations]; 120 | } 121 | 122 | @end 123 | -------------------------------------------------------------------------------- /dist/animation-view.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"animation-view.js","sourceRoot":"C:/WorkSpaces/Web/react-native-animation/src/","sources":["animation-view.tsx"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /android/src/main/java/com/baidu/wefan/TBNAnimationView.java: -------------------------------------------------------------------------------- 1 | package com.baidu.wefan; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorSet; 5 | import android.animation.ObjectAnimator; 6 | import android.animation.PropertyValuesHolder; 7 | import android.content.Context; 8 | import android.view.MotionEvent; 9 | import android.view.ViewGroup; 10 | import android.view.animation.AlphaAnimation; 11 | import android.view.animation.Animation; 12 | import android.view.animation.AnimationSet; 13 | import android.view.animation.LinearInterpolator; 14 | import android.view.animation.RotateAnimation; 15 | import android.view.animation.ScaleAnimation; 16 | import android.view.animation.TranslateAnimation; 17 | 18 | import com.facebook.react.bridge.Arguments; 19 | import com.facebook.react.bridge.ReactContext; 20 | import com.facebook.react.bridge.WritableMap; 21 | import com.facebook.react.uimanager.UIManagerModule; 22 | import com.facebook.react.uimanager.events.RCTEventEmitter; 23 | 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | 27 | /** 28 | * Created by zzy on 2016/6/28. 29 | */ 30 | public class TBNAnimationView extends ViewGroup { 31 | AnimationSet animationSet; 32 | AnimatorSet animatorSet; 33 | 34 | public TBNAnimationView(Context context) { 35 | super(context); 36 | } 37 | 38 | public void clear() { 39 | // this.clearAnimation(); 40 | if (animatorSet != null) { 41 | animatorSet.cancel(); 42 | } 43 | } 44 | 45 | public void start() { 46 | if (animatorSet != null) { 47 | // this.startAnimation(animationSet); 48 | animatorSet.start(); 49 | } 50 | } 51 | 52 | @Override 53 | public boolean onTouchEvent(MotionEvent ev) { 54 | return super.onTouchEvent(ev); 55 | } 56 | 57 | @Override 58 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 59 | // No-op since UIManagerModule handles actually laying out children. 60 | } 61 | 62 | public void addAnimators(AnimationModel[] data) { 63 | animatorSet = new AnimatorSet(); 64 | List animators = new ArrayList<>(); 65 | for (AnimationModel m : data) { 66 | ObjectAnimator animator = null; 67 | switch (m.type) { 68 | case Translate: 69 | PropertyValuesHolder tranX = PropertyValuesHolder.ofFloat("translationX", m.from, m.to); 70 | PropertyValuesHolder tranY = PropertyValuesHolder.ofFloat("translationY", m.from2, m.to2); 71 | PropertyValuesHolder tranZ = PropertyValuesHolder.ofFloat("translationZ", m.from3, m.to3); 72 | animator = ObjectAnimator.ofPropertyValuesHolder(this, tranX, tranY, tranZ); 73 | break; 74 | case Rotate: 75 | PropertyValuesHolder rotaX = PropertyValuesHolder.ofFloat("rotationX", m.from, m.to); 76 | PropertyValuesHolder rotaY = PropertyValuesHolder.ofFloat("rotationY", m.from2, m.to2); 77 | PropertyValuesHolder rotaZ = PropertyValuesHolder.ofFloat("rotation", m.from3, m.to3); 78 | animator = ObjectAnimator.ofPropertyValuesHolder(this, rotaX, rotaY, rotaZ); 79 | break; 80 | case Scale: 81 | PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", m.from, m.to); 82 | PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", m.from2, m.to2); 83 | PropertyValuesHolder scaleZ = PropertyValuesHolder.ofFloat("scaleZ", m.from3, m.to3); 84 | animator = ObjectAnimator.ofPropertyValuesHolder(this, scaleX, scaleY, scaleZ); 85 | break; 86 | case Alpha: 87 | animator = ObjectAnimator.ofFloat(this, "alpha", m.from, m.to); 88 | break; 89 | default: 90 | break; 91 | } 92 | 93 | if (animator == null) { 94 | continue; 95 | } 96 | animator.setDuration(m.duration); 97 | animator.setInterpolator(new LinearInterpolator()); 98 | animator.setRepeatCount(m.repeat); 99 | animator.setStartDelay(m.startOffset); 100 | animators.add(animator); 101 | } 102 | animatorSet.addListener(new Animator.AnimatorListener() { 103 | @Override 104 | public void onAnimationStart(Animator animation) { 105 | // onReceiveNativeEvent("onAnimationStart"); 106 | onReceiveNativeEvent(new AnimationEvent( 107 | getId(), 108 | AnimationEvent.ON_ANIMATION_START 109 | )); 110 | } 111 | 112 | @Override 113 | public void onAnimationEnd(Animator animation) { 114 | // onReceiveNativeEvent("onAnimationEnd"); 115 | onReceiveNativeEvent(new AnimationEvent( 116 | getId(), 117 | AnimationEvent.ON_ANIMATION_END 118 | )); 119 | } 120 | 121 | @Override 122 | public void onAnimationCancel(Animator animation) { 123 | // onReceiveNativeEvent("onAnimationCancel"); 124 | onReceiveNativeEvent(new AnimationEvent( 125 | getId(), 126 | AnimationEvent.ON_ANIMATION_CANCEL 127 | )); 128 | } 129 | 130 | @Override 131 | public void onAnimationRepeat(Animator animation) { 132 | // onReceiveNativeEvent("onAnimationRepeat"); 133 | onReceiveNativeEvent(new AnimationEvent( 134 | getId(), 135 | AnimationEvent.ON_ANIMATION_REPEAT 136 | )); 137 | } 138 | }); 139 | 140 | animatorSet.playTogether(animators); 141 | } 142 | 143 | public void onReceiveNativeEvent(AnimationEvent event) { 144 | ReactContext reactContext = (ReactContext) getContext(); 145 | reactContext.getNativeModule(UIManagerModule.class) 146 | .getEventDispatcher() 147 | .dispatchEvent(event); 148 | } 149 | 150 | } 151 | -------------------------------------------------------------------------------- /dist/animation-view.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author : zhangzhenyang 3 | * @description : 动画基础组件 4 | * @update : 2016-07-24 17:35:49 5 | */ 6 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 7 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 8 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 9 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 10 | return c > 3 && r && Object.defineProperty(target, key, r), r; 11 | }; 12 | import * as React from 'react'; 13 | import { Dimensions, findNodeHandle, UIManager, requireNativeComponent, Platform, } from 'react-native'; 14 | import immutableRenderDecorator from './immutableRenderDecorator'; 15 | const TBNAnimationView = requireNativeComponent('TBNAnimationView', AnimationView, { 16 | nativeOnly: { 17 | onAnimationStart: true, 18 | onAnimationEnd: true, 19 | onAnimationCancel: true, 20 | onAnimationRepeat: true, 21 | } 22 | }); 23 | let AnimationView = class AnimationView extends React.Component { 24 | constructor(props, context) { 25 | super(props, context); 26 | this._screen_scale = Dimensions.get('window').scale; 27 | this.isUnmount = false; 28 | this._assignRoot = this._assignRoot.bind(this); 29 | this.isStart = false; 30 | this.data = this.processData(props.data); 31 | } 32 | start() { 33 | if (this.isUnmount) { 34 | return false; 35 | } 36 | UIManager.dispatchViewManagerCommand(findNodeHandle(this), UIManager.TBNAnimationView.Commands.start, [Platform.OS === 'android' ? JSON.stringify(this.data || []) : this.data]); 37 | this.isStart = true; 38 | } 39 | clear() { 40 | try { 41 | UIManager.dispatchViewManagerCommand(findNodeHandle(this), UIManager.TBNAnimationView.Commands.clear, []); 42 | } 43 | catch (error) { 44 | } 45 | this.isStart = false; 46 | } 47 | add(data) { 48 | if (data) { 49 | this.data = this.processData(data); 50 | } 51 | // UIManager.dispatchViewManagerCommand( 52 | // findNodeHandle(this), 53 | // UIManager.TBNAnimationView.Commands.add, 54 | // [data || this.data] 55 | // // [JSON.stringify(this.data || data)] 56 | // ) 57 | } 58 | componentWillMount() { 59 | } 60 | componentDidMount() { 61 | this.add(); 62 | if (this.props.autoplay) { 63 | this.start(); 64 | } 65 | } 66 | componentWillUnmount() { 67 | this.isUnmount = true; 68 | this.clear(); 69 | } 70 | componentWillReceiveProps(nextProps) { 71 | if (nextProps !== this.props 72 | && nextProps.data !== this.props.data) { 73 | if (nextProps.autoclear) { 74 | this.clear(); 75 | } 76 | this.data = this.processData(nextProps.data); 77 | this.add(); 78 | if (this.props.autoplay) { 79 | setTimeout(() => { 80 | this.start(); 81 | }, 0); 82 | } 83 | } 84 | } 85 | onAnimationStart() { 86 | this.props.onStart && this.props.onStart(this); 87 | } 88 | onAnimationEnd() { 89 | this.props.onEnd && this.props.onEnd(this); 90 | } 91 | onAnimationCancel() { 92 | this.props.onCancel && this.props.onCancel(this); 93 | } 94 | onAnimationRepeat() { 95 | this.props.onRepeat && this.props.onRepeat(this); 96 | } 97 | render() { 98 | return (React.createElement(TBNAnimationView, { ref: this._assignRoot, style: this.props.style, onAnimationStart: this.onAnimationStart.bind(this), onAnimationEnd: this.onAnimationEnd.bind(this), onAnimationCancel: this.onAnimationCancel.bind(this), onAnimationRepeat: this.onAnimationRepeat.bind(this) }, this.props.children)); 99 | } 100 | _assignRoot(component) { 101 | this._root = component; 102 | } 103 | setNativeProps(nativeProps) { 104 | this._root.setNativeProps(nativeProps); 105 | } 106 | processData(oriData) { 107 | let data = (oriData || []).slice(); 108 | data.forEach((ani) => { 109 | if (ani.duration) { 110 | ani.duration = parseInt(ani.duration.toFixed(0)); 111 | } 112 | if (ani.startOffset) { 113 | ani.startOffset = parseInt(ani.startOffset.toFixed(0)); 114 | } 115 | if (Platform.OS === 'android') { 116 | ani.from = ani.from || 0; 117 | ani.to = ani.to || 0; 118 | ani.from2 = ani.from2 || 0; 119 | ani.to2 = ani.to2 || 0; 120 | ani.from3 = ani.from3 || 0; 121 | ani.to3 = ani.to3 || 0; 122 | switch (ani.type) { 123 | case 'Translate': 124 | if (ani.from) { 125 | ani.from *= this._screen_scale; 126 | } 127 | if (ani.to) { 128 | ani.to *= this._screen_scale; 129 | } 130 | if (ani.from2) { 131 | ani.from2 *= this._screen_scale; 132 | } 133 | if (ani.to2) { 134 | ani.to2 *= this._screen_scale; 135 | } 136 | if (ani.from3) { 137 | ani.from3 *= this._screen_scale; 138 | } 139 | if (ani.to3) { 140 | ani.to3 *= this._screen_scale; 141 | } 142 | break; 143 | } 144 | } 145 | else if (Platform.OS === 'ios') { 146 | switch (ani.type) { 147 | case 'Rotate': 148 | if (ani.from) { 149 | ani.from /= (180 / Math.PI); 150 | } 151 | if (ani.to) { 152 | ani.to /= (180 / Math.PI); 153 | } 154 | if (ani.from2) { 155 | ani.from2 /= (180 / Math.PI); 156 | } 157 | if (ani.to2) { 158 | ani.to2 /= (180 / Math.PI); 159 | } 160 | if (ani.from3) { 161 | ani.from3 /= (180 / Math.PI); 162 | } 163 | if (ani.to3) { 164 | ani.to3 /= (180 / Math.PI); 165 | } 166 | break; 167 | } 168 | } 169 | }); 170 | return data; 171 | } 172 | }; 173 | AnimationView = __decorate([ 174 | immutableRenderDecorator 175 | ], AnimationView); 176 | export { AnimationView }; 177 | //# sourceMappingURL=animation-view.js.map -------------------------------------------------------------------------------- /src/animation-view.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author : zhangzhenyang 3 | * @description : 动画基础组件 4 | * @update : 2016-07-24 17:35:49 5 | */ 6 | 7 | import * as React from 'react' 8 | import { 9 | DeviceEventEmitter, 10 | Dimensions, 11 | findNodeHandle, 12 | UIManager, 13 | requireNativeComponent, 14 | Platform, 15 | } from 'react-native' 16 | import immutableRenderDecorator from './immutableRenderDecorator' 17 | import { AnimationModel, AnimationGroup } from './animation-model' 18 | 19 | const TBNAnimationView = requireNativeComponent('TBNAnimationView', AnimationView, { 20 | nativeOnly: { 21 | onAnimationStart: true, 22 | onAnimationEnd: true, 23 | onAnimationCancel: true, 24 | onAnimationRepeat: true, 25 | } 26 | }) 27 | 28 | export interface PropsDefine { 29 | /** 动画数据 */ 30 | data: AnimationModel[] 31 | style?: React.ViewStyle 32 | /** 是否自动播放 */ 33 | autoplay?: boolean 34 | /** 是否数据变更时自动清除动画 */ 35 | autoclear?: boolean 36 | /** 开始播放动画回调 */ 37 | onStart?: (view: AnimationView) => void 38 | /** 结束播放动画回调 */ 39 | onEnd?: (view: AnimationView) => void 40 | /** 取消播放动画回调 */ 41 | onCancel?: (view: AnimationView) => void 42 | /** 动画循环回调 */ 43 | onRepeat?: (view: AnimationView) => void 44 | } 45 | @immutableRenderDecorator 46 | export class AnimationView extends React.Component { 47 | private _root: AnimationView 48 | private _screen_scale = Dimensions.get('window').scale 49 | private isStart: boolean 50 | private data: AnimationModel[] 51 | private isUnmount = false 52 | 53 | constructor(props: PropsDefine, context: any) { 54 | super(props, context) 55 | 56 | this._assignRoot = this._assignRoot.bind(this) 57 | this.isStart = false 58 | this.data = this.processData(props.data) 59 | } 60 | 61 | public start() { 62 | if (this.isUnmount) { 63 | return false 64 | } 65 | UIManager.dispatchViewManagerCommand( 66 | findNodeHandle(this), 67 | UIManager.TBNAnimationView.Commands.start, 68 | [Platform.OS === 'android' ? JSON.stringify(this.data || []) : this.data] 69 | ) 70 | this.isStart = true 71 | } 72 | 73 | public clear() { 74 | try { 75 | UIManager.dispatchViewManagerCommand( 76 | findNodeHandle(this), 77 | UIManager.TBNAnimationView.Commands.clear, 78 | [] 79 | ) 80 | } catch (error) { 81 | } 82 | this.isStart = false 83 | } 84 | 85 | public add(data?: AnimationModel[]) { 86 | if (data) { 87 | this.data = this.processData(data) 88 | } 89 | // UIManager.dispatchViewManagerCommand( 90 | // findNodeHandle(this), 91 | // UIManager.TBNAnimationView.Commands.add, 92 | // [data || this.data] 93 | // // [JSON.stringify(this.data || data)] 94 | // ) 95 | } 96 | 97 | componentWillMount() { 98 | } 99 | 100 | componentDidMount() { 101 | this.add() 102 | if (this.props.autoplay) { 103 | this.start() 104 | } 105 | } 106 | 107 | componentWillUnmount() { 108 | this.isUnmount = true 109 | this.clear() 110 | } 111 | 112 | componentWillReceiveProps(nextProps: PropsDefine) { 113 | if (nextProps !== this.props 114 | && nextProps.data !== this.props.data) { 115 | if (nextProps.autoclear) { 116 | this.clear() 117 | } 118 | 119 | this.data = this.processData(nextProps.data) 120 | this.add() 121 | if (this.props.autoplay) { 122 | setTimeout(() => { 123 | this.start() 124 | }, 0) 125 | } 126 | } 127 | } 128 | 129 | onAnimationStart() { 130 | this.props.onStart && this.props.onStart(this) 131 | } 132 | 133 | onAnimationEnd() { 134 | this.props.onEnd && this.props.onEnd(this) 135 | } 136 | 137 | onAnimationCancel() { 138 | this.props.onCancel && this.props.onCancel(this) 139 | } 140 | 141 | onAnimationRepeat() { 142 | this.props.onRepeat && this.props.onRepeat(this) 143 | } 144 | 145 | render() { 146 | return ( 147 | 155 | {this.props.children} 156 | 157 | ) 158 | } 159 | 160 | private _assignRoot(component: AnimationView) { 161 | this._root = component 162 | } 163 | 164 | private setNativeProps(nativeProps: PropsDefine) { 165 | this._root.setNativeProps(nativeProps) 166 | } 167 | 168 | private processData(oriData: AnimationModel[]): AnimationModel[] { 169 | let data = (oriData || []).slice() 170 | data.forEach((ani) => { 171 | if (ani.duration) { 172 | ani.duration = parseInt(ani.duration.toFixed(0)) 173 | } 174 | if (ani.startOffset) { 175 | ani.startOffset = parseInt(ani.startOffset.toFixed(0)) 176 | } 177 | if (Platform.OS === 'android') { 178 | ani.from = ani.from || 0 179 | ani.to = ani.to || 0 180 | ani.from2 = ani.from2 || 0 181 | ani.to2 = ani.to2 || 0 182 | ani.from3 = ani.from3 || 0 183 | ani.to3 = ani.to3 || 0 184 | switch (ani.type) { 185 | case 'Translate': 186 | if (ani.from) { 187 | ani.from *= this._screen_scale 188 | } 189 | if (ani.to) { 190 | ani.to *= this._screen_scale 191 | } 192 | if (ani.from2) { 193 | ani.from2 *= this._screen_scale 194 | } 195 | if (ani.to2) { 196 | ani.to2 *= this._screen_scale 197 | } 198 | if (ani.from3) { 199 | ani.from3 *= this._screen_scale 200 | } 201 | if (ani.to3) { 202 | ani.to3 *= this._screen_scale 203 | } 204 | break 205 | } 206 | } else if (Platform.OS === 'ios') { 207 | switch (ani.type) { 208 | case 'Rotate': 209 | if (ani.from) { 210 | ani.from /= (180 / Math.PI) 211 | } 212 | if (ani.to) { 213 | ani.to /= (180 / Math.PI) 214 | } 215 | if (ani.from2) { 216 | ani.from2 /= (180 / Math.PI) 217 | } 218 | if (ani.to2) { 219 | ani.to2 /= (180 / Math.PI) 220 | } 221 | if (ani.from3) { 222 | ani.from3 /= (180 / Math.PI) 223 | } 224 | if (ani.to3) { 225 | ani.to3 /= (180 / Math.PI) 226 | } 227 | break 228 | } 229 | } 230 | }) 231 | return data 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /android/react-native-animation.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /typings/globals/react/index.d.ts: -------------------------------------------------------------------------------- 1 | // Generated by typings 2 | // Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/edcbaabb56bb0866df95dbfdf279f4a680051217/react/react.d.ts 3 | declare namespace __React { 4 | 5 | // 6 | // React Elements 7 | // ---------------------------------------------------------------------- 8 | 9 | type ReactType = string | ComponentClass | StatelessComponent; 10 | 11 | type Key = string | number; 12 | type Ref = string | ((instance: T) => any); 13 | type ComponentState = {} | void; 14 | 15 | interface Attributes { 16 | key?: Key; 17 | } 18 | interface ClassAttributes extends Attributes { 19 | ref?: Ref; 20 | } 21 | 22 | interface ReactElement

{ 23 | type: string | ComponentClass

| SFC

; 24 | props: P; 25 | key?: Key; 26 | } 27 | 28 | interface SFCElement

extends ReactElement

{ 29 | type: SFC

; 30 | } 31 | 32 | type CElement> = ComponentElement; 33 | interface ComponentElement> extends ReactElement

{ 34 | type: ComponentClass

; 35 | ref?: Ref; 36 | } 37 | 38 | type ClassicElement

= CElement>; 39 | 40 | interface DOMElement

extends ReactElement

{ 41 | type: string; 42 | ref: Ref; 43 | } 44 | 45 | interface ReactHTMLElement extends DOMElement { 46 | } 47 | 48 | interface ReactSVGElement extends DOMElement { 49 | } 50 | 51 | // 52 | // Factories 53 | // ---------------------------------------------------------------------- 54 | 55 | interface Factory

{ 56 | (props?: P & Attributes, ...children: ReactNode[]): ReactElement

; 57 | } 58 | 59 | interface SFCFactory

{ 60 | (props?: P & Attributes, ...children: ReactNode[]): SFCElement

; 61 | } 62 | 63 | interface ComponentFactory> { 64 | (props?: P & ClassAttributes, ...children: ReactNode[]): CElement; 65 | } 66 | 67 | type CFactory> = ComponentFactory; 68 | type ClassicFactory

= CFactory>; 69 | 70 | interface DOMFactory

{ 71 | (props?: P & ClassAttributes, ...children: ReactNode[]): DOMElement; 72 | } 73 | 74 | interface HTMLFactory extends DOMFactory { 75 | } 76 | 77 | interface SVGFactory extends DOMFactory { 78 | } 79 | 80 | // 81 | // React Nodes 82 | // http://facebook.github.io/react/docs/glossary.html 83 | // ---------------------------------------------------------------------- 84 | 85 | type ReactText = string | number; 86 | type ReactChild = ReactElement | ReactText; 87 | 88 | // Should be Array but type aliases cannot be recursive 89 | type ReactFragment = {} | Array; 90 | type ReactNode = ReactChild | ReactFragment | boolean; 91 | 92 | // 93 | // Top Level API 94 | // ---------------------------------------------------------------------- 95 | 96 | function createClass(spec: ComponentSpec): ClassicComponentClass

; 97 | 98 | function createFactory

( 99 | type: string): DOMFactory; 100 | function createFactory

(type: SFC

): SFCFactory

; 101 | function createFactory

( 102 | type: ClassType, ClassicComponentClass

>): CFactory>; 103 | function createFactory, C extends ComponentClass

>( 104 | type: ClassType): CFactory; 105 | function createFactory

(type: ComponentClass

| SFC

): Factory

; 106 | 107 | function createElement

( 108 | type: string, 109 | props?: P & ClassAttributes, 110 | ...children: ReactNode[]): DOMElement; 111 | function createElement

( 112 | type: SFC

, 113 | props?: P & Attributes, 114 | ...children: ReactNode[]): SFCElement

; 115 | function createElement

( 116 | type: ClassType, ClassicComponentClass

>, 117 | props?: P & ClassAttributes>, 118 | ...children: ReactNode[]): CElement>; 119 | function createElement, C extends ComponentClass

>( 120 | type: ClassType, 121 | props?: P & ClassAttributes, 122 | ...children: ReactNode[]): CElement; 123 | function createElement

( 124 | type: ComponentClass

| SFC

, 125 | props?: P & Attributes, 126 | ...children: ReactNode[]): ReactElement

; 127 | 128 | function cloneElement

( 129 | element: DOMElement, 130 | props?: P & ClassAttributes, 131 | ...children: ReactNode[]): DOMElement; 132 | function cloneElement

( 133 | element: SFCElement

, 134 | props?: Q, // should be Q & Attributes, but then Q is inferred as {} 135 | ...children: ReactNode[]): SFCElement

; 136 | function cloneElement

>( 137 | element: CElement, 138 | props?: Q, // should be Q & ClassAttributes 139 | ...children: ReactNode[]): CElement; 140 | function cloneElement

( 141 | element: ReactElement

, 142 | props?: Q, // should be Q & Attributes 143 | ...children: ReactNode[]): ReactElement

; 144 | 145 | function isValidElement

(object: {}): object is ReactElement

; 146 | 147 | var DOM: ReactDOM; 148 | var PropTypes: ReactPropTypes; 149 | var Children: ReactChildren; 150 | var version: string; 151 | 152 | // 153 | // Component API 154 | // ---------------------------------------------------------------------- 155 | 156 | type ReactInstance = Component | Element; 157 | 158 | // Base component for plain JS classes 159 | class Component implements ComponentLifecycle { 160 | constructor(props?: P, context?: any); 161 | setState(f: (prevState: S, props: P) => S, callback?: () => any): void; 162 | setState(state: S, callback?: () => any): void; 163 | forceUpdate(callback?: () => any): void; 164 | render(): JSX.Element; 165 | 166 | // React.Props is now deprecated, which means that the `children` 167 | // property is not available on `P` by default, even though you can 168 | // always pass children as variadic arguments to `createElement`. 169 | // In the future, if we can define its call signature conditionally 170 | // on the existence of `children` in `P`, then we should remove this. 171 | props: P & { children?: ReactNode }; 172 | state: S; 173 | context: {}; 174 | refs: { 175 | [key: string]: ReactInstance 176 | }; 177 | } 178 | 179 | class PureComponent extends Component {} 180 | 181 | interface ClassicComponent extends Component { 182 | replaceState(nextState: S, callback?: () => any): void; 183 | isMounted(): boolean; 184 | getInitialState?(): S; 185 | } 186 | 187 | interface ChildContextProvider { 188 | getChildContext(): CC; 189 | } 190 | 191 | // 192 | // Class Interfaces 193 | // ---------------------------------------------------------------------- 194 | 195 | type SFC

= StatelessComponent

; 196 | interface StatelessComponent

{ 197 | (props?: P, context?: any): ReactElement; 198 | propTypes?: ValidationMap

; 199 | contextTypes?: ValidationMap; 200 | defaultProps?: P; 201 | displayName?: string; 202 | } 203 | 204 | interface ComponentClass

{ 205 | new(props?: P, context?: any): Component; 206 | propTypes?: ValidationMap

; 207 | contextTypes?: ValidationMap; 208 | childContextTypes?: ValidationMap; 209 | defaultProps?: P; 210 | displayName?: string; 211 | } 212 | 213 | interface ClassicComponentClass

extends ComponentClass

{ 214 | new(props?: P, context?: any): ClassicComponent; 215 | getDefaultProps?(): P; 216 | } 217 | 218 | /** 219 | * We use an intersection type to infer multiple type parameters from 220 | * a single argument, which is useful for many top-level API defs. 221 | * See https://github.com/Microsoft/TypeScript/issues/7234 for more info. 222 | */ 223 | type ClassType, C extends ComponentClass

> = 224 | C & 225 | (new() => T) & 226 | (new() => { props: P }); 227 | 228 | // 229 | // Component Specs and Lifecycle 230 | // ---------------------------------------------------------------------- 231 | 232 | interface ComponentLifecycle { 233 | componentWillMount?(): void; 234 | componentDidMount?(): void; 235 | componentWillReceiveProps?(nextProps: P, nextContext: any): void; 236 | shouldComponentUpdate?(nextProps: P, nextState: S, nextContext: any): boolean; 237 | componentWillUpdate?(nextProps: P, nextState: S, nextContext: any): void; 238 | componentDidUpdate?(prevProps: P, prevState: S, prevContext: any): void; 239 | componentWillUnmount?(): void; 240 | } 241 | 242 | interface Mixin extends ComponentLifecycle { 243 | mixins?: Mixin; 244 | statics?: { 245 | [key: string]: any; 246 | }; 247 | 248 | displayName?: string; 249 | propTypes?: ValidationMap; 250 | contextTypes?: ValidationMap; 251 | childContextTypes?: ValidationMap; 252 | 253 | getDefaultProps?(): P; 254 | getInitialState?(): S; 255 | } 256 | 257 | interface ComponentSpec extends Mixin { 258 | render(): ReactElement; 259 | 260 | [propertyName: string]: any; 261 | } 262 | 263 | // 264 | // Event System 265 | // ---------------------------------------------------------------------- 266 | 267 | interface SyntheticEvent { 268 | bubbles: boolean; 269 | cancelable: boolean; 270 | currentTarget: EventTarget; 271 | defaultPrevented: boolean; 272 | eventPhase: number; 273 | isTrusted: boolean; 274 | nativeEvent: Event; 275 | preventDefault(): void; 276 | stopPropagation(): void; 277 | persist(): void; 278 | target: EventTarget; 279 | timeStamp: Date; 280 | type: string; 281 | } 282 | 283 | interface ClipboardEvent extends SyntheticEvent { 284 | clipboardData: DataTransfer; 285 | } 286 | 287 | interface CompositionEvent extends SyntheticEvent { 288 | data: string; 289 | } 290 | 291 | interface DragEvent extends MouseEvent { 292 | dataTransfer: DataTransfer; 293 | } 294 | 295 | interface FocusEvent extends SyntheticEvent { 296 | relatedTarget: EventTarget; 297 | } 298 | 299 | interface FormEvent extends SyntheticEvent { 300 | } 301 | 302 | interface KeyboardEvent extends SyntheticEvent { 303 | altKey: boolean; 304 | charCode: number; 305 | ctrlKey: boolean; 306 | getModifierState(key: string): boolean; 307 | key: string; 308 | keyCode: number; 309 | locale: string; 310 | location: number; 311 | metaKey: boolean; 312 | repeat: boolean; 313 | shiftKey: boolean; 314 | which: number; 315 | } 316 | 317 | interface MouseEvent extends SyntheticEvent { 318 | altKey: boolean; 319 | button: number; 320 | buttons: number; 321 | clientX: number; 322 | clientY: number; 323 | ctrlKey: boolean; 324 | getModifierState(key: string): boolean; 325 | metaKey: boolean; 326 | pageX: number; 327 | pageY: number; 328 | relatedTarget: EventTarget; 329 | screenX: number; 330 | screenY: number; 331 | shiftKey: boolean; 332 | } 333 | 334 | interface TouchEvent extends SyntheticEvent { 335 | altKey: boolean; 336 | changedTouches: TouchList; 337 | ctrlKey: boolean; 338 | getModifierState(key: string): boolean; 339 | metaKey: boolean; 340 | shiftKey: boolean; 341 | targetTouches: TouchList; 342 | touches: TouchList; 343 | } 344 | 345 | interface UIEvent extends SyntheticEvent { 346 | detail: number; 347 | view: AbstractView; 348 | } 349 | 350 | interface WheelEvent extends MouseEvent { 351 | deltaMode: number; 352 | deltaX: number; 353 | deltaY: number; 354 | deltaZ: number; 355 | } 356 | 357 | interface AnimationEvent extends SyntheticEvent { 358 | animationName: string; 359 | pseudoElement: string; 360 | elapsedTime: number; 361 | } 362 | 363 | interface TransitionEvent extends SyntheticEvent { 364 | propertyName: string; 365 | pseudoElement: string; 366 | elapsedTime: number; 367 | } 368 | 369 | // 370 | // Event Handler Types 371 | // ---------------------------------------------------------------------- 372 | 373 | interface EventHandler { 374 | (event: E): void; 375 | } 376 | 377 | type ReactEventHandler = EventHandler; 378 | 379 | type ClipboardEventHandler = EventHandler; 380 | type CompositionEventHandler = EventHandler; 381 | type DragEventHandler = EventHandler; 382 | type FocusEventHandler = EventHandler; 383 | type FormEventHandler = EventHandler; 384 | type KeyboardEventHandler = EventHandler; 385 | type MouseEventHandler = EventHandler; 386 | type TouchEventHandler = EventHandler; 387 | type UIEventHandler = EventHandler; 388 | type WheelEventHandler = EventHandler; 389 | type AnimationEventHandler = EventHandler; 390 | type TransitionEventHandler = EventHandler; 391 | 392 | // 393 | // Props / DOM Attributes 394 | // ---------------------------------------------------------------------- 395 | 396 | /** 397 | * @deprecated. This was used to allow clients to pass `ref` and `key` 398 | * to `createElement`, which is no longer necessary due to intersection 399 | * types. If you need to declare a props object before passing it to 400 | * `createElement` or a factory, use `ClassAttributes`: 401 | * 402 | * ```ts 403 | * var b: Button; 404 | * var props: ButtonProps & ClassAttributes