[change] update Animated implementation

Mirror contents of React Native 0.55.4
This commit is contained in:
Nicolas Gallagher
2018-05-22 12:44:01 -07:00
parent 5fcb36fc21
commit f254c8eae6
28 changed files with 624 additions and 403 deletions

View File

@@ -16,13 +16,17 @@ import invariant from 'fbjs/lib/invariant';
const { shouldUseNativeDriver } = NativeAnimatedHelper;
export type Mapping = { [key: string]: Mapping } | AnimatedValue;
export type Mapping = {[key: string]: Mapping} | AnimatedValue;
export type EventConfig = {
listener?: ?Function,
useNativeDriver?: boolean
useNativeDriver?: boolean,
};
function attachNativeEvent(viewRef: any, eventName: string, argMapping: Array<?Mapping>) {
function attachNativeEvent(
viewRef: any,
eventName: string,
argMapping: Array<?Mapping>,
) {
// Find animated values in `argMapping` and create an array representing their
// key path inside the `nativeEvent` object. Ex.: ['contentOffset', 'x'].
const eventMappings = [];
@@ -33,7 +37,7 @@ function attachNativeEvent(viewRef: any, eventName: string, argMapping: Array<?M
eventMappings.push({
nativeEventPath: path,
animatedValueTag: value.__getNativeTag()
animatedValueTag: value.__getNativeTag(),
});
} else if (typeof value === 'object') {
for (const key in value) {
@@ -44,7 +48,7 @@ function attachNativeEvent(viewRef: any, eventName: string, argMapping: Array<?M
invariant(
argMapping[0] && argMapping[0].nativeEvent,
'Native driven events only support animated values contained inside `nativeEvent`.'
'Native driven events only support animated values contained inside `nativeEvent`.',
);
// Assume that the event containing `nativeEvent` is always the first argument.
@@ -53,7 +57,11 @@ function attachNativeEvent(viewRef: any, eventName: string, argMapping: Array<?M
const viewTag = findNodeHandle(viewRef);
eventMappings.forEach(mapping => {
NativeAnimatedHelper.API.addAnimatedEventToView(viewTag, eventName, mapping);
NativeAnimatedHelper.API.addAnimatedEventToView(
viewTag,
eventName,
mapping,
);
});
return {
@@ -62,10 +70,10 @@ function attachNativeEvent(viewRef: any, eventName: string, argMapping: Array<?M
NativeAnimatedHelper.API.removeAnimatedEventFromView(
viewTag,
eventName,
mapping.animatedValueTag
mapping.animatedValueTag,
);
});
}
},
};
}
@@ -74,7 +82,7 @@ class AnimatedEvent {
_listeners: Array<Function> = [];
_callListeners: Function;
_attachedEvent: ?{
detach: () => void
detach: () => void,
};
__isNative: boolean;
@@ -101,13 +109,23 @@ class AnimatedEvent {
}
__attach(viewRef: any, eventName: string) {
invariant(this.__isNative, 'Only native driven events need to be attached.');
invariant(
this.__isNative,
'Only native driven events need to be attached.',
);
this._attachedEvent = attachNativeEvent(viewRef, eventName, this._argMapping);
this._attachedEvent = attachNativeEvent(
viewRef,
eventName,
this._argMapping,
);
}
__detach(viewTag: any, eventName: string) {
invariant(this.__isNative, 'Only native driven events need to be detached.');
invariant(
this.__isNative,
'Only native driven events need to be detached.',
);
this._attachedEvent && this._attachedEvent.detach();
}
@@ -153,17 +171,17 @@ class AnimatedEvent {
typeof recMapping +
' for key ' +
key +
', event value must map to AnimatedValue'
', event value must map to AnimatedValue',
);
return;
}
invariant(
typeof recMapping === 'object',
'Bad mapping of type ' + typeof recMapping + ' for key ' + key
'Bad mapping of type ' + typeof recMapping + ' for key ' + key,
);
invariant(
typeof recEvt === 'object',
'Bad event of type ' + typeof recEvt + ' for key ' + key
'Bad event of type ' + typeof recEvt + ' for key ' + key,
);
for (const mappingKey in recMapping) {
traverse(recMapping[mappingKey], recEvt[mappingKey], mappingKey);

View File

@@ -34,25 +34,31 @@ import type { DecayAnimationConfig } from './animations/DecayAnimation';
import type { SpringAnimationConfig } from './animations/SpringAnimation';
import type { Mapping, EventConfig } from './AnimatedEvent';
type CompositeAnimation = {
export type CompositeAnimation = {
start: (callback?: ?EndCallback) => void,
stop: () => void,
reset: () => void,
_startNativeLoop: (iterations?: number) => void,
_isUsingNativeDriver: () => boolean
_isUsingNativeDriver: () => boolean,
};
const add = function(a: AnimatedNode | number, b: AnimatedNode | number): AnimatedAddition {
const add = function(
a: AnimatedNode | number,
b: AnimatedNode | number,
): AnimatedAddition {
return new AnimatedAddition(a, b);
};
const divide = function(a: AnimatedNode | number, b: AnimatedNode | number): AnimatedDivision {
const divide = function(
a: AnimatedNode | number,
b: AnimatedNode | number,
): AnimatedDivision {
return new AnimatedDivision(a, b);
};
const multiply = function(
a: AnimatedNode | number,
b: AnimatedNode | number
b: AnimatedNode | number,
): AnimatedMultiplication {
return new AnimatedMultiplication(a, b);
};
@@ -61,11 +67,18 @@ const modulo = function(a: AnimatedNode, modulus: number): AnimatedModulo {
return new AnimatedModulo(a, modulus);
};
const diffClamp = function(a: AnimatedNode, min: number, max: number): AnimatedDiffClamp {
const diffClamp = function(
a: AnimatedNode,
min: number,
max: number,
): AnimatedDiffClamp {
return new AnimatedDiffClamp(a, min, max);
};
const _combineCallbacks = function(callback: ?EndCallback, config: AnimationConfig) {
const _combineCallbacks = function(
callback: ?EndCallback,
config: AnimationConfig,
) {
if (callback && config.onComplete) {
return (...args) => {
config.onComplete && config.onComplete(...args);
@@ -79,13 +92,13 @@ const _combineCallbacks = function(callback: ?EndCallback, config: AnimationConf
const maybeVectorAnim = function(
value: AnimatedValue | AnimatedValueXY,
config: Object,
anim: (value: AnimatedValue, config: Object) => CompositeAnimation
anim: (value: AnimatedValue, config: Object) => CompositeAnimation,
): ?CompositeAnimation {
if (value instanceof AnimatedValueXY) {
const configX = { ...config };
const configY = { ...config };
const configX = {...config};
const configY = {...config};
for (const key in config) {
const { x, y } = config[key];
const {x, y} = config[key];
if (x !== undefined && y !== undefined) {
configX[key] = x;
configY[key] = y;
@@ -95,19 +108,19 @@ const maybeVectorAnim = function(
const aY = anim((value: AnimatedValueXY).y, configY);
// We use `stopTogether: false` here because otherwise tracking will break
// because the second animation will get stopped before it can update.
return parallel([aX, aY], { stopTogether: false });
return parallel([aX, aY], {stopTogether: false});
}
return null;
};
const spring = function(
value: AnimatedValue | AnimatedValueXY,
config: SpringAnimationConfig
config: SpringAnimationConfig,
): CompositeAnimation {
const start = function(
animatedValue: AnimatedValue | AnimatedValueXY,
configuration: SpringAnimationConfig,
callback?: ?EndCallback
callback?: ?EndCallback,
): void {
callback = _combineCallbacks(callback, configuration);
const singleValue: any = animatedValue;
@@ -120,8 +133,8 @@ const spring = function(
configuration.toValue,
SpringAnimation,
singleConfig,
callback
)
callback,
),
);
} else {
singleValue.animate(new SpringAnimation(singleConfig), callback);
@@ -142,25 +155,25 @@ const spring = function(
},
_startNativeLoop: function(iterations?: number): void {
const singleConfig = { ...config, iterations };
const singleConfig = {...config, iterations};
start(value, singleConfig);
},
_isUsingNativeDriver: function(): boolean {
return config.useNativeDriver || false;
}
},
}
);
};
const timing = function(
value: AnimatedValue | AnimatedValueXY,
config: TimingAnimationConfig
config: TimingAnimationConfig,
): CompositeAnimation {
const start = function(
animatedValue: AnimatedValue | AnimatedValueXY,
configuration: TimingAnimationConfig,
callback?: ?EndCallback
callback?: ?EndCallback,
): void {
callback = _combineCallbacks(callback, configuration);
const singleValue: any = animatedValue;
@@ -173,8 +186,8 @@ const timing = function(
configuration.toValue,
TimingAnimation,
singleConfig,
callback
)
callback,
),
);
} else {
singleValue.animate(new TimingAnimation(singleConfig), callback);
@@ -196,25 +209,25 @@ const timing = function(
},
_startNativeLoop: function(iterations?: number): void {
const singleConfig = { ...config, iterations };
const singleConfig = {...config, iterations};
start(value, singleConfig);
},
_isUsingNativeDriver: function(): boolean {
return config.useNativeDriver || false;
}
},
}
);
};
const decay = function(
value: AnimatedValue | AnimatedValueXY,
config: DecayAnimationConfig
config: DecayAnimationConfig,
): CompositeAnimation {
const start = function(
animatedValue: AnimatedValue | AnimatedValueXY,
configuration: DecayAnimationConfig,
callback?: ?EndCallback
callback?: ?EndCallback,
): void {
callback = _combineCallbacks(callback, configuration);
const singleValue: any = animatedValue;
@@ -238,18 +251,20 @@ const decay = function(
},
_startNativeLoop: function(iterations?: number): void {
const singleConfig = { ...config, iterations };
const singleConfig = {...config, iterations};
start(value, singleConfig);
},
_isUsingNativeDriver: function(): boolean {
return config.useNativeDriver || false;
}
},
}
);
};
const sequence = function(animations: Array<CompositeAnimation>): CompositeAnimation {
const sequence = function(
animations: Array<CompositeAnimation>,
): CompositeAnimation {
let current = 0;
return {
start: function(callback?: ?EndCallback) {
@@ -270,7 +285,7 @@ const sequence = function(animations: Array<CompositeAnimation>): CompositeAnima
};
if (animations.length === 0) {
callback && callback({ finished: true });
callback && callback({finished: true});
} else {
animations[current].start(onComplete);
}
@@ -293,22 +308,22 @@ const sequence = function(animations: Array<CompositeAnimation>): CompositeAnima
_startNativeLoop: function() {
throw new Error(
'Loops run using the native driver cannot contain Animated.sequence animations'
'Loops run using the native driver cannot contain Animated.sequence animations',
);
},
_isUsingNativeDriver: function(): boolean {
return false;
}
},
};
};
type ParallelConfig = {
stopTogether?: boolean // If one is stopped, stop all. default: true
stopTogether?: boolean, // If one is stopped, stop all. default: true
};
const parallel = function(
animations: Array<CompositeAnimation>,
config?: ?ParallelConfig
config?: ?ParallelConfig,
): CompositeAnimation {
let doneCount = 0;
// Make sure we only call stop() at most once for each animation
@@ -318,7 +333,7 @@ const parallel = function(
const result = {
start: function(callback?: ?EndCallback) {
if (doneCount === animations.length) {
callback && callback({ finished: true });
callback && callback({finished: true});
return;
}
@@ -338,7 +353,7 @@ const parallel = function(
};
if (!animation) {
cb({ finished: true });
cb({finished: true});
} else {
animation.start(cb);
}
@@ -362,13 +377,13 @@ const parallel = function(
_startNativeLoop: function() {
throw new Error(
'Loops run using the native driver cannot contain Animated.parallel animations'
'Loops run using the native driver cannot contain Animated.parallel animations',
);
},
_isUsingNativeDriver: function(): boolean {
return false;
}
},
};
return result;
@@ -376,29 +391,36 @@ const parallel = function(
const delay = function(time: number): CompositeAnimation {
// Would be nice to make a specialized implementation
return timing(new AnimatedValue(0), { toValue: 0, delay: time, duration: 0 });
return timing(new AnimatedValue(0), {toValue: 0, delay: time, duration: 0});
};
const stagger = function(time: number, animations: Array<CompositeAnimation>): CompositeAnimation {
const stagger = function(
time: number,
animations: Array<CompositeAnimation>,
): CompositeAnimation {
return parallel(
animations.map((animation, i) => {
return sequence([delay(time * i), animation]);
})
}),
);
};
type LoopAnimationConfig = { iterations: number };
type LoopAnimationConfig = {iterations: number};
const loop = function(
animation: CompositeAnimation,
{ iterations = -1 }: LoopAnimationConfig = {}
{iterations = -1}: LoopAnimationConfig = {},
): CompositeAnimation {
let isFinished = false;
let iterationsSoFar = 0;
return {
start: function(callback?: ?EndCallback) {
const restart = function(result: EndResult = { finished: true }): void {
if (isFinished || iterationsSoFar === iterations || result.finished === false) {
const restart = function(result: EndResult = {finished: true}): void {
if (
isFinished ||
iterationsSoFar === iterations ||
result.finished === false
) {
callback && callback(result);
} else {
iterationsSoFar++;
@@ -407,7 +429,7 @@ const loop = function(
}
};
if (!animation || iterations === 0) {
callback && callback({ finished: true });
callback && callback({finished: true});
} else {
if (animation._isUsingNativeDriver()) {
animation._startNativeLoop(iterations);
@@ -429,18 +451,20 @@ const loop = function(
},
_startNativeLoop: function() {
throw new Error('Loops run using the native driver cannot contain Animated.loop animations');
throw new Error(
'Loops run using the native driver cannot contain Animated.loop animations',
);
},
_isUsingNativeDriver: function(): boolean {
return animation._isUsingNativeDriver();
}
},
};
};
function forkEvent(
event: ?AnimatedEvent | ?Function,
listener: Function
listener: Function,
): AnimatedEvent | Function {
if (!event) {
return listener;
@@ -455,7 +479,10 @@ function forkEvent(
}
}
function unforkEvent(event: ?AnimatedEvent | ?Function, listener: Function): void {
function unforkEvent(
event: ?AnimatedEvent | ?Function,
listener: Function,
): void {
if (event && event instanceof AnimatedEvent) {
event.__removeListener(listener);
}
@@ -638,7 +665,7 @@ const AnimatedImplementation = {
forkEvent,
unforkEvent,
__PropsOnlyForTests: AnimatedProps
__PropsOnlyForTests: AnimatedProps,
};
export default AnimatedImplementation;
export default AnimatedImplementation

View File

@@ -61,22 +61,14 @@ class Easing {
/**
* A stepping function, returns 1 for any positive value of `n`.
*/
/* $FlowFixMe(>=0.59.0 site=react_native_fb) This comment suppresses an error
* caught by Flow 0.59 which was not caught before. Most likely, this error
* is because an exported function parameter is missing an annotation.
* Without an annotation, these parameters are uncovered by Flow. */
static step0(n) {
static step0(n: number) {
return n > 0 ? 1 : 0;
}
/**
* A stepping function, returns 1 if `n` is greater than or equal to 1.
*/
/* $FlowFixMe(>=0.59.0 site=react_native_fb) This comment suppresses an error
* caught by Flow 0.59 which was not caught before. Most likely, this error
* is because an exported function parameter is missing an annotation.
* Without an annotation, these parameters are uncovered by Flow. */
static step1(n) {
static step1(n: number) {
return n >= 1 ? 1 : 0;
}
@@ -86,11 +78,7 @@ class Easing {
*
* http://cubic-bezier.com/#0,0,1,1
*/
/* $FlowFixMe(>=0.59.0 site=react_native_fb) This comment suppresses an error
* caught by Flow 0.59 which was not caught before. Most likely, this error
* is because an exported function parameter is missing an annotation.
* Without an annotation, these parameters are uncovered by Flow. */
static linear(t) {
static linear(t: number) {
return t;
}
@@ -113,11 +101,7 @@ class Easing {
*
* http://easings.net/#easeInQuad
*/
/* $FlowFixMe(>=0.59.0 site=react_native_fb) This comment suppresses an error
* caught by Flow 0.59 which was not caught before. Most likely, this error
* is because an exported function parameter is missing an annotation.
* Without an annotation, these parameters are uncovered by Flow. */
static quad(t) {
static quad(t: number) {
return t * t;
}
@@ -127,11 +111,7 @@ class Easing {
*
* http://easings.net/#easeInCubic
*/
/* $FlowFixMe(>=0.59.0 site=react_native_fb) This comment suppresses an error
* caught by Flow 0.59 which was not caught before. Most likely, this error
* is because an exported function parameter is missing an annotation.
* Without an annotation, these parameters are uncovered by Flow. */
static cubic(t) {
static cubic(t: number) {
return t * t * t;
}
@@ -141,17 +121,8 @@ class Easing {
* n = 4: http://easings.net/#easeInQuart
* n = 5: http://easings.net/#easeInQuint
*/
/* $FlowFixMe(>=0.59.0 site=react_native_fb) This comment suppresses an error
* caught by Flow 0.59 which was not caught before. Most likely, this error
* is because an exported function parameter is missing an annotation.
* Without an annotation, these parameters are uncovered by Flow. */
static poly(n) {
/* $FlowFixMe(>=0.59.0 site=react_native_fb) This comment suppresses an
* error caught by Flow 0.59 which was not caught before. Most likely, this
* error is because an exported function parameter is missing an
* annotation. Without an annotation, these parameters are uncovered by
* Flow. */
return t => Math.pow(t, n);
static poly(n: number) {
return (t: number) => Math.pow(t, n);
}
/**
@@ -159,11 +130,7 @@ class Easing {
*
* http://easings.net/#easeInSine
*/
/* $FlowFixMe(>=0.59.0 site=react_native_fb) This comment suppresses an error
* caught by Flow 0.59 which was not caught before. Most likely, this error
* is because an exported function parameter is missing an annotation.
* Without an annotation, these parameters are uncovered by Flow. */
static sin(t) {
static sin(t: number) {
return 1 - Math.cos(t * Math.PI / 2);
}
@@ -172,11 +139,7 @@ class Easing {
*
* http://easings.net/#easeInCirc
*/
/* $FlowFixMe(>=0.59.0 site=react_native_fb) This comment suppresses an error
* caught by Flow 0.59 which was not caught before. Most likely, this error
* is because an exported function parameter is missing an annotation.
* Without an annotation, these parameters are uncovered by Flow. */
static circle(t) {
static circle(t: number) {
return 1 - Math.sqrt(1 - t * t);
}
@@ -185,11 +148,7 @@ class Easing {
*
* http://easings.net/#easeInExpo
*/
/* $FlowFixMe(>=0.59.0 site=react_native_fb) This comment suppresses an error
* caught by Flow 0.59 which was not caught before. Most likely, this error
* is because an exported function parameter is missing an annotation.
* Without an annotation, these parameters are uncovered by Flow. */
static exp(t) {
static exp(t: number) {
return Math.pow(2, 10 * (t - 1));
}
@@ -205,7 +164,7 @@ class Easing {
*/
static elastic(bounciness: number = 1): (t: number) => number {
const p = bounciness * Math.PI;
return t => 1 - Math.pow(Math.cos(t * Math.PI / 2), 3) * Math.cos(t * p);
return (t) => 1 - Math.pow(Math.cos(t * Math.PI / 2), 3) * Math.cos(t * p);
}
/**
@@ -220,7 +179,7 @@ class Easing {
if (s === undefined) {
s = 1.70158;
}
return t => t * t * ((s + 1) * t - s);
return (t) => t * t * ((s + 1) * t - s);
}
/**
@@ -254,22 +213,31 @@ class Easing {
* A useful tool to visualize cubic bezier curves can be found at
* http://cubic-bezier.com/
*/
static bezier(x1: number, y1: number, x2: number, y2: number): (t: number) => number {
static bezier(
x1: number,
y1: number,
x2: number,
y2: number
): (t: number) => number {
return _bezier(x1, y1, x2, y2);
}
/**
* Runs an easing function forwards.
*/
static in(easing: (t: number) => number): (t: number) => number {
static in(
easing: (t: number) => number,
): (t: number) => number {
return easing;
}
/**
* Runs an easing function backwards.
*/
static out(easing: (t: number) => number): (t: number) => number {
return t => 1 - easing(1 - t);
static out(
easing: (t: number) => number,
): (t: number) => number {
return (t) => 1 - easing(1 - t);
}
/**
@@ -277,8 +245,10 @@ class Easing {
* forwards for half of the duration, then backwards for the rest of the
* duration.
*/
static inOut(easing: (t: number) => number): (t: number) => number {
return t => {
static inOut(
easing: (t: number) => number,
): (t: number) => number {
return (t) => {
if (t < 0.5) {
return easing(t * 2) / 2;
}

View File

@@ -13,19 +13,19 @@ import invariant from 'fbjs/lib/invariant';
import NativeModules from '../../../exports/NativeModules';
import NativeEventEmitter from '../../../modules/NativeEventEmitter';
import type { AnimationConfig } from './animations/Animation';
import type { EventConfig } from './AnimatedEvent';
import type {AnimationConfig} from './animations/Animation';
import type {EventConfig} from './AnimatedEvent';
const NativeAnimatedModule = NativeModules.NativeAnimatedModule;
let __nativeAnimatedNodeTagCount = 1; /* used for animated nodes */
let __nativeAnimationIdCount = 1; /* used for started animations */
type EndResult = { finished: boolean };
type EndResult = {finished: boolean};
type EndCallback = (result: EndResult) => void;
type EventMapping = {
nativeEventPath: Array<string>,
animatedValueTag: ?number
animatedValueTag: ?number,
};
let nativeEventEmitter;
@@ -51,7 +51,10 @@ const API = {
assertNativeAnimatedModule();
NativeAnimatedModule.connectAnimatedNodes(parentTag, childTag);
},
disconnectAnimatedNodes: function(parentTag: ?number, childTag: ?number): void {
disconnectAnimatedNodes: function(
parentTag: ?number,
childTag: ?number,
): void {
assertNativeAnimatedModule();
NativeAnimatedModule.disconnectAnimatedNodes(parentTag, childTag);
},
@@ -59,10 +62,15 @@ const API = {
animationId: ?number,
nodeTag: ?number,
config: Object,
endCallback: EndCallback
endCallback: EndCallback,
): void {
assertNativeAnimatedModule();
NativeAnimatedModule.startAnimatingNode(animationId, nodeTag, config, endCallback);
NativeAnimatedModule.startAnimatingNode(
animationId,
nodeTag,
config,
endCallback,
);
},
stopAnimation: function(animationId: ?number) {
assertNativeAnimatedModule();
@@ -84,11 +92,17 @@ const API = {
assertNativeAnimatedModule();
NativeAnimatedModule.extractAnimatedNodeOffset(nodeTag);
},
connectAnimatedNodeToView: function(nodeTag: ?number, viewTag: ?number): void {
connectAnimatedNodeToView: function(
nodeTag: ?number,
viewTag: ?number,
): void {
assertNativeAnimatedModule();
NativeAnimatedModule.connectAnimatedNodeToView(nodeTag, viewTag);
},
disconnectAnimatedNodeFromView: function(nodeTag: ?number, viewTag: ?number): void {
disconnectAnimatedNodeFromView: function(
nodeTag: ?number,
viewTag: ?number,
): void {
assertNativeAnimatedModule();
NativeAnimatedModule.disconnectAnimatedNodeFromView(nodeTag, viewTag);
},
@@ -99,15 +113,27 @@ const API = {
addAnimatedEventToView: function(
viewTag: ?number,
eventName: string,
eventMapping: EventMapping
eventMapping: EventMapping,
) {
assertNativeAnimatedModule();
NativeAnimatedModule.addAnimatedEventToView(viewTag, eventName, eventMapping);
NativeAnimatedModule.addAnimatedEventToView(
viewTag,
eventName,
eventMapping,
);
},
removeAnimatedEventFromView(viewTag: ?number, eventName: string, animatedNodeTag: ?number) {
removeAnimatedEventFromView(
viewTag: ?number,
eventName: string,
animatedNodeTag: ?number,
) {
assertNativeAnimatedModule();
NativeAnimatedModule.removeAnimatedEventFromView(viewTag, eventName, animatedNodeTag);
}
NativeAnimatedModule.removeAnimatedEventFromView(
viewTag,
eventName,
animatedNodeTag,
);
},
};
/**
@@ -126,7 +152,7 @@ const STYLES_WHITELIST = {
scaleX: true,
scaleY: true,
translateX: true,
translateY: true
translateY: true,
};
const TRANSFORM_WHITELIST = {
@@ -138,13 +164,37 @@ const TRANSFORM_WHITELIST = {
rotate: true,
rotateX: true,
rotateY: true,
perspective: true
perspective: true,
};
const SUPPORTED_INTERPOLATION_PARAMS = {
inputRange: true,
outputRange: true,
extrapolate: true,
extrapolateRight: true,
extrapolateLeft: true,
};
function addWhitelistedStyleProp(prop: string): void {
STYLES_WHITELIST[prop] = true;
}
function addWhitelistedTransformProp(prop: string): void {
TRANSFORM_WHITELIST[prop] = true;
}
function addWhitelistedInterpolationParam(param: string): void {
SUPPORTED_INTERPOLATION_PARAMS[param] = true;
}
function validateTransform(configs: Array<Object>): void {
configs.forEach(config => {
if (!TRANSFORM_WHITELIST.hasOwnProperty(config.property)) {
throw new Error(`Property '${config.property}' is not supported by native animated module`);
throw new Error(
`Property '${
config.property
}' is not supported by native animated module`,
);
}
});
}
@@ -152,22 +202,19 @@ function validateTransform(configs: Array<Object>): void {
function validateStyles(styles: Object): void {
for (var key in styles) {
if (!STYLES_WHITELIST.hasOwnProperty(key)) {
throw new Error(`Style property '${key}' is not supported by native animated module`);
throw new Error(
`Style property '${key}' is not supported by native animated module`,
);
}
}
}
function validateInterpolation(config: Object): void {
var SUPPORTED_INTERPOLATION_PARAMS = {
inputRange: true,
outputRange: true,
extrapolate: true,
extrapolateRight: true,
extrapolateLeft: true
};
for (var key in config) {
if (!SUPPORTED_INTERPOLATION_PARAMS.hasOwnProperty(key)) {
throw new Error(`Interpolation property '${key}' is not supported by native animated module`);
throw new Error(
`Interpolation property '${key}' is not supported by native animated module`,
);
}
}
}
@@ -194,7 +241,7 @@ function shouldUseNativeDriver(config: AnimationConfig | EventConfig): boolean {
'animated module is missing. Falling back to JS-based animation. To ' +
'resolve this, add `RCTAnimation` module to this app, or remove ' +
'`useNativeDriver`. ' +
'More info: https://github.com/facebook/react-native/issues/11094#issuecomment-263240420'
'More info: https://github.com/facebook/react-native/issues/11094#issuecomment-263240420',
);
_warnedMissingNativeAnimated = true;
}
@@ -206,6 +253,9 @@ function shouldUseNativeDriver(config: AnimationConfig | EventConfig): boolean {
const NativeAnimatedHelper = {
API,
addWhitelistedStyleProp,
addWhitelistedTransformProp,
addWhitelistedInterpolationParam,
validateStyles,
validateTransform,
validateInterpolation,
@@ -223,6 +273,9 @@ const NativeAnimatedHelper = {
export {
API,
addWhitelistedStyleProp,
addWhitelistedTransformProp,
addWhitelistedInterpolationParam,
validateStyles,
validateTransform,
validateInterpolation,

View File

@@ -11,7 +11,7 @@
type SpringConfigType = {
stiffness: number,
damping: number
damping: number,
};
function stiffnessFromOrigamiValue(oValue) {
@@ -22,20 +22,26 @@ function dampingFromOrigamiValue(oValue) {
return (oValue - 8) * 3 + 25;
}
function fromOrigamiTensionAndFriction(tension: number, friction: number): SpringConfigType {
function fromOrigamiTensionAndFriction(
tension: number,
friction: number,
): SpringConfigType {
return {
stiffness: stiffnessFromOrigamiValue(tension),
damping: dampingFromOrigamiValue(friction)
damping: dampingFromOrigamiValue(friction),
};
}
function fromBouncinessAndSpeed(bounciness: number, speed: number): SpringConfigType {
function fromBouncinessAndSpeed(
bounciness: number,
speed: number,
): SpringConfigType {
function normalize(value, startValue, endValue) {
return (value - startValue) / (endValue - startValue);
}
function projectNormal(n, start, end) {
return start + n * (end - start);
return start + (n * (end - start));
}
function linearInterpolation(t, start, end) {
@@ -47,15 +53,18 @@ function fromBouncinessAndSpeed(bounciness: number, speed: number): SpringConfig
}
function b3Friction1(x) {
return 0.0007 * Math.pow(x, 3) - 0.031 * Math.pow(x, 2) + 0.64 * x + 1.28;
return (0.0007 * Math.pow(x, 3)) -
(0.031 * Math.pow(x, 2)) + 0.64 * x + 1.28;
}
function b3Friction2(x) {
return 0.000044 * Math.pow(x, 3) - 0.006 * Math.pow(x, 2) + 0.36 * x + 2;
return (0.000044 * Math.pow(x, 3)) -
(0.006 * Math.pow(x, 2)) + 0.36 * x + 2;
}
function b3Friction3(x) {
return 0.00000045 * Math.pow(x, 3) - 0.000332 * Math.pow(x, 2) + 0.1078 * x + 5.84;
return (0.00000045 * Math.pow(x, 3)) -
(0.000332 * Math.pow(x, 2)) + 0.1078 * x + 5.84;
}
function b3Nobounce(tension) {
@@ -72,11 +81,15 @@ function fromBouncinessAndSpeed(bounciness: number, speed: number): SpringConfig
b = projectNormal(b, 0, 0.8);
var s = normalize(speed / 1.7, 0, 20);
var bouncyTension = projectNormal(s, 0.5, 200);
var bouncyFriction = quadraticOutInterpolation(b, b3Nobounce(bouncyTension), 0.01);
var bouncyFriction = quadraticOutInterpolation(
b,
b3Nobounce(bouncyTension),
0.01
);
return {
stiffness: stiffnessFromOrigamiValue(bouncyTension),
damping: dampingFromOrigamiValue(bouncyFriction)
damping: dampingFromOrigamiValue(bouncyFriction),
};
}

View File

@@ -13,14 +13,14 @@ import NativeAnimatedHelper from '../NativeAnimatedHelper';
import type AnimatedValue from '../nodes/AnimatedValue';
export type EndResult = { finished: boolean };
export type EndResult = {finished: boolean};
export type EndCallback = (result: EndResult) => void;
export type AnimationConfig = {
isInteraction?: boolean,
useNativeDriver?: boolean,
onComplete?: ?EndCallback,
iterations?: number
iterations?: number,
};
// Important note: start() and stop() will only be called at most once.
@@ -37,7 +37,7 @@ class Animation {
onUpdate: (value: number) => void,
onEnd: ?EndCallback,
previousAnimation: ?Animation,
animatedValue: AnimatedValue
animatedValue: AnimatedValue,
): void {}
stop(): void {
if (this.__nativeId) {
@@ -62,7 +62,7 @@ class Animation {
this.__nativeId,
animatedValue.__getNativeTag(),
this.__getNativeAnimationConfig(),
this.__debouncedOnEnd.bind(this)
this.__debouncedOnEnd.bind(this),
);
}
}

View File

@@ -17,13 +17,13 @@ import type { AnimationConfig, EndCallback } from './Animation';
import type AnimatedValue from '../nodes/AnimatedValue';
export type DecayAnimationConfig = AnimationConfig & {
velocity: number | { x: number, y: number },
deceleration?: number
velocity: number | {x: number, y: number},
deceleration?: number,
};
export type DecayAnimationConfigSingle = AnimationConfig & {
velocity: number,
deceleration?: number
deceleration?: number,
};
class DecayAnimation extends Animation {
@@ -38,10 +38,12 @@ class DecayAnimation extends Animation {
constructor(config: DecayAnimationConfigSingle) {
super();
this._deceleration = config.deceleration !== undefined ? config.deceleration : 0.998;
this._deceleration =
config.deceleration !== undefined ? config.deceleration : 0.998;
this._velocity = config.velocity;
this._useNativeDriver = shouldUseNativeDriver(config);
this.__isInteraction = config.isInteraction !== undefined ? config.isInteraction : true;
this.__isInteraction =
config.isInteraction !== undefined ? config.isInteraction : true;
this.__iterations = config.iterations !== undefined ? config.iterations : 1;
}
@@ -50,7 +52,7 @@ class DecayAnimation extends Animation {
type: 'decay',
deceleration: this._deceleration,
velocity: this._velocity,
iterations: this.__iterations
iterations: this.__iterations,
};
}
@@ -59,7 +61,7 @@ class DecayAnimation extends Animation {
onUpdate: (value: number) => void,
onEnd: ?EndCallback,
previousAnimation: ?Animation,
animatedValue: AnimatedValue
animatedValue: AnimatedValue,
): void {
this.__active = true;
this._lastValue = fromValue;
@@ -86,7 +88,7 @@ class DecayAnimation extends Animation {
this._onUpdate(value);
if (Math.abs(this._lastValue - value) < 0.1) {
this.__debouncedOnEnd({ finished: true });
this.__debouncedOnEnd({finished: true});
return;
}
@@ -100,7 +102,7 @@ class DecayAnimation extends Animation {
super.stop();
this.__active = false;
global.cancelAnimationFrame(this._animationFrame);
this.__debouncedOnEnd({ finished: false });
this.__debouncedOnEnd({finished: false});
}
}

View File

@@ -17,14 +17,14 @@ import SpringConfig from '../SpringConfig';
import invariant from 'fbjs/lib/invariant';
import { shouldUseNativeDriver } from '../NativeAnimatedHelper';
import type { AnimationConfig, EndCallback } from './Animation';
import type {AnimationConfig, EndCallback} from './Animation';
export type SpringAnimationConfig = AnimationConfig & {
toValue: number | AnimatedValue | { x: number, y: number } | AnimatedValueXY,
toValue: number | AnimatedValue | {x: number, y: number} | AnimatedValueXY,
overshootClamping?: boolean,
restDisplacementThreshold?: number,
restSpeedThreshold?: number,
velocity?: number | { x: number, y: number },
velocity?: number | {x: number, y: number},
bounciness?: number,
speed?: number,
tension?: number,
@@ -32,7 +32,7 @@ export type SpringAnimationConfig = AnimationConfig & {
stiffness?: number,
damping?: number,
mass?: number,
delay?: number
delay?: number,
};
export type SpringAnimationConfigSingle = AnimationConfig & {
@@ -48,7 +48,7 @@ export type SpringAnimationConfigSingle = AnimationConfig & {
stiffness?: number,
damping?: number,
mass?: number,
delay?: number
delay?: number,
};
function withDefault<T>(value: ?T, defaultValue: T): T {
@@ -84,14 +84,18 @@ class SpringAnimation extends Animation {
super();
this._overshootClamping = withDefault(config.overshootClamping, false);
this._restDisplacementThreshold = withDefault(config.restDisplacementThreshold, 0.001);
this._restDisplacementThreshold = withDefault(
config.restDisplacementThreshold,
0.001,
);
this._restSpeedThreshold = withDefault(config.restSpeedThreshold, 0.001);
this._initialVelocity = withDefault(config.velocity, 0);
this._lastVelocity = withDefault(config.velocity, 0);
this._toValue = config.toValue;
this._delay = withDefault(config.delay, 0);
this._useNativeDriver = shouldUseNativeDriver(config);
this.__isInteraction = config.isInteraction !== undefined ? config.isInteraction : true;
this.__isInteraction =
config.isInteraction !== undefined ? config.isInteraction : true;
this.__iterations = config.iterations !== undefined ? config.iterations : 1;
if (
@@ -104,7 +108,7 @@ class SpringAnimation extends Animation {
config.speed === undefined &&
config.tension === undefined &&
config.friction === undefined,
'You can define one of bounciness/speed, tension/friction, or stiffness/damping/mass, but not more than one'
'You can define one of bounciness/speed, tension/friction, or stiffness/damping/mass, but not more than one',
);
this._stiffness = withDefault(config.stiffness, 100);
this._damping = withDefault(config.damping, 10);
@@ -118,11 +122,11 @@ class SpringAnimation extends Animation {
config.stiffness === undefined &&
config.damping === undefined &&
config.mass === undefined,
'You can define one of bounciness/speed, tension/friction, or stiffness/damping/mass, but not more than one'
'You can define one of bounciness/speed, tension/friction, or stiffness/damping/mass, but not more than one',
);
const springConfig = SpringConfig.fromBouncinessAndSpeed(
withDefault(config.bounciness, 8),
withDefault(config.speed, 12)
withDefault(config.speed, 12),
);
this._stiffness = springConfig.stiffness;
this._damping = springConfig.damping;
@@ -132,7 +136,7 @@ class SpringAnimation extends Animation {
// We assume mass is 1.
const springConfig = SpringConfig.fromOrigamiTensionAndFriction(
withDefault(config.tension, 40),
withDefault(config.friction, 7)
withDefault(config.friction, 7),
);
this._stiffness = springConfig.stiffness;
this._damping = springConfig.damping;
@@ -155,7 +159,7 @@ class SpringAnimation extends Animation {
mass: this._mass,
initialVelocity: withDefault(this._initialVelocity, this._lastVelocity),
toValue: this._toValue,
iterations: this.__iterations
iterations: this.__iterations,
};
}
@@ -164,7 +168,7 @@ class SpringAnimation extends Animation {
onUpdate: (value: number) => void,
onEnd: ?EndCallback,
previousAnimation: ?Animation,
animatedValue: AnimatedValue
animatedValue: AnimatedValue,
): void {
this.__active = true;
this._startPosition = fromValue;
@@ -204,7 +208,7 @@ class SpringAnimation extends Animation {
return {
lastPosition: this._lastPosition,
lastVelocity: this._lastVelocity,
lastTime: this._lastTime
lastTime: this._lastTime,
};
}
@@ -262,21 +266,25 @@ class SpringAnimation extends Animation {
position =
this._toValue -
envelope *
((v0 + zeta * omega0 * x0) / omega1 * Math.sin(omega1 * t) + x0 * Math.cos(omega1 * t));
((v0 + zeta * omega0 * x0) / omega1 * Math.sin(omega1 * t) +
x0 * Math.cos(omega1 * t));
// This looks crazy -- it's actually just the derivative of the
// oscillation function
velocity =
zeta *
omega0 *
envelope *
(Math.sin(omega1 * t) * (v0 + zeta * omega0 * x0) / omega1 + x0 * Math.cos(omega1 * t)) -
(Math.sin(omega1 * t) * (v0 + zeta * omega0 * x0) / omega1 +
x0 * Math.cos(omega1 * t)) -
envelope *
(Math.cos(omega1 * t) * (v0 + zeta * omega0 * x0) - omega1 * x0 * Math.sin(omega1 * t));
(Math.cos(omega1 * t) * (v0 + zeta * omega0 * x0) -
omega1 * x0 * Math.sin(omega1 * t));
} else {
// Critically damped
const envelope = Math.exp(-omega0 * t);
position = this._toValue - envelope * (x0 + (v0 + omega0 * x0) * t);
velocity = envelope * (v0 * (t * omega0 - 1) + t * x0 * (omega0 * omega0));
velocity =
envelope * (v0 * (t * omega0 - 1) + t * x0 * (omega0 * omega0));
}
this._lastTime = now;
@@ -301,7 +309,8 @@ class SpringAnimation extends Animation {
const isVelocity = Math.abs(velocity) <= this._restSpeedThreshold;
let isDisplacement = true;
if (this._stiffness !== 0) {
isDisplacement = Math.abs(this._toValue - position) <= this._restDisplacementThreshold;
isDisplacement =
Math.abs(this._toValue - position) <= this._restDisplacementThreshold;
}
if (isOvershooting || (isVelocity && isDisplacement)) {
@@ -312,7 +321,7 @@ class SpringAnimation extends Animation {
this._onUpdate(this._toValue);
}
this.__debouncedOnEnd({ finished: true });
this.__debouncedOnEnd({finished: true});
return;
}
this._animationFrame = requestAnimationFrame(this.onUpdate.bind(this));
@@ -323,7 +332,7 @@ class SpringAnimation extends Animation {
this.__active = false;
clearTimeout(this._timeout);
global.cancelAnimationFrame(this._animationFrame);
this.__debouncedOnEnd({ finished: false });
this.__debouncedOnEnd({finished: false});
}
}

View File

@@ -16,20 +16,20 @@ import Easing from '../Easing';
import { shouldUseNativeDriver } from '../NativeAnimatedHelper';
import type { AnimationConfig, EndCallback } from './Animation';
import type {AnimationConfig, EndCallback} from './Animation';
export type TimingAnimationConfig = AnimationConfig & {
toValue: number | AnimatedValue | { x: number, y: number } | AnimatedValueXY,
toValue: number | AnimatedValue | {x: number, y: number} | AnimatedValueXY,
easing?: (value: number) => number,
duration?: number,
delay?: number
delay?: number,
};
export type TimingAnimationConfigSingle = AnimationConfig & {
toValue: number | AnimatedValue,
easing?: (value: number) => number,
duration?: number,
delay?: number
delay?: number,
};
let _easeInOut;
@@ -59,7 +59,8 @@ class TimingAnimation extends Animation {
this._duration = config.duration !== undefined ? config.duration : 500;
this._delay = config.delay !== undefined ? config.delay : 0;
this.__iterations = config.iterations !== undefined ? config.iterations : 1;
this.__isInteraction = config.isInteraction !== undefined ? config.isInteraction : true;
this.__isInteraction =
config.isInteraction !== undefined ? config.isInteraction : true;
this._useNativeDriver = shouldUseNativeDriver(config);
}
@@ -74,7 +75,7 @@ class TimingAnimation extends Animation {
type: 'frames',
frames,
toValue: this._toValue,
iterations: this.__iterations
iterations: this.__iterations,
};
}
@@ -83,7 +84,7 @@ class TimingAnimation extends Animation {
onUpdate: (value: number) => void,
onEnd: ?EndCallback,
previousAnimation: ?Animation,
animatedValue: AnimatedValue
animatedValue: AnimatedValue,
): void {
this.__active = true;
this._fromValue = fromValue;
@@ -96,13 +97,15 @@ class TimingAnimation extends Animation {
// not cause intermixed JS and native animations.
if (this._duration === 0 && !this._useNativeDriver) {
this._onUpdate(this._toValue);
this.__debouncedOnEnd({ finished: true });
this.__debouncedOnEnd({finished: true});
} else {
this._startTime = Date.now();
if (this._useNativeDriver) {
this.__startNativeAnimation(animatedValue);
} else {
this._animationFrame = requestAnimationFrame(this.onUpdate.bind(this));
this._animationFrame = requestAnimationFrame(
this.onUpdate.bind(this),
);
}
}
};
@@ -119,15 +122,18 @@ class TimingAnimation extends Animation {
if (this._duration === 0) {
this._onUpdate(this._toValue);
} else {
this._onUpdate(this._fromValue + this._easing(1) * (this._toValue - this._fromValue));
this._onUpdate(
this._fromValue + this._easing(1) * (this._toValue - this._fromValue),
);
}
this.__debouncedOnEnd({ finished: true });
this.__debouncedOnEnd({finished: true});
return;
}
this._onUpdate(
this._fromValue +
this._easing((now - this._startTime) / this._duration) * (this._toValue - this._fromValue)
this._easing((now - this._startTime) / this._duration) *
(this._toValue - this._fromValue),
);
if (this.__active) {
this._animationFrame = requestAnimationFrame(this.onUpdate.bind(this));
@@ -139,7 +145,7 @@ class TimingAnimation extends Animation {
this.__active = false;
clearTimeout(this._timeout);
global.cancelAnimationFrame(this._animationFrame);
this.__debouncedOnEnd({ finished: false });
this.__debouncedOnEnd({finished: false});
}
}

View File

@@ -7,54 +7,42 @@
*/
'use strict';
// These values are established by empiricism with tests (tradeoff: performance VS precision)
var NEWTON_ITERATIONS = 4;
var NEWTON_MIN_SLOPE = 0.001;
var SUBDIVISION_PRECISION = 0.0000001;
var SUBDIVISION_MAX_ITERATIONS = 10;
// These values are established by empiricism with tests (tradeoff: performance VS precision)
var NEWTON_ITERATIONS = 4;
var NEWTON_MIN_SLOPE = 0.001;
var SUBDIVISION_PRECISION = 0.0000001;
var SUBDIVISION_MAX_ITERATIONS = 10;
var kSplineTableSize = 11;
var kSampleStepSize = 1.0 / (kSplineTableSize - 1.0);
var kSplineTableSize = 11;
var kSampleStepSize = 1.0 / (kSplineTableSize - 1.0);
var float32ArraySupported = typeof Float32Array === 'function';
var float32ArraySupported = typeof Float32Array === 'function';
function A(aA1, aA2) {
return 1.0 - 3.0 * aA2 + 3.0 * aA1;
}
function B(aA1, aA2) {
return 3.0 * aA2 - 6.0 * aA1;
}
function C(aA1) {
return 3.0 * aA1;
}
function A (aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; }
function B (aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; }
function C (aA1) { return 3.0 * aA1; }
// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
function calcBezier(aT, aA1, aA2) {
return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT;
}
// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
function calcBezier (aT, aA1, aA2) { return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT; }
// Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
function getSlope(aT, aA1, aA2) {
return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1);
}
// Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
function getSlope (aT, aA1, aA2) { return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1); }
function binarySubdivide(aX, aA, aB, mX1, mX2) {
var currentX,
currentT,
i = 0;
do {
currentT = aA + (aB - aA) / 2.0;
currentX = calcBezier(currentT, mX1, mX2) - aX;
if (currentX > 0.0) {
aB = currentT;
} else {
aA = currentT;
}
} while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS);
return currentT;
}
function binarySubdivide (aX, aA, aB, mX1, mX2) {
var currentX, currentT, i = 0;
do {
currentT = aA + (aB - aA) / 2.0;
currentX = calcBezier(currentT, mX1, mX2) - aX;
if (currentX > 0.0) {
aB = currentT;
} else {
aA = currentT;
}
} while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS);
return currentT;
}
function newtonRaphsonIterate(aX, aGuessT, mX1, mX2) {
function newtonRaphsonIterate (aX, aGuessT, mX1, mX2) {
for (var i = 0; i < NEWTON_ITERATIONS; ++i) {
var currentSlope = getSlope(aGuessT, mX1, mX2);
if (currentSlope === 0.0) {
@@ -64,63 +52,56 @@ function newtonRaphsonIterate(aX, aGuessT, mX1, mX2) {
aGuessT -= currentX / currentSlope;
}
return aGuessT;
}
}
function bezier(mX1, mY1, mX2, mY2) {
if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) {
// eslint-disable-line yoda
throw new Error('bezier x values must be in [0, 1] range');
}
module.exports = function bezier (mX1, mY1, mX2, mY2) {
if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) { // eslint-disable-line yoda
throw new Error('bezier x values must be in [0, 1] range');
}
// Precompute samples table
var sampleValues = float32ArraySupported
? new Float32Array(kSplineTableSize)
: new Array(kSplineTableSize);
if (mX1 !== mY1 || mX2 !== mY2) {
for (var i = 0; i < kSplineTableSize; ++i) {
sampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2);
}
}
// Precompute samples table
var sampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize);
if (mX1 !== mY1 || mX2 !== mY2) {
for (var i = 0; i < kSplineTableSize; ++i) {
sampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2);
}
}
function getTForX(aX) {
var intervalStart = 0.0;
var currentSample = 1;
var lastSample = kSplineTableSize - 1;
function getTForX (aX) {
var intervalStart = 0.0;
var currentSample = 1;
var lastSample = kSplineTableSize - 1;
for (; currentSample !== lastSample && sampleValues[currentSample] <= aX; ++currentSample) {
intervalStart += kSampleStepSize;
}
--currentSample;
for (; currentSample !== lastSample && sampleValues[currentSample] <= aX; ++currentSample) {
intervalStart += kSampleStepSize;
}
--currentSample;
// Interpolate to provide an initial guess for t
var dist =
(aX - sampleValues[currentSample]) /
(sampleValues[currentSample + 1] - sampleValues[currentSample]);
var guessForT = intervalStart + dist * kSampleStepSize;
// Interpolate to provide an initial guess for t
var dist = (aX - sampleValues[currentSample]) / (sampleValues[currentSample + 1] - sampleValues[currentSample]);
var guessForT = intervalStart + dist * kSampleStepSize;
var initialSlope = getSlope(guessForT, mX1, mX2);
if (initialSlope >= NEWTON_MIN_SLOPE) {
return newtonRaphsonIterate(aX, guessForT, mX1, mX2);
} else if (initialSlope === 0.0) {
return guessForT;
} else {
return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize, mX1, mX2);
}
}
var initialSlope = getSlope(guessForT, mX1, mX2);
if (initialSlope >= NEWTON_MIN_SLOPE) {
return newtonRaphsonIterate(aX, guessForT, mX1, mX2);
} else if (initialSlope === 0.0) {
return guessForT;
} else {
return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize, mX1, mX2);
}
}
return function BezierEasing(x) {
if (mX1 === mY1 && mX2 === mY2) {
return x; // linear
}
// Because JavaScript number are imprecise, we should guarantee the extremes are right.
if (x === 0) {
return 0;
}
if (x === 1) {
return 1;
}
return calcBezier(getTForX(x), mY1, mY2);
};
}
export default bezier;
return function BezierEasing (x) {
if (mX1 === mY1 && mX2 === mY2) {
return x; // linear
}
// Because JavaScript number are imprecise, we should guarantee the extremes are right.
if (x === 0) {
return 0;
}
if (x === 1) {
return 1;
}
return calcBezier(getTForX(x), mY1, mY2);
};
};

View File

@@ -13,8 +13,16 @@ import { AnimatedEvent } from './AnimatedEvent';
import AnimatedProps from './nodes/AnimatedProps';
import React from 'react';
import ViewStylePropTypes from '../../../exports/View/ViewStylePropTypes';
import invariant from 'fbjs/lib/invariant';
function createAnimatedComponent(Component: any): any {
invariant(
typeof Component === 'string' ||
(Component.prototype && Component.prototype.isReactComponent),
'`createAnimatedComponent` does not support stateless functional components; ' +
'use a class component instead.',
);
class AnimatedComponent extends React.Component<Object> {
_component: any;
_invokeAnimatedPropsCallbackOnMount: boolean = false;
@@ -39,7 +47,7 @@ function createAnimatedComponent(Component: any): any {
this._component.setNativeProps(props);
}
componentWillMount() {
UNSAFE_componentWillMount() {
this._attachProps(this.props);
}
@@ -93,12 +101,14 @@ function createAnimatedComponent(Component: any): any {
) {
this.forceUpdate();
} else if (!this._propsAnimated.__isNative) {
this._component.setNativeProps(this._propsAnimated.__getAnimatedValue());
this._component.setNativeProps(
this._propsAnimated.__getAnimatedValue(),
);
} else {
throw new Error(
'Attempting to run JS driven animation on animated ' +
'node that has been moved to "native" earlier by starting an ' +
'animation with `useNativeDriver: true`'
'animation with `useNativeDriver: true`',
);
}
};
@@ -106,7 +116,10 @@ function createAnimatedComponent(Component: any): any {
_attachProps(nextProps) {
const oldPropsAnimated = this._propsAnimated;
this._propsAnimated = new AnimatedProps(nextProps, this._animatedPropsCallback);
this._propsAnimated = new AnimatedProps(
nextProps,
this._animatedPropsCallback,
);
// When you call detach, it removes the element from the parent list
// of children. If it goes to 0, then the parent also detaches itself
@@ -119,7 +132,7 @@ function createAnimatedComponent(Component: any): any {
oldPropsAnimated && oldPropsAnimated.__detach();
}
componentWillReceiveProps(newProps) {
UNSAFE_componentWillReceiveProps(newProps) {
this._attachProps(newProps);
}
@@ -141,9 +154,11 @@ function createAnimatedComponent(Component: any): any {
ref={this._setComponentRef}
// The native driver updates views directly through the UI thread so we
// have to make sure the view doesn't get optimized away because it cannot
// go through the NativeViewHierachyManager since it operates on the shadow
// go through the NativeViewHierarchyManager since it operates on the shadow
// thread.
collapsable={this._propsAnimated.__isNative ? false : props.collapsable}
collapsable={
this._propsAnimated.__isNative ? false : props.collapsable
}
/>
);
}
@@ -177,11 +192,11 @@ function createAnimatedComponent(Component: any): any {
'should nest it in a style object. ' +
'E.g. `{ style: { ' +
key +
': ... } }`'
': ... } }`',
);
}
}
}
},
};
return AnimatedComponent;

View File

@@ -14,7 +14,7 @@ import AnimatedNode from './AnimatedNode';
import AnimatedValue from './AnimatedValue';
import AnimatedWithChildren from './AnimatedWithChildren';
import type { InterpolationConfigType } from './AnimatedInterpolation';
import type {InterpolationConfigType} from './AnimatedInterpolation';
class AnimatedAddition extends AnimatedWithChildren {
_a: AnimatedNode;
@@ -54,7 +54,7 @@ class AnimatedAddition extends AnimatedWithChildren {
__getNativeConfig(): any {
return {
type: 'addition',
input: [this._a.__getNativeTag(), this._b.__getNativeTag()]
input: [this._a.__getNativeTag(), this._b.__getNativeTag()],
};
}
}

View File

@@ -13,7 +13,7 @@ import AnimatedInterpolation from './AnimatedInterpolation';
import AnimatedNode from './AnimatedNode';
import AnimatedWithChildren from './AnimatedWithChildren';
import type { InterpolationConfigType } from './AnimatedInterpolation';
import type {InterpolationConfigType} from './AnimatedInterpolation';
class AnimatedDiffClamp extends AnimatedWithChildren {
_a: AnimatedNode;
@@ -62,7 +62,7 @@ class AnimatedDiffClamp extends AnimatedWithChildren {
type: 'diffclamp',
input: this._a.__getNativeTag(),
min: this._min,
max: this._max
max: this._max,
};
}
}

View File

@@ -14,7 +14,7 @@ import AnimatedNode from './AnimatedNode';
import AnimatedValue from './AnimatedValue';
import AnimatedWithChildren from './AnimatedWithChildren';
import type { InterpolationConfigType } from './AnimatedInterpolation';
import type {InterpolationConfigType} from './AnimatedInterpolation';
class AnimatedDivision extends AnimatedWithChildren {
_a: AnimatedNode;
@@ -59,7 +59,7 @@ class AnimatedDivision extends AnimatedWithChildren {
__getNativeConfig(): any {
return {
type: 'division',
input: [this._a.__getNativeTag(), this._b.__getNativeTag()]
input: [this._a.__getNativeTag(), this._b.__getNativeTag()],
};
}
}

View File

@@ -29,7 +29,7 @@ export type InterpolationConfigType = {
easing?: (input: number) => number,
extrapolate?: ExtrapolateType,
extrapolateLeft?: ExtrapolateType,
extrapolateRight?: ExtrapolateType
extrapolateRight?: ExtrapolateType,
};
const linear = t => t;
@@ -38,7 +38,9 @@ const linear = t => t;
* Very handy helper to map input ranges to output ranges with an easing
* function and custom behavior outside of the ranges.
*/
function createInterpolation(config: InterpolationConfigType): (input: number) => number | string {
function createInterpolation(
config: InterpolationConfigType,
): (input: number) => number | string {
if (config.outputRange && typeof config.outputRange[0] === 'string') {
return createInterpolationFromStringOutputRange(config);
}
@@ -56,7 +58,7 @@ function createInterpolation(config: InterpolationConfigType): (input: number) =
inputRange.length +
') and outputRange (' +
outputRange.length +
') must have the same length'
') must have the same length',
);
const easing = config.easing || linear;
@@ -76,7 +78,10 @@ function createInterpolation(config: InterpolationConfigType): (input: number) =
}
return input => {
invariant(typeof input === 'number', 'Cannot interpolation an input which is not a number');
invariant(
typeof input === 'number',
'Cannot interpolation an input which is not a number',
);
const range = findRange(input, inputRange);
return interpolate(
@@ -87,7 +92,7 @@ function createInterpolation(config: InterpolationConfigType): (input: number) =
outputRange[range + 1],
easing,
extrapolateLeft,
extrapolateRight
extrapolateRight,
);
};
}
@@ -100,7 +105,7 @@ function interpolate(
outputMax: number,
easing: (input: number) => number,
extrapolateLeft: ExtrapolateType,
extrapolateRight: ExtrapolateType
extrapolateRight: ExtrapolateType,
) {
let result = input;
@@ -187,7 +192,7 @@ const stringShapeRegex = /[0-9\.-]+/g;
* -45deg // values with units
*/
function createInterpolationFromStringOutputRange(
config: InterpolationConfigType
config: InterpolationConfigType,
): (input: number) => string {
let outputRange: Array<string> = (config.outputRange: any);
invariant(outputRange.length >= 2, 'Bad output range');
@@ -218,12 +223,14 @@ function createInterpolationFromStringOutputRange(
/* $FlowFixMe(>=0.18.0): `outputRange[0].match()` can return `null`. Need to
* guard against this possibility.
*/
const interpolations = outputRange[0].match(stringShapeRegex).map((value, i) => {
return createInterpolation({
...config,
outputRange: outputRanges[i]
const interpolations = outputRange[0]
.match(stringShapeRegex)
.map((value, i) => {
return createInterpolation({
...config,
outputRange: outputRanges[i],
});
});
});
// rgba requires that the r,g,b are integers.... so we want to round them, but we *dont* want to
// round the opacity (4th column).
@@ -236,7 +243,8 @@ function createInterpolationFromStringOutputRange(
// 'rgba(${interpolations[0](input)}, ${interpolations[1](input)}, ...'
return outputRange[0].replace(stringShapeRegex, () => {
const val = +interpolations[i++](input);
const rounded = shouldRound && i < 4 ? Math.round(val) : Math.round(val * 1000) / 1000;
const rounded =
shouldRound && i < 4 ? Math.round(val) : Math.round(val * 1000) / 1000;
return String(rounded);
});
};
@@ -251,7 +259,7 @@ function checkPattern(arr: Array<string>) {
for (let i = 1; i < arr.length; ++i) {
invariant(
pattern === arr[i].replace(stringShapeRegex, ''),
'invalid pattern ' + arr[0] + ' and ' + arr[i]
'invalid pattern ' + arr[0] + ' and ' + arr[i],
);
}
}
@@ -277,7 +285,7 @@ function checkValidInputRange(arr: Array<number>) {
* mean this implicit string conversion, you can do something like
* String(myThing)
*/
'inputRange must be monotonically increasing ' + arr
'inputRange must be monotonically increasing ' + arr,
);
}
}
@@ -292,7 +300,7 @@ function checkInfiniteRange(name: string, arr: Array<number>) {
* this implicit string conversion, you can do something like
* String(myThing)
*/
name + 'cannot be ]-infinity;+infinity[ ' + arr
name + 'cannot be ]-infinity;+infinity[ ' + arr,
);
}
@@ -320,7 +328,7 @@ class AnimatedInterpolation extends AnimatedWithChildren {
const parentValue: number = this._parent.__getValue();
invariant(
typeof parentValue === 'number',
'Cannot interpolate an input which is not a number.'
'Cannot interpolate an input which is not a number.',
);
return this._interpolation(parentValue);
}
@@ -363,11 +371,13 @@ class AnimatedInterpolation extends AnimatedWithChildren {
return {
inputRange: this._config.inputRange,
// Only the `outputRange` can contain strings so we don't need to tranform `inputRange` here
// Only the `outputRange` can contain strings so we don't need to transform `inputRange` here
outputRange: this.__transformDataType(this._config.outputRange),
extrapolateLeft: this._config.extrapolateLeft || this._config.extrapolate || 'extend',
extrapolateRight: this._config.extrapolateRight || this._config.extrapolate || 'extend',
type: 'interpolation'
extrapolateLeft:
this._config.extrapolateLeft || this._config.extrapolate || 'extend',
extrapolateRight:
this._config.extrapolateRight || this._config.extrapolate || 'extend',
type: 'interpolation',
};
}
}

View File

@@ -13,7 +13,7 @@ import AnimatedInterpolation from './AnimatedInterpolation';
import AnimatedNode from './AnimatedNode';
import AnimatedWithChildren from './AnimatedWithChildren';
import type { InterpolationConfigType } from './AnimatedInterpolation';
import type {InterpolationConfigType} from './AnimatedInterpolation';
class AnimatedModulo extends AnimatedWithChildren {
_a: AnimatedNode;
@@ -31,7 +31,9 @@ class AnimatedModulo extends AnimatedWithChildren {
}
__getValue(): number {
return (this._a.__getValue() % this._modulus + this._modulus) % this._modulus;
return (
(this._a.__getValue() % this._modulus + this._modulus) % this._modulus
);
}
interpolate(config: InterpolationConfigType): AnimatedInterpolation {
@@ -51,7 +53,7 @@ class AnimatedModulo extends AnimatedWithChildren {
return {
type: 'modulus',
input: this._a.__getNativeTag(),
modulus: this._modulus
modulus: this._modulus,
};
}
}

View File

@@ -14,7 +14,7 @@ import AnimatedNode from './AnimatedNode';
import AnimatedValue from './AnimatedValue';
import AnimatedWithChildren from './AnimatedWithChildren';
import type { InterpolationConfigType } from './AnimatedInterpolation';
import type {InterpolationConfigType} from './AnimatedInterpolation';
class AnimatedMultiplication extends AnimatedWithChildren {
_a: AnimatedNode;
@@ -54,7 +54,7 @@ class AnimatedMultiplication extends AnimatedWithChildren {
__getNativeConfig(): any {
return {
type: 'multiplication',
input: [this._a.__getNativeTag(), this._b.__getNativeTag()]
input: [this._a.__getNativeTag(), this._b.__getNativeTag()],
};
}
}

View File

@@ -43,16 +43,24 @@ class AnimatedNode {
}
__getNativeTag(): ?number {
NativeAnimatedHelper.assertNativeAnimatedModule();
invariant(this.__isNative, 'Attempt to get native tag from node not marked as "native"');
invariant(
this.__isNative,
'Attempt to get native tag from node not marked as "native"',
);
if (this.__nativeTag == null) {
const nativeTag: ?number = NativeAnimatedHelper.generateNewNodeTag();
NativeAnimatedHelper.API.createAnimatedNode(nativeTag, this.__getNativeConfig());
NativeAnimatedHelper.API.createAnimatedNode(
nativeTag,
this.__getNativeConfig(),
);
this.__nativeTag = nativeTag;
}
return this.__nativeTag;
}
__getNativeConfig(): Object {
throw new Error('This JS animated node type cannot be used as native animated node');
throw new Error(
'This JS animated node type cannot be used as native animated node',
);
}
toJSON(): any {
return this.__getValue();

View File

@@ -27,7 +27,7 @@ class AnimatedProps extends AnimatedNode {
if (props.style) {
props = {
...props,
style: new AnimatedStyle(props.style)
style: new AnimatedStyle(props.style),
};
}
this._props = props;
@@ -118,16 +118,32 @@ class AnimatedProps extends AnimatedNode {
__connectAnimatedView(): void {
invariant(this.__isNative, 'Expected node to be marked as "native"');
const nativeViewTag: ?number = findNodeHandle(this._animatedView);
invariant(nativeViewTag != null, 'Unable to locate attached view in the native tree');
NativeAnimatedHelper.API.connectAnimatedNodeToView(this.__getNativeTag(), nativeViewTag);
const nativeViewTag: ?number = findNodeHandle(
this._animatedView,
);
invariant(
nativeViewTag != null,
'Unable to locate attached view in the native tree',
);
NativeAnimatedHelper.API.connectAnimatedNodeToView(
this.__getNativeTag(),
nativeViewTag,
);
}
__disconnectAnimatedView(): void {
invariant(this.__isNative, 'Expected node to be marked as "native"');
const nativeViewTag: ?number = findNodeHandle(this._animatedView);
invariant(nativeViewTag != null, 'Unable to locate attached view in the native tree');
NativeAnimatedHelper.API.disconnectAnimatedNodeFromView(this.__getNativeTag(), nativeViewTag);
const nativeViewTag: ?number = findNodeHandle(
this._animatedView,
);
invariant(
nativeViewTag != null,
'Unable to locate attached view in the native tree',
);
NativeAnimatedHelper.API.disconnectAnimatedNodeFromView(
this.__getNativeTag(),
nativeViewTag,
);
}
__getNativeConfig(): Object {
@@ -140,7 +156,7 @@ class AnimatedProps extends AnimatedNode {
}
return {
type: 'props',
props: propsConfig
props: propsConfig,
};
}
}

View File

@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @noflow
* @format
*/
'use strict';
@@ -26,14 +26,14 @@ class AnimatedStyle extends AnimatedWithChildren {
if (style.transform) {
style = {
...style,
transform: new AnimatedTransform(style.transform)
transform: new AnimatedTransform(style.transform),
};
}
this._style = style;
}
// Recursively get values for nested styles (like iOS's shadowOffset)
_walkStyleAndGetValues(style: Object) {
_walkStyleAndGetValues(style) {
const updatedStyle = {};
for (const key in style) {
const value = style[key];
@@ -58,7 +58,7 @@ class AnimatedStyle extends AnimatedWithChildren {
}
// Recursively get animated values for nested styles (like iOS's shadowOffset)
_walkStyleAndGetAnimatedValues(style: Object) {
_walkStyleAndGetAnimatedValues(style) {
const updatedStyle = {};
for (const key in style) {
const value = style[key];
@@ -117,7 +117,7 @@ class AnimatedStyle extends AnimatedWithChildren {
NativeAnimatedHelper.validateStyles(styleConfig);
return {
type: 'style',
style: styleConfig
style: styleConfig,
};
}
}

View File

@@ -11,8 +11,12 @@
import AnimatedValue from './AnimatedValue';
import AnimatedNode from './AnimatedNode';
import {
generateNewAnimationId,
shouldUseNativeDriver,
} from '../NativeAnimatedHelper';
import type { EndCallback } from '../animations/Animation';
import type {EndCallback} from '../animations/Animation';
class AnimatedTracking extends AnimatedNode {
_value: AnimatedValue;
@@ -20,29 +24,46 @@ class AnimatedTracking extends AnimatedNode {
_callback: ?EndCallback;
_animationConfig: Object;
_animationClass: any;
_useNativeDriver: boolean;
constructor(
value: AnimatedValue,
parent: AnimatedNode,
animationClass: any,
animationConfig: Object,
callback?: ?EndCallback
callback?: ?EndCallback,
) {
super();
this._value = value;
this._parent = parent;
this._animationClass = animationClass;
this._animationConfig = animationConfig;
this._useNativeDriver = shouldUseNativeDriver(animationConfig);
this._callback = callback;
this.__attach();
}
__makeNative() {
this.__isNative = true;
this._parent.__makeNative();
super.__makeNative();
this._value.__makeNative();
}
__getValue(): Object {
return this._parent.__getValue();
}
__attach(): void {
this._parent.__addChild(this);
if (this._useNativeDriver) {
// when the tracking starts we need to convert this node to a "native node"
// so that the parent node will be made "native" too. This is necessary as
// if we don't do this `update` method will get called. At that point it
// may be too late as it would mean the JS driver has already started
// updating node values
this.__makeNative();
}
}
__detach(): void {
@@ -54,11 +75,27 @@ class AnimatedTracking extends AnimatedNode {
this._value.animate(
new this._animationClass({
...this._animationConfig,
toValue: (this._animationConfig.toValue: any).__getValue()
toValue: (this._animationConfig.toValue: any).__getValue(),
}),
this._callback
this._callback,
);
}
__getNativeConfig(): any {
const animation = new this._animationClass({
...this._animationConfig,
// remove toValue from the config as it's a ref to Animated.Value
toValue: undefined,
});
const animationConfig = animation.__getNativeAnimationConfig();
return {
type: 'tracking',
animationId: generateNewAnimationId(),
animationConfig,
toValue: this._parent.__getNativeTag(),
value: this._value.__getNativeTag(),
};
}
}
export default AnimatedTracking;

View File

@@ -14,9 +14,9 @@ import AnimatedWithChildren from './AnimatedWithChildren';
import NativeAnimatedHelper from '../NativeAnimatedHelper';
class AnimatedTransform extends AnimatedWithChildren {
_transforms: Array<Object>;
_transforms: $ReadOnlyArray<Object>;
constructor(transforms: Array<Object>) {
constructor(transforms: $ReadOnlyArray<Object>) {
super();
this._transforms = transforms;
}
@@ -33,7 +33,7 @@ class AnimatedTransform extends AnimatedWithChildren {
});
}
__getValue(): Array<Object> {
__getValue(): $ReadOnlyArray<Object> {
return this._transforms.map(transform => {
const result = {};
for (const key in transform) {
@@ -48,7 +48,7 @@ class AnimatedTransform extends AnimatedWithChildren {
});
}
__getAnimatedValue(): Array<Object> {
__getAnimatedValue(): $ReadOnlyArray<Object> {
return this._transforms.map(transform => {
const result = {};
for (const key in transform) {
@@ -97,13 +97,13 @@ class AnimatedTransform extends AnimatedWithChildren {
transConfigs.push({
type: 'animated',
property: key,
nodeTag: value.__getNativeTag()
nodeTag: value.__getNativeTag(),
});
} else {
transConfigs.push({
type: 'static',
property: key,
value
value,
});
}
}
@@ -112,7 +112,7 @@ class AnimatedTransform extends AnimatedWithChildren {
NativeAnimatedHelper.validateTransform(transConfigs);
return {
type: 'transform',
transforms: transConfigs
transforms: transConfigs,
};
}
}

View File

@@ -15,12 +15,13 @@ import AnimatedWithChildren from './AnimatedWithChildren';
import InteractionManager from '../../../../exports/InteractionManager';
import NativeAnimatedHelper from '../NativeAnimatedHelper';
import type Animation, { EndCallback } from '../animations/Animation';
import type { InterpolationConfigType } from './AnimatedInterpolation';
import type Animation, {EndCallback} from '../animations/Animation';
import type {InterpolationConfigType} from './AnimatedInterpolation';
import type AnimatedTracking from './AnimatedTracking';
const NativeAnimatedAPI = NativeAnimatedHelper.API;
type ValueListenerCallback = (state: { value: number }) => void;
type ValueListenerCallback = (state: {value: number}) => void;
let _uniqueId = 1;
@@ -73,8 +74,8 @@ class AnimatedValue extends AnimatedWithChildren {
_startingValue: number;
_offset: number;
_animation: ?Animation;
_tracking: ?AnimatedNode;
_listeners: { [key: string]: ValueListenerCallback };
_tracking: ?AnimatedTracking;
_listeners: {[key: string]: ValueListenerCallback};
__nativeAnimatedValueListener: ?any;
constructor(value: number) {
@@ -115,7 +116,7 @@ class AnimatedValue extends AnimatedWithChildren {
}
this._updateValue(
value,
!this.__isNative /* don't perform a flush for natively driven values */
!this.__isNative /* don't perform a flush for natively driven values */,
);
if (this.__isNative) {
NativeAnimatedAPI.setAnimatedNodeValue(this.__getNativeTag(), value);
@@ -218,7 +219,7 @@ class AnimatedValue extends AnimatedWithChildren {
return;
}
this._updateValue(data.value, false /* flush */);
}
},
);
}
@@ -293,7 +294,7 @@ class AnimatedValue extends AnimatedWithChildren {
callback && callback(result);
},
previousAnimation,
this
this,
);
}
@@ -308,7 +309,7 @@ class AnimatedValue extends AnimatedWithChildren {
/**
* Typically only used internally.
*/
track(tracking: AnimatedNode): void {
track(tracking: AnimatedTracking): void {
this.stopTracking();
this._tracking = tracking;
}
@@ -319,7 +320,7 @@ class AnimatedValue extends AnimatedWithChildren {
_flush(this);
}
for (const key in this._listeners) {
this._listeners[key]({ value: this.__getValue() });
this._listeners[key]({value: this.__getValue()});
}
}
@@ -327,7 +328,7 @@ class AnimatedValue extends AnimatedWithChildren {
return {
type: 'value',
value: this._value,
offset: this._offset
offset: this._offset,
};
}
}

View File

@@ -14,7 +14,7 @@ import AnimatedWithChildren from './AnimatedWithChildren';
import invariant from 'fbjs/lib/invariant';
type ValueXYListenerCallback = (value: { x: number, y: number }) => void;
type ValueXYListenerCallback = (value: {x: number, y: number}) => void;
let _uniqueId = 1;
@@ -27,18 +27,21 @@ let _uniqueId = 1;
class AnimatedValueXY extends AnimatedWithChildren {
x: AnimatedValue;
y: AnimatedValue;
_listeners: { [key: string]: { x: string, y: string } };
_listeners: {[key: string]: {x: string, y: string}};
constructor(valueIn?: ?{ x: number | AnimatedValue, y: number | AnimatedValue }) {
constructor(
valueIn?: ?{+x: number | AnimatedValue, +y: number | AnimatedValue},
) {
super();
const value: any = valueIn || { x: 0, y: 0 }; // @flowfixme: shouldn't need `: any`
const value: any = valueIn || {x: 0, y: 0}; // @flowfixme: shouldn't need `: any`
if (typeof value.x === 'number' && typeof value.y === 'number') {
this.x = new AnimatedValue(value.x);
this.y = new AnimatedValue(value.y);
} else {
invariant(
value.x instanceof AnimatedValue && value.y instanceof AnimatedValue,
'AnimatedValueXY must be initalized with an object of numbers or ' + 'AnimatedValues.'
'AnimatedValueXY must be initialized with an object of numbers or ' +
'AnimatedValues.',
);
this.x = value.x;
this.y = value.y;
@@ -52,7 +55,7 @@ class AnimatedValueXY extends AnimatedWithChildren {
*
* See http://facebook.github.io/react-native/docs/animatedvaluexy.html#setvalue
*/
setValue(value: { x: number, y: number }) {
setValue(value: {x: number, y: number}) {
this.x.setValue(value.x);
this.y.setValue(value.y);
}
@@ -64,7 +67,7 @@ class AnimatedValueXY extends AnimatedWithChildren {
*
* See http://facebook.github.io/react-native/docs/animatedvaluexy.html#setoffset
*/
setOffset(offset: { x: number, y: number }) {
setOffset(offset: {x: number, y: number}) {
this.x.setOffset(offset.x);
this.y.setOffset(offset.y);
}
@@ -91,10 +94,10 @@ class AnimatedValueXY extends AnimatedWithChildren {
this.y.extractOffset();
}
__getValue(): { x: number, y: number } {
__getValue(): {x: number, y: number} {
return {
x: this.x.__getValue(),
y: this.y.__getValue()
y: this.y.__getValue(),
};
}
@@ -103,7 +106,7 @@ class AnimatedValueXY extends AnimatedWithChildren {
*
* See http://facebook.github.io/react-native/docs/animatedvaluexy.html#resetanimation
*/
resetAnimation(callback?: (value: { x: number, y: number }) => void): void {
resetAnimation(callback?: (value: {x: number, y: number}) => void): void {
this.x.resetAnimation();
this.y.resetAnimation();
callback && callback(this.__getValue());
@@ -116,7 +119,7 @@ class AnimatedValueXY extends AnimatedWithChildren {
*
* See http://facebook.github.io/react-native/docs/animatedvaluexy.html#stopanimation
*/
stopAnimation(callback?: (value: { x: number, y: number }) => void): void {
stopAnimation(callback?: (value: {x: number, y: number}) => void): void {
this.x.stopAnimation();
this.y.stopAnimation();
callback && callback(this.__getValue());
@@ -133,12 +136,12 @@ class AnimatedValueXY extends AnimatedWithChildren {
*/
addListener(callback: ValueXYListenerCallback): string {
const id = String(_uniqueId++);
const jointCallback = ({ value: number }) => {
const jointCallback = ({value: number}) => {
callback(this.__getValue());
};
this._listeners[id] = {
x: this.x.addListener(jointCallback),
y: this.y.addListener(jointCallback)
y: this.y.addListener(jointCallback),
};
return id;
}
@@ -171,10 +174,10 @@ class AnimatedValueXY extends AnimatedWithChildren {
*
* See http://facebook.github.io/react-native/docs/animatedvaluexy.html#getlayout
*/
getLayout(): { [key: string]: AnimatedValue } {
getLayout(): {[key: string]: AnimatedValue} {
return {
left: this.x,
top: this.y
top: this.y,
};
}
@@ -183,8 +186,8 @@ class AnimatedValueXY extends AnimatedWithChildren {
*
* See http://facebook.github.io/react-native/docs/animatedvaluexy.html#gettranslatetransform
*/
getTranslateTransform(): Array<{ [key: string]: AnimatedValue }> {
return [{ translateX: this.x }, { translateY: this.y }];
getTranslateTransform(): Array<{[key: string]: AnimatedValue}> {
return [{translateX: this.x}, {translateY: this.y}];
}
}

View File

@@ -27,7 +27,7 @@ class AnimatedWithChildren extends AnimatedNode {
child.__makeNative();
NativeAnimatedHelper.API.connectAnimatedNodes(
this.__getNativeTag(),
child.__getNativeTag()
child.__getNativeTag(),
);
}
}
@@ -41,7 +41,10 @@ class AnimatedWithChildren extends AnimatedNode {
if (this.__isNative) {
// Only accept "native" animated nodes as children
child.__makeNative();
NativeAnimatedHelper.API.connectAnimatedNodes(this.__getNativeTag(), child.__getNativeTag());
NativeAnimatedHelper.API.connectAnimatedNodes(
this.__getNativeTag(),
child.__getNativeTag(),
);
}
}
@@ -54,7 +57,7 @@ class AnimatedWithChildren extends AnimatedNode {
if (this.__isNative && child.__isNative) {
NativeAnimatedHelper.API.disconnectAnimatedNodes(
this.__getNativeTag(),
child.__getNativeTag()
child.__getNativeTag(),
);
}
this._children.splice(index, 1);

View File

@@ -0,0 +1,13 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
module.exports = {
createInteractionHandle: function() {},
clearInteractionHandle: function() {}
};

View File

@@ -0,0 +1,24 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
function SetPolyfill() {
this._cache = [];
}
SetPolyfill.prototype.add = function(e) {
if (this._cache.indexOf(e) === -1) {
this._cache.push(e);
}
};
SetPolyfill.prototype.forEach = function(cb) {
this._cache.forEach(cb);
};
module.exports = SetPolyfill;

View File

@@ -0,0 +1,10 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
module.exports = function(style) {
return style;
};