This commit is contained in:
Yamozha
2021-04-02 02:24:13 +03:00
parent c23950b545
commit 7256d79e2c
31493 changed files with 3036630 additions and 0 deletions

View File

@ -0,0 +1,168 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
import AnimatedValue from './nodes/AnimatedValue';
import NativeAnimatedHelper from './NativeAnimatedHelper';
import findNodeHandle from '../../../exports/findNodeHandle';
import invariant from 'fbjs/lib/invariant';
var shouldUseNativeDriver = NativeAnimatedHelper.shouldUseNativeDriver;
function attachNativeEvent(viewRef, eventName, argMapping) {
// Find animated values in `argMapping` and create an array representing their
// key path inside the `nativeEvent` object. Ex.: ['contentOffset', 'x'].
var eventMappings = [];
var traverse = function traverse(value, path) {
if (value instanceof AnimatedValue) {
value.__makeNative();
eventMappings.push({
nativeEventPath: path,
animatedValueTag: value.__getNativeTag()
});
} else if (typeof value === 'object') {
for (var _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, []);
var viewTag = findNodeHandle(viewRef);
eventMappings.forEach(function (mapping) {
NativeAnimatedHelper.API.addAnimatedEventToView(viewTag, eventName, mapping);
});
return {
detach: function detach() {
eventMappings.forEach(function (mapping) {
NativeAnimatedHelper.API.removeAnimatedEventFromView(viewTag, eventName, mapping.animatedValueTag);
});
}
};
}
var AnimatedEvent =
/*#__PURE__*/
function () {
function AnimatedEvent(argMapping, config) {
if (config === void 0) {
config = {};
}
this._listeners = [];
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();
}
}
var _proto = AnimatedEvent.prototype;
_proto.__addListener = function __addListener(callback) {
this._listeners.push(callback);
};
_proto.__removeListener = function __removeListener(callback) {
this._listeners = this._listeners.filter(function (listener) {
return listener !== callback;
});
};
_proto.__attach = function __attach(viewRef, eventName) {
invariant(this.__isNative, 'Only native driven events need to be attached.');
this._attachedEvent = attachNativeEvent(viewRef, eventName, this._argMapping);
};
_proto.__detach = function __detach(viewTag, eventName) {
invariant(this.__isNative, 'Only native driven events need to be detached.');
this._attachedEvent && this._attachedEvent.detach();
};
_proto.__getHandler = function __getHandler() {
var _this = this;
if (this.__isNative) {
return this._callListeners;
}
return function () {
for (var _len = arguments.length, args = new Array(_len), _key2 = 0; _key2 < _len; _key2++) {
args[_key2] = arguments[_key2];
}
var traverse = function traverse(recMapping, recEvt, key) {
if (typeof recEvt === 'number' && recMapping instanceof AnimatedValue) {
recMapping.setValue(recEvt);
} else if (typeof recMapping === 'object') {
for (var 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(function (mapping, idx) {
traverse(mapping, args[idx], 'arg' + idx);
});
}
_this._callListeners.apply(_this, args);
};
};
_proto._callListeners = function _callListeners() {
for (var _len2 = arguments.length, args = new Array(_len2), _key3 = 0; _key3 < _len2; _key3++) {
args[_key3] = arguments[_key3];
}
this._listeners.forEach(function (listener) {
return listener.apply(void 0, args);
});
};
_proto._validateMapping = function _validateMapping() {
var traverse = function 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 (var mappingKey in recMapping) {
traverse(recMapping[mappingKey], recEvt[mappingKey], mappingKey);
}
};
};
return AnimatedEvent;
}();
export { AnimatedEvent, attachNativeEvent };
export default {
AnimatedEvent: AnimatedEvent,
attachNativeEvent: attachNativeEvent
};

View File

@ -0,0 +1,616 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
* @preventMunge
*/
'use strict';
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import { AnimatedEvent, attachNativeEvent } from './AnimatedEvent';
import AnimatedAddition from './nodes/AnimatedAddition';
import AnimatedDiffClamp from './nodes/AnimatedDiffClamp';
import AnimatedDivision from './nodes/AnimatedDivision';
import AnimatedInterpolation from './nodes/AnimatedInterpolation';
import AnimatedModulo from './nodes/AnimatedModulo';
import AnimatedMultiplication from './nodes/AnimatedMultiplication';
import AnimatedNode from './nodes/AnimatedNode';
import AnimatedProps from './nodes/AnimatedProps';
import AnimatedSubtraction from './nodes/AnimatedSubtraction';
import AnimatedTracking from './nodes/AnimatedTracking';
import AnimatedValue from './nodes/AnimatedValue';
import AnimatedValueXY from './nodes/AnimatedValueXY';
import DecayAnimation from './animations/DecayAnimation';
import SpringAnimation from './animations/SpringAnimation';
import TimingAnimation from './animations/TimingAnimation';
import createAnimatedComponent from './createAnimatedComponent';
var add = function add(a, b) {
return new AnimatedAddition(a, b);
};
var subtract = function subtract(a, b) {
return new AnimatedSubtraction(a, b);
};
var divide = function divide(a, b) {
return new AnimatedDivision(a, b);
};
var multiply = function multiply(a, b) {
return new AnimatedMultiplication(a, b);
};
var modulo = function modulo(a, modulus) {
return new AnimatedModulo(a, modulus);
};
var diffClamp = function diffClamp(a, min, max) {
return new AnimatedDiffClamp(a, min, max);
};
var _combineCallbacks = function _combineCallbacks(callback, config) {
if (callback && config.onComplete) {
return function () {
config.onComplete && config.onComplete.apply(config, arguments);
callback && callback.apply(void 0, arguments);
};
} else {
return callback || config.onComplete;
}
};
var maybeVectorAnim = function maybeVectorAnim(value, config, anim) {
if (value instanceof AnimatedValueXY) {
var configX = _objectSpread({}, config);
var configY = _objectSpread({}, config);
for (var key in config) {
var _config$key = config[key],
x = _config$key.x,
y = _config$key.y;
if (x !== undefined && y !== undefined) {
configX[key] = x;
configY[key] = y;
}
}
var aX = anim(value.x, configX);
var aY = anim(value.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;
};
var spring = function spring(value, config) {
var _start = function start(animatedValue, configuration, callback) {
callback = _combineCallbacks(callback, configuration);
var singleValue = animatedValue;
var singleConfig = 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 start(callback) {
_start(value, config, callback);
},
stop: function stop() {
value.stopAnimation();
},
reset: function reset() {
value.resetAnimation();
},
_startNativeLoop: function _startNativeLoop(iterations) {
var singleConfig = _objectSpread({}, config, {
iterations: iterations
});
_start(value, singleConfig);
},
_isUsingNativeDriver: function _isUsingNativeDriver() {
return config.useNativeDriver || false;
}
};
};
var timing = function timing(value, config) {
var _start2 = function start(animatedValue, configuration, callback) {
callback = _combineCallbacks(callback, configuration);
var singleValue = animatedValue;
var singleConfig = 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 start(callback) {
_start2(value, config, callback);
},
stop: function stop() {
value.stopAnimation();
},
reset: function reset() {
value.resetAnimation();
},
_startNativeLoop: function _startNativeLoop(iterations) {
var singleConfig = _objectSpread({}, config, {
iterations: iterations
});
_start2(value, singleConfig);
},
_isUsingNativeDriver: function _isUsingNativeDriver() {
return config.useNativeDriver || false;
}
};
};
var decay = function decay(value, config) {
var _start3 = function start(animatedValue, configuration, callback) {
callback = _combineCallbacks(callback, configuration);
var singleValue = animatedValue;
var singleConfig = configuration;
singleValue.stopTracking();
singleValue.animate(new DecayAnimation(singleConfig), callback);
};
return maybeVectorAnim(value, config, decay) || {
start: function start(callback) {
_start3(value, config, callback);
},
stop: function stop() {
value.stopAnimation();
},
reset: function reset() {
value.resetAnimation();
},
_startNativeLoop: function _startNativeLoop(iterations) {
var singleConfig = _objectSpread({}, config, {
iterations: iterations
});
_start3(value, singleConfig);
},
_isUsingNativeDriver: function _isUsingNativeDriver() {
return config.useNativeDriver || false;
}
};
};
var sequence = function sequence(animations) {
var current = 0;
return {
start: function start(callback) {
var onComplete = function onComplete(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 stop() {
if (current < animations.length) {
animations[current].stop();
}
},
reset: function reset() {
animations.forEach(function (animation, idx) {
if (idx <= current) {
animation.reset();
}
});
current = 0;
},
_startNativeLoop: function _startNativeLoop() {
throw new Error('Loops run using the native driver cannot contain Animated.sequence animations');
},
_isUsingNativeDriver: function _isUsingNativeDriver() {
return false;
}
};
};
var parallel = function parallel(animations, config) {
var doneCount = 0; // Make sure we only call stop() at most once for each animation
var hasEnded = {};
var stopTogether = !(config && config.stopTogether === false);
var result = {
start: function start(callback) {
if (doneCount === animations.length) {
callback && callback({
finished: true
});
return;
}
animations.forEach(function (animation, idx) {
var cb = function cb(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 stop() {
animations.forEach(function (animation, idx) {
!hasEnded[idx] && animation.stop();
hasEnded[idx] = true;
});
},
reset: function reset() {
animations.forEach(function (animation, idx) {
animation.reset();
hasEnded[idx] = false;
doneCount = 0;
});
},
_startNativeLoop: function _startNativeLoop() {
throw new Error('Loops run using the native driver cannot contain Animated.parallel animations');
},
_isUsingNativeDriver: function _isUsingNativeDriver() {
return false;
}
};
return result;
};
var delay = function delay(time) {
// Would be nice to make a specialized implementation
return timing(new AnimatedValue(0), {
toValue: 0,
delay: time,
duration: 0
});
};
var stagger = function stagger(time, animations) {
return parallel(animations.map(function (animation, i) {
return sequence([delay(time * i), animation]);
}));
};
var loop = function loop(animation, _temp) {
var _ref = _temp === void 0 ? {} : _temp,
_ref$iterations = _ref.iterations,
iterations = _ref$iterations === void 0 ? -1 : _ref$iterations,
_ref$resetBeforeItera = _ref.resetBeforeIteration,
resetBeforeIteration = _ref$resetBeforeItera === void 0 ? true : _ref$resetBeforeItera;
var isFinished = false;
var iterationsSoFar = 0;
return {
start: function start(callback) {
var restart = function restart(result) {
if (result === void 0) {
result = {
finished: true
};
}
if (isFinished || iterationsSoFar === iterations || result.finished === false) {
callback && callback(result);
} else {
iterationsSoFar++;
resetBeforeIteration && 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 stop() {
isFinished = true;
animation.stop();
},
reset: function reset() {
iterationsSoFar = 0;
isFinished = false;
animation.reset();
},
_startNativeLoop: function _startNativeLoop() {
throw new Error('Loops run using the native driver cannot contain Animated.loop animations');
},
_isUsingNativeDriver: function _isUsingNativeDriver() {
return animation._isUsingNativeDriver();
}
};
};
function forkEvent(event, listener) {
if (!event) {
return listener;
} else if (event instanceof AnimatedEvent) {
event.__addListener(listener);
return event;
} else {
return function () {
typeof event === 'function' && event.apply(void 0, arguments);
listener.apply(void 0, arguments);
};
}
}
function unforkEvent(event, listener) {
if (event && event instanceof AnimatedEvent) {
event.__removeListener(listener);
}
}
var event = function event(argMapping, config) {
var 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.
* If additional transforms are added, be sure to include them in
* AnimatedMock.js as well.
*
* See http://facebook.github.io/react-native/docs/animated.html
*/
var AnimatedImplementation = {
/**
* 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/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: 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: 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: 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: add,
/**
* Creates a new Animated value composed by subtracting the second Animated
* value from the first Animated value.
*
* See http://facebook.github.io/react-native/docs/animated.html#subtract
*/
subtract: subtract,
/**
* 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: 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: 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: 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: diffClamp,
/**
* Starts an animation after the given delay.
*
* See http://facebook.github.io/react-native/docs/animated.html#delay
*/
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: 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: 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: 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: 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: event,
/**
* Make any React component Animatable. Used to create `Animated.View`, etc.
*
* See http://facebook.github.io/react-native/docs/animated.html#createanimatedcomponent
*/
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: 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: forkEvent,
unforkEvent: unforkEvent,
/**
* Expose Event class, so it can be used as a type for type checkers.
*/
Event: AnimatedEvent,
__PropsOnlyForTests: AnimatedProps
};
export default AnimatedImplementation;

View File

@ -0,0 +1,290 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*
*/
'use strict';
import _bezier from './bezier';
var _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
*/
var Easing =
/*#__PURE__*/
function () {
function Easing() {}
/**
* A stepping function, returns 1 for any positive value of `n`.
*/
Easing.step0 = function step0(n) {
return n > 0 ? 1 : 0;
}
/**
* A stepping function, returns 1 if `n` is greater than or equal to 1.
*/
;
Easing.step1 = function 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
*/
;
Easing.linear = function linear(t) {
return t;
}
/**
* A simple inertial interaction, similar to an object slowly accelerating to
* speed.
*
* http://cubic-bezier.com/#.42,0,1,1
*/
;
Easing.ease = function ease(t) {
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
*/
;
Easing.quad = function quad(t) {
return t * t;
}
/**
* A cubic function, `f(t) = t * t * t`. Position equals the cube of elapsed
* time.
*
* http://easings.net/#easeInCubic
*/
;
Easing.cubic = function 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
*/
;
Easing.poly = function poly(n) {
return function (t) {
return Math.pow(t, n);
};
}
/**
* A sinusoidal function.
*
* http://easings.net/#easeInSine
*/
;
Easing.sin = function sin(t) {
return 1 - Math.cos(t * Math.PI / 2);
}
/**
* A circular function.
*
* http://easings.net/#easeInCirc
*/
;
Easing.circle = function circle(t) {
return 1 - Math.sqrt(1 - t * t);
}
/**
* An exponential function.
*
* http://easings.net/#easeInExpo
*/
;
Easing.exp = function 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
*/
;
Easing.elastic = function elastic(bounciness) {
if (bounciness === void 0) {
bounciness = 1;
}
var p = bounciness * Math.PI;
return function (t) {
return 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)
*/
;
Easing.back = function back(s) {
if (s === void 0) {
s = 1.70158;
}
return function (t) {
return t * t * ((s + 1) * t - s);
};
}
/**
* Provides a simple bouncing effect.
*
* http://easings.net/#easeInBounce
*/
;
Easing.bounce = function bounce(t) {
if (t < 1 / 2.75) {
return 7.5625 * t * t;
}
if (t < 2 / 2.75) {
var _t = t - 1.5 / 2.75;
return 7.5625 * _t * _t + 0.75;
}
if (t < 2.5 / 2.75) {
var _t2 = t - 2.25 / 2.75;
return 7.5625 * _t2 * _t2 + 0.9375;
}
var t2 = t - 2.625 / 2.75;
return 7.5625 * t2 * t2 + 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/
*/
;
Easing.bezier = function bezier(x1, y1, x2, y2) {
return _bezier(x1, y1, x2, y2);
}
/**
* Runs an easing function forwards.
*/
;
Easing.in = function _in(easing) {
return easing;
}
/**
* Runs an easing function backwards.
*/
;
Easing.out = function out(easing) {
return function (t) {
return 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.
*/
;
Easing.inOut = function inOut(easing) {
return function (t) {
if (t < 0.5) {
return easing(t * 2) / 2;
}
return 1 - easing((1 - t) * 2) / 2;
};
};
return Easing;
}();
export default Easing;

View File

@ -0,0 +1,261 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
import NativeEventEmitter from '../NativeEventEmitter';
import NativeAnimatedModule from './NativeAnimatedModule';
import invariant from 'fbjs/lib/invariant';
var __nativeAnimatedNodeTagCount = 1;
/* used for animated nodes */
var __nativeAnimationIdCount = 1;
/* used for started animations */
var nativeEventEmitter;
var queueConnections = false;
var queue = [];
/**
* Simple wrappers around NativeAnimatedModule to provide flow and autocmplete support for
* the native module methods
*/
var API = {
enableQueue: function enableQueue() {
queueConnections = true;
},
disableQueue: function disableQueue() {
invariant(NativeAnimatedModule, 'Native animated module is not available');
queueConnections = false;
for (var q = 0, l = queue.length; q < l; q++) {
var args = queue[q];
NativeAnimatedModule.connectAnimatedNodes(args[0], args[1]);
}
queue.length = 0;
},
createAnimatedNode: function createAnimatedNode(tag, config) {
invariant(NativeAnimatedModule, 'Native animated module is not available');
NativeAnimatedModule.createAnimatedNode(tag, config);
},
startListeningToAnimatedNodeValue: function startListeningToAnimatedNodeValue(tag) {
invariant(NativeAnimatedModule, 'Native animated module is not available');
NativeAnimatedModule.startListeningToAnimatedNodeValue(tag);
},
stopListeningToAnimatedNodeValue: function stopListeningToAnimatedNodeValue(tag) {
invariant(NativeAnimatedModule, 'Native animated module is not available');
NativeAnimatedModule.stopListeningToAnimatedNodeValue(tag);
},
connectAnimatedNodes: function connectAnimatedNodes(parentTag, childTag) {
invariant(NativeAnimatedModule, 'Native animated module is not available');
if (queueConnections) {
queue.push([parentTag, childTag]);
return;
}
NativeAnimatedModule.connectAnimatedNodes(parentTag, childTag);
},
disconnectAnimatedNodes: function disconnectAnimatedNodes(parentTag, childTag) {
invariant(NativeAnimatedModule, 'Native animated module is not available');
NativeAnimatedModule.disconnectAnimatedNodes(parentTag, childTag);
},
startAnimatingNode: function startAnimatingNode(animationId, nodeTag, config, endCallback) {
invariant(NativeAnimatedModule, 'Native animated module is not available');
NativeAnimatedModule.startAnimatingNode(animationId, nodeTag, config, endCallback);
},
stopAnimation: function stopAnimation(animationId) {
invariant(NativeAnimatedModule, 'Native animated module is not available');
NativeAnimatedModule.stopAnimation(animationId);
},
setAnimatedNodeValue: function setAnimatedNodeValue(nodeTag, value) {
invariant(NativeAnimatedModule, 'Native animated module is not available');
NativeAnimatedModule.setAnimatedNodeValue(nodeTag, value);
},
setAnimatedNodeOffset: function setAnimatedNodeOffset(nodeTag, offset) {
invariant(NativeAnimatedModule, 'Native animated module is not available');
NativeAnimatedModule.setAnimatedNodeOffset(nodeTag, offset);
},
flattenAnimatedNodeOffset: function flattenAnimatedNodeOffset(nodeTag) {
invariant(NativeAnimatedModule, 'Native animated module is not available');
NativeAnimatedModule.flattenAnimatedNodeOffset(nodeTag);
},
extractAnimatedNodeOffset: function extractAnimatedNodeOffset(nodeTag) {
invariant(NativeAnimatedModule, 'Native animated module is not available');
NativeAnimatedModule.extractAnimatedNodeOffset(nodeTag);
},
connectAnimatedNodeToView: function connectAnimatedNodeToView(nodeTag, viewTag) {
invariant(NativeAnimatedModule, 'Native animated module is not available');
NativeAnimatedModule.connectAnimatedNodeToView(nodeTag, viewTag);
},
disconnectAnimatedNodeFromView: function disconnectAnimatedNodeFromView(nodeTag, viewTag) {
invariant(NativeAnimatedModule, 'Native animated module is not available');
NativeAnimatedModule.disconnectAnimatedNodeFromView(nodeTag, viewTag);
},
dropAnimatedNode: function dropAnimatedNode(tag) {
invariant(NativeAnimatedModule, 'Native animated module is not available');
NativeAnimatedModule.dropAnimatedNode(tag);
},
addAnimatedEventToView: function addAnimatedEventToView(viewTag, eventName, eventMapping) {
invariant(NativeAnimatedModule, 'Native animated module is not available');
NativeAnimatedModule.addAnimatedEventToView(viewTag, eventName, eventMapping);
},
removeAnimatedEventFromView: function removeAnimatedEventFromView(viewTag, eventName, animatedNodeTag) {
invariant(NativeAnimatedModule, 'Native animated module is not available');
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).
*/
var STYLES_WHITELIST = {
opacity: true,
transform: true,
borderRadius: true,
borderBottomEndRadius: true,
borderBottomLeftRadius: true,
borderBottomRightRadius: true,
borderBottomStartRadius: true,
borderTopEndRadius: true,
borderTopLeftRadius: true,
borderTopRightRadius: true,
borderTopStartRadius: true,
elevation: true,
/* ios styles */
shadowOpacity: true,
shadowRadius: true,
/* legacy android transform properties */
scaleX: true,
scaleY: true,
translateX: true,
translateY: true
};
var TRANSFORM_WHITELIST = {
translateX: true,
translateY: true,
scale: true,
scaleX: true,
scaleY: true,
rotate: true,
rotateX: true,
rotateY: true,
perspective: true
};
var SUPPORTED_INTERPOLATION_PARAMS = {
inputRange: true,
outputRange: true,
extrapolate: true,
extrapolateRight: true,
extrapolateLeft: true
};
function addWhitelistedStyleProp(prop) {
STYLES_WHITELIST[prop] = true;
}
function addWhitelistedTransformProp(prop) {
TRANSFORM_WHITELIST[prop] = true;
}
function addWhitelistedInterpolationParam(param) {
SUPPORTED_INTERPOLATION_PARAMS[param] = true;
}
function validateTransform(configs) {
configs.forEach(function (config) {
if (!TRANSFORM_WHITELIST.hasOwnProperty(config.property)) {
throw new Error("Property '" + config.property + "' is not supported by native animated module");
}
});
}
function validateStyles(styles) {
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) {
for (var _key2 in config) {
if (!SUPPORTED_INTERPOLATION_PARAMS.hasOwnProperty(_key2)) {
throw new Error("Interpolation property '" + _key2 + "' is not supported by native animated module");
}
}
}
function generateNewNodeTag() {
return __nativeAnimatedNodeTagCount++;
}
function generateNewAnimationId() {
return __nativeAnimationIdCount++;
}
function assertNativeAnimatedModule() {
invariant(NativeAnimatedModule, 'Native animated module is not available');
}
function shouldUseNativeDriver(config) {
if (config.useNativeDriver === true && !NativeAnimatedModule) {
return false;
}
return config.useNativeDriver || false;
}
function transformDataType(value) {
// Change the string type to number type so we can reuse the same logic in
// iOS and Android platform
if (typeof value !== 'string') {
return value;
}
if (/deg$/.test(value)) {
var degrees = parseFloat(value) || 0;
var radians = degrees * Math.PI / 180.0;
return radians;
} else {
return value;
}
}
var NativeAnimatedHelper = {
API: API,
addWhitelistedStyleProp: addWhitelistedStyleProp,
addWhitelistedTransformProp: addWhitelistedTransformProp,
addWhitelistedInterpolationParam: addWhitelistedInterpolationParam,
validateStyles: validateStyles,
validateTransform: validateTransform,
validateInterpolation: validateInterpolation,
generateNewNodeTag: generateNewNodeTag,
generateNewAnimationId: generateNewAnimationId,
assertNativeAnimatedModule: assertNativeAnimatedModule,
shouldUseNativeDriver: shouldUseNativeDriver,
transformDataType: transformDataType,
get nativeEventEmitter() {
if (!nativeEventEmitter) {
nativeEventEmitter = new NativeEventEmitter(NativeAnimatedModule);
}
return nativeEventEmitter;
}
};
export { API, addWhitelistedStyleProp, addWhitelistedTransformProp, addWhitelistedInterpolationParam, validateStyles, validateTransform, validateInterpolation, generateNewNodeTag, generateNewAnimationId, assertNativeAnimatedModule, shouldUseNativeDriver, transformDataType };
export default NativeAnimatedHelper;

View File

@ -0,0 +1,13 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry';
export default TurboModuleRegistry.get('NativeAnimatedModule');

View File

@ -0,0 +1,81 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*
*/
'use strict';
function stiffnessFromOrigamiValue(oValue) {
return (oValue - 30) * 3.62 + 194;
}
function dampingFromOrigamiValue(oValue) {
return (oValue - 8) * 3 + 25;
}
function fromOrigamiTensionAndFriction(tension, friction) {
return {
stiffness: stiffnessFromOrigamiValue(tension),
damping: dampingFromOrigamiValue(friction)
};
}
function fromBouncinessAndSpeed(bounciness, speed) {
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)
};
}
export { fromOrigamiTensionAndFriction, fromBouncinessAndSpeed };
export default {
fromOrigamiTensionAndFriction: fromOrigamiTensionAndFriction,
fromBouncinessAndSpeed: fromBouncinessAndSpeed
};

View File

@ -0,0 +1,58 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
import NativeAnimatedHelper from '../NativeAnimatedHelper';
// 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.
var Animation =
/*#__PURE__*/
function () {
function Animation() {}
var _proto = Animation.prototype;
_proto.start = function start(fromValue, onUpdate, onEnd, previousAnimation, animatedValue) {};
_proto.stop = function stop() {
if (this.__nativeId) {
NativeAnimatedHelper.API.stopAnimation(this.__nativeId);
}
};
_proto.__getNativeAnimationConfig = function __getNativeAnimationConfig() {
// 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.
;
_proto.__debouncedOnEnd = function __debouncedOnEnd(result) {
var onEnd = this.__onEnd;
this.__onEnd = null;
onEnd && onEnd(result);
};
_proto.__startNativeAnimation = function __startNativeAnimation(animatedValue) {
NativeAnimatedHelper.API.enableQueue();
animatedValue.__makeNative();
NativeAnimatedHelper.API.disableQueue();
this.__nativeId = NativeAnimatedHelper.generateNewAnimationId();
NativeAnimatedHelper.API.startAnimatingNode(this.__nativeId, animatedValue.__getNativeTag(), this.__getNativeAnimationConfig(), this.__debouncedOnEnd.bind(this));
};
return Animation;
}();
export default Animation;

View File

@ -0,0 +1,97 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
import Animation from './Animation';
import { shouldUseNativeDriver } from '../NativeAnimatedHelper';
var DecayAnimation =
/*#__PURE__*/
function (_Animation) {
_inheritsLoose(DecayAnimation, _Animation);
function DecayAnimation(config) {
var _config$deceleration, _config$isInteraction, _config$iterations;
var _this;
_this = _Animation.call(this) || this;
_this._deceleration = (_config$deceleration = config.deceleration) !== null && _config$deceleration !== void 0 ? _config$deceleration : 0.998;
_this._velocity = config.velocity;
_this._useNativeDriver = shouldUseNativeDriver(config);
_this.__isInteraction = (_config$isInteraction = config.isInteraction) !== null && _config$isInteraction !== void 0 ? _config$isInteraction : !_this._useNativeDriver;
_this.__iterations = (_config$iterations = config.iterations) !== null && _config$iterations !== void 0 ? _config$iterations : 1;
return _this;
}
var _proto = DecayAnimation.prototype;
_proto.__getNativeAnimationConfig = function __getNativeAnimationConfig() {
return {
type: 'decay',
deceleration: this._deceleration,
velocity: this._velocity,
iterations: this.__iterations
};
};
_proto.start = function start(fromValue, onUpdate, onEnd, previousAnimation, animatedValue) {
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));
}
};
_proto.onUpdate = function onUpdate() {
var now = Date.now();
var 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));
}
};
_proto.stop = function stop() {
_Animation.prototype.stop.call(this);
this.__active = false;
global.cancelAnimationFrame(this._animationFrame);
this.__debouncedOnEnd({
finished: false
});
};
return DecayAnimation;
}(Animation);
export default DecayAnimation;

View File

@ -0,0 +1,272 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
import AnimatedValue from '../nodes/AnimatedValue';
import AnimatedValueXY from '../nodes/AnimatedValueXY';
import Animation from './Animation';
import SpringConfig from '../SpringConfig';
import invariant from 'fbjs/lib/invariant';
import { shouldUseNativeDriver } from '../NativeAnimatedHelper';
var SpringAnimation =
/*#__PURE__*/
function (_Animation) {
_inheritsLoose(SpringAnimation, _Animation);
function SpringAnimation(config) {
var _config$overshootClam, _config$restDisplacem, _config$restSpeedThre, _config$velocity, _config$velocity2, _config$delay, _config$isInteraction, _config$iterations;
var _this;
_this = _Animation.call(this) || this;
_this._overshootClamping = (_config$overshootClam = config.overshootClamping) !== null && _config$overshootClam !== void 0 ? _config$overshootClam : false;
_this._restDisplacementThreshold = (_config$restDisplacem = config.restDisplacementThreshold) !== null && _config$restDisplacem !== void 0 ? _config$restDisplacem : 0.001;
_this._restSpeedThreshold = (_config$restSpeedThre = config.restSpeedThreshold) !== null && _config$restSpeedThre !== void 0 ? _config$restSpeedThre : 0.001;
_this._initialVelocity = (_config$velocity = config.velocity) !== null && _config$velocity !== void 0 ? _config$velocity : 0;
_this._lastVelocity = (_config$velocity2 = config.velocity) !== null && _config$velocity2 !== void 0 ? _config$velocity2 : 0;
_this._toValue = config.toValue;
_this._delay = (_config$delay = config.delay) !== null && _config$delay !== void 0 ? _config$delay : 0;
_this._useNativeDriver = shouldUseNativeDriver(config);
_this.__isInteraction = (_config$isInteraction = config.isInteraction) !== null && _config$isInteraction !== void 0 ? _config$isInteraction : !_this._useNativeDriver;
_this.__iterations = (_config$iterations = config.iterations) !== null && _config$iterations !== void 0 ? _config$iterations : 1;
if (config.stiffness !== undefined || config.damping !== undefined || config.mass !== undefined) {
var _config$stiffness, _config$damping, _config$mass;
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 = (_config$stiffness = config.stiffness) !== null && _config$stiffness !== void 0 ? _config$stiffness : 100;
_this._damping = (_config$damping = config.damping) !== null && _config$damping !== void 0 ? _config$damping : 10;
_this._mass = (_config$mass = config.mass) !== null && _config$mass !== void 0 ? _config$mass : 1;
} else if (config.bounciness !== undefined || config.speed !== undefined) {
var _config$bounciness, _config$speed;
// 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');
var springConfig = SpringConfig.fromBouncinessAndSpeed((_config$bounciness = config.bounciness) !== null && _config$bounciness !== void 0 ? _config$bounciness : 8, (_config$speed = config.speed) !== null && _config$speed !== void 0 ? _config$speed : 12);
_this._stiffness = springConfig.stiffness;
_this._damping = springConfig.damping;
_this._mass = 1;
} else {
var _config$tension, _config$friction;
// Convert the origami tension/friction values to stiffness/damping
// We assume mass is 1.
var _springConfig = SpringConfig.fromOrigamiTensionAndFriction((_config$tension = config.tension) !== null && _config$tension !== void 0 ? _config$tension : 40, (_config$friction = config.friction) !== null && _config$friction !== void 0 ? _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');
return _this;
}
var _proto = SpringAnimation.prototype;
_proto.__getNativeAnimationConfig = function __getNativeAnimationConfig() {
var _this$_initialVelocit;
return {
type: 'spring',
overshootClamping: this._overshootClamping,
restDisplacementThreshold: this._restDisplacementThreshold,
restSpeedThreshold: this._restSpeedThreshold,
stiffness: this._stiffness,
damping: this._damping,
mass: this._mass,
initialVelocity: (_this$_initialVelocit = this._initialVelocity) !== null && _this$_initialVelocit !== void 0 ? _this$_initialVelocit : this._lastVelocity,
toValue: this._toValue,
iterations: this.__iterations
};
};
_proto.start = function start(fromValue, onUpdate, onEnd, previousAnimation, animatedValue) {
var _this2 = this;
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) {
var 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;
}
var start = function start() {
if (_this2._useNativeDriver) {
_this2.__startNativeAnimation(animatedValue);
} else {
_this2.onUpdate();
}
}; // If this._delay is more than 0, we start after the timeout.
if (this._delay) {
this._timeout = setTimeout(start, this._delay);
} else {
start();
}
};
_proto.getInternalState = function getInternalState() {
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.
*/
;
_proto.onUpdate = function onUpdate() {
// 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.
var MAX_STEPS = 64;
var now = Date.now();
if (now > this._lastTime + MAX_STEPS) {
now = this._lastTime + MAX_STEPS;
}
var deltaTime = (now - this._lastTime) / 1000;
this._frameTime += deltaTime;
var c = this._damping;
var m = this._mass;
var k = this._stiffness;
var v0 = -this._initialVelocity;
var zeta = c / (2 * Math.sqrt(k * m)); // damping ratio
var omega0 = Math.sqrt(k / m); // undamped angular frequency of the oscillator (rad/ms)
var omega1 = omega0 * Math.sqrt(1.0 - zeta * zeta); // exponential decay
var x0 = this._toValue - this._startPosition; // calculate the oscillation from x0 = 1 to x = 0
var position = 0.0;
var velocity = 0.0;
var t = this._frameTime;
if (zeta < 1) {
// Under damped
var 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
var _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
var isOvershooting = false;
if (this._overshootClamping && this._stiffness !== 0) {
if (this._startPosition < this._toValue) {
isOvershooting = position > this._toValue;
} else {
isOvershooting = position < this._toValue;
}
}
var isVelocity = Math.abs(velocity) <= this._restSpeedThreshold;
var 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));
};
_proto.stop = function stop() {
_Animation.prototype.stop.call(this);
this.__active = false;
clearTimeout(this._timeout);
global.cancelAnimationFrame(this._animationFrame);
this.__debouncedOnEnd({
finished: false
});
};
return SpringAnimation;
}(Animation);
export default SpringAnimation;

View File

@ -0,0 +1,145 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
import AnimatedValue from '../nodes/AnimatedValue';
import AnimatedValueXY from '../nodes/AnimatedValueXY';
import Animation from './Animation';
import Easing from '../Easing';
import { shouldUseNativeDriver } from '../NativeAnimatedHelper';
var _easeInOut;
function easeInOut() {
if (!_easeInOut) {
_easeInOut = Easing.inOut(Easing.ease);
}
return _easeInOut;
}
var TimingAnimation =
/*#__PURE__*/
function (_Animation) {
_inheritsLoose(TimingAnimation, _Animation);
function TimingAnimation(config) {
var _config$easing, _config$duration, _config$delay, _config$iterations, _config$isInteraction;
var _this;
_this = _Animation.call(this) || this;
_this._toValue = config.toValue;
_this._easing = (_config$easing = config.easing) !== null && _config$easing !== void 0 ? _config$easing : easeInOut();
_this._duration = (_config$duration = config.duration) !== null && _config$duration !== void 0 ? _config$duration : 500;
_this._delay = (_config$delay = config.delay) !== null && _config$delay !== void 0 ? _config$delay : 0;
_this.__iterations = (_config$iterations = config.iterations) !== null && _config$iterations !== void 0 ? _config$iterations : 1;
_this._useNativeDriver = shouldUseNativeDriver(config);
_this.__isInteraction = (_config$isInteraction = config.isInteraction) !== null && _config$isInteraction !== void 0 ? _config$isInteraction : !_this._useNativeDriver;
return _this;
}
var _proto = TimingAnimation.prototype;
_proto.__getNativeAnimationConfig = function __getNativeAnimationConfig() {
var frameDuration = 1000.0 / 60.0;
var frames = [];
for (var dt = 0.0; dt < this._duration; dt += frameDuration) {
frames.push(this._easing(dt / this._duration));
}
frames.push(this._easing(1));
return {
type: 'frames',
frames: frames,
toValue: this._toValue,
iterations: this.__iterations
};
};
_proto.start = function start(fromValue, onUpdate, onEnd, previousAnimation, animatedValue) {
var _this2 = this;
this.__active = true;
this._fromValue = fromValue;
this._onUpdate = onUpdate;
this.__onEnd = onEnd;
var start = function 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 (_this2._duration === 0 && !_this2._useNativeDriver) {
_this2._onUpdate(_this2._toValue);
_this2.__debouncedOnEnd({
finished: true
});
} else {
_this2._startTime = Date.now();
if (_this2._useNativeDriver) {
_this2.__startNativeAnimation(animatedValue);
} else {
_this2._animationFrame = requestAnimationFrame(_this2.onUpdate.bind(_this2));
}
}
};
if (this._delay) {
this._timeout = setTimeout(start, this._delay);
} else {
start();
}
};
_proto.onUpdate = function onUpdate() {
var 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));
}
};
_proto.stop = function stop() {
_Animation.prototype.stop.call(this);
this.__active = false;
clearTimeout(this._timeout);
global.cancelAnimationFrame(this._animationFrame);
this.__debouncedOnEnd({
finished: false
});
};
return TimingAnimation;
}(Animation);
export default TimingAnimation;

View File

@ -0,0 +1,138 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* BezierEasing - use bezier curve for transition easing function
* https://github.com/gre/bezier-easing
*
*
* @format
* @copyright 2014-2015 Gaëtan Renaudeau. MIT License.
*/
'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,
aA = _aA,
aB = _aB;
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) {
var aGuessT = _aGuessT;
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 (!(mX1 >= 0 && mX1 <= 1 && mX2 >= 0 && mX2 <= 1)) {
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);
};
};

View File

@ -0,0 +1,186 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
import { AnimatedEvent } from './AnimatedEvent';
import AnimatedProps from './nodes/AnimatedProps';
import React from 'react';
import invariant from 'fbjs/lib/invariant';
import mergeRefs from '../../../modules/mergeRefs';
function createAnimatedComponent(Component, defaultProps) {
invariant(typeof Component !== 'function' || Component.prototype && Component.prototype.isReactComponent, '`createAnimatedComponent` does not support stateless functional components; ' + 'use a class component instead.');
var AnimatedComponent =
/*#__PURE__*/
function (_React$Component) {
_inheritsLoose(AnimatedComponent, _React$Component);
function AnimatedComponent(props) {
var _this;
_this = _React$Component.call(this, props) || this;
_this._invokeAnimatedPropsCallbackOnMount = false;
_this._eventDetachers = [];
_this._animatedPropsCallback = function () {
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`');
}
};
_this._setComponentRef = mergeRefs(_this.props.forwardedRef, function (ref) {
_this._prevComponent = _this._component;
_this._component = ref; // TODO: Delete this in a future release.
if (ref != null && ref.getNode == null) {
ref.getNode = function () {
var _ref$constructor$name;
console.warn('%s: Calling `getNode()` on the ref of an Animated component ' + 'is no longer necessary. You can now directly use the ref ' + 'instead. This method will be removed in a future release.', (_ref$constructor$name = ref.constructor.name) !== null && _ref$constructor$name !== void 0 ? _ref$constructor$name : '<<anonymous>>');
return ref;
};
}
});
return _this;
}
var _proto = AnimatedComponent.prototype;
_proto.componentWillUnmount = function componentWillUnmount() {
this._propsAnimated && this._propsAnimated.__detach();
this._detachNativeEvents();
};
_proto.UNSAFE_componentWillMount = function UNSAFE_componentWillMount() {
this._attachProps(this.props);
};
_proto.componentDidMount = function componentDidMount() {
if (this._invokeAnimatedPropsCallbackOnMount) {
this._invokeAnimatedPropsCallbackOnMount = false;
this._animatedPropsCallback();
}
this._propsAnimated.setNativeView(this._component);
this._attachNativeEvents();
};
_proto._attachNativeEvents = function _attachNativeEvents() {
var _this2 = this;
// Make sure to get the scrollable node for components that implement
// `ScrollResponder.Mixin`.
var scrollableNode = this._component && this._component.getScrollableNode ? this._component.getScrollableNode() : this._component;
var _loop = function _loop(key) {
var prop = _this2.props[key];
if (prop instanceof AnimatedEvent && prop.__isNative) {
prop.__attach(scrollableNode, key);
_this2._eventDetachers.push(function () {
return prop.__detach(scrollableNode, key);
});
}
};
for (var key in this.props) {
_loop(key);
}
};
_proto._detachNativeEvents = function _detachNativeEvents() {
this._eventDetachers.forEach(function (remove) {
return 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.
;
_proto._attachProps = function _attachProps(nextProps) {
var 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();
};
_proto.UNSAFE_componentWillReceiveProps = function UNSAFE_componentWillReceiveProps(newProps) {
this._attachProps(newProps);
};
_proto.componentDidUpdate = function componentDidUpdate(prevProps) {
if (this._component !== this._prevComponent) {
this._propsAnimated.setNativeView(this._component);
}
if (this._component !== this._prevComponent || prevProps !== this.props) {
this._detachNativeEvents();
this._attachNativeEvents();
}
};
_proto.render = function render() {
var props = this._propsAnimated.__getValue();
return React.createElement(Component, _extends({}, defaultProps, 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 NativeViewHierarchyManager since it operates on the shadow
// thread.
,
collapsable: false
}));
};
return AnimatedComponent;
}(React.Component);
AnimatedComponent.__skipSetNativeProps_FOR_TESTS_ONLY = false;
var propTypes = Component.propTypes;
return React.forwardRef(function AnimatedComponentWrapper(props, ref) {
return React.createElement(AnimatedComponent, _extends({}, props, ref == null ? null : {
forwardedRef: ref
}));
});
}
export default createAnimatedComponent;

View File

@ -0,0 +1,75 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
import AnimatedInterpolation from './AnimatedInterpolation';
import AnimatedNode from './AnimatedNode';
import AnimatedValue from './AnimatedValue';
import AnimatedWithChildren from './AnimatedWithChildren';
var AnimatedAddition =
/*#__PURE__*/
function (_AnimatedWithChildren) {
_inheritsLoose(AnimatedAddition, _AnimatedWithChildren);
function AnimatedAddition(a, b) {
var _this;
_this = _AnimatedWithChildren.call(this) || this;
_this._a = typeof a === 'number' ? new AnimatedValue(a) : a;
_this._b = typeof b === 'number' ? new AnimatedValue(b) : b;
return _this;
}
var _proto = AnimatedAddition.prototype;
_proto.__makeNative = function __makeNative() {
this._a.__makeNative();
this._b.__makeNative();
_AnimatedWithChildren.prototype.__makeNative.call(this);
};
_proto.__getValue = function __getValue() {
return this._a.__getValue() + this._b.__getValue();
};
_proto.interpolate = function interpolate(config) {
return new AnimatedInterpolation(this, config);
};
_proto.__attach = function __attach() {
this._a.__addChild(this);
this._b.__addChild(this);
};
_proto.__detach = function __detach() {
this._a.__removeChild(this);
this._b.__removeChild(this);
_AnimatedWithChildren.prototype.__detach.call(this);
};
_proto.__getNativeConfig = function __getNativeConfig() {
return {
type: 'addition',
input: [this._a.__getNativeTag(), this._b.__getNativeTag()]
};
};
return AnimatedAddition;
}(AnimatedWithChildren);
export default AnimatedAddition;

View File

@ -0,0 +1,77 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
import AnimatedInterpolation from './AnimatedInterpolation';
import AnimatedNode from './AnimatedNode';
import AnimatedWithChildren from './AnimatedWithChildren';
var AnimatedDiffClamp =
/*#__PURE__*/
function (_AnimatedWithChildren) {
_inheritsLoose(AnimatedDiffClamp, _AnimatedWithChildren);
function AnimatedDiffClamp(a, min, max) {
var _this;
_this = _AnimatedWithChildren.call(this) || this;
_this._a = a;
_this._min = min;
_this._max = max;
_this._value = _this._lastValue = _this._a.__getValue();
return _this;
}
var _proto = AnimatedDiffClamp.prototype;
_proto.__makeNative = function __makeNative() {
this._a.__makeNative();
_AnimatedWithChildren.prototype.__makeNative.call(this);
};
_proto.interpolate = function interpolate(config) {
return new AnimatedInterpolation(this, config);
};
_proto.__getValue = function __getValue() {
var value = this._a.__getValue();
var diff = value - this._lastValue;
this._lastValue = value;
this._value = Math.min(Math.max(this._value + diff, this._min), this._max);
return this._value;
};
_proto.__attach = function __attach() {
this._a.__addChild(this);
};
_proto.__detach = function __detach() {
this._a.__removeChild(this);
_AnimatedWithChildren.prototype.__detach.call(this);
};
_proto.__getNativeConfig = function __getNativeConfig() {
return {
type: 'diffclamp',
input: this._a.__getNativeTag(),
min: this._min,
max: this._max
};
};
return AnimatedDiffClamp;
}(AnimatedWithChildren);
export default AnimatedDiffClamp;

View File

@ -0,0 +1,83 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
import AnimatedInterpolation from './AnimatedInterpolation';
import AnimatedNode from './AnimatedNode';
import AnimatedValue from './AnimatedValue';
import AnimatedWithChildren from './AnimatedWithChildren';
var AnimatedDivision =
/*#__PURE__*/
function (_AnimatedWithChildren) {
_inheritsLoose(AnimatedDivision, _AnimatedWithChildren);
function AnimatedDivision(a, b) {
var _this;
_this = _AnimatedWithChildren.call(this) || this;
_this._a = typeof a === 'number' ? new AnimatedValue(a) : a;
_this._b = typeof b === 'number' ? new AnimatedValue(b) : b;
return _this;
}
var _proto = AnimatedDivision.prototype;
_proto.__makeNative = function __makeNative() {
this._a.__makeNative();
this._b.__makeNative();
_AnimatedWithChildren.prototype.__makeNative.call(this);
};
_proto.__getValue = function __getValue() {
var a = this._a.__getValue();
var b = this._b.__getValue();
if (b === 0) {
console.error('Detected division by zero in AnimatedDivision');
}
return a / b;
};
_proto.interpolate = function interpolate(config) {
return new AnimatedInterpolation(this, config);
};
_proto.__attach = function __attach() {
this._a.__addChild(this);
this._b.__addChild(this);
};
_proto.__detach = function __detach() {
this._a.__removeChild(this);
this._b.__removeChild(this);
_AnimatedWithChildren.prototype.__detach.call(this);
};
_proto.__getNativeConfig = function __getNativeConfig() {
return {
type: 'division',
input: [this._a.__getNativeTag(), this._b.__getNativeTag()]
};
};
return AnimatedDivision;
}(AnimatedWithChildren);
export default AnimatedDivision;

View File

@ -0,0 +1,330 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
/* eslint no-bitwise: 0 */
'use strict';
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import AnimatedNode from './AnimatedNode';
import AnimatedWithChildren from './AnimatedWithChildren';
import NativeAnimatedHelper from '../NativeAnimatedHelper';
import invariant from 'fbjs/lib/invariant';
import normalizeColor from 'normalize-css-color';
var linear = function linear(t) {
return 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) {
if (config.outputRange && typeof config.outputRange[0] === 'string') {
return createInterpolationFromStringOutputRange(config);
}
var outputRange = config.outputRange;
checkInfiniteRange('outputRange', outputRange);
var 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');
var easing = config.easing || linear;
var extrapolateLeft = 'extend';
if (config.extrapolateLeft !== undefined) {
extrapolateLeft = config.extrapolateLeft;
} else if (config.extrapolate !== undefined) {
extrapolateLeft = config.extrapolate;
}
var extrapolateRight = 'extend';
if (config.extrapolateRight !== undefined) {
extrapolateRight = config.extrapolateRight;
} else if (config.extrapolate !== undefined) {
extrapolateRight = config.extrapolate;
}
return function (input) {
invariant(typeof input === 'number', 'Cannot interpolation an input which is not a number');
var range = findRange(input, inputRange);
return interpolate(input, inputRange[range], inputRange[range + 1], outputRange[range], outputRange[range + 1], easing, extrapolateLeft, extrapolateRight);
};
}
function interpolate(input, inputMin, inputMax, outputMin, outputMax, easing, extrapolateLeft, extrapolateRight) {
var 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) {
var int32Color = normalizeColor(input);
if (int32Color === null) {
return input;
}
int32Color = int32Color || 0;
var r = (int32Color & 0xff000000) >>> 24;
var g = (int32Color & 0x00ff0000) >>> 16;
var b = (int32Color & 0x0000ff00) >>> 8;
var a = (int32Color & 0x000000ff) / 255;
return "rgba(" + r + ", " + g + ", " + b + ", " + a + ")";
}
var stringShapeRegex = /[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?/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) {
var outputRange = config.outputRange;
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.
*/
var outputRanges = outputRange[0].match(stringShapeRegex).map(function () {
return [];
});
outputRange.forEach(function (value) {
/* $FlowFixMe(>=0.18.0): `value.match()` can return `null`. Need to guard
* against this possibility.
*/
value.match(stringShapeRegex).forEach(function (number, i) {
outputRanges[i].push(+number);
});
});
/* $FlowFixMe(>=0.18.0): `outputRange[0].match()` can return `null`. Need to
* guard against this possibility.
*/
var interpolations = outputRange[0].match(stringShapeRegex).map(function (value, i) {
return createInterpolation(_objectSpread({}, 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).
var shouldRound = isRgbOrRgba(outputRange[0]);
return function (input) {
var i = 0; // 'rgba(0, 100, 200, 0)'
// ->
// 'rgba(${interpolations[0](input)}, ${interpolations[1](input)}, ...'
return outputRange[0].replace(stringShapeRegex, function () {
var val = +interpolations[i++](input);
if (shouldRound) {
val = i < 4 ? Math.round(val) : Math.round(val * 1000) / 1000;
}
return String(val);
});
};
}
function isRgbOrRgba(range) {
return typeof range === 'string' && range.startsWith('rgb');
}
function checkPattern(arr) {
var pattern = arr[0].replace(stringShapeRegex, '');
for (var i = 1; i < arr.length; ++i) {
invariant(pattern === arr[i].replace(stringShapeRegex, ''), 'invalid pattern ' + arr[0] + ' and ' + arr[i]);
}
}
function findRange(input, inputRange) {
var i;
for (i = 1; i < inputRange.length - 1; ++i) {
if (inputRange[i] >= input) {
break;
}
}
return i - 1;
}
function checkValidInputRange(arr) {
invariant(arr.length >= 2, 'inputRange must have at least 2 elements');
for (var 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 non-decreasing ' + arr);
}
}
function checkInfiniteRange(name, arr) {
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);
}
var AnimatedInterpolation =
/*#__PURE__*/
function (_AnimatedWithChildren) {
_inheritsLoose(AnimatedInterpolation, _AnimatedWithChildren);
// Export for testing.
function AnimatedInterpolation(parent, config) {
var _this;
_this = _AnimatedWithChildren.call(this) || this;
_this._parent = parent;
_this._config = config;
_this._interpolation = createInterpolation(config);
return _this;
}
var _proto = AnimatedInterpolation.prototype;
_proto.__makeNative = function __makeNative() {
this._parent.__makeNative();
_AnimatedWithChildren.prototype.__makeNative.call(this);
};
_proto.__getValue = function __getValue() {
var parentValue = this._parent.__getValue();
invariant(typeof parentValue === 'number', 'Cannot interpolate an input which is not a number.');
return this._interpolation(parentValue);
};
_proto.interpolate = function interpolate(config) {
return new AnimatedInterpolation(this, config);
};
_proto.__attach = function __attach() {
this._parent.__addChild(this);
};
_proto.__detach = function __detach() {
this._parent.__removeChild(this);
_AnimatedWithChildren.prototype.__detach.call(this);
};
_proto.__transformDataType = function __transformDataType(range) {
// $FlowFixMe
return range.map(NativeAnimatedHelper.transformDataType);
};
_proto.__getNativeConfig = function __getNativeConfig() {
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 transform `inputRange` here
outputRange: this.__transformDataType(this._config.outputRange),
extrapolateLeft: this._config.extrapolateLeft || this._config.extrapolate || 'extend',
extrapolateRight: this._config.extrapolateRight || this._config.extrapolate || 'extend',
type: 'interpolation'
};
};
return AnimatedInterpolation;
}(AnimatedWithChildren);
AnimatedInterpolation.__createInterpolation = createInterpolation;
export default AnimatedInterpolation;

View File

@ -0,0 +1,69 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
import AnimatedInterpolation from './AnimatedInterpolation';
import AnimatedNode from './AnimatedNode';
import AnimatedWithChildren from './AnimatedWithChildren';
var AnimatedModulo =
/*#__PURE__*/
function (_AnimatedWithChildren) {
_inheritsLoose(AnimatedModulo, _AnimatedWithChildren);
function AnimatedModulo(a, modulus) {
var _this;
_this = _AnimatedWithChildren.call(this) || this;
_this._a = a;
_this._modulus = modulus;
return _this;
}
var _proto = AnimatedModulo.prototype;
_proto.__makeNative = function __makeNative() {
this._a.__makeNative();
_AnimatedWithChildren.prototype.__makeNative.call(this);
};
_proto.__getValue = function __getValue() {
return (this._a.__getValue() % this._modulus + this._modulus) % this._modulus;
};
_proto.interpolate = function interpolate(config) {
return new AnimatedInterpolation(this, config);
};
_proto.__attach = function __attach() {
this._a.__addChild(this);
};
_proto.__detach = function __detach() {
this._a.__removeChild(this);
_AnimatedWithChildren.prototype.__detach.call(this);
};
_proto.__getNativeConfig = function __getNativeConfig() {
return {
type: 'modulus',
input: this._a.__getNativeTag(),
modulus: this._modulus
};
};
return AnimatedModulo;
}(AnimatedWithChildren);
export default AnimatedModulo;

View File

@ -0,0 +1,75 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
import AnimatedInterpolation from './AnimatedInterpolation';
import AnimatedNode from './AnimatedNode';
import AnimatedValue from './AnimatedValue';
import AnimatedWithChildren from './AnimatedWithChildren';
var AnimatedMultiplication =
/*#__PURE__*/
function (_AnimatedWithChildren) {
_inheritsLoose(AnimatedMultiplication, _AnimatedWithChildren);
function AnimatedMultiplication(a, b) {
var _this;
_this = _AnimatedWithChildren.call(this) || this;
_this._a = typeof a === 'number' ? new AnimatedValue(a) : a;
_this._b = typeof b === 'number' ? new AnimatedValue(b) : b;
return _this;
}
var _proto = AnimatedMultiplication.prototype;
_proto.__makeNative = function __makeNative() {
this._a.__makeNative();
this._b.__makeNative();
_AnimatedWithChildren.prototype.__makeNative.call(this);
};
_proto.__getValue = function __getValue() {
return this._a.__getValue() * this._b.__getValue();
};
_proto.interpolate = function interpolate(config) {
return new AnimatedInterpolation(this, config);
};
_proto.__attach = function __attach() {
this._a.__addChild(this);
this._b.__addChild(this);
};
_proto.__detach = function __detach() {
this._a.__removeChild(this);
this._b.__removeChild(this);
_AnimatedWithChildren.prototype.__detach.call(this);
};
_proto.__getNativeConfig = function __getNativeConfig() {
return {
type: 'multiplication',
input: [this._a.__getNativeTag(), this._b.__getNativeTag()]
};
};
return AnimatedMultiplication;
}(AnimatedWithChildren);
export default AnimatedMultiplication;

View File

@ -0,0 +1,185 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
import NativeAnimatedHelper from '../NativeAnimatedHelper';
import invariant from 'fbjs/lib/invariant';
var NativeAnimatedAPI = NativeAnimatedHelper.API;
var _uniqueId = 1; // Note(vjeux): this would be better as an interface but flow doesn't
// support them yet
var AnimatedNode =
/*#__PURE__*/
function () {
var _proto = AnimatedNode.prototype;
_proto.__attach = function __attach() {};
_proto.__detach = function __detach() {
if (this.__isNative && this.__nativeTag != null) {
NativeAnimatedHelper.API.dropAnimatedNode(this.__nativeTag);
this.__nativeTag = undefined;
}
};
_proto.__getValue = function __getValue() {};
_proto.__getAnimatedValue = function __getAnimatedValue() {
return this.__getValue();
};
_proto.__addChild = function __addChild(child) {};
_proto.__removeChild = function __removeChild(child) {};
_proto.__getChildren = function __getChildren() {
return [];
}
/* Methods and props used by native Animated impl */
;
function AnimatedNode() {
this._listeners = {};
}
_proto.__makeNative = function __makeNative() {
if (!this.__isNative) {
throw new Error('This node cannot be made a "native" animated node');
}
if (this.hasListeners()) {
this._startListeningToNativeValueUpdates();
}
}
/**
* 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
*/
;
_proto.addListener = function addListener(callback) {
var 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
*/
;
_proto.removeListener = function removeListener(id) {
delete this._listeners[id];
if (this.__isNative && !this.hasListeners()) {
this._stopListeningForNativeValueUpdates();
}
}
/**
* Remove all registered listeners.
*
* See http://facebook.github.io/react-native/docs/animatedvalue.html#removealllisteners
*/
;
_proto.removeAllListeners = function removeAllListeners() {
this._listeners = {};
if (this.__isNative) {
this._stopListeningForNativeValueUpdates();
}
};
_proto.hasListeners = function hasListeners() {
return !!Object.keys(this._listeners).length;
};
_proto._startListeningToNativeValueUpdates = function _startListeningToNativeValueUpdates() {
var _this = this;
if (this.__nativeAnimatedValueListener && !this.__shouldUpdateListenersForNewNativeTag) {
return;
}
if (this.__shouldUpdateListenersForNewNativeTag) {
this.__shouldUpdateListenersForNewNativeTag = false;
this._stopListeningForNativeValueUpdates();
}
NativeAnimatedAPI.startListeningToAnimatedNodeValue(this.__getNativeTag());
this.__nativeAnimatedValueListener = NativeAnimatedHelper.nativeEventEmitter.addListener('onAnimatedValueUpdate', function (data) {
if (data.tag !== _this.__getNativeTag()) {
return;
}
_this._onAnimatedValueUpdateReceived(data.value);
});
};
_proto._onAnimatedValueUpdateReceived = function _onAnimatedValueUpdateReceived(value) {
this.__callListeners(value);
};
_proto.__callListeners = function __callListeners(value) {
for (var _key in this._listeners) {
this._listeners[_key]({
value: value
});
}
};
_proto._stopListeningForNativeValueUpdates = function _stopListeningForNativeValueUpdates() {
if (!this.__nativeAnimatedValueListener) {
return;
}
this.__nativeAnimatedValueListener.remove();
this.__nativeAnimatedValueListener = null;
NativeAnimatedAPI.stopListeningToAnimatedNodeValue(this.__getNativeTag());
};
_proto.__getNativeTag = function __getNativeTag() {
NativeAnimatedHelper.assertNativeAnimatedModule();
invariant(this.__isNative, 'Attempt to get native tag from node not marked as "native"');
if (this.__nativeTag == null) {
var nativeTag = NativeAnimatedHelper.generateNewNodeTag();
this.__nativeTag = nativeTag;
NativeAnimatedHelper.API.createAnimatedNode(nativeTag, this.__getNativeConfig());
this.__shouldUpdateListenersForNewNativeTag = true;
}
return this.__nativeTag;
};
_proto.__getNativeConfig = function __getNativeConfig() {
throw new Error('This JS animated node type cannot be used as native animated node');
};
_proto.toJSON = function toJSON() {
return this.__getValue();
};
return AnimatedNode;
}();
export default AnimatedNode;

View File

@ -0,0 +1,185 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
import { AnimatedEvent } from '../AnimatedEvent';
import AnimatedNode from './AnimatedNode';
import AnimatedStyle from './AnimatedStyle';
import NativeAnimatedHelper from '../NativeAnimatedHelper';
import findNodeHandle from '../../../../exports/findNodeHandle';
import invariant from 'fbjs/lib/invariant';
var AnimatedProps =
/*#__PURE__*/
function (_AnimatedNode) {
_inheritsLoose(AnimatedProps, _AnimatedNode);
function AnimatedProps(props, callback) {
var _this;
_this = _AnimatedNode.call(this) || this;
if (props.style) {
props = _objectSpread({}, props, {
style: new AnimatedStyle(props.style)
});
}
_this._props = props;
_this._callback = callback;
_this.__attach();
return _this;
}
var _proto = AnimatedProps.prototype;
_proto.__getValue = function __getValue() {
var props = {};
for (var key in this._props) {
var 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;
};
_proto.__getAnimatedValue = function __getAnimatedValue() {
var props = {};
for (var key in this._props) {
var value = this._props[key];
if (value instanceof AnimatedNode) {
props[key] = value.__getAnimatedValue();
}
}
return props;
};
_proto.__attach = function __attach() {
for (var key in this._props) {
var value = this._props[key];
if (value instanceof AnimatedNode) {
value.__addChild(this);
}
}
};
_proto.__detach = function __detach() {
if (this.__isNative && this._animatedView) {
this.__disconnectAnimatedView();
}
for (var key in this._props) {
var value = this._props[key];
if (value instanceof AnimatedNode) {
value.__removeChild(this);
}
}
_AnimatedNode.prototype.__detach.call(this);
};
_proto.update = function update() {
this._callback();
};
_proto.__makeNative = function __makeNative() {
if (!this.__isNative) {
this.__isNative = true;
for (var key in this._props) {
var value = this._props[key];
if (value instanceof AnimatedNode) {
value.__makeNative();
}
}
if (this._animatedView) {
this.__connectAnimatedView();
}
}
};
_proto.setNativeView = function setNativeView(animatedView) {
if (this._animatedView === animatedView) {
return;
}
this._animatedView = animatedView;
if (this.__isNative) {
this.__connectAnimatedView();
}
};
_proto.__connectAnimatedView = function __connectAnimatedView() {
invariant(this.__isNative, 'Expected node to be marked as "native"');
var nativeViewTag = findNodeHandle(this._animatedView);
invariant(nativeViewTag != null, 'Unable to locate attached view in the native tree');
NativeAnimatedHelper.API.connectAnimatedNodeToView(this.__getNativeTag(), nativeViewTag);
};
_proto.__disconnectAnimatedView = function __disconnectAnimatedView() {
invariant(this.__isNative, 'Expected node to be marked as "native"');
var nativeViewTag = findNodeHandle(this._animatedView);
invariant(nativeViewTag != null, 'Unable to locate attached view in the native tree');
NativeAnimatedHelper.API.disconnectAnimatedNodeFromView(this.__getNativeTag(), nativeViewTag);
};
_proto.__getNativeConfig = function __getNativeConfig() {
var propsConfig = {};
for (var propKey in this._props) {
var value = this._props[propKey];
if (value instanceof AnimatedNode) {
value.__makeNative();
propsConfig[propKey] = value.__getNativeTag();
}
}
return {
type: 'props',
props: propsConfig
};
};
return AnimatedProps;
}(AnimatedNode);
export default AnimatedProps;

View File

@ -0,0 +1,159 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
import AnimatedNode from './AnimatedNode';
import AnimatedTransform from './AnimatedTransform';
import AnimatedWithChildren from './AnimatedWithChildren';
import NativeAnimatedHelper from '../NativeAnimatedHelper';
import StyleSheet from '../../../../exports/StyleSheet';
var flattenStyle = StyleSheet.flatten;
var AnimatedStyle =
/*#__PURE__*/
function (_AnimatedWithChildren) {
_inheritsLoose(AnimatedStyle, _AnimatedWithChildren);
function AnimatedStyle(style) {
var _this;
_this = _AnimatedWithChildren.call(this) || this;
style = flattenStyle(style) || {};
if (style.transform) {
style = _objectSpread({}, style, {
transform: new AnimatedTransform(style.transform)
});
}
_this._style = style;
return _this;
} // Recursively get values for nested styles (like iOS's shadowOffset)
var _proto = AnimatedStyle.prototype;
_proto._walkStyleAndGetValues = function _walkStyleAndGetValues(style) {
var updatedStyle = {};
for (var key in style) {
var 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;
};
_proto.__getValue = function __getValue() {
return this._walkStyleAndGetValues(this._style);
} // Recursively get animated values for nested styles (like iOS's shadowOffset)
;
_proto._walkStyleAndGetAnimatedValues = function _walkStyleAndGetAnimatedValues(style) {
var updatedStyle = {};
for (var key in style) {
var 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;
};
_proto.__getAnimatedValue = function __getAnimatedValue() {
return this._walkStyleAndGetAnimatedValues(this._style);
};
_proto.__attach = function __attach() {
for (var key in this._style) {
var value = this._style[key];
if (value instanceof AnimatedNode) {
value.__addChild(this);
}
}
};
_proto.__detach = function __detach() {
for (var key in this._style) {
var value = this._style[key];
if (value instanceof AnimatedNode) {
value.__removeChild(this);
}
}
_AnimatedWithChildren.prototype.__detach.call(this);
};
_proto.__makeNative = function __makeNative() {
for (var key in this._style) {
var value = this._style[key];
if (value instanceof AnimatedNode) {
value.__makeNative();
}
}
_AnimatedWithChildren.prototype.__makeNative.call(this);
};
_proto.__getNativeConfig = function __getNativeConfig() {
var styleConfig = {};
for (var styleKey in this._style) {
if (this._style[styleKey] instanceof AnimatedNode) {
var style = this._style[styleKey];
style.__makeNative();
styleConfig[styleKey] = style.__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
};
};
return AnimatedStyle;
}(AnimatedWithChildren);
export default AnimatedStyle;

View File

@ -0,0 +1,75 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
import AnimatedInterpolation from './AnimatedInterpolation';
import AnimatedNode from './AnimatedNode';
import AnimatedValue from './AnimatedValue';
import AnimatedWithChildren from './AnimatedWithChildren';
var AnimatedSubtraction =
/*#__PURE__*/
function (_AnimatedWithChildren) {
_inheritsLoose(AnimatedSubtraction, _AnimatedWithChildren);
function AnimatedSubtraction(a, b) {
var _this;
_this = _AnimatedWithChildren.call(this) || this;
_this._a = typeof a === 'number' ? new AnimatedValue(a) : a;
_this._b = typeof b === 'number' ? new AnimatedValue(b) : b;
return _this;
}
var _proto = AnimatedSubtraction.prototype;
_proto.__makeNative = function __makeNative() {
this._a.__makeNative();
this._b.__makeNative();
_AnimatedWithChildren.prototype.__makeNative.call(this);
};
_proto.__getValue = function __getValue() {
return this._a.__getValue() - this._b.__getValue();
};
_proto.interpolate = function interpolate(config) {
return new AnimatedInterpolation(this, config);
};
_proto.__attach = function __attach() {
this._a.__addChild(this);
this._b.__addChild(this);
};
_proto.__detach = function __detach() {
this._a.__removeChild(this);
this._b.__removeChild(this);
_AnimatedWithChildren.prototype.__detach.call(this);
};
_proto.__getNativeConfig = function __getNativeConfig() {
return {
type: 'subtraction',
input: [this._a.__getNativeTag(), this._b.__getNativeTag()]
};
};
return AnimatedSubtraction;
}(AnimatedWithChildren);
export default AnimatedSubtraction;

View File

@ -0,0 +1,106 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
import AnimatedValue from './AnimatedValue';
import AnimatedNode from './AnimatedNode';
import { generateNewAnimationId, shouldUseNativeDriver } from '../NativeAnimatedHelper';
var AnimatedTracking =
/*#__PURE__*/
function (_AnimatedNode) {
_inheritsLoose(AnimatedTracking, _AnimatedNode);
function AnimatedTracking(value, parent, animationClass, animationConfig, callback) {
var _this;
_this = _AnimatedNode.call(this) || this;
_this._value = value;
_this._parent = parent;
_this._animationClass = animationClass;
_this._animationConfig = animationConfig;
_this._useNativeDriver = shouldUseNativeDriver(animationConfig);
_this._callback = callback;
_this.__attach();
return _this;
}
var _proto = AnimatedTracking.prototype;
_proto.__makeNative = function __makeNative() {
this.__isNative = true;
this._parent.__makeNative();
_AnimatedNode.prototype.__makeNative.call(this);
this._value.__makeNative();
};
_proto.__getValue = function __getValue() {
return this._parent.__getValue();
};
_proto.__attach = function __attach() {
this._parent.__addChild(this);
if (this._useNativeDriver) {
// when the tracking starts we need to convert this node to a "native node"
// so that the parent node will be made "native" too. This is necessary as
// if we don't do this `update` method will get called. At that point it
// may be too late as it would mean the JS driver has already started
// updating node values
this.__makeNative();
}
};
_proto.__detach = function __detach() {
this._parent.__removeChild(this);
_AnimatedNode.prototype.__detach.call(this);
};
_proto.update = function update() {
this._value.animate(new this._animationClass(_objectSpread({}, this._animationConfig, {
toValue: this._animationConfig.toValue.__getValue()
})), this._callback);
};
_proto.__getNativeConfig = function __getNativeConfig() {
var animation = new this._animationClass(_objectSpread({}, this._animationConfig, {
// remove toValue from the config as it's a ref to Animated.Value
toValue: undefined
}));
var animationConfig = animation.__getNativeAnimationConfig();
return {
type: 'tracking',
animationId: generateNewAnimationId(),
animationConfig: animationConfig,
toValue: this._parent.__getNativeTag(),
value: this._value.__getNativeTag()
};
};
return AnimatedTracking;
}(AnimatedNode);
export default AnimatedTracking;

View File

@ -0,0 +1,147 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
import AnimatedNode from './AnimatedNode';
import AnimatedWithChildren from './AnimatedWithChildren';
import NativeAnimatedHelper from '../NativeAnimatedHelper';
var AnimatedTransform =
/*#__PURE__*/
function (_AnimatedWithChildren) {
_inheritsLoose(AnimatedTransform, _AnimatedWithChildren);
function AnimatedTransform(transforms) {
var _this;
_this = _AnimatedWithChildren.call(this) || this;
_this._transforms = transforms;
return _this;
}
var _proto = AnimatedTransform.prototype;
_proto.__makeNative = function __makeNative() {
_AnimatedWithChildren.prototype.__makeNative.call(this);
this._transforms.forEach(function (transform) {
for (var key in transform) {
var value = transform[key];
if (value instanceof AnimatedNode) {
value.__makeNative();
}
}
});
};
_proto.__getValue = function __getValue() {
return this._transforms.map(function (transform) {
var result = {};
for (var key in transform) {
var value = transform[key];
if (value instanceof AnimatedNode) {
result[key] = value.__getValue();
} else {
result[key] = value;
}
}
return result;
});
};
_proto.__getAnimatedValue = function __getAnimatedValue() {
return this._transforms.map(function (transform) {
var result = {};
for (var key in transform) {
var value = transform[key];
if (value instanceof AnimatedNode) {
result[key] = value.__getAnimatedValue();
} else {
// All transform components needed to recompose matrix
result[key] = value;
}
}
return result;
});
};
_proto.__attach = function __attach() {
var _this2 = this;
this._transforms.forEach(function (transform) {
for (var key in transform) {
var value = transform[key];
if (value instanceof AnimatedNode) {
value.__addChild(_this2);
}
}
});
};
_proto.__detach = function __detach() {
var _this3 = this;
this._transforms.forEach(function (transform) {
for (var key in transform) {
var value = transform[key];
if (value instanceof AnimatedNode) {
value.__removeChild(_this3);
}
}
});
_AnimatedWithChildren.prototype.__detach.call(this);
};
_proto.__getNativeConfig = function __getNativeConfig() {
var transConfigs = [];
this._transforms.forEach(function (transform) {
for (var key in transform) {
var value = transform[key];
if (value instanceof AnimatedNode) {
transConfigs.push({
type: 'animated',
property: key,
nodeTag: value.__getNativeTag()
});
} else {
transConfigs.push({
type: 'static',
property: key,
value: value
});
}
}
});
NativeAnimatedHelper.validateTransform(transConfigs);
return {
type: 'transform',
transforms: transConfigs
};
};
return AnimatedTransform;
}(AnimatedWithChildren);
export default AnimatedTransform;

View File

@ -0,0 +1,287 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
import AnimatedInterpolation from './AnimatedInterpolation';
import AnimatedWithChildren from './AnimatedWithChildren';
import InteractionManager from '../../../../exports/InteractionManager';
import NativeAnimatedHelper from '../NativeAnimatedHelper';
var NativeAnimatedAPI = NativeAnimatedHelper.API;
/**
* 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) {
var animatedStyles = new Set();
function findAnimatedStyles(node) {
/* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an
* error found when Flow v0.68 was deployed. To see the error delete this
* comment and run Flow. */
if (typeof node.update === 'function') {
animatedStyles.add(node);
} else {
node.__getChildren().forEach(findAnimatedStyles);
}
}
findAnimatedStyles(rootNode);
/* $FlowFixMe */
animatedStyles.forEach(function (animatedStyle) {
return 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
*/
var AnimatedValue =
/*#__PURE__*/
function (_AnimatedWithChildren) {
_inheritsLoose(AnimatedValue, _AnimatedWithChildren);
function AnimatedValue(value) {
var _this;
_this = _AnimatedWithChildren.call(this) || this;
_this._startingValue = _this._value = value;
_this._offset = 0;
_this._animation = null;
return _this;
}
var _proto = AnimatedValue.prototype;
_proto.__detach = function __detach() {
this.stopAnimation();
_AnimatedWithChildren.prototype.__detach.call(this);
};
_proto.__getValue = function __getValue() {
return this._value + this._offset;
}
/**
* 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
*/
;
_proto.setValue = function setValue(value) {
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
*/
;
_proto.setOffset = function setOffset(offset) {
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
*/
;
_proto.flattenOffset = function flattenOffset() {
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
*/
;
_proto.extractOffset = function extractOffset() {
this._offset += this._value;
this._value = 0;
if (this.__isNative) {
NativeAnimatedAPI.extractAnimatedNodeOffset(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
*/
;
_proto.stopAnimation = function stopAnimation(callback) {
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
*/
;
_proto.resetAnimation = function resetAnimation(callback) {
this.stopAnimation(callback);
this._value = this._startingValue;
};
_proto._onAnimatedValueUpdateReceived = function _onAnimatedValueUpdateReceived(value) {
this._updateValue(value, false
/*flush*/
);
}
/**
* Interpolates the value before updating the property, e.g. mapping 0-1 to
* 0-10.
*/
;
_proto.interpolate = function interpolate(config) {
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
*/
;
_proto.animate = function animate(animation, callback) {
var _this2 = this;
var handle = null;
if (animation.__isInteraction) {
handle = InteractionManager.createInteractionHandle();
}
var previousAnimation = this._animation;
this._animation && this._animation.stop();
this._animation = animation;
animation.start(this._value, function (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
_this2._updateValue(value, true
/* flush */
);
}, function (result) {
_this2._animation = null;
if (handle !== null) {
InteractionManager.clearInteractionHandle(handle);
}
callback && callback(result);
}, previousAnimation, this);
}
/**
* Typically only used internally.
*/
;
_proto.stopTracking = function stopTracking() {
this._tracking && this._tracking.__detach();
this._tracking = null;
}
/**
* Typically only used internally.
*/
;
_proto.track = function track(tracking) {
this.stopTracking();
this._tracking = tracking;
};
_proto._updateValue = function _updateValue(value, flush) {
this._value = value;
if (flush) {
_flush(this);
}
_AnimatedWithChildren.prototype.__callListeners.call(this, this.__getValue());
};
_proto.__getNativeConfig = function __getNativeConfig() {
return {
type: 'value',
value: this._value,
offset: this._offset
};
};
return AnimatedValue;
}(AnimatedWithChildren);
export default AnimatedValue;

View File

@ -0,0 +1,220 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
import AnimatedValue from './AnimatedValue';
import AnimatedWithChildren from './AnimatedWithChildren';
import invariant from 'fbjs/lib/invariant';
var _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
*/
var AnimatedValueXY =
/*#__PURE__*/
function (_AnimatedWithChildren) {
_inheritsLoose(AnimatedValueXY, _AnimatedWithChildren);
// $FlowFixMe
function AnimatedValueXY(valueIn) {
var _this;
_this = _AnimatedWithChildren.call(this) || this;
var value = valueIn || {
x: 0,
y: 0
}; // fixme: 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 initialized with an object of numbers or ' + 'AnimatedValues.');
_this.x = value.x;
_this.y = value.y;
}
_this._listeners = {};
return _this;
}
/**
* 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
*/
var _proto = AnimatedValueXY.prototype;
_proto.setValue = function setValue(value) {
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
*/
;
_proto.setOffset = function setOffset(offset) {
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
*/
;
_proto.flattenOffset = function flattenOffset() {
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
*/
;
_proto.extractOffset = function extractOffset() {
this.x.extractOffset();
this.y.extractOffset();
};
_proto.__getValue = function __getValue() {
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
*/
;
_proto.resetAnimation = function resetAnimation(callback) {
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
*/
;
_proto.stopAnimation = function stopAnimation(callback) {
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
*/
// $FlowFixMe
;
_proto.addListener = function addListener(callback) {
var _this2 = this;
var id = String(_uniqueId++);
var jointCallback = function jointCallback(_ref) {
var number = _ref.value;
callback(_this2.__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
*/
;
_proto.removeListener = function removeListener(id) {
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
*/
;
_proto.removeAllListeners = function removeAllListeners() {
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
*/
;
_proto.getLayout = function getLayout() {
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
*/
;
_proto.getTranslateTransform = function getTranslateTransform() {
return [{
translateX: this.x
}, {
translateY: this.y
}];
};
return AnimatedValueXY;
}(AnimatedWithChildren);
export default AnimatedValueXY;

View File

@ -0,0 +1,125 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
import AnimatedNode from './AnimatedNode';
import NativeAnimatedHelper from '../NativeAnimatedHelper';
var AnimatedWithChildren =
/*#__PURE__*/
function (_AnimatedNode) {
_inheritsLoose(AnimatedWithChildren, _AnimatedNode);
function AnimatedWithChildren() {
var _this;
_this = _AnimatedNode.call(this) || this;
_this._children = [];
return _this;
}
var _proto = AnimatedWithChildren.prototype;
_proto.__makeNative = function __makeNative() {
if (!this.__isNative) {
this.__isNative = true;
for (var _iterator = this._children, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
var _ref;
if (_isArray) {
if (_i >= _iterator.length) break;
_ref = _iterator[_i++];
} else {
_i = _iterator.next();
if (_i.done) break;
_ref = _i.value;
}
var child = _ref;
child.__makeNative();
NativeAnimatedHelper.API.connectAnimatedNodes(this.__getNativeTag(), child.__getNativeTag());
}
}
_AnimatedNode.prototype.__makeNative.call(this);
};
_proto.__addChild = function __addChild(child) {
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());
}
};
_proto.__removeChild = function __removeChild(child) {
var 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();
}
};
_proto.__getChildren = function __getChildren() {
return this._children;
};
_proto.__callListeners = function __callListeners(value) {
_AnimatedNode.prototype.__callListeners.call(this, value);
if (!this.__isNative) {
for (var _iterator2 = this._children, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) {
var _ref2;
if (_isArray2) {
if (_i2 >= _iterator2.length) break;
_ref2 = _iterator2[_i2++];
} else {
_i2 = _iterator2.next();
if (_i2.done) break;
_ref2 = _i2.value;
}
var child = _ref2;
if (child.__getValue) {
child.__callListeners(child.__getValue());
}
}
}
};
return AnimatedWithChildren;
}(AnimatedNode);
export default AnimatedWithChildren;

View File

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

View File

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

View File

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

View File

@ -0,0 +1,97 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*
*/
'use strict';
import InteractionManager from '../../../exports/InteractionManager';
/**
* A simple class for batching up invocations of a low-pri callback. A timeout is set to run the
* callback once after a delay, no matter how many times it's scheduled. Once the delay is reached,
* InteractionManager.runAfterInteractions is used to invoke the callback after any hi-pri
* interactions are done running.
*
* Make sure to cleanup with dispose(). Example:
*
* class Widget extends React.Component {
* _batchedSave: new Batchinator(() => this._saveState, 1000);
* _saveSate() {
* // save this.state to disk
* }
* componentDidUpdate() {
* this._batchedSave.schedule();
* }
* componentWillUnmount() {
* this._batchedSave.dispose();
* }
* ...
* }
*/
var Batchinator =
/*#__PURE__*/
function () {
function Batchinator(callback, delayMS) {
this._delay = delayMS;
this._callback = callback;
}
/*
* Cleanup any pending tasks.
*
* By default, if there is a pending task the callback is run immediately. Set the option abort to
* true to not call the callback if it was pending.
*/
var _proto = Batchinator.prototype;
_proto.dispose = function dispose(options) {
if (options === void 0) {
options = {
abort: false
};
}
if (this._taskHandle) {
this._taskHandle.cancel();
if (!options.abort) {
this._callback();
}
this._taskHandle = null;
}
};
_proto.schedule = function schedule() {
var _this = this;
if (this._taskHandle) {
return;
}
var timeoutHandle = setTimeout(function () {
_this._taskHandle = InteractionManager.runAfterInteractions(function () {
// Note that we clear the handle before invoking the callback so that if the callback calls
// schedule again, it will actually schedule another task.
_this._taskHandle = null;
_this._callback();
});
}, this._delay);
this._taskHandle = {
cancel: function cancel() {
return clearTimeout(timeoutHandle);
}
};
};
return Batchinator;
}();
export default Batchinator;

View File

@ -0,0 +1,245 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import performanceNow from 'fbjs/lib/performanceNow';
import warning from 'fbjs/lib/warning';
var Info = function Info() {
this.any_blank_count = 0;
this.any_blank_ms = 0;
this.any_blank_speed_sum = 0;
this.mostly_blank_count = 0;
this.mostly_blank_ms = 0;
this.pixels_blank = 0;
this.pixels_sampled = 0;
this.pixels_scrolled = 0;
this.total_time_spent = 0;
this.sample_count = 0;
};
var DEBUG = false;
var _listeners = [];
var _minSampleCount = 10;
var _sampleRate = DEBUG ? 1 : null;
/**
* A helper class for detecting when the maximem fill rate of `VirtualizedList` is exceeded.
* By default the sampling rate is set to zero and this will do nothing. If you want to collect
* samples (e.g. to log them), make sure to call `FillRateHelper.setSampleRate(0.0-1.0)`.
*
* Listeners and sample rate are global for all `VirtualizedList`s - typical usage will combine with
* `SceneTracker.getActiveScene` to determine the context of the events.
*/
var FillRateHelper =
/*#__PURE__*/
function () {
FillRateHelper.addListener = function addListener(callback) {
warning(_sampleRate !== null, 'Call `FillRateHelper.setSampleRate` before `addListener`.');
_listeners.push(callback);
return {
remove: function remove() {
_listeners = _listeners.filter(function (listener) {
return callback !== listener;
});
}
};
};
FillRateHelper.setSampleRate = function setSampleRate(sampleRate) {
_sampleRate = sampleRate;
};
FillRateHelper.setMinSampleCount = function setMinSampleCount(minSampleCount) {
_minSampleCount = minSampleCount;
};
function FillRateHelper(getFrameMetrics) {
this._anyBlankStartTime = null;
this._enabled = false;
this._info = new Info();
this._mostlyBlankStartTime = null;
this._samplesStartTime = null;
this._getFrameMetrics = getFrameMetrics;
this._enabled = (_sampleRate || 0) > Math.random();
this._resetData();
}
var _proto = FillRateHelper.prototype;
_proto.activate = function activate() {
if (this._enabled && this._samplesStartTime == null) {
DEBUG && console.debug('FillRateHelper: activate');
this._samplesStartTime = performanceNow();
}
};
_proto.deactivateAndFlush = function deactivateAndFlush() {
if (!this._enabled) {
return;
}
var start = this._samplesStartTime; // const for flow
if (start == null) {
DEBUG && console.debug('FillRateHelper: bail on deactivate with no start time');
return;
}
if (this._info.sample_count < _minSampleCount) {
// Don't bother with under-sampled events.
this._resetData();
return;
}
var total_time_spent = performanceNow() - start;
var info = _objectSpread({}, this._info, {
total_time_spent: total_time_spent
});
if (DEBUG) {
var derived = {
avg_blankness: this._info.pixels_blank / this._info.pixels_sampled,
avg_speed: this._info.pixels_scrolled / (total_time_spent / 1000),
avg_speed_when_any_blank: this._info.any_blank_speed_sum / this._info.any_blank_count,
any_blank_per_min: this._info.any_blank_count / (total_time_spent / 1000 / 60),
any_blank_time_frac: this._info.any_blank_ms / total_time_spent,
mostly_blank_per_min: this._info.mostly_blank_count / (total_time_spent / 1000 / 60),
mostly_blank_time_frac: this._info.mostly_blank_ms / total_time_spent
};
for (var key in derived) {
derived[key] = Math.round(1000 * derived[key]) / 1000;
}
console.debug('FillRateHelper deactivateAndFlush: ', {
derived: derived,
info: info
});
}
_listeners.forEach(function (listener) {
return listener(info);
});
this._resetData();
};
_proto.computeBlankness = function computeBlankness(props, state, scrollMetrics) {
if (!this._enabled || props.getItemCount(props.data) === 0 || this._samplesStartTime == null) {
return 0;
}
var dOffset = scrollMetrics.dOffset,
offset = scrollMetrics.offset,
velocity = scrollMetrics.velocity,
visibleLength = scrollMetrics.visibleLength; // Denominator metrics that we track for all events - most of the time there is no blankness and
// we want to capture that.
this._info.sample_count++;
this._info.pixels_sampled += Math.round(visibleLength);
this._info.pixels_scrolled += Math.round(Math.abs(dOffset));
var scrollSpeed = Math.round(Math.abs(velocity) * 1000); // px / sec
// Whether blank now or not, record the elapsed time blank if we were blank last time.
var now = performanceNow();
if (this._anyBlankStartTime != null) {
this._info.any_blank_ms += now - this._anyBlankStartTime;
}
this._anyBlankStartTime = null;
if (this._mostlyBlankStartTime != null) {
this._info.mostly_blank_ms += now - this._mostlyBlankStartTime;
}
this._mostlyBlankStartTime = null;
var blankTop = 0;
var first = state.first;
var firstFrame = this._getFrameMetrics(first);
while (first <= state.last && (!firstFrame || !firstFrame.inLayout)) {
firstFrame = this._getFrameMetrics(first);
first++;
} // Only count blankTop if we aren't rendering the first item, otherwise we will count the header
// as blank.
if (firstFrame && first > 0) {
blankTop = Math.min(visibleLength, Math.max(0, firstFrame.offset - offset));
}
var blankBottom = 0;
var last = state.last;
var lastFrame = this._getFrameMetrics(last);
while (last >= state.first && (!lastFrame || !lastFrame.inLayout)) {
lastFrame = this._getFrameMetrics(last);
last--;
} // Only count blankBottom if we aren't rendering the last item, otherwise we will count the
// footer as blank.
if (lastFrame && last < props.getItemCount(props.data) - 1) {
var bottomEdge = lastFrame.offset + lastFrame.length;
blankBottom = Math.min(visibleLength, Math.max(0, offset + visibleLength - bottomEdge));
}
var pixels_blank = Math.round(blankTop + blankBottom);
var blankness = pixels_blank / visibleLength;
if (blankness > 0) {
this._anyBlankStartTime = now;
this._info.any_blank_speed_sum += scrollSpeed;
this._info.any_blank_count++;
this._info.pixels_blank += pixels_blank;
if (blankness > 0.5) {
this._mostlyBlankStartTime = now;
this._info.mostly_blank_count++;
}
} else if (scrollSpeed < 0.01 || Math.abs(dOffset) < 1) {
this.deactivateAndFlush();
}
return blankness;
};
_proto.enabled = function enabled() {
return this._enabled;
};
_proto._resetData = function _resetData() {
this._anyBlankStartTime = null;
this._info = new Info();
this._mostlyBlankStartTime = null;
this._samplesStartTime = null;
};
return FillRateHelper;
}();
export default FillRateHelper;

View File

@ -0,0 +1,451 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import deepDiffer from '../deepDiffer';
import * as React from 'react';
import StyleSheet from '../../../exports/StyleSheet';
import View from '../../../exports/View';
import VirtualizedList from '../VirtualizedList';
import invariant from 'fbjs/lib/invariant';
var defaultProps = _objectSpread({}, VirtualizedList.defaultProps, {
numColumns: 1,
/**
* Enabling this prop on Android greatly improves scrolling performance with no known issues.
* The alternative is that scrolling on Android is unusably bad. Enabling it on iOS has a few
* known issues.
*/
removeClippedSubviews: false
});
/**
* A performant interface for rendering simple, flat lists, supporting the most handy features:
*
* - Fully cross-platform.
* - Optional horizontal mode.
* - Configurable viewability callbacks.
* - Header support.
* - Footer support.
* - Separator support.
* - Pull to Refresh.
* - Scroll loading.
* - ScrollToIndex support.
*
* If you need section support, use [`<SectionList>`](docs/sectionlist.html).
*
* Minimal Example:
*
* <FlatList
* data={[{key: 'a'}, {key: 'b'}]}
* renderItem={({item}) => <Text>{item.key}</Text>}
* />
*
* More complex, multi-select example demonstrating `PureComponent` usage for perf optimization and avoiding bugs.
*
* - By binding the `onPressItem` handler, the props will remain `===` and `PureComponent` will
* prevent wasteful re-renders unless the actual `id`, `selected`, or `title` props change, even
* if the components rendered in `MyListItem` did not have such optimizations.
* - By passing `extraData={this.state}` to `FlatList` we make sure `FlatList` itself will re-render
* when the `state.selected` changes. Without setting this prop, `FlatList` would not know it
* needs to re-render any items because it is also a `PureComponent` and the prop comparison will
* not show any changes.
* - `keyExtractor` tells the list to use the `id`s for the react keys instead of the default `key` property.
*
*
* class MyListItem extends React.PureComponent {
* _onPress = () => {
* this.props.onPressItem(this.props.id);
* };
*
* render() {
* const textColor = this.props.selected ? "red" : "black";
* return (
* <TouchableOpacity onPress={this._onPress}>
* <View>
* <Text style={{ color: textColor }}>
* {this.props.title}
* </Text>
* </View>
* </TouchableOpacity>
* );
* }
* }
*
* class MultiSelectList extends React.PureComponent {
* state = {selected: (new Map(): Map<string, boolean>)};
*
* _keyExtractor = (item, index) => item.id;
*
* _onPressItem = (id: string) => {
* // updater functions are preferred for transactional updates
* this.setState((state) => {
* // copy the map rather than modifying state.
* const selected = new Map(state.selected);
* selected.set(id, !selected.get(id)); // toggle
* return {selected};
* });
* };
*
* _renderItem = ({item}) => (
* <MyListItem
* id={item.id}
* onPressItem={this._onPressItem}
* selected={!!this.state.selected.get(item.id)}
* title={item.title}
* />
* );
*
* render() {
* return (
* <FlatList
* data={this.props.data}
* extraData={this.state}
* keyExtractor={this._keyExtractor}
* renderItem={this._renderItem}
* />
* );
* }
* }
*
* This is a convenience wrapper around [`<VirtualizedList>`](docs/virtualizedlist.html),
* and thus inherits its props (as well as those of `ScrollView`) that aren't explicitly listed
* here, along with the following caveats:
*
* - Internal state is not preserved when content scrolls out of the render window. Make sure all
* your data is captured in the item data or external stores like Flux, Redux, or Relay.
* - This is a `PureComponent` which means that it will not re-render if `props` remain shallow-
* equal. Make sure that everything your `renderItem` function depends on is passed as a prop
* (e.g. `extraData`) that is not `===` after updates, otherwise your UI may not update on
* changes. This includes the `data` prop and parent component state.
* - In order to constrain memory and enable smooth scrolling, content is rendered asynchronously
* offscreen. This means it's possible to scroll faster than the fill rate ands momentarily see
* blank content. This is a tradeoff that can be adjusted to suit the needs of each application,
* and we are working on improving it behind the scenes.
* - By default, the list looks for a `key` prop on each item and uses that for the React key.
* Alternatively, you can provide a custom `keyExtractor` prop.
*
* Also inherits [ScrollView Props](docs/scrollview.html#props), unless it is nested in another FlatList of same orientation.
*/
var FlatList =
/*#__PURE__*/
function (_React$PureComponent) {
_inheritsLoose(FlatList, _React$PureComponent);
var _proto = FlatList.prototype;
/**
* Scrolls to the end of the content. May be janky without `getItemLayout` prop.
*/
_proto.scrollToEnd = function scrollToEnd(params) {
if (this._listRef) {
this._listRef.scrollToEnd(params);
}
}
/**
* Scrolls to the item at the specified index such that it is positioned in the viewable area
* such that `viewPosition` 0 places it at the top, 1 at the bottom, and 0.5 centered in the
* middle. `viewOffset` is a fixed number of pixels to offset the final target position.
*
* Note: cannot scroll to locations outside the render window without specifying the
* `getItemLayout` prop.
*/
;
_proto.scrollToIndex = function scrollToIndex(params) {
if (this._listRef) {
this._listRef.scrollToIndex(params);
}
}
/**
* Requires linear scan through data - use `scrollToIndex` instead if possible.
*
* Note: cannot scroll to locations outside the render window without specifying the
* `getItemLayout` prop.
*/
;
_proto.scrollToItem = function scrollToItem(params) {
if (this._listRef) {
this._listRef.scrollToItem(params);
}
}
/**
* Scroll to a specific content pixel offset in the list.
*
* Check out [scrollToOffset](docs/virtualizedlist.html#scrolltooffset) of VirtualizedList
*/
;
_proto.scrollToOffset = function scrollToOffset(params) {
if (this._listRef) {
this._listRef.scrollToOffset(params);
}
}
/**
* Tells the list an interaction has occurred, which should trigger viewability calculations, e.g.
* if `waitForInteractions` is true and the user has not scrolled. This is typically called by
* taps on items or by navigation actions.
*/
;
_proto.recordInteraction = function recordInteraction() {
if (this._listRef) {
this._listRef.recordInteraction();
}
}
/**
* Displays the scroll indicators momentarily.
*
* @platform ios
*/
;
_proto.flashScrollIndicators = function flashScrollIndicators() {
if (this._listRef) {
this._listRef.flashScrollIndicators();
}
}
/**
* Provides a handle to the underlying scroll responder.
*/
;
_proto.getScrollResponder = function getScrollResponder() {
if (this._listRef) {
return this._listRef.getScrollResponder();
}
}
/**
* Provides a reference to the underlying host component
*/
;
_proto.getNativeScrollRef = function getNativeScrollRef() {
if (this._listRef) {
return this._listRef.getScrollRef();
}
};
_proto.getScrollableNode = function getScrollableNode() {
if (this._listRef) {
return this._listRef.getScrollableNode();
}
};
_proto.setNativeProps = function setNativeProps(props) {
if (this._listRef) {
this._listRef.setNativeProps(props);
}
};
function FlatList(props) {
var _this;
_this = _React$PureComponent.call(this, props) || this;
_this._virtualizedListPairs = [];
_this._captureRef = function (ref) {
_this._listRef = ref;
};
_this._getItem = function (data, index) {
var numColumns = _this.props.numColumns;
if (numColumns > 1) {
var ret = [];
for (var kk = 0; kk < numColumns; kk++) {
var _item = data[index * numColumns + kk];
if (_item != null) {
ret.push(_item);
}
}
return ret;
} else {
return data[index];
}
};
_this._getItemCount = function (data) {
return data ? Math.ceil(data.length / _this.props.numColumns) : 0;
};
_this._keyExtractor = function (items, index) {
var _this$props = _this.props,
keyExtractor = _this$props.keyExtractor,
numColumns = _this$props.numColumns;
if (numColumns > 1) {
invariant(Array.isArray(items), 'FlatList: Encountered internal consistency error, expected each item to consist of an ' + 'array with 1-%s columns; instead, received a single item.', numColumns);
return items.map(function (it, kk) {
return keyExtractor(it, index * numColumns + kk);
}).join(':');
} else {
/* $FlowFixMe(>=0.63.0 site=react_native_fb) This comment suppresses an
* error found when Flow v0.63 was deployed. To see the error delete this
* comment and run Flow. */
return keyExtractor(items, index);
}
};
_this._renderItem = function (info) {
var _this$props2 = _this.props,
renderItem = _this$props2.renderItem,
numColumns = _this$props2.numColumns,
columnWrapperStyle = _this$props2.columnWrapperStyle;
if (numColumns > 1) {
var _item2 = info.item,
_index = info.index;
invariant(Array.isArray(_item2), 'Expected array of items with numColumns > 1');
return React.createElement(View, {
style: StyleSheet.compose(styles.row, columnWrapperStyle)
}, _item2.map(function (it, kk) {
var element = renderItem({
item: it,
index: _index * numColumns + kk,
separators: info.separators
});
return element != null ? React.createElement(React.Fragment, {
key: kk
}, element) : null;
}));
} else {
return renderItem(info);
}
};
_this._checkProps(_this.props);
if (_this.props.viewabilityConfigCallbackPairs) {
_this._virtualizedListPairs = _this.props.viewabilityConfigCallbackPairs.map(function (pair) {
return {
viewabilityConfig: pair.viewabilityConfig,
onViewableItemsChanged: _this._createOnViewableItemsChanged(pair.onViewableItemsChanged)
};
});
} else if (_this.props.onViewableItemsChanged) {
/* $FlowFixMe(>=0.63.0 site=react_native_fb) This comment suppresses an
* error found when Flow v0.63 was deployed. To see the error delete this
* comment and run Flow. */
_this._virtualizedListPairs.push({
viewabilityConfig: _this.props.viewabilityConfig,
onViewableItemsChanged: _this._createOnViewableItemsChanged(_this.props.onViewableItemsChanged)
});
}
return _this;
}
_proto.componentDidUpdate = function componentDidUpdate(prevProps) {
invariant(prevProps.numColumns === this.props.numColumns, 'Changing numColumns on the fly is not supported. Change the key prop on FlatList when ' + 'changing the number of columns to force a fresh render of the component.');
invariant(prevProps.onViewableItemsChanged === this.props.onViewableItemsChanged, 'Changing onViewableItemsChanged on the fly is not supported');
invariant(!deepDiffer(prevProps.viewabilityConfig, this.props.viewabilityConfig), 'Changing viewabilityConfig on the fly is not supported');
invariant(prevProps.viewabilityConfigCallbackPairs === this.props.viewabilityConfigCallbackPairs, 'Changing viewabilityConfigCallbackPairs on the fly is not supported');
this._checkProps(this.props);
};
_proto._checkProps = function _checkProps(props) {
var getItem = props.getItem,
getItemCount = props.getItemCount,
horizontal = props.horizontal,
numColumns = props.numColumns,
columnWrapperStyle = props.columnWrapperStyle,
onViewableItemsChanged = props.onViewableItemsChanged,
viewabilityConfigCallbackPairs = props.viewabilityConfigCallbackPairs;
invariant(!getItem && !getItemCount, 'FlatList does not support custom data formats.');
if (numColumns > 1) {
invariant(!horizontal, 'numColumns does not support horizontal.');
} else {
invariant(!columnWrapperStyle, 'columnWrapperStyle not supported for single column lists');
}
invariant(!(onViewableItemsChanged && viewabilityConfigCallbackPairs), 'FlatList does not support setting both onViewableItemsChanged and ' + 'viewabilityConfigCallbackPairs.');
};
_proto._pushMultiColumnViewable = function _pushMultiColumnViewable(arr, v) {
var _this$props3 = this.props,
numColumns = _this$props3.numColumns,
keyExtractor = _this$props3.keyExtractor;
v.item.forEach(function (item, ii) {
invariant(v.index != null, 'Missing index!');
var index = v.index * numColumns + ii;
arr.push(_objectSpread({}, v, {
item: item,
key: keyExtractor(item, index),
index: index
}));
});
};
_proto._createOnViewableItemsChanged = function _createOnViewableItemsChanged(onViewableItemsChanged) {
var _this2 = this;
return function (info) {
var numColumns = _this2.props.numColumns;
if (onViewableItemsChanged) {
if (numColumns > 1) {
var changed = [];
var viewableItems = [];
info.viewableItems.forEach(function (v) {
return _this2._pushMultiColumnViewable(viewableItems, v);
});
info.changed.forEach(function (v) {
return _this2._pushMultiColumnViewable(changed, v);
});
onViewableItemsChanged({
viewableItems: viewableItems,
changed: changed
});
} else {
onViewableItemsChanged(info);
}
}
};
};
_proto.render = function render() {
return React.createElement(VirtualizedList, _extends({}, this.props, {
renderItem: this._renderItem,
getItem: this._getItem,
getItemCount: this._getItemCount,
keyExtractor: this._keyExtractor,
ref: this._captureRef,
viewabilityConfigCallbackPairs: this._virtualizedListPairs
}));
};
return FlatList;
}(React.PureComponent);
FlatList.defaultProps = defaultProps;
var styles = StyleSheet.create({
row: {
flexDirection: 'row'
}
});
export default FlatList;

View File

@ -0,0 +1,93 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*
*/
'use strict';
import infoLog from '../infoLog';
import performanceNow from 'fbjs/lib/performanceNow';
/**
* A utility for tracking stalls in the JS event loop that prevent timers and
* other events from being processed in a timely manner.
*
* The "stall" time is defined as the amount of time in access of the acceptable
* threshold, which is typically around 100-200ms. So if the treshold is set to
* 100 and a timer fires 150 ms later than it was scheduled because the event
* loop was tied up, that would be considered a 50ms stall.
*
* By default, logs stall events to the console when installed. Can also be
* queried with `getStats`.
*/
var JSEventLoopWatchdog = {
getStats: function getStats() {
return {
stallCount: stallCount,
totalStallTime: totalStallTime,
longestStall: longestStall,
acceptableBusyTime: acceptableBusyTime
};
},
reset: function reset() {
infoLog('JSEventLoopWatchdog: reset');
totalStallTime = 0;
stallCount = 0;
longestStall = 0;
lastInterval = performanceNow();
},
addHandler: function addHandler(handler) {
handlers.push(handler);
},
install: function install(_ref) {
var thresholdMS = _ref.thresholdMS;
acceptableBusyTime = thresholdMS;
if (installed) {
return;
}
installed = true;
lastInterval = performanceNow();
function iteration() {
var now = performanceNow();
var busyTime = now - lastInterval;
if (busyTime >= thresholdMS) {
var stallTime = busyTime - thresholdMS;
stallCount++;
totalStallTime += stallTime;
longestStall = Math.max(longestStall, stallTime);
var msg = "JSEventLoopWatchdog: JS thread busy for " + busyTime + "ms. " + (totalStallTime + "ms in " + stallCount + " stalls so far. ");
handlers.forEach(function (handler) {
msg += handler.onStall({
lastInterval: lastInterval,
busyTime: busyTime
}) || '';
});
infoLog(msg);
}
handlers.forEach(function (handler) {
handler.onIterate && handler.onIterate();
});
lastInterval = now;
setTimeout(iteration, thresholdMS / 5);
}
iteration();
}
};
var acceptableBusyTime = 0;
var installed = false;
var totalStallTime = 0;
var stallCount = 0;
var longestStall = 0;
var lastInterval = 0;
var handlers = [];
export default JSEventLoopWatchdog;

View File

@ -0,0 +1,114 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
import Platform from '../../../exports/Platform';
import UIManager from '../../../exports/UIManager';
var __DEV__ = process.env.NODE_ENV !== 'production';
function configureNext(config, onAnimationDidEnd) {
if (!Platform.isTesting) {
UIManager.configureNextLayoutAnimation(config, onAnimationDidEnd !== null && onAnimationDidEnd !== void 0 ? onAnimationDidEnd : function () {}, function () {}
/* unused onError */
);
}
}
function create(duration, type, property) {
return {
duration: duration,
create: {
type: type,
property: property
},
update: {
type: type
},
delete: {
type: type,
property: property
}
};
}
var Presets = {
easeInEaseOut: create(300, 'easeInEaseOut', 'opacity'),
linear: create(500, 'linear', 'opacity'),
spring: {
duration: 700,
create: {
type: 'linear',
property: 'opacity'
},
update: {
type: 'spring',
springDamping: 0.4
},
delete: {
type: 'linear',
property: 'opacity'
}
}
};
/**
* Automatically animates views to their new positions when the
* next layout happens.
*
* A common way to use this API is to call it before calling `setState`.
*
* Note that in order to get this to work on **Android** you need to set the following flags via `UIManager`:
*
* UIManager.setLayoutAnimationEnabledExperimental && UIManager.setLayoutAnimationEnabledExperimental(true);
*/
var LayoutAnimation = {
/**
* Schedules an animation to happen on the next layout.
*
* @param config Specifies animation properties:
*
* - `duration` in milliseconds
* - `create`, `AnimationConfig` for animating in new views
* - `update`, `AnimationConfig` for animating views that have been updated
*
* @param onAnimationDidEnd Called when the animation finished.
* Only supported on iOS.
* @param onError Called on error. Only supported on iOS.
*/
configureNext: configureNext,
/**
* Helper for creating a config for `configureNext`.
*/
create: create,
Types: Object.freeze({
spring: 'spring',
linear: 'linear',
easeInEaseOut: 'easeInEaseOut',
easeIn: 'easeIn',
easeOut: 'easeOut',
keyboard: 'keyboard'
}),
Properties: Object.freeze({
opacity: 'opacity',
scaleX: 'scaleX',
scaleY: 'scaleY',
scaleXY: 'scaleXY'
}),
checkConfig: function checkConfig() {
console.error('LayoutAnimation.checkConfig(...) has been disabled.');
},
Presets: Presets,
easeInEaseOut: configureNext.bind(null, Presets.easeInEaseOut),
linear: configureNext.bind(null, Presets.linear),
spring: configureNext.bind(null, Presets.spring)
};
export default LayoutAnimation;

View File

@ -0,0 +1,83 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*
*/
'use strict';
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
import EventEmitter from '../emitter/EventEmitter';
import EventSubscriptionVendor from '../emitter/EventSubscriptionVendor';
var __DEV__ = process.env.NODE_ENV !== 'production';
function checkNativeEventModule(eventType) {
if (eventType) {
if (eventType.lastIndexOf('statusBar', 0) === 0) {
throw new Error('`' + eventType + '` event should be registered via the StatusBarIOS module');
}
if (eventType.lastIndexOf('keyboard', 0) === 0) {
throw new Error('`' + eventType + '` event should be registered via the Keyboard module');
}
if (eventType === 'appStateDidChange' || eventType === 'memoryWarning') {
throw new Error('`' + eventType + '` event should be registered via the AppState module');
}
}
}
/**
* Deprecated - subclass NativeEventEmitter to create granular event modules instead of
* adding all event listeners directly to RCTDeviceEventEmitter.
*/
var RCTDeviceEventEmitter =
/*#__PURE__*/
function (_EventEmitter) {
_inheritsLoose(RCTDeviceEventEmitter, _EventEmitter);
function RCTDeviceEventEmitter() {
var _this;
var sharedSubscriber = new EventSubscriptionVendor();
_this = _EventEmitter.call(this, sharedSubscriber) || this;
_this.sharedSubscriber = sharedSubscriber;
return _this;
}
var _proto = RCTDeviceEventEmitter.prototype;
_proto.addListener = function addListener(eventType, listener, context) {
if (__DEV__) {
checkNativeEventModule(eventType);
}
return _EventEmitter.prototype.addListener.call(this, eventType, listener, context);
};
_proto.removeAllListeners = function removeAllListeners(eventType) {
if (__DEV__) {
checkNativeEventModule(eventType);
}
_EventEmitter.prototype.removeAllListeners.call(this, eventType);
};
_proto.removeSubscription = function removeSubscription(subscription) {
if (subscription.emitter !== this) {
subscription.emitter.removeSubscription(subscription);
} else {
_EventEmitter.prototype.removeSubscription.call(this, subscription);
}
};
return RCTDeviceEventEmitter;
}(EventEmitter);
export default new RCTDeviceEventEmitter();

View File

@ -0,0 +1,63 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*
*/
'use strict';
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
import EventEmitter from '../emitter/EventEmitter';
import RCTDeviceEventEmitter from './RCTDeviceEventEmitter';
import invariant from 'fbjs/lib/invariant';
/**
* Abstract base class for implementing event-emitting modules. This implements
* a subset of the standard EventEmitter node module API.
*/
var NativeEventEmitter =
/*#__PURE__*/
function (_EventEmitter) {
_inheritsLoose(NativeEventEmitter, _EventEmitter);
function NativeEventEmitter(nativeModule) {
return _EventEmitter.call(this, RCTDeviceEventEmitter.sharedSubscriber) || this;
}
var _proto = NativeEventEmitter.prototype;
_proto.addListener = function addListener(eventType, listener, context) {
if (this._nativeModule != null) {
this._nativeModule.addListener(eventType);
}
return _EventEmitter.prototype.addListener.call(this, eventType, listener, context);
};
_proto.removeAllListeners = function removeAllListeners(eventType) {
invariant(eventType, 'eventType argument is required.');
var count = this.listeners(eventType).length;
if (this._nativeModule != null) {
this._nativeModule.removeListeners(count);
}
_EventEmitter.prototype.removeAllListeners.call(this, eventType);
};
_proto.removeSubscription = function removeSubscription(subscription) {
if (this._nativeModule != null) {
this._nativeModule.removeListeners(1);
}
_EventEmitter.prototype.removeSubscription.call(this, subscription);
};
return NativeEventEmitter;
}(EventEmitter);
export default NativeEventEmitter;

View File

@ -0,0 +1,402 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
import InteractionManager from '../../../exports/InteractionManager';
import TouchHistoryMath from '../TouchHistoryMath';
var currentCentroidXOfTouchesChangedAfter = TouchHistoryMath.currentCentroidXOfTouchesChangedAfter;
var currentCentroidYOfTouchesChangedAfter = TouchHistoryMath.currentCentroidYOfTouchesChangedAfter;
var previousCentroidXOfTouchesChangedAfter = TouchHistoryMath.previousCentroidXOfTouchesChangedAfter;
var previousCentroidYOfTouchesChangedAfter = TouchHistoryMath.previousCentroidYOfTouchesChangedAfter;
var currentCentroidX = TouchHistoryMath.currentCentroidX;
var currentCentroidY = TouchHistoryMath.currentCentroidY;
/**
* `PanResponder` reconciles several touches into a single gesture. It makes
* single-touch gestures resilient to extra touches, and can be used to
* recognize simple multi-touch gestures.
*
* By default, `PanResponder` holds an `InteractionManager` handle to block
* long-running JS events from interrupting active gestures.
*
* It provides a predictable wrapper of the responder handlers provided by the
* [gesture responder system](docs/gesture-responder-system.html).
* For each handler, it provides a new `gestureState` object alongside the
* native event object:
*
* ```
* onPanResponderMove: (event, gestureState) => {}
* ```
*
* A native event is a synthetic touch event with the following form:
*
* - `nativeEvent`
* + `changedTouches` - Array of all touch events that have changed since the last event
* + `identifier` - The ID of the touch
* + `locationX` - The X position of the touch, relative to the element
* + `locationY` - The Y position of the touch, relative to the element
* + `pageX` - The X position of the touch, relative to the root element
* + `pageY` - The Y position of the touch, relative to the root element
* + `target` - The node id of the element receiving the touch event
* + `timestamp` - A time identifier for the touch, useful for velocity calculation
* + `touches` - Array of all current touches on the screen
*
* A `gestureState` object has the following:
*
* - `stateID` - ID of the gestureState- persisted as long as there at least
* one touch on screen
* - `moveX` - the latest screen coordinates of the recently-moved touch
* - `moveY` - the latest screen coordinates of the recently-moved touch
* - `x0` - the screen coordinates of the responder grant
* - `y0` - the screen coordinates of the responder grant
* - `dx` - accumulated distance of the gesture since the touch started
* - `dy` - accumulated distance of the gesture since the touch started
* - `vx` - current velocity of the gesture
* - `vy` - current velocity of the gesture
* - `numberActiveTouches` - Number of touches currently on screen
*
* ### Basic Usage
*
* ```
* componentWillMount: function() {
* this._panResponder = PanResponder.create({
* // Ask to be the responder:
* onStartShouldSetPanResponder: (evt, gestureState) => true,
* onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
* onMoveShouldSetPanResponder: (evt, gestureState) => true,
* onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
*
* onPanResponderGrant: (evt, gestureState) => {
* // The gesture has started. Show visual feedback so the user knows
* // what is happening!
*
* // gestureState.d{x,y} will be set to zero now
* },
* onPanResponderMove: (evt, gestureState) => {
* // The most recent move distance is gestureState.move{X,Y}
*
* // The accumulated gesture distance since becoming responder is
* // gestureState.d{x,y}
* },
* onPanResponderTerminationRequest: (evt, gestureState) => true,
* onPanResponderRelease: (evt, gestureState) => {
* // The user has released all touches while this view is the
* // responder. This typically means a gesture has succeeded
* },
* onPanResponderTerminate: (evt, gestureState) => {
* // Another component has become the responder, so this gesture
* // should be cancelled
* },
* onShouldBlockNativeResponder: (evt, gestureState) => {
* // Returns whether this component should block native components from becoming the JS
* // responder. Returns true by default. Is currently only supported on android.
* return true;
* },
* });
* },
*
* render: function() {
* return (
* <View {...this._panResponder.panHandlers} />
* );
* },
*
* ```
*
* ### Working Example
*
* To see it in action, try the
* [PanResponder example in RNTester](https://github.com/facebook/react-native/blob/master/RNTester/js/PanResponderExample.js)
*/
var PanResponder = {
/**
*
* A graphical explanation of the touch data flow:
*
* +----------------------------+ +--------------------------------+
* | ResponderTouchHistoryStore | |TouchHistoryMath |
* +----------------------------+ +----------+---------------------+
* |Global store of touchHistory| |Allocation-less math util |
* |including activeness, start | |on touch history (centroids |
* |position, prev/cur position.| |and multitouch movement etc) |
* | | | |
* +----^-----------------------+ +----^---------------------------+
* | |
* | (records relevant history |
* | of touches relevant for |
* | implementing higher level |
* | gestures) |
* | |
* +----+-----------------------+ +----|---------------------------+
* | ResponderEventPlugin | | | Your App/Component |
* +----------------------------+ +----|---------------------------+
* |Negotiates which view gets | Low level | | High level |
* |onResponderMove events. | events w/ | +-+-------+ events w/ |
* |Also records history into | touchHistory| | Pan | multitouch + |
* |ResponderTouchHistoryStore. +---------------->Responder+-----> accumulative|
* +----------------------------+ attached to | | | distance and |
* each event | +---------+ velocity. |
* | |
* | |
* +--------------------------------+
*
*
*
* Gesture that calculates cumulative movement over time in a way that just
* "does the right thing" for multiple touches. The "right thing" is very
* nuanced. When moving two touches in opposite directions, the cumulative
* distance is zero in each dimension. When two touches move in parallel five
* pixels in the same direction, the cumulative distance is five, not ten. If
* two touches start, one moves five in a direction, then stops and the other
* touch moves fives in the same direction, the cumulative distance is ten.
*
* This logic requires a kind of processing of time "clusters" of touch events
* so that two touch moves that essentially occur in parallel but move every
* other frame respectively, are considered part of the same movement.
*
* Explanation of some of the non-obvious fields:
*
* - moveX/moveY: If no move event has been observed, then `(moveX, moveY)` is
* invalid. If a move event has been observed, `(moveX, moveY)` is the
* centroid of the most recently moved "cluster" of active touches.
* (Currently all move have the same timeStamp, but later we should add some
* threshold for what is considered to be "moving"). If a palm is
* accidentally counted as a touch, but a finger is moving greatly, the palm
* will move slightly, but we only want to count the single moving touch.
* - x0/y0: Centroid location (non-cumulative) at the time of becoming
* responder.
* - dx/dy: Cumulative touch distance - not the same thing as sum of each touch
* distance. Accounts for touch moves that are clustered together in time,
* moving the same direction. Only valid when currently responder (otherwise,
* it only represents the drag distance below the threshold).
* - vx/vy: Velocity.
*/
_initializeGestureState: function _initializeGestureState(gestureState) {
gestureState.moveX = 0;
gestureState.moveY = 0;
gestureState.x0 = 0;
gestureState.y0 = 0;
gestureState.dx = 0;
gestureState.dy = 0;
gestureState.vx = 0;
gestureState.vy = 0;
gestureState.numberActiveTouches = 0; // All `gestureState` accounts for timeStamps up until:
gestureState._accountsForMovesUpTo = 0;
},
/**
* This is nuanced and is necessary. It is incorrect to continuously take all
* active *and* recently moved touches, find the centroid, and track how that
* result changes over time. Instead, we must take all recently moved
* touches, and calculate how the centroid has changed just for those
* recently moved touches, and append that change to an accumulator. This is
* to (at least) handle the case where the user is moving three fingers, and
* then one of the fingers stops but the other two continue.
*
* This is very different than taking all of the recently moved touches and
* storing their centroid as `dx/dy`. For correctness, we must *accumulate
* changes* in the centroid of recently moved touches.
*
* There is also some nuance with how we handle multiple moved touches in a
* single event. With the way `ReactNativeEventEmitter` dispatches touches as
* individual events, multiple touches generate two 'move' events, each of
* them triggering `onResponderMove`. But with the way `PanResponder` works,
* all of the gesture inference is performed on the first dispatch, since it
* looks at all of the touches (even the ones for which there hasn't been a
* native dispatch yet). Therefore, `PanResponder` does not call
* `onResponderMove` passed the first dispatch. This diverges from the
* typical responder callback pattern (without using `PanResponder`), but
* avoids more dispatches than necessary.
*/
_updateGestureStateOnMove: function _updateGestureStateOnMove(gestureState, touchHistory) {
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
gestureState.moveX = currentCentroidXOfTouchesChangedAfter(touchHistory, gestureState._accountsForMovesUpTo);
gestureState.moveY = currentCentroidYOfTouchesChangedAfter(touchHistory, gestureState._accountsForMovesUpTo);
var movedAfter = gestureState._accountsForMovesUpTo;
var prevX = previousCentroidXOfTouchesChangedAfter(touchHistory, movedAfter);
var x = currentCentroidXOfTouchesChangedAfter(touchHistory, movedAfter);
var prevY = previousCentroidYOfTouchesChangedAfter(touchHistory, movedAfter);
var y = currentCentroidYOfTouchesChangedAfter(touchHistory, movedAfter);
var nextDX = gestureState.dx + (x - prevX);
var nextDY = gestureState.dy + (y - prevY); // TODO: This must be filtered intelligently.
var dt = touchHistory.mostRecentTimeStamp - gestureState._accountsForMovesUpTo;
gestureState.vx = (nextDX - gestureState.dx) / dt;
gestureState.vy = (nextDY - gestureState.dy) / dt;
gestureState.dx = nextDX;
gestureState.dy = nextDY;
gestureState._accountsForMovesUpTo = touchHistory.mostRecentTimeStamp;
},
/**
* @param {object} config Enhanced versions of all of the responder callbacks
* that provide not only the typical `ResponderSyntheticEvent`, but also the
* `PanResponder` gesture state. Simply replace the word `Responder` with
* `PanResponder` in each of the typical `onResponder*` callbacks. For
* example, the `config` object would look like:
*
* - `onMoveShouldSetPanResponder: (e, gestureState) => {...}`
* - `onMoveShouldSetPanResponderCapture: (e, gestureState) => {...}`
* - `onStartShouldSetPanResponder: (e, gestureState) => {...}`
* - `onStartShouldSetPanResponderCapture: (e, gestureState) => {...}`
* - `onPanResponderReject: (e, gestureState) => {...}`
* - `onPanResponderGrant: (e, gestureState) => {...}`
* - `onPanResponderStart: (e, gestureState) => {...}`
* - `onPanResponderEnd: (e, gestureState) => {...}`
* - `onPanResponderRelease: (e, gestureState) => {...}`
* - `onPanResponderMove: (e, gestureState) => {...}`
* - `onPanResponderTerminate: (e, gestureState) => {...}`
* - `onPanResponderTerminationRequest: (e, gestureState) => {...}`
* - `onShouldBlockNativeResponder: (e, gestureState) => {...}`
*
* In general, for events that have capture equivalents, we update the
* gestureState once in the capture phase and can use it in the bubble phase
* as well.
*
* Be careful with onStartShould* callbacks. They only reflect updated
* `gestureState` for start/end events that bubble/capture to the Node.
* Once the node is the responder, you can rely on every start/end event
* being processed by the gesture and `gestureState` being updated
* accordingly. (numberActiveTouches) may not be totally accurate unless you
* are the responder.
*/
create: function create(config) {
var interactionState = {
handle: null
};
var gestureState = {
// Useful for debugging
stateID: Math.random(),
moveX: 0,
moveY: 0,
x0: 0,
y0: 0,
dx: 0,
dy: 0,
vx: 0,
vy: 0,
numberActiveTouches: 0,
_accountsForMovesUpTo: 0
};
var panHandlers = {
onStartShouldSetResponder: function onStartShouldSetResponder(event) {
return config.onStartShouldSetPanResponder == null ? false : config.onStartShouldSetPanResponder(event, gestureState);
},
onMoveShouldSetResponder: function onMoveShouldSetResponder(event) {
return config.onMoveShouldSetPanResponder == null ? false : config.onMoveShouldSetPanResponder(event, gestureState);
},
onStartShouldSetResponderCapture: function onStartShouldSetResponderCapture(event) {
// TODO: Actually, we should reinitialize the state any time
// touches.length increases from 0 active to > 0 active.
if (event.nativeEvent.touches.length === 1) {
PanResponder._initializeGestureState(gestureState);
}
gestureState.numberActiveTouches = event.touchHistory.numberActiveTouches;
return config.onStartShouldSetPanResponderCapture != null ? config.onStartShouldSetPanResponderCapture(event, gestureState) : false;
},
onMoveShouldSetResponderCapture: function onMoveShouldSetResponderCapture(event) {
var touchHistory = event.touchHistory; // Responder system incorrectly dispatches should* to current responder
// Filter out any touch moves past the first one - we would have
// already processed multi-touch geometry during the first event.
if (gestureState._accountsForMovesUpTo === touchHistory.mostRecentTimeStamp) {
return false;
}
PanResponder._updateGestureStateOnMove(gestureState, touchHistory);
return config.onMoveShouldSetPanResponderCapture ? config.onMoveShouldSetPanResponderCapture(event, gestureState) : false;
},
onResponderGrant: function onResponderGrant(event) {
if (!interactionState.handle) {
interactionState.handle = InteractionManager.createInteractionHandle();
}
gestureState.x0 = currentCentroidX(event.touchHistory);
gestureState.y0 = currentCentroidY(event.touchHistory);
gestureState.dx = 0;
gestureState.dy = 0;
if (config.onPanResponderGrant) {
config.onPanResponderGrant(event, gestureState);
} // TODO: t7467124 investigate if this can be removed
return config.onShouldBlockNativeResponder == null ? true : config.onShouldBlockNativeResponder(event, gestureState);
},
onResponderReject: function onResponderReject(event) {
clearInteractionHandle(interactionState, config.onPanResponderReject, event, gestureState);
},
onResponderRelease: function onResponderRelease(event) {
clearInteractionHandle(interactionState, config.onPanResponderRelease, event, gestureState);
PanResponder._initializeGestureState(gestureState);
},
onResponderStart: function onResponderStart(event) {
var touchHistory = event.touchHistory;
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
if (config.onPanResponderStart) {
config.onPanResponderStart(event, gestureState);
}
},
onResponderMove: function onResponderMove(event) {
var touchHistory = event.touchHistory; // Guard against the dispatch of two touch moves when there are two
// simultaneously changed touches.
if (gestureState._accountsForMovesUpTo === touchHistory.mostRecentTimeStamp) {
return;
} // Filter out any touch moves past the first one - we would have
// already processed multi-touch geometry during the first event.
PanResponder._updateGestureStateOnMove(gestureState, touchHistory);
if (config.onPanResponderMove) {
config.onPanResponderMove(event, gestureState);
}
},
onResponderEnd: function onResponderEnd(event) {
var touchHistory = event.touchHistory;
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
clearInteractionHandle(interactionState, config.onPanResponderEnd, event, gestureState);
},
onResponderTerminate: function onResponderTerminate(event) {
clearInteractionHandle(interactionState, config.onPanResponderTerminate, event, gestureState);
PanResponder._initializeGestureState(gestureState);
},
onResponderTerminationRequest: function onResponderTerminationRequest(event) {
return config.onPanResponderTerminationRequest == null ? true : config.onPanResponderTerminationRequest(event, gestureState);
}
};
return {
panHandlers: panHandlers,
getInteractionHandle: function getInteractionHandle() {
return interactionState.handle;
}
};
}
};
function clearInteractionHandle(interactionState, callback, event, gestureState) {
if (interactionState.handle) {
InteractionManager.clearInteractionHandle(interactionState.handle);
interactionState.handle = null;
}
if (callback) {
callback(event, gestureState);
}
}
export default PanResponder;

View File

@ -0,0 +1,65 @@
/* eslint-disable */
/**
* Copyright 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* From React 16.0.0
*/
import invariant from 'fbjs/lib/invariant';
var twoArgumentPooler = function twoArgumentPooler(a1, a2) {
var Klass = this;
if (Klass.instancePool.length) {
var instance = Klass.instancePool.pop();
Klass.call(instance, a1, a2);
return instance;
} else {
return new Klass(a1, a2);
}
};
var standardReleaser = function standardReleaser(instance) {
var Klass = this;
instance.destructor();
if (Klass.instancePool.length < Klass.poolSize) {
Klass.instancePool.push(instance);
}
};
var DEFAULT_POOL_SIZE = 10;
var DEFAULT_POOLER = twoArgumentPooler;
/**
* Augments `CopyConstructor` to be a poolable class, augmenting only the class
* itself (statically) not adding any prototypical fields. Any CopyConstructor
* you give this may have a `poolSize` property, and will look for a
* prototypical `destructor` on instances.
*
* @param {Function} CopyConstructor Constructor that can be used to reset.
* @param {Function} pooler Customizable pooler.
*/
var addPoolingTo = function addPoolingTo(CopyConstructor, pooler) {
// Casting as any so that flow ignores the actual implementation and trusts
// it to match the type we declared
var NewKlass = CopyConstructor;
NewKlass.instancePool = [];
NewKlass.getPooled = pooler || DEFAULT_POOLER;
if (!NewKlass.poolSize) {
NewKlass.poolSize = DEFAULT_POOL_SIZE;
}
NewKlass.release = standardReleaser;
return NewKlass;
};
var PooledClass = {
addPoolingTo: addPoolingTo,
twoArgumentPooler: twoArgumentPooler
};
export default PooledClass;

View File

@ -0,0 +1,199 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import Platform from '../../../exports/Platform';
import * as React from 'react';
import ScrollView from '../../../exports/ScrollView';
import VirtualizedSectionList from '../VirtualizedSectionList';
var defaultProps = _objectSpread({}, VirtualizedSectionList.defaultProps, {
stickySectionHeadersEnabled: Platform.OS === 'ios'
});
/**
* A performant interface for rendering sectioned lists, supporting the most handy features:
*
* - Fully cross-platform.
* - Configurable viewability callbacks.
* - List header support.
* - List footer support.
* - Item separator support.
* - Section header support.
* - Section separator support.
* - Heterogeneous data and item rendering support.
* - Pull to Refresh.
* - Scroll loading.
*
* If you don't need section support and want a simpler interface, use
* [`<FlatList>`](/react-native/docs/flatlist.html).
*
* Simple Examples:
*
* <SectionList
* renderItem={({item}) => <ListItem title={item} />}
* renderSectionHeader={({section}) => <Header title={section.title} />}
* sections={[ // homogeneous rendering between sections
* {data: [...], title: ...},
* {data: [...], title: ...},
* {data: [...], title: ...},
* ]}
* />
*
* <SectionList
* sections={[ // heterogeneous rendering between sections
* {data: [...], renderItem: ...},
* {data: [...], renderItem: ...},
* {data: [...], renderItem: ...},
* ]}
* />
*
* This is a convenience wrapper around [`<VirtualizedList>`](docs/virtualizedlist.html),
* and thus inherits its props (as well as those of `ScrollView`) that aren't explicitly listed
* here, along with the following caveats:
*
* - Internal state is not preserved when content scrolls out of the render window. Make sure all
* your data is captured in the item data or external stores like Flux, Redux, or Relay.
* - This is a `PureComponent` which means that it will not re-render if `props` remain shallow-
* equal. Make sure that everything your `renderItem` function depends on is passed as a prop
* (e.g. `extraData`) that is not `===` after updates, otherwise your UI may not update on
* changes. This includes the `data` prop and parent component state.
* - In order to constrain memory and enable smooth scrolling, content is rendered asynchronously
* offscreen. This means it's possible to scroll faster than the fill rate and momentarily see
* blank content. This is a tradeoff that can be adjusted to suit the needs of each application,
* and we are working on improving it behind the scenes.
* - By default, the list looks for a `key` prop on each item and uses that for the React key.
* Alternatively, you can provide a custom `keyExtractor` prop.
*
*/
var SectionList =
/*#__PURE__*/
function (_React$PureComponent) {
_inheritsLoose(SectionList, _React$PureComponent);
function SectionList() {
var _this;
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
_this = _React$PureComponent.call.apply(_React$PureComponent, [this].concat(args)) || this;
_this._captureRef = function (ref) {
// $FlowFixMe
_this._wrapperListRef = ref;
};
return _this;
}
var _proto = SectionList.prototype;
/**
* Scrolls to the item at the specified `sectionIndex` and `itemIndex` (within the section)
* positioned in the viewable area such that `viewPosition` 0 places it at the top (and may be
* covered by a sticky header), 1 at the bottom, and 0.5 centered in the middle. `viewOffset` is a
* fixed number of pixels to offset the final target position, e.g. to compensate for sticky
* headers.
*
* Note: cannot scroll to locations outside the render window without specifying the
* `getItemLayout` prop.
*/
_proto.scrollToLocation = function scrollToLocation(params) {
if (this._wrapperListRef != null) {
this._wrapperListRef.scrollToLocation(params);
}
}
/**
* Tells the list an interaction has occurred, which should trigger viewability calculations, e.g.
* if `waitForInteractions` is true and the user has not scrolled. This is typically called by
* taps on items or by navigation actions.
*/
;
_proto.recordInteraction = function recordInteraction() {
var listRef = this._wrapperListRef && this._wrapperListRef.getListRef();
listRef && listRef.recordInteraction();
}
/**
* Displays the scroll indicators momentarily.
*
* @platform ios
*/
;
_proto.flashScrollIndicators = function flashScrollIndicators() {
var listRef = this._wrapperListRef && this._wrapperListRef.getListRef();
listRef && listRef.flashScrollIndicators();
}
/**
* Provides a handle to the underlying scroll responder.
*/
;
_proto.getScrollResponder = function getScrollResponder() {
var listRef = this._wrapperListRef && this._wrapperListRef.getListRef();
if (listRef) {
return listRef.getScrollResponder();
}
};
_proto.getScrollableNode = function getScrollableNode() {
var listRef = this._wrapperListRef && this._wrapperListRef.getListRef();
if (listRef) {
return listRef.getScrollableNode();
}
};
_proto.setNativeProps = function setNativeProps(props) {
var listRef = this._wrapperListRef && this._wrapperListRef.getListRef();
if (listRef) {
listRef.setNativeProps(props);
}
};
_proto.render = function render() {
return (
/* $FlowFixMe(>=0.66.0 site=react_native_fb) This comment suppresses an
* error found when Flow v0.66 was deployed. To see the error delete this
* comment and run Flow. */
React.createElement(VirtualizedSectionList, _extends({}, this.props, {
ref: this._captureRef,
getItemCount: function getItemCount(items) {
return items.length;
},
getItem: function getItem(items, index) {
return items[index];
}
}))
);
};
return SectionList;
}(React.PureComponent);
SectionList.defaultProps = defaultProps;
export default SectionList;

View File

@ -0,0 +1,54 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*
*/
'use strict';
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
import * as React from 'react';
/**
* Renders static content efficiently by allowing React to short-circuit the
* reconciliation process. This component should be used when you know that a
* subtree of components will never need to be updated.
*
* const someValue = ...; // We know for certain this value will never change.
* return (
* <StaticContainer>
* <MyComponent value={someValue} />
* </StaticContainer>
* );
*
* Typically, you will not need to use this component and should opt for normal
* React reconciliation.
*/
var StaticContainer =
/*#__PURE__*/
function (_React$Component) {
_inheritsLoose(StaticContainer, _React$Component);
function StaticContainer() {
return _React$Component.apply(this, arguments) || this;
}
var _proto = StaticContainer.prototype;
_proto.shouldComponentUpdate = function shouldComponentUpdate(nextProps) {
return !!nextProps.shouldUpdate;
};
_proto.render = function render() {
var child = this.props.children;
return child === null || child === false ? null : React.Children.only(child);
};
return StaticContainer;
}(React.Component);
export default StaticContainer;

View File

@ -0,0 +1,38 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*
*/
'use strict';
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
import * as React from 'react';
var StaticRenderer =
/*#__PURE__*/
function (_React$Component) {
_inheritsLoose(StaticRenderer, _React$Component);
function StaticRenderer() {
return _React$Component.apply(this, arguments) || this;
}
var _proto = StaticRenderer.prototype;
_proto.shouldComponentUpdate = function shouldComponentUpdate(nextProps) {
return nextProps.shouldUpdate;
};
_proto.render = function render() {
return this.props.render();
};
return StaticRenderer;
}(React.Component);
export default StaticRenderer;

View File

@ -0,0 +1,96 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
var TouchHistoryMath = {
/**
* This code is optimized and not intended to look beautiful. This allows
* computing of touch centroids that have moved after `touchesChangedAfter`
* timeStamp. You can compute the current centroid involving all touches
* moves after `touchesChangedAfter`, or you can compute the previous
* centroid of all touches that were moved after `touchesChangedAfter`.
*
* @param {TouchHistoryMath} touchHistory Standard Responder touch track
* data.
* @param {number} touchesChangedAfter timeStamp after which moved touches
* are considered "actively moving" - not just "active".
* @param {boolean} isXAxis Consider `x` dimension vs. `y` dimension.
* @param {boolean} ofCurrent Compute current centroid for actively moving
* touches vs. previous centroid of now actively moving touches.
* @return {number} value of centroid in specified dimension.
*/
centroidDimension: function centroidDimension(touchHistory, touchesChangedAfter, isXAxis, ofCurrent) {
var touchBank = touchHistory.touchBank;
var total = 0;
var count = 0;
var oneTouchData = touchHistory.numberActiveTouches === 1 ? touchHistory.touchBank[touchHistory.indexOfSingleActiveTouch] : null;
if (oneTouchData !== null) {
if (oneTouchData.touchActive && oneTouchData.currentTimeStamp > touchesChangedAfter) {
total += ofCurrent && isXAxis ? oneTouchData.currentPageX : ofCurrent && !isXAxis ? oneTouchData.currentPageY : !ofCurrent && isXAxis ? oneTouchData.previousPageX : oneTouchData.previousPageY;
count = 1;
}
} else {
for (var i = 0; i < touchBank.length; i++) {
var touchTrack = touchBank[i];
if (touchTrack !== null && touchTrack !== undefined && touchTrack.touchActive && touchTrack.currentTimeStamp >= touchesChangedAfter) {
var toAdd = void 0; // Yuck, program temporarily in invalid state.
if (ofCurrent && isXAxis) {
toAdd = touchTrack.currentPageX;
} else if (ofCurrent && !isXAxis) {
toAdd = touchTrack.currentPageY;
} else if (!ofCurrent && isXAxis) {
toAdd = touchTrack.previousPageX;
} else {
toAdd = touchTrack.previousPageY;
}
total += toAdd;
count++;
}
}
}
return count > 0 ? total / count : TouchHistoryMath.noCentroid;
},
currentCentroidXOfTouchesChangedAfter: function currentCentroidXOfTouchesChangedAfter(touchHistory, touchesChangedAfter) {
return TouchHistoryMath.centroidDimension(touchHistory, touchesChangedAfter, true, // isXAxis
true // ofCurrent
);
},
currentCentroidYOfTouchesChangedAfter: function currentCentroidYOfTouchesChangedAfter(touchHistory, touchesChangedAfter) {
return TouchHistoryMath.centroidDimension(touchHistory, touchesChangedAfter, false, // isXAxis
true // ofCurrent
);
},
previousCentroidXOfTouchesChangedAfter: function previousCentroidXOfTouchesChangedAfter(touchHistory, touchesChangedAfter) {
return TouchHistoryMath.centroidDimension(touchHistory, touchesChangedAfter, true, // isXAxis
false // ofCurrent
);
},
previousCentroidYOfTouchesChangedAfter: function previousCentroidYOfTouchesChangedAfter(touchHistory, touchesChangedAfter) {
return TouchHistoryMath.centroidDimension(touchHistory, touchesChangedAfter, false, // isXAxis
false // ofCurrent
);
},
currentCentroidX: function currentCentroidX(touchHistory) {
return TouchHistoryMath.centroidDimension(touchHistory, 0, // touchesChangedAfter
true, // isXAxis
true // ofCurrent
);
},
currentCentroidY: function currentCentroidY(touchHistory) {
return TouchHistoryMath.centroidDimension(touchHistory, 0, // touchesChangedAfter
false, // isXAxis
true // ofCurrent
);
},
noCentroid: -1
};
export default TouchHistoryMath;

View File

@ -0,0 +1,26 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
/**
* NOTE: This is React Native specific export type.
*
* RCTExport is an interface type that allows native code generation for React
* Native native modules. It exists as a hint to the codegen tool that any
* interface that extends it needs to be codegen'ed. Example usage:
*
* export interface RCTFoobar extends RCTExport<void> {}
*
* Native definition for RCTFoobar will then be generated.
*
* The type param T is a placeholder for future codegen hinting, like versioning
* information, native base classes, etc. For now, simply use `void` type as
* there's nothing to give hint about.
*/
// eslint-disable-next-line no-unused-vars

View File

@ -0,0 +1,20 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
import invariant from 'fbjs/lib/invariant';
export function get(name) {
return null;
}
export function getEnforcing(name) {
var module = get(name);
invariant(module != null, "TurboModuleRegistry.getEnforcing(...): '" + name + "' could not be found. " + 'Verify that a module by this name is registered in the native binary.');
return module;
}

View File

@ -0,0 +1,10 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';

View File

@ -0,0 +1,271 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import invariant from 'fbjs/lib/invariant';
/**
* A Utility class for calculating viewable items based on current metrics like scroll position and
* layout.
*
* An item is said to be in a "viewable" state when any of the following
* is true for longer than `minimumViewTime` milliseconds (after an interaction if `waitForInteraction`
* is true):
*
* - Occupying >= `viewAreaCoveragePercentThreshold` of the view area XOR fraction of the item
* visible in the view area >= `itemVisiblePercentThreshold`.
* - Entirely visible on screen
*/
var ViewabilityHelper =
/*#__PURE__*/
function () {
/* $FlowFixMe(>=0.63.0 site=react_native_fb) This comment suppresses an error
* found when Flow v0.63 was deployed. To see the error delete this comment
* and run Flow. */
function ViewabilityHelper(config) {
if (config === void 0) {
config = {
viewAreaCoveragePercentThreshold: 0
};
}
this._hasInteracted = false;
this._timers = new Set();
this._viewableIndices = [];
this._viewableItems = new Map();
this._config = config;
}
/**
* Cleanup, e.g. on unmount. Clears any pending timers.
*/
var _proto = ViewabilityHelper.prototype;
_proto.dispose = function dispose() {
this._timers.forEach(clearTimeout);
}
/**
* Determines which items are viewable based on the current metrics and config.
*/
;
_proto.computeViewableItems = function computeViewableItems(itemCount, scrollOffset, viewportHeight, getFrameMetrics, renderRange) {
var _this$_config = this._config,
itemVisiblePercentThreshold = _this$_config.itemVisiblePercentThreshold,
viewAreaCoveragePercentThreshold = _this$_config.viewAreaCoveragePercentThreshold;
var viewAreaMode = viewAreaCoveragePercentThreshold != null;
var viewablePercentThreshold = viewAreaMode ? viewAreaCoveragePercentThreshold : itemVisiblePercentThreshold;
invariant(viewablePercentThreshold != null && itemVisiblePercentThreshold != null !== (viewAreaCoveragePercentThreshold != null), 'Must set exactly one of itemVisiblePercentThreshold or viewAreaCoveragePercentThreshold');
var viewableIndices = [];
if (itemCount === 0) {
return viewableIndices;
}
var firstVisible = -1;
var _ref = renderRange || {
first: 0,
last: itemCount - 1
},
first = _ref.first,
last = _ref.last;
if (last >= itemCount) {
console.warn('Invalid render range computing viewability ' + JSON.stringify({
renderRange: renderRange,
itemCount: itemCount
}));
return [];
}
for (var idx = first; idx <= last; idx++) {
var metrics = getFrameMetrics(idx);
if (!metrics) {
continue;
}
var top = metrics.offset - scrollOffset;
var bottom = top + metrics.length;
if (top < viewportHeight && bottom > 0) {
firstVisible = idx;
if (_isViewable(viewAreaMode, viewablePercentThreshold, top, bottom, viewportHeight, metrics.length)) {
viewableIndices.push(idx);
}
} else if (firstVisible >= 0) {
break;
}
}
return viewableIndices;
}
/**
* Figures out which items are viewable and how that has changed from before and calls
* `onViewableItemsChanged` as appropriate.
*/
;
_proto.onUpdate = function onUpdate(itemCount, scrollOffset, viewportHeight, getFrameMetrics, createViewToken, onViewableItemsChanged, renderRange) {
var _this = this;
if (this._config.waitForInteraction && !this._hasInteracted || itemCount === 0 || !getFrameMetrics(0)) {
return;
}
var viewableIndices = [];
if (itemCount) {
viewableIndices = this.computeViewableItems(itemCount, scrollOffset, viewportHeight, getFrameMetrics, renderRange);
}
if (this._viewableIndices.length === viewableIndices.length && this._viewableIndices.every(function (v, ii) {
return v === viewableIndices[ii];
})) {
// We might get a lot of scroll events where visibility doesn't change and we don't want to do
// extra work in those cases.
return;
}
this._viewableIndices = viewableIndices;
if (this._config.minimumViewTime) {
var handle = setTimeout(function () {
_this._timers.delete(handle);
_this._onUpdateSync(viewableIndices, onViewableItemsChanged, createViewToken);
}, this._config.minimumViewTime);
this._timers.add(handle);
} else {
this._onUpdateSync(viewableIndices, onViewableItemsChanged, createViewToken);
}
}
/**
* clean-up cached _viewableIndices to evaluate changed items on next update
*/
;
_proto.resetViewableIndices = function resetViewableIndices() {
this._viewableIndices = [];
}
/**
* Records that an interaction has happened even if there has been no scroll.
*/
;
_proto.recordInteraction = function recordInteraction() {
this._hasInteracted = true;
};
_proto._onUpdateSync = function _onUpdateSync( // $FlowFixMe
viewableIndicesToCheck, // $FlowFixMe
onViewableItemsChanged, // $FlowFixMe
createViewToken) {
var _this2 = this;
// Filter out indices that have gone out of view since this call was scheduled.
viewableIndicesToCheck = viewableIndicesToCheck.filter(function (ii) {
return _this2._viewableIndices.includes(ii);
});
var prevItems = this._viewableItems;
var nextItems = new Map(viewableIndicesToCheck.map(function (ii) {
var viewable = createViewToken(ii, true);
return [viewable.key, viewable];
}));
var changed = [];
for (var _iterator = nextItems, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
var _ref2;
if (_isArray) {
if (_i >= _iterator.length) break;
_ref2 = _iterator[_i++];
} else {
_i = _iterator.next();
if (_i.done) break;
_ref2 = _i.value;
}
var _ref4 = _ref2,
key = _ref4[0],
viewable = _ref4[1];
if (!prevItems.has(key)) {
changed.push(viewable);
}
}
for (var _iterator2 = prevItems, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) {
var _ref3;
if (_isArray2) {
if (_i2 >= _iterator2.length) break;
_ref3 = _iterator2[_i2++];
} else {
_i2 = _iterator2.next();
if (_i2.done) break;
_ref3 = _i2.value;
}
var _ref5 = _ref3,
_key = _ref5[0],
_viewable = _ref5[1];
if (!nextItems.has(_key)) {
changed.push(_objectSpread({}, _viewable, {
isViewable: false
}));
}
}
if (changed.length > 0) {
this._viewableItems = nextItems;
onViewableItemsChanged({
viewableItems: Array.from(nextItems.values()),
changed: changed,
viewabilityConfig: this._config
});
}
};
return ViewabilityHelper;
}();
function _isViewable(viewAreaMode, viewablePercentThreshold, top, bottom, viewportHeight, itemLength) {
if (_isEntirelyVisible(top, bottom, viewportHeight)) {
return true;
} else {
var pixels = _getPixelsVisible(top, bottom, viewportHeight);
var percent = 100 * (viewAreaMode ? pixels / viewportHeight : pixels / itemLength);
return percent >= viewablePercentThreshold;
}
}
function _getPixelsVisible(top, bottom, viewportHeight) {
var visibleHeight = Math.min(bottom, viewportHeight) - Math.max(top, 0);
return Math.max(0, visibleHeight);
}
function _isEntirelyVisible(top, bottom, viewportHeight) {
return top >= 0 && bottom <= viewportHeight && bottom > top;
}
export default ViewabilityHelper;

View File

@ -0,0 +1,178 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
import invariant from 'fbjs/lib/invariant';
/**
* Used to find the indices of the frames that overlap the given offsets. Useful for finding the
* items that bound different windows of content, such as the visible area or the buffered overscan
* area.
*/
function elementsThatOverlapOffsets(offsets, itemCount, getFrameMetrics) {
var out = [];
var outLength = 0;
for (var ii = 0; ii < itemCount; ii++) {
var frame = getFrameMetrics(ii);
var trailingOffset = frame.offset + frame.length;
for (var kk = 0; kk < offsets.length; kk++) {
if (out[kk] == null && trailingOffset >= offsets[kk]) {
out[kk] = ii;
outLength++;
if (kk === offsets.length - 1) {
invariant(outLength === offsets.length, 'bad offsets input, should be in increasing order: %s', JSON.stringify(offsets));
return out;
}
}
}
}
return out;
}
/**
* Computes the number of elements in the `next` range that are new compared to the `prev` range.
* Handy for calculating how many new items will be rendered when the render window changes so we
* can restrict the number of new items render at once so that content can appear on the screen
* faster.
*/
function newRangeCount(prev, next) {
return next.last - next.first + 1 - Math.max(0, 1 + Math.min(next.last, prev.last) - Math.max(next.first, prev.first));
}
/**
* Custom logic for determining which items should be rendered given the current frame and scroll
* metrics, as well as the previous render state. The algorithm may evolve over time, but generally
* prioritizes the visible area first, then expands that with overscan regions ahead and behind,
* biased in the direction of scroll.
*/
function computeWindowedRenderLimits(props, prev, getFrameMetricsApprox, scrollMetrics) {
var data = props.data,
getItemCount = props.getItemCount,
maxToRenderPerBatch = props.maxToRenderPerBatch,
windowSize = props.windowSize;
var itemCount = getItemCount(data);
if (itemCount === 0) {
return prev;
}
var offset = scrollMetrics.offset,
velocity = scrollMetrics.velocity,
visibleLength = scrollMetrics.visibleLength; // Start with visible area, then compute maximum overscan region by expanding from there, biased
// in the direction of scroll. Total overscan area is capped, which should cap memory consumption
// too.
var visibleBegin = Math.max(0, offset);
var visibleEnd = visibleBegin + visibleLength;
var overscanLength = (windowSize - 1) * visibleLength; // Considering velocity seems to introduce more churn than it's worth.
var leadFactor = 0.5; // Math.max(0, Math.min(1, velocity / 25 + 0.5));
var fillPreference = velocity > 1 ? 'after' : velocity < -1 ? 'before' : 'none';
var overscanBegin = Math.max(0, visibleBegin - (1 - leadFactor) * overscanLength);
var overscanEnd = Math.max(0, visibleEnd + leadFactor * overscanLength);
var lastItemOffset = getFrameMetricsApprox(itemCount - 1).offset;
if (lastItemOffset < overscanBegin) {
// Entire list is before our overscan window
return {
first: Math.max(0, itemCount - 1 - maxToRenderPerBatch),
last: itemCount - 1
};
} // Find the indices that correspond to the items at the render boundaries we're targeting.
var _elementsThatOverlapO = elementsThatOverlapOffsets([overscanBegin, visibleBegin, visibleEnd, overscanEnd], props.getItemCount(props.data), getFrameMetricsApprox),
overscanFirst = _elementsThatOverlapO[0],
first = _elementsThatOverlapO[1],
last = _elementsThatOverlapO[2],
overscanLast = _elementsThatOverlapO[3];
overscanFirst = overscanFirst == null ? 0 : overscanFirst;
first = first == null ? Math.max(0, overscanFirst) : first;
overscanLast = overscanLast == null ? itemCount - 1 : overscanLast;
last = last == null ? Math.min(overscanLast, first + maxToRenderPerBatch - 1) : last;
var visible = {
first: first,
last: last
}; // We want to limit the number of new cells we're rendering per batch so that we can fill the
// content on the screen quickly. If we rendered the entire overscan window at once, the user
// could be staring at white space for a long time waiting for a bunch of offscreen content to
// render.
var newCellCount = newRangeCount(prev, visible);
while (true) {
if (first <= overscanFirst && last >= overscanLast) {
// If we fill the entire overscan range, we're done.
break;
}
var maxNewCells = newCellCount >= maxToRenderPerBatch;
var firstWillAddMore = first <= prev.first || first > prev.last;
var firstShouldIncrement = first > overscanFirst && (!maxNewCells || !firstWillAddMore);
var lastWillAddMore = last >= prev.last || last < prev.first;
var lastShouldIncrement = last < overscanLast && (!maxNewCells || !lastWillAddMore);
if (maxNewCells && !firstShouldIncrement && !lastShouldIncrement) {
// We only want to stop if we've hit maxNewCells AND we cannot increment first or last
// without rendering new items. This let's us preserve as many already rendered items as
// possible, reducing render churn and keeping the rendered overscan range as large as
// possible.
break;
}
if (firstShouldIncrement && !(fillPreference === 'after' && lastShouldIncrement && lastWillAddMore)) {
if (firstWillAddMore) {
newCellCount++;
}
first--;
}
if (lastShouldIncrement && !(fillPreference === 'before' && firstShouldIncrement && firstWillAddMore)) {
if (lastWillAddMore) {
newCellCount++;
}
last++;
}
}
if (!(last >= first && first >= 0 && last < itemCount && first >= overscanFirst && last <= overscanLast && first <= visible.first && last >= visible.last)) {
throw new Error('Bad window calculation ' + JSON.stringify({
first: first,
last: last,
itemCount: itemCount,
overscanFirst: overscanFirst,
overscanLast: overscanLast,
visible: visible
}));
}
return {
first: first,
last: last
};
}
var VirtualizeUtils = {
computeWindowedRenderLimits: computeWindowedRenderLimits,
elementsThatOverlapOffsets: elementsThatOverlapOffsets,
newRangeCount: newRangeCount
};
export { computeWindowedRenderLimits, elementsThatOverlapOffsets, newRangeCount };
export default VirtualizeUtils;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,445 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
import * as React from 'react';
import View from '../../../exports/View';
import VirtualizedList from '../VirtualizedList';
import invariant from 'fbjs/lib/invariant';
/**
* Right now this just flattens everything into one list and uses VirtualizedList under the
* hood. The only operation that might not scale well is concatting the data arrays of all the
* sections when new props are received, which should be plenty fast for up to ~10,000 items.
*/
var VirtualizedSectionList =
/*#__PURE__*/
function (_React$PureComponent) {
_inheritsLoose(VirtualizedSectionList, _React$PureComponent);
var _proto = VirtualizedSectionList.prototype;
_proto.scrollToLocation = function scrollToLocation(params) {
var index = params.itemIndex;
for (var i = 0; i < params.sectionIndex; i++) {
index += this.props.getItemCount(this.props.sections[i].data) + 2;
}
var viewOffset = 0;
if (params.itemIndex > 0 && this.props.stickySectionHeadersEnabled) {
var frame = this._listRef._getFrameMetricsApprox(index - params.itemIndex);
viewOffset = frame.length;
}
var toIndexParams = _objectSpread({}, params, {
viewOffset: viewOffset,
index: index
});
this._listRef.scrollToIndex(toIndexParams);
};
_proto.getListRef = function getListRef() {
return this._listRef;
};
function VirtualizedSectionList(props, context) {
var _this;
_this = _React$PureComponent.call(this, props, context) || this;
_this._keyExtractor = function (item, index) {
var info = _this._subExtractor(index);
return info && info.key || String(index);
};
_this._convertViewable = function (viewable) {
invariant(viewable.index != null, 'Received a broken ViewToken');
var info = _this._subExtractor(viewable.index);
if (!info) {
return null;
}
var keyExtractor = info.section.keyExtractor || _this.props.keyExtractor;
return _objectSpread({}, viewable, {
index: info.index,
/* $FlowFixMe(>=0.63.0 site=react_native_fb) This comment suppresses an
* error found when Flow v0.63 was deployed. To see the error delete this
* comment and run Flow. */
key: keyExtractor(viewable.item, info.index),
section: info.section
});
};
_this._onViewableItemsChanged = function (_ref) {
var viewableItems = _ref.viewableItems,
changed = _ref.changed;
if (_this.props.onViewableItemsChanged) {
_this.props.onViewableItemsChanged({
viewableItems: viewableItems.map(_this._convertViewable, _assertThisInitialized(_this)).filter(Boolean),
changed: changed.map(_this._convertViewable, _assertThisInitialized(_this)).filter(Boolean)
});
}
};
_this._renderItem = function (_ref2) {
var item = _ref2.item,
index = _ref2.index;
var info = _this._subExtractor(index);
if (!info) {
return null;
}
var infoIndex = info.index;
if (infoIndex == null) {
var section = info.section;
if (info.header === true) {
var renderSectionHeader = _this.props.renderSectionHeader;
return renderSectionHeader ? renderSectionHeader({
section: section
}) : null;
} else {
var renderSectionFooter = _this.props.renderSectionFooter;
return renderSectionFooter ? renderSectionFooter({
section: section
}) : null;
}
} else {
var renderItem = info.section.renderItem || _this.props.renderItem;
var SeparatorComponent = _this._getSeparatorComponent(index, info);
invariant(renderItem, 'no renderItem!');
return React.createElement(ItemWithSeparator, {
SeparatorComponent: SeparatorComponent,
LeadingSeparatorComponent: infoIndex === 0 ? _this.props.SectionSeparatorComponent : undefined,
cellKey: info.key,
index: infoIndex,
item: item,
leadingItem: info.leadingItem,
leadingSection: info.leadingSection,
onUpdateSeparator: _this._onUpdateSeparator,
prevCellKey: (_this._subExtractor(index - 1) || {}).key,
ref: function ref(_ref3) {
_this._cellRefs[info.key] = _ref3;
},
renderItem: renderItem,
section: info.section,
trailingItem: info.trailingItem,
trailingSection: info.trailingSection
});
}
};
_this._onUpdateSeparator = function (key, newProps) {
var ref = _this._cellRefs[key];
ref && ref.updateSeparatorProps(newProps);
};
_this._cellRefs = {};
_this._captureRef = function (ref) {
/* $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. */
_this._listRef = ref;
};
_this.state = _this._computeState(props);
return _this;
}
_proto.UNSAFE_componentWillReceiveProps = function UNSAFE_componentWillReceiveProps(nextProps) {
this.setState(this._computeState(nextProps));
};
_proto._computeState = function _computeState(props) {
var offset = props.ListHeaderComponent ? 1 : 0;
var stickyHeaderIndices = [];
var itemCount = props.sections ? props.sections.reduce(function (v, section) {
stickyHeaderIndices.push(v + offset);
return v + props.getItemCount(section.data) + 2; // Add two for the section header and footer.
}, 0) : 0;
return {
childProps: _objectSpread({}, props, {
renderItem: this._renderItem,
ItemSeparatorComponent: undefined,
// Rendered with renderItem
data: props.sections,
getItemCount: function getItemCount() {
return itemCount;
},
// $FlowFixMe
getItem: function getItem(sections, index) {
return _getItem(props, sections, index);
},
keyExtractor: this._keyExtractor,
onViewableItemsChanged: props.onViewableItemsChanged ? this._onViewableItemsChanged : undefined,
stickyHeaderIndices: props.stickySectionHeadersEnabled ? stickyHeaderIndices : undefined
})
};
};
_proto.render = function render() {
return React.createElement(VirtualizedList, _extends({}, this.state.childProps, {
ref: this._captureRef
}));
};
_proto._subExtractor = function _subExtractor(index) {
var itemIndex = index;
var _this$props = this.props,
getItem = _this$props.getItem,
getItemCount = _this$props.getItemCount,
keyExtractor = _this$props.keyExtractor,
sections = _this$props.sections;
for (var i = 0; i < sections.length; i++) {
var section = sections[i];
var sectionData = section.data;
var key = section.key || String(i);
itemIndex -= 1; // The section adds an item for the header
if (itemIndex >= getItemCount(sectionData) + 1) {
itemIndex -= getItemCount(sectionData) + 1; // The section adds an item for the footer.
} else if (itemIndex === -1) {
return {
section: section,
key: key + ':header',
index: null,
header: true,
trailingSection: sections[i + 1]
};
} else if (itemIndex === getItemCount(sectionData)) {
return {
section: section,
key: key + ':footer',
index: null,
header: false,
trailingSection: sections[i + 1]
};
} else {
var extractor = section.keyExtractor || keyExtractor;
return {
section: section,
key: key + ':' + extractor(getItem(sectionData, itemIndex), itemIndex),
index: itemIndex,
leadingItem: getItem(sectionData, itemIndex - 1),
leadingSection: sections[i - 1],
trailingItem: getItem(sectionData, itemIndex + 1),
trailingSection: sections[i + 1]
};
}
}
};
_proto._getSeparatorComponent = function _getSeparatorComponent(index, info) {
info = info || this._subExtractor(index);
if (!info) {
return null;
}
var ItemSeparatorComponent = info.section.ItemSeparatorComponent || this.props.ItemSeparatorComponent;
var SectionSeparatorComponent = this.props.SectionSeparatorComponent;
var isLastItemInList = index === this.state.childProps.getItemCount() - 1;
var isLastItemInSection = info.index === this.props.getItemCount(info.section.data) - 1;
if (SectionSeparatorComponent && isLastItemInSection) {
return SectionSeparatorComponent;
}
if (ItemSeparatorComponent && !isLastItemInSection && !isLastItemInList) {
return ItemSeparatorComponent;
}
return null;
};
return VirtualizedSectionList;
}(React.PureComponent);
VirtualizedSectionList.defaultProps = _objectSpread({}, VirtualizedList.defaultProps, {
data: []
});
var ItemWithSeparator =
/*#__PURE__*/
function (_React$Component) {
_inheritsLoose(ItemWithSeparator, _React$Component);
function ItemWithSeparator() {
var _this2;
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
_this2 = _React$Component.call.apply(_React$Component, [this].concat(args)) || this;
_this2.state = {
separatorProps: {
highlighted: false,
leadingItem: _this2.props.item,
leadingSection: _this2.props.leadingSection,
section: _this2.props.section,
trailingItem: _this2.props.trailingItem,
trailingSection: _this2.props.trailingSection
},
leadingSeparatorProps: {
highlighted: false,
leadingItem: _this2.props.leadingItem,
leadingSection: _this2.props.leadingSection,
section: _this2.props.section,
trailingItem: _this2.props.item,
trailingSection: _this2.props.trailingSection
}
};
_this2._separators = {
highlight: function highlight() {
['leading', 'trailing'].forEach(function (s) {
return _this2._separators.updateProps(s, {
highlighted: true
});
});
},
unhighlight: function unhighlight() {
['leading', 'trailing'].forEach(function (s) {
return _this2._separators.updateProps(s, {
highlighted: false
});
});
},
updateProps: function updateProps(select, newProps) {
var _this2$props = _this2.props,
LeadingSeparatorComponent = _this2$props.LeadingSeparatorComponent,
cellKey = _this2$props.cellKey,
prevCellKey = _this2$props.prevCellKey;
if (select === 'leading' && LeadingSeparatorComponent != null) {
_this2.setState(function (state) {
return {
leadingSeparatorProps: _objectSpread({}, state.leadingSeparatorProps, {}, newProps)
};
});
} else {
_this2.props.onUpdateSeparator(select === 'leading' && prevCellKey || cellKey, newProps);
}
}
};
return _this2;
}
ItemWithSeparator.getDerivedStateFromProps = function getDerivedStateFromProps(props, prevState) {
return {
separatorProps: _objectSpread({}, prevState.separatorProps, {
leadingItem: props.item,
leadingSection: props.leadingSection,
section: props.section,
trailingItem: props.trailingItem,
trailingSection: props.trailingSection
}),
leadingSeparatorProps: _objectSpread({}, prevState.leadingSeparatorProps, {
leadingItem: props.leadingItem,
leadingSection: props.leadingSection,
section: props.section,
trailingItem: props.item,
trailingSection: props.trailingSection
})
};
};
var _proto2 = ItemWithSeparator.prototype;
_proto2.updateSeparatorProps = function updateSeparatorProps(newProps) {
this.setState(function (state) {
return {
separatorProps: _objectSpread({}, state.separatorProps, {}, newProps)
};
});
};
_proto2.render = function render() {
var _this$props2 = this.props,
LeadingSeparatorComponent = _this$props2.LeadingSeparatorComponent,
SeparatorComponent = _this$props2.SeparatorComponent,
item = _this$props2.item,
index = _this$props2.index,
section = _this$props2.section;
var element = this.props.renderItem({
item: item,
index: index,
section: section,
separators: this._separators
});
var leadingSeparator = LeadingSeparatorComponent && React.createElement(LeadingSeparatorComponent, this.state.leadingSeparatorProps);
var separator = SeparatorComponent && React.createElement(SeparatorComponent, this.state.separatorProps);
return leadingSeparator || separator ?
/* $FlowFixMe(>=0.89.0 site=react_native_fb) This comment suppresses an
* error found when Flow v0.89 was deployed. To see the error, delete
* this comment and run Flow. */
React.createElement(View, null, leadingSeparator, element, separator) : element;
};
return ItemWithSeparator;
}(React.Component);
function _getItem(props, sections, index) {
if (!sections) {
return null;
}
var itemIdx = index - 1;
for (var i = 0; i < sections.length; i++) {
var section = sections[i];
var sectionData = section.data;
var itemCount = props.getItemCount(sectionData);
if (itemIdx === -1 || itemIdx === itemCount) {
// We intend for there to be overflow by one on both ends of the list.
// This will be for headers and footers. When returning a header or footer
// item the section itself is the item.
return section;
} else if (itemIdx < itemCount) {
// If we are in the bounds of the list's data then return the item.
return props.getItem(sectionData, itemIdx);
} else {
itemIdx -= itemCount + 2; // Add two for the header and footer
}
}
return null;
}
export default VirtualizedSectionList;

View File

@ -0,0 +1,81 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*
*/
'use strict';
/*
* @returns {bool} true if different, false if equal
*/
var deepDiffer = function deepDiffer(one, two, maxDepth) {
if (maxDepth === void 0) {
maxDepth = -1;
}
if (maxDepth === 0) {
return true;
}
if (one === two) {
// Short circuit on identical object references instead of traversing them.
return false;
}
if (typeof one === 'function' && typeof two === 'function') {
// We consider all functions equal
return false;
}
if (typeof one !== 'object' || one === null) {
// Primitives can be directly compared
return one !== two;
}
if (typeof two !== 'object' || two === null) {
// We know they are different because the previous case would have triggered
// otherwise.
return true;
}
if (one.constructor !== two.constructor) {
return true;
}
if (Array.isArray(one)) {
// We know two is also an array because the constructors are equal
var len = one.length;
if (two.length !== len) {
return true;
}
for (var ii = 0; ii < len; ii++) {
if (deepDiffer(one[ii], two[ii], maxDepth - 1)) {
return true;
}
}
} else {
for (var key in one) {
if (deepDiffer(one[key], two[key], maxDepth - 1)) {
return true;
}
}
for (var twoKey in two) {
// The only case we haven't checked yet is keys that are in two but aren't
// in one, which means they are different.
if (one[twoKey] === undefined && two[twoKey] !== undefined) {
return true;
}
}
}
return false;
};
export default deepDiffer;

View File

@ -0,0 +1,60 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*
*/
'use strict';
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
import EventSubscription from './EventSubscription';
/**
* EmitterSubscription represents a subscription with listener and context data.
*/
var EmitterSubscription =
/*#__PURE__*/
function (_EventSubscription) {
_inheritsLoose(EmitterSubscription, _EventSubscription);
/**
* @param {EventEmitter} emitter - The event emitter that registered this
* subscription
* @param {EventSubscriptionVendor} subscriber - The subscriber that controls
* this subscription
* @param {function} listener - Function to invoke when the specified event is
* emitted
* @param {*} context - Optional context object to use when invoking the
* listener
*/
function EmitterSubscription(emitter, subscriber, listener, context) {
var _this;
_this = _EventSubscription.call(this, subscriber) || this;
_this.emitter = emitter;
_this.listener = listener;
_this.context = context;
return _this;
}
/**
* Removes this subscription from the emitter that registered it.
* Note: we're overriding the `remove()` method of EventSubscription here
* but deliberately not calling `super.remove()` as the responsibility
* for removing the subscription lies with the EventEmitter.
*/
var _proto = EmitterSubscription.prototype;
_proto.remove = function remove() {
this.emitter.removeSubscription(this);
};
return EmitterSubscription;
}(EventSubscription);
export default EmitterSubscription;

View File

@ -0,0 +1,228 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*
* @typecheck
*/
'use strict';
import EmitterSubscription from './EmitterSubscription';
import EventSubscriptionVendor from './EventSubscriptionVendor';
import invariant from 'fbjs/lib/invariant';
var sparseFilterPredicate = function sparseFilterPredicate() {
return true;
};
/**
* @class EventEmitter
* @description
* An EventEmitter is responsible for managing a set of listeners and publishing
* events to them when it is told that such events happened. In addition to the
* data for the given event it also sends a event control object which allows
* the listeners/handlers to prevent the default behavior of the given event.
*
* The emitter is designed to be generic enough to support all the different
* contexts in which one might want to emit events. It is a simple multicast
* mechanism on top of which extra functionality can be composed. For example, a
* more advanced emitter may use an EventHolder and EventFactory.
*/
var EventEmitter =
/*#__PURE__*/
function () {
/**
* @constructor
*
* @param {EventSubscriptionVendor} subscriber - Optional subscriber instance
* to use. If omitted, a new subscriber will be created for the emitter.
*/
function EventEmitter(subscriber) {
this._subscriber = subscriber || new EventSubscriptionVendor();
}
/**
* Adds a listener to be invoked when events of the specified type are
* emitted. An optional calling context may be provided. The data arguments
* emitted will be passed to the listener function.
*
* TODO: Annotate the listener arg's type. This is tricky because listeners
* can be invoked with varargs.
*
* @param {string} eventType - Name of the event to listen to
* @param {function} listener - Function to invoke when the specified event is
* emitted
* @param {*} context - Optional context object to use when invoking the
* listener
*/
var _proto = EventEmitter.prototype;
_proto.addListener = function addListener(eventType, listener, context) {
return this._subscriber.addSubscription(eventType, new EmitterSubscription(this, this._subscriber, listener, context));
}
/**
* Similar to addListener, except that the listener is removed after it is
* invoked once.
*
* @param {string} eventType - Name of the event to listen to
* @param {function} listener - Function to invoke only once when the
* specified event is emitted
* @param {*} context - Optional context object to use when invoking the
* listener
*/
;
_proto.once = function once(eventType, listener, context) {
var _this = this;
return this.addListener(eventType, function () {
_this.removeCurrentListener();
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
listener.apply(context, args);
});
}
/**
* Removes all of the registered listeners, including those registered as
* listener maps.
*
* @param {?string} eventType - Optional name of the event whose registered
* listeners to remove
*/
;
_proto.removeAllListeners = function removeAllListeners(eventType) {
this._subscriber.removeAllSubscriptions(eventType);
}
/**
* Provides an API that can be called during an eventing cycle to remove the
* last listener that was invoked. This allows a developer to provide an event
* object that can remove the listener (or listener map) during the
* invocation.
*
* If it is called when not inside of an emitting cycle it will throw.
*
* @throws {Error} When called not during an eventing cycle
*
* @example
* var subscription = emitter.addListenerMap({
* someEvent: function(data, event) {
* console.log(data);
* emitter.removeCurrentListener();
* }
* });
*
* emitter.emit('someEvent', 'abc'); // logs 'abc'
* emitter.emit('someEvent', 'def'); // does not log anything
*/
;
_proto.removeCurrentListener = function removeCurrentListener() {
invariant(!!this._currentSubscription, 'Not in an emitting cycle; there is no current subscription');
this.removeSubscription(this._currentSubscription);
}
/**
* Removes a specific subscription. Called by the `remove()` method of the
* subscription itself to ensure any necessary cleanup is performed.
*/
;
_proto.removeSubscription = function removeSubscription(subscription) {
invariant(subscription.emitter === this, 'Subscription does not belong to this emitter.');
this._subscriber.removeSubscription(subscription);
}
/**
* Returns an array of listeners that are currently registered for the given
* event.
*
* @param {string} eventType - Name of the event to query
* @returns {array}
*/
;
_proto.listeners = function listeners(eventType) {
var subscriptions = this._subscriber.getSubscriptionsForType(eventType);
return subscriptions ? subscriptions // We filter out missing entries because the array is sparse.
// "callbackfn is called only for elements of the array which actually
// exist; it is not called for missing elements of the array."
// https://www.ecma-international.org/ecma-262/9.0/index.html#sec-array.prototype.filter
.filter(sparseFilterPredicate).map(function (subscription) {
return subscription.listener;
}) : [];
}
/**
* Emits an event of the given type with the given data. All handlers of that
* particular type will be notified.
*
* @param {string} eventType - Name of the event to emit
* @param {...*} Arbitrary arguments to be passed to each registered listener
*
* @example
* emitter.addListener('someEvent', function(message) {
* console.log(message);
* });
*
* emitter.emit('someEvent', 'abc'); // logs 'abc'
*/
;
_proto.emit = function emit(eventType) {
var subscriptions = this._subscriber.getSubscriptionsForType(eventType);
if (subscriptions) {
for (var i = 0, l = subscriptions.length; i < l; i++) {
var subscription = subscriptions[i]; // The subscription may have been removed during this event loop.
if (subscription && subscription.listener) {
this._currentSubscription = subscription;
subscription.listener.apply(subscription.context, Array.prototype.slice.call(arguments, 1));
}
}
this._currentSubscription = null;
}
}
/**
* Removes the given listener for event of specific type.
*
* @param {string} eventType - Name of the event to emit
* @param {function} listener - Function to invoke when the specified event is
* emitted
*
* @example
* emitter.removeListener('someEvent', function(message) {
* console.log(message);
* }); // removes the listener if already registered
*
*/
;
_proto.removeListener = function removeListener(eventType, listener) {
var subscriptions = this._subscriber.getSubscriptionsForType(eventType);
if (subscriptions) {
for (var i = 0, l = subscriptions.length; i < l; i++) {
var subscription = subscriptions[i]; // The subscription may have been removed during this event loop.
// its listener matches the listener in method parameters
if (subscription && subscription.listener === listener) {
subscription.remove();
}
}
}
};
return EventEmitter;
}();
export default EventEmitter;

View File

@ -0,0 +1,185 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*
*/
'use strict';
/**
* @class EventEmitterWithHolding
* @description
* An EventEmitterWithHolding decorates an event emitter and enables one to
* "hold" or cache events and then have a handler register later to actually
* handle them.
*
* This is separated into its own decorator so that only those who want to use
* the holding functionality have to and others can just use an emitter. Since
* it implements the emitter interface it can also be combined with anything
* that uses an emitter.
*/
var EventEmitterWithHolding =
/*#__PURE__*/
function () {
/**
* @constructor
* @param {object} emitter - The object responsible for emitting the actual
* events.
* @param {object} holder - The event holder that is responsible for holding
* and then emitting held events.
*/
function EventEmitterWithHolding(emitter, holder) {
this._emitter = emitter;
this._eventHolder = holder;
this._currentEventToken = null;
this._emittingHeldEvents = false;
}
/**
* @see EventEmitter#addListener
*/
var _proto = EventEmitterWithHolding.prototype;
_proto.addListener = function addListener(eventType, listener, context) {
return this._emitter.addListener(eventType, listener, context);
}
/**
* @see EventEmitter#once
*/
;
_proto.once = function once(eventType, listener, context) {
return this._emitter.once(eventType, listener, context);
}
/**
* Adds a listener to be invoked when events of the specified type are
* emitted. An optional calling context may be provided. The data arguments
* emitted will be passed to the listener function. In addition to subscribing
* to all subsequent events, this method will also handle any events that have
* already been emitted, held, and not released.
*
* @param {string} eventType - Name of the event to listen to
* @param {function} listener - Function to invoke when the specified event is
* emitted
* @param {*} context - Optional context object to use when invoking the
* listener
*
* @example
* emitter.emitAndHold('someEvent', 'abc');
*
* emitter.addRetroactiveListener('someEvent', function(message) {
* console.log(message);
* }); // logs 'abc'
*/
;
_proto.addRetroactiveListener = function addRetroactiveListener(eventType, listener, context) {
var subscription = this._emitter.addListener(eventType, listener, context);
this._emittingHeldEvents = true;
this._eventHolder.emitToListener(eventType, listener, context);
this._emittingHeldEvents = false;
return subscription;
}
/**
* @see EventEmitter#removeAllListeners
*/
;
_proto.removeAllListeners = function removeAllListeners(eventType) {
this._emitter.removeAllListeners(eventType);
}
/**
* @see EventEmitter#removeCurrentListener
*/
;
_proto.removeCurrentListener = function removeCurrentListener() {
this._emitter.removeCurrentListener();
}
/**
* @see EventEmitter#listeners
*/
;
_proto.listeners = function listeners(eventType)
/* TODO: Annotate return type here */
{
return this._emitter.listeners(eventType);
}
/**
* @see EventEmitter#emit
*/
;
_proto.emit = function emit(eventType) {
var _this$_emitter;
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
(_this$_emitter = this._emitter).emit.apply(_this$_emitter, [eventType].concat(args));
}
/**
* Emits an event of the given type with the given data, and holds that event
* in order to be able to dispatch it to a later subscriber when they say they
* want to handle held events.
*
* @param {string} eventType - Name of the event to emit
* @param {...*} Arbitrary arguments to be passed to each registered listener
*
* @example
* emitter.emitAndHold('someEvent', 'abc');
*
* emitter.addRetroactiveListener('someEvent', function(message) {
* console.log(message);
* }); // logs 'abc'
*/
;
_proto.emitAndHold = function emitAndHold(eventType) {
var _this$_eventHolder, _this$_emitter2;
for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
args[_key2 - 1] = arguments[_key2];
}
this._currentEventToken = (_this$_eventHolder = this._eventHolder).holdEvent.apply(_this$_eventHolder, [eventType].concat(args));
(_this$_emitter2 = this._emitter).emit.apply(_this$_emitter2, [eventType].concat(args));
this._currentEventToken = null;
}
/**
* @see EventHolder#releaseCurrentEvent
*/
;
_proto.releaseCurrentEvent = function releaseCurrentEvent() {
if (this._currentEventToken) {
this._eventHolder.releaseEvent(this._currentEventToken);
} else if (this._emittingHeldEvents) {
this._eventHolder.releaseCurrentEvent();
}
}
/**
* @see EventHolder#releaseEventType
* @param {string} eventType
*/
;
_proto.releaseHeldEventType = function releaseHeldEventType(eventType) {
this._eventHolder.releaseEventType(eventType);
};
return EventEmitterWithHolding;
}();
export default EventEmitterWithHolding;

View File

@ -0,0 +1,137 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*
*/
'use strict';
import invariant from 'fbjs/lib/invariant';
var EventHolder =
/*#__PURE__*/
function () {
function EventHolder() {
this._heldEvents = {};
this._currentEventKey = null;
}
/**
* Holds a given event for processing later.
*
* TODO: Annotate return type better. The structural type of the return here
* is pretty obvious.
*
* @param {string} eventType - Name of the event to hold and later emit
* @param {...*} Arbitrary arguments to be passed to each registered listener
* @return {object} Token that can be used to release the held event
*
* @example
*
* holder.holdEvent({someEvent: 'abc'});
*
* holder.emitToHandler({
* someEvent: function(data, event) {
* console.log(data);
* }
* }); //logs 'abc'
*
*/
var _proto = EventHolder.prototype;
_proto.holdEvent = function holdEvent(eventType) {
this._heldEvents[eventType] = this._heldEvents[eventType] || [];
var eventsOfType = this._heldEvents[eventType];
var key = {
eventType: eventType,
index: eventsOfType.length
};
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
eventsOfType.push(args);
return key;
}
/**
* Emits the held events of the specified type to the given listener.
*
* @param {?string} eventType - Optional name of the events to replay
* @param {function} listener - The listener to which to dispatch the event
* @param {?object} context - Optional context object to use when invoking
* the listener
*/
;
_proto.emitToListener = function emitToListener(eventType, listener, context) {
var _this = this;
var eventsOfType = this._heldEvents[eventType];
if (!eventsOfType) {
return;
}
var origEventKey = this._currentEventKey;
eventsOfType.forEach(function (
/*?array*/
eventHeld,
/*number*/
index) {
if (!eventHeld) {
return;
}
_this._currentEventKey = {
eventType: eventType,
index: index
};
listener.apply(context, eventHeld);
});
this._currentEventKey = origEventKey;
}
/**
* Provides an API that can be called during an eventing cycle to release
* the last event that was invoked, so that it is no longer "held".
*
* If it is called when not inside of an emitting cycle it will throw.
*
* @throws {Error} When called not during an eventing cycle
*/
;
_proto.releaseCurrentEvent = function releaseCurrentEvent() {
invariant(this._currentEventKey !== null, 'Not in an emitting cycle; there is no current event');
this._currentEventKey && this.releaseEvent(this._currentEventKey);
}
/**
* Releases the event corresponding to the handle that was returned when the
* event was first held.
*
* @param {object} token - The token returned from holdEvent
*/
;
_proto.releaseEvent = function releaseEvent(token) {
delete this._heldEvents[token.eventType][token.index];
}
/**
* Releases all events of a certain type.
*
* @param {string} type
*/
;
_proto.releaseEventType = function releaseEventType(type) {
this._heldEvents[type] = [];
};
return EventHolder;
}();
export default EventHolder;

View File

@ -0,0 +1,40 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*
*/
'use strict';
/**
* EventSubscription represents a subscription to a particular event. It can
* remove its own subscription.
*/
var EventSubscription =
/*#__PURE__*/
function () {
/**
* @param {EventSubscriptionVendor} subscriber the subscriber that controls
* this subscription.
*/
function EventSubscription(subscriber) {
this.subscriber = subscriber;
}
/**
* Removes this subscription from the subscriber that controls it.
*/
var _proto = EventSubscription.prototype;
_proto.remove = function remove() {
this.subscriber.removeSubscription(this);
};
return EventSubscription;
}();
export default EventSubscription;

View File

@ -0,0 +1,103 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*
*/
'use strict';
import invariant from 'fbjs/lib/invariant';
/**
* EventSubscriptionVendor stores a set of EventSubscriptions that are
* subscribed to a particular event type.
*/
var EventSubscriptionVendor =
/*#__PURE__*/
function () {
function EventSubscriptionVendor() {
this._subscriptionsForType = {};
this._currentSubscription = null;
}
/**
* Adds a subscription keyed by an event type.
*
* @param {string} eventType
* @param {EventSubscription} subscription
*/
var _proto = EventSubscriptionVendor.prototype;
_proto.addSubscription = function addSubscription(eventType, subscription) {
invariant(subscription.subscriber === this, 'The subscriber of the subscription is incorrectly set.');
if (!this._subscriptionsForType[eventType]) {
this._subscriptionsForType[eventType] = [];
}
var key = this._subscriptionsForType[eventType].length;
this._subscriptionsForType[eventType].push(subscription);
subscription.eventType = eventType;
subscription.key = key;
return subscription;
}
/**
* Removes a bulk set of the subscriptions.
*
* @param {?string} eventType - Optional name of the event type whose
* registered supscriptions to remove, if null remove all subscriptions.
*/
;
_proto.removeAllSubscriptions = function removeAllSubscriptions(eventType) {
if (eventType === undefined) {
this._subscriptionsForType = {};
} else {
delete this._subscriptionsForType[eventType];
}
}
/**
* Removes a specific subscription. Instead of calling this function, call
* `subscription.remove()` directly.
*
* @param {object} subscription
*/
;
_proto.removeSubscription = function removeSubscription(subscription) {
var eventType = subscription.eventType;
var key = subscription.key;
var subscriptionsForType = this._subscriptionsForType[eventType];
if (subscriptionsForType) {
delete subscriptionsForType[key];
}
}
/**
* Returns the array of subscriptions that are currently registered for the
* given event type.
*
* Note: This array can be potentially sparse as subscriptions are deleted
* from it when they are removed.
*
* TODO: This returns a nullable array. wat?
*
* @param {string} eventType
* @returns {?array}
*/
;
_proto.getSubscriptionsForType = function getSubscriptionsForType(eventType) {
return this._subscriptionsForType[eventType];
};
return EventSubscriptionVendor;
}();
export default EventSubscriptionVendor;

View File

@ -0,0 +1,130 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*
*/
'use strict';
var __DEV__ = process.env.NODE_ENV !== 'production';
/**
* EventValidator is designed to validate event types to make it easier to catch
* common mistakes. It accepts a map of all of the different types of events
* that the emitter can emit. Then, if a user attempts to emit an event that is
* not one of those specified types the emitter will throw an error. Also, it
* provides a relatively simple matcher so that if it thinks that you likely
* mistyped the event name it will suggest what you might have meant to type in
* the error message.
*/
var EventValidator = {
/**
* @param {Object} emitter - The object responsible for emitting the actual
* events
* @param {Object} types - The collection of valid types that will be used to
* check for errors
* @return {Object} A new emitter with event type validation
* @example
* const types = {someEvent: true, anotherEvent: true};
* const emitter = EventValidator.addValidation(emitter, types);
*/
addValidation: function addValidation(emitter, types) {
var eventTypes = Object.keys(types);
var emitterWithValidation = Object.create(emitter);
Object.assign(emitterWithValidation, {
emit: function emit(type, a, b, c, d, e, _) {
assertAllowsEventType(type, eventTypes);
return emitter.emit.call(this, type, a, b, c, d, e, _);
}
});
return emitterWithValidation;
}
};
function assertAllowsEventType(type, allowedTypes) {
if (allowedTypes.indexOf(type) === -1) {
throw new TypeError(errorMessageFor(type, allowedTypes));
}
}
function errorMessageFor(type, allowedTypes) {
var message = 'Unknown event type "' + type + '". ';
if (__DEV__) {
message += recommendationFor(type, allowedTypes);
}
message += 'Known event types: ' + allowedTypes.join(', ') + '.';
return message;
} // Allow for good error messages
if (__DEV__) {
var recommendationFor = function recommendationFor(type, allowedTypes) {
var closestTypeRecommendation = closestTypeFor(type, allowedTypes);
if (isCloseEnough(closestTypeRecommendation, type)) {
return 'Did you mean "' + closestTypeRecommendation.type + '"? ';
} else {
return '';
}
};
var closestTypeFor = function closestTypeFor(type, allowedTypes) {
var typeRecommendations = allowedTypes.map(typeRecommendationFor.bind(this, type));
return typeRecommendations.sort(recommendationSort)[0];
};
var typeRecommendationFor = function typeRecommendationFor(type, recommendedType) {
return {
type: recommendedType,
distance: damerauLevenshteinDistance(type, recommendedType)
};
};
var recommendationSort = function recommendationSort(recommendationA, recommendationB) {
if (recommendationA.distance < recommendationB.distance) {
return -1;
} else if (recommendationA.distance > recommendationB.distance) {
return 1;
} else {
return 0;
}
};
var isCloseEnough = function isCloseEnough(closestType, actualType) {
return closestType.distance / actualType.length < 0.334;
};
var damerauLevenshteinDistance = function damerauLevenshteinDistance(a, b) {
var i, j;
var d = [];
for (i = 0; i <= a.length; i++) {
d[i] = [i];
}
for (j = 1; j <= b.length; j++) {
d[0][j] = j;
}
for (i = 1; i <= a.length; i++) {
for (j = 1; j <= b.length; j++) {
var cost = a.charAt(i - 1) === b.charAt(j - 1) ? 0 : 1;
d[i][j] = Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost);
if (i > 1 && j > 1 && a.charAt(i - 1) === b.charAt(j - 2) && a.charAt(i - 2) === b.charAt(j - 1)) {
d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + cost);
}
}
}
return d[a.length][b.length];
};
}
export default EventValidator;

View File

@ -0,0 +1,118 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*
*/
'use strict';
import EventEmitter from './EventEmitter';
import EventEmitterWithHolding from './EventEmitterWithHolding';
import EventHolder from './EventHolder';
import invariant from 'fbjs/lib/invariant';
import keyOf from 'fbjs/lib/keyOf';
var __DEV__ = process.env.NODE_ENV !== 'production';
var TYPES_KEY = keyOf({
__types: true
});
/**
* API to setup an object or constructor to be able to emit data events.
*
* @example
* function Dog() { ...dog stuff... }
* mixInEventEmitter(Dog, {bark: true});
*
* var puppy = new Dog();
* puppy.addListener('bark', function (volume) {
* console.log('Puppy', this, 'barked at volume:', volume);
* });
* puppy.emit('bark', 'quiet');
* // Puppy <puppy> barked at volume: quiet
*
*
* // A "singleton" object may also be commissioned:
*
* var Singleton = {};
* mixInEventEmitter(Singleton, {lonely: true});
* Singleton.emit('lonely', true);
*/
function mixInEventEmitter(cls, types) {
invariant(types, 'Must supply set of valid event types'); // If this is a constructor, write to the prototype, otherwise write to the
// singleton object.
var target = cls.prototype || cls;
invariant(!target.__eventEmitter, 'An active emitter is already mixed in');
var ctor = cls.constructor;
if (ctor) {
invariant(ctor === Object || ctor === Function, 'Mix EventEmitter into a class, not an instance');
} // Keep track of the provided types, union the types if they already exist,
// which allows for prototype subclasses to provide more types.
if (target.hasOwnProperty(TYPES_KEY)) {
Object.assign(target.__types, types);
} else if (target.__types) {
target.__types = Object.assign({}, target.__types, types);
} else {
target.__types = types;
}
Object.assign(target, EventEmitterMixin);
}
var EventEmitterMixin = {
emit: function emit(eventType, a, b, c, d, e, _) {
return this.__getEventEmitter().emit(eventType, a, b, c, d, e, _);
},
emitAndHold: function emitAndHold(eventType, a, b, c, d, e, _) {
return this.__getEventEmitter().emitAndHold(eventType, a, b, c, d, e, _);
},
addListener: function addListener(eventType, listener, context) {
return this.__getEventEmitter().addListener(eventType, listener, context);
},
once: function once(eventType, listener, context) {
return this.__getEventEmitter().once(eventType, listener, context);
},
addRetroactiveListener: function addRetroactiveListener(eventType, listener, context) {
return this.__getEventEmitter().addRetroactiveListener(eventType, listener, context);
},
addListenerMap: function addListenerMap(listenerMap, context) {
return this.__getEventEmitter().addListenerMap(listenerMap, context);
},
addRetroactiveListenerMap: function addRetroactiveListenerMap(listenerMap, context) {
return this.__getEventEmitter().addListenerMap(listenerMap, context);
},
removeAllListeners: function removeAllListeners() {
this.__getEventEmitter().removeAllListeners();
},
removeCurrentListener: function removeCurrentListener() {
this.__getEventEmitter().removeCurrentListener();
},
releaseHeldEventType: function releaseHeldEventType(eventType) {
this.__getEventEmitter().releaseHeldEventType(eventType);
},
__getEventEmitter: function __getEventEmitter() {
if (!this.__eventEmitter) {
var emitter = new EventEmitter();
if (__DEV__) {
var EventValidator = require('./EventValidator').default;
emitter = EventValidator.addValidation(emitter, this.__types);
}
var holder = new EventHolder();
this.__eventEmitter = new EventEmitterWithHolding(emitter, holder);
}
return this.__eventEmitter;
}
};
export default mixInEventEmitter;

View File

@ -0,0 +1,18 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
/**
* Intentional info-level logging for clear separation from ad-hoc console debug logging.
*/
function infoLog() {
var _console;
return (_console = console).log.apply(_console, arguments);
}
export default infoLog;