├── .babelrc ├── .flowconfig ├── .gitignore ├── .npmignore ├── .prettierrc ├── AnimatedParticle.js ├── BaseEmitter.js ├── BurstAndMoveEmitter.js ├── Emitter.js ├── Example ├── .babelrc ├── .buckconfig ├── .flowconfig ├── .gitattributes ├── .gitignore ├── .prettierrc ├── .watchmanconfig ├── App.js ├── android │ ├── app │ │ ├── BUCK │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ ├── MainActivity.java │ │ │ │ └── MainApplication.java │ │ │ └── res │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ └── values │ │ │ ├── strings.xml │ │ │ └── styles.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── keystores │ │ ├── BUCK │ │ └── debug.keystore.properties │ └── settings.gradle ├── animations │ └── Spin.js ├── app.json ├── assets │ ├── coin.png │ └── star.png ├── examples │ ├── CoinsExplosion.js │ ├── Confetti.js │ └── StarsToTarget.js ├── index.js ├── ios │ ├── Example-tvOS │ │ └── Info.plist │ ├── Example-tvOSTests │ │ └── Info.plist │ ├── Example.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── Example-tvOS.xcscheme │ │ │ └── Example.xcscheme │ ├── Example │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Base.lproj │ │ │ └── LaunchScreen.xib │ │ ├── Images.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── Info.plist │ │ └── main.m │ └── ExampleTests │ │ ├── ExampleTests.m │ │ └── Info.plist ├── package-lock.json ├── package.json ├── screenshosts │ └── particles.gif └── yarn.lock ├── README.md ├── __tests__ ├── BustAndMoveEmitter.spec.js ├── Emitter.spec.js └── __snapshots__ │ ├── BustAndMoveEmitter.spec.js.snap │ └── Emitter.spec.js.snap ├── entities ├── Particle.js └── Vector.js ├── index.js ├── package-lock.json ├── package.json ├── utils ├── __tests__ │ ├── emit-particle.spec.js │ ├── move-particle.spec.js │ └── vector-helpers.spec.js ├── emit-particle.js ├── move-particle.js └── vector-helpers.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["react-native"] 3 | } 4 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | ; Ignore metro 3 | .*/node_modules/.* 4 | 5 | [include] 6 | 7 | [libs] 8 | node_modules/react-native/Libraries/react-native/react-native-interface.js 9 | node_modules/react-native/flow/ 10 | node_modules/react-native/flow-github/ 11 | 12 | [options] 13 | emoji=true 14 | 15 | module.system=haste 16 | module.system.haste.use_name_reducers=true 17 | 18 | [version] 19 | ^0.75.0 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules 3 | coverage 4 | 5 | yarn-error.log 6 | .DS_Store -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .idea 2 | Example 3 | coverage 4 | README.md 5 | .babelrc 6 | .prettierrc -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "tabWidth": 2, 4 | "singleQuote": true, 5 | "trailingComma": "none" 6 | } 7 | -------------------------------------------------------------------------------- /AnimatedParticle.js: -------------------------------------------------------------------------------- 1 | //@flow 2 | import React from 'react'; 3 | 4 | import { StyleSheet, Animated, Easing } from 'react-native'; 5 | import type { InterpolationConfigType } from 'react-native/Libraries/Animated/src/nodes/AnimatedInterpolation'; 6 | 7 | import type { Element } from 'react'; 8 | import type { VectorType } from './entities/Vector'; 9 | 10 | export interface IAnimatedParticle { 11 | /** Number of particles to emit */ 12 | path: VectorType[]; 13 | 14 | /** The position from where the particles should be generated */ 15 | lifetime: number; 16 | 17 | /** Function triggered when the particle reaches the lifetime */ 18 | onLifeEnds: () => any; 19 | 20 | /** Start the animation on the initialization */ 21 | autoStart: boolean; 22 | 23 | /** Start the animation on the initialization */ 24 | style: any; 25 | 26 | children: Element; 27 | } 28 | 29 | interface IAnimatedParticleState { 30 | animatedValue: Animated.Value; 31 | opacityValue: Animated.Value; 32 | translateX: InterpolationConfigType; 33 | translateY: InterpolationConfigType; 34 | } 35 | 36 | type InterpolationConfig = { 37 | translateX: InterpolationConfigType, 38 | translateY: InterpolationConfigType 39 | }; 40 | 41 | export default class AnimatedParticle extends React.Component< 42 | IAnimatedParticle, 43 | IAnimatedParticleState 44 | > { 45 | static defaultProps = {}; 46 | 47 | constructor(props: IAnimatedParticle) { 48 | super(props); 49 | 50 | this.state = { 51 | animatedValue: new Animated.Value(0), 52 | opacityValue: new Animated.Value(1), 53 | ...this._createInterpolations(props.path) 54 | }; 55 | } 56 | 57 | render() { 58 | const { children } = this.props; 59 | const { 60 | animatedValue, 61 | translateX, 62 | translateY, 63 | opacityValue, 64 | style 65 | } = this.state; 66 | 67 | const animatedStyle = { 68 | opacity: opacityValue, 69 | transform: [ 70 | { 71 | translateX: animatedValue.interpolate(translateX) 72 | }, 73 | { 74 | translateY: animatedValue.interpolate(translateY) 75 | } 76 | ] 77 | }; 78 | 79 | return ( 80 | 81 | {children} 82 | 83 | ); 84 | } 85 | 86 | componentDidMount() { 87 | const { autoStart } = this.props; 88 | autoStart && this.start(); 89 | } 90 | 91 | start = () => { 92 | const { path, onLifeEnds, onAnimate } = this.props; 93 | const { animatedValue, opacityValue } = this.state; 94 | 95 | this.animation = 96 | this.animation || onAnimate(path, animatedValue, opacityValue); 97 | 98 | this.animation.start(() => { 99 | onLifeEnds && onLifeEnds(); 100 | }); 101 | }; 102 | 103 | _createInterpolations = (path: VectorType[]): InterpolationConfig => { 104 | const segments = path.length; 105 | 106 | const inputRange: number[] = new Array(segments); 107 | const outputRangeX: number[] = new Array(segments); 108 | const outputRangeY: number[] = new Array(segments); 109 | 110 | for (let i = 0; i < path.length; i++) { 111 | inputRange[i] = i; 112 | outputRangeX[i] = path[i].x; 113 | outputRangeY[i] = path[i].y; 114 | } 115 | 116 | return { 117 | translateX: { 118 | inputRange, 119 | outputRange: outputRangeX 120 | }, 121 | translateY: { 122 | inputRange, 123 | outputRange: outputRangeY 124 | } 125 | }; 126 | }; 127 | } 128 | 129 | const styles = StyleSheet.create({ 130 | particle: { 131 | position: 'absolute', 132 | top: 0, 133 | left: 0 134 | } 135 | }); 136 | -------------------------------------------------------------------------------- /BaseEmitter.js: -------------------------------------------------------------------------------- 1 | //@flow 2 | import React from 'react'; 3 | import type { Element } from 'react'; 4 | import debounce from 'lodash.debounce'; 5 | import { Vector } from './entities/Vector'; 6 | import AnimatedParticle from './AnimatedParticle'; 7 | import type { VectorType } from './entities/Vector'; 8 | import type { ParticleType } from './entities/Particle'; 9 | import { Dimensions, View, StyleSheet, Animated } from 'react-native'; 10 | 11 | const windowDimensions = Dimensions.get('window'); 12 | 13 | export type BaseEmitterType = { 14 | /** Start emitting particles after initialization */ 15 | autoStart?: boolean, 16 | /** The total of particles to be emitted */ 17 | numberOfParticles: number, 18 | /** Interval between emitting a new batch of particles */ 19 | interval: number, 20 | /** The position from where the particles should be generated */ 21 | fromPosition?: VectorType | (() => VectorType), 22 | /** Number of particles to be be emitted on each cycle */ 23 | emissionRate: number, 24 | /** The particle life time (ms) */ 25 | particleLife: number, 26 | /** Width of the emitter */ 27 | width?: number, 28 | /** Height of the emitter */ 29 | height?: number, 30 | /** Style of the particle container */ 31 | particleContainerStyle?: any, 32 | /** The particle content to be rendered */ 33 | children: Element, 34 | /** Reference to the Emiter */ 35 | ref: BaseEmitterType => void, 36 | /** Function to calculate a new bunch of particles */ 37 | onCalculate: (position: VectorType, count: number) => ParticleConfig[], 38 | /** Function used to animate particles */ 39 | onAnimate: (Animated.Value, Animated.Value) => void, 40 | infiniteLoop?: boolean 41 | }; 42 | 43 | type BaseEmitterState = { 44 | visibleParticles: ParticleConfig[] 45 | }; 46 | 47 | export type ParticleConfig = { 48 | particle: ParticleType, 49 | path: VectorType[] 50 | }; 51 | 52 | class BaseEmitter extends React.Component { 53 | // All particles 54 | particles: ParticleConfig[] = []; 55 | // Particles scheduled to be destroyed 56 | particlesToDestroy: number[] = []; 57 | // Number of generated particles 58 | particlesCounter: number = 0; 59 | // Last time a bunch of particles was emitted 60 | lastEmission: number; 61 | // Is emitting particles 62 | isEmitting: boolean = true; 63 | 64 | // Request animation frame callback reference 65 | _raf: AnimationFrameID; 66 | _timeout: TimeoutID; 67 | 68 | // Component is mounted 69 | _isMounted: boolean = false; 70 | 71 | static defaultProps = { 72 | autoStart: true, 73 | width: windowDimensions.width, 74 | height: windowDimensions.height, 75 | fromPosition: Vector(0, 0), 76 | infinite: false 77 | }; 78 | 79 | constructor(props: BaseEmitterType) { 80 | super(props); 81 | 82 | this.state = { 83 | // List of visible particles 84 | visibleParticles: [] 85 | }; 86 | 87 | (this: any)._loop = debounce(this._loop.bind(this), 100); 88 | } 89 | 90 | render() { 91 | const { 92 | particleLife, 93 | children, 94 | particleContainerStyle, 95 | onAnimate 96 | } = this.props; 97 | const { visibleParticles } = this.state; 98 | 99 | // The job is done 100 | if (!this.isEmitting && !visibleParticles.length) return null; 101 | 102 | const child = React.Children.only(children); 103 | 104 | return visibleParticles.map((obj, i) => ( 105 | 114 | {child} 115 | 116 | )); 117 | } 118 | 119 | componentDidMount() { 120 | this._isMounted = true; 121 | const { autoStart } = this.props; 122 | autoStart && this.start(); 123 | } 124 | 125 | shouldComponentUpdate( 126 | nextProps: BaseEmitterType, 127 | nextState: BaseEmitterState 128 | ) { 129 | return ( 130 | this.state.visibleParticles.length !== nextState.visibleParticles.length 131 | ); 132 | } 133 | 134 | componentWillUnmount() { 135 | this._isMounted = false; 136 | this._raf && cancelAnimationFrame(this._raf); 137 | this._timeout && clearTimeout(this._timeout); 138 | } 139 | 140 | stopEmitting() { 141 | const { particleLife } = this.props; 142 | this.isEmitting = false; 143 | 144 | // Schedule a final loop for when the last particles are done 145 | this._timeout = setTimeout(this._loop.bind(this), particleLife + 1); 146 | } 147 | 148 | start() { 149 | this.isEmitting = true; 150 | this.particlesCounter = 0; 151 | this.particles = []; 152 | this._loop(); 153 | } 154 | 155 | _loop() { 156 | this._cleanUp(); 157 | this._calculate(); 158 | this._draw(); 159 | this._queue(); 160 | } 161 | 162 | _cleanUp() { 163 | // Remove particles scheduled to be destroyed 164 | this.particles = this.particles.filter( 165 | p => !this.particlesToDestroy.includes(p.particle.id) 166 | ); 167 | this.particlesToDestroy = []; 168 | } 169 | 170 | _calculate() { 171 | const { onCalculate, numberOfParticles, interval } = this.props; 172 | 173 | if (!this.isEmitting) return; 174 | 175 | if (this.particlesCounter >= numberOfParticles && !this.props.infiniteLoop) { 176 | // Stop emitting new particles 177 | return this.stopEmitting(); 178 | } 179 | 180 | if (Date.now() - this.lastEmission < interval) return; 181 | 182 | this.lastEmission = Date.now(); 183 | 184 | const newParticles = onCalculate( 185 | this._getInitialPosition(), 186 | this.particlesCounter 187 | ); 188 | 189 | // Add the new generated particles 190 | this.particles.push(...newParticles); 191 | this.particlesCounter = this.particlesCounter + newParticles.length; 192 | } 193 | 194 | _draw() { 195 | const { width, height } = this.props; 196 | // Filter the visible particles 197 | this.setState({ 198 | visibleParticles: this.particles 199 | // Remove the particles out of bounds 200 | .filter(p => { 201 | const { x, y } = p.particle.position; 202 | return x >= 0 && x <= width && y >= 0 && y <= height; 203 | }) 204 | }); 205 | } 206 | 207 | _queue() { 208 | if (!this.isEmitting) return; 209 | this._raf = requestAnimationFrame(() => this._loop()); 210 | } 211 | 212 | _getInitialPosition(): VectorType { 213 | const { fromPosition } = this.props; 214 | 215 | if (!fromPosition) return Vector(0, 0); 216 | 217 | if (typeof fromPosition === 'function') { 218 | return fromPosition(); 219 | } 220 | 221 | if (Object.prototype.toString.apply(fromPosition) === '[object Object]') { 222 | return fromPosition; 223 | } 224 | 225 | return Vector(0, 0); 226 | } 227 | 228 | _destroyParticle = (particle: ParticleType): Function => (): void => { 229 | this.particlesToDestroy.push(particle.id); 230 | if (!this.isEmitting && this._isMounted) { 231 | this._loop(); 232 | } 233 | }; 234 | } 235 | 236 | export default BaseEmitter; 237 | -------------------------------------------------------------------------------- /BurstAndMoveEmitter.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import { Animated, Dimensions, Easing } from 'react-native'; 4 | import type { VectorType } from './entities/Vector'; 5 | import { Vector } from './entities/Vector'; 6 | import { fromAngle, toRadians, add } from './utils/vector-helpers'; 7 | import BaseEmitter from './BaseEmitter'; 8 | import { Particle } from './entities/Particle'; 9 | import type { ParticleConfig, BaseEmitterType } from './BaseEmitter'; 10 | 11 | const { width, height } = Dimensions.get('window'); 12 | 13 | type IBurstAndMoveEmitter = BaseEmitterType & { 14 | finalPoint: VectorType, 15 | radius: number, 16 | burstTime: number, 17 | waitTime: number, 18 | moveTime: number, 19 | onCalculate?: () => ParticleConfig[], 20 | onAnimate?: (Animated.Value, Animated.Value) => void 21 | }; 22 | export interface IBurstAndMoveEmitterState { 23 | particles: Array[]; 24 | } 25 | 26 | export default class BurstAndMoveEmitter extends Component< 27 | IBurstAndMoveEmitter, 28 | IBurstAndMoveEmitterState 29 | > { 30 | static defaultProps = { 31 | finalPoint: Vector(width, height), 32 | burstTime: 300, 33 | waitTime: 1000, 34 | moveTime: 1000 35 | }; 36 | 37 | emitter: BaseEmitter; 38 | _storeEmitterRef: BaseEmitter => void; 39 | 40 | constructor(props: IBurstAndMoveEmitter) { 41 | super(props); 42 | 43 | this._calculate = this._calculate.bind(this); 44 | this._animateParticle = this._animateParticle.bind(this); 45 | this._storeEmitterRef = emitter => (this.emitter = emitter); 46 | } 47 | 48 | render() { 49 | const { children, ...props } = this.props; 50 | 51 | return ( 52 | 58 | {children} 59 | 60 | ); 61 | } 62 | 63 | _calculate = (initialPosition: VectorType, particlesCounter: number) => { 64 | const { numberOfParticles, radius, finalPoint, emissionRate } = this.props; 65 | 66 | const particles: ParticleConfig[] = []; 67 | 68 | const rate = Math.min(numberOfParticles, emissionRate); 69 | 70 | for (let i = 0; i < rate; i++) { 71 | // Generate a random magnitude lower than or equals the radius 72 | const magnitude = Math.round(Math.random() * radius); 73 | 74 | // Generate a random angle between 0 and 360 75 | const angle = Math.round(Math.random() * 360); 76 | 77 | // Calculate a vector based on the angle and magnitude. 78 | const burstPoint = add( 79 | initialPosition, 80 | fromAngle(toRadians(angle), magnitude) 81 | ); 82 | 83 | // first step - Emit new particles 84 | const particle = Particle( 85 | Vector(0, 0), 86 | Vector(0, 0), 87 | particlesCounter + i, 88 | initialPosition 89 | ); 90 | const path: VectorType[] = [initialPosition, burstPoint, finalPoint]; 91 | 92 | particles.push({ 93 | particle, 94 | path 95 | }); 96 | } 97 | 98 | return particles; 99 | }; 100 | 101 | _animateParticle = (path, transformValue, opacityValue) => { 102 | const { burstTime, moveTime, waitTime } = this.props; 103 | return Animated.parallel([ 104 | Animated.sequence([ 105 | Animated.timing(transformValue, { 106 | toValue: 1, 107 | duration: burstTime, 108 | easing: Easing.out(Easing.quad), 109 | useNativeDriver: true 110 | }), 111 | Animated.timing(transformValue, { 112 | toValue: 2, 113 | duration: moveTime, 114 | delay: waitTime, 115 | easing: Easing.in(Easing.quad), 116 | useNativeDriver: true 117 | }), 118 | Animated.timing(opacityValue, { 119 | toValue: 0, 120 | duration: moveTime * 0.5, 121 | useNativeDriver: true 122 | }) 123 | ]) 124 | ]); 125 | }; 126 | 127 | start() { 128 | this.emitter.start(); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /Emitter.js: -------------------------------------------------------------------------------- 1 | //@flow 2 | import type { Element } from 'react'; 3 | import React from 'react'; 4 | import { Animated, Easing } from 'react-native'; 5 | import { Vector } from './entities/Vector'; 6 | import { fromAngle, toRadians } from './utils/vector-helpers'; 7 | import { move } from './utils/move-particle'; 8 | import emitParticle from './utils/emit-particle'; 9 | import type { VectorType } from './entities/Vector'; 10 | import type { ParticleType } from './entities/Particle'; 11 | import type { BaseEmitterType } from './BaseEmitter'; 12 | import BaseEmitter from './BaseEmitter'; 13 | 14 | export type EmitterType = BaseEmitterType & { 15 | /** The direction angle of the particle (in degrees) */ 16 | direction: number, 17 | /** The spread angle where particles are allowed to be rendered (in degrees) */ 18 | spread: number, 19 | /** The speed of each particle */ 20 | speed?: number, 21 | /** Gravity force to be applied to the particle movement */ 22 | gravity?: number, 23 | /** number of steps the animation will be divided ( more segments == more precise animation == slow performance) */ 24 | segments?: number 25 | }; 26 | 27 | export class Emitter extends React.Component { 28 | emitter: BaseEmitter; 29 | 30 | static defaultProps = { 31 | gravity: 0.2, 32 | segments: 10, 33 | speed: 5 34 | }; 35 | 36 | _storeEmitterRef: any => void; 37 | 38 | constructor(props: EmitterType) { 39 | super(props); 40 | this._calculate = this._calculate.bind(this); 41 | this._animateParticle = this._animateParticle.bind(this); 42 | this._storeEmitterRef = emitter => (this.emitter = emitter); 43 | } 44 | 45 | render() { 46 | return ( 47 | 53 | ); 54 | } 55 | 56 | _calculate = (initialPosition: VectorType, particlesCounter: number) => { 57 | const { 58 | numberOfParticles, 59 | emissionRate, 60 | direction, 61 | speed, 62 | spread, 63 | gravity, 64 | segments 65 | } = this.props; 66 | 67 | // if we're at our max, stop emitting. 68 | const rate = Math.min(numberOfParticles, emissionRate); 69 | const newParticles = []; 70 | // for [emissionRate], emit a particle 71 | for (let j = 0; j < rate; j++) { 72 | /* 73 | first step - Emit new particles 74 | */ 75 | const particle = emitParticle( 76 | initialPosition, 77 | fromAngle(toRadians(direction), speed), 78 | toRadians(spread), 79 | //Apply gravity to the vertical axis 80 | Vector(0, gravity), 81 | // Particle id 82 | particlesCounter + j 83 | ); 84 | 85 | // Calculate the particle path 86 | // TODO: Improve the performance currently O(n2) 87 | let path: VectorType[] = []; 88 | let particleMovement: ParticleType = particle; 89 | for (let j = 0; j < segments; j++) { 90 | path.push(particleMovement.position); 91 | particleMovement = move(particleMovement); 92 | } 93 | newParticles.push({ 94 | particle, 95 | path 96 | }); 97 | } 98 | 99 | return newParticles; 100 | }; 101 | 102 | _animateParticle = (path, transformValue, opacityValue) => { 103 | const { particleLife } = this.props; 104 | return Animated.parallel([ 105 | Animated.timing(transformValue, { 106 | toValue: path.length, 107 | duration: particleLife, 108 | useNativeDriver: true 109 | }), 110 | Animated.timing(opacityValue, { 111 | toValue: 0, 112 | ease: Easing.inOut(Easing.quad), 113 | delay: particleLife * 0.8, 114 | duration: particleLife * 0.2, 115 | useNativeDriver: true 116 | }) 117 | ]); 118 | }; 119 | 120 | start() { 121 | this.emitter.start(); 122 | } 123 | } 124 | 125 | export default Emitter; 126 | -------------------------------------------------------------------------------- /Example/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["react-native"] 3 | } 4 | -------------------------------------------------------------------------------- /Example/.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /Example/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | ; We fork some components by platform 3 | .*/*[.]android.js 4 | 5 | ; Ignore "BUCK" generated dirs 6 | /\.buckd/ 7 | 8 | ; Ignore unexpected extra "@providesModule" 9 | .*/node_modules/.*/node_modules/fbjs/.* 10 | 11 | ; Ignore duplicate module providers 12 | ; For RN Apps installed via npm, "Libraries" folder is inside 13 | ; "node_modules/react-native" but in the source repo it is in the root 14 | .*/Libraries/react-native/React.js 15 | 16 | ; Ignore polyfills 17 | .*/Libraries/polyfills/.* 18 | 19 | ; Ignore metro 20 | .*/node_modules/metro/.* 21 | 22 | [include] 23 | 24 | [libs] 25 | node_modules/react-native/Libraries/react-native/react-native-interface.js 26 | node_modules/react-native/flow/ 27 | node_modules/react-native/flow-github/ 28 | 29 | [options] 30 | emoji=true 31 | 32 | module.system=haste 33 | module.system.haste.use_name_reducers=true 34 | # get basename 35 | module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1' 36 | # strip .js or .js.flow suffix 37 | module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1' 38 | # strip .ios suffix 39 | module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1' 40 | module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1' 41 | module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1' 42 | module.system.haste.paths.blacklist=.*/__tests__/.* 43 | module.system.haste.paths.blacklist=.*/__mocks__/.* 44 | module.system.haste.paths.blacklist=/node_modules/react-native/Libraries/Animated/src/polyfills/.* 45 | module.system.haste.paths.whitelist=/node_modules/react-native/Libraries/.* 46 | 47 | munge_underscores=true 48 | 49 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' 50 | 51 | module.file_ext=.js 52 | module.file_ext=.jsx 53 | module.file_ext=.json 54 | module.file_ext=.native.js 55 | 56 | suppress_type=$FlowIssue 57 | suppress_type=$FlowFixMe 58 | suppress_type=$FlowFixMeProps 59 | suppress_type=$FlowFixMeState 60 | 61 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 62 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 63 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 64 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError 65 | 66 | [version] 67 | ^0.75.0 68 | -------------------------------------------------------------------------------- /Example/.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | -------------------------------------------------------------------------------- /Example/.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 | project.xcworkspace 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | 33 | # node.js 34 | # 35 | node_modules/ 36 | npm-debug.log 37 | yarn-error.log 38 | 39 | # BUCK 40 | buck-out/ 41 | \.buckd/ 42 | *.keystore 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://docs.fastlane.tools/best-practices/source-control/ 50 | 51 | */fastlane/report.xml 52 | */fastlane/Preview.html 53 | */fastlane/screenshots 54 | 55 | # Bundle artifact 56 | *.jsbundle 57 | -------------------------------------------------------------------------------- /Example/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "tabWidth": 2, 4 | "singleQuote": true, 5 | "trailingComma": "none" 6 | } 7 | -------------------------------------------------------------------------------- /Example/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /Example/App.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample React Native App 3 | * https://github.com/facebook/react-native 4 | * 5 | * @format 6 | * @flow 7 | */ 8 | 9 | import React, { Component } from 'react'; 10 | import { Button, StyleSheet, View } from 'react-native'; 11 | 12 | import CoinsExplosion from './examples/CoinsExplosion'; 13 | import Confetti from './examples/Confetti'; 14 | import StarsToTarget from './examples/StarsToTarget'; 15 | 16 | type Props = {}; 17 | export default class App extends Component { 18 | render() { 19 | return ( 20 | 21 |