mirror of
https://github.com/zhigang1992/react-native-web.git
synced 2026-03-27 01:34:17 +08:00
[change] update the Animated implementation
Replaces the 'animated' package with the latest implementation from React Native. Requires a few imports to be replaced. Close #716 Fix #714 Fix #688
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
.*/__tests__/.*
|
||||
.*/benchmarks/.*
|
||||
.*/docs/.*
|
||||
.*/node_modules/animated/*
|
||||
.*/node_modules/babel-plugin-transform-react-remove-prop-types/*
|
||||
|
||||
[include]
|
||||
|
||||
@@ -19,12 +19,12 @@
|
||||
"docs:start": "cd docs && yarn && yarn start",
|
||||
"docs:release": "cd docs && yarn release",
|
||||
"flow": "flow",
|
||||
"fmt": "find babel benchmarks docs jest src -name '*.js' | grep -v -E '(node_modules|dist)' | xargs yarn fmt:cmd",
|
||||
"fmt": "find babel benchmarks docs jest src -name '*.js' | grep -v -E '(node_modules|dist|vendor)' | xargs yarn fmt:cmd",
|
||||
"fmt:cmd": "prettier --print-width=100 --single-quote --write",
|
||||
"jest": "jest",
|
||||
"jest:watch": "yarn test --watch",
|
||||
"lint": "yarn lint:cmd babel benchmarks docs jest src",
|
||||
"lint:cmd": "eslint --ignore-path .gitignore --fix",
|
||||
"lint:cmd": "eslint --ignore-path .gitignore --ignore-pattern '/src/vendor/*' --fix",
|
||||
"precommit": "lint-staged",
|
||||
"release": "yarn lint && yarn test && yarn build && npm publish",
|
||||
"test": "flow && jest"
|
||||
@@ -61,7 +61,6 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"animated": "^0.2.0",
|
||||
"array-find-index": "^1.0.2",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"create-react-class": "^15.6.2",
|
||||
|
||||
@@ -3,27 +3,25 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule Animated
|
||||
* @noflow
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import Animated from 'animated';
|
||||
import AnimatedImplementation from '../../vendor/Animated/AnimatedImplementation';
|
||||
import Image from '../../components/Image';
|
||||
import ScrollView from '../../components/ScrollView';
|
||||
import StyleSheet from '../StyleSheet';
|
||||
import Text from '../../components/Text';
|
||||
import View from '../../components/View';
|
||||
|
||||
Animated.inject.FlattenStyle(StyleSheet.flatten);
|
||||
|
||||
const AnimatedImplementation = {
|
||||
...Animated,
|
||||
Image: Animated.createAnimatedComponent(Image),
|
||||
ScrollView: Animated.createAnimatedComponent(ScrollView),
|
||||
Text: Animated.createAnimatedComponent(Text),
|
||||
View: Animated.createAnimatedComponent(View)
|
||||
const Animated = {
|
||||
...AnimatedImplementation,
|
||||
Image: AnimatedImplementation.createAnimatedComponent(Image),
|
||||
ScrollView: AnimatedImplementation.createAnimatedComponent(ScrollView),
|
||||
View: AnimatedImplementation.createAnimatedComponent(View),
|
||||
Text: AnimatedImplementation.createAnimatedComponent(Text)
|
||||
};
|
||||
|
||||
export default AnimatedImplementation;
|
||||
export default Animated;
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule Easing
|
||||
* @noflow
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import Easing from 'animated/lib/Easing';
|
||||
import Easing from '../../vendor/Animated/Easing';
|
||||
export default Easing;
|
||||
|
||||
25
src/modules/NativeEventEmitter/index.js
Normal file
25
src/modules/NativeEventEmitter/index.js
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule NativeEventEmitter
|
||||
* @noflow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
class NativeEventEmitter {
|
||||
addListener() {}
|
||||
emit() {}
|
||||
listeners() {}
|
||||
once() {}
|
||||
removeAllListeners() {}
|
||||
removeCurrentListener() {}
|
||||
removeListener() {}
|
||||
removeSubscription() {}
|
||||
}
|
||||
|
||||
module.exports = NativeEventEmitter;
|
||||
@@ -1,3 +1,3 @@
|
||||
// NativeModules shim
|
||||
const NativeModules = {};
|
||||
export default NativeModules;
|
||||
module.exports = NativeModules;
|
||||
|
||||
196
src/vendor/Animated/AnimatedEvent.js
vendored
Normal file
196
src/vendor/Animated/AnimatedEvent.js
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule AnimatedEvent
|
||||
* @noflow
|
||||
* @format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const AnimatedValue = require('./nodes/AnimatedValue');
|
||||
const NativeAnimatedHelper = require('./NativeAnimatedHelper');
|
||||
const findNodeHandle = require('../../modules/findNodeHandle').default;
|
||||
|
||||
const invariant = require('fbjs/lib/invariant');
|
||||
const {shouldUseNativeDriver} = require('./NativeAnimatedHelper');
|
||||
|
||||
export type Mapping = {[key: string]: Mapping} | AnimatedValue;
|
||||
export type EventConfig = {
|
||||
listener?: ?Function,
|
||||
useNativeDriver?: boolean,
|
||||
};
|
||||
|
||||
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 = [];
|
||||
|
||||
const traverse = (value, path) => {
|
||||
if (value instanceof AnimatedValue) {
|
||||
value.__makeNative();
|
||||
|
||||
eventMappings.push({
|
||||
nativeEventPath: path,
|
||||
animatedValueTag: value.__getNativeTag(),
|
||||
});
|
||||
} else if (typeof value === 'object') {
|
||||
for (const key in value) {
|
||||
traverse(value[key], path.concat(key));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
invariant(
|
||||
argMapping[0] && argMapping[0].nativeEvent,
|
||||
'Native driven events only support animated values contained inside `nativeEvent`.',
|
||||
);
|
||||
|
||||
// Assume that the event containing `nativeEvent` is always the first argument.
|
||||
traverse(argMapping[0].nativeEvent, []);
|
||||
|
||||
const viewTag = findNodeHandle(viewRef);
|
||||
|
||||
eventMappings.forEach(mapping => {
|
||||
NativeAnimatedHelper.API.addAnimatedEventToView(
|
||||
viewTag,
|
||||
eventName,
|
||||
mapping,
|
||||
);
|
||||
});
|
||||
|
||||
return {
|
||||
detach() {
|
||||
eventMappings.forEach(mapping => {
|
||||
NativeAnimatedHelper.API.removeAnimatedEventFromView(
|
||||
viewTag,
|
||||
eventName,
|
||||
mapping.animatedValueTag,
|
||||
);
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
class AnimatedEvent {
|
||||
_argMapping: Array<?Mapping>;
|
||||
_listeners: Array<Function> = [];
|
||||
_callListeners: Function;
|
||||
_attachedEvent: ?{
|
||||
detach: () => void,
|
||||
};
|
||||
__isNative: boolean;
|
||||
|
||||
constructor(argMapping: Array<?Mapping>, config?: EventConfig = {}) {
|
||||
this._argMapping = argMapping;
|
||||
if (config.listener) {
|
||||
this.__addListener(config.listener);
|
||||
}
|
||||
this._callListeners = this._callListeners.bind(this);
|
||||
this._attachedEvent = null;
|
||||
this.__isNative = shouldUseNativeDriver(config);
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
this._validateMapping();
|
||||
}
|
||||
}
|
||||
|
||||
__addListener(callback: Function): void {
|
||||
this._listeners.push(callback);
|
||||
}
|
||||
|
||||
__removeListener(callback: Function): void {
|
||||
this._listeners = this._listeners.filter(listener => listener !== callback);
|
||||
}
|
||||
|
||||
__attach(viewRef: any, eventName: string) {
|
||||
invariant(
|
||||
this.__isNative,
|
||||
'Only native driven events need to be attached.',
|
||||
);
|
||||
|
||||
this._attachedEvent = attachNativeEvent(
|
||||
viewRef,
|
||||
eventName,
|
||||
this._argMapping,
|
||||
);
|
||||
}
|
||||
|
||||
__detach(viewTag: any, eventName: string) {
|
||||
invariant(
|
||||
this.__isNative,
|
||||
'Only native driven events need to be detached.',
|
||||
);
|
||||
|
||||
this._attachedEvent && this._attachedEvent.detach();
|
||||
}
|
||||
|
||||
__getHandler() {
|
||||
if (this.__isNative) {
|
||||
return this._callListeners;
|
||||
}
|
||||
|
||||
return (...args: any) => {
|
||||
const traverse = (recMapping, recEvt, key) => {
|
||||
if (typeof recEvt === 'number' && recMapping instanceof AnimatedValue) {
|
||||
recMapping.setValue(recEvt);
|
||||
} else if (typeof recMapping === 'object') {
|
||||
for (const mappingKey in recMapping) {
|
||||
/* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This
|
||||
* comment suppresses an error when upgrading Flow's support for
|
||||
* React. To see the error delete this comment and run Flow. */
|
||||
traverse(recMapping[mappingKey], recEvt[mappingKey], mappingKey);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (!this.__isNative) {
|
||||
this._argMapping.forEach((mapping, idx) => {
|
||||
traverse(mapping, args[idx], 'arg' + idx);
|
||||
});
|
||||
}
|
||||
this._callListeners(...args);
|
||||
};
|
||||
}
|
||||
|
||||
_callListeners(...args) {
|
||||
this._listeners.forEach(listener => listener(...args));
|
||||
}
|
||||
|
||||
_validateMapping() {
|
||||
const traverse = (recMapping, recEvt, key) => {
|
||||
if (typeof recEvt === 'number') {
|
||||
invariant(
|
||||
recMapping instanceof AnimatedValue,
|
||||
'Bad mapping of type ' +
|
||||
typeof recMapping +
|
||||
' for key ' +
|
||||
key +
|
||||
', event value must map to AnimatedValue',
|
||||
);
|
||||
return;
|
||||
}
|
||||
invariant(
|
||||
typeof recMapping === 'object',
|
||||
'Bad mapping of type ' + typeof recMapping + ' for key ' + key,
|
||||
);
|
||||
invariant(
|
||||
typeof recEvt === 'object',
|
||||
'Bad event of type ' + typeof recEvt + ' for key ' + key,
|
||||
);
|
||||
for (const mappingKey in recMapping) {
|
||||
traverse(recMapping[mappingKey], recEvt[mappingKey], mappingKey);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {AnimatedEvent, attachNativeEvent};
|
||||
676
src/vendor/Animated/AnimatedImplementation.js
vendored
Normal file
676
src/vendor/Animated/AnimatedImplementation.js
vendored
Normal file
@@ -0,0 +1,676 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule AnimatedImplementation
|
||||
* @flow
|
||||
* @format
|
||||
* @preventMunge
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const {AnimatedEvent, attachNativeEvent} = require('./AnimatedEvent');
|
||||
const AnimatedAddition = require('./nodes/AnimatedAddition');
|
||||
const AnimatedDiffClamp = require('./nodes/AnimatedDiffClamp');
|
||||
const AnimatedDivision = require('./nodes/AnimatedDivision');
|
||||
const AnimatedInterpolation = require('./nodes/AnimatedInterpolation');
|
||||
const AnimatedModulo = require('./nodes/AnimatedModulo');
|
||||
const AnimatedMultiplication = require('./nodes/AnimatedMultiplication');
|
||||
const AnimatedNode = require('./nodes/AnimatedNode');
|
||||
const AnimatedProps = require('./nodes/AnimatedProps');
|
||||
const AnimatedTracking = require('./nodes/AnimatedTracking');
|
||||
const AnimatedValue = require('./nodes/AnimatedValue');
|
||||
const AnimatedValueXY = require('./nodes/AnimatedValueXY');
|
||||
const DecayAnimation = require('./animations/DecayAnimation');
|
||||
const SpringAnimation = require('./animations/SpringAnimation');
|
||||
const TimingAnimation = require('./animations/TimingAnimation');
|
||||
|
||||
const createAnimatedComponent = require('./createAnimatedComponent');
|
||||
|
||||
import type {
|
||||
AnimationConfig,
|
||||
EndCallback,
|
||||
EndResult,
|
||||
} from './animations/Animation';
|
||||
import type {TimingAnimationConfig} from './animations/TimingAnimation';
|
||||
import type {DecayAnimationConfig} from './animations/DecayAnimation';
|
||||
import type {SpringAnimationConfig} from './animations/SpringAnimation';
|
||||
import type {Mapping, EventConfig} from './AnimatedEvent';
|
||||
|
||||
type CompositeAnimation = {
|
||||
start: (callback?: ?EndCallback) => void,
|
||||
stop: () => void,
|
||||
reset: () => void,
|
||||
_startNativeLoop: (iterations?: number) => void,
|
||||
_isUsingNativeDriver: () => boolean,
|
||||
};
|
||||
|
||||
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 {
|
||||
return new AnimatedDivision(a, b);
|
||||
};
|
||||
|
||||
const multiply = function(
|
||||
a: AnimatedNode | number,
|
||||
b: AnimatedNode | number,
|
||||
): AnimatedMultiplication {
|
||||
return new AnimatedMultiplication(a, b);
|
||||
};
|
||||
|
||||
const modulo = function(a: AnimatedNode, modulus: number): AnimatedModulo {
|
||||
return new AnimatedModulo(a, modulus);
|
||||
};
|
||||
|
||||
const diffClamp = function(
|
||||
a: AnimatedNode,
|
||||
min: number,
|
||||
max: number,
|
||||
): AnimatedDiffClamp {
|
||||
return new AnimatedDiffClamp(a, min, max);
|
||||
};
|
||||
|
||||
const _combineCallbacks = function(
|
||||
callback: ?EndCallback,
|
||||
config: AnimationConfig,
|
||||
) {
|
||||
if (callback && config.onComplete) {
|
||||
return (...args) => {
|
||||
config.onComplete && config.onComplete(...args);
|
||||
callback && callback(...args);
|
||||
};
|
||||
} else {
|
||||
return callback || config.onComplete;
|
||||
}
|
||||
};
|
||||
|
||||
const maybeVectorAnim = function(
|
||||
value: AnimatedValue | AnimatedValueXY,
|
||||
config: Object,
|
||||
anim: (value: AnimatedValue, config: Object) => CompositeAnimation,
|
||||
): ?CompositeAnimation {
|
||||
if (value instanceof AnimatedValueXY) {
|
||||
const configX = {...config};
|
||||
const configY = {...config};
|
||||
for (const key in config) {
|
||||
const {x, y} = config[key];
|
||||
if (x !== undefined && y !== undefined) {
|
||||
configX[key] = x;
|
||||
configY[key] = y;
|
||||
}
|
||||
}
|
||||
const aX = anim((value: AnimatedValueXY).x, configX);
|
||||
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 null;
|
||||
};
|
||||
|
||||
const spring = function(
|
||||
value: AnimatedValue | AnimatedValueXY,
|
||||
config: SpringAnimationConfig,
|
||||
): CompositeAnimation {
|
||||
const start = function(
|
||||
animatedValue: AnimatedValue | AnimatedValueXY,
|
||||
configuration: SpringAnimationConfig,
|
||||
callback?: ?EndCallback,
|
||||
): void {
|
||||
callback = _combineCallbacks(callback, configuration);
|
||||
const singleValue: any = animatedValue;
|
||||
const singleConfig: any = configuration;
|
||||
singleValue.stopTracking();
|
||||
if (configuration.toValue instanceof AnimatedNode) {
|
||||
singleValue.track(
|
||||
new AnimatedTracking(
|
||||
singleValue,
|
||||
configuration.toValue,
|
||||
SpringAnimation,
|
||||
singleConfig,
|
||||
callback,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
singleValue.animate(new SpringAnimation(singleConfig), callback);
|
||||
}
|
||||
};
|
||||
return (
|
||||
maybeVectorAnim(value, config, spring) || {
|
||||
start: function(callback?: ?EndCallback): void {
|
||||
start(value, config, callback);
|
||||
},
|
||||
|
||||
stop: function(): void {
|
||||
value.stopAnimation();
|
||||
},
|
||||
|
||||
reset: function(): void {
|
||||
value.resetAnimation();
|
||||
},
|
||||
|
||||
_startNativeLoop: function(iterations?: number): void {
|
||||
const singleConfig = {...config, iterations};
|
||||
start(value, singleConfig);
|
||||
},
|
||||
|
||||
_isUsingNativeDriver: function(): boolean {
|
||||
return config.useNativeDriver || false;
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const timing = function(
|
||||
value: AnimatedValue | AnimatedValueXY,
|
||||
config: TimingAnimationConfig,
|
||||
): CompositeAnimation {
|
||||
const start = function(
|
||||
animatedValue: AnimatedValue | AnimatedValueXY,
|
||||
configuration: TimingAnimationConfig,
|
||||
callback?: ?EndCallback,
|
||||
): void {
|
||||
callback = _combineCallbacks(callback, configuration);
|
||||
const singleValue: any = animatedValue;
|
||||
const singleConfig: any = configuration;
|
||||
singleValue.stopTracking();
|
||||
if (configuration.toValue instanceof AnimatedNode) {
|
||||
singleValue.track(
|
||||
new AnimatedTracking(
|
||||
singleValue,
|
||||
configuration.toValue,
|
||||
TimingAnimation,
|
||||
singleConfig,
|
||||
callback,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
singleValue.animate(new TimingAnimation(singleConfig), callback);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
maybeVectorAnim(value, config, timing) || {
|
||||
start: function(callback?: ?EndCallback): void {
|
||||
start(value, config, callback);
|
||||
},
|
||||
|
||||
stop: function(): void {
|
||||
value.stopAnimation();
|
||||
},
|
||||
|
||||
reset: function(): void {
|
||||
value.resetAnimation();
|
||||
},
|
||||
|
||||
_startNativeLoop: function(iterations?: number): void {
|
||||
const singleConfig = {...config, iterations};
|
||||
start(value, singleConfig);
|
||||
},
|
||||
|
||||
_isUsingNativeDriver: function(): boolean {
|
||||
return config.useNativeDriver || false;
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const decay = function(
|
||||
value: AnimatedValue | AnimatedValueXY,
|
||||
config: DecayAnimationConfig,
|
||||
): CompositeAnimation {
|
||||
const start = function(
|
||||
animatedValue: AnimatedValue | AnimatedValueXY,
|
||||
configuration: DecayAnimationConfig,
|
||||
callback?: ?EndCallback,
|
||||
): void {
|
||||
callback = _combineCallbacks(callback, configuration);
|
||||
const singleValue: any = animatedValue;
|
||||
const singleConfig: any = configuration;
|
||||
singleValue.stopTracking();
|
||||
singleValue.animate(new DecayAnimation(singleConfig), callback);
|
||||
};
|
||||
|
||||
return (
|
||||
maybeVectorAnim(value, config, decay) || {
|
||||
start: function(callback?: ?EndCallback): void {
|
||||
start(value, config, callback);
|
||||
},
|
||||
|
||||
stop: function(): void {
|
||||
value.stopAnimation();
|
||||
},
|
||||
|
||||
reset: function(): void {
|
||||
value.resetAnimation();
|
||||
},
|
||||
|
||||
_startNativeLoop: function(iterations?: number): void {
|
||||
const singleConfig = {...config, iterations};
|
||||
start(value, singleConfig);
|
||||
},
|
||||
|
||||
_isUsingNativeDriver: function(): boolean {
|
||||
return config.useNativeDriver || false;
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const sequence = function(
|
||||
animations: Array<CompositeAnimation>,
|
||||
): CompositeAnimation {
|
||||
let current = 0;
|
||||
return {
|
||||
start: function(callback?: ?EndCallback) {
|
||||
const onComplete = function(result) {
|
||||
if (!result.finished) {
|
||||
callback && callback(result);
|
||||
return;
|
||||
}
|
||||
|
||||
current++;
|
||||
|
||||
if (current === animations.length) {
|
||||
callback && callback(result);
|
||||
return;
|
||||
}
|
||||
|
||||
animations[current].start(onComplete);
|
||||
};
|
||||
|
||||
if (animations.length === 0) {
|
||||
callback && callback({finished: true});
|
||||
} else {
|
||||
animations[current].start(onComplete);
|
||||
}
|
||||
},
|
||||
|
||||
stop: function() {
|
||||
if (current < animations.length) {
|
||||
animations[current].stop();
|
||||
}
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
animations.forEach((animation, idx) => {
|
||||
if (idx <= current) {
|
||||
animation.reset();
|
||||
}
|
||||
});
|
||||
current = 0;
|
||||
},
|
||||
|
||||
_startNativeLoop: function() {
|
||||
throw new Error(
|
||||
'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
|
||||
};
|
||||
const parallel = function(
|
||||
animations: Array<CompositeAnimation>,
|
||||
config?: ?ParallelConfig,
|
||||
): CompositeAnimation {
|
||||
let doneCount = 0;
|
||||
// Make sure we only call stop() at most once for each animation
|
||||
const hasEnded = {};
|
||||
const stopTogether = !(config && config.stopTogether === false);
|
||||
|
||||
const result = {
|
||||
start: function(callback?: ?EndCallback) {
|
||||
if (doneCount === animations.length) {
|
||||
callback && callback({finished: true});
|
||||
return;
|
||||
}
|
||||
|
||||
animations.forEach((animation, idx) => {
|
||||
const cb = function(endResult) {
|
||||
hasEnded[idx] = true;
|
||||
doneCount++;
|
||||
if (doneCount === animations.length) {
|
||||
doneCount = 0;
|
||||
callback && callback(endResult);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!endResult.finished && stopTogether) {
|
||||
result.stop();
|
||||
}
|
||||
};
|
||||
|
||||
if (!animation) {
|
||||
cb({finished: true});
|
||||
} else {
|
||||
animation.start(cb);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
stop: function(): void {
|
||||
animations.forEach((animation, idx) => {
|
||||
!hasEnded[idx] && animation.stop();
|
||||
hasEnded[idx] = true;
|
||||
});
|
||||
},
|
||||
|
||||
reset: function(): void {
|
||||
animations.forEach((animation, idx) => {
|
||||
animation.reset();
|
||||
hasEnded[idx] = false;
|
||||
doneCount = 0;
|
||||
});
|
||||
},
|
||||
|
||||
_startNativeLoop: function() {
|
||||
throw new Error(
|
||||
'Loops run using the native driver cannot contain Animated.parallel animations',
|
||||
);
|
||||
},
|
||||
|
||||
_isUsingNativeDriver: function(): boolean {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
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});
|
||||
};
|
||||
|
||||
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};
|
||||
|
||||
const loop = function(
|
||||
animation: CompositeAnimation,
|
||||
{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
|
||||
) {
|
||||
callback && callback(result);
|
||||
} else {
|
||||
iterationsSoFar++;
|
||||
animation.reset();
|
||||
animation.start(restart);
|
||||
}
|
||||
};
|
||||
if (!animation || iterations === 0) {
|
||||
callback && callback({finished: true});
|
||||
} else {
|
||||
if (animation._isUsingNativeDriver()) {
|
||||
animation._startNativeLoop(iterations);
|
||||
} else {
|
||||
restart(); // Start looping recursively on the js thread
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
stop: function(): void {
|
||||
isFinished = true;
|
||||
animation.stop();
|
||||
},
|
||||
|
||||
reset: function(): void {
|
||||
iterationsSoFar = 0;
|
||||
isFinished = false;
|
||||
animation.reset();
|
||||
},
|
||||
|
||||
_startNativeLoop: function() {
|
||||
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,
|
||||
): AnimatedEvent | Function {
|
||||
if (!event) {
|
||||
return listener;
|
||||
} else if (event instanceof AnimatedEvent) {
|
||||
event.__addListener(listener);
|
||||
return event;
|
||||
} else {
|
||||
return (...args) => {
|
||||
typeof event === 'function' && event(...args);
|
||||
listener(...args);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function unforkEvent(
|
||||
event: ?AnimatedEvent | ?Function,
|
||||
listener: Function,
|
||||
): void {
|
||||
if (event && event instanceof AnimatedEvent) {
|
||||
event.__removeListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
const event = function(argMapping: Array<?Mapping>, config?: EventConfig): any {
|
||||
const animatedEvent = new AnimatedEvent(argMapping, config);
|
||||
if (animatedEvent.__isNative) {
|
||||
return animatedEvent;
|
||||
} else {
|
||||
return animatedEvent.__getHandler();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The `Animated` library is designed to make animations fluid, powerful, and
|
||||
* easy to build and maintain. `Animated` focuses on declarative relationships
|
||||
* between inputs and outputs, with configurable transforms in between, and
|
||||
* simple `start`/`stop` methods to control time-based animation execution.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html
|
||||
*/
|
||||
module.exports = {
|
||||
/**
|
||||
* Standard value class for driving animations. Typically initialized with
|
||||
* `new Animated.Value(0);`
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#value
|
||||
*/
|
||||
Value: AnimatedValue,
|
||||
/**
|
||||
* 2D value class for driving 2D animations, such as pan gestures.
|
||||
*
|
||||
* See https://facebook.github.io/react-native/releases/next/docs/animatedvaluexy.html
|
||||
*/
|
||||
ValueXY: AnimatedValueXY,
|
||||
/**
|
||||
* Exported to use the Interpolation type in flow.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#interpolation
|
||||
*/
|
||||
Interpolation: AnimatedInterpolation,
|
||||
/**
|
||||
* Exported for ease of type checking. All animated values derive from this
|
||||
* class.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#node
|
||||
*/
|
||||
Node: AnimatedNode,
|
||||
|
||||
/**
|
||||
* Animates a value from an initial velocity to zero based on a decay
|
||||
* coefficient.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#decay
|
||||
*/
|
||||
decay,
|
||||
/**
|
||||
* Animates a value along a timed easing curve. The Easing module has tons of
|
||||
* predefined curves, or you can use your own function.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#timing
|
||||
*/
|
||||
timing,
|
||||
/**
|
||||
* Animates a value according to an analytical spring model based on
|
||||
* damped harmonic oscillation.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#spring
|
||||
*/
|
||||
spring,
|
||||
|
||||
/**
|
||||
* Creates a new Animated value composed from two Animated values added
|
||||
* together.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#add
|
||||
*/
|
||||
add,
|
||||
|
||||
/**
|
||||
* Creates a new Animated value composed by dividing the first Animated value
|
||||
* by the second Animated value.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#divide
|
||||
*/
|
||||
divide,
|
||||
|
||||
/**
|
||||
* Creates a new Animated value composed from two Animated values multiplied
|
||||
* together.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#multiply
|
||||
*/
|
||||
multiply,
|
||||
|
||||
/**
|
||||
* Creates a new Animated value that is the (non-negative) modulo of the
|
||||
* provided Animated value.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#modulo
|
||||
*/
|
||||
modulo,
|
||||
|
||||
/**
|
||||
* Create a new Animated value that is limited between 2 values. It uses the
|
||||
* difference between the last value so even if the value is far from the
|
||||
* bounds it will start changing when the value starts getting closer again.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#diffclamp
|
||||
*/
|
||||
diffClamp,
|
||||
|
||||
/**
|
||||
* Starts an animation after the given delay.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#delay
|
||||
*/
|
||||
delay,
|
||||
/**
|
||||
* Starts an array of animations in order, waiting for each to complete
|
||||
* before starting the next. If the current running animation is stopped, no
|
||||
* following animations will be started.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#sequence
|
||||
*/
|
||||
sequence,
|
||||
/**
|
||||
* Starts an array of animations all at the same time. By default, if one
|
||||
* of the animations is stopped, they will all be stopped. You can override
|
||||
* this with the `stopTogether` flag.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#parallel
|
||||
*/
|
||||
parallel,
|
||||
/**
|
||||
* Array of animations may run in parallel (overlap), but are started in
|
||||
* sequence with successive delays. Nice for doing trailing effects.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#stagger
|
||||
*/
|
||||
stagger,
|
||||
/**
|
||||
* Loops a given animation continuously, so that each time it reaches the
|
||||
* end, it resets and begins again from the start.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#loop
|
||||
*/
|
||||
loop,
|
||||
|
||||
/**
|
||||
* Takes an array of mappings and extracts values from each arg accordingly,
|
||||
* then calls `setValue` on the mapped outputs.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#event
|
||||
*/
|
||||
event,
|
||||
|
||||
/**
|
||||
* Make any React component Animatable. Used to create `Animated.View`, etc.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#createanimatedcomponent
|
||||
*/
|
||||
createAnimatedComponent,
|
||||
|
||||
/**
|
||||
* Imperative API to attach an animated value to an event on a view. Prefer
|
||||
* using `Animated.event` with `useNativeDrive: true` if possible.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#attachnativeevent
|
||||
*/
|
||||
attachNativeEvent,
|
||||
|
||||
/**
|
||||
* Advanced imperative API for snooping on animated events that are passed in
|
||||
* through props. Use values directly where possible.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#forkevent
|
||||
*/
|
||||
forkEvent,
|
||||
unforkEvent,
|
||||
|
||||
__PropsOnlyForTests: AnimatedProps,
|
||||
};
|
||||
303
src/vendor/Animated/Easing.js
vendored
Normal file
303
src/vendor/Animated/Easing.js
vendored
Normal file
@@ -0,0 +1,303 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule Easing
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
let ease;
|
||||
|
||||
/**
|
||||
* The `Easing` module implements common easing functions. This module is used
|
||||
* by [Animate.timing()](docs/animate.html#timing) to convey physically
|
||||
* believable motion in animations.
|
||||
*
|
||||
* You can find a visualization of some common easing functions at
|
||||
* http://easings.net/
|
||||
*
|
||||
* ### Predefined animations
|
||||
*
|
||||
* The `Easing` module provides several predefined animations through the
|
||||
* following methods:
|
||||
*
|
||||
* - [`back`](docs/easing.html#back) provides a simple animation where the
|
||||
* object goes slightly back before moving forward
|
||||
* - [`bounce`](docs/easing.html#bounce) provides a bouncing animation
|
||||
* - [`ease`](docs/easing.html#ease) provides a simple inertial animation
|
||||
* - [`elastic`](docs/easing.html#elastic) provides a simple spring interaction
|
||||
*
|
||||
* ### Standard functions
|
||||
*
|
||||
* Three standard easing functions are provided:
|
||||
*
|
||||
* - [`linear`](docs/easing.html#linear)
|
||||
* - [`quad`](docs/easing.html#quad)
|
||||
* - [`cubic`](docs/easing.html#cubic)
|
||||
*
|
||||
* The [`poly`](docs/easing.html#poly) function can be used to implement
|
||||
* quartic, quintic, and other higher power functions.
|
||||
*
|
||||
* ### Additional functions
|
||||
*
|
||||
* Additional mathematical functions are provided by the following methods:
|
||||
*
|
||||
* - [`bezier`](docs/easing.html#bezier) provides a cubic bezier curve
|
||||
* - [`circle`](docs/easing.html#circle) provides a circular function
|
||||
* - [`sin`](docs/easing.html#sin) provides a sinusoidal function
|
||||
* - [`exp`](docs/easing.html#exp) provides an exponential function
|
||||
*
|
||||
* The following helpers are used to modify other easing functions.
|
||||
*
|
||||
* - [`in`](docs/easing.html#in) runs an easing function forwards
|
||||
* - [`inOut`](docs/easing.html#inout) makes any easing function symmetrical
|
||||
* - [`out`](docs/easing.html#out) runs an easing function backwards
|
||||
*/
|
||||
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) {
|
||||
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) {
|
||||
return n >= 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* A linear function, `f(t) = t`. Position correlates to elapsed time one to
|
||||
* one.
|
||||
*
|
||||
* 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) {
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple inertial interaction, similar to an object slowly accelerating to
|
||||
* speed.
|
||||
*
|
||||
* http://cubic-bezier.com/#.42,0,1,1
|
||||
*/
|
||||
static ease(t: number): number {
|
||||
if (!ease) {
|
||||
ease = Easing.bezier(0.42, 0, 1, 1);
|
||||
}
|
||||
return ease(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* A quadratic function, `f(t) = t * t`. Position equals the square of elapsed
|
||||
* time.
|
||||
*
|
||||
* 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) {
|
||||
return t * t;
|
||||
}
|
||||
|
||||
/**
|
||||
* A cubic function, `f(t) = t * t * t`. Position equals the cube of elapsed
|
||||
* time.
|
||||
*
|
||||
* 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) {
|
||||
return t * t * t;
|
||||
}
|
||||
|
||||
/**
|
||||
* A power function. Position is equal to the Nth power of elapsed time.
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sinusoidal function.
|
||||
*
|
||||
* 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) {
|
||||
return 1 - Math.cos(t * Math.PI / 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* A circular function.
|
||||
*
|
||||
* 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) {
|
||||
return 1 - Math.sqrt(1 - t * t);
|
||||
}
|
||||
|
||||
/**
|
||||
* An exponential function.
|
||||
*
|
||||
* 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) {
|
||||
return Math.pow(2, 10 * (t - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple elastic interaction, similar to a spring oscillating back and
|
||||
* forth.
|
||||
*
|
||||
* Default bounciness is 1, which overshoots a little bit once. 0 bounciness
|
||||
* doesn't overshoot at all, and bounciness of N > 1 will overshoot about N
|
||||
* times.
|
||||
*
|
||||
* http://easings.net/#easeInElastic
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use with `Animated.parallel()` to create a simple effect where the object
|
||||
* animates back slightly as the animation starts.
|
||||
*
|
||||
* Wolfram Plot:
|
||||
*
|
||||
* - http://tiny.cc/back_default (s = 1.70158, default)
|
||||
*/
|
||||
static back(s: number): (t: number) => number {
|
||||
if (s === undefined) {
|
||||
s = 1.70158;
|
||||
}
|
||||
return (t) => t * t * ((s + 1) * t - s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a simple bouncing effect.
|
||||
*
|
||||
* http://easings.net/#easeInBounce
|
||||
*/
|
||||
static bounce(t: number): number {
|
||||
if (t < 1 / 2.75) {
|
||||
return 7.5625 * t * t;
|
||||
}
|
||||
|
||||
if (t < 2 / 2.75) {
|
||||
t -= 1.5 / 2.75;
|
||||
return 7.5625 * t * t + 0.75;
|
||||
}
|
||||
|
||||
if (t < 2.5 / 2.75) {
|
||||
t -= 2.25 / 2.75;
|
||||
return 7.5625 * t * t + 0.9375;
|
||||
}
|
||||
|
||||
t -= 2.625 / 2.75;
|
||||
return 7.5625 * t * t + 0.984375;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a cubic bezier curve, equivalent to CSS Transitions'
|
||||
* `transition-timing-function`.
|
||||
*
|
||||
* 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 {
|
||||
const _bezier = require('./bezier');
|
||||
return _bezier(x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs an easing function forwards.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes any easing function symmetrical. The easing function will run
|
||||
* 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) => {
|
||||
if (t < 0.5) {
|
||||
return easing(t * 2) / 2;
|
||||
}
|
||||
return 1 - easing((1 - t) * 2) / 2;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Easing;
|
||||
259
src/vendor/Animated/NativeAnimatedHelper.js
vendored
Normal file
259
src/vendor/Animated/NativeAnimatedHelper.js
vendored
Normal file
@@ -0,0 +1,259 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule NativeAnimatedHelper
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const invariant = require('fbjs/lib/invariant');
|
||||
const NativeModules = require('../../modules/NativeModules');
|
||||
const NativeEventEmitter = require('../../modules/NativeEventEmitter');
|
||||
|
||||
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 EndCallback = (result: EndResult) => void;
|
||||
type EventMapping = {
|
||||
nativeEventPath: Array<string>,
|
||||
animatedValueTag: ?number,
|
||||
};
|
||||
|
||||
let nativeEventEmitter;
|
||||
|
||||
/**
|
||||
* Simple wrappers around NativeAnimatedModule to provide flow and autocmplete support for
|
||||
* the native module methods
|
||||
*/
|
||||
const API = {
|
||||
createAnimatedNode: function(tag: ?number, config: Object): void {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.createAnimatedNode(tag, config);
|
||||
},
|
||||
startListeningToAnimatedNodeValue: function(tag: ?number) {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.startListeningToAnimatedNodeValue(tag);
|
||||
},
|
||||
stopListeningToAnimatedNodeValue: function(tag: ?number) {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.stopListeningToAnimatedNodeValue(tag);
|
||||
},
|
||||
connectAnimatedNodes: function(parentTag: ?number, childTag: ?number): void {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.connectAnimatedNodes(parentTag, childTag);
|
||||
},
|
||||
disconnectAnimatedNodes: function(
|
||||
parentTag: ?number,
|
||||
childTag: ?number,
|
||||
): void {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.disconnectAnimatedNodes(parentTag, childTag);
|
||||
},
|
||||
startAnimatingNode: function(
|
||||
animationId: ?number,
|
||||
nodeTag: ?number,
|
||||
config: Object,
|
||||
endCallback: EndCallback,
|
||||
): void {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.startAnimatingNode(
|
||||
animationId,
|
||||
nodeTag,
|
||||
config,
|
||||
endCallback,
|
||||
);
|
||||
},
|
||||
stopAnimation: function(animationId: ?number) {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.stopAnimation(animationId);
|
||||
},
|
||||
setAnimatedNodeValue: function(nodeTag: ?number, value: ?number): void {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.setAnimatedNodeValue(nodeTag, value);
|
||||
},
|
||||
setAnimatedNodeOffset: function(nodeTag: ?number, offset: ?number): void {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.setAnimatedNodeOffset(nodeTag, offset);
|
||||
},
|
||||
flattenAnimatedNodeOffset: function(nodeTag: ?number): void {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.flattenAnimatedNodeOffset(nodeTag);
|
||||
},
|
||||
extractAnimatedNodeOffset: function(nodeTag: ?number): void {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.extractAnimatedNodeOffset(nodeTag);
|
||||
},
|
||||
connectAnimatedNodeToView: function(
|
||||
nodeTag: ?number,
|
||||
viewTag: ?number,
|
||||
): void {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.connectAnimatedNodeToView(nodeTag, viewTag);
|
||||
},
|
||||
disconnectAnimatedNodeFromView: function(
|
||||
nodeTag: ?number,
|
||||
viewTag: ?number,
|
||||
): void {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.disconnectAnimatedNodeFromView(nodeTag, viewTag);
|
||||
},
|
||||
dropAnimatedNode: function(tag: ?number): void {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.dropAnimatedNode(tag);
|
||||
},
|
||||
addAnimatedEventToView: function(
|
||||
viewTag: ?number,
|
||||
eventName: string,
|
||||
eventMapping: EventMapping,
|
||||
) {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.addAnimatedEventToView(
|
||||
viewTag,
|
||||
eventName,
|
||||
eventMapping,
|
||||
);
|
||||
},
|
||||
removeAnimatedEventFromView(
|
||||
viewTag: ?number,
|
||||
eventName: string,
|
||||
animatedNodeTag: ?number,
|
||||
) {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.removeAnimatedEventFromView(
|
||||
viewTag,
|
||||
eventName,
|
||||
animatedNodeTag,
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Styles allowed by the native animated implementation.
|
||||
*
|
||||
* In general native animated implementation should support any numeric property that doesn't need
|
||||
* to be updated through the shadow view hierarchy (all non-layout properties).
|
||||
*/
|
||||
const STYLES_WHITELIST = {
|
||||
opacity: true,
|
||||
transform: true,
|
||||
/* ios styles */
|
||||
shadowOpacity: true,
|
||||
shadowRadius: true,
|
||||
/* legacy android transform properties */
|
||||
scaleX: true,
|
||||
scaleY: true,
|
||||
translateX: true,
|
||||
translateY: true,
|
||||
};
|
||||
|
||||
const TRANSFORM_WHITELIST = {
|
||||
translateX: true,
|
||||
translateY: true,
|
||||
scale: true,
|
||||
scaleX: true,
|
||||
scaleY: true,
|
||||
rotate: true,
|
||||
rotateX: true,
|
||||
rotateY: true,
|
||||
perspective: 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`,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function generateNewNodeTag(): number {
|
||||
return __nativeAnimatedNodeTagCount++;
|
||||
}
|
||||
|
||||
function generateNewAnimationId(): number {
|
||||
return __nativeAnimationIdCount++;
|
||||
}
|
||||
|
||||
function assertNativeAnimatedModule(): void {
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
}
|
||||
|
||||
let _warnedMissingNativeAnimated = false;
|
||||
|
||||
function shouldUseNativeDriver(config: AnimationConfig | EventConfig): boolean {
|
||||
if (config.useNativeDriver && !NativeAnimatedModule) {
|
||||
if (!_warnedMissingNativeAnimated) {
|
||||
console.warn(
|
||||
'Animated: `useNativeDriver` is not supported because the native ' +
|
||||
'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',
|
||||
);
|
||||
_warnedMissingNativeAnimated = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return config.useNativeDriver || false;
|
||||
}
|
||||
|
||||
const NativeAnimatedHelper = {
|
||||
API,
|
||||
validateStyles,
|
||||
validateTransform,
|
||||
validateInterpolation,
|
||||
generateNewNodeTag,
|
||||
generateNewAnimationId,
|
||||
assertNativeAnimatedModule,
|
||||
shouldUseNativeDriver,
|
||||
get nativeEventEmitter() {
|
||||
if (!nativeEventEmitter) {
|
||||
nativeEventEmitter = new NativeEventEmitter(NativeAnimatedModule);
|
||||
}
|
||||
return nativeEventEmitter;
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = NativeAnimatedHelper;
|
||||
1
src/vendor/Animated/SHA
vendored
Normal file
1
src/vendor/Animated/SHA
vendored
Normal file
@@ -0,0 +1 @@
|
||||
facebook/react-native@71006f74cdafdae7212c8a10603fb972c6ee338c
|
||||
102
src/vendor/Animated/SpringConfig.js
vendored
Normal file
102
src/vendor/Animated/SpringConfig.js
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule SpringConfig
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
type SpringConfigType = {
|
||||
stiffness: number,
|
||||
damping: number,
|
||||
};
|
||||
|
||||
function stiffnessFromOrigamiValue(oValue) {
|
||||
return (oValue - 30) * 3.62 + 194;
|
||||
}
|
||||
|
||||
function dampingFromOrigamiValue(oValue) {
|
||||
return (oValue - 8) * 3 + 25;
|
||||
}
|
||||
|
||||
function fromOrigamiTensionAndFriction(
|
||||
tension: number,
|
||||
friction: number,
|
||||
): SpringConfigType {
|
||||
return {
|
||||
stiffness: stiffnessFromOrigamiValue(tension),
|
||||
damping: dampingFromOrigamiValue(friction),
|
||||
};
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
function linearInterpolation(t, start, end) {
|
||||
return t * end + (1 - t) * start;
|
||||
}
|
||||
|
||||
function quadraticOutInterpolation(t, start, end) {
|
||||
return linearInterpolation(2 * t - t * t, start, end);
|
||||
}
|
||||
|
||||
function b3Friction1(x) {
|
||||
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;
|
||||
}
|
||||
|
||||
function b3Friction3(x) {
|
||||
return (0.00000045 * Math.pow(x, 3)) -
|
||||
(0.000332 * Math.pow(x, 2)) + 0.1078 * x + 5.84;
|
||||
}
|
||||
|
||||
function b3Nobounce(tension) {
|
||||
if (tension <= 18) {
|
||||
return b3Friction1(tension);
|
||||
} else if (tension > 18 && tension <= 44) {
|
||||
return b3Friction2(tension);
|
||||
} else {
|
||||
return b3Friction3(tension);
|
||||
}
|
||||
}
|
||||
|
||||
var b = normalize(bounciness / 1.7, 0, 20);
|
||||
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
|
||||
);
|
||||
|
||||
return {
|
||||
stiffness: stiffnessFromOrigamiValue(bouncyTension),
|
||||
damping: dampingFromOrigamiValue(bouncyFriction),
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
fromOrigamiTensionAndFriction,
|
||||
fromBouncinessAndSpeed,
|
||||
};
|
||||
73
src/vendor/Animated/animations/Animation.js
vendored
Normal file
73
src/vendor/Animated/animations/Animation.js
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule Animation
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const NativeAnimatedHelper = require('../NativeAnimatedHelper');
|
||||
|
||||
import type AnimatedValue from '../nodes/AnimatedValue';
|
||||
|
||||
export type EndResult = {finished: boolean};
|
||||
export type EndCallback = (result: EndResult) => void;
|
||||
|
||||
export type AnimationConfig = {
|
||||
isInteraction?: boolean,
|
||||
useNativeDriver?: boolean,
|
||||
onComplete?: ?EndCallback,
|
||||
iterations?: number,
|
||||
};
|
||||
|
||||
// Important note: start() and stop() will only be called at most once.
|
||||
// Once an animation has been stopped or finished its course, it will
|
||||
// not be reused.
|
||||
class Animation {
|
||||
__active: boolean;
|
||||
__isInteraction: boolean;
|
||||
__nativeId: number;
|
||||
__onEnd: ?EndCallback;
|
||||
__iterations: number;
|
||||
start(
|
||||
fromValue: number,
|
||||
onUpdate: (value: number) => void,
|
||||
onEnd: ?EndCallback,
|
||||
previousAnimation: ?Animation,
|
||||
animatedValue: AnimatedValue,
|
||||
): void {}
|
||||
stop(): void {
|
||||
if (this.__nativeId) {
|
||||
NativeAnimatedHelper.API.stopAnimation(this.__nativeId);
|
||||
}
|
||||
}
|
||||
__getNativeAnimationConfig(): any {
|
||||
// Subclasses that have corresponding animation implementation done in native
|
||||
// should override this method
|
||||
throw new Error('This animation type cannot be offloaded to native');
|
||||
}
|
||||
// Helper function for subclasses to make sure onEnd is only called once.
|
||||
__debouncedOnEnd(result: EndResult): void {
|
||||
const onEnd = this.__onEnd;
|
||||
this.__onEnd = null;
|
||||
onEnd && onEnd(result);
|
||||
}
|
||||
__startNativeAnimation(animatedValue: AnimatedValue): void {
|
||||
animatedValue.__makeNative();
|
||||
this.__nativeId = NativeAnimatedHelper.generateNewAnimationId();
|
||||
NativeAnimatedHelper.API.startAnimatingNode(
|
||||
this.__nativeId,
|
||||
animatedValue.__getNativeTag(),
|
||||
this.__getNativeAnimationConfig(),
|
||||
this.__debouncedOnEnd.bind(this),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Animation;
|
||||
112
src/vendor/Animated/animations/DecayAnimation.js
vendored
Normal file
112
src/vendor/Animated/animations/DecayAnimation.js
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule DecayAnimation
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const Animation = require('./Animation');
|
||||
|
||||
const {shouldUseNativeDriver} = require('../NativeAnimatedHelper');
|
||||
|
||||
import type {AnimationConfig, EndCallback} from './Animation';
|
||||
import type AnimatedValue from '../nodes/AnimatedValue';
|
||||
|
||||
export type DecayAnimationConfig = AnimationConfig & {
|
||||
velocity: number | {x: number, y: number},
|
||||
deceleration?: number,
|
||||
};
|
||||
|
||||
export type DecayAnimationConfigSingle = AnimationConfig & {
|
||||
velocity: number,
|
||||
deceleration?: number,
|
||||
};
|
||||
|
||||
class DecayAnimation extends Animation {
|
||||
_startTime: number;
|
||||
_lastValue: number;
|
||||
_fromValue: number;
|
||||
_deceleration: number;
|
||||
_velocity: number;
|
||||
_onUpdate: (value: number) => void;
|
||||
_animationFrame: any;
|
||||
_useNativeDriver: boolean;
|
||||
|
||||
constructor(config: DecayAnimationConfigSingle) {
|
||||
super();
|
||||
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.__iterations = config.iterations !== undefined ? config.iterations : 1;
|
||||
}
|
||||
|
||||
__getNativeAnimationConfig() {
|
||||
return {
|
||||
type: 'decay',
|
||||
deceleration: this._deceleration,
|
||||
velocity: this._velocity,
|
||||
iterations: this.__iterations,
|
||||
};
|
||||
}
|
||||
|
||||
start(
|
||||
fromValue: number,
|
||||
onUpdate: (value: number) => void,
|
||||
onEnd: ?EndCallback,
|
||||
previousAnimation: ?Animation,
|
||||
animatedValue: AnimatedValue,
|
||||
): void {
|
||||
this.__active = true;
|
||||
this._lastValue = fromValue;
|
||||
this._fromValue = fromValue;
|
||||
this._onUpdate = onUpdate;
|
||||
this.__onEnd = onEnd;
|
||||
this._startTime = Date.now();
|
||||
if (this._useNativeDriver) {
|
||||
this.__startNativeAnimation(animatedValue);
|
||||
} else {
|
||||
this._animationFrame = requestAnimationFrame(this.onUpdate.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
onUpdate(): void {
|
||||
const now = Date.now();
|
||||
|
||||
const value =
|
||||
this._fromValue +
|
||||
this._velocity /
|
||||
(1 - this._deceleration) *
|
||||
(1 - Math.exp(-(1 - this._deceleration) * (now - this._startTime)));
|
||||
|
||||
this._onUpdate(value);
|
||||
|
||||
if (Math.abs(this._lastValue - value) < 0.1) {
|
||||
this.__debouncedOnEnd({finished: true});
|
||||
return;
|
||||
}
|
||||
|
||||
this._lastValue = value;
|
||||
if (this.__active) {
|
||||
this._animationFrame = requestAnimationFrame(this.onUpdate.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
super.stop();
|
||||
this.__active = false;
|
||||
global.cancelAnimationFrame(this._animationFrame);
|
||||
this.__debouncedOnEnd({finished: false});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DecayAnimation;
|
||||
342
src/vendor/Animated/animations/SpringAnimation.js
vendored
Normal file
342
src/vendor/Animated/animations/SpringAnimation.js
vendored
Normal file
@@ -0,0 +1,342 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule SpringAnimation
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const AnimatedValue = require('../nodes/AnimatedValue');
|
||||
const AnimatedValueXY = require('../nodes/AnimatedValueXY');
|
||||
const Animation = require('./Animation');
|
||||
const SpringConfig = require('../SpringConfig');
|
||||
|
||||
const invariant = require('fbjs/lib/invariant');
|
||||
const {shouldUseNativeDriver} = require('../NativeAnimatedHelper');
|
||||
|
||||
import type {AnimationConfig, EndCallback} from './Animation';
|
||||
|
||||
export type SpringAnimationConfig = AnimationConfig & {
|
||||
toValue: number | AnimatedValue | {x: number, y: number} | AnimatedValueXY,
|
||||
overshootClamping?: boolean,
|
||||
restDisplacementThreshold?: number,
|
||||
restSpeedThreshold?: number,
|
||||
velocity?: number | {x: number, y: number},
|
||||
bounciness?: number,
|
||||
speed?: number,
|
||||
tension?: number,
|
||||
friction?: number,
|
||||
stiffness?: number,
|
||||
damping?: number,
|
||||
mass?: number,
|
||||
delay?: number,
|
||||
};
|
||||
|
||||
export type SpringAnimationConfigSingle = AnimationConfig & {
|
||||
toValue: number | AnimatedValue,
|
||||
overshootClamping?: boolean,
|
||||
restDisplacementThreshold?: number,
|
||||
restSpeedThreshold?: number,
|
||||
velocity?: number,
|
||||
bounciness?: number,
|
||||
speed?: number,
|
||||
tension?: number,
|
||||
friction?: number,
|
||||
stiffness?: number,
|
||||
damping?: number,
|
||||
mass?: number,
|
||||
delay?: number,
|
||||
};
|
||||
|
||||
function withDefault<T>(value: ?T, defaultValue: T): T {
|
||||
if (value === undefined || value === null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
class SpringAnimation extends Animation {
|
||||
_overshootClamping: boolean;
|
||||
_restDisplacementThreshold: number;
|
||||
_restSpeedThreshold: number;
|
||||
_lastVelocity: number;
|
||||
_startPosition: number;
|
||||
_lastPosition: number;
|
||||
_fromValue: number;
|
||||
_toValue: any;
|
||||
_stiffness: number;
|
||||
_damping: number;
|
||||
_mass: number;
|
||||
_initialVelocity: number;
|
||||
_delay: number;
|
||||
_timeout: any;
|
||||
_startTime: number;
|
||||
_lastTime: number;
|
||||
_frameTime: number;
|
||||
_onUpdate: (value: number) => void;
|
||||
_animationFrame: any;
|
||||
_useNativeDriver: boolean;
|
||||
|
||||
constructor(config: SpringAnimationConfigSingle) {
|
||||
super();
|
||||
|
||||
this._overshootClamping = withDefault(config.overshootClamping, false);
|
||||
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.__iterations = config.iterations !== undefined ? config.iterations : 1;
|
||||
|
||||
if (
|
||||
config.stiffness !== undefined ||
|
||||
config.damping !== undefined ||
|
||||
config.mass !== undefined
|
||||
) {
|
||||
invariant(
|
||||
config.bounciness === undefined &&
|
||||
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',
|
||||
);
|
||||
this._stiffness = withDefault(config.stiffness, 100);
|
||||
this._damping = withDefault(config.damping, 10);
|
||||
this._mass = withDefault(config.mass, 1);
|
||||
} else if (config.bounciness !== undefined || config.speed !== undefined) {
|
||||
// Convert the origami bounciness/speed values to stiffness/damping
|
||||
// We assume mass is 1.
|
||||
invariant(
|
||||
config.tension === undefined &&
|
||||
config.friction === undefined &&
|
||||
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',
|
||||
);
|
||||
const springConfig = SpringConfig.fromBouncinessAndSpeed(
|
||||
withDefault(config.bounciness, 8),
|
||||
withDefault(config.speed, 12),
|
||||
);
|
||||
this._stiffness = springConfig.stiffness;
|
||||
this._damping = springConfig.damping;
|
||||
this._mass = 1;
|
||||
} else {
|
||||
// Convert the origami tension/friction values to stiffness/damping
|
||||
// We assume mass is 1.
|
||||
const springConfig = SpringConfig.fromOrigamiTensionAndFriction(
|
||||
withDefault(config.tension, 40),
|
||||
withDefault(config.friction, 7),
|
||||
);
|
||||
this._stiffness = springConfig.stiffness;
|
||||
this._damping = springConfig.damping;
|
||||
this._mass = 1;
|
||||
}
|
||||
|
||||
invariant(this._stiffness > 0, 'Stiffness value must be greater than 0');
|
||||
invariant(this._damping > 0, 'Damping value must be greater than 0');
|
||||
invariant(this._mass > 0, 'Mass value must be greater than 0');
|
||||
}
|
||||
|
||||
__getNativeAnimationConfig() {
|
||||
return {
|
||||
type: 'spring',
|
||||
overshootClamping: this._overshootClamping,
|
||||
restDisplacementThreshold: this._restDisplacementThreshold,
|
||||
restSpeedThreshold: this._restSpeedThreshold,
|
||||
stiffness: this._stiffness,
|
||||
damping: this._damping,
|
||||
mass: this._mass,
|
||||
initialVelocity: withDefault(this._initialVelocity, this._lastVelocity),
|
||||
toValue: this._toValue,
|
||||
iterations: this.__iterations,
|
||||
};
|
||||
}
|
||||
|
||||
start(
|
||||
fromValue: number,
|
||||
onUpdate: (value: number) => void,
|
||||
onEnd: ?EndCallback,
|
||||
previousAnimation: ?Animation,
|
||||
animatedValue: AnimatedValue,
|
||||
): void {
|
||||
this.__active = true;
|
||||
this._startPosition = fromValue;
|
||||
this._lastPosition = this._startPosition;
|
||||
|
||||
this._onUpdate = onUpdate;
|
||||
this.__onEnd = onEnd;
|
||||
this._lastTime = Date.now();
|
||||
this._frameTime = 0.0;
|
||||
|
||||
if (previousAnimation instanceof SpringAnimation) {
|
||||
const internalState = previousAnimation.getInternalState();
|
||||
this._lastPosition = internalState.lastPosition;
|
||||
this._lastVelocity = internalState.lastVelocity;
|
||||
// Set the initial velocity to the last velocity
|
||||
this._initialVelocity = this._lastVelocity;
|
||||
this._lastTime = internalState.lastTime;
|
||||
}
|
||||
|
||||
const start = () => {
|
||||
if (this._useNativeDriver) {
|
||||
this.__startNativeAnimation(animatedValue);
|
||||
} else {
|
||||
this.onUpdate();
|
||||
}
|
||||
};
|
||||
|
||||
// If this._delay is more than 0, we start after the timeout.
|
||||
if (this._delay) {
|
||||
this._timeout = setTimeout(start, this._delay);
|
||||
} else {
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
getInternalState(): Object {
|
||||
return {
|
||||
lastPosition: this._lastPosition,
|
||||
lastVelocity: this._lastVelocity,
|
||||
lastTime: this._lastTime,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* This spring model is based off of a damped harmonic oscillator
|
||||
* (https://en.wikipedia.org/wiki/Harmonic_oscillator#Damped_harmonic_oscillator).
|
||||
*
|
||||
* We use the closed form of the second order differential equation:
|
||||
*
|
||||
* x'' + (2ζ⍵_0)x' + ⍵^2x = 0
|
||||
*
|
||||
* where
|
||||
* ⍵_0 = √(k / m) (undamped angular frequency of the oscillator),
|
||||
* ζ = c / 2√mk (damping ratio),
|
||||
* c = damping constant
|
||||
* k = stiffness
|
||||
* m = mass
|
||||
*
|
||||
* The derivation of the closed form is described in detail here:
|
||||
* http://planetmath.org/sites/default/files/texpdf/39745.pdf
|
||||
*
|
||||
* This algorithm happens to match the algorithm used by CASpringAnimation,
|
||||
* a QuartzCore (iOS) API that creates spring animations.
|
||||
*/
|
||||
onUpdate(): void {
|
||||
// If for some reason we lost a lot of frames (e.g. process large payload or
|
||||
// stopped in the debugger), we only advance by 4 frames worth of
|
||||
// computation and will continue on the next frame. It's better to have it
|
||||
// running at faster speed than jumping to the end.
|
||||
const MAX_STEPS = 64;
|
||||
let now = Date.now();
|
||||
if (now > this._lastTime + MAX_STEPS) {
|
||||
now = this._lastTime + MAX_STEPS;
|
||||
}
|
||||
|
||||
const deltaTime = (now - this._lastTime) / 1000;
|
||||
this._frameTime += deltaTime;
|
||||
|
||||
const c: number = this._damping;
|
||||
const m: number = this._mass;
|
||||
const k: number = this._stiffness;
|
||||
const v0: number = -this._initialVelocity;
|
||||
|
||||
const zeta = c / (2 * Math.sqrt(k * m)); // damping ratio
|
||||
const omega0 = Math.sqrt(k / m); // undamped angular frequency of the oscillator (rad/ms)
|
||||
const omega1 = omega0 * Math.sqrt(1.0 - zeta * zeta); // exponential decay
|
||||
const x0 = this._toValue - this._startPosition; // calculate the oscillation from x0 = 1 to x = 0
|
||||
|
||||
let position = 0.0;
|
||||
let velocity = 0.0;
|
||||
const t = this._frameTime;
|
||||
if (zeta < 1) {
|
||||
// Under damped
|
||||
const envelope = Math.exp(-zeta * omega0 * t);
|
||||
position =
|
||||
this._toValue -
|
||||
envelope *
|
||||
((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)) -
|
||||
envelope *
|
||||
(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));
|
||||
}
|
||||
|
||||
this._lastTime = now;
|
||||
this._lastPosition = position;
|
||||
this._lastVelocity = velocity;
|
||||
|
||||
this._onUpdate(position);
|
||||
if (!this.__active) {
|
||||
// a listener might have stopped us in _onUpdate
|
||||
return;
|
||||
}
|
||||
|
||||
// Conditions for stopping the spring animation
|
||||
let isOvershooting = false;
|
||||
if (this._overshootClamping && this._stiffness !== 0) {
|
||||
if (this._startPosition < this._toValue) {
|
||||
isOvershooting = position > this._toValue;
|
||||
} else {
|
||||
isOvershooting = position < this._toValue;
|
||||
}
|
||||
}
|
||||
const isVelocity = Math.abs(velocity) <= this._restSpeedThreshold;
|
||||
let isDisplacement = true;
|
||||
if (this._stiffness !== 0) {
|
||||
isDisplacement =
|
||||
Math.abs(this._toValue - position) <= this._restDisplacementThreshold;
|
||||
}
|
||||
|
||||
if (isOvershooting || (isVelocity && isDisplacement)) {
|
||||
if (this._stiffness !== 0) {
|
||||
// Ensure that we end up with a round value
|
||||
this._lastPosition = this._toValue;
|
||||
this._lastVelocity = 0;
|
||||
this._onUpdate(this._toValue);
|
||||
}
|
||||
|
||||
this.__debouncedOnEnd({finished: true});
|
||||
return;
|
||||
}
|
||||
this._animationFrame = requestAnimationFrame(this.onUpdate.bind(this));
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
super.stop();
|
||||
this.__active = false;
|
||||
clearTimeout(this._timeout);
|
||||
global.cancelAnimationFrame(this._animationFrame);
|
||||
this.__debouncedOnEnd({finished: false});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SpringAnimation;
|
||||
155
src/vendor/Animated/animations/TimingAnimation.js
vendored
Normal file
155
src/vendor/Animated/animations/TimingAnimation.js
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule TimingAnimation
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const AnimatedValue = require('../nodes/AnimatedValue');
|
||||
const AnimatedValueXY = require('../nodes/AnimatedValueXY');
|
||||
const Animation = require('./Animation');
|
||||
|
||||
const {shouldUseNativeDriver} = require('../NativeAnimatedHelper');
|
||||
|
||||
import type {AnimationConfig, EndCallback} from './Animation';
|
||||
|
||||
export type TimingAnimationConfig = AnimationConfig & {
|
||||
toValue: number | AnimatedValue | {x: number, y: number} | AnimatedValueXY,
|
||||
easing?: (value: number) => number,
|
||||
duration?: number,
|
||||
delay?: number,
|
||||
};
|
||||
|
||||
export type TimingAnimationConfigSingle = AnimationConfig & {
|
||||
toValue: number | AnimatedValue,
|
||||
easing?: (value: number) => number,
|
||||
duration?: number,
|
||||
delay?: number,
|
||||
};
|
||||
|
||||
let _easeInOut;
|
||||
function easeInOut() {
|
||||
if (!_easeInOut) {
|
||||
const Easing = require('../Easing');
|
||||
_easeInOut = Easing.inOut(Easing.ease);
|
||||
}
|
||||
return _easeInOut;
|
||||
}
|
||||
|
||||
class TimingAnimation extends Animation {
|
||||
_startTime: number;
|
||||
_fromValue: number;
|
||||
_toValue: any;
|
||||
_duration: number;
|
||||
_delay: number;
|
||||
_easing: (value: number) => number;
|
||||
_onUpdate: (value: number) => void;
|
||||
_animationFrame: any;
|
||||
_timeout: any;
|
||||
_useNativeDriver: boolean;
|
||||
|
||||
constructor(config: TimingAnimationConfigSingle) {
|
||||
super();
|
||||
this._toValue = config.toValue;
|
||||
this._easing = config.easing !== undefined ? config.easing : easeInOut();
|
||||
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._useNativeDriver = shouldUseNativeDriver(config);
|
||||
}
|
||||
|
||||
__getNativeAnimationConfig(): any {
|
||||
const frameDuration = 1000.0 / 60.0;
|
||||
const frames = [];
|
||||
for (let dt = 0.0; dt < this._duration; dt += frameDuration) {
|
||||
frames.push(this._easing(dt / this._duration));
|
||||
}
|
||||
frames.push(this._easing(1));
|
||||
return {
|
||||
type: 'frames',
|
||||
frames,
|
||||
toValue: this._toValue,
|
||||
iterations: this.__iterations,
|
||||
};
|
||||
}
|
||||
|
||||
start(
|
||||
fromValue: number,
|
||||
onUpdate: (value: number) => void,
|
||||
onEnd: ?EndCallback,
|
||||
previousAnimation: ?Animation,
|
||||
animatedValue: AnimatedValue,
|
||||
): void {
|
||||
this.__active = true;
|
||||
this._fromValue = fromValue;
|
||||
this._onUpdate = onUpdate;
|
||||
this.__onEnd = onEnd;
|
||||
|
||||
const start = () => {
|
||||
// Animations that sometimes have 0 duration and sometimes do not
|
||||
// still need to use the native driver when duration is 0 so as to
|
||||
// not cause intermixed JS and native animations.
|
||||
if (this._duration === 0 && !this._useNativeDriver) {
|
||||
this._onUpdate(this._toValue);
|
||||
this.__debouncedOnEnd({finished: true});
|
||||
} else {
|
||||
this._startTime = Date.now();
|
||||
if (this._useNativeDriver) {
|
||||
this.__startNativeAnimation(animatedValue);
|
||||
} else {
|
||||
this._animationFrame = requestAnimationFrame(
|
||||
this.onUpdate.bind(this),
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (this._delay) {
|
||||
this._timeout = setTimeout(start, this._delay);
|
||||
} else {
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
onUpdate(): void {
|
||||
const now = Date.now();
|
||||
if (now >= this._startTime + this._duration) {
|
||||
if (this._duration === 0) {
|
||||
this._onUpdate(this._toValue);
|
||||
} else {
|
||||
this._onUpdate(
|
||||
this._fromValue + this._easing(1) * (this._toValue - this._fromValue),
|
||||
);
|
||||
}
|
||||
this.__debouncedOnEnd({finished: true});
|
||||
return;
|
||||
}
|
||||
|
||||
this._onUpdate(
|
||||
this._fromValue +
|
||||
this._easing((now - this._startTime) / this._duration) *
|
||||
(this._toValue - this._fromValue),
|
||||
);
|
||||
if (this.__active) {
|
||||
this._animationFrame = requestAnimationFrame(this.onUpdate.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
super.stop();
|
||||
this.__active = false;
|
||||
clearTimeout(this._timeout);
|
||||
global.cancelAnimationFrame(this._animationFrame);
|
||||
this.__debouncedOnEnd({finished: false});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TimingAnimation;
|
||||
108
src/vendor/Animated/bezier.js
vendored
Normal file
108
src/vendor/Animated/bezier.js
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* BezierEasing - use bezier curve for transition easing function
|
||||
* https://github.com/gre/bezier-easing
|
||||
*
|
||||
* @copyright 2014-2015 Gaëtan Renaudeau. MIT License.
|
||||
* @providesModule bezier
|
||||
* @noflow
|
||||
*/
|
||||
'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;
|
||||
|
||||
var kSplineTableSize = 11;
|
||||
var kSampleStepSize = 1.0 / (kSplineTableSize - 1.0);
|
||||
|
||||
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; }
|
||||
|
||||
// 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); }
|
||||
|
||||
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) {
|
||||
for (var i = 0; i < NEWTON_ITERATIONS; ++i) {
|
||||
var currentSlope = getSlope(aGuessT, mX1, mX2);
|
||||
if (currentSlope === 0.0) {
|
||||
return aGuessT;
|
||||
}
|
||||
var currentX = calcBezier(aGuessT, mX1, mX2) - aX;
|
||||
aGuessT -= currentX / currentSlope;
|
||||
}
|
||||
return aGuessT;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
function getTForX (aX) {
|
||||
var intervalStart = 0.0;
|
||||
var currentSample = 1;
|
||||
var lastSample = kSplineTableSize - 1;
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
};
|
||||
};
|
||||
200
src/vendor/Animated/createAnimatedComponent.js
vendored
Normal file
200
src/vendor/Animated/createAnimatedComponent.js
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule createAnimatedComponent
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const {AnimatedEvent} = require('./AnimatedEvent');
|
||||
const AnimatedProps = require('./nodes/AnimatedProps');
|
||||
const React = require('react');
|
||||
const ViewStylePropTypes = require('../../components/View/ViewStylePropTypes').default;
|
||||
|
||||
function createAnimatedComponent(Component: any): any {
|
||||
class AnimatedComponent extends React.Component<Object> {
|
||||
_component: any;
|
||||
_invokeAnimatedPropsCallbackOnMount: boolean = false;
|
||||
_prevComponent: any;
|
||||
_propsAnimated: AnimatedProps;
|
||||
_eventDetachers: Array<Function> = [];
|
||||
_setComponentRef: Function;
|
||||
|
||||
static __skipSetNativeProps_FOR_TESTS_ONLY = false;
|
||||
|
||||
constructor(props: Object) {
|
||||
super(props);
|
||||
this._setComponentRef = this._setComponentRef.bind(this);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this._propsAnimated && this._propsAnimated.__detach();
|
||||
this._detachNativeEvents();
|
||||
}
|
||||
|
||||
setNativeProps(props) {
|
||||
this._component.setNativeProps(props);
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this._attachProps(this.props);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this._invokeAnimatedPropsCallbackOnMount) {
|
||||
this._invokeAnimatedPropsCallbackOnMount = false;
|
||||
this._animatedPropsCallback();
|
||||
}
|
||||
|
||||
this._propsAnimated.setNativeView(this._component);
|
||||
this._attachNativeEvents();
|
||||
}
|
||||
|
||||
_attachNativeEvents() {
|
||||
// Make sure to get the scrollable node for components that implement
|
||||
// `ScrollResponder.Mixin`.
|
||||
const scrollableNode = this._component.getScrollableNode
|
||||
? this._component.getScrollableNode()
|
||||
: this._component;
|
||||
|
||||
for (const key in this.props) {
|
||||
const prop = this.props[key];
|
||||
if (prop instanceof AnimatedEvent && prop.__isNative) {
|
||||
prop.__attach(scrollableNode, key);
|
||||
this._eventDetachers.push(() => prop.__detach(scrollableNode, key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_detachNativeEvents() {
|
||||
this._eventDetachers.forEach(remove => remove());
|
||||
this._eventDetachers = [];
|
||||
}
|
||||
|
||||
// The system is best designed when setNativeProps is implemented. It is
|
||||
// able to avoid re-rendering and directly set the attributes that changed.
|
||||
// However, setNativeProps can only be implemented on leaf native
|
||||
// components. If you want to animate a composite component, you need to
|
||||
// re-render it. In this case, we have a fallback that uses forceUpdate.
|
||||
_animatedPropsCallback = () => {
|
||||
if (this._component == null) {
|
||||
// AnimatedProps is created in will-mount because it's used in render.
|
||||
// But this callback may be invoked before mount in async mode,
|
||||
// In which case we should defer the setNativeProps() call.
|
||||
// React may throw away uncommitted work in async mode,
|
||||
// So a deferred call won't always be invoked.
|
||||
this._invokeAnimatedPropsCallbackOnMount = true;
|
||||
} else if (
|
||||
AnimatedComponent.__skipSetNativeProps_FOR_TESTS_ONLY ||
|
||||
typeof this._component.setNativeProps !== 'function'
|
||||
) {
|
||||
this.forceUpdate();
|
||||
} else if (!this._propsAnimated.__isNative) {
|
||||
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`',
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
_attachProps(nextProps) {
|
||||
const oldPropsAnimated = this._propsAnimated;
|
||||
|
||||
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
|
||||
// and so on.
|
||||
// An optimization is to attach the new elements and THEN detach the old
|
||||
// ones instead of detaching and THEN attaching.
|
||||
// This way the intermediate state isn't to go to 0 and trigger
|
||||
// this expensive recursive detaching to then re-attach everything on
|
||||
// the very next operation.
|
||||
oldPropsAnimated && oldPropsAnimated.__detach();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(newProps) {
|
||||
this._attachProps(newProps);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (this._component !== this._prevComponent) {
|
||||
this._propsAnimated.setNativeView(this._component);
|
||||
}
|
||||
if (this._component !== this._prevComponent || prevProps !== this.props) {
|
||||
this._detachNativeEvents();
|
||||
this._attachNativeEvents();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const props = this._propsAnimated.__getValue();
|
||||
return (
|
||||
<Component
|
||||
{...props}
|
||||
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
|
||||
// thread.
|
||||
collapsable={
|
||||
this._propsAnimated.__isNative ? false : props.collapsable
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
_setComponentRef(c) {
|
||||
this._prevComponent = this._component;
|
||||
this._component = c;
|
||||
}
|
||||
|
||||
// A third party library can use getNode()
|
||||
// to get the node reference of the decorated component
|
||||
getNode() {
|
||||
return this._component;
|
||||
}
|
||||
}
|
||||
|
||||
const propTypes = Component.propTypes;
|
||||
|
||||
AnimatedComponent.propTypes = {
|
||||
style: function(props, propName, componentName) {
|
||||
if (!propTypes) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const key in ViewStylePropTypes) {
|
||||
if (!propTypes[key] && props[key] !== undefined) {
|
||||
console.warn(
|
||||
'You are setting the style `{ ' +
|
||||
key +
|
||||
': ... }` as a prop. You ' +
|
||||
'should nest it in a style object. ' +
|
||||
'E.g. `{ style: { ' +
|
||||
key +
|
||||
': ... } }`',
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
return AnimatedComponent;
|
||||
}
|
||||
|
||||
module.exports = createAnimatedComponent;
|
||||
65
src/vendor/Animated/nodes/AnimatedAddition.js
vendored
Normal file
65
src/vendor/Animated/nodes/AnimatedAddition.js
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule AnimatedAddition
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const AnimatedInterpolation = require('./AnimatedInterpolation');
|
||||
const AnimatedNode = require('./AnimatedNode');
|
||||
const AnimatedValue = require('./AnimatedValue');
|
||||
const AnimatedWithChildren = require('./AnimatedWithChildren');
|
||||
|
||||
import type {InterpolationConfigType} from './AnimatedInterpolation';
|
||||
|
||||
class AnimatedAddition extends AnimatedWithChildren {
|
||||
_a: AnimatedNode;
|
||||
_b: AnimatedNode;
|
||||
|
||||
constructor(a: AnimatedNode | number, b: AnimatedNode | number) {
|
||||
super();
|
||||
this._a = typeof a === 'number' ? new AnimatedValue(a) : a;
|
||||
this._b = typeof b === 'number' ? new AnimatedValue(b) : b;
|
||||
}
|
||||
|
||||
__makeNative() {
|
||||
this._a.__makeNative();
|
||||
this._b.__makeNative();
|
||||
super.__makeNative();
|
||||
}
|
||||
|
||||
__getValue(): number {
|
||||
return this._a.__getValue() + this._b.__getValue();
|
||||
}
|
||||
|
||||
interpolate(config: InterpolationConfigType): AnimatedInterpolation {
|
||||
return new AnimatedInterpolation(this, config);
|
||||
}
|
||||
|
||||
__attach(): void {
|
||||
this._a.__addChild(this);
|
||||
this._b.__addChild(this);
|
||||
}
|
||||
|
||||
__detach(): void {
|
||||
this._a.__removeChild(this);
|
||||
this._b.__removeChild(this);
|
||||
super.__detach();
|
||||
}
|
||||
|
||||
__getNativeConfig(): any {
|
||||
return {
|
||||
type: 'addition',
|
||||
input: [this._a.__getNativeTag(), this._b.__getNativeTag()],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AnimatedAddition;
|
||||
73
src/vendor/Animated/nodes/AnimatedDiffClamp.js
vendored
Normal file
73
src/vendor/Animated/nodes/AnimatedDiffClamp.js
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule AnimatedDiffClamp
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const AnimatedInterpolation = require('./AnimatedInterpolation');
|
||||
const AnimatedNode = require('./AnimatedNode');
|
||||
const AnimatedWithChildren = require('./AnimatedWithChildren');
|
||||
|
||||
import type {InterpolationConfigType} from './AnimatedInterpolation';
|
||||
|
||||
class AnimatedDiffClamp extends AnimatedWithChildren {
|
||||
_a: AnimatedNode;
|
||||
_min: number;
|
||||
_max: number;
|
||||
_value: number;
|
||||
_lastValue: number;
|
||||
|
||||
constructor(a: AnimatedNode, min: number, max: number) {
|
||||
super();
|
||||
|
||||
this._a = a;
|
||||
this._min = min;
|
||||
this._max = max;
|
||||
this._value = this._lastValue = this._a.__getValue();
|
||||
}
|
||||
|
||||
__makeNative() {
|
||||
this._a.__makeNative();
|
||||
super.__makeNative();
|
||||
}
|
||||
|
||||
interpolate(config: InterpolationConfigType): AnimatedInterpolation {
|
||||
return new AnimatedInterpolation(this, config);
|
||||
}
|
||||
|
||||
__getValue(): number {
|
||||
const value = this._a.__getValue();
|
||||
const diff = value - this._lastValue;
|
||||
this._lastValue = value;
|
||||
this._value = Math.min(Math.max(this._value + diff, this._min), this._max);
|
||||
return this._value;
|
||||
}
|
||||
|
||||
__attach(): void {
|
||||
this._a.__addChild(this);
|
||||
}
|
||||
|
||||
__detach(): void {
|
||||
this._a.__removeChild(this);
|
||||
super.__detach();
|
||||
}
|
||||
|
||||
__getNativeConfig(): any {
|
||||
return {
|
||||
type: 'diffclamp',
|
||||
input: this._a.__getNativeTag(),
|
||||
min: this._min,
|
||||
max: this._max,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AnimatedDiffClamp;
|
||||
70
src/vendor/Animated/nodes/AnimatedDivision.js
vendored
Normal file
70
src/vendor/Animated/nodes/AnimatedDivision.js
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule AnimatedDivision
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const AnimatedInterpolation = require('./AnimatedInterpolation');
|
||||
const AnimatedNode = require('./AnimatedNode');
|
||||
const AnimatedValue = require('./AnimatedValue');
|
||||
const AnimatedWithChildren = require('./AnimatedWithChildren');
|
||||
|
||||
import type {InterpolationConfigType} from './AnimatedInterpolation';
|
||||
|
||||
class AnimatedDivision extends AnimatedWithChildren {
|
||||
_a: AnimatedNode;
|
||||
_b: AnimatedNode;
|
||||
|
||||
constructor(a: AnimatedNode | number, b: AnimatedNode | number) {
|
||||
super();
|
||||
this._a = typeof a === 'number' ? new AnimatedValue(a) : a;
|
||||
this._b = typeof b === 'number' ? new AnimatedValue(b) : b;
|
||||
}
|
||||
|
||||
__makeNative() {
|
||||
this._a.__makeNative();
|
||||
this._b.__makeNative();
|
||||
super.__makeNative();
|
||||
}
|
||||
|
||||
__getValue(): number {
|
||||
const a = this._a.__getValue();
|
||||
const b = this._b.__getValue();
|
||||
if (b === 0) {
|
||||
console.error('Detected division by zero in AnimatedDivision');
|
||||
}
|
||||
return a / b;
|
||||
}
|
||||
|
||||
interpolate(config: InterpolationConfigType): AnimatedInterpolation {
|
||||
return new AnimatedInterpolation(this, config);
|
||||
}
|
||||
|
||||
__attach(): void {
|
||||
this._a.__addChild(this);
|
||||
this._b.__addChild(this);
|
||||
}
|
||||
|
||||
__detach(): void {
|
||||
this._a.__removeChild(this);
|
||||
this._b.__removeChild(this);
|
||||
super.__detach();
|
||||
}
|
||||
|
||||
__getNativeConfig(): any {
|
||||
return {
|
||||
type: 'division',
|
||||
input: [this._a.__getNativeTag(), this._b.__getNativeTag()],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AnimatedDivision;
|
||||
388
src/vendor/Animated/nodes/AnimatedInterpolation.js
vendored
Normal file
388
src/vendor/Animated/nodes/AnimatedInterpolation.js
vendored
Normal file
@@ -0,0 +1,388 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule AnimatedInterpolation
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
/* eslint no-bitwise: 0 */
|
||||
'use strict';
|
||||
|
||||
const AnimatedNode = require('./AnimatedNode');
|
||||
const AnimatedWithChildren = require('./AnimatedWithChildren');
|
||||
const NativeAnimatedHelper = require('../NativeAnimatedHelper');
|
||||
|
||||
const invariant = require('fbjs/lib/invariant');
|
||||
const normalizeColor = require('normalize-css-color');
|
||||
|
||||
type ExtrapolateType = 'extend' | 'identity' | 'clamp';
|
||||
|
||||
export type InterpolationConfigType = {
|
||||
inputRange: Array<number>,
|
||||
/* $FlowFixMe(>=0.38.0 site=react_native_fb,react_native_oss) - Flow error
|
||||
* detected during the deployment of v0.38.0. To see the error, remove this
|
||||
* comment and run flow
|
||||
*/
|
||||
outputRange: Array<number> | Array<string>,
|
||||
easing?: (input: number) => number,
|
||||
extrapolate?: ExtrapolateType,
|
||||
extrapolateLeft?: ExtrapolateType,
|
||||
extrapolateRight?: ExtrapolateType,
|
||||
};
|
||||
|
||||
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 {
|
||||
if (config.outputRange && typeof config.outputRange[0] === 'string') {
|
||||
return createInterpolationFromStringOutputRange(config);
|
||||
}
|
||||
|
||||
const outputRange: Array<number> = (config.outputRange: any);
|
||||
checkInfiniteRange('outputRange', outputRange);
|
||||
|
||||
const inputRange = config.inputRange;
|
||||
checkInfiniteRange('inputRange', inputRange);
|
||||
checkValidInputRange(inputRange);
|
||||
|
||||
invariant(
|
||||
inputRange.length === outputRange.length,
|
||||
'inputRange (' +
|
||||
inputRange.length +
|
||||
') and outputRange (' +
|
||||
outputRange.length +
|
||||
') must have the same length',
|
||||
);
|
||||
|
||||
const easing = config.easing || linear;
|
||||
|
||||
let extrapolateLeft: ExtrapolateType = 'extend';
|
||||
if (config.extrapolateLeft !== undefined) {
|
||||
extrapolateLeft = config.extrapolateLeft;
|
||||
} else if (config.extrapolate !== undefined) {
|
||||
extrapolateLeft = config.extrapolate;
|
||||
}
|
||||
|
||||
let extrapolateRight: ExtrapolateType = 'extend';
|
||||
if (config.extrapolateRight !== undefined) {
|
||||
extrapolateRight = config.extrapolateRight;
|
||||
} else if (config.extrapolate !== undefined) {
|
||||
extrapolateRight = config.extrapolate;
|
||||
}
|
||||
|
||||
return input => {
|
||||
invariant(
|
||||
typeof input === 'number',
|
||||
'Cannot interpolation an input which is not a number',
|
||||
);
|
||||
|
||||
const range = findRange(input, inputRange);
|
||||
return interpolate(
|
||||
input,
|
||||
inputRange[range],
|
||||
inputRange[range + 1],
|
||||
outputRange[range],
|
||||
outputRange[range + 1],
|
||||
easing,
|
||||
extrapolateLeft,
|
||||
extrapolateRight,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
function interpolate(
|
||||
input: number,
|
||||
inputMin: number,
|
||||
inputMax: number,
|
||||
outputMin: number,
|
||||
outputMax: number,
|
||||
easing: (input: number) => number,
|
||||
extrapolateLeft: ExtrapolateType,
|
||||
extrapolateRight: ExtrapolateType,
|
||||
) {
|
||||
let result = input;
|
||||
|
||||
// Extrapolate
|
||||
if (result < inputMin) {
|
||||
if (extrapolateLeft === 'identity') {
|
||||
return result;
|
||||
} else if (extrapolateLeft === 'clamp') {
|
||||
result = inputMin;
|
||||
} else if (extrapolateLeft === 'extend') {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
if (result > inputMax) {
|
||||
if (extrapolateRight === 'identity') {
|
||||
return result;
|
||||
} else if (extrapolateRight === 'clamp') {
|
||||
result = inputMax;
|
||||
} else if (extrapolateRight === 'extend') {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
if (outputMin === outputMax) {
|
||||
return outputMin;
|
||||
}
|
||||
|
||||
if (inputMin === inputMax) {
|
||||
if (input <= inputMin) {
|
||||
return outputMin;
|
||||
}
|
||||
return outputMax;
|
||||
}
|
||||
|
||||
// Input Range
|
||||
if (inputMin === -Infinity) {
|
||||
result = -result;
|
||||
} else if (inputMax === Infinity) {
|
||||
result = result - inputMin;
|
||||
} else {
|
||||
result = (result - inputMin) / (inputMax - inputMin);
|
||||
}
|
||||
|
||||
// Easing
|
||||
result = easing(result);
|
||||
|
||||
// Output Range
|
||||
if (outputMin === -Infinity) {
|
||||
result = -result;
|
||||
} else if (outputMax === Infinity) {
|
||||
result = result + outputMin;
|
||||
} else {
|
||||
result = result * (outputMax - outputMin) + outputMin;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function colorToRgba(input: string): string {
|
||||
let int32Color = normalizeColor(input);
|
||||
if (int32Color === null) {
|
||||
return input;
|
||||
}
|
||||
|
||||
int32Color = int32Color || 0;
|
||||
|
||||
const r = (int32Color & 0xff000000) >>> 24;
|
||||
const g = (int32Color & 0x00ff0000) >>> 16;
|
||||
const b = (int32Color & 0x0000ff00) >>> 8;
|
||||
const a = (int32Color & 0x000000ff) / 255;
|
||||
|
||||
return `rgba(${r}, ${g}, ${b}, ${a})`;
|
||||
}
|
||||
|
||||
const stringShapeRegex = /[0-9\.-]+/g;
|
||||
|
||||
/**
|
||||
* Supports string shapes by extracting numbers so new values can be computed,
|
||||
* and recombines those values into new strings of the same shape. Supports
|
||||
* things like:
|
||||
*
|
||||
* rgba(123, 42, 99, 0.36) // colors
|
||||
* -45deg // values with units
|
||||
*/
|
||||
function createInterpolationFromStringOutputRange(
|
||||
config: InterpolationConfigType,
|
||||
): (input: number) => string {
|
||||
let outputRange: Array<string> = (config.outputRange: any);
|
||||
invariant(outputRange.length >= 2, 'Bad output range');
|
||||
outputRange = outputRange.map(colorToRgba);
|
||||
checkPattern(outputRange);
|
||||
|
||||
// ['rgba(0, 100, 200, 0)', 'rgba(50, 150, 250, 0.5)']
|
||||
// ->
|
||||
// [
|
||||
// [0, 50],
|
||||
// [100, 150],
|
||||
// [200, 250],
|
||||
// [0, 0.5],
|
||||
// ]
|
||||
/* $FlowFixMe(>=0.18.0): `outputRange[0].match()` can return `null`. Need to
|
||||
* guard against this possibility.
|
||||
*/
|
||||
const outputRanges = outputRange[0].match(stringShapeRegex).map(() => []);
|
||||
outputRange.forEach(value => {
|
||||
/* $FlowFixMe(>=0.18.0): `value.match()` can return `null`. Need to guard
|
||||
* against this possibility.
|
||||
*/
|
||||
value.match(stringShapeRegex).forEach((number, i) => {
|
||||
outputRanges[i].push(+number);
|
||||
});
|
||||
});
|
||||
|
||||
/* $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],
|
||||
});
|
||||
});
|
||||
|
||||
// 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).
|
||||
const shouldRound = isRgbOrRgba(outputRange[0]);
|
||||
|
||||
return input => {
|
||||
let i = 0;
|
||||
// 'rgba(0, 100, 200, 0)'
|
||||
// ->
|
||||
// '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;
|
||||
return String(rounded);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function isRgbOrRgba(range) {
|
||||
return typeof range === 'string' && range.startsWith('rgb');
|
||||
}
|
||||
|
||||
function checkPattern(arr: Array<string>) {
|
||||
const pattern = arr[0].replace(stringShapeRegex, '');
|
||||
for (let i = 1; i < arr.length; ++i) {
|
||||
invariant(
|
||||
pattern === arr[i].replace(stringShapeRegex, ''),
|
||||
'invalid pattern ' + arr[0] + ' and ' + arr[i],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function findRange(input: number, inputRange: Array<number>) {
|
||||
let i;
|
||||
for (i = 1; i < inputRange.length - 1; ++i) {
|
||||
if (inputRange[i] >= input) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i - 1;
|
||||
}
|
||||
|
||||
function checkValidInputRange(arr: Array<number>) {
|
||||
invariant(arr.length >= 2, 'inputRange must have at least 2 elements');
|
||||
for (let i = 1; i < arr.length; ++i) {
|
||||
invariant(
|
||||
arr[i] >= arr[i - 1],
|
||||
/* $FlowFixMe(>=0.13.0) - In the addition expression below this comment,
|
||||
* one or both of the operands may be something that doesn't cleanly
|
||||
* convert to a string, like undefined, null, and object, etc. If you really
|
||||
* mean this implicit string conversion, you can do something like
|
||||
* String(myThing)
|
||||
*/
|
||||
'inputRange must be monotonically increasing ' + arr,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function checkInfiniteRange(name: string, arr: Array<number>) {
|
||||
invariant(arr.length >= 2, name + ' must have at least 2 elements');
|
||||
invariant(
|
||||
arr.length !== 2 || arr[0] !== -Infinity || arr[1] !== Infinity,
|
||||
/* $FlowFixMe(>=0.13.0) - In the addition expression below this comment,
|
||||
* one or both of the operands may be something that doesn't cleanly convert
|
||||
* to a string, like undefined, null, and object, etc. If you really mean
|
||||
* this implicit string conversion, you can do something like
|
||||
* String(myThing)
|
||||
*/
|
||||
name + 'cannot be ]-infinity;+infinity[ ' + arr,
|
||||
);
|
||||
}
|
||||
|
||||
class AnimatedInterpolation extends AnimatedWithChildren {
|
||||
// Export for testing.
|
||||
static __createInterpolation = createInterpolation;
|
||||
|
||||
_parent: AnimatedNode;
|
||||
_config: InterpolationConfigType;
|
||||
_interpolation: (input: number) => number | string;
|
||||
|
||||
constructor(parent: AnimatedNode, config: InterpolationConfigType) {
|
||||
super();
|
||||
this._parent = parent;
|
||||
this._config = config;
|
||||
this._interpolation = createInterpolation(config);
|
||||
}
|
||||
|
||||
__makeNative() {
|
||||
this._parent.__makeNative();
|
||||
super.__makeNative();
|
||||
}
|
||||
|
||||
__getValue(): number | string {
|
||||
const parentValue: number = this._parent.__getValue();
|
||||
invariant(
|
||||
typeof parentValue === 'number',
|
||||
'Cannot interpolate an input which is not a number.',
|
||||
);
|
||||
return this._interpolation(parentValue);
|
||||
}
|
||||
|
||||
interpolate(config: InterpolationConfigType): AnimatedInterpolation {
|
||||
return new AnimatedInterpolation(this, config);
|
||||
}
|
||||
|
||||
__attach(): void {
|
||||
this._parent.__addChild(this);
|
||||
}
|
||||
|
||||
__detach(): void {
|
||||
this._parent.__removeChild(this);
|
||||
super.__detach();
|
||||
}
|
||||
|
||||
__transformDataType(range: Array<any>) {
|
||||
// Change the string array type to number array
|
||||
// So we can reuse the same logic in iOS and Android platform
|
||||
return range.map(function(value) {
|
||||
if (typeof value !== 'string') {
|
||||
return value;
|
||||
}
|
||||
if (/deg$/.test(value)) {
|
||||
const degrees = parseFloat(value) || 0;
|
||||
const radians = degrees * Math.PI / 180.0;
|
||||
return radians;
|
||||
} else {
|
||||
// Assume radians
|
||||
return parseFloat(value) || 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
__getNativeConfig(): any {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
NativeAnimatedHelper.validateInterpolation(this._config);
|
||||
}
|
||||
|
||||
return {
|
||||
inputRange: this._config.inputRange,
|
||||
// Only the `outputRange` can contain strings so we don't need to tranform `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',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AnimatedInterpolation;
|
||||
64
src/vendor/Animated/nodes/AnimatedModulo.js
vendored
Normal file
64
src/vendor/Animated/nodes/AnimatedModulo.js
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule AnimatedModulo
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const AnimatedInterpolation = require('./AnimatedInterpolation');
|
||||
const AnimatedNode = require('./AnimatedNode');
|
||||
const AnimatedWithChildren = require('./AnimatedWithChildren');
|
||||
|
||||
import type {InterpolationConfigType} from './AnimatedInterpolation';
|
||||
|
||||
class AnimatedModulo extends AnimatedWithChildren {
|
||||
_a: AnimatedNode;
|
||||
_modulus: number;
|
||||
|
||||
constructor(a: AnimatedNode, modulus: number) {
|
||||
super();
|
||||
this._a = a;
|
||||
this._modulus = modulus;
|
||||
}
|
||||
|
||||
__makeNative() {
|
||||
this._a.__makeNative();
|
||||
super.__makeNative();
|
||||
}
|
||||
|
||||
__getValue(): number {
|
||||
return (
|
||||
(this._a.__getValue() % this._modulus + this._modulus) % this._modulus
|
||||
);
|
||||
}
|
||||
|
||||
interpolate(config: InterpolationConfigType): AnimatedInterpolation {
|
||||
return new AnimatedInterpolation(this, config);
|
||||
}
|
||||
|
||||
__attach(): void {
|
||||
this._a.__addChild(this);
|
||||
}
|
||||
|
||||
__detach(): void {
|
||||
this._a.__removeChild(this);
|
||||
super.__detach();
|
||||
}
|
||||
|
||||
__getNativeConfig(): any {
|
||||
return {
|
||||
type: 'modulus',
|
||||
input: this._a.__getNativeTag(),
|
||||
modulus: this._modulus,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AnimatedModulo;
|
||||
65
src/vendor/Animated/nodes/AnimatedMultiplication.js
vendored
Normal file
65
src/vendor/Animated/nodes/AnimatedMultiplication.js
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule AnimatedMultiplication
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const AnimatedInterpolation = require('./AnimatedInterpolation');
|
||||
const AnimatedNode = require('./AnimatedNode');
|
||||
const AnimatedValue = require('./AnimatedValue');
|
||||
const AnimatedWithChildren = require('./AnimatedWithChildren');
|
||||
|
||||
import type {InterpolationConfigType} from './AnimatedInterpolation';
|
||||
|
||||
class AnimatedMultiplication extends AnimatedWithChildren {
|
||||
_a: AnimatedNode;
|
||||
_b: AnimatedNode;
|
||||
|
||||
constructor(a: AnimatedNode | number, b: AnimatedNode | number) {
|
||||
super();
|
||||
this._a = typeof a === 'number' ? new AnimatedValue(a) : a;
|
||||
this._b = typeof b === 'number' ? new AnimatedValue(b) : b;
|
||||
}
|
||||
|
||||
__makeNative() {
|
||||
this._a.__makeNative();
|
||||
this._b.__makeNative();
|
||||
super.__makeNative();
|
||||
}
|
||||
|
||||
__getValue(): number {
|
||||
return this._a.__getValue() * this._b.__getValue();
|
||||
}
|
||||
|
||||
interpolate(config: InterpolationConfigType): AnimatedInterpolation {
|
||||
return new AnimatedInterpolation(this, config);
|
||||
}
|
||||
|
||||
__attach(): void {
|
||||
this._a.__addChild(this);
|
||||
this._b.__addChild(this);
|
||||
}
|
||||
|
||||
__detach(): void {
|
||||
this._a.__removeChild(this);
|
||||
this._b.__removeChild(this);
|
||||
super.__detach();
|
||||
}
|
||||
|
||||
__getNativeConfig(): any {
|
||||
return {
|
||||
type: 'multiplication',
|
||||
input: [this._a.__getNativeTag(), this._b.__getNativeTag()],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AnimatedMultiplication;
|
||||
73
src/vendor/Animated/nodes/AnimatedNode.js
vendored
Normal file
73
src/vendor/Animated/nodes/AnimatedNode.js
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule AnimatedNode
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const NativeAnimatedHelper = require('../NativeAnimatedHelper');
|
||||
|
||||
const invariant = require('fbjs/lib/invariant');
|
||||
|
||||
// Note(vjeux): this would be better as an interface but flow doesn't
|
||||
// support them yet
|
||||
class AnimatedNode {
|
||||
__attach(): void {}
|
||||
__detach(): void {
|
||||
if (this.__isNative && this.__nativeTag != null) {
|
||||
NativeAnimatedHelper.API.dropAnimatedNode(this.__nativeTag);
|
||||
this.__nativeTag = undefined;
|
||||
}
|
||||
}
|
||||
__getValue(): any {}
|
||||
__getAnimatedValue(): any {
|
||||
return this.__getValue();
|
||||
}
|
||||
__addChild(child: AnimatedNode) {}
|
||||
__removeChild(child: AnimatedNode) {}
|
||||
__getChildren(): Array<AnimatedNode> {
|
||||
return [];
|
||||
}
|
||||
|
||||
/* Methods and props used by native Animated impl */
|
||||
__isNative: boolean;
|
||||
__nativeTag: ?number;
|
||||
__makeNative() {
|
||||
if (!this.__isNative) {
|
||||
throw new Error('This node cannot be made a "native" animated node');
|
||||
}
|
||||
}
|
||||
__getNativeTag(): ?number {
|
||||
NativeAnimatedHelper.assertNativeAnimatedModule();
|
||||
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(),
|
||||
);
|
||||
this.__nativeTag = nativeTag;
|
||||
}
|
||||
return this.__nativeTag;
|
||||
}
|
||||
__getNativeConfig(): Object {
|
||||
throw new Error(
|
||||
'This JS animated node type cannot be used as native animated node',
|
||||
);
|
||||
}
|
||||
toJSON(): any {
|
||||
return this.__getValue();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AnimatedNode;
|
||||
167
src/vendor/Animated/nodes/AnimatedProps.js
vendored
Normal file
167
src/vendor/Animated/nodes/AnimatedProps.js
vendored
Normal file
@@ -0,0 +1,167 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule AnimatedProps
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const {AnimatedEvent} = require('../AnimatedEvent');
|
||||
const AnimatedNode = require('./AnimatedNode');
|
||||
const AnimatedStyle = require('./AnimatedStyle');
|
||||
const NativeAnimatedHelper = require('../NativeAnimatedHelper');
|
||||
const findNodeHandle = require('../../../modules/findNodeHandle').default;
|
||||
|
||||
const invariant = require('fbjs/lib/invariant');
|
||||
|
||||
class AnimatedProps extends AnimatedNode {
|
||||
_props: Object;
|
||||
_animatedView: any;
|
||||
_callback: () => void;
|
||||
|
||||
constructor(props: Object, callback: () => void) {
|
||||
super();
|
||||
if (props.style) {
|
||||
props = {
|
||||
...props,
|
||||
style: new AnimatedStyle(props.style),
|
||||
};
|
||||
}
|
||||
this._props = props;
|
||||
this._callback = callback;
|
||||
this.__attach();
|
||||
}
|
||||
|
||||
__getValue(): Object {
|
||||
const props = {};
|
||||
for (const key in this._props) {
|
||||
const value = this._props[key];
|
||||
if (value instanceof AnimatedNode) {
|
||||
if (!value.__isNative || value instanceof AnimatedStyle) {
|
||||
// We cannot use value of natively driven nodes this way as the value we have access from
|
||||
// JS may not be up to date.
|
||||
props[key] = value.__getValue();
|
||||
}
|
||||
} else if (value instanceof AnimatedEvent) {
|
||||
props[key] = value.__getHandler();
|
||||
} else {
|
||||
props[key] = value;
|
||||
}
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
__getAnimatedValue(): Object {
|
||||
const props = {};
|
||||
for (const key in this._props) {
|
||||
const value = this._props[key];
|
||||
if (value instanceof AnimatedNode) {
|
||||
props[key] = value.__getAnimatedValue();
|
||||
}
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
__attach(): void {
|
||||
for (const key in this._props) {
|
||||
const value = this._props[key];
|
||||
if (value instanceof AnimatedNode) {
|
||||
value.__addChild(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__detach(): void {
|
||||
if (this.__isNative && this._animatedView) {
|
||||
this.__disconnectAnimatedView();
|
||||
}
|
||||
for (const key in this._props) {
|
||||
const value = this._props[key];
|
||||
if (value instanceof AnimatedNode) {
|
||||
value.__removeChild(this);
|
||||
}
|
||||
}
|
||||
super.__detach();
|
||||
}
|
||||
|
||||
update(): void {
|
||||
this._callback();
|
||||
}
|
||||
|
||||
__makeNative(): void {
|
||||
if (!this.__isNative) {
|
||||
this.__isNative = true;
|
||||
for (const key in this._props) {
|
||||
const value = this._props[key];
|
||||
if (value instanceof AnimatedNode) {
|
||||
value.__makeNative();
|
||||
}
|
||||
}
|
||||
if (this._animatedView) {
|
||||
this.__connectAnimatedView();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setNativeView(animatedView: any): void {
|
||||
if (this._animatedView === animatedView) {
|
||||
return;
|
||||
}
|
||||
this._animatedView = animatedView;
|
||||
if (this.__isNative) {
|
||||
this.__connectAnimatedView();
|
||||
}
|
||||
}
|
||||
|
||||
__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,
|
||||
);
|
||||
}
|
||||
|
||||
__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,
|
||||
);
|
||||
}
|
||||
|
||||
__getNativeConfig(): Object {
|
||||
const propsConfig = {};
|
||||
for (const propKey in this._props) {
|
||||
const value = this._props[propKey];
|
||||
if (value instanceof AnimatedNode) {
|
||||
propsConfig[propKey] = value.__getNativeTag();
|
||||
}
|
||||
}
|
||||
return {
|
||||
type: 'props',
|
||||
props: propsConfig,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AnimatedProps;
|
||||
127
src/vendor/Animated/nodes/AnimatedStyle.js
vendored
Normal file
127
src/vendor/Animated/nodes/AnimatedStyle.js
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule AnimatedStyle
|
||||
* @noflow
|
||||
* @format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const AnimatedNode = require('./AnimatedNode');
|
||||
const AnimatedTransform = require('./AnimatedTransform');
|
||||
const AnimatedWithChildren = require('./AnimatedWithChildren');
|
||||
const NativeAnimatedHelper = require('../NativeAnimatedHelper');
|
||||
|
||||
const flattenStyle = require('../../../apis/StyleSheet/flattenStyle').default;
|
||||
|
||||
class AnimatedStyle extends AnimatedWithChildren {
|
||||
_style: Object;
|
||||
|
||||
constructor(style: any) {
|
||||
super();
|
||||
style = flattenStyle(style) || {};
|
||||
if (style.transform) {
|
||||
style = {
|
||||
...style,
|
||||
transform: new AnimatedTransform(style.transform),
|
||||
};
|
||||
}
|
||||
this._style = style;
|
||||
}
|
||||
|
||||
// Recursively get values for nested styles (like iOS's shadowOffset)
|
||||
_walkStyleAndGetValues(style) {
|
||||
const updatedStyle = {};
|
||||
for (const key in style) {
|
||||
const value = style[key];
|
||||
if (value instanceof AnimatedNode) {
|
||||
if (!value.__isNative) {
|
||||
// We cannot use value of natively driven nodes this way as the value we have access from
|
||||
// JS may not be up to date.
|
||||
updatedStyle[key] = value.__getValue();
|
||||
}
|
||||
} else if (value && !Array.isArray(value) && typeof value === 'object') {
|
||||
// Support animating nested values (for example: shadowOffset.height)
|
||||
updatedStyle[key] = this._walkStyleAndGetValues(value);
|
||||
} else {
|
||||
updatedStyle[key] = value;
|
||||
}
|
||||
}
|
||||
return updatedStyle;
|
||||
}
|
||||
|
||||
__getValue(): Object {
|
||||
return this._walkStyleAndGetValues(this._style);
|
||||
}
|
||||
|
||||
// Recursively get animated values for nested styles (like iOS's shadowOffset)
|
||||
_walkStyleAndGetAnimatedValues(style) {
|
||||
const updatedStyle = {};
|
||||
for (const key in style) {
|
||||
const value = style[key];
|
||||
if (value instanceof AnimatedNode) {
|
||||
updatedStyle[key] = value.__getAnimatedValue();
|
||||
} else if (value && !Array.isArray(value) && typeof value === 'object') {
|
||||
// Support animating nested values (for example: shadowOffset.height)
|
||||
updatedStyle[key] = this._walkStyleAndGetAnimatedValues(value);
|
||||
}
|
||||
}
|
||||
return updatedStyle;
|
||||
}
|
||||
|
||||
__getAnimatedValue(): Object {
|
||||
return this._walkStyleAndGetAnimatedValues(this._style);
|
||||
}
|
||||
|
||||
__attach(): void {
|
||||
for (const key in this._style) {
|
||||
const value = this._style[key];
|
||||
if (value instanceof AnimatedNode) {
|
||||
value.__addChild(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__detach(): void {
|
||||
for (const key in this._style) {
|
||||
const value = this._style[key];
|
||||
if (value instanceof AnimatedNode) {
|
||||
value.__removeChild(this);
|
||||
}
|
||||
}
|
||||
super.__detach();
|
||||
}
|
||||
|
||||
__makeNative() {
|
||||
super.__makeNative();
|
||||
for (const key in this._style) {
|
||||
const value = this._style[key];
|
||||
if (value instanceof AnimatedNode) {
|
||||
value.__makeNative();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__getNativeConfig(): Object {
|
||||
const styleConfig = {};
|
||||
for (const styleKey in this._style) {
|
||||
if (this._style[styleKey] instanceof AnimatedNode) {
|
||||
styleConfig[styleKey] = this._style[styleKey].__getNativeTag();
|
||||
}
|
||||
// Non-animated styles are set using `setNativeProps`, no need
|
||||
// to pass those as a part of the node config
|
||||
}
|
||||
NativeAnimatedHelper.validateStyles(styleConfig);
|
||||
return {
|
||||
type: 'style',
|
||||
style: styleConfig,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AnimatedStyle;
|
||||
67
src/vendor/Animated/nodes/AnimatedTracking.js
vendored
Normal file
67
src/vendor/Animated/nodes/AnimatedTracking.js
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule AnimatedTracking
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const AnimatedValue = require('./AnimatedValue');
|
||||
const AnimatedNode = require('./AnimatedNode');
|
||||
|
||||
import type {EndCallback} from '../animations/Animation';
|
||||
|
||||
class AnimatedTracking extends AnimatedNode {
|
||||
_value: AnimatedValue;
|
||||
_parent: AnimatedNode;
|
||||
_callback: ?EndCallback;
|
||||
_animationConfig: Object;
|
||||
_animationClass: any;
|
||||
|
||||
constructor(
|
||||
value: AnimatedValue,
|
||||
parent: AnimatedNode,
|
||||
animationClass: any,
|
||||
animationConfig: Object,
|
||||
callback?: ?EndCallback,
|
||||
) {
|
||||
super();
|
||||
this._value = value;
|
||||
this._parent = parent;
|
||||
this._animationClass = animationClass;
|
||||
this._animationConfig = animationConfig;
|
||||
this._callback = callback;
|
||||
this.__attach();
|
||||
}
|
||||
|
||||
__getValue(): Object {
|
||||
return this._parent.__getValue();
|
||||
}
|
||||
|
||||
__attach(): void {
|
||||
this._parent.__addChild(this);
|
||||
}
|
||||
|
||||
__detach(): void {
|
||||
this._parent.__removeChild(this);
|
||||
super.__detach();
|
||||
}
|
||||
|
||||
update(): void {
|
||||
this._value.animate(
|
||||
new this._animationClass({
|
||||
...this._animationConfig,
|
||||
toValue: (this._animationConfig.toValue: any).__getValue(),
|
||||
}),
|
||||
this._callback,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AnimatedTracking;
|
||||
123
src/vendor/Animated/nodes/AnimatedTransform.js
vendored
Normal file
123
src/vendor/Animated/nodes/AnimatedTransform.js
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule AnimatedTransform
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const AnimatedNode = require('./AnimatedNode');
|
||||
const AnimatedWithChildren = require('./AnimatedWithChildren');
|
||||
const NativeAnimatedHelper = require('../NativeAnimatedHelper');
|
||||
|
||||
class AnimatedTransform extends AnimatedWithChildren {
|
||||
_transforms: Array<Object>;
|
||||
|
||||
constructor(transforms: Array<Object>) {
|
||||
super();
|
||||
this._transforms = transforms;
|
||||
}
|
||||
|
||||
__makeNative() {
|
||||
super.__makeNative();
|
||||
this._transforms.forEach(transform => {
|
||||
for (const key in transform) {
|
||||
const value = transform[key];
|
||||
if (value instanceof AnimatedNode) {
|
||||
value.__makeNative();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
__getValue(): Array<Object> {
|
||||
return this._transforms.map(transform => {
|
||||
const result = {};
|
||||
for (const key in transform) {
|
||||
const value = transform[key];
|
||||
if (value instanceof AnimatedNode) {
|
||||
result[key] = value.__getValue();
|
||||
} else {
|
||||
result[key] = value;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
__getAnimatedValue(): Array<Object> {
|
||||
return this._transforms.map(transform => {
|
||||
const result = {};
|
||||
for (const key in transform) {
|
||||
const value = transform[key];
|
||||
if (value instanceof AnimatedNode) {
|
||||
result[key] = value.__getAnimatedValue();
|
||||
} else {
|
||||
// All transform components needed to recompose matrix
|
||||
result[key] = value;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
__attach(): void {
|
||||
this._transforms.forEach(transform => {
|
||||
for (const key in transform) {
|
||||
const value = transform[key];
|
||||
if (value instanceof AnimatedNode) {
|
||||
value.__addChild(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
__detach(): void {
|
||||
this._transforms.forEach(transform => {
|
||||
for (const key in transform) {
|
||||
const value = transform[key];
|
||||
if (value instanceof AnimatedNode) {
|
||||
value.__removeChild(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
super.__detach();
|
||||
}
|
||||
|
||||
__getNativeConfig(): any {
|
||||
const transConfigs = [];
|
||||
|
||||
this._transforms.forEach(transform => {
|
||||
for (const key in transform) {
|
||||
const value = transform[key];
|
||||
if (value instanceof AnimatedNode) {
|
||||
transConfigs.push({
|
||||
type: 'animated',
|
||||
property: key,
|
||||
nodeTag: value.__getNativeTag(),
|
||||
});
|
||||
} else {
|
||||
transConfigs.push({
|
||||
type: 'static',
|
||||
property: key,
|
||||
value,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
NativeAnimatedHelper.validateTransform(transConfigs);
|
||||
return {
|
||||
type: 'transform',
|
||||
transforms: transConfigs,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AnimatedTransform;
|
||||
338
src/vendor/Animated/nodes/AnimatedValue.js
vendored
Normal file
338
src/vendor/Animated/nodes/AnimatedValue.js
vendored
Normal file
@@ -0,0 +1,338 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule AnimatedValue
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const AnimatedInterpolation = require('./AnimatedInterpolation');
|
||||
const AnimatedNode = require('./AnimatedNode');
|
||||
const AnimatedWithChildren = require('./AnimatedWithChildren');
|
||||
const InteractionManager = require('../../../apis/InteractionManager').default;
|
||||
const NativeAnimatedHelper = require('../NativeAnimatedHelper');
|
||||
|
||||
import type Animation, {EndCallback} from '../animations/Animation';
|
||||
import type {InterpolationConfigType} from './AnimatedInterpolation';
|
||||
|
||||
const NativeAnimatedAPI = NativeAnimatedHelper.API;
|
||||
|
||||
type ValueListenerCallback = (state: {value: number}) => void;
|
||||
|
||||
let _uniqueId = 1;
|
||||
|
||||
/**
|
||||
* Animated works by building a directed acyclic graph of dependencies
|
||||
* transparently when you render your Animated components.
|
||||
*
|
||||
* new Animated.Value(0)
|
||||
* .interpolate() .interpolate() new Animated.Value(1)
|
||||
* opacity translateY scale
|
||||
* style transform
|
||||
* View#234 style
|
||||
* View#123
|
||||
*
|
||||
* A) Top Down phase
|
||||
* When an Animated.Value is updated, we recursively go down through this
|
||||
* graph in order to find leaf nodes: the views that we flag as needing
|
||||
* an update.
|
||||
*
|
||||
* B) Bottom Up phase
|
||||
* When a view is flagged as needing an update, we recursively go back up
|
||||
* in order to build the new value that it needs. The reason why we need
|
||||
* this two-phases process is to deal with composite props such as
|
||||
* transform which can receive values from multiple parents.
|
||||
*/
|
||||
function _flush(rootNode: AnimatedValue): void {
|
||||
const animatedStyles = new Set();
|
||||
function findAnimatedStyles(node) {
|
||||
if (typeof node.update === 'function') {
|
||||
animatedStyles.add(node);
|
||||
} else {
|
||||
node.__getChildren().forEach(findAnimatedStyles);
|
||||
}
|
||||
}
|
||||
findAnimatedStyles(rootNode);
|
||||
/* $FlowFixMe */
|
||||
animatedStyles.forEach(animatedStyle => animatedStyle.update());
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard value for driving animations. One `Animated.Value` can drive
|
||||
* multiple properties in a synchronized fashion, but can only be driven by one
|
||||
* mechanism at a time. Using a new mechanism (e.g. starting a new animation,
|
||||
* or calling `setValue`) will stop any previous ones.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvalue.html
|
||||
*/
|
||||
class AnimatedValue extends AnimatedWithChildren {
|
||||
_value: number;
|
||||
_startingValue: number;
|
||||
_offset: number;
|
||||
_animation: ?Animation;
|
||||
_tracking: ?AnimatedNode;
|
||||
_listeners: {[key: string]: ValueListenerCallback};
|
||||
__nativeAnimatedValueListener: ?any;
|
||||
|
||||
constructor(value: number) {
|
||||
super();
|
||||
this._startingValue = this._value = value;
|
||||
this._offset = 0;
|
||||
this._animation = null;
|
||||
this._listeners = {};
|
||||
}
|
||||
|
||||
__detach() {
|
||||
this.stopAnimation();
|
||||
super.__detach();
|
||||
}
|
||||
|
||||
__getValue(): number {
|
||||
return this._value + this._offset;
|
||||
}
|
||||
|
||||
__makeNative() {
|
||||
super.__makeNative();
|
||||
|
||||
if (Object.keys(this._listeners).length) {
|
||||
this._startListeningToNativeValueUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Directly set the value. This will stop any animations running on the value
|
||||
* and update all the bound properties.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvalue.html#setvalue
|
||||
*/
|
||||
setValue(value: number): void {
|
||||
if (this._animation) {
|
||||
this._animation.stop();
|
||||
this._animation = null;
|
||||
}
|
||||
this._updateValue(
|
||||
value,
|
||||
!this.__isNative /* don't perform a flush for natively driven values */,
|
||||
);
|
||||
if (this.__isNative) {
|
||||
NativeAnimatedAPI.setAnimatedNodeValue(this.__getNativeTag(), value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an offset that is applied on top of whatever value is set, whether via
|
||||
* `setValue`, an animation, or `Animated.event`. Useful for compensating
|
||||
* things like the start of a pan gesture.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvalue.html#setoffset
|
||||
*/
|
||||
setOffset(offset: number): void {
|
||||
this._offset = offset;
|
||||
if (this.__isNative) {
|
||||
NativeAnimatedAPI.setAnimatedNodeOffset(this.__getNativeTag(), offset);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the offset value into the base value and resets the offset to zero.
|
||||
* The final output of the value is unchanged.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvalue.html#flattenoffset
|
||||
*/
|
||||
flattenOffset(): void {
|
||||
this._value += this._offset;
|
||||
this._offset = 0;
|
||||
if (this.__isNative) {
|
||||
NativeAnimatedAPI.flattenAnimatedNodeOffset(this.__getNativeTag());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the offset value to the base value, and resets the base value to zero.
|
||||
* The final output of the value is unchanged.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvalue.html#extractoffset
|
||||
*/
|
||||
extractOffset(): void {
|
||||
this._offset += this._value;
|
||||
this._value = 0;
|
||||
if (this.__isNative) {
|
||||
NativeAnimatedAPI.extractAnimatedNodeOffset(this.__getNativeTag());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an asynchronous listener to the value so you can observe updates from
|
||||
* animations. This is useful because there is no way to
|
||||
* synchronously read the value because it might be driven natively.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvalue.html#addlistener
|
||||
*/
|
||||
addListener(callback: ValueListenerCallback): string {
|
||||
const id = String(_uniqueId++);
|
||||
this._listeners[id] = callback;
|
||||
if (this.__isNative) {
|
||||
this._startListeningToNativeValueUpdates();
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a listener. The `id` param shall match the identifier
|
||||
* previously returned by `addListener()`.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvalue.html#removelistener
|
||||
*/
|
||||
removeListener(id: string): void {
|
||||
delete this._listeners[id];
|
||||
if (this.__isNative && Object.keys(this._listeners).length === 0) {
|
||||
this._stopListeningForNativeValueUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all registered listeners.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvalue.html#removealllisteners
|
||||
*/
|
||||
removeAllListeners(): void {
|
||||
this._listeners = {};
|
||||
if (this.__isNative) {
|
||||
this._stopListeningForNativeValueUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
_startListeningToNativeValueUpdates() {
|
||||
if (this.__nativeAnimatedValueListener) {
|
||||
return;
|
||||
}
|
||||
|
||||
NativeAnimatedAPI.startListeningToAnimatedNodeValue(this.__getNativeTag());
|
||||
this.__nativeAnimatedValueListener = NativeAnimatedHelper.nativeEventEmitter.addListener(
|
||||
'onAnimatedValueUpdate',
|
||||
data => {
|
||||
if (data.tag !== this.__getNativeTag()) {
|
||||
return;
|
||||
}
|
||||
this._updateValue(data.value, false /* flush */);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
_stopListeningForNativeValueUpdates() {
|
||||
if (!this.__nativeAnimatedValueListener) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.__nativeAnimatedValueListener.remove();
|
||||
this.__nativeAnimatedValueListener = null;
|
||||
NativeAnimatedAPI.stopListeningToAnimatedNodeValue(this.__getNativeTag());
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops any running animation or tracking. `callback` is invoked with the
|
||||
* final value after stopping the animation, which is useful for updating
|
||||
* state to match the animation position with layout.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvalue.html#stopanimation
|
||||
*/
|
||||
stopAnimation(callback?: ?(value: number) => void): void {
|
||||
this.stopTracking();
|
||||
this._animation && this._animation.stop();
|
||||
this._animation = null;
|
||||
callback && callback(this.__getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops any animation and resets the value to its original.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvalue.html#resetanimation
|
||||
*/
|
||||
resetAnimation(callback?: ?(value: number) => void): void {
|
||||
this.stopAnimation(callback);
|
||||
this._value = this._startingValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolates the value before updating the property, e.g. mapping 0-1 to
|
||||
* 0-10.
|
||||
*/
|
||||
interpolate(config: InterpolationConfigType): AnimatedInterpolation {
|
||||
return new AnimatedInterpolation(this, config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Typically only used internally, but could be used by a custom Animation
|
||||
* class.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvalue.html#animate
|
||||
*/
|
||||
animate(animation: Animation, callback: ?EndCallback): void {
|
||||
let handle = null;
|
||||
if (animation.__isInteraction) {
|
||||
handle = InteractionManager.createInteractionHandle();
|
||||
}
|
||||
const previousAnimation = this._animation;
|
||||
this._animation && this._animation.stop();
|
||||
this._animation = animation;
|
||||
animation.start(
|
||||
this._value,
|
||||
value => {
|
||||
// Natively driven animations will never call into that callback, therefore we can always
|
||||
// pass flush = true to allow the updated value to propagate to native with setNativeProps
|
||||
this._updateValue(value, true /* flush */);
|
||||
},
|
||||
result => {
|
||||
this._animation = null;
|
||||
if (handle !== null) {
|
||||
InteractionManager.clearInteractionHandle(handle);
|
||||
}
|
||||
callback && callback(result);
|
||||
},
|
||||
previousAnimation,
|
||||
this,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Typically only used internally.
|
||||
*/
|
||||
stopTracking(): void {
|
||||
this._tracking && this._tracking.__detach();
|
||||
this._tracking = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Typically only used internally.
|
||||
*/
|
||||
track(tracking: AnimatedNode): void {
|
||||
this.stopTracking();
|
||||
this._tracking = tracking;
|
||||
}
|
||||
|
||||
_updateValue(value: number, flush: boolean): void {
|
||||
this._value = value;
|
||||
if (flush) {
|
||||
_flush(this);
|
||||
}
|
||||
for (const key in this._listeners) {
|
||||
this._listeners[key]({value: this.__getValue()});
|
||||
}
|
||||
}
|
||||
|
||||
__getNativeConfig(): Object {
|
||||
return {
|
||||
type: 'value',
|
||||
value: this._value,
|
||||
offset: this._offset,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AnimatedValue;
|
||||
197
src/vendor/Animated/nodes/AnimatedValueXY.js
vendored
Normal file
197
src/vendor/Animated/nodes/AnimatedValueXY.js
vendored
Normal file
@@ -0,0 +1,197 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule AnimatedValueXY
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const AnimatedValue = require('./AnimatedValue');
|
||||
const AnimatedWithChildren = require('./AnimatedWithChildren');
|
||||
|
||||
const invariant = require('fbjs/lib/invariant');
|
||||
|
||||
type ValueXYListenerCallback = (value: {x: number, y: number}) => void;
|
||||
|
||||
let _uniqueId = 1;
|
||||
|
||||
/**
|
||||
* 2D Value for driving 2D animations, such as pan gestures. Almost identical
|
||||
* API to normal `Animated.Value`, but multiplexed.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvaluexy.html
|
||||
*/
|
||||
class AnimatedValueXY extends AnimatedWithChildren {
|
||||
x: AnimatedValue;
|
||||
y: AnimatedValue;
|
||||
_listeners: {[key: string]: {x: string, y: string}};
|
||||
|
||||
constructor(
|
||||
valueIn?: ?{x: number | AnimatedValue, y: number | AnimatedValue},
|
||||
) {
|
||||
super();
|
||||
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.',
|
||||
);
|
||||
this.x = value.x;
|
||||
this.y = value.y;
|
||||
}
|
||||
this._listeners = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Directly set the value. This will stop any animations running on the value
|
||||
* and update all the bound properties.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvaluexy.html#setvalue
|
||||
*/
|
||||
setValue(value: {x: number, y: number}) {
|
||||
this.x.setValue(value.x);
|
||||
this.y.setValue(value.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an offset that is applied on top of whatever value is set, whether
|
||||
* via `setValue`, an animation, or `Animated.event`. Useful for compensating
|
||||
* things like the start of a pan gesture.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvaluexy.html#setoffset
|
||||
*/
|
||||
setOffset(offset: {x: number, y: number}) {
|
||||
this.x.setOffset(offset.x);
|
||||
this.y.setOffset(offset.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the offset value into the base value and resets the offset to zero.
|
||||
* The final output of the value is unchanged.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvaluexy.html#flattenoffset
|
||||
*/
|
||||
flattenOffset(): void {
|
||||
this.x.flattenOffset();
|
||||
this.y.flattenOffset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the offset value to the base value, and resets the base value to
|
||||
* zero. The final output of the value is unchanged.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvaluexy.html#extractoffset
|
||||
*/
|
||||
extractOffset(): void {
|
||||
this.x.extractOffset();
|
||||
this.y.extractOffset();
|
||||
}
|
||||
|
||||
__getValue(): {x: number, y: number} {
|
||||
return {
|
||||
x: this.x.__getValue(),
|
||||
y: this.y.__getValue(),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops any animation and resets the value to its original.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvaluexy.html#resetanimation
|
||||
*/
|
||||
resetAnimation(callback?: (value: {x: number, y: number}) => void): void {
|
||||
this.x.resetAnimation();
|
||||
this.y.resetAnimation();
|
||||
callback && callback(this.__getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops any running animation or tracking. `callback` is invoked with the
|
||||
* final value after stopping the animation, which is useful for updating
|
||||
* state to match the animation position with layout.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvaluexy.html#stopanimation
|
||||
*/
|
||||
stopAnimation(callback?: (value: {x: number, y: number}) => void): void {
|
||||
this.x.stopAnimation();
|
||||
this.y.stopAnimation();
|
||||
callback && callback(this.__getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an asynchronous listener to the value so you can observe updates from
|
||||
* animations. This is useful because there is no way to synchronously read
|
||||
* the value because it might be driven natively.
|
||||
*
|
||||
* Returns a string that serves as an identifier for the listener.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvaluexy.html#addlistener
|
||||
*/
|
||||
addListener(callback: ValueXYListenerCallback): string {
|
||||
const id = String(_uniqueId++);
|
||||
const jointCallback = ({value: number}) => {
|
||||
callback(this.__getValue());
|
||||
};
|
||||
this._listeners[id] = {
|
||||
x: this.x.addListener(jointCallback),
|
||||
y: this.y.addListener(jointCallback),
|
||||
};
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a listener. The `id` param shall match the identifier
|
||||
* previously returned by `addListener()`.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvaluexy.html#removelistener
|
||||
*/
|
||||
removeListener(id: string): void {
|
||||
this.x.removeListener(this._listeners[id].x);
|
||||
this.y.removeListener(this._listeners[id].y);
|
||||
delete this._listeners[id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all registered listeners.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvaluexy.html#removealllisteners
|
||||
*/
|
||||
removeAllListeners(): void {
|
||||
this.x.removeAllListeners();
|
||||
this.y.removeAllListeners();
|
||||
this._listeners = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts `{x, y}` into `{left, top}` for use in style.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvaluexy.html#getlayout
|
||||
*/
|
||||
getLayout(): {[key: string]: AnimatedValue} {
|
||||
return {
|
||||
left: this.x,
|
||||
top: this.y,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts `{x, y}` into a useable translation transform.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvaluexy.html#gettranslatetransform
|
||||
*/
|
||||
getTranslateTransform(): Array<{[key: string]: AnimatedValue}> {
|
||||
return [{translateX: this.x}, {translateY: this.y}];
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AnimatedValueXY;
|
||||
77
src/vendor/Animated/nodes/AnimatedWithChildren.js
vendored
Normal file
77
src/vendor/Animated/nodes/AnimatedWithChildren.js
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule AnimatedWithChildren
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const AnimatedNode = require('./AnimatedNode');
|
||||
const NativeAnimatedHelper = require('../NativeAnimatedHelper');
|
||||
|
||||
class AnimatedWithChildren extends AnimatedNode {
|
||||
_children: Array<AnimatedNode>;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._children = [];
|
||||
}
|
||||
|
||||
__makeNative() {
|
||||
if (!this.__isNative) {
|
||||
this.__isNative = true;
|
||||
for (const child of this._children) {
|
||||
child.__makeNative();
|
||||
NativeAnimatedHelper.API.connectAnimatedNodes(
|
||||
this.__getNativeTag(),
|
||||
child.__getNativeTag(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__addChild(child: AnimatedNode): void {
|
||||
if (this._children.length === 0) {
|
||||
this.__attach();
|
||||
}
|
||||
this._children.push(child);
|
||||
if (this.__isNative) {
|
||||
// Only accept "native" animated nodes as children
|
||||
child.__makeNative();
|
||||
NativeAnimatedHelper.API.connectAnimatedNodes(
|
||||
this.__getNativeTag(),
|
||||
child.__getNativeTag(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
__removeChild(child: AnimatedNode): void {
|
||||
const index = this._children.indexOf(child);
|
||||
if (index === -1) {
|
||||
console.warn("Trying to remove a child that doesn't exist");
|
||||
return;
|
||||
}
|
||||
if (this.__isNative && child.__isNative) {
|
||||
NativeAnimatedHelper.API.disconnectAnimatedNodes(
|
||||
this.__getNativeTag(),
|
||||
child.__getNativeTag(),
|
||||
);
|
||||
}
|
||||
this._children.splice(index, 1);
|
||||
if (this._children.length === 0) {
|
||||
this.__detach();
|
||||
}
|
||||
}
|
||||
|
||||
__getChildren(): Array<AnimatedNode> {
|
||||
return this._children;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AnimatedWithChildren;
|
||||
2
src/vendor/PooledClass/index.js
vendored
2
src/vendor/PooledClass/index.js
vendored
@@ -7,6 +7,8 @@
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* From React 16.0.0
|
||||
*/
|
||||
|
||||
import invariant from 'fbjs/lib/invariant';
|
||||
|
||||
1
src/vendor/dangerousStyleValue/index.js
vendored
1
src/vendor/dangerousStyleValue/index.js
vendored
@@ -9,6 +9,7 @@
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule dangerousStyleValue
|
||||
* From React 16.0.0
|
||||
*/
|
||||
|
||||
import isUnitlessNumber from '../../modules/unitlessNumbers';
|
||||
|
||||
1
src/vendor/setValueForStyles/index.js
vendored
1
src/vendor/setValueForStyles/index.js
vendored
@@ -8,6 +8,7 @@
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* From React 16.0.0
|
||||
*/
|
||||
|
||||
import dangerousStyleValue from '../dangerousStyleValue';
|
||||
|
||||
1
src/vendor/warnValidStyle/index.js
vendored
1
src/vendor/warnValidStyle/index.js
vendored
@@ -9,6 +9,7 @@
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule warnValidStyle
|
||||
* From React 16.0.0
|
||||
*/
|
||||
|
||||
var emptyFunction = require('fbjs/lib/emptyFunction');
|
||||
|
||||
@@ -169,13 +169,6 @@ amdefine@>=0.0.4:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
|
||||
|
||||
animated@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/animated/-/animated-0.2.0.tgz#1a0e96f097b3fbc5b64d7eddc723bcc0a6f97633"
|
||||
dependencies:
|
||||
invariant "^2.2.0"
|
||||
normalize-css-color "^1.0.1"
|
||||
|
||||
ansi-align@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f"
|
||||
@@ -3925,7 +3918,7 @@ nopt@~3.0.6:
|
||||
dependencies:
|
||||
abbrev "1"
|
||||
|
||||
normalize-css-color@^1.0.1, normalize-css-color@^1.0.2:
|
||||
normalize-css-color@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/normalize-css-color/-/normalize-css-color-1.0.2.tgz#02991e97cccec6623fe573afbbf0de6a1f3e9f8d"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user