Prettier React Native Libraries

Reviewed By: sahrens

Differential Revision: D7961488

fbshipit-source-id: 05f9b8b0b91ae77f9040a5321ccc18f7c3c1ce9a
This commit is contained in:
Eli White 2018-05-10 19:06:46 -07:00 committed by Facebook Github Bot
parent 1e2de71290
commit d01ab66b47
301 changed files with 6259 additions and 3781 deletions

View File

@ -4,7 +4,9 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
*/ */
'use strict'; 'use strict';
// TODO: Move this into an ART mode called "serialized" or something // TODO: Move this into an ART mode called "serialized" or something
@ -19,7 +21,6 @@ const CURVE_TO = 3;
const ARC = 4; const ARC = 4;
const SerializablePath = Class(Path, { const SerializablePath = Class(Path, {
initialize: function(path) { initialize: function(path) {
this.reset(); this.reset();
if (path instanceof SerializablePath) { if (path instanceof SerializablePath) {
@ -54,7 +55,18 @@ const SerializablePath = Class(Path, {
onArc: function(sx, sy, ex, ey, cx, cy, rx, ry, sa, ea, ccw, rotation) { onArc: function(sx, sy, ex, ey, cx, cy, rx, ry, sa, ea, ccw, rotation) {
if (rx !== ry || rotation) { if (rx !== ry || rotation) {
return this._arcToBezier( return this._arcToBezier(
sx, sy, ex, ey, cx, cy, rx, ry, sa, ea, ccw, rotation sx,
sy,
ex,
ey,
cx,
cy,
rx,
ry,
sa,
ea,
ccw,
rotation,
); );
} }
this.path.push(ARC, cx, cy, rx, sa, ea, ccw ? 0 : 1); this.path.push(ARC, cx, cy, rx, sa, ea, ccw ? 0 : 1);
@ -66,8 +78,7 @@ const SerializablePath = Class(Path, {
toJSON: function() { toJSON: function() {
return this.path; return this.path;
} },
}); });
module.exports = SerializablePath; module.exports = SerializablePath;

View File

@ -4,7 +4,9 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
*/ */
'use strict'; 'use strict';
const Color = require('art/core/color'); const Color = require('art/core/color');
@ -69,58 +71,57 @@ const SurfaceViewAttributes = merge(ReactNativeViewAttributes.UIView, {
}); });
const NodeAttributes = { const NodeAttributes = {
transform: { diff: arrayDiffer }, transform: {diff: arrayDiffer},
opacity: true, opacity: true,
}; };
const GroupAttributes = merge(NodeAttributes, { const GroupAttributes = merge(NodeAttributes, {
clipping: { diff: arrayDiffer } clipping: {diff: arrayDiffer},
}); });
const RenderableAttributes = merge(NodeAttributes, { const RenderableAttributes = merge(NodeAttributes, {
fill: { diff: arrayDiffer }, fill: {diff: arrayDiffer},
stroke: { diff: arrayDiffer }, stroke: {diff: arrayDiffer},
strokeWidth: true, strokeWidth: true,
strokeCap: true, strokeCap: true,
strokeJoin: true, strokeJoin: true,
strokeDash: { diff: arrayDiffer }, strokeDash: {diff: arrayDiffer},
}); });
const ShapeAttributes = merge(RenderableAttributes, { const ShapeAttributes = merge(RenderableAttributes, {
d: { diff: arrayDiffer }, d: {diff: arrayDiffer},
}); });
const TextAttributes = merge(RenderableAttributes, { const TextAttributes = merge(RenderableAttributes, {
alignment: true, alignment: true,
frame: { diff: fontAndLinesDiffer }, frame: {diff: fontAndLinesDiffer},
path: { diff: arrayDiffer } path: {diff: arrayDiffer},
}); });
// Native Components // Native Components
const NativeSurfaceView = createReactNativeComponentClass('ARTSurfaceView', const NativeSurfaceView = createReactNativeComponentClass(
'ARTSurfaceView',
() => ({ () => ({
validAttributes: SurfaceViewAttributes, validAttributes: SurfaceViewAttributes,
uiViewClassName: 'ARTSurfaceView', uiViewClassName: 'ARTSurfaceView',
})); }),
);
const NativeGroup = createReactNativeComponentClass('ARTGroup', const NativeGroup = createReactNativeComponentClass('ARTGroup', () => ({
() => ({ validAttributes: GroupAttributes,
validAttributes: GroupAttributes, uiViewClassName: 'ARTGroup',
uiViewClassName: 'ARTGroup', }));
}));
const NativeShape = createReactNativeComponentClass('ARTShape', const NativeShape = createReactNativeComponentClass('ARTShape', () => ({
() => ({ validAttributes: ShapeAttributes,
validAttributes: ShapeAttributes, uiViewClassName: 'ARTShape',
uiViewClassName: 'ARTShape', }));
}));
const NativeText = createReactNativeComponentClass('ARTText', const NativeText = createReactNativeComponentClass('ARTText', () => ({
() => ({ validAttributes: TextAttributes,
validAttributes: TextAttributes, uiViewClassName: 'ARTText',
uiViewClassName: 'ARTText', }));
}));
// Utilities // Utilities
@ -145,7 +146,7 @@ class Surface extends React.Component {
}; };
getChildContext() { getChildContext() {
return { isInSurface: true }; return {isInSurface: true};
} }
render() { render() {
@ -153,7 +154,7 @@ class Surface extends React.Component {
const w = extractNumber(props.width, 0); const w = extractNumber(props.width, 0);
const h = extractNumber(props.height, 0); const h = extractNumber(props.height, 0);
return ( return (
<NativeSurfaceView style={[props.style, { width: w, height: h }]}> <NativeSurfaceView style={[props.style, {width: w, height: h}]}>
{this.props.children} {this.props.children}
</NativeSurfaceView> </NativeSurfaceView>
); );
@ -175,10 +176,10 @@ function extractNumber(value, defaultValue) {
const pooledTransform = new Transform(); const pooledTransform = new Transform();
function extractTransform(props) { function extractTransform(props) {
const scaleX = props.scaleX != null ? props.scaleX : const scaleX =
props.scale != null ? props.scale : 1; props.scaleX != null ? props.scaleX : props.scale != null ? props.scale : 1;
const scaleY = props.scaleY != null ? props.scaleY : const scaleY =
props.scale != null ? props.scale : 1; props.scaleY != null ? props.scaleY : props.scale != null ? props.scale : 1;
pooledTransform pooledTransform
.transformTo(1, 0, 0, 1, 0, 0) .transformTo(1, 0, 0, 1, 0, 0)
@ -191,9 +192,12 @@ function extractTransform(props) {
} }
return [ return [
pooledTransform.xx, pooledTransform.yx, pooledTransform.xx,
pooledTransform.xy, pooledTransform.yy, pooledTransform.yx,
pooledTransform.x, pooledTransform.y, pooledTransform.xy,
pooledTransform.yy,
pooledTransform.x,
pooledTransform.y,
]; ];
} }
@ -222,7 +226,7 @@ class Group extends React.Component {
const props = this.props; const props = this.props;
invariant( invariant(
this.context.isInSurface, this.context.isInSurface,
'ART: <Group /> must be a child of a <Surface />' 'ART: <Group /> must be a child of a <Surface />',
); );
return ( return (
<NativeGroup <NativeGroup
@ -299,7 +303,7 @@ function insertOffsetsIntoArray(stops, targetArray, atIndex, multi, reverse) {
} }
} else { } else {
for (const offsetString in stops) { for (const offsetString in stops) {
offsetNumber = (+offsetString) * multi; offsetNumber = +offsetString * multi;
targetArray[atIndex + i] = reverse ? 1 - offsetNumber : offsetNumber; targetArray[atIndex + i] = reverse ? 1 - offsetNumber : offsetNumber;
i++; i++;
} }
@ -370,17 +374,23 @@ function extractColor(color) {
function extractStrokeCap(strokeCap) { function extractStrokeCap(strokeCap) {
switch (strokeCap) { switch (strokeCap) {
case 'butt': return 0; case 'butt':
case 'square': return 2; return 0;
default: return 1; // round case 'square':
return 2;
default:
return 1; // round
} }
} }
function extractStrokeJoin(strokeJoin) { function extractStrokeJoin(strokeJoin) {
switch (strokeJoin) { switch (strokeJoin) {
case 'miter': return 0; case 'miter':
case 'bevel': return 2; return 0;
default: return 1; // round case 'bevel':
return 2;
default:
return 1; // round
} }
} }
@ -404,7 +414,6 @@ class Shape extends React.Component {
strokeJoin={extractStrokeJoin(props.strokeJoin)} strokeJoin={extractStrokeJoin(props.strokeJoin)}
strokeWidth={extractNumber(props.strokeWidth, 1)} strokeWidth={extractNumber(props.strokeWidth, 1)}
transform={extractTransform(props)} transform={extractTransform(props)}
d={d} d={d}
/> />
); );
@ -422,9 +431,10 @@ function extractSingleFontFamily(fontFamilyString) {
// ART on the web allows for multiple font-families to be specified. // ART on the web allows for multiple font-families to be specified.
// For compatibility, we extract the first font-family, hoping // For compatibility, we extract the first font-family, hoping
// we'll get a match. // we'll get a match.
return fontFamilyString.split(',')[0] return fontFamilyString
.replace(fontFamilyPrefix, '') .split(',')[0]
.replace(fontFamilySuffix, ''); .replace(fontFamilyPrefix, '')
.replace(fontFamilySuffix, '');
} }
function parseFontString(font) { function parseFontString(font) {
@ -458,7 +468,8 @@ function extractFont(font) {
} }
const fontFamily = extractSingleFontFamily(font.fontFamily); const fontFamily = extractSingleFontFamily(font.fontFamily);
const fontSize = +font.fontSize || 12; const fontSize = +font.fontSize || 12;
const fontWeight = font.fontWeight != null ? font.fontWeight.toString() : '400'; const fontWeight =
font.fontWeight != null ? font.fontWeight.toString() : '400';
return { return {
// Normalize // Normalize
fontFamily: fontFamily, fontFamily: fontFamily,
@ -470,7 +481,7 @@ function extractFont(font) {
const newLine = /\n/g; const newLine = /\n/g;
function extractFontAndLines(font, text) { function extractFontAndLines(font, text) {
return { font: extractFont(font), lines: text.split(newLine) }; return {font: extractFont(font), lines: text.split(newLine)};
} }
function extractAlignment(alignment) { function extractAlignment(alignment) {
@ -488,10 +499,12 @@ class Text extends React.Component {
render() { render() {
const props = this.props; const props = this.props;
const path = props.path; const path = props.path;
const textPath = path ? (path instanceof Path ? path : new Path(path)).toJSON() : null; const textPath = path
? (path instanceof Path ? path : new Path(path)).toJSON()
: null;
const textFrame = extractFontAndLines( const textFrame = extractFontAndLines(
props.font, props.font,
childrenAsString(props.children) childrenAsString(props.children),
); );
return ( return (
<NativeText <NativeText
@ -503,7 +516,6 @@ class Text extends React.Component {
strokeJoin={extractStrokeJoin(props.strokeJoin)} strokeJoin={extractStrokeJoin(props.strokeJoin)}
strokeWidth={extractNumber(props.strokeWidth, 1)} strokeWidth={extractNumber(props.strokeWidth, 1)}
transform={extractTransform(props)} transform={extractTransform(props)}
alignment={extractAlignment(props.alignment)} alignment={extractAlignment(props.alignment)}
frame={textFrame} frame={textFrame}
path={textPath} path={textPath}
@ -518,13 +530,14 @@ function LinearGradient(stops, x1, y1, x2, y2) {
const type = LINEAR_GRADIENT; const type = LINEAR_GRADIENT;
if (arguments.length < 5) { if (arguments.length < 5) {
const angle = ((x1 == null) ? 270 : x1) * Math.PI / 180; const angle = (x1 == null ? 270 : x1) * Math.PI / 180;
let x = Math.cos(angle); let x = Math.cos(angle);
let y = -Math.sin(angle); let y = -Math.sin(angle);
const l = (Math.abs(x) + Math.abs(y)) / 2; const l = (Math.abs(x) + Math.abs(y)) / 2;
x *= l; y *= l; x *= l;
y *= l;
x1 = 0.5 - x; x1 = 0.5 - x;
x2 = 0.5 + x; x2 = 0.5 + x;

View File

@ -4,15 +4,17 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const AlertIOS = require('AlertIOS'); const AlertIOS = require('AlertIOS');
const NativeModules = require('NativeModules'); const NativeModules = require('NativeModules');
const Platform = require('Platform'); const Platform = require('Platform');
import type { AlertType, AlertButtonStyle } from 'AlertIOS'; import type {AlertType, AlertButtonStyle} from 'AlertIOS';
export type Buttons = Array<{ export type Buttons = Array<{
text?: string, text?: string,
@ -31,7 +33,6 @@ type Options = {
* See http://facebook.github.io/react-native/docs/alert.html * See http://facebook.github.io/react-native/docs/alert.html
*/ */
class Alert { class Alert {
/** /**
* Launches an alert dialog with the specified title and message. * Launches an alert dialog with the specified title and message.
* *
@ -46,7 +47,9 @@ class Alert {
): void { ): void {
if (Platform.OS === 'ios') { if (Platform.OS === 'ios') {
if (typeof type !== 'undefined') { if (typeof type !== 'undefined') {
console.warn('Alert.alert() with a 5th "type" parameter is deprecated and will be removed. Use AlertIOS.prompt() instead.'); console.warn(
'Alert.alert() with a 5th "type" parameter is deprecated and will be removed. Use AlertIOS.prompt() instead.',
);
AlertIOS.alert(title, message, buttons, type); AlertIOS.alert(title, message, buttons, type);
return; return;
} }
@ -61,7 +64,6 @@ class Alert {
* Wrapper around the Android native module. * Wrapper around the Android native module.
*/ */
class AlertAndroid { class AlertAndroid {
static alert( static alert(
title: ?string, title: ?string,
message?: ?string, message?: ?string,
@ -78,35 +80,41 @@ class AlertAndroid {
} }
// At most three buttons (neutral, negative, positive). Ignore rest. // At most three buttons (neutral, negative, positive). Ignore rest.
// The text 'OK' should be probably localized. iOS Alert does that in native. // The text 'OK' should be probably localized. iOS Alert does that in native.
const validButtons: Buttons = buttons ? buttons.slice(0, 3) : [{text: 'OK'}]; const validButtons: Buttons = buttons
? buttons.slice(0, 3)
: [{text: 'OK'}];
const buttonPositive = validButtons.pop(); const buttonPositive = validButtons.pop();
const buttonNegative = validButtons.pop(); const buttonNegative = validButtons.pop();
const buttonNeutral = validButtons.pop(); const buttonNeutral = validButtons.pop();
if (buttonNeutral) { if (buttonNeutral) {
config = {...config, buttonNeutral: buttonNeutral.text || '' }; config = {...config, buttonNeutral: buttonNeutral.text || ''};
} }
if (buttonNegative) { if (buttonNegative) {
config = {...config, buttonNegative: buttonNegative.text || '' }; config = {...config, buttonNegative: buttonNegative.text || ''};
} }
if (buttonPositive) { if (buttonPositive) {
config = {...config, buttonPositive: buttonPositive.text || '' }; config = {...config, buttonPositive: buttonPositive.text || ''};
} }
NativeModules.DialogManagerAndroid.showAlert( NativeModules.DialogManagerAndroid.showAlert(
config, config,
(errorMessage) => console.warn(errorMessage), errorMessage => console.warn(errorMessage),
(action, buttonKey) => { (action, buttonKey) => {
if (action === NativeModules.DialogManagerAndroid.buttonClicked) { if (action === NativeModules.DialogManagerAndroid.buttonClicked) {
if (buttonKey === NativeModules.DialogManagerAndroid.buttonNeutral) { if (buttonKey === NativeModules.DialogManagerAndroid.buttonNeutral) {
buttonNeutral.onPress && buttonNeutral.onPress(); buttonNeutral.onPress && buttonNeutral.onPress();
} else if (buttonKey === NativeModules.DialogManagerAndroid.buttonNegative) { } else if (
buttonKey === NativeModules.DialogManagerAndroid.buttonNegative
) {
buttonNegative.onPress && buttonNegative.onPress(); buttonNegative.onPress && buttonNegative.onPress();
} else if (buttonKey === NativeModules.DialogManagerAndroid.buttonPositive) { } else if (
buttonKey === NativeModules.DialogManagerAndroid.buttonPositive
) {
buttonPositive.onPress && buttonPositive.onPress(); buttonPositive.onPress && buttonPositive.onPress();
} }
} else if (action === NativeModules.DialogManagerAndroid.dismissed) { } else if (action === NativeModules.DialogManagerAndroid.dismissed) {
options && options.onDismiss && options.onDismiss(); options && options.onDismiss && options.onDismiss();
} }
} },
); );
} }
} }

View File

@ -4,9 +4,11 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
* @jsdoc * @jsdoc
*/ */
'use strict'; 'use strict';
const RCTAlertManager = require('NativeModules').AlertManager; const RCTAlertManager = require('NativeModules').AlertManager;
@ -18,7 +20,7 @@ export type AlertType = $Enum<{
/** /**
* Default alert with no inputs * Default alert with no inputs
*/ */
'default': string, default: string,
/** /**
* Plain text input alert * Plain text input alert
*/ */
@ -40,15 +42,15 @@ export type AlertButtonStyle = $Enum<{
/** /**
* Default button style * Default button style
*/ */
'default': string, default: string,
/** /**
* Cancel button style * Cancel button style
*/ */
'cancel': string, cancel: string,
/** /**
* Destructive button style * Destructive button style
*/ */
'destructive': string, destructive: string,
}>; }>;
/** /**
@ -87,11 +89,13 @@ class AlertIOS {
static alert( static alert(
title: ?string, title: ?string,
message?: ?string, message?: ?string,
callbackOrButtons?: ?(() => void) | ButtonsArray, callbackOrButtons?: ?((() => void) | ButtonsArray),
type?: AlertType, type?: AlertType,
): void { ): void {
if (typeof type !== 'undefined') { if (typeof type !== 'undefined') {
console.warn('AlertIOS.alert() with a 4th "type" parameter is deprecated and will be removed. Use AlertIOS.prompt() instead.'); console.warn(
'AlertIOS.alert() with a 4th "type" parameter is deprecated and will be removed. Use AlertIOS.prompt() instead.',
);
this.prompt(title, message, callbackOrButtons, type); this.prompt(title, message, callbackOrButtons, type);
return; return;
} }
@ -106,26 +110,30 @@ class AlertIOS {
static prompt( static prompt(
title: ?string, title: ?string,
message?: ?string, message?: ?string,
callbackOrButtons?: ?((text: string) => void) | ButtonsArray, callbackOrButtons?: ?(((text: string) => void) | ButtonsArray),
type?: ?AlertType = 'plain-text', type?: ?AlertType = 'plain-text',
defaultValue?: string, defaultValue?: string,
keyboardType?: string keyboardType?: string,
): void { ): void {
if (typeof type === 'function') { if (typeof type === 'function') {
console.warn( console.warn(
'You passed a callback function as the "type" argument to AlertIOS.prompt(). React Native is ' + 'You passed a callback function as the "type" argument to AlertIOS.prompt(). React Native is ' +
'assuming you want to use the deprecated AlertIOS.prompt(title, defaultValue, buttons, callback) ' + 'assuming you want to use the deprecated AlertIOS.prompt(title, defaultValue, buttons, callback) ' +
'signature. The current signature is AlertIOS.prompt(title, message, callbackOrButtons, type, defaultValue, ' + 'signature. The current signature is AlertIOS.prompt(title, message, callbackOrButtons, type, defaultValue, ' +
'keyboardType) and the old syntax will be removed in a future version.'); 'keyboardType) and the old syntax will be removed in a future version.',
);
const callback = type; const callback = type;
RCTAlertManager.alertWithArgs({ RCTAlertManager.alertWithArgs(
title: title || '', {
type: 'plain-text', title: title || '',
defaultValue: message, type: 'plain-text',
}, (id, value) => { defaultValue: message,
callback(value); },
}); (id, value) => {
callback(value);
},
);
return; return;
} }
@ -135,8 +143,7 @@ class AlertIOS {
let destructiveButtonKey; let destructiveButtonKey;
if (typeof callbackOrButtons === 'function') { if (typeof callbackOrButtons === 'function') {
callbacks = [callbackOrButtons]; callbacks = [callbackOrButtons];
} } else if (callbackOrButtons instanceof Array) {
else if (callbackOrButtons instanceof Array) {
callbackOrButtons.forEach((btn, index) => { callbackOrButtons.forEach((btn, index) => {
callbacks[index] = btn.onPress; callbacks[index] = btn.onPress;
if (btn.style === 'cancel') { if (btn.style === 'cancel') {
@ -152,19 +159,22 @@ class AlertIOS {
}); });
} }
RCTAlertManager.alertWithArgs({ RCTAlertManager.alertWithArgs(
title: title || '', {
message: message || undefined, title: title || '',
buttons, message: message || undefined,
type: type || undefined, buttons,
defaultValue, type: type || undefined,
cancelButtonKey, defaultValue,
destructiveButtonKey, cancelButtonKey,
keyboardType, destructiveButtonKey,
}, (id, value) => { keyboardType,
const cb = callbacks[id]; },
cb && cb(value); (id, value) => {
}); const cb = callbacks[id];
cb && cb(value);
},
);
} }
} }

View File

@ -4,7 +4,9 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
*/ * @format
*/
'use strict'; 'use strict';
const NativeModules = require('NativeModules'); const NativeModules = require('NativeModules');
@ -15,8 +17,9 @@ module.exports = {
alertWithArgs: function(args, callback) { alertWithArgs: function(args, callback) {
// TODO(5998984): Polyfill it correctly with DialogManagerAndroid // TODO(5998984): Polyfill it correctly with DialogManagerAndroid
NativeModules.DialogManagerAndroid.showAlert( NativeModules.DialogManagerAndroid.showAlert(
args, args,
emptyCallback, emptyCallback,
callback || emptyCallback); callback || emptyCallback,
);
}, },
}; };

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const RCTAlertManager = require('NativeModules').AlertManager; const RCTAlertManager = require('NativeModules').AlertManager;

View File

@ -3,6 +3,8 @@
* *
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*
* @format
*/ */
'use strict'; 'use strict';
@ -20,58 +22,52 @@ var objectAssign = require('object-assign');
var runSequence = require('run-sequence'); var runSequence = require('run-sequence');
var webpackStream = require('webpack-stream'); var webpackStream = require('webpack-stream');
var DEVELOPMENT_HEADER = [ var DEVELOPMENT_HEADER =
'/**', ['/**', ' * Animated v<%= version %>', ' */'].join('\n') + '\n';
' * Animated v<%= version %>', var PRODUCTION_HEADER =
' */' [
].join('\n') + '\n'; '/**',
var PRODUCTION_HEADER = [ ' * Animated v<%= version %>',
'/**', ' *',
' * Animated v<%= version %>', ' * Copyright (c) 2013-present, Facebook, Inc.',
' *', ' *',
' * 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.',
' * This source code is licensed under the MIT license found in the', ' */',
' * LICENSE file in the root directory of this source tree.', ].join('\n') + '\n';
' */'
].join('\n') + '\n';
var babelOpts = { var babelOpts = {
nonStandard: true, nonStandard: true,
loose: [ loose: ['es6.classes'],
'es6.classes'
],
stage: 1, stage: 1,
plugins: [babelPluginDEV, babelPluginModules], plugins: [babelPluginDEV, babelPluginModules],
_moduleMap: objectAssign({}, require('fbjs/module-map'), { _moduleMap: objectAssign({}, require('fbjs/module-map'), {
'React': 'react', React: 'react',
}) }),
}; };
var buildDist = function(opts) { var buildDist = function(opts) {
var webpackOpts = { var webpackOpts = {
debug: opts.debug, debug: opts.debug,
externals: { externals: {
'react': 'React', react: 'React',
}, },
module: { module: {
loaders: [ loaders: [{test: /\.js$/, loader: 'babel'}],
{test: /\.js$/, loader: 'babel'}
],
}, },
output: { output: {
filename: opts.output, filename: opts.output,
library: 'Animated' library: 'Animated',
}, },
plugins: [ plugins: [
new webpackStream.webpack.DefinePlugin({ new webpackStream.webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify( 'process.env.NODE_ENV': JSON.stringify(
opts.debug ? 'development' : 'production' opts.debug ? 'development' : 'production',
), ),
}), }),
new webpackStream.webpack.optimize.OccurenceOrderPlugin(), new webpackStream.webpack.optimize.OccurenceOrderPlugin(),
new webpackStream.webpack.optimize.DedupePlugin() new webpackStream.webpack.optimize.DedupePlugin(),
] ],
}; };
if (!opts.debug) { if (!opts.debug) {
webpackOpts.plugins.push( webpackOpts.plugins.push(
@ -79,9 +75,9 @@ var buildDist = function(opts) {
compress: { compress: {
hoist_vars: true, hoist_vars: true,
screw_ie8: true, screw_ie8: true,
warnings: false warnings: false,
} },
}) }),
); );
} }
return webpackStream(webpackOpts, null, function(err, stats) { return webpackStream(webpackOpts, null, function(err, stats) {
@ -101,7 +97,7 @@ var paths = {
src: [ src: [
'*src/**/*.js', '*src/**/*.js',
'!src/**/__tests__/**/*.js', '!src/**/__tests__/**/*.js',
'!src/**/__mocks__/**/*.js' '!src/**/__mocks__/**/*.js',
], ],
}; };
@ -117,32 +113,36 @@ gulp.task('modules', function() {
.pipe(gulp.dest(paths.lib)); .pipe(gulp.dest(paths.lib));
}); });
gulp.task('dist', ['modules'], function () { gulp.task('dist', ['modules'], function() {
var distOpts = { var distOpts = {
debug: true, debug: true,
output: 'animated.js' output: 'animated.js',
}; };
return gulp return gulp
.src(paths.entry) .src(paths.entry)
.pipe(buildDist(distOpts)) .pipe(buildDist(distOpts))
.pipe(derequire()) .pipe(derequire())
.pipe(header(DEVELOPMENT_HEADER, { .pipe(
version: process.env.npm_package_version header(DEVELOPMENT_HEADER, {
})) version: process.env.npm_package_version,
}),
)
.pipe(gulp.dest(paths.dist)); .pipe(gulp.dest(paths.dist));
}); });
gulp.task('dist:min', ['modules'], function () { gulp.task('dist:min', ['modules'], function() {
var distOpts = { var distOpts = {
debug: false, debug: false,
output: 'animated.min.js' output: 'animated.min.js',
}; };
return gulp return gulp
.src(paths.entry) .src(paths.entry)
.pipe(buildDist(distOpts)) .pipe(buildDist(distOpts))
.pipe(header(PRODUCTION_HEADER, { .pipe(
version: process.env.npm_package_version header(PRODUCTION_HEADER, {
})) version: process.env.npm_package_version,
}),
)
.pipe(gulp.dest(paths.dist)); .pipe(gulp.dest(paths.dist));
}); });

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const AnimatedImplementation = require('AnimatedImplementation'); const AnimatedImplementation = require('AnimatedImplementation');

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
let ease; let ease;
@ -162,7 +164,7 @@ class Easing {
*/ */
static elastic(bounciness: number = 1): (t: number) => number { static elastic(bounciness: number = 1): (t: number) => number {
const p = bounciness * Math.PI; const p = bounciness * Math.PI;
return (t) => 1 - Math.pow(Math.cos(t * Math.PI / 2), 3) * Math.cos(t * p); return t => 1 - Math.pow(Math.cos(t * Math.PI / 2), 3) * Math.cos(t * p);
} }
/** /**
@ -177,7 +179,7 @@ class Easing {
if (s === undefined) { if (s === undefined) {
s = 1.70158; s = 1.70158;
} }
return (t) => t * t * ((s + 1) * t - s); return t => t * t * ((s + 1) * t - s);
} }
/** /**
@ -215,7 +217,7 @@ class Easing {
x1: number, x1: number,
y1: number, y1: number,
x2: number, x2: number,
y2: number y2: number,
): (t: number) => number { ): (t: number) => number {
const _bezier = require('bezier'); const _bezier = require('bezier');
return _bezier(x1, y1, x2, y2); return _bezier(x1, y1, x2, y2);
@ -224,19 +226,15 @@ class Easing {
/** /**
* Runs an easing function forwards. * Runs an easing function forwards.
*/ */
static in( static in(easing: (t: number) => number): (t: number) => number {
easing: (t: number) => number,
): (t: number) => number {
return easing; return easing;
} }
/** /**
* Runs an easing function backwards. * Runs an easing function backwards.
*/ */
static out( static out(easing: (t: number) => number): (t: number) => number {
easing: (t: number) => number, return t => 1 - easing(1 - t);
): (t: number) => number {
return (t) => 1 - easing(1 - t);
} }
/** /**
@ -244,10 +242,8 @@ class Easing {
* forwards for half of the duration, then backwards for the rest of the * forwards for half of the duration, then backwards for the rest of the
* duration. * duration.
*/ */
static inOut( static inOut(easing: (t: number) => number): (t: number) => number {
easing: (t: number) => number, return t => {
): (t: number) => number {
return (t) => {
if (t < 0.5) { if (t < 0.5) {
return easing(t * 2) / 2; return easing(t * 2) / 2;
} }

View File

@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
@ -41,7 +42,7 @@ function fromBouncinessAndSpeed(
} }
function projectNormal(n, start, end) { function projectNormal(n, start, end) {
return start + (n * (end - start)); return start + n * (end - start);
} }
function linearInterpolation(t, start, end) { function linearInterpolation(t, start, end) {
@ -53,18 +54,20 @@ function fromBouncinessAndSpeed(
} }
function b3Friction1(x) { function b3Friction1(x) {
return (0.0007 * Math.pow(x, 3)) - return 0.0007 * Math.pow(x, 3) - 0.031 * Math.pow(x, 2) + 0.64 * x + 1.28;
(0.031 * Math.pow(x, 2)) + 0.64 * x + 1.28;
} }
function b3Friction2(x) { function b3Friction2(x) {
return (0.000044 * Math.pow(x, 3)) - return 0.000044 * Math.pow(x, 3) - 0.006 * Math.pow(x, 2) + 0.36 * x + 2;
(0.006 * Math.pow(x, 2)) + 0.36 * x + 2;
} }
function b3Friction3(x) { function b3Friction3(x) {
return (0.00000045 * Math.pow(x, 3)) - return (
(0.000332 * Math.pow(x, 2)) + 0.1078 * x + 5.84; 0.00000045 * Math.pow(x, 3) -
0.000332 * Math.pow(x, 2) +
0.1078 * x +
5.84
);
} }
function b3Nobounce(tension) { function b3Nobounce(tension) {
@ -84,7 +87,7 @@ function fromBouncinessAndSpeed(
const bouncyFriction = quadraticOutInterpolation( const bouncyFriction = quadraticOutInterpolation(
b, b,
b3Nobounce(bouncyTension), b3Nobounce(bouncyTension),
0.01 0.01,
); );
return { return {

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @emails oncall+react_native * @emails oncall+react_native
*/ */
'use strict'; 'use strict';
let Animated = require('Animated'); let Animated = require('Animated');
@ -15,29 +17,33 @@ describe('Animated tests', () => {
}); });
describe('Animated', () => { describe('Animated', () => {
it('works end to end', () => { it('works end to end', () => {
const anim = new Animated.Value(0); const anim = new Animated.Value(0);
const callback = jest.fn(); const callback = jest.fn();
const node = new Animated.__PropsOnlyForTests({ const node = new Animated.__PropsOnlyForTests(
style: { {
backgroundColor: 'red', style: {
opacity: anim, backgroundColor: 'red',
transform: [ opacity: anim,
{translateX: anim.interpolate({ transform: [
inputRange: [0, 1], {
outputRange: [100, 200], translateX: anim.interpolate({
})}, inputRange: [0, 1],
{scale: anim}, outputRange: [100, 200],
], }),
shadowOffset: { },
width: anim, {scale: anim},
height: anim, ],
shadowOffset: {
width: anim,
height: anim,
},
}, },
} },
}, callback); callback,
);
expect(anim.__getChildren().length).toBe(3); expect(anim.__getChildren().length).toBe(3);
@ -45,10 +51,7 @@ describe('Animated tests', () => {
style: { style: {
backgroundColor: 'red', backgroundColor: 'red',
opacity: 0, opacity: 0,
transform: [ transform: [{translateX: 100}, {scale: 0}],
{translateX: 100},
{scale: 0},
],
shadowOffset: { shadowOffset: {
width: 0, width: 0,
height: 0, height: 0,
@ -64,10 +67,7 @@ describe('Animated tests', () => {
style: { style: {
backgroundColor: 'red', backgroundColor: 'red',
opacity: 0.5, opacity: 0.5,
transform: [ transform: [{translateX: 150}, {scale: 0.5}],
{translateX: 150},
{scale: 0.5},
],
shadowOffset: { shadowOffset: {
width: 0.5, width: 0.5,
height: 0.5, height: 0.5,
@ -107,7 +107,6 @@ describe('Animated tests', () => {
expect(anim.__detach).toBeCalled(); expect(anim.__detach).toBeCalled();
}); });
it('stops animation when detached', () => { it('stops animation when detached', () => {
const anim = new Animated.Value(0); const anim = new Animated.Value(0);
const callback = jest.fn(); const callback = jest.fn();
@ -141,7 +140,8 @@ describe('Animated tests', () => {
anim.addListener(listener); anim.addListener(listener);
Animated.spring(anim, {toValue: 15}).start(); Animated.spring(anim, {toValue: 15}).start();
jest.runAllTimers(); jest.runAllTimers();
const lastValue = listener.mock.calls[listener.mock.calls.length - 2][0].value; const lastValue =
listener.mock.calls[listener.mock.calls.length - 2][0].value;
expect(lastValue).not.toBe(15); expect(lastValue).not.toBe(15);
expect(lastValue).toBeCloseTo(15); expect(lastValue).toBeCloseTo(15);
expect(anim.__getValue()).toBe(15); expect(anim.__getValue()).toBe(15);
@ -151,9 +151,14 @@ describe('Animated tests', () => {
const anim = new Animated.Value(0); const anim = new Animated.Value(0);
const listener = jest.fn(); const listener = jest.fn();
anim.addListener(listener); anim.addListener(listener);
Animated.spring(anim, {stiffness: 8000, damping: 2000, toValue: 15}).start(); Animated.spring(anim, {
stiffness: 8000,
damping: 2000,
toValue: 15,
}).start();
jest.runAllTimers(); jest.runAllTimers();
const lastValue = listener.mock.calls[listener.mock.calls.length - 2][0].value; const lastValue =
listener.mock.calls[listener.mock.calls.length - 2][0].value;
expect(lastValue).not.toBe(15); expect(lastValue).not.toBe(15);
expect(lastValue).toBeCloseTo(15); expect(lastValue).toBeCloseTo(15);
expect(anim.__getValue()).toBe(15); expect(anim.__getValue()).toBe(15);
@ -164,9 +169,7 @@ describe('Animated tests', () => {
}); });
}); });
describe('Animated Sequence', () => { describe('Animated Sequence', () => {
it('works with an empty sequence', () => { it('works with an empty sequence', () => {
const cb = jest.fn(); const cb = jest.fn();
Animated.sequence([]).start(cb); Animated.sequence([]).start(cb);
@ -232,9 +235,12 @@ describe('Animated tests', () => {
}); });
describe('Animated Loop', () => { describe('Animated Loop', () => {
it('loops indefinitely if config not specified', () => { it('loops indefinitely if config not specified', () => {
const animation = {start: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; const animation = {
start: jest.fn(),
reset: jest.fn(),
_isUsingNativeDriver: () => false,
};
const cb = jest.fn(); const cb = jest.fn();
const loop = Animated.loop(animation); const loop = Animated.loop(animation);
@ -261,10 +267,14 @@ describe('Animated tests', () => {
}); });
it('loops indefinitely if iterations is -1', () => { it('loops indefinitely if iterations is -1', () => {
const animation = {start: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; const animation = {
start: jest.fn(),
reset: jest.fn(),
_isUsingNativeDriver: () => false,
};
const cb = jest.fn(); const cb = jest.fn();
const loop = Animated.loop(animation, { iterations: -1 }); const loop = Animated.loop(animation, {iterations: -1});
expect(animation.start).not.toBeCalled(); expect(animation.start).not.toBeCalled();
@ -288,10 +298,14 @@ describe('Animated tests', () => {
}); });
it('loops indefinitely if iterations not specified', () => { it('loops indefinitely if iterations not specified', () => {
const animation = {start: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; const animation = {
start: jest.fn(),
reset: jest.fn(),
_isUsingNativeDriver: () => false,
};
const cb = jest.fn(); const cb = jest.fn();
const loop = Animated.loop(animation, { anotherKey: 'value' }); const loop = Animated.loop(animation, {anotherKey: 'value'});
expect(animation.start).not.toBeCalled(); expect(animation.start).not.toBeCalled();
@ -315,10 +329,14 @@ describe('Animated tests', () => {
}); });
it('loops three times if iterations is 3', () => { it('loops three times if iterations is 3', () => {
const animation = {start: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; const animation = {
start: jest.fn(),
reset: jest.fn(),
_isUsingNativeDriver: () => false,
};
const cb = jest.fn(); const cb = jest.fn();
const loop = Animated.loop(animation, { iterations: 3 }); const loop = Animated.loop(animation, {iterations: 3});
expect(animation.start).not.toBeCalled(); expect(animation.start).not.toBeCalled();
@ -342,10 +360,14 @@ describe('Animated tests', () => {
}); });
it('does not loop if iterations is 1', () => { it('does not loop if iterations is 1', () => {
const animation = {start: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; const animation = {
start: jest.fn(),
reset: jest.fn(),
_isUsingNativeDriver: () => false,
};
const cb = jest.fn(); const cb = jest.fn();
const loop = Animated.loop(animation, { iterations: 1 }); const loop = Animated.loop(animation, {iterations: 1});
expect(animation.start).not.toBeCalled(); expect(animation.start).not.toBeCalled();
@ -359,10 +381,14 @@ describe('Animated tests', () => {
}); });
it('does not animate if iterations is 0', () => { it('does not animate if iterations is 0', () => {
const animation = {start: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; const animation = {
start: jest.fn(),
reset: jest.fn(),
_isUsingNativeDriver: () => false,
};
const cb = jest.fn(); const cb = jest.fn();
const loop = Animated.loop(animation, { iterations: 0 }); const loop = Animated.loop(animation, {iterations: 0});
expect(animation.start).not.toBeCalled(); expect(animation.start).not.toBeCalled();
@ -373,7 +399,11 @@ describe('Animated tests', () => {
}); });
it('supports interrupting an indefinite loop', () => { it('supports interrupting an indefinite loop', () => {
const animation = {start: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; const animation = {
start: jest.fn(),
reset: jest.fn(),
_isUsingNativeDriver: () => false,
};
const cb = jest.fn(); const cb = jest.fn();
Animated.loop(animation).start(cb); Animated.loop(animation).start(cb);
@ -391,7 +421,12 @@ describe('Animated tests', () => {
}); });
it('supports stopping loop', () => { it('supports stopping loop', () => {
const animation = {start: jest.fn(), stop: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; const animation = {
start: jest.fn(),
stop: jest.fn(),
reset: jest.fn(),
_isUsingNativeDriver: () => false,
};
const cb = jest.fn(); const cb = jest.fn();
const loop = Animated.loop(animation); const loop = Animated.loop(animation);
@ -409,7 +444,6 @@ describe('Animated tests', () => {
}); });
describe('Animated Parallel', () => { describe('Animated Parallel', () => {
it('works with an empty parallel', () => { it('works with an empty parallel', () => {
const cb = jest.fn(); const cb = jest.fn();
Animated.parallel([]).start(cb); Animated.parallel([]).start(cb);
@ -470,7 +504,6 @@ describe('Animated tests', () => {
expect(cb).toBeCalledWith({finished: false}); expect(cb).toBeCalledWith({finished: false});
}); });
it('does not call stop more than once when stopping', () => { it('does not call stop more than once when stopping', () => {
const anim1 = {start: jest.fn(), stop: jest.fn()}; const anim1 = {start: jest.fn(), stop: jest.fn()};
const anim2 = {start: jest.fn(), stop: jest.fn()}; const anim2 = {start: jest.fn(), stop: jest.fn()};
@ -504,10 +537,7 @@ describe('Animated tests', () => {
it('should call anim after delay in sequence', () => { it('should call anim after delay in sequence', () => {
const anim = {start: jest.fn(), stop: jest.fn()}; const anim = {start: jest.fn(), stop: jest.fn()};
const cb = jest.fn(); const cb = jest.fn();
Animated.sequence([ Animated.sequence([Animated.delay(1000), anim]).start(cb);
Animated.delay(1000),
anim,
]).start(cb);
jest.runAllTimers(); jest.runAllTimers();
expect(anim.start.mock.calls.length).toBe(1); expect(anim.start.mock.calls.length).toBe(1);
expect(cb).not.toBeCalled(); expect(cb).not.toBeCalled();
@ -529,19 +559,14 @@ describe('Animated tests', () => {
describe('Animated Events', () => { describe('Animated Events', () => {
it('should map events', () => { it('should map events', () => {
const value = new Animated.Value(0); const value = new Animated.Value(0);
const handler = Animated.event( const handler = Animated.event([null, {state: {foo: value}}]);
[null, {state: {foo: value}}],
);
handler({bar: 'ignoreBar'}, {state: {baz: 'ignoreBaz', foo: 42}}); handler({bar: 'ignoreBar'}, {state: {baz: 'ignoreBaz', foo: 42}});
expect(value.__getValue()).toBe(42); expect(value.__getValue()).toBe(42);
}); });
it('should call listeners', () => { it('should call listeners', () => {
const value = new Animated.Value(0); const value = new Animated.Value(0);
const listener = jest.fn(); const listener = jest.fn();
const handler = Animated.event( const handler = Animated.event([{foo: value}], {listener});
[{foo: value}],
{listener},
);
handler({foo: 42}); handler({foo: 42});
expect(value.__getValue()).toBe(42); expect(value.__getValue()).toBe(42);
expect(listener.mock.calls.length).toBe(1); expect(listener.mock.calls.length).toBe(1);
@ -550,10 +575,7 @@ describe('Animated tests', () => {
it('should call forked event listeners', () => { it('should call forked event listeners', () => {
const value = new Animated.Value(0); const value = new Animated.Value(0);
const listener = jest.fn(); const listener = jest.fn();
const handler = Animated.event( const handler = Animated.event([{foo: value}], {listener});
[{foo: value}],
{listener},
);
const listener2 = jest.fn(); const listener2 = jest.fn();
const forkedHandler = Animated.forkEvent(handler, listener2); const forkedHandler = Animated.forkEvent(handler, listener2);
forkedHandler({foo: 42}); forkedHandler({foo: 42});
@ -577,7 +599,7 @@ describe('Animated tests', () => {
InteractionManager = require('InteractionManager'); InteractionManager = require('InteractionManager');
}); });
afterEach(()=> { afterEach(() => {
jest.unmock('InteractionManager'); jest.unmock('InteractionManager');
}); });
@ -633,7 +655,7 @@ describe('Animated tests', () => {
Animated.timing(value2, { Animated.timing(value2, {
toValue: value1.interpolate({ toValue: value1.interpolate({
inputRange: [0, 2], inputRange: [0, 2],
outputRange: [0, 1] outputRange: [0, 1],
}), }),
duration: 0, duration: 0,
}).start(); }).start();
@ -665,24 +687,24 @@ describe('Animated tests', () => {
const callback = jest.fn(); const callback = jest.fn();
const node = new Animated.__PropsOnlyForTests({ const node = new Animated.__PropsOnlyForTests(
style: { {
opacity: vec.x.interpolate({ style: {
inputRange: [0, 42], opacity: vec.x.interpolate({
outputRange: [0.2, 0.8], inputRange: [0, 42],
}), outputRange: [0.2, 0.8],
transform: vec.getTranslateTransform(), }),
...vec.getLayout(), transform: vec.getTranslateTransform(),
} ...vec.getLayout(),
}, callback); },
},
callback,
);
expect(node.__getValue()).toEqual({ expect(node.__getValue()).toEqual({
style: { style: {
opacity: 0.2, opacity: 0.2,
transform: [ transform: [{translateX: 0}, {translateY: 0}],
{translateX: 0},
{translateY: 0},
],
left: 0, left: 0,
top: 0, top: 0,
}, },
@ -695,10 +717,7 @@ describe('Animated tests', () => {
expect(node.__getValue()).toEqual({ expect(node.__getValue()).toEqual({
style: { style: {
opacity: 0.8, opacity: 0.8,
transform: [ transform: [{translateX: 42}, {translateY: 1492}],
{translateX: 42},
{translateY: 1492},
],
left: 42, left: 42,
top: 1492, top: 1492,
}, },
@ -767,7 +786,7 @@ describe('Animated tests', () => {
it('should removeAll', () => { it('should removeAll', () => {
const value1 = new Animated.Value(0); const value1 = new Animated.Value(0);
const listener = jest.fn(); const listener = jest.fn();
[1,2,3,4].forEach(() => value1.addListener(listener)); [1, 2, 3, 4].forEach(() => value1.addListener(listener));
value1.setValue(42); value1.setValue(42);
expect(listener.mock.calls.length).toBe(4); expect(listener.mock.calls.length).toBe(4);
expect(listener).toBeCalledWith({value: 42}); expect(listener).toBeCalledWith({value: 42});

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @emails oncall+react_native * @emails oncall+react_native
*/ */
'use strict'; 'use strict';
const ClassComponentMock = class {}; const ClassComponentMock = class {};
@ -39,7 +41,6 @@ function createAndMountComponent(ComponentClass, props) {
} }
describe('Native Animated', () => { describe('Native Animated', () => {
const nativeAnimatedModule = require('NativeModules').NativeAnimatedModule; const nativeAnimatedModule = require('NativeModules').NativeAnimatedModule;
beforeEach(() => { beforeEach(() => {
@ -64,7 +65,11 @@ describe('Native Animated', () => {
describe('Animated Value', () => { describe('Animated Value', () => {
it('proxies `setValue` correctly', () => { it('proxies `setValue` correctly', () => {
const anim = new Animated.Value(0); const anim = new Animated.Value(0);
Animated.timing(anim, {toValue: 10, duration: 1000, useNativeDriver: true}).start(); Animated.timing(anim, {
toValue: 10,
duration: 1000,
useNativeDriver: true,
}).start();
const c = createAndMountComponent(Animated.View, { const c = createAndMountComponent(Animated.View, {
style: { style: {
@ -82,7 +87,10 @@ describe('Native Animated', () => {
anim.setValue(0.5); anim.setValue(0.5);
expect(nativeAnimatedModule.setAnimatedNodeValue).toBeCalledWith(expect.any(Number), 0.5); expect(nativeAnimatedModule.setAnimatedNodeValue).toBeCalledWith(
expect.any(Number),
0.5,
);
expect(c.refs.node.setNativeProps).not.toHaveBeenCalled(); expect(c.refs.node.setNativeProps).not.toHaveBeenCalled();
}); });
@ -101,8 +109,10 @@ describe('Native Animated', () => {
{type: 'value', value: 0, offset: 10}, {type: 'value', value: 0, offset: 10},
); );
anim.setOffset(20); anim.setOffset(20);
expect(nativeAnimatedModule.setAnimatedNodeOffset) expect(nativeAnimatedModule.setAnimatedNodeOffset).toBeCalledWith(
.toBeCalledWith(expect.any(Number), 20); expect.any(Number),
20,
);
}); });
it('should flatten offset', () => { it('should flatten offset', () => {
@ -119,8 +129,9 @@ describe('Native Animated', () => {
{type: 'value', value: 0, offset: 0}, {type: 'value', value: 0, offset: 0},
); );
anim.flattenOffset(); anim.flattenOffset();
expect(nativeAnimatedModule.flattenAnimatedNodeOffset) expect(nativeAnimatedModule.flattenAnimatedNodeOffset).toBeCalledWith(
.toBeCalledWith(expect.any(Number)); expect.any(Number),
);
}); });
it('should extract offset', () => { it('should extract offset', () => {
@ -137,8 +148,9 @@ describe('Native Animated', () => {
{type: 'value', value: 0, offset: 0}, {type: 'value', value: 0, offset: 0},
); );
anim.extractOffset(); anim.extractOffset();
expect(nativeAnimatedModule.extractAnimatedNodeOffset) expect(nativeAnimatedModule.extractAnimatedNodeOffset).toBeCalledWith(
.toBeCalledWith(expect.any(Number)); expect.any(Number),
);
}); });
}); });
@ -148,33 +160,35 @@ describe('Native Animated', () => {
value1.__makeNative(); value1.__makeNative();
const listener = jest.fn(); const listener = jest.fn();
const id = value1.addListener(listener); const id = value1.addListener(listener);
expect(nativeAnimatedModule.startListeningToAnimatedNodeValue) expect(
.toHaveBeenCalledWith(value1.__getNativeTag()); nativeAnimatedModule.startListeningToAnimatedNodeValue,
).toHaveBeenCalledWith(value1.__getNativeTag());
NativeAnimatedHelper.nativeEventEmitter.emit( NativeAnimatedHelper.nativeEventEmitter.emit('onAnimatedValueUpdate', {
'onAnimatedValueUpdate', value: 42,
{value: 42, tag: value1.__getNativeTag()}, tag: value1.__getNativeTag(),
); });
expect(listener).toHaveBeenCalledTimes(1); expect(listener).toHaveBeenCalledTimes(1);
expect(listener).toBeCalledWith({value: 42}); expect(listener).toBeCalledWith({value: 42});
expect(value1.__getValue()).toBe(42); expect(value1.__getValue()).toBe(42);
NativeAnimatedHelper.nativeEventEmitter.emit( NativeAnimatedHelper.nativeEventEmitter.emit('onAnimatedValueUpdate', {
'onAnimatedValueUpdate', value: 7,
{value: 7, tag: value1.__getNativeTag()}, tag: value1.__getNativeTag(),
); });
expect(listener).toHaveBeenCalledTimes(2); expect(listener).toHaveBeenCalledTimes(2);
expect(listener).toBeCalledWith({value: 7}); expect(listener).toBeCalledWith({value: 7});
expect(value1.__getValue()).toBe(7); expect(value1.__getValue()).toBe(7);
value1.removeListener(id); value1.removeListener(id);
expect(nativeAnimatedModule.stopListeningToAnimatedNodeValue) expect(
.toHaveBeenCalledWith(value1.__getNativeTag()); nativeAnimatedModule.stopListeningToAnimatedNodeValue,
).toHaveBeenCalledWith(value1.__getNativeTag());
NativeAnimatedHelper.nativeEventEmitter.emit( NativeAnimatedHelper.nativeEventEmitter.emit('onAnimatedValueUpdate', {
'onAnimatedValueUpdate', value: 1492,
{value: 1492, tag: value1.__getNativeTag()}, tag: value1.__getNativeTag(),
); });
expect(listener).toHaveBeenCalledTimes(2); expect(listener).toHaveBeenCalledTimes(2);
expect(value1.__getValue()).toBe(7); expect(value1.__getValue()).toBe(7);
}); });
@ -183,25 +197,27 @@ describe('Native Animated', () => {
const value1 = new Animated.Value(0); const value1 = new Animated.Value(0);
value1.__makeNative(); value1.__makeNative();
const listener = jest.fn(); const listener = jest.fn();
[1,2,3,4].forEach(() => value1.addListener(listener)); [1, 2, 3, 4].forEach(() => value1.addListener(listener));
expect(nativeAnimatedModule.startListeningToAnimatedNodeValue) expect(
.toHaveBeenCalledWith(value1.__getNativeTag()); nativeAnimatedModule.startListeningToAnimatedNodeValue,
).toHaveBeenCalledWith(value1.__getNativeTag());
NativeAnimatedHelper.nativeEventEmitter.emit( NativeAnimatedHelper.nativeEventEmitter.emit('onAnimatedValueUpdate', {
'onAnimatedValueUpdate', value: 42,
{value: 42, tag: value1.__getNativeTag()}, tag: value1.__getNativeTag(),
); });
expect(listener).toHaveBeenCalledTimes(4); expect(listener).toHaveBeenCalledTimes(4);
expect(listener).toBeCalledWith({value: 42}); expect(listener).toBeCalledWith({value: 42});
value1.removeAllListeners(); value1.removeAllListeners();
expect(nativeAnimatedModule.stopListeningToAnimatedNodeValue) expect(
.toHaveBeenCalledWith(value1.__getNativeTag()); nativeAnimatedModule.stopListeningToAnimatedNodeValue,
).toHaveBeenCalledWith(value1.__getNativeTag());
NativeAnimatedHelper.nativeEventEmitter.emit( NativeAnimatedHelper.nativeEventEmitter.emit('onAnimatedValueUpdate', {
'onAnimatedValueUpdate', value: 7,
{value: 7, tag: value1.__getNativeTag()}, tag: value1.__getNativeTag(),
); });
expect(listener).toHaveBeenCalledTimes(4); expect(listener).toHaveBeenCalledTimes(4);
}); });
}); });
@ -210,15 +226,17 @@ describe('Native Animated', () => {
it('should map events', () => { it('should map events', () => {
const value = new Animated.Value(0); const value = new Animated.Value(0);
value.__makeNative(); value.__makeNative();
const event = Animated.event( const event = Animated.event([{nativeEvent: {state: {foo: value}}}], {
[{nativeEvent: {state: {foo: value}}}], useNativeDriver: true,
{useNativeDriver: true}, });
);
const c = createAndMountComponent(Animated.View, {onTouchMove: event}); const c = createAndMountComponent(Animated.View, {onTouchMove: event});
expect(nativeAnimatedModule.addAnimatedEventToView).toBeCalledWith( expect(nativeAnimatedModule.addAnimatedEventToView).toBeCalledWith(
expect.any(Number), expect.any(Number),
'onTouchMove', 'onTouchMove',
{nativeEventPath: ['state', 'foo'], animatedValueTag: value.__getNativeTag()}, {
nativeEventPath: ['state', 'foo'],
animatedValueTag: value.__getNativeTag(),
},
); );
c.componentWillUnmount(); c.componentWillUnmount();
@ -232,12 +250,12 @@ describe('Native Animated', () => {
it('should throw on invalid event path', () => { it('should throw on invalid event path', () => {
const value = new Animated.Value(0); const value = new Animated.Value(0);
value.__makeNative(); value.__makeNative();
const event = Animated.event( const event = Animated.event([{notNativeEvent: {foo: value}}], {
[{notNativeEvent: {foo: value}}], useNativeDriver: true,
{useNativeDriver: true}, });
); expect(() =>
expect(() => createAndMountComponent(Animated.View, {onTouchMove: event})) createAndMountComponent(Animated.View, {onTouchMove: event}),
.toThrowError(/nativeEvent/); ).toThrowError(/nativeEvent/);
expect(nativeAnimatedModule.addAnimatedEventToView).not.toBeCalled(); expect(nativeAnimatedModule.addAnimatedEventToView).not.toBeCalled();
}); });
@ -245,10 +263,10 @@ describe('Native Animated', () => {
const value = new Animated.Value(0); const value = new Animated.Value(0);
value.__makeNative(); value.__makeNative();
const listener = jest.fn(); const listener = jest.fn();
const event = Animated.event( const event = Animated.event([{nativeEvent: {foo: value}}], {
[{nativeEvent: {foo: value}}], useNativeDriver: true,
{useNativeDriver: true, listener}, listener,
); });
const handler = event.__getHandler(); const handler = event.__getHandler();
handler({foo: 42}); handler({foo: 42});
expect(listener).toHaveBeenCalledTimes(1); expect(listener).toHaveBeenCalledTimes(1);
@ -265,21 +283,34 @@ describe('Native Animated', () => {
}, },
}); });
Animated.timing(anim, {toValue: 10, duration: 1000, useNativeDriver: true}).start(); Animated.timing(anim, {
toValue: 10,
duration: 1000,
useNativeDriver: true,
}).start();
c.componentWillUnmount(); c.componentWillUnmount();
expect(nativeAnimatedModule.createAnimatedNode).toHaveBeenCalledTimes(3); expect(nativeAnimatedModule.createAnimatedNode).toHaveBeenCalledTimes(3);
expect(nativeAnimatedModule.connectAnimatedNodes).toHaveBeenCalledTimes(2); expect(nativeAnimatedModule.connectAnimatedNodes).toHaveBeenCalledTimes(
2,
);
expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith( expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith(
expect.any(Number), expect.any(Number),
expect.any(Number), expect.any(Number),
{type: 'frames', frames: expect.any(Array), toValue: expect.any(Number), iterations: 1}, {
expect.any(Function) type: 'frames',
frames: expect.any(Array),
toValue: expect.any(Number),
iterations: 1,
},
expect.any(Function),
); );
expect(nativeAnimatedModule.disconnectAnimatedNodes).toHaveBeenCalledTimes(2); expect(
nativeAnimatedModule.disconnectAnimatedNodes,
).toHaveBeenCalledTimes(2);
expect(nativeAnimatedModule.dropAnimatedNode).toHaveBeenCalledTimes(3); expect(nativeAnimatedModule.dropAnimatedNode).toHaveBeenCalledTimes(3);
}); });
@ -291,14 +322,24 @@ describe('Native Animated', () => {
}, },
}); });
Animated.timing(anim, {toValue: 10, duration: 1000, useNativeDriver: true}).start(); Animated.timing(anim, {
toValue: 10,
duration: 1000,
useNativeDriver: true,
}).start();
expect(nativeAnimatedModule.createAnimatedNode) expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
.toBeCalledWith(expect.any(Number), {type: 'value', value: 0, offset: 0}); expect.any(Number),
expect(nativeAnimatedModule.createAnimatedNode) {type: 'value', value: 0, offset: 0},
.toBeCalledWith(expect.any(Number), {type: 'style', style: {opacity: expect.any(Number)}}); );
expect(nativeAnimatedModule.createAnimatedNode) expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
.toBeCalledWith(expect.any(Number), {type: 'props', props: {style: expect.any(Number)}}); expect.any(Number),
{type: 'style', style: {opacity: expect.any(Number)}},
);
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
expect.any(Number),
{type: 'props', props: {style: expect.any(Number)}},
);
}); });
it('sends a valid graph description for Animated.add nodes', () => { it('sends a valid graph description for Animated.add nodes', () => {
@ -318,19 +359,23 @@ describe('Native Animated', () => {
{type: 'addition', input: expect.any(Array)}, {type: 'addition', input: expect.any(Array)},
); );
const additionCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter( const additionCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter(
(call) => call[1].type === 'addition' call => call[1].type === 'addition',
); );
expect(additionCalls.length).toBe(1); expect(additionCalls.length).toBe(1);
const additionCall = additionCalls[0]; const additionCall = additionCalls[0];
const additionNodeTag = additionCall[0]; const additionNodeTag = additionCall[0];
const additionConnectionCalls = nativeAnimatedModule.connectAnimatedNodes.mock.calls.filter( const additionConnectionCalls = nativeAnimatedModule.connectAnimatedNodes.mock.calls.filter(
(call) => call[1] === additionNodeTag call => call[1] === additionNodeTag,
); );
expect(additionConnectionCalls.length).toBe(2); expect(additionConnectionCalls.length).toBe(2);
expect(nativeAnimatedModule.createAnimatedNode) expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
.toBeCalledWith(additionCall[1].input[0], {type: 'value', value: 1, offset: 0}); additionCall[1].input[0],
expect(nativeAnimatedModule.createAnimatedNode) {type: 'value', value: 1, offset: 0},
.toBeCalledWith(additionCall[1].input[1], {type: 'value', value: 2, offset: 0}); );
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
additionCall[1].input[1],
{type: 'value', value: 2, offset: 0},
);
}); });
it('sends a valid graph description for Animated.subtract nodes', () => { it('sends a valid graph description for Animated.subtract nodes', () => {
@ -350,19 +395,23 @@ describe('Native Animated', () => {
{type: 'subtraction', input: expect.any(Array)}, {type: 'subtraction', input: expect.any(Array)},
); );
const subtractionCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter( const subtractionCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter(
(call) => call[1].type === 'subtraction' call => call[1].type === 'subtraction',
); );
expect(subtractionCalls.length).toBe(1); expect(subtractionCalls.length).toBe(1);
const subtractionCall = subtractionCalls[0]; const subtractionCall = subtractionCalls[0];
const subtractionNodeTag = subtractionCall[0]; const subtractionNodeTag = subtractionCall[0];
const subtractionConnectionCalls = nativeAnimatedModule.connectAnimatedNodes.mock.calls.filter( const subtractionConnectionCalls = nativeAnimatedModule.connectAnimatedNodes.mock.calls.filter(
(call) => call[1] === subtractionNodeTag call => call[1] === subtractionNodeTag,
); );
expect(subtractionConnectionCalls.length).toBe(2); expect(subtractionConnectionCalls.length).toBe(2);
expect(nativeAnimatedModule.createAnimatedNode) expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
.toBeCalledWith(subtractionCall[1].input[0], {type: 'value', value: 2, offset: 0}); subtractionCall[1].input[0],
expect(nativeAnimatedModule.createAnimatedNode) {type: 'value', value: 2, offset: 0},
.toBeCalledWith(subtractionCall[1].input[1], {type: 'value', value: 1, offset: 0}); );
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
subtractionCall[1].input[1],
{type: 'value', value: 1, offset: 0},
);
}); });
it('sends a valid graph description for Animated.multiply nodes', () => { it('sends a valid graph description for Animated.multiply nodes', () => {
@ -382,19 +431,23 @@ describe('Native Animated', () => {
{type: 'multiplication', input: expect.any(Array)}, {type: 'multiplication', input: expect.any(Array)},
); );
const multiplicationCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter( const multiplicationCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter(
(call) => call[1].type === 'multiplication' call => call[1].type === 'multiplication',
); );
expect(multiplicationCalls.length).toBe(1); expect(multiplicationCalls.length).toBe(1);
const multiplicationCall = multiplicationCalls[0]; const multiplicationCall = multiplicationCalls[0];
const multiplicationNodeTag = multiplicationCall[0]; const multiplicationNodeTag = multiplicationCall[0];
const multiplicationConnectionCalls = nativeAnimatedModule.connectAnimatedNodes.mock.calls.filter( const multiplicationConnectionCalls = nativeAnimatedModule.connectAnimatedNodes.mock.calls.filter(
(call) => call[1] === multiplicationNodeTag call => call[1] === multiplicationNodeTag,
); );
expect(multiplicationConnectionCalls.length).toBe(2); expect(multiplicationConnectionCalls.length).toBe(2);
expect(nativeAnimatedModule.createAnimatedNode) expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
.toBeCalledWith(multiplicationCall[1].input[0], {type: 'value', value: 2, offset: 0}); multiplicationCall[1].input[0],
expect(nativeAnimatedModule.createAnimatedNode) {type: 'value', value: 2, offset: 0},
.toBeCalledWith(multiplicationCall[1].input[1], {type: 'value', value: 1, offset: 0}); );
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
multiplicationCall[1].input[1],
{type: 'value', value: 1, offset: 0},
);
}); });
it('sends a valid graph description for Animated.divide nodes', () => { it('sends a valid graph description for Animated.divide nodes', () => {
@ -409,22 +462,28 @@ describe('Native Animated', () => {
}, },
}); });
expect(nativeAnimatedModule.createAnimatedNode) expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
.toBeCalledWith(expect.any(Number), {type: 'division', input: expect.any(Array)}); expect.any(Number),
{type: 'division', input: expect.any(Array)},
);
const divisionCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter( const divisionCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter(
(call) => call[1].type === 'division' call => call[1].type === 'division',
); );
expect(divisionCalls.length).toBe(1); expect(divisionCalls.length).toBe(1);
const divisionCall = divisionCalls[0]; const divisionCall = divisionCalls[0];
const divisionNodeTag = divisionCall[0]; const divisionNodeTag = divisionCall[0];
const divisionConnectionCalls = nativeAnimatedModule.connectAnimatedNodes.mock.calls.filter( const divisionConnectionCalls = nativeAnimatedModule.connectAnimatedNodes.mock.calls.filter(
(call) => call[1] === divisionNodeTag call => call[1] === divisionNodeTag,
); );
expect(divisionConnectionCalls.length).toBe(2); expect(divisionConnectionCalls.length).toBe(2);
expect(nativeAnimatedModule.createAnimatedNode) expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
.toBeCalledWith(divisionCall[1].input[0], {type: 'value', value: 4, offset: 0}); divisionCall[1].input[0],
expect(nativeAnimatedModule.createAnimatedNode) {type: 'value', value: 4, offset: 0},
.toBeCalledWith(divisionCall[1].input[1], {type: 'value', value: 2, offset: 0}); );
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
divisionCall[1].input[1],
{type: 'value', value: 2, offset: 0},
);
}); });
it('sends a valid graph description for Animated.modulo nodes', () => { it('sends a valid graph description for Animated.modulo nodes', () => {
@ -442,17 +501,19 @@ describe('Native Animated', () => {
{type: 'modulus', modulus: 4, input: expect.any(Number)}, {type: 'modulus', modulus: 4, input: expect.any(Number)},
); );
const moduloCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter( const moduloCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter(
(call) => call[1].type === 'modulus' call => call[1].type === 'modulus',
); );
expect(moduloCalls.length).toBe(1); expect(moduloCalls.length).toBe(1);
const moduloCall = moduloCalls[0]; const moduloCall = moduloCalls[0];
const moduloNodeTag = moduloCall[0]; const moduloNodeTag = moduloCall[0];
const moduloConnectionCalls = nativeAnimatedModule.connectAnimatedNodes.mock.calls.filter( const moduloConnectionCalls = nativeAnimatedModule.connectAnimatedNodes.mock.calls.filter(
(call) => call[1] === moduloNodeTag call => call[1] === moduloNodeTag,
); );
expect(moduloConnectionCalls.length).toBe(1); expect(moduloConnectionCalls.length).toBe(1);
expect(nativeAnimatedModule.createAnimatedNode) expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
.toBeCalledWith(moduloCall[1].input, {type: 'value', value: 4, offset: 0}); moduloCall[1].input,
{type: 'value', value: 4, offset: 0},
);
}); });
it('sends a valid graph description for interpolate() nodes', () => { it('sends a valid graph description for interpolate() nodes', () => {
@ -470,23 +531,28 @@ describe('Native Animated', () => {
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
expect.any(Number), expect.any(Number),
{type: 'value', value: 10, offset: 0} {type: 'value', value: 10, offset: 0},
); );
expect(nativeAnimatedModule.createAnimatedNode) expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
.toBeCalledWith(expect.any(Number), { expect.any(Number),
{
type: 'interpolation', type: 'interpolation',
inputRange: [10, 20], inputRange: [10, 20],
outputRange: [0, 1], outputRange: [0, 1],
extrapolateLeft: 'extend', extrapolateLeft: 'extend',
extrapolateRight: 'extend', extrapolateRight: 'extend',
}); },
);
const interpolationNodeTag = nativeAnimatedModule.createAnimatedNode.mock.calls.find( const interpolationNodeTag = nativeAnimatedModule.createAnimatedNode.mock.calls.find(
(call) => call[1].type === 'interpolation' call => call[1].type === 'interpolation',
)[0]; )[0];
const valueNodeTag = nativeAnimatedModule.createAnimatedNode.mock.calls.find( const valueNodeTag = nativeAnimatedModule.createAnimatedNode.mock.calls.find(
(call) => call[1].type === 'value' call => call[1].type === 'value',
)[0]; )[0];
expect(nativeAnimatedModule.connectAnimatedNodes).toBeCalledWith(valueNodeTag, interpolationNodeTag); expect(nativeAnimatedModule.connectAnimatedNodes).toBeCalledWith(
valueNodeTag,
interpolationNodeTag,
);
}); });
it('sends a valid graph description for transform nodes', () => { it('sends a valid graph description for transform nodes', () => {
@ -503,15 +569,18 @@ describe('Native Animated', () => {
expect.any(Number), expect.any(Number),
{ {
type: 'transform', type: 'transform',
transforms: [{ transforms: [
nodeTag: expect.any(Number), {
property: 'translateX', nodeTag: expect.any(Number),
type: 'animated', property: 'translateX',
}, { type: 'animated',
value: 2, },
property: 'scale', {
type: 'static', value: 2,
}], property: 'scale',
type: 'static',
},
],
}, },
); );
}); });
@ -531,20 +600,22 @@ describe('Native Animated', () => {
{type: 'diffclamp', input: expect.any(Number), max: 20, min: 0}, {type: 'diffclamp', input: expect.any(Number), max: 20, min: 0},
); );
const diffClampCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter( const diffClampCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter(
(call) => call[1].type === 'diffclamp' call => call[1].type === 'diffclamp',
); );
expect(diffClampCalls.length).toBe(1); expect(diffClampCalls.length).toBe(1);
const diffClampCall = diffClampCalls[0]; const diffClampCall = diffClampCalls[0];
const diffClampNodeTag = diffClampCall[0]; const diffClampNodeTag = diffClampCall[0];
const diffClampConnectionCalls = nativeAnimatedModule.connectAnimatedNodes.mock.calls.filter( const diffClampConnectionCalls = nativeAnimatedModule.connectAnimatedNodes.mock.calls.filter(
(call) => call[1] === diffClampNodeTag call => call[1] === diffClampNodeTag,
); );
expect(diffClampConnectionCalls.length).toBe(1); expect(diffClampConnectionCalls.length).toBe(1);
expect(nativeAnimatedModule.createAnimatedNode) expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
.toBeCalledWith(diffClampCall[1].input, {type: 'value', value: 2, offset: 0}); diffClampCall[1].input,
{type: 'value', value: 2, offset: 0},
);
}); });
it('doesn\'t call into native API if useNativeDriver is set to false', () => { it("doesn't call into native API if useNativeDriver is set to false", () => {
const anim = new Animated.Value(0); const anim = new Animated.Value(0);
const c = createAndMountComponent(Animated.View, { const c = createAndMountComponent(Animated.View, {
@ -553,7 +624,11 @@ describe('Native Animated', () => {
}, },
}); });
Animated.timing(anim, {toValue: 10, duration: 1000, useNativeDriver: false}).start(); Animated.timing(anim, {
toValue: 10,
duration: 1000,
useNativeDriver: false,
}).start();
c.componentWillUnmount(); c.componentWillUnmount();
@ -569,10 +644,18 @@ describe('Native Animated', () => {
}, },
}); });
Animated.timing(anim, {toValue: 10, duration: 50, useNativeDriver: true}).start(); Animated.timing(anim, {
toValue: 10,
duration: 50,
useNativeDriver: true,
}).start();
jest.runAllTimers(); jest.runAllTimers();
Animated.timing(anim, {toValue: 4, duration: 500, useNativeDriver: false}).start(); Animated.timing(anim, {
toValue: 4,
duration: 500,
useNativeDriver: false,
}).start();
expect(jest.runAllTimers).toThrow(); expect(jest.runAllTimers).toThrow();
}); });
@ -585,7 +668,11 @@ describe('Native Animated', () => {
}, },
}); });
const animation = Animated.timing(anim, {toValue: 10, duration: 50, useNativeDriver: true}); const animation = Animated.timing(anim, {
toValue: 10,
duration: 50,
useNativeDriver: true,
});
expect(animation.start).toThrowError(/left/); expect(animation.start).toThrowError(/left/);
}); });
@ -603,29 +690,47 @@ describe('Native Animated', () => {
removeClippedSubviews: true, removeClippedSubviews: true,
}); });
expect(nativeAnimatedModule.createAnimatedNode) expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
.toBeCalledWith(expect.any(Number), { type: 'style', style: { opacity: expect.any(Number) }}); expect.any(Number),
expect(nativeAnimatedModule.createAnimatedNode) {type: 'style', style: {opacity: expect.any(Number)}},
.toBeCalledWith(expect.any(Number), { type: 'props', props: { style: expect.any(Number) }}); );
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
expect.any(Number),
{type: 'props', props: {style: expect.any(Number)}},
);
}); });
}); });
describe('Animations', () => { describe('Animations', () => {
it('sends a valid timing animation description', () => { it('sends a valid timing animation description', () => {
const anim = new Animated.Value(0); const anim = new Animated.Value(0);
Animated.timing(anim, {toValue: 10, duration: 1000, useNativeDriver: true}).start(); Animated.timing(anim, {
toValue: 10,
duration: 1000,
useNativeDriver: true,
}).start();
expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith( expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith(
expect.any(Number), expect.any(Number),
expect.any(Number), expect.any(Number),
{type: 'frames', frames: expect.any(Array), toValue: expect.any(Number), iterations: 1}, {
expect.any(Function) type: 'frames',
frames: expect.any(Array),
toValue: expect.any(Number),
iterations: 1,
},
expect.any(Function),
); );
}); });
it('sends a valid spring animation description', () => { it('sends a valid spring animation description', () => {
const anim = new Animated.Value(0); const anim = new Animated.Value(0);
Animated.spring(anim, {toValue: 10, friction: 5, tension: 164, useNativeDriver: true}).start(); Animated.spring(anim, {
toValue: 10,
friction: 5,
tension: 164,
useNativeDriver: true,
}).start();
expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith( expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith(
expect.any(Number), expect.any(Number),
expect.any(Number), expect.any(Number),
@ -641,7 +746,7 @@ describe('Native Animated', () => {
toValue: 10, toValue: 10,
iterations: 1, iterations: 1,
}, },
expect.any(Function) expect.any(Function),
); );
Animated.spring(anim, { Animated.spring(anim, {
@ -649,7 +754,7 @@ describe('Native Animated', () => {
stiffness: 1000, stiffness: 1000,
damping: 500, damping: 500,
mass: 3, mass: 3,
useNativeDriver: true useNativeDriver: true,
}).start(); }).start();
expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith( expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith(
expect.any(Number), expect.any(Number),
@ -666,10 +771,15 @@ describe('Native Animated', () => {
toValue: 10, toValue: 10,
iterations: 1, iterations: 1,
}, },
expect.any(Function) expect.any(Function),
); );
Animated.spring(anim, {toValue: 10, bounciness: 8, speed: 10, useNativeDriver: true}).start(); Animated.spring(anim, {
toValue: 10,
bounciness: 8,
speed: 10,
useNativeDriver: true,
}).start();
expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith( expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith(
expect.any(Number), expect.any(Number),
expect.any(Number), expect.any(Number),
@ -685,49 +795,67 @@ describe('Native Animated', () => {
toValue: 10, toValue: 10,
iterations: 1, iterations: 1,
}, },
expect.any(Function) expect.any(Function),
); );
}); });
it('sends a valid decay animation description', () => { it('sends a valid decay animation description', () => {
const anim = new Animated.Value(0); const anim = new Animated.Value(0);
Animated.decay(anim, {velocity: 10, deceleration: 0.1, useNativeDriver: true}).start(); Animated.decay(anim, {
velocity: 10,
deceleration: 0.1,
useNativeDriver: true,
}).start();
expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith( expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith(
expect.any(Number), expect.any(Number),
expect.any(Number), expect.any(Number),
{type: 'decay', deceleration: 0.1, velocity: 10, iterations: 1}, {type: 'decay', deceleration: 0.1, velocity: 10, iterations: 1},
expect.any(Function) expect.any(Function),
); );
}); });
it('works with Animated.loop', () => { it('works with Animated.loop', () => {
const anim = new Animated.Value(0); const anim = new Animated.Value(0);
Animated.loop( Animated.loop(
Animated.decay(anim, {velocity: 10, deceleration: 0.1, useNativeDriver: true}), Animated.decay(anim, {
{ iterations: 10 }, velocity: 10,
deceleration: 0.1,
useNativeDriver: true,
}),
{iterations: 10},
).start(); ).start();
expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith( expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith(
expect.any(Number), expect.any(Number),
expect.any(Number), expect.any(Number),
{type: 'decay', deceleration: 0.1, velocity: 10, iterations: 10}, {type: 'decay', deceleration: 0.1, velocity: 10, iterations: 10},
expect.any(Function) expect.any(Function),
); );
}); });
it('sends stopAnimation command to native', () => { it('sends stopAnimation command to native', () => {
const value = new Animated.Value(0); const value = new Animated.Value(0);
const animation = Animated.timing(value, {toValue: 10, duration: 50, useNativeDriver: true}); const animation = Animated.timing(value, {
toValue: 10,
duration: 50,
useNativeDriver: true,
});
animation.start(); animation.start();
expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith( expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith(
expect.any(Number), expect.any(Number),
expect.any(Number), expect.any(Number),
{type: 'frames', frames: expect.any(Array), toValue: expect.any(Number), iterations: 1}, {
expect.any(Function) type: 'frames',
frames: expect.any(Array),
toValue: expect.any(Number),
iterations: 1,
},
expect.any(Function),
); );
const animationId = nativeAnimatedModule.startAnimatingNode.mock.calls[0][0]; const animationId =
nativeAnimatedModule.startAnimatingNode.mock.calls[0][0];
animation.stop(); animation.stop();
expect(nativeAnimatedModule.stopAnimation).toBeCalledWith(animationId); expect(nativeAnimatedModule.stopAnimation).toBeCalledWith(animationId);

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @emails oncall+react_native * @emails oncall+react_native
*/ */
'use strict'; 'use strict';
const Easing = require('Easing'); const Easing = require('Easing');
@ -88,23 +90,363 @@ describe('Easing', () => {
} }
const Samples = { const Samples = {
in_quad: [0,0.0030864197530864196,0.012345679012345678,0.027777777777777776,0.04938271604938271,0.0771604938271605,0.1111111111111111,0.15123456790123457,0.19753086419753085,0.25,0.308641975308642,0.37345679012345684,0.4444444444444444,0.5216049382716049,0.6049382716049383,0.6944444444444445,0.7901234567901234,0.8919753086419753,1], in_quad: [
out_quad: [0,0.10802469135802469,0.20987654320987653,0.3055555555555555,0.3950617283950617,0.47839506172839513,0.5555555555555556,0.6265432098765432,0.691358024691358,0.75,0.8024691358024691,0.8487654320987654,0.888888888888889,0.9228395061728394,0.9506172839506174,0.9722222222222221,0.9876543209876543,0.9969135802469136,1], 0,
inOut_quad: [0,0.006172839506172839,0.024691358024691357,0.05555555555555555,0.09876543209876543,0.154320987654321,0.2222222222222222,0.30246913580246915,0.3950617283950617,0.5,0.6049382716049383,0.697530864197531,0.7777777777777777,0.845679012345679,0.9012345679012346,0.9444444444444444,0.9753086419753086,0.9938271604938271,1], 0.0030864197530864196,
in_cubic: [0,0.00017146776406035664,0.0013717421124828531,0.004629629629629629,0.010973936899862825,0.021433470507544586,0.037037037037037035,0.05881344307270234,0.0877914951989026,0.125,0.1714677640603567,0.22822359396433475,0.2962962962962963,0.37671467764060357,0.4705075445816187,0.5787037037037038,0.7023319615912208,0.8424211248285322,1], 0.012345679012345678,
out_cubic: [0,0.15757887517146785,0.2976680384087792,0.42129629629629617,0.5294924554183813,0.6232853223593964,0.7037037037037036,0.7717764060356652,0.8285322359396433,0.875,0.9122085048010974,0.9411865569272977,0.9629629629629629,0.9785665294924554,0.9890260631001372,0.9953703703703703,0.9986282578875172,0.9998285322359396,1], 0.027777777777777776,
inOut_cubic: [0,0.0006858710562414266,0.0054869684499314125,0.018518518518518517,0.0438957475994513,0.08573388203017834,0.14814814814814814,0.23525377229080935,0.3511659807956104,0.5,0.6488340192043895,0.7647462277091908,0.8518518518518519,0.9142661179698217,0.9561042524005487,0.9814814814814815,0.9945130315500685,0.9993141289437586,1], 0.04938271604938271,
in_sin: [0,0.003805301908254455,0.01519224698779198,0.03407417371093169,0.06030737921409157,0.09369221296335006,0.1339745962155613,0.1808479557110082,0.233955556881022,0.2928932188134524,0.35721239031346064,0.42642356364895384,0.4999999999999999,0.5773817382593005,0.6579798566743311,0.7411809548974793,0.8263518223330696,0.9128442572523416,0.9999999999999999], 0.0771604938271605,
out_sin: [0,0.08715574274765817,0.17364817766693033,0.25881904510252074,0.3420201433256687,0.42261826174069944,0.49999999999999994,0.573576436351046,0.6427876096865393,0.7071067811865475,0.766044443118978,0.8191520442889918,0.8660254037844386,0.9063077870366499,0.9396926207859083,0.9659258262890683,0.984807753012208,0.9961946980917455,1], 0.1111111111111111,
inOut_sin: [0,0.00759612349389599,0.030153689607045786,0.06698729810778065,0.116977778440511,0.17860619515673032,0.24999999999999994,0.32898992833716556,0.4131759111665348,0.49999999999999994,0.5868240888334652,0.6710100716628343,0.7499999999999999,0.8213938048432696,0.883022221559489,0.9330127018922194,0.9698463103929542,0.9924038765061041,1], 0.15123456790123457,
in_exp: [0,0.0014352875901128893,0.002109491677524035,0.0031003926796253885,0.004556754060844206,0.006697218616039631,0.009843133202303688,0.014466792379488908,0.021262343752724643,0.03125,0.045929202883612456,0.06750373368076916,0.09921256574801243,0.1458161299470146,0.2143109957132682,0.31498026247371835,0.46293735614364506,0.6803950000871883,1], 0.19753086419753085,
out_exp: [0,0.31960499991281155,0.5370626438563548,0.6850197375262816,0.7856890042867318,0.8541838700529854,0.9007874342519875,0.9324962663192309,0.9540707971163875,0.96875,0.9787376562472754,0.9855332076205111,0.9901568667976963,0.9933027813839603,0.9954432459391558,0.9968996073203746,0.9978905083224759,0.9985647124098871,1], 0.25,
inOut_exp: [0,0.0010547458387620175,0.002278377030422103,0.004921566601151844,0.010631171876362321,0.022964601441806228,0.049606282874006216,0.1071554978566341,0.23146867807182253,0.5,0.7685313219281775,0.892844502143366,0.9503937171259937,0.9770353985581938,0.9893688281236377,0.9950784333988482,0.9977216229695779,0.998945254161238,1], 0.308641975308642,
in_circle: [0,0.0015444024660317135,0.006192010000093506,0.013986702816730645,0.025003956956430873,0.03935464078941209,0.057190958417936644,0.07871533601238889,0.10419358352238339,0.1339745962155614,0.1685205807169019,0.20845517506805522,0.2546440075000701,0.3083389112228482,0.37146063894529113,0.4472292016074334,0.5418771527091488,0.6713289009389102,1], 0.37345679012345684,
out_circle: [0,0.3286710990610898,0.45812284729085123,0.5527707983925666,0.6285393610547089,0.6916610887771518,0.7453559924999298,0.7915448249319448,0.8314794192830981,0.8660254037844386,0.8958064164776166,0.9212846639876111,0.9428090415820634,0.9606453592105879,0.9749960430435691,0.9860132971832694,0.9938079899999065,0.9984555975339683,1], 0.4444444444444444,
inOut_circle: [0,0.003096005000046753,0.012501978478215436,0.028595479208968322,0.052096791761191696,0.08426029035845095,0.12732200375003505,0.18573031947264557,0.2709385763545744,0.5,0.7290614236454256,0.8142696805273546,0.8726779962499649,0.915739709641549,0.9479032082388084,0.9714045207910317,0.9874980215217846,0.9969039949999532,1], 0.5216049382716049,
in_back_: [0,-0.004788556241426612,-0.017301289437585736,-0.0347587962962963,-0.05438167352537723,-0.07339051783264748,-0.08900592592592595,-0.09844849451303156,-0.0989388203017833,-0.08769750000000004,-0.06194513031550073,-0.018902307956104283,0.044210370370370254,0.13017230795610413,0.2417629080932785,0.3817615740740742,0.5529477091906719,0.7581007167352535,0.9999999999999998], 0.6049382716049383,
out_back_: [2.220446049250313e-16,0.24189928326474652,0.44705229080932807,0.6182384259259258,0.7582370919067215,0.8698276920438959,0.9557896296296297,1.0189023079561044,1.0619451303155008,1.0876975,1.0989388203017834,1.0984484945130315,1.089005925925926,1.0733905178326475,1.0543816735253773,1.0347587962962963,1.0173012894375857,1.0047885562414267,1], 0.6944444444444445,
0.7901234567901234,
0.8919753086419753,
1,
],
out_quad: [
0,
0.10802469135802469,
0.20987654320987653,
0.3055555555555555,
0.3950617283950617,
0.47839506172839513,
0.5555555555555556,
0.6265432098765432,
0.691358024691358,
0.75,
0.8024691358024691,
0.8487654320987654,
0.888888888888889,
0.9228395061728394,
0.9506172839506174,
0.9722222222222221,
0.9876543209876543,
0.9969135802469136,
1,
],
inOut_quad: [
0,
0.006172839506172839,
0.024691358024691357,
0.05555555555555555,
0.09876543209876543,
0.154320987654321,
0.2222222222222222,
0.30246913580246915,
0.3950617283950617,
0.5,
0.6049382716049383,
0.697530864197531,
0.7777777777777777,
0.845679012345679,
0.9012345679012346,
0.9444444444444444,
0.9753086419753086,
0.9938271604938271,
1,
],
in_cubic: [
0,
0.00017146776406035664,
0.0013717421124828531,
0.004629629629629629,
0.010973936899862825,
0.021433470507544586,
0.037037037037037035,
0.05881344307270234,
0.0877914951989026,
0.125,
0.1714677640603567,
0.22822359396433475,
0.2962962962962963,
0.37671467764060357,
0.4705075445816187,
0.5787037037037038,
0.7023319615912208,
0.8424211248285322,
1,
],
out_cubic: [
0,
0.15757887517146785,
0.2976680384087792,
0.42129629629629617,
0.5294924554183813,
0.6232853223593964,
0.7037037037037036,
0.7717764060356652,
0.8285322359396433,
0.875,
0.9122085048010974,
0.9411865569272977,
0.9629629629629629,
0.9785665294924554,
0.9890260631001372,
0.9953703703703703,
0.9986282578875172,
0.9998285322359396,
1,
],
inOut_cubic: [
0,
0.0006858710562414266,
0.0054869684499314125,
0.018518518518518517,
0.0438957475994513,
0.08573388203017834,
0.14814814814814814,
0.23525377229080935,
0.3511659807956104,
0.5,
0.6488340192043895,
0.7647462277091908,
0.8518518518518519,
0.9142661179698217,
0.9561042524005487,
0.9814814814814815,
0.9945130315500685,
0.9993141289437586,
1,
],
in_sin: [
0,
0.003805301908254455,
0.01519224698779198,
0.03407417371093169,
0.06030737921409157,
0.09369221296335006,
0.1339745962155613,
0.1808479557110082,
0.233955556881022,
0.2928932188134524,
0.35721239031346064,
0.42642356364895384,
0.4999999999999999,
0.5773817382593005,
0.6579798566743311,
0.7411809548974793,
0.8263518223330696,
0.9128442572523416,
0.9999999999999999,
],
out_sin: [
0,
0.08715574274765817,
0.17364817766693033,
0.25881904510252074,
0.3420201433256687,
0.42261826174069944,
0.49999999999999994,
0.573576436351046,
0.6427876096865393,
0.7071067811865475,
0.766044443118978,
0.8191520442889918,
0.8660254037844386,
0.9063077870366499,
0.9396926207859083,
0.9659258262890683,
0.984807753012208,
0.9961946980917455,
1,
],
inOut_sin: [
0,
0.00759612349389599,
0.030153689607045786,
0.06698729810778065,
0.116977778440511,
0.17860619515673032,
0.24999999999999994,
0.32898992833716556,
0.4131759111665348,
0.49999999999999994,
0.5868240888334652,
0.6710100716628343,
0.7499999999999999,
0.8213938048432696,
0.883022221559489,
0.9330127018922194,
0.9698463103929542,
0.9924038765061041,
1,
],
in_exp: [
0,
0.0014352875901128893,
0.002109491677524035,
0.0031003926796253885,
0.004556754060844206,
0.006697218616039631,
0.009843133202303688,
0.014466792379488908,
0.021262343752724643,
0.03125,
0.045929202883612456,
0.06750373368076916,
0.09921256574801243,
0.1458161299470146,
0.2143109957132682,
0.31498026247371835,
0.46293735614364506,
0.6803950000871883,
1,
],
out_exp: [
0,
0.31960499991281155,
0.5370626438563548,
0.6850197375262816,
0.7856890042867318,
0.8541838700529854,
0.9007874342519875,
0.9324962663192309,
0.9540707971163875,
0.96875,
0.9787376562472754,
0.9855332076205111,
0.9901568667976963,
0.9933027813839603,
0.9954432459391558,
0.9968996073203746,
0.9978905083224759,
0.9985647124098871,
1,
],
inOut_exp: [
0,
0.0010547458387620175,
0.002278377030422103,
0.004921566601151844,
0.010631171876362321,
0.022964601441806228,
0.049606282874006216,
0.1071554978566341,
0.23146867807182253,
0.5,
0.7685313219281775,
0.892844502143366,
0.9503937171259937,
0.9770353985581938,
0.9893688281236377,
0.9950784333988482,
0.9977216229695779,
0.998945254161238,
1,
],
in_circle: [
0,
0.0015444024660317135,
0.006192010000093506,
0.013986702816730645,
0.025003956956430873,
0.03935464078941209,
0.057190958417936644,
0.07871533601238889,
0.10419358352238339,
0.1339745962155614,
0.1685205807169019,
0.20845517506805522,
0.2546440075000701,
0.3083389112228482,
0.37146063894529113,
0.4472292016074334,
0.5418771527091488,
0.6713289009389102,
1,
],
out_circle: [
0,
0.3286710990610898,
0.45812284729085123,
0.5527707983925666,
0.6285393610547089,
0.6916610887771518,
0.7453559924999298,
0.7915448249319448,
0.8314794192830981,
0.8660254037844386,
0.8958064164776166,
0.9212846639876111,
0.9428090415820634,
0.9606453592105879,
0.9749960430435691,
0.9860132971832694,
0.9938079899999065,
0.9984555975339683,
1,
],
inOut_circle: [
0,
0.003096005000046753,
0.012501978478215436,
0.028595479208968322,
0.052096791761191696,
0.08426029035845095,
0.12732200375003505,
0.18573031947264557,
0.2709385763545744,
0.5,
0.7290614236454256,
0.8142696805273546,
0.8726779962499649,
0.915739709641549,
0.9479032082388084,
0.9714045207910317,
0.9874980215217846,
0.9969039949999532,
1,
],
in_back_: [
0,
-0.004788556241426612,
-0.017301289437585736,
-0.0347587962962963,
-0.05438167352537723,
-0.07339051783264748,
-0.08900592592592595,
-0.09844849451303156,
-0.0989388203017833,
-0.08769750000000004,
-0.06194513031550073,
-0.018902307956104283,
0.044210370370370254,
0.13017230795610413,
0.2417629080932785,
0.3817615740740742,
0.5529477091906719,
0.7581007167352535,
0.9999999999999998,
],
out_back_: [
2.220446049250313e-16,
0.24189928326474652,
0.44705229080932807,
0.6182384259259258,
0.7582370919067215,
0.8698276920438959,
0.9557896296296297,
1.0189023079561044,
1.0619451303155008,
1.0876975,
1.0989388203017834,
1.0984484945130315,
1.089005925925926,
1.0733905178326475,
1.0543816735253773,
1.0347587962962963,
1.0173012894375857,
1.0047885562414267,
1,
],
}; };
Object.keys(Samples).forEach(function(type) { Object.keys(Samples).forEach(function(type) {

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @emails oncall+react_native * @emails oncall+react_native
*/ */
'use strict'; 'use strict';
const AnimatedInterpolation = require('../nodes/AnimatedInterpolation'); const AnimatedInterpolation = require('../nodes/AnimatedInterpolation');

View File

@ -74,7 +74,10 @@ describe('bezier', function() {
describe('common properties', function() { describe('common properties', function() {
it('should be the right value at extremes', function() { it('should be the right value at extremes', function() {
repeat(10)(function() { repeat(10)(function() {
const a = Math.random(), b = 2 * Math.random() - 0.5, c = Math.random(), d = 2 * Math.random() - 0.5; const a = Math.random(),
b = 2 * Math.random() - 0.5,
c = Math.random(),
d = 2 * Math.random() - 0.5;
const easing = bezier(a, b, c, d); const easing = bezier(a, b, c, d);
expect(easing(0)).toBe(0); expect(easing(0)).toBe(0);
expect(easing(1)).toBe(1); expect(easing(1)).toBe(1);
@ -83,7 +86,10 @@ describe('bezier', function() {
it('should approach the projected value of its x=y projected curve', function() { it('should approach the projected value of its x=y projected curve', function() {
repeat(10)(function() { repeat(10)(function() {
const a = Math.random(), b = Math.random(), c = Math.random(), d = Math.random(); const a = Math.random(),
b = Math.random(),
c = Math.random(),
d = Math.random();
const easing = bezier(a, b, c, d); const easing = bezier(a, b, c, d);
const projected = bezier(b, a, d, c); const projected = bezier(b, a, d, c);
const composed = function(x) { const composed = function(x) {
@ -96,7 +102,10 @@ describe('bezier', function() {
describe('two same instances', function() { describe('two same instances', function() {
it('should be strictly equals', function() { it('should be strictly equals', function() {
repeat(10)(function() { repeat(10)(function() {
const a = Math.random(), b = 2 * Math.random() - 0.5, c = Math.random(), d = 2 * Math.random() - 0.5; const a = Math.random(),
b = 2 * Math.random() - 0.5,
c = Math.random(),
d = 2 * Math.random() - 0.5;
allEquals(bezier(a, b, c, d), bezier(a, b, c, d), 100, 0); allEquals(bezier(a, b, c, d), bezier(a, b, c, d), 100, 0);
}); });
}); });
@ -104,14 +113,20 @@ describe('bezier', function() {
describe('symetric curves', function() { describe('symetric curves', function() {
it('should have a central value y~=0.5 at x=0.5', function() { it('should have a central value y~=0.5 at x=0.5', function() {
repeat(10)(function() { repeat(10)(function() {
const a = Math.random(), b = 2 * Math.random() - 0.5, c = 1 - a, d = 1 - b; const a = Math.random(),
b = 2 * Math.random() - 0.5,
c = 1 - a,
d = 1 - b;
const easing = bezier(a, b, c, d); const easing = bezier(a, b, c, d);
assertClose(easing(0.5), 0.5, 2); assertClose(easing(0.5), 0.5, 2);
}); });
}); });
it('should be symmetrical', function() { it('should be symmetrical', function() {
repeat(10)(function() { repeat(10)(function() {
const a = Math.random(), b = 2 * Math.random() - 0.5, c = 1 - a, d = 1 - b; const a = Math.random(),
b = 2 * Math.random() - 0.5,
c = 1 - a,
d = 1 - b;
const easing = bezier(a, b, c, d); const easing = bezier(a, b, c, d);
const sym = function(x) { const sym = function(x) {
return 1 - easing(1 - x); return 1 - easing(1 - x);

View File

@ -2,47 +2,64 @@
* BezierEasing - use bezier curve for transition easing function * BezierEasing - use bezier curve for transition easing function
* https://github.com/gre/bezier-easing * https://github.com/gre/bezier-easing
* *
* @format
* @copyright 2014-2015 Gaëtan Renaudeau. MIT License. * @copyright 2014-2015 Gaëtan Renaudeau. MIT License.
* @noflow * @noflow
*/ */
'use strict'; 'use strict';
// These values are established by empiricism with tests (tradeoff: performance VS precision) // These values are established by empiricism with tests (tradeoff: performance VS precision)
const NEWTON_ITERATIONS = 4; const NEWTON_ITERATIONS = 4;
const NEWTON_MIN_SLOPE = 0.001; const NEWTON_MIN_SLOPE = 0.001;
const SUBDIVISION_PRECISION = 0.0000001; const SUBDIVISION_PRECISION = 0.0000001;
const SUBDIVISION_MAX_ITERATIONS = 10; const SUBDIVISION_MAX_ITERATIONS = 10;
const kSplineTableSize = 11; const kSplineTableSize = 11;
const kSampleStepSize = 1.0 / (kSplineTableSize - 1.0); const kSampleStepSize = 1.0 / (kSplineTableSize - 1.0);
const float32ArraySupported = typeof Float32Array === 'function'; const float32ArraySupported = typeof Float32Array === 'function';
function A (aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; } function A(aA1, aA2) {
function B (aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; } return 1.0 - 3.0 * aA2 + 3.0 * aA1;
function C (aA1) { return 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. // 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; } 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. // 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 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) { function binarySubdivide(aX, aA, aB, mX1, mX2) {
let currentX, currentT, i = 0; let currentX,
do { currentT,
currentT = aA + (aB - aA) / 2.0; i = 0;
currentX = calcBezier(currentT, mX1, mX2) - aX; do {
if (currentX > 0.0) { currentT = aA + (aB - aA) / 2.0;
aB = currentT; currentX = calcBezier(currentT, mX1, mX2) - aX;
} else { if (currentX > 0.0) {
aA = currentT; aB = currentT;
} } else {
} while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS); aA = currentT;
return currentT; }
} } while (
Math.abs(currentX) > SUBDIVISION_PRECISION &&
++i < SUBDIVISION_MAX_ITERATIONS
);
return currentT;
}
function newtonRaphsonIterate (aX, aGuessT, mX1, mX2) { function newtonRaphsonIterate(aX, aGuessT, mX1, mX2) {
for (let i = 0; i < NEWTON_ITERATIONS; ++i) { for (let i = 0; i < NEWTON_ITERATIONS; ++i) {
const currentSlope = getSlope(aGuessT, mX1, mX2); const currentSlope = getSlope(aGuessT, mX1, mX2);
if (currentSlope === 0.0) { if (currentSlope === 0.0) {
@ -52,56 +69,71 @@
aGuessT -= currentX / currentSlope; aGuessT -= currentX / currentSlope;
} }
return aGuessT; return aGuessT;
} }
module.exports = function bezier (mX1, mY1, mX2, mY2) { module.exports = function bezier(mX1, mY1, mX2, mY2) {
if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) { // eslint-disable-line yoda if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) {
throw new Error('bezier x values must be in [0, 1] range'); // eslint-disable-line yoda
} throw new Error('bezier x values must be in [0, 1] range');
}
// Precompute samples table // Precompute samples table
const sampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize); const sampleValues = float32ArraySupported
if (mX1 !== mY1 || mX2 !== mY2) { ? new Float32Array(kSplineTableSize)
for (let i = 0; i < kSplineTableSize; ++i) { : new Array(kSplineTableSize);
sampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2); if (mX1 !== mY1 || mX2 !== mY2) {
} for (let i = 0; i < kSplineTableSize; ++i) {
} sampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2);
}
}
function getTForX (aX) { function getTForX(aX) {
let intervalStart = 0.0; let intervalStart = 0.0;
let currentSample = 1; let currentSample = 1;
const lastSample = kSplineTableSize - 1; const lastSample = kSplineTableSize - 1;
for (; currentSample !== lastSample && sampleValues[currentSample] <= aX; ++currentSample) { for (
intervalStart += kSampleStepSize; ;
} currentSample !== lastSample && sampleValues[currentSample] <= aX;
--currentSample; ++currentSample
) {
intervalStart += kSampleStepSize;
}
--currentSample;
// Interpolate to provide an initial guess for t // Interpolate to provide an initial guess for t
const dist = (aX - sampleValues[currentSample]) / (sampleValues[currentSample + 1] - sampleValues[currentSample]); const dist =
const guessForT = intervalStart + dist * kSampleStepSize; (aX - sampleValues[currentSample]) /
(sampleValues[currentSample + 1] - sampleValues[currentSample]);
const guessForT = intervalStart + dist * kSampleStepSize;
const initialSlope = getSlope(guessForT, mX1, mX2); const initialSlope = getSlope(guessForT, mX1, mX2);
if (initialSlope >= NEWTON_MIN_SLOPE) { if (initialSlope >= NEWTON_MIN_SLOPE) {
return newtonRaphsonIterate(aX, guessForT, mX1, mX2); return newtonRaphsonIterate(aX, guessForT, mX1, mX2);
} else if (initialSlope === 0.0) { } else if (initialSlope === 0.0) {
return guessForT; return guessForT;
} else { } else {
return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize, mX1, mX2); return binarySubdivide(
} aX,
} intervalStart,
intervalStart + kSampleStepSize,
mX1,
mX2,
);
}
}
return function BezierEasing (x) { return function BezierEasing(x) {
if (mX1 === mY1 && mX2 === mY2) { if (mX1 === mY1 && mX2 === mY2) {
return x; // linear return x; // linear
} }
// Because JavaScript number are imprecise, we should guarantee the extremes are right. // Because JavaScript number are imprecise, we should guarantee the extremes are right.
if (x === 0) { if (x === 0) {
return 0; return 0;
} }
if (x === 1) { if (x === 1) {
return 1; return 1;
} }
return calcBezier(getTForX(x), mY1, mY2); return calcBezier(getTForX(x), mY1, mY2);
}; };
}; };

View File

@ -3,11 +3,13 @@
* *
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*
* @format
*/ */
'use strict'; 'use strict';
module.exports = { module.exports = {
createInteractionHandle: function() {}, createInteractionHandle: function() {},
clearInteractionHandle: function() {} clearInteractionHandle: function() {},
}; };

View File

@ -3,6 +3,8 @@
* *
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*
* @format
*/ */
'use strict'; 'use strict';

View File

@ -3,7 +3,10 @@
* *
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*
* @format
*/ */
'use strict'; 'use strict';
module.exports = function(style) { module.exports = function(style) {
return style; return style;

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const MissingNativeEventEmitterShim = require('MissingNativeEventEmitterShim'); const MissingNativeEventEmitterShim = require('MissingNativeEventEmitterShim');
@ -23,7 +25,6 @@ const invariant = require('fbjs/lib/invariant');
* See http://facebook.github.io/react-native/docs/appstate.html * See http://facebook.github.io/react-native/docs/appstate.html
*/ */
class AppState extends NativeEventEmitter { class AppState extends NativeEventEmitter {
_eventHandlers: Object; _eventHandlers: Object;
currentState: ?string; currentState: ?string;
isAvailable: boolean = true; isAvailable: boolean = true;
@ -47,27 +48,21 @@ class AppState extends NativeEventEmitter {
// prop is up to date, we have to register an observer that updates it // prop is up to date, we have to register an observer that updates it
// whenever the state changes, even if nobody cares. We should just // whenever the state changes, even if nobody cares. We should just
// deprecate the `currentState` property and get rid of this. // deprecate the `currentState` property and get rid of this.
this.addListener( this.addListener('appStateDidChange', appStateData => {
'appStateDidChange', eventUpdated = true;
(appStateData) => { this.currentState = appStateData.app_state;
eventUpdated = true; });
this.currentState = appStateData.app_state;
}
);
// TODO: see above - this request just populates the value of `currentState` // TODO: see above - this request just populates the value of `currentState`
// when the module is first initialized. Would be better to get rid of the // when the module is first initialized. Would be better to get rid of the
// prop and expose `getCurrentAppState` method directly. // prop and expose `getCurrentAppState` method directly.
RCTAppState.getCurrentAppState( RCTAppState.getCurrentAppState(appStateData => {
(appStateData) => { // It's possible that the state will have changed here & listeners need to be notified
// It's possible that the state will have changed here & listeners need to be notified if (!eventUpdated && this.currentState !== appStateData.app_state) {
if (!eventUpdated && this.currentState !== appStateData.app_state) { this.currentState = appStateData.app_state;
this.currentState = appStateData.app_state; this.emit('appStateDidChange', appStateData);
this.emit('appStateDidChange', appStateData); }
} }, logError);
},
logError
);
} }
// TODO: now that AppState is a subclass of NativeEventEmitter, we could // TODO: now that AppState is a subclass of NativeEventEmitter, we could
@ -75,32 +70,30 @@ class AppState extends NativeEventEmitter {
// addListener` and `listener.remove()` directly. That will be a breaking // addListener` and `listener.remove()` directly. That will be a breaking
// change though, as both the method and event names are different // change though, as both the method and event names are different
// (addListener events are currently required to be globally unique). // (addListener events are currently required to be globally unique).
/** /**
* Add a handler to AppState changes by listening to the `change` event type * Add a handler to AppState changes by listening to the `change` event type
* and providing the handler. * and providing the handler.
* *
* See http://facebook.github.io/react-native/docs/appstate.html#addeventlistener * See http://facebook.github.io/react-native/docs/appstate.html#addeventlistener
*/ */
addEventListener( addEventListener(type: string, handler: Function) {
type: string,
handler: Function
) {
invariant( invariant(
['change', 'memoryWarning'].indexOf(type) !== -1, ['change', 'memoryWarning'].indexOf(type) !== -1,
'Trying to subscribe to unknown event: "%s"', type 'Trying to subscribe to unknown event: "%s"',
type,
); );
if (type === 'change') { if (type === 'change') {
this._eventHandlers[type].set(handler, this.addListener( this._eventHandlers[type].set(
'appStateDidChange', handler,
(appStateData) => { this.addListener('appStateDidChange', appStateData => {
handler(appStateData.app_state); handler(appStateData.app_state);
} }),
)); );
} else if (type === 'memoryWarning') { } else if (type === 'memoryWarning') {
this._eventHandlers[type].set(handler, this.addListener( this._eventHandlers[type].set(
'memoryWarning', handler,
handler this.addListener('memoryWarning', handler),
)); );
} }
} }
@ -109,13 +102,11 @@ class AppState extends NativeEventEmitter {
* *
* See http://facebook.github.io/react-native/docs/appstate.html#removeeventlistener * See http://facebook.github.io/react-native/docs/appstate.html#removeeventlistener
*/ */
removeEventListener( removeEventListener(type: string, handler: Function) {
type: string,
handler: Function
) {
invariant( invariant(
['change', 'memoryWarning'].indexOf(type) !== -1, ['change', 'memoryWarning'].indexOf(type) !== -1,
'Trying to remove listener for unknown event: "%s"', type 'Trying to remove listener for unknown event: "%s"',
type,
); );
if (!this._eventHandlers[type].has(handler)) { if (!this._eventHandlers[type].has(handler)) {
return; return;

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const MessageQueue = require('MessageQueue'); const MessageQueue = require('MessageQueue');

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const BatchedBridge = require('BatchedBridge'); const BatchedBridge = require('BatchedBridge');
@ -15,53 +17,66 @@ const invariant = require('fbjs/lib/invariant');
import type {ExtendedError} from 'parseErrorStack'; import type {ExtendedError} from 'parseErrorStack';
type ModuleConfig = [ type ModuleConfig = [
string, /* name */ string /* name */,
?Object, /* constants */ ?Object /* constants */,
Array<string>, /* functions */ Array<string> /* functions */,
Array<number>, /* promise method IDs */ Array<number> /* promise method IDs */,
Array<number>, /* sync method IDs */ Array<number> /* sync method IDs */,
]; ];
export type MethodType = 'async' | 'promise' | 'sync'; export type MethodType = 'async' | 'promise' | 'sync';
function genModule(config: ?ModuleConfig, moduleID: number): ?{name: string, module?: Object} { function genModule(
config: ?ModuleConfig,
moduleID: number,
): ?{name: string, module?: Object} {
if (!config) { if (!config) {
return null; return null;
} }
const [moduleName, constants, methods, promiseMethods, syncMethods] = config; const [moduleName, constants, methods, promiseMethods, syncMethods] = config;
invariant(!moduleName.startsWith('RCT') && !moduleName.startsWith('RK'), invariant(
'Module name prefixes should\'ve been stripped by the native side ' + !moduleName.startsWith('RCT') && !moduleName.startsWith('RK'),
'but wasn\'t for ' + moduleName); "Module name prefixes should've been stripped by the native side " +
"but wasn't for " +
moduleName,
);
if (!constants && !methods) { if (!constants && !methods) {
// Module contents will be filled in lazily later // Module contents will be filled in lazily later
return { name: moduleName }; return {name: moduleName};
} }
const module = {}; const module = {};
methods && methods.forEach((methodName, methodID) => { methods &&
const isPromise = promiseMethods && arrayContains(promiseMethods, methodID); methods.forEach((methodName, methodID) => {
const isSync = syncMethods && arrayContains(syncMethods, methodID); const isPromise =
invariant(!isPromise || !isSync, 'Cannot have a method that is both async and a sync hook'); promiseMethods && arrayContains(promiseMethods, methodID);
const methodType = isPromise ? 'promise' : isSync ? 'sync' : 'async'; const isSync = syncMethods && arrayContains(syncMethods, methodID);
module[methodName] = genMethod(moduleID, methodID, methodType); invariant(
}); !isPromise || !isSync,
'Cannot have a method that is both async and a sync hook',
);
const methodType = isPromise ? 'promise' : isSync ? 'sync' : 'async';
module[methodName] = genMethod(moduleID, methodID, methodType);
});
Object.assign(module, constants); Object.assign(module, constants);
if (__DEV__) { if (__DEV__) {
BatchedBridge.createDebugLookup(moduleID, moduleName, methods); BatchedBridge.createDebugLookup(moduleID, moduleName, methods);
} }
return { name: moduleName, module }; return {name: moduleName, module};
} }
// export this method as a global so we can call it from native // export this method as a global so we can call it from native
global.__fbGenNativeModule = genModule; global.__fbGenNativeModule = genModule;
function loadModule(name: string, moduleID: number): ?Object { function loadModule(name: string, moduleID: number): ?Object {
invariant(global.nativeRequireModuleConfig, invariant(
'Can\'t lazily create module without nativeRequireModuleConfig'); global.nativeRequireModuleConfig,
"Can't lazily create module without nativeRequireModuleConfig",
);
const config = global.nativeRequireModuleConfig(name); const config = global.nativeRequireModuleConfig(name);
const info = genModule(config, moduleID); const info = genModule(config, moduleID);
return info && info.module; return info && info.module;
@ -72,18 +87,25 @@ function genMethod(moduleID: number, methodID: number, type: MethodType) {
if (type === 'promise') { if (type === 'promise') {
fn = function(...args: Array<any>) { fn = function(...args: Array<any>) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
BatchedBridge.enqueueNativeCall(moduleID, methodID, args, BatchedBridge.enqueueNativeCall(
(data) => resolve(data), moduleID,
(errorData) => reject(createErrorFromErrorData(errorData))); methodID,
args,
data => resolve(data),
errorData => reject(createErrorFromErrorData(errorData)),
);
}); });
}; };
} else if (type === 'sync') { } else if (type === 'sync') {
fn = function(...args: Array<any>) { fn = function(...args: Array<any>) {
if (__DEV__) { if (__DEV__) {
invariant(global.nativeCallSyncHook, 'Calling synchronous methods on native ' + invariant(
'modules is not supported in Chrome.\n\n Consider providing alternative ' + global.nativeCallSyncHook,
'methods to expose this method in debug mode, e.g. by exposing constants ' + 'Calling synchronous methods on native ' +
'ahead-of-time.'); 'modules is not supported in Chrome.\n\n Consider providing alternative ' +
'methods to expose this method in debug mode, e.g. by exposing constants ' +
'ahead-of-time.',
);
} }
return global.nativeCallSyncHook(moduleID, methodID, args); return global.nativeCallSyncHook(moduleID, methodID, args);
}; };
@ -93,15 +115,22 @@ function genMethod(moduleID: number, methodID: number, type: MethodType) {
const secondLastArg = args.length > 1 ? args[args.length - 2] : null; const secondLastArg = args.length > 1 ? args[args.length - 2] : null;
const hasSuccessCallback = typeof lastArg === 'function'; const hasSuccessCallback = typeof lastArg === 'function';
const hasErrorCallback = typeof secondLastArg === 'function'; const hasErrorCallback = typeof secondLastArg === 'function';
hasErrorCallback && invariant( hasErrorCallback &&
hasSuccessCallback, invariant(
'Cannot have a non-function arg after a function arg.' hasSuccessCallback,
); 'Cannot have a non-function arg after a function arg.',
);
const onSuccess = hasSuccessCallback ? lastArg : null; const onSuccess = hasSuccessCallback ? lastArg : null;
const onFail = hasErrorCallback ? secondLastArg : null; const onFail = hasErrorCallback ? secondLastArg : null;
const callbackCount = hasSuccessCallback + hasErrorCallback; const callbackCount = hasSuccessCallback + hasErrorCallback;
args = args.slice(0, args.length - callbackCount); args = args.slice(0, args.length - callbackCount);
BatchedBridge.enqueueNativeCall(moduleID, methodID, args, onFail, onSuccess); BatchedBridge.enqueueNativeCall(
moduleID,
methodID,
args,
onFail,
onSuccess,
);
}; };
} }
fn.type = type; fn.type = type;
@ -113,41 +142,43 @@ function arrayContains<T>(array: Array<T>, value: T): boolean {
} }
function createErrorFromErrorData(errorData: {message: string}): ExtendedError { function createErrorFromErrorData(errorData: {message: string}): ExtendedError {
const { const {message, ...extraErrorInfo} = errorData || {};
message, const error: ExtendedError = new Error(message);
...extraErrorInfo
} = errorData || {};
const error : ExtendedError = new Error(message);
error.framesToPop = 1; error.framesToPop = 1;
return Object.assign(error, extraErrorInfo); return Object.assign(error, extraErrorInfo);
} }
let NativeModules : {[moduleName: string]: Object} = {}; let NativeModules: {[moduleName: string]: Object} = {};
if (global.nativeModuleProxy) { if (global.nativeModuleProxy) {
NativeModules = global.nativeModuleProxy; NativeModules = global.nativeModuleProxy;
} else { } else {
const bridgeConfig = global.__fbBatchedBridgeConfig; const bridgeConfig = global.__fbBatchedBridgeConfig;
invariant(bridgeConfig, '__fbBatchedBridgeConfig is not set, cannot invoke native modules'); invariant(
bridgeConfig,
'__fbBatchedBridgeConfig is not set, cannot invoke native modules',
);
const defineLazyObjectProperty = require('defineLazyObjectProperty'); const defineLazyObjectProperty = require('defineLazyObjectProperty');
(bridgeConfig.remoteModuleConfig || []).forEach((config: ModuleConfig, moduleID: number) => { (bridgeConfig.remoteModuleConfig || []).forEach(
// Initially this config will only contain the module name when running in JSC. The actual (config: ModuleConfig, moduleID: number) => {
// configuration of the module will be lazily loaded. // Initially this config will only contain the module name when running in JSC. The actual
const info = genModule(config, moduleID); // configuration of the module will be lazily loaded.
if (!info) { const info = genModule(config, moduleID);
return; if (!info) {
} return;
}
if (info.module) { if (info.module) {
NativeModules[info.name] = info.module; NativeModules[info.name] = info.module;
} }
// If there's no module config, define a lazy getter // If there's no module config, define a lazy getter
else { else {
defineLazyObjectProperty(NativeModules, info.name, { defineLazyObjectProperty(NativeModules, info.name, {
get: () => loadModule(info.name, moduleID) get: () => loadModule(info.name, moduleID),
}); });
} }
}); },
);
} }
module.exports = NativeModules; module.exports = NativeModules;

View File

@ -5,11 +5,14 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* These don't actually exist anywhere in the code. * These don't actually exist anywhere in the code.
*
* @format
*/ */
'use strict'; 'use strict';
const remoteModulesConfig = [ const remoteModulesConfig = [
['RemoteModule1',null,['remoteMethod','promiseMethod'],[]], ['RemoteModule1', null, ['remoteMethod', 'promiseMethod'], []],
['RemoteModule2',null,['remoteMethod','promiseMethod'],[]], ['RemoteModule2', null, ['remoteMethod', 'promiseMethod'], []],
]; ];
const MessageQueueTestConfig = { const MessageQueueTestConfig = {

View File

@ -4,7 +4,9 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
*/ */
'use strict'; 'use strict';
/** /**
@ -13,10 +15,8 @@
* cases. * cases.
*/ */
const MessageQueueTestModule = { const MessageQueueTestModule = {
testHook1: function() { testHook1: function() {},
}, testHook2: function() {},
testHook2: function() {
}
}; };
module.exports = MessageQueueTestModule; module.exports = MessageQueueTestModule;

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @emails oncall+react_native * @emails oncall+react_native
*/ */
'use strict'; 'use strict';
jest jest
@ -59,7 +61,12 @@ describe('MessageQueue', function() {
const onSucc = jest.fn(); const onSucc = jest.fn();
// Perform communication // Perform communication
NativeModules.RemoteModule1.promiseMethod('paloAlto', 'menloPark', onFail, onSucc); NativeModules.RemoteModule1.promiseMethod(
'paloAlto',
'menloPark',
onFail,
onSucc,
);
NativeModules.RemoteModule2.promiseMethod('mac', 'windows', onFail, onSucc); NativeModules.RemoteModule2.promiseMethod('mac', 'windows', onFail, onSucc);
const resultingRemoteInvocations = BatchedBridge.flushedQueue(); const resultingRemoteInvocations = BatchedBridge.flushedQueue();
@ -73,9 +80,10 @@ describe('MessageQueue', function() {
expect(resultingRemoteInvocations[0][0]).toBe(0); // `RemoteModule1` expect(resultingRemoteInvocations[0][0]).toBe(0); // `RemoteModule1`
expect(resultingRemoteInvocations[1][0]).toBe(1); // `promiseMethod` expect(resultingRemoteInvocations[1][0]).toBe(1); // `promiseMethod`
expect([ // the arguments expect([
// the arguments
resultingRemoteInvocations[2][0][0], resultingRemoteInvocations[2][0][0],
resultingRemoteInvocations[2][0][1] resultingRemoteInvocations[2][0][1],
]).toEqual(['paloAlto', 'menloPark']); ]).toEqual(['paloAlto', 'menloPark']);
// Callbacks ids are tacked onto the end of the remote arguments. // Callbacks ids are tacked onto the end of the remote arguments.
const firstFailCBID = resultingRemoteInvocations[2][0][2]; const firstFailCBID = resultingRemoteInvocations[2][0][2];
@ -83,9 +91,10 @@ describe('MessageQueue', function() {
expect(resultingRemoteInvocations[0][1]).toBe(1); // `RemoteModule2` expect(resultingRemoteInvocations[0][1]).toBe(1); // `RemoteModule2`
expect(resultingRemoteInvocations[1][1]).toBe(1); // `promiseMethod` expect(resultingRemoteInvocations[1][1]).toBe(1); // `promiseMethod`
expect([ // the arguments expect([
// the arguments
resultingRemoteInvocations[2][1][0], resultingRemoteInvocations[2][1][0],
resultingRemoteInvocations[2][1][1] resultingRemoteInvocations[2][1][1],
]).toEqual(['mac', 'windows']); ]).toEqual(['mac', 'windows']);
const secondFailCBID = resultingRemoteInvocations[2][1][2]; const secondFailCBID = resultingRemoteInvocations[2][1][2];
const secondSuccCBID = resultingRemoteInvocations[2][1][3]; const secondSuccCBID = resultingRemoteInvocations[2][1][3];

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const RCTDeviceEventEmitter = require('RCTDeviceEventEmitter'); const RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
@ -14,12 +16,14 @@ const infoLog = require('infoLog');
import type EmitterSubscription from 'EmitterSubscription'; import type EmitterSubscription from 'EmitterSubscription';
type ExtraData = { [key: string]: string }; type ExtraData = {[key: string]: string};
type SourceCallback = () => string; type SourceCallback = () => string;
type DebugData = { extras: ExtraData, files: ExtraData }; type DebugData = {extras: ExtraData, files: ExtraData};
function defaultExtras() { function defaultExtras() {
BugReporting.addFileSource('react_hierarchy.txt', () => require('dumpReactTree')()); BugReporting.addFileSource('react_hierarchy.txt', () =>
require('dumpReactTree')(),
);
} }
/** /**
@ -36,14 +40,20 @@ class BugReporting {
static _maybeInit() { static _maybeInit() {
if (!BugReporting._subscription) { if (!BugReporting._subscription) {
BugReporting._subscription = RCTDeviceEventEmitter BugReporting._subscription = RCTDeviceEventEmitter.addListener(
.addListener('collectBugExtraData', BugReporting.collectExtraData, null); 'collectBugExtraData',
BugReporting.collectExtraData,
null,
);
defaultExtras(); defaultExtras();
} }
if (!BugReporting._redboxSubscription) { if (!BugReporting._redboxSubscription) {
BugReporting._redboxSubscription = RCTDeviceEventEmitter BugReporting._redboxSubscription = RCTDeviceEventEmitter.addListener(
.addListener('collectRedBoxExtraData', BugReporting.collectExtraData, null); 'collectRedBoxExtraData',
BugReporting.collectExtraData,
null,
);
} }
} }
@ -55,7 +65,10 @@ class BugReporting {
* *
* Conflicts trample with a warning. * Conflicts trample with a warning.
*/ */
static addSource(key: string, callback: SourceCallback): {remove: () => void} { static addSource(
key: string,
callback: SourceCallback,
): {remove: () => void} {
return this._addSource(key, callback, BugReporting._extraSources); return this._addSource(key, callback, BugReporting._extraSources);
} }
@ -67,17 +80,30 @@ class BugReporting {
* *
* Conflicts trample with a warning. * Conflicts trample with a warning.
*/ */
static addFileSource(key: string, callback: SourceCallback): {remove: () => void} { static addFileSource(
key: string,
callback: SourceCallback,
): {remove: () => void} {
return this._addSource(key, callback, BugReporting._fileSources); return this._addSource(key, callback, BugReporting._fileSources);
} }
static _addSource(key: string, callback: SourceCallback, source: Map<string, SourceCallback>): {remove: () => void} { static _addSource(
key: string,
callback: SourceCallback,
source: Map<string, SourceCallback>,
): {remove: () => void} {
BugReporting._maybeInit(); BugReporting._maybeInit();
if (source.has(key)) { if (source.has(key)) {
console.warn(`BugReporting.add* called multiple times for same key '${key}'`); console.warn(
`BugReporting.add* called multiple times for same key '${key}'`,
);
} }
source.set(key, callback); source.set(key, callback);
return {remove: () => { source.delete(key); }}; return {
remove: () => {
source.delete(key);
},
};
} }
/** /**
@ -106,7 +132,7 @@ class BugReporting {
RedBoxNativeModule.setExtraData && RedBoxNativeModule.setExtraData &&
RedBoxNativeModule.setExtraData(extraData, 'From BugReporting.js'); RedBoxNativeModule.setExtraData(extraData, 'From BugReporting.js');
return { extras: extraData, files: fileData }; return {extras: extraData, files: fileData};
} }
} }

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
/* /*
@ -35,7 +37,7 @@ function getReactTree() {
'React tree dumps have been temporarily disabled while React is ' + 'React tree dumps have been temporarily disabled while React is ' +
'upgraded to Fiber.' 'upgraded to Fiber.'
); );
/* /*
let output = ''; let output = '';
const rootIds = Object.getOwnPropertyNames(ReactNativeMount._instancesByContainerID); const rootIds = Object.getOwnPropertyNames(ReactNativeMount._instancesByContainerID);
for (const rootId of rootIds) { for (const rootId of rootIds) {

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
/** /**
@ -31,7 +33,10 @@ function getData(element: Object): Object {
if (typeof element !== 'object') { if (typeof element !== 'object') {
nodeType = 'Text'; nodeType = 'Text';
text = element + ''; text = element + '';
} else if (element._currentElement === null || element._currentElement === false) { } else if (
element._currentElement === null ||
element._currentElement === false
) {
nodeType = 'Empty'; nodeType = 'Empty';
} else if (element._renderedComponent) { } else if (element._renderedComponent) {
nodeType = 'NativeWrapper'; nodeType = 'NativeWrapper';
@ -65,7 +70,11 @@ function getData(element: Object): Object {
name = element.getName(); name = element.getName();
// 0.14 top-level wrapper // 0.14 top-level wrapper
// TODO(jared): The backend should just act as if these don't exist. // TODO(jared): The backend should just act as if these don't exist.
if (element._renderedComponent && element._currentElement.props === element._renderedComponent._currentElement) { if (
element._renderedComponent &&
element._currentElement.props ===
element._renderedComponent._currentElement
) {
nodeType = 'Wrapper'; nodeType = 'Wrapper';
} }
if (name === null) { if (name === null) {
@ -133,7 +142,7 @@ function setInContext(inst, path: Array<string | number>, value: any) {
function setIn(obj: Object, path: Array<string | number>, value: any) { function setIn(obj: Object, path: Array<string | number>, value: any) {
const last = path.pop(); const last = path.pop();
const parent = path.reduce((obj_, attr) => obj_ ? obj_[attr] : null, obj); const parent = path.reduce((obj_, attr) => (obj_ ? obj_[attr] : null), obj);
if (parent) { if (parent) {
parent[last] = value; parent[last] = value;
} }
@ -158,7 +167,11 @@ function copyWithSetImpl(obj, path, idx, value) {
return updated; return updated;
} }
function copyWithSet(obj: Object | Array<any>, path: Array<string | number>, value: any): Object | Array<any> { function copyWithSet(
obj: Object | Array<any>,
path: Array<string | number>,
value: any,
): Object | Array<any> {
return copyWithSetImpl(obj, path, 0, value); return copyWithSetImpl(obj, path, 0, value);
} }

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const RCTImagePicker = require('NativeModules').ImagePickerIOS; const RCTImagePicker = require('NativeModules').ImagePickerIOS;
@ -17,20 +19,36 @@ const ImagePickerIOS = {
canUseCamera: function(callback: Function) { canUseCamera: function(callback: Function) {
return RCTImagePicker.canUseCamera(callback); return RCTImagePicker.canUseCamera(callback);
}, },
openCameraDialog: function(config: Object, successCallback: Function, cancelCallback: Function) { openCameraDialog: function(
config: Object,
successCallback: Function,
cancelCallback: Function,
) {
config = { config = {
videoMode: false, videoMode: false,
...config, ...config,
}; };
return RCTImagePicker.openCameraDialog(config, successCallback, cancelCallback); return RCTImagePicker.openCameraDialog(
config,
successCallback,
cancelCallback,
);
}, },
openSelectDialog: function(config: Object, successCallback: Function, cancelCallback: Function) { openSelectDialog: function(
config: Object,
successCallback: Function,
cancelCallback: Function,
) {
config = { config = {
showImages: true, showImages: true,
showVideos: false, showVideos: false,
...config, ...config,
}; };
return RCTImagePicker.openSelectDialog(config, successCallback, cancelCallback); return RCTImagePicker.openSelectDialog(
config,
successCallback,
cancelCallback,
);
}, },
}; };

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
/* eslint no-bitwise: 0 */ /* eslint no-bitwise: 0 */
'use strict'; 'use strict';
@ -30,30 +32,39 @@ function normalizeColor(color: string | number): ?number {
if ((match = matchers.rgb.exec(color))) { if ((match = matchers.rgb.exec(color))) {
return ( return (
(// b // b
(parse255(match[1]) << 24 | // r ((parse255(match[1]) << 24) | // r
parse255(match[2]) << 16 | // g (parse255(match[2]) << 16) | // g
parse255(match[3]) << 8 | 0x000000ff)) // a (parse255(match[3]) << 8) |
) >>> 0; 0x000000ff) >>> // a
0
);
} }
if ((match = matchers.rgba.exec(color))) { if ((match = matchers.rgba.exec(color))) {
return ( return (
(// b // b
(parse255(match[1]) << 24 | // r ((parse255(match[1]) << 24) | // r
parse255(match[2]) << 16 | // g (parse255(match[2]) << 16) | // g
parse255(match[3]) << 8 | parse1(match[4]))) // a (parse255(match[3]) << 8) |
) >>> 0; parse1(match[4])) >>> // a
0
);
} }
if ((match = matchers.hex3.exec(color))) { if ((match = matchers.hex3.exec(color))) {
return parseInt( return (
match[1] + match[1] + // r parseInt(
match[2] + match[2] + // g match[1] +
match[3] + match[3] + // b match[1] + // r
'ff', // a match[2] +
16 match[2] + // g
) >>> 0; match[3] +
match[3] + // b
'ff', // a
16,
) >>> 0
);
} }
// https://drafts.csswg.org/css-color-4/#hex-notation // https://drafts.csswg.org/css-color-4/#hex-notation
@ -62,13 +73,19 @@ function normalizeColor(color: string | number): ?number {
} }
if ((match = matchers.hex4.exec(color))) { if ((match = matchers.hex4.exec(color))) {
return parseInt( return (
match[1] + match[1] + // r parseInt(
match[2] + match[2] + // g match[1] +
match[3] + match[3] + // b match[1] + // r
match[4] + match[4], // a match[2] +
16 match[2] + // g
) >>> 0; match[3] +
match[3] + // b
match[4] +
match[4], // a
16,
) >>> 0
);
} }
if ((match = matchers.hsl.exec(color))) { if ((match = matchers.hsl.exec(color))) {
@ -76,9 +93,11 @@ function normalizeColor(color: string | number): ?number {
(hslToRgb( (hslToRgb(
parse360(match[1]), // h parse360(match[1]), // h
parsePercentage(match[2]), // s parsePercentage(match[2]), // s
parsePercentage(match[3]) // l parsePercentage(match[3]), // l
) | 0x000000ff) // a ) |
) >>> 0; 0x000000ff) >>> // a
0
);
} }
if ((match = matchers.hsla.exec(color))) { if ((match = matchers.hsla.exec(color))) {
@ -86,9 +105,11 @@ function normalizeColor(color: string | number): ?number {
(hslToRgb( (hslToRgb(
parse360(match[1]), // h parse360(match[1]), // h
parsePercentage(match[2]), // s parsePercentage(match[2]), // s
parsePercentage(match[3]) // l parsePercentage(match[3]), // l
) | parse1(match[4])) // a ) |
) >>> 0; parse1(match[4])) >>> // a
0
);
} }
return null; return null;
@ -121,9 +142,9 @@ function hslToRgb(h: number, s: number, l: number): number {
const b = hue2rgb(p, q, h - 1 / 3); const b = hue2rgb(p, q, h - 1 / 3);
return ( return (
Math.round(r * 255) << 24 | (Math.round(r * 255) << 24) |
Math.round(g * 255) << 16 | (Math.round(g * 255) << 16) |
Math.round(b * 255) << 8 (Math.round(b * 255) << 8)
); );
} }
@ -159,7 +180,7 @@ function parse255(str: string): number {
function parse360(str: string): number { function parse360(str: string): number {
const int = parseFloat(str); const int = parseFloat(str);
return (((int % 360) + 360) % 360) / 360; return ((int % 360 + 360) % 360) / 360;
} }
function parse1(str: string): number { function parse1(str: string): number {

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const NativeModules = require('NativeModules'); const NativeModules = require('NativeModules');
@ -32,33 +34,30 @@ const _subscriptions = new Map();
*/ */
const AccessibilityInfo = { const AccessibilityInfo = {
fetch: function(): Promise { fetch: function(): Promise {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
RCTAccessibilityInfo.isTouchExplorationEnabled( RCTAccessibilityInfo.isTouchExplorationEnabled(function(resp) {
function(resp) { resolve(resp);
resolve(resp); });
}
);
}); });
}, },
addEventListener: function ( addEventListener: function(
eventName: ChangeEventName, eventName: ChangeEventName,
handler: Function handler: Function,
): void { ): void {
const listener = RCTDeviceEventEmitter.addListener( const listener = RCTDeviceEventEmitter.addListener(
TOUCH_EXPLORATION_EVENT, TOUCH_EXPLORATION_EVENT,
(enabled) => { enabled => {
handler(enabled); handler(enabled);
} },
); );
_subscriptions.set(handler, listener); _subscriptions.set(handler, listener);
}, },
removeEventListener: function( removeEventListener: function(
eventName: ChangeEventName, eventName: ChangeEventName,
handler: Function handler: Function,
): void { ): void {
const listener = _subscriptions.get(handler); const listener = _subscriptions.get(handler);
if (!listener) { if (!listener) {
@ -67,7 +66,6 @@ const AccessibilityInfo = {
listener.remove(); listener.remove();
_subscriptions.delete(handler); _subscriptions.delete(handler);
}, },
}; };
module.exports = AccessibilityInfo; module.exports = AccessibilityInfo;

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const NativeModules = require('NativeModules'); const NativeModules = require('NativeModules');
@ -19,7 +21,7 @@ const ANNOUNCEMENT_DID_FINISH_EVENT = 'announcementDidFinish';
type ChangeEventName = $Enum<{ type ChangeEventName = $Enum<{
change: string, change: string,
announcementFinished: string announcementFinished: string,
}>; }>;
const _subscriptions = new Map(); const _subscriptions = new Map();
@ -34,7 +36,6 @@ const _subscriptions = new Map();
* See http://facebook.github.io/react-native/docs/accessibilityinfo.html * See http://facebook.github.io/react-native/docs/accessibilityinfo.html
*/ */
const AccessibilityInfo = { const AccessibilityInfo = {
/** /**
* Query whether a screen reader is currently enabled. * Query whether a screen reader is currently enabled.
* *
@ -45,10 +46,7 @@ const AccessibilityInfo = {
*/ */
fetch: function(): Promise { fetch: function(): Promise {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
AccessibilityManager.getCurrentVoiceOverState( AccessibilityManager.getCurrentVoiceOverState(resolve, reject);
resolve,
reject
);
}); });
}, },
@ -67,27 +65,28 @@ const AccessibilityInfo = {
* *
* See http://facebook.github.io/react-native/docs/accessibilityinfo.html#addeventlistener * See http://facebook.github.io/react-native/docs/accessibilityinfo.html#addeventlistener
*/ */
addEventListener: function ( addEventListener: function(
eventName: ChangeEventName, eventName: ChangeEventName,
handler: Function handler: Function,
): Object { ): Object {
let listener; let listener;
if (eventName === 'change') { if (eventName === 'change') {
listener = RCTDeviceEventEmitter.addListener( listener = RCTDeviceEventEmitter.addListener(VOICE_OVER_EVENT, handler);
VOICE_OVER_EVENT,
handler
);
} else if (eventName === 'announcementFinished') { } else if (eventName === 'announcementFinished') {
listener = RCTDeviceEventEmitter.addListener( listener = RCTDeviceEventEmitter.addListener(
ANNOUNCEMENT_DID_FINISH_EVENT, ANNOUNCEMENT_DID_FINISH_EVENT,
handler handler,
); );
} }
_subscriptions.set(handler, listener); _subscriptions.set(handler, listener);
return { return {
remove: AccessibilityInfo.removeEventListener.bind(null, eventName, handler), remove: AccessibilityInfo.removeEventListener.bind(
null,
eventName,
handler,
),
}; };
}, },
@ -98,9 +97,7 @@ const AccessibilityInfo = {
* *
* See http://facebook.github.io/react-native/docs/accessibilityinfo.html#setaccessibilityfocus * See http://facebook.github.io/react-native/docs/accessibilityinfo.html#setaccessibilityfocus
*/ */
setAccessibilityFocus: function( setAccessibilityFocus: function(reactTag: number): void {
reactTag: number
): void {
AccessibilityManager.setAccessibilityFocus(reactTag); AccessibilityManager.setAccessibilityFocus(reactTag);
}, },
@ -111,9 +108,7 @@ const AccessibilityInfo = {
* *
* See http://facebook.github.io/react-native/docs/accessibilityinfo.html#announceforaccessibility * See http://facebook.github.io/react-native/docs/accessibilityinfo.html#announceforaccessibility
*/ */
announceForAccessibility: function( announceForAccessibility: function(announcement: string): void {
announcement: string
): void {
AccessibilityManager.announceForAccessibility(announcement); AccessibilityManager.announceForAccessibility(announcement);
}, },
@ -124,7 +119,7 @@ const AccessibilityInfo = {
*/ */
removeEventListener: function( removeEventListener: function(
eventName: ChangeEventName, eventName: ChangeEventName,
handler: Function handler: Function,
): void { ): void {
const listener = _subscriptions.get(handler); const listener = _subscriptions.get(handler);
if (!listener) { if (!listener) {
@ -133,7 +128,6 @@ const AccessibilityInfo = {
listener.remove(); listener.remove();
_subscriptions.delete(handler); _subscriptions.delete(handler);
}, },
}; };
module.exports = AccessibilityInfo; module.exports = AccessibilityInfo;

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const ColorPropType = require('ColorPropType'); const ColorPropType = require('ColorPropType');
@ -31,7 +33,7 @@ type DefaultProps = {
color: any, color: any,
hidesWhenStopped: boolean, hidesWhenStopped: boolean,
size: IndicatorSize, size: IndicatorSize,
} };
/** /**
* Displays a circular loading indicator. * Displays a circular loading indicator.
@ -63,7 +65,7 @@ const ActivityIndicator = createReactClass({
* See http://facebook.github.io/react-native/docs/activityindicator.html#size * See http://facebook.github.io/react-native/docs/activityindicator.html#size
*/ */
size: PropTypes.oneOfType([ size: PropTypes.oneOfType([
PropTypes.oneOf([ 'small', 'large' ]), PropTypes.oneOf(['small', 'large']),
PropTypes.number, PropTypes.number,
]), ]),
/** /**
@ -117,14 +119,14 @@ const ActivityIndicator = createReactClass({
)} )}
</View> </View>
); );
} },
}); });
if (Platform.OS === 'ios') { if (Platform.OS === 'ios') {
RCTActivityIndicator = requireNativeComponent( RCTActivityIndicator = requireNativeComponent(
'RCTActivityIndicatorView', 'RCTActivityIndicatorView',
ActivityIndicator, ActivityIndicator,
{ nativeOnly: { activityIndicatorViewStyle: true } } {nativeOnly: {activityIndicatorViewStyle: true}},
); );
} }

View File

@ -4,12 +4,15 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const Platform = require('Platform'); const Platform = require('Platform');
const TVNavigationEventEmitter = require('NativeModules').TVNavigationEventEmitter; const TVNavigationEventEmitter = require('NativeModules')
.TVNavigationEventEmitter;
const NativeEventEmitter = require('NativeEventEmitter'); const NativeEventEmitter = require('NativeEventEmitter');
function TVEventHandler() { function TVEventHandler() {
@ -17,19 +20,24 @@ function TVEventHandler() {
this.__nativeTVNavigationEventEmitter = null; this.__nativeTVNavigationEventEmitter = null;
} }
TVEventHandler.prototype.enable = function(component: ?any, callback: Function) { TVEventHandler.prototype.enable = function(
component: ?any,
callback: Function,
) {
if (Platform.OS === 'ios' && !TVNavigationEventEmitter) { if (Platform.OS === 'ios' && !TVNavigationEventEmitter) {
return; return;
} }
this.__nativeTVNavigationEventEmitter = new NativeEventEmitter(TVNavigationEventEmitter); this.__nativeTVNavigationEventEmitter = new NativeEventEmitter(
TVNavigationEventEmitter,
);
this.__nativeTVNavigationEventListener = this.__nativeTVNavigationEventEmitter.addListener( this.__nativeTVNavigationEventListener = this.__nativeTVNavigationEventEmitter.addListener(
'onHWKeyEvent', 'onHWKeyEvent',
(data) => { data => {
if (callback) { if (callback) {
callback(component, data); callback(component, data);
} }
} },
); );
}; };

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const PropTypes = require('prop-types'); const PropTypes = require('prop-types');
@ -13,66 +15,65 @@ const PropTypes = require('prop-types');
* Additional View properties for Apple TV * Additional View properties for Apple TV
*/ */
const TVViewPropTypes = { const TVViewPropTypes = {
/** /**
* When set to true, this view will be focusable * When set to true, this view will be focusable
* and navigable using the TV remote. * and navigable using the TV remote.
*/ */
isTVSelectable: PropTypes.bool, isTVSelectable: PropTypes.bool,
/** /**
* May be set to true to force the TV focus engine to move focus to this view. * May be set to true to force the TV focus engine to move focus to this view.
*/ */
hasTVPreferredFocus: PropTypes.bool, hasTVPreferredFocus: PropTypes.bool,
/** /**
* *(Apple TV only)* Object with properties to control Apple TV parallax effects. * *(Apple TV only)* Object with properties to control Apple TV parallax effects.
* *
* enabled: If true, parallax effects are enabled. Defaults to true. * enabled: If true, parallax effects are enabled. Defaults to true.
* shiftDistanceX: Defaults to 2.0. * shiftDistanceX: Defaults to 2.0.
* shiftDistanceY: Defaults to 2.0. * shiftDistanceY: Defaults to 2.0.
* tiltAngle: Defaults to 0.05. * tiltAngle: Defaults to 0.05.
* magnification: Defaults to 1.0. * magnification: Defaults to 1.0.
* pressMagnification: Defaults to 1.0. * pressMagnification: Defaults to 1.0.
* pressDuration: Defaults to 0.3. * pressDuration: Defaults to 0.3.
* pressDelay: Defaults to 0.0. * pressDelay: Defaults to 0.0.
* *
* @platform ios * @platform ios
*/ */
tvParallaxProperties: PropTypes.object, tvParallaxProperties: PropTypes.object,
/** /**
* *(Apple TV only)* May be used to change the appearance of the Apple TV parallax effect when this view goes in or out of focus. Defaults to 2.0. * *(Apple TV only)* May be used to change the appearance of the Apple TV parallax effect when this view goes in or out of focus. Defaults to 2.0.
* *
* @platform ios * @platform ios
*/ */
tvParallaxShiftDistanceX: PropTypes.number, tvParallaxShiftDistanceX: PropTypes.number,
/** /**
* *(Apple TV only)* May be used to change the appearance of the Apple TV parallax effect when this view goes in or out of focus. Defaults to 2.0. * *(Apple TV only)* May be used to change the appearance of the Apple TV parallax effect when this view goes in or out of focus. Defaults to 2.0.
* *
* @platform ios * @platform ios
*/ */
tvParallaxShiftDistanceY: PropTypes.number, tvParallaxShiftDistanceY: PropTypes.number,
/** /**
* *(Apple TV only)* May be used to change the appearance of the Apple TV parallax effect when this view goes in or out of focus. Defaults to 0.05. * *(Apple TV only)* May be used to change the appearance of the Apple TV parallax effect when this view goes in or out of focus. Defaults to 0.05.
* *
* @platform ios * @platform ios
*/ */
tvParallaxTiltAngle: PropTypes.number, tvParallaxTiltAngle: PropTypes.number,
/**
* *(Apple TV only)* May be used to change the appearance of the Apple TV parallax effect when this view goes in or out of focus. Defaults to 1.0.
*
* @platform ios
*/
tvParallaxMagnification: PropTypes.number,
/**
* *(Apple TV only)* May be used to change the appearance of the Apple TV parallax effect when this view goes in or out of focus. Defaults to 1.0.
*
* @platform ios
*/
tvParallaxMagnification: PropTypes.number,
}; };
export type TVViewProps = { export type TVViewProps = {
isTVSelectable?: bool, isTVSelectable?: boolean,
hasTVPreferredFocus?: bool, hasTVPreferredFocus?: boolean,
tvParallaxProperties?: Object, tvParallaxProperties?: Object,
tvParallaxShiftDistanceX?: number, tvParallaxShiftDistanceX?: number,
tvParallaxShiftDistanceY?: number, tvParallaxShiftDistanceY?: number,

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const ColorPropType = require('ColorPropType'); const ColorPropType = require('ColorPropType');
@ -117,8 +119,10 @@ class Button extends React.Component<{
typeof title === 'string', typeof title === 'string',
'The title prop of a Button must be a string', 'The title prop of a Button must be a string',
); );
const formattedTitle = Platform.OS === 'android' ? title.toUpperCase() : title; const formattedTitle =
const Touchable = Platform.OS === 'android' ? TouchableNativeFeedback : TouchableOpacity; Platform.OS === 'android' ? title.toUpperCase() : title;
const Touchable =
Platform.OS === 'android' ? TouchableNativeFeedback : TouchableOpacity;
return ( return (
<Touchable <Touchable
accessibilityComponentType="button" accessibilityComponentType="button"
@ -129,7 +133,9 @@ class Button extends React.Component<{
disabled={disabled} disabled={disabled}
onPress={onPress}> onPress={onPress}>
<View style={buttonStyles}> <View style={buttonStyles}>
<Text style={textStyles} disabled={disabled}>{formattedTitle}</Text> <Text style={textStyles} disabled={disabled}>
{formattedTitle}
</Text>
</View> </View>
</Touchable> </Touchable>
); );
@ -166,7 +172,7 @@ const styles = StyleSheet.create({
android: { android: {
elevation: 0, elevation: 0,
backgroundColor: '#dfdfdf', backgroundColor: '#dfdfdf',
} },
}), }),
textDisabled: Platform.select({ textDisabled: Platform.select({
ios: { ios: {
@ -174,7 +180,7 @@ const styles = StyleSheet.create({
}, },
android: { android: {
color: '#a1a1a1', color: '#a1a1a1',
} },
}), }),
}); });

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const Clipboard = require('NativeModules').Clipboard; const Clipboard = require('NativeModules').Clipboard;
@ -36,5 +38,5 @@ module.exports = {
*/ */
setString(content: string) { setString(content: string) {
Clipboard.setString(content); Clipboard.setString(content);
} },
}; };

View File

@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
*/ */
'use strict'; 'use strict';
@ -17,7 +18,9 @@ class DummyDatePickerIOS extends React.Component {
render() { render() {
return ( return (
<View style={[styles.dummyDatePickerIOS, this.props.style]}> <View style={[styles.dummyDatePickerIOS, this.props.style]}>
<Text style={styles.datePickerText}>DatePickerIOS is not supported on this platform!</Text> <Text style={styles.datePickerText}>
DatePickerIOS is not supported on this platform!
</Text>
</View> </View>
); );
} }
@ -37,7 +40,7 @@ const styles = StyleSheet.create({
datePickerText: { datePickerText: {
color: '#333333', color: '#333333',
margin: 20, margin: 20,
} },
}); });
module.exports = DummyDatePickerIOS; module.exports = DummyDatePickerIOS;

View File

@ -4,10 +4,13 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @flow
* *
* This is a controlled component version of RCTDatePickerIOS * This is a controlled component version of RCTDatePickerIOS
*
* @format
* @flow
*/ */
'use strict'; 'use strict';
const NativeMethodsMixin = require('NativeMethodsMixin'); const NativeMethodsMixin = require('NativeMethodsMixin');
@ -125,9 +128,8 @@ const DatePickerIOS = createReactClass({
_onChange: function(event: Event) { _onChange: function(event: Event) {
const nativeTimeStamp = event.nativeEvent.timestamp; const nativeTimeStamp = event.nativeEvent.timestamp;
this.props.onDateChange && this.props.onDateChange( this.props.onDateChange &&
new Date(nativeTimeStamp) this.props.onDateChange(new Date(nativeTimeStamp));
);
// $FlowFixMe(>=0.41.0) // $FlowFixMe(>=0.41.0)
this.props.onChange && this.props.onChange(event); this.props.onChange && this.props.onChange(event);
}, },
@ -141,9 +143,17 @@ const DatePickerIOS = createReactClass({
return ( return (
<View style={props.style}> <View style={props.style}>
<RCTDatePickerIOS <RCTDatePickerIOS
ref={ picker => { this._picker = picker; } } ref={picker => {
this._picker = picker;
}}
style={styles.datePickerIOS} style={styles.datePickerIOS}
date={props.date ? props.date.getTime() : props.initialDate ? props.initialDate.getTime() : undefined} date={
props.date
? props.date.getTime()
: props.initialDate
? props.initialDate.getTime()
: undefined
}
locale={props.locale ? props.locale : undefined} locale={props.locale ? props.locale : undefined}
maximumDate={ maximumDate={
props.maximumDate ? props.maximumDate.getTime() : undefined props.maximumDate ? props.maximumDate.getTime() : undefined
@ -160,7 +170,7 @@ const DatePickerIOS = createReactClass({
/> />
</View> </View>
); );
} },
}); });
const styles = StyleSheet.create({ const styles = StyleSheet.create({
@ -178,7 +188,7 @@ const RCTDatePickerIOS = requireNativeComponent('RCTDatePicker', {
maximumDate: PropTypes.number, maximumDate: PropTypes.number,
onDateChange: () => null, onDateChange: () => null,
onChange: PropTypes.func, onChange: PropTypes.func,
} },
}); });
module.exports = DatePickerIOS; module.exports = DatePickerIOS;

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const DatePickerModule = require('NativeModules').DatePickerAndroid; const DatePickerModule = require('NativeModules').DatePickerAndroid;
@ -76,11 +78,15 @@ class DatePickerAndroid {
/** /**
* A date has been selected. * A date has been selected.
*/ */
static get dateSetAction() { return 'dateSetAction'; } static get dateSetAction() {
return 'dateSetAction';
}
/** /**
* The dialog has been dismissed. * The dialog has been dismissed.
*/ */
static get dismissedAction() { return 'dismissedAction'; } static get dismissedAction() {
return 'dismissedAction';
}
} }
module.exports = DatePickerAndroid; module.exports = DatePickerAndroid;

View File

@ -4,14 +4,16 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const DatePickerAndroid = { const DatePickerAndroid = {
async open(options: Object): Promise<Object> { async open(options: Object): Promise<Object> {
return Promise.reject({ return Promise.reject({
message: 'DatePickerAndroid is not supported on this platform.' message: 'DatePickerAndroid is not supported on this platform.',
}); });
}, },
}; };

View File

@ -4,7 +4,9 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
*/ */
'use strict'; 'use strict';
const ColorPropType = require('ColorPropType'); const ColorPropType = require('ColorPropType');
@ -28,11 +30,7 @@ const requireNativeComponent = require('requireNativeComponent');
const RK_DRAWER_REF = 'drawerlayout'; const RK_DRAWER_REF = 'drawerlayout';
const INNERVIEW_REF = 'innerView'; const INNERVIEW_REF = 'innerView';
const DRAWER_STATES = [ const DRAWER_STATES = ['Idle', 'Dragging', 'Settling'];
'Idle',
'Dragging',
'Settling',
];
/** /**
* React component that wraps the platform `DrawerLayout` (Android only). The * React component that wraps the platform `DrawerLayout` (Android only). The
@ -99,7 +97,7 @@ const DrawerLayoutAndroid = createReactClass({
*/ */
drawerPosition: PropTypes.oneOf([ drawerPosition: PropTypes.oneOf([
DrawerConsts.DrawerPosition.Left, DrawerConsts.DrawerPosition.Left,
DrawerConsts.DrawerPosition.Right DrawerConsts.DrawerPosition.Right,
]), ]),
/** /**
* Specifies the width of the drawer, more precisely the width of the view that be pulled in * Specifies the width of the drawer, more precisely the width of the view that be pulled in
@ -116,7 +114,7 @@ const DrawerLayoutAndroid = createReactClass({
drawerLockMode: PropTypes.oneOf([ drawerLockMode: PropTypes.oneOf([
'unlocked', 'unlocked',
'locked-closed', 'locked-closed',
'locked-open' 'locked-open',
]), ]),
/** /**
* Function called whenever there is an interaction with the navigation view. * Function called whenever there is an interaction with the navigation view.
@ -168,31 +166,41 @@ const DrawerLayoutAndroid = createReactClass({
}, },
render: function() { render: function() {
const drawStatusBar = Platform.Version >= 21 && this.props.statusBarBackgroundColor; const drawStatusBar =
const drawerViewWrapper = Platform.Version >= 21 && this.props.statusBarBackgroundColor;
const drawerViewWrapper = (
<View <View
style={[ style={[
styles.drawerSubview, styles.drawerSubview,
{width: this.props.drawerWidth, backgroundColor: this.props.drawerBackgroundColor} {
width: this.props.drawerWidth,
backgroundColor: this.props.drawerBackgroundColor,
},
]} ]}
collapsable={false}> collapsable={false}>
{this.props.renderNavigationView()} {this.props.renderNavigationView()}
{drawStatusBar && <View style={styles.drawerStatusBar} />} {drawStatusBar && <View style={styles.drawerStatusBar} />}
</View>; </View>
const childrenWrapper = );
const childrenWrapper = (
<View ref={INNERVIEW_REF} style={styles.mainSubview} collapsable={false}> <View ref={INNERVIEW_REF} style={styles.mainSubview} collapsable={false}>
{drawStatusBar && {drawStatusBar && (
<StatusBar <StatusBar
translucent translucent
backgroundColor={this.props.statusBarBackgroundColor} backgroundColor={this.props.statusBarBackgroundColor}
/>} />
{drawStatusBar && )}
<View style={[ {drawStatusBar && (
styles.statusBar, <View
{backgroundColor: this.props.statusBarBackgroundColor} style={[
]} />} styles.statusBar,
{backgroundColor: this.props.statusBarBackgroundColor},
]}
/>
)}
{this.props.children} {this.props.children}
</View>; </View>
);
return ( return (
<AndroidDrawerLayout <AndroidDrawerLayout
{...this.props} {...this.props}
@ -234,7 +242,9 @@ const DrawerLayoutAndroid = createReactClass({
_onDrawerStateChanged: function(event) { _onDrawerStateChanged: function(event) {
if (this.props.onDrawerStateChanged) { if (this.props.onDrawerStateChanged) {
this.props.onDrawerStateChanged(DRAWER_STATES[event.nativeEvent.drawerState]); this.props.onDrawerStateChanged(
DRAWER_STATES[event.nativeEvent.drawerState],
);
} }
}, },
@ -245,7 +255,7 @@ const DrawerLayoutAndroid = createReactClass({
UIManager.dispatchViewManagerCommand( UIManager.dispatchViewManagerCommand(
this._getDrawerLayoutHandle(), this._getDrawerLayoutHandle(),
UIManager.AndroidDrawerLayout.Commands.openDrawer, UIManager.AndroidDrawerLayout.Commands.openDrawer,
null null,
); );
}, },
@ -256,29 +266,28 @@ const DrawerLayoutAndroid = createReactClass({
UIManager.dispatchViewManagerCommand( UIManager.dispatchViewManagerCommand(
this._getDrawerLayoutHandle(), this._getDrawerLayoutHandle(),
UIManager.AndroidDrawerLayout.Commands.closeDrawer, UIManager.AndroidDrawerLayout.Commands.closeDrawer,
null null,
); );
}, },
/** /**
* Closing and opening example * Closing and opening example
* Note: To access the drawer you have to give it a ref. Refs do not work on stateless components * Note: To access the drawer you have to give it a ref. Refs do not work on stateless components
* render () { * render () {
* this.openDrawer = () => { * this.openDrawer = () => {
* this.refs.DRAWER.openDrawer() * this.refs.DRAWER.openDrawer()
* } * }
* this.closeDrawer = () => { * this.closeDrawer = () => {
* this.refs.DRAWER.closeDrawer() * this.refs.DRAWER.closeDrawer()
* } * }
* return ( * return (
* <DrawerLayoutAndroid ref={'DRAWER'}> * <DrawerLayoutAndroid ref={'DRAWER'}>
* </DrawerLayoutAndroid> * </DrawerLayoutAndroid>
* ) * )
* } * }
*/ */
_getDrawerLayoutHandle: function() { _getDrawerLayoutHandle: function() {
return ReactNative.findNodeHandle(this.refs[RK_DRAWER_REF]); return ReactNative.findNodeHandle(this.refs[RK_DRAWER_REF]);
}, },
}); });
const styles = StyleSheet.create({ const styles = StyleSheet.create({
@ -312,6 +321,9 @@ const styles = StyleSheet.create({
}); });
// The View that contains both the actual drawer and the main view // The View that contains both the actual drawer and the main view
const AndroidDrawerLayout = requireNativeComponent('AndroidDrawerLayout', DrawerLayoutAndroid); const AndroidDrawerLayout = requireNativeComponent(
'AndroidDrawerLayout',
DrawerLayoutAndroid,
);
module.exports = DrawerLayoutAndroid; module.exports = DrawerLayoutAndroid;

View File

@ -4,7 +4,9 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
*/ */
'use strict'; 'use strict';
module.exports = require('UnimplementedView'); module.exports = require('UnimplementedView');

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const LayoutAnimation = require('LayoutAnimation'); const LayoutAnimation = require('LayoutAnimation');

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const createReactClass = require('create-react-class'); const createReactClass = require('create-react-class');
@ -66,9 +68,9 @@ const KeyboardAvoidingView = createReactClass({
*/ */
keyboardVerticalOffset: PropTypes.number.isRequired, keyboardVerticalOffset: PropTypes.number.isRequired,
/** /**
* This is to allow us to manually control which KAV shuld take effect when * This is to allow us to manually control which KAV shuld take effect when
* having more than one KAV at the same screen * having more than one KAV at the same screen
*/ */
enabled: PropTypes.bool.isRequired, enabled: PropTypes.bool.isRequired,
}, },
@ -130,10 +132,16 @@ const KeyboardAvoidingView = createReactClass({
this.frame = event.nativeEvent.layout; this.frame = event.nativeEvent.layout;
}, },
UNSAFE_componentWillUpdate(nextProps: Object, nextState: Object, nextContext?: Object): void { UNSAFE_componentWillUpdate(
if (nextState.bottom === this.state.bottom && nextProps: Object,
this.props.behavior === 'height' && nextState: Object,
nextProps.behavior === 'height') { nextContext?: Object,
): void {
if (
nextState.bottom === this.state.bottom &&
this.props.behavior === 'height' &&
nextProps.behavior === 'height'
) {
// If the component rerenders without an internal state change, e.g. // If the component rerenders without an internal state change, e.g.
// triggered by parent component re-rendering, no need for bottom to change. // triggered by parent component re-rendering, no need for bottom to change.
nextState.bottom = 0; nextState.bottom = 0;
@ -154,7 +162,7 @@ const KeyboardAvoidingView = createReactClass({
}, },
componentWillUnmount() { componentWillUnmount() {
this.subscriptions.forEach((sub) => sub.remove()); this.subscriptions.forEach(sub => sub.remove());
}, },
render(): React.Element<any> { render(): React.Element<any> {
@ -172,17 +180,25 @@ const KeyboardAvoidingView = createReactClass({
heightStyle = {height: this.frame.height - bottomHeight, flex: 0}; heightStyle = {height: this.frame.height - bottomHeight, flex: 0};
} }
return ( return (
<View ref={viewRef} style={[style, heightStyle]} onLayout={this._onLayout} {...props}> <View
ref={viewRef}
style={[style, heightStyle]}
onLayout={this._onLayout}
{...props}>
{children} {children}
</View> </View>
); );
case 'position': case 'position':
const positionStyle = {bottom: bottomHeight}; const positionStyle = {bottom: bottomHeight};
const { contentContainerStyle } = this.props; const {contentContainerStyle} = this.props;
return ( return (
<View ref={viewRef} style={style} onLayout={this._onLayout} {...props}> <View
ref={viewRef}
style={style}
onLayout={this._onLayout}
{...props}>
<View style={[contentContainerStyle, positionStyle]}> <View style={[contentContainerStyle, positionStyle]}>
{children} {children}
</View> </View>
@ -192,14 +208,22 @@ const KeyboardAvoidingView = createReactClass({
case 'padding': case 'padding':
const paddingStyle = {paddingBottom: bottomHeight}; const paddingStyle = {paddingBottom: bottomHeight};
return ( return (
<View ref={viewRef} style={[style, paddingStyle]} onLayout={this._onLayout} {...props}> <View
ref={viewRef}
style={[style, paddingStyle]}
onLayout={this._onLayout}
{...props}>
{children} {children}
</View> </View>
); );
default: default:
return ( return (
<View ref={viewRef} onLayout={this._onLayout} style={style} {...props}> <View
ref={viewRef}
onLayout={this._onLayout}
style={style}
{...props}>
{children} {children}
</View> </View>
); );

View File

@ -4,7 +4,9 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
*/ */
'use strict'; 'use strict';
const React = require('React'); const React = require('React');
@ -22,14 +24,14 @@ const LazyRenderer = createReactClass({
UNSAFE_componentWillMount: function(): void { UNSAFE_componentWillMount: function(): void {
this.setState({ this.setState({
_lazyRender : true, _lazyRender: true,
}); });
}, },
componentDidMount: function(): void { componentDidMount: function(): void {
requestAnimationFrame(() => { requestAnimationFrame(() => {
this.setState({ this.setState({
_lazyRender : false, _lazyRender: false,
}); });
}); });
}, },

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
module.exports = require('UnimplementedView'); module.exports = require('UnimplementedView');

View File

@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
@ -14,7 +15,7 @@ const View = require('View');
const ViewPropTypes = require('ViewPropTypes'); const ViewPropTypes = require('ViewPropTypes');
const requireNativeComponent = require('requireNativeComponent'); const requireNativeComponent = require('requireNativeComponent');
import type { ViewProps } from 'ViewPropTypes'; import type {ViewProps} from 'ViewPropTypes';
type Props = ViewProps & { type Props = ViewProps & {
children: any, children: any,
@ -70,13 +71,13 @@ class MaskedViewIOS extends React.Component<Props> {
_hasWarnedInvalidRenderMask = false; _hasWarnedInvalidRenderMask = false;
render() { render() {
const { maskElement, children, ...otherViewProps } = this.props; const {maskElement, children, ...otherViewProps} = this.props;
if (!React.isValidElement(maskElement)) { if (!React.isValidElement(maskElement)) {
if (!this._hasWarnedInvalidRenderMask) { if (!this._hasWarnedInvalidRenderMask) {
console.warn( console.warn(
'MaskedView: Invalid `maskElement` prop was passed to MaskedView. ' + 'MaskedView: Invalid `maskElement` prop was passed to MaskedView. ' +
'Expected a React Element. No mask will render.' 'Expected a React Element. No mask will render.',
); );
this._hasWarnedInvalidRenderMask = true; this._hasWarnedInvalidRenderMask = true;
} }

View File

@ -4,7 +4,9 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
*/ */
'use strict'; 'use strict';
module.exports = require('UnimplementedView'); module.exports = require('UnimplementedView');

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const EventEmitter = require('EventEmitter'); const EventEmitter = require('EventEmitter');
@ -40,14 +42,12 @@ class NavigatorTransitionerIOS extends React.Component<$FlowFixMeProps> {
requestSchedulingNavigation(cb) { requestSchedulingNavigation(cb) {
RCTNavigatorManager.requestSchedulingJavaScriptNavigation( RCTNavigatorManager.requestSchedulingJavaScriptNavigation(
ReactNative.findNodeHandle(this), ReactNative.findNodeHandle(this),
cb cb,
); );
} }
render() { render() {
return ( return <RCTNavigator {...this.props} />;
<RCTNavigator {...this.props}/>
);
} }
} }
@ -107,7 +107,7 @@ type State = {
toIndex: number, toIndex: number,
makingNavigatorRequest: boolean, makingNavigatorRequest: boolean,
updatingAllIndicesAtOrBeyond: ?number, updatingAllIndicesAtOrBeyond: ?number,
} };
type Event = Object; type Event = Object;
@ -308,7 +308,6 @@ const NavigatorIOS = createReactClass({
displayName: 'NavigatorIOS', displayName: 'NavigatorIOS',
propTypes: { propTypes: {
/** /**
* NavigatorIOS uses `route` objects to identify child views, their props, * NavigatorIOS uses `route` objects to identify child views, their props,
* and navigation bar configuration. Navigation operations such as push * and navigation bar configuration. Navigation operations such as push
@ -436,17 +435,16 @@ const NavigatorIOS = createReactClass({
*/ */
barStyle: PropTypes.oneOf(['default', 'black']), barStyle: PropTypes.oneOf(['default', 'black']),
/** /**
* The text color of the navigation bar title. * The text color of the navigation bar title.
*/ */
titleTextColor: PropTypes.string, titleTextColor: PropTypes.string,
/** /**
* Boolean value that indicates whether the navigation bar is * Boolean value that indicates whether the navigation bar is
* translucent. * translucent.
*/ */
translucent: PropTypes.bool, translucent: PropTypes.bool,
}).isRequired, }).isRequired,
/** /**
@ -507,7 +505,6 @@ const NavigatorIOS = createReactClass({
* behavior. * behavior.
*/ */
interactivePopGestureEnabled: PropTypes.bool, interactivePopGestureEnabled: PropTypes.bool,
}, },
navigator: (undefined: ?Object), navigator: (undefined: ?Object),
@ -608,7 +605,7 @@ const NavigatorIOS = createReactClass({
_tryLockNavigator: function(cb: () => void) { _tryLockNavigator: function(cb: () => void) {
this.refs[TRANSITIONER_REF].requestSchedulingNavigation( this.refs[TRANSITIONER_REF].requestSchedulingNavigation(
(acquiredLock) => acquiredLock && cb() acquiredLock => acquiredLock && cb(),
); );
}, },
@ -617,7 +614,9 @@ const NavigatorIOS = createReactClass({
invariant( invariant(
newObservedTopOfStack <= this.state.requestedTopOfStack, newObservedTopOfStack <= this.state.requestedTopOfStack,
'No navigator item should be pushed without JS knowing about it %s %s', newObservedTopOfStack, this.state.requestedTopOfStack 'No navigator item should be pushed without JS knowing about it %s %s',
newObservedTopOfStack,
this.state.requestedTopOfStack,
); );
const wasWaitingForConfirmation = const wasWaitingForConfirmation =
this.state.requestedTopOfStack !== this.state.observedTopOfStack; this.state.requestedTopOfStack !== this.state.observedTopOfStack;
@ -625,7 +624,7 @@ const NavigatorIOS = createReactClass({
invariant( invariant(
newObservedTopOfStack === this.state.requestedTopOfStack, newObservedTopOfStack === this.state.requestedTopOfStack,
'If waiting for observedTopOfStack to reach requestedTopOfStack, ' + 'If waiting for observedTopOfStack to reach requestedTopOfStack, ' +
'the only valid observedTopOfStack should be requestedTopOfStack.' 'the only valid observedTopOfStack should be requestedTopOfStack.',
); );
} }
// Mark the most recent observation regardless of if we can lock the // Mark the most recent observation regardless of if we can lock the
@ -653,12 +652,15 @@ const NavigatorIOS = createReactClass({
// even uses the indices in this case, but let's make this describe the // even uses the indices in this case, but let's make this describe the
// truth anyways). // truth anyways).
const updatingAllIndicesAtOrBeyond = const updatingAllIndicesAtOrBeyond =
this.state.routeStack.length > this.state.observedTopOfStack + 1 ? this.state.routeStack.length > this.state.observedTopOfStack + 1
this.state.observedTopOfStack + 1 : ? this.state.observedTopOfStack + 1
null; : null;
this.setState({ this.setState({
idStack: this.state.idStack.slice(0, this.state.observedTopOfStack + 1), idStack: this.state.idStack.slice(0, this.state.observedTopOfStack + 1),
routeStack: this.state.routeStack.slice(0, this.state.observedTopOfStack + 1), routeStack: this.state.routeStack.slice(
0,
this.state.observedTopOfStack + 1,
),
// Now we rerequest the top of stack that we observed. // Now we rerequest the top of stack that we observed.
requestedTopOfStack: this.state.observedTopOfStack, requestedTopOfStack: this.state.observedTopOfStack,
makingNavigatorRequest: true, makingNavigatorRequest: true,
@ -675,7 +677,6 @@ const NavigatorIOS = createReactClass({
// Make sure all previous requests are caught up first. Otherwise reject. // Make sure all previous requests are caught up first. Otherwise reject.
if (this.state.requestedTopOfStack === this.state.observedTopOfStack) { if (this.state.requestedTopOfStack === this.state.observedTopOfStack) {
this._tryLockNavigator(() => { this._tryLockNavigator(() => {
const nextStack = this.state.routeStack.concat([route]); const nextStack = this.state.routeStack.concat([route]);
const nextIDStack = this.state.idStack.concat([getuid()]); const nextIDStack = this.state.idStack.concat([getuid()]);
this.setState({ this.setState({
@ -752,7 +753,6 @@ const NavigatorIOS = createReactClass({
makingNavigatorRequest: false, makingNavigatorRequest: false,
updatingAllIndicesAtOrBeyond: index, updatingAllIndicesAtOrBeyond: index,
}); });
}, },
/** /**
@ -787,7 +787,7 @@ const NavigatorIOS = createReactClass({
const indexOfRoute = this.state.routeStack.indexOf(route); const indexOfRoute = this.state.routeStack.indexOf(route);
invariant( invariant(
indexOfRoute !== -1, indexOfRoute !== -1,
'Calling pop to route for a route that doesn\'t exist!' "Calling pop to route for a route that doesn't exist!",
); );
const numToPop = this.state.routeStack.length - indexOfRoute - 1; const numToPop = this.state.routeStack.length - indexOfRoute - 1;
this.popN(numToPop); this.popN(numToPop);
@ -851,16 +851,8 @@ const NavigatorIOS = createReactClass({
<RCTNavigatorItem <RCTNavigatorItem
{...props} {...props}
{...route} {...route}
style={[ style={[styles.stackItem, itemWrapperStyle, wrapperStyle]}>
styles.stackItem, <Component navigator={this.navigator} route={route} {...passProps} />
itemWrapperStyle,
wrapperStyle
]}>
<Component
navigator={this.navigator}
route={route}
{...passProps}
/>
</RCTNavigatorItem> </RCTNavigatorItem>
</StaticContainer> </StaticContainer>
); );
@ -872,8 +864,9 @@ const NavigatorIOS = createReactClass({
this.state.updatingAllIndicesAtOrBeyond !== null; this.state.updatingAllIndicesAtOrBeyond !== null;
// If not recursing update to navigator at all, may as well avoid // If not recursing update to navigator at all, may as well avoid
// computation of navigator children. // computation of navigator children.
const items = shouldRecurseToNavigator ? const items = shouldRecurseToNavigator
this.state.routeStack.map(this._routeToStackItem) : null; ? this.state.routeStack.map(this._routeToStackItem)
: null;
return ( return (
<StaticContainer shouldUpdate={shouldRecurseToNavigator}> <StaticContainer shouldUpdate={shouldRecurseToNavigator}>
<NavigatorTransitionerIOS <NavigatorTransitionerIOS
@ -883,7 +876,9 @@ const NavigatorIOS = createReactClass({
vertical={this.props.vertical} vertical={this.props.vertical}
requestedTopOfStack={this.state.requestedTopOfStack} requestedTopOfStack={this.state.requestedTopOfStack}
onNavigationComplete={this._handleNavigationComplete} onNavigationComplete={this._handleNavigationComplete}
interactivePopGestureEnabled={this.props.interactivePopGestureEnabled}> interactivePopGestureEnabled={
this.props.interactivePopGestureEnabled
}>
{items} {items}
</NavigatorTransitionerIOS> </NavigatorTransitionerIOS>
</StaticContainer> </StaticContainer>
@ -911,9 +906,7 @@ const NavigatorIOS = createReactClass({
render: function() { render: function() {
return ( return (
// $FlowFixMe(>=0.41.0) // $FlowFixMe(>=0.41.0)
<View style={this.props.style}> <View style={this.props.style}>{this._renderNavigationStackItems()}</View>
{this._renderNavigationStackItems()}
</View>
); );
}, },
}); });

View File

@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
@ -35,36 +36,36 @@ const MODE_DROPDOWN = 'dropdown';
* Individual selectable item in a Picker. * Individual selectable item in a Picker.
*/ */
class PickerItem extends React.Component<{ class PickerItem extends React.Component<{
label: string, label: string,
value?: any, value?: any,
color?: ColorPropType, color?: ColorPropType,
testID?: string, testID?: string,
}> { }> {
static propTypes = { static propTypes = {
/** /**
* Text to display for this item. * Text to display for this item.
*/ */
label: PropTypes.string.isRequired, label: PropTypes.string.isRequired,
/** /**
* The value to be passed to picker's `onValueChange` callback when * The value to be passed to picker's `onValueChange` callback when
* this item is selected. Can be a string or an integer. * this item is selected. Can be a string or an integer.
*/ */
value: PropTypes.any, value: PropTypes.any,
/** /**
* Color of this item's text. * Color of this item's text.
* @platform android * @platform android
*/ */
color: ColorPropType, color: ColorPropType,
/** /**
* Used to locate the item in end-to-end tests. * Used to locate the item in end-to-end tests.
*/ */
testID: PropTypes.string, testID: PropTypes.string,
}; };
render() { render() {
// The items are not rendered directly // The items are not rendered directly
throw null; throw null;
} }
} }
/** /**
@ -78,87 +79,89 @@ class PickerItem extends React.Component<{
* </Picker> * </Picker>
*/ */
class Picker extends React.Component<{ class Picker extends React.Component<{
style?: $FlowFixMe, style?: $FlowFixMe,
selectedValue?: any, selectedValue?: any,
onValueChange?: Function, onValueChange?: Function,
enabled?: boolean, enabled?: boolean,
mode?: 'dialog' | 'dropdown', mode?: 'dialog' | 'dropdown',
itemStyle?: $FlowFixMe, itemStyle?: $FlowFixMe,
prompt?: string, prompt?: string,
testID?: string, testID?: string,
}> { }> {
/** /**
* On Android, display the options in a dialog. * On Android, display the options in a dialog.
*/ */
static MODE_DIALOG = MODE_DIALOG; static MODE_DIALOG = MODE_DIALOG;
/** /**
* On Android, display the options in a dropdown (this is the default). * On Android, display the options in a dropdown (this is the default).
*/ */
static MODE_DROPDOWN = MODE_DROPDOWN; static MODE_DROPDOWN = MODE_DROPDOWN;
static Item = PickerItem; static Item = PickerItem;
static defaultProps = { static defaultProps = {
mode: MODE_DIALOG, mode: MODE_DIALOG,
}; };
// $FlowFixMe(>=0.41.0) // $FlowFixMe(>=0.41.0)
static propTypes = { static propTypes = {
...ViewPropTypes, ...ViewPropTypes,
style: pickerStyleType, style: pickerStyleType,
/** /**
* Value matching value of one of the items. Can be a string or an integer. * Value matching value of one of the items. Can be a string or an integer.
*/ */
selectedValue: PropTypes.any, selectedValue: PropTypes.any,
/** /**
* Callback for when an item is selected. This is called with the following parameters: * Callback for when an item is selected. This is called with the following parameters:
* - `itemValue`: the `value` prop of the item that was selected * - `itemValue`: the `value` prop of the item that was selected
* - `itemPosition`: the index of the selected item in this picker * - `itemPosition`: the index of the selected item in this picker
*/ */
onValueChange: PropTypes.func, onValueChange: PropTypes.func,
/** /**
* If set to false, the picker will be disabled, i.e. the user will not be able to make a * If set to false, the picker will be disabled, i.e. the user will not be able to make a
* selection. * selection.
* @platform android * @platform android
*/ */
enabled: PropTypes.bool, enabled: PropTypes.bool,
/** /**
* On Android, specifies how to display the selection items when the user taps on the picker: * On Android, specifies how to display the selection items when the user taps on the picker:
* *
* - 'dialog': Show a modal dialog. This is the default. * - 'dialog': Show a modal dialog. This is the default.
* - 'dropdown': Shows a dropdown anchored to the picker view * - 'dropdown': Shows a dropdown anchored to the picker view
* *
* @platform android * @platform android
*/ */
mode: PropTypes.oneOf(['dialog', 'dropdown']), mode: PropTypes.oneOf(['dialog', 'dropdown']),
/** /**
* Style to apply to each of the item labels. * Style to apply to each of the item labels.
* @platform ios * @platform ios
*/ */
itemStyle: itemStylePropType, itemStyle: itemStylePropType,
/** /**
* Prompt string for this picker, used on Android in dialog mode as the title of the dialog. * Prompt string for this picker, used on Android in dialog mode as the title of the dialog.
* @platform android * @platform android
*/ */
prompt: PropTypes.string, prompt: PropTypes.string,
/** /**
* Used to locate this view in end-to-end tests. * Used to locate this view in end-to-end tests.
*/ */
testID: PropTypes.string, testID: PropTypes.string,
}; };
render() { render() {
if (Platform.OS === 'ios') { if (Platform.OS === 'ios') {
// $FlowFixMe found when converting React.createClass to ES6 // $FlowFixMe found when converting React.createClass to ES6
return <PickerIOS {...this.props}>{this.props.children}</PickerIOS>; return <PickerIOS {...this.props}>{this.props.children}</PickerIOS>;
} else if (Platform.OS === 'android') { } else if (Platform.OS === 'android') {
// $FlowFixMe found when converting React.createClass to ES6 return (
return <PickerAndroid {...this.props}>{this.props.children}</PickerAndroid>; // $FlowFixMe found when converting React.createClass to ES6
} else { <PickerAndroid {...this.props}>{this.props.children}</PickerAndroid>
return <UnimplementedView />; );
} } else {
} return <UnimplementedView />;
}
}
} }
module.exports = Picker; module.exports = Picker;

View File

@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
@ -33,15 +34,18 @@ type Event = Object;
/** /**
* Not exposed as a public API - use <Picker> instead. * Not exposed as a public API - use <Picker> instead.
*/ */
class PickerAndroid extends React.Component<{ class PickerAndroid extends React.Component<
style?: $FlowFixMe, {
selectedValue?: any, style?: $FlowFixMe,
enabled?: boolean, selectedValue?: any,
mode?: 'dialog' | 'dropdown', enabled?: boolean,
onValueChange?: Function, mode?: 'dialog' | 'dropdown',
prompt?: string, onValueChange?: Function,
testID?: string, prompt?: string,
}, *> { testID?: string,
},
*,
> {
static propTypes = { static propTypes = {
...ViewPropTypes, ...ViewPropTypes,
style: pickerStyleType, style: pickerStyleType,
@ -68,7 +72,7 @@ class PickerAndroid extends React.Component<{
} }
// Translate prop and children into stuff that the native picker understands. // Translate prop and children into stuff that the native picker understands.
_stateFromProps = (props) => { _stateFromProps = props => {
let selectedIndex = 0; let selectedIndex = 0;
const items = React.Children.map(props.children, (child, index) => { const items = React.Children.map(props.children, (child, index) => {
if (child.props.value === props.selectedValue) { if (child.props.value === props.selectedValue) {
@ -87,7 +91,8 @@ class PickerAndroid extends React.Component<{
}; };
render() { render() {
const Picker = this.props.mode === MODE_DROPDOWN ? DropdownPicker : DialogPicker; const Picker =
this.props.mode === MODE_DROPDOWN ? DropdownPicker : DialogPicker;
const nativeProps = { const nativeProps = {
enabled: this.props.enabled, enabled: this.props.enabled,
@ -130,8 +135,13 @@ class PickerAndroid extends React.Component<{
// disallow/undo/mutate the selection of certain values. In other // disallow/undo/mutate the selection of certain values. In other
// words, the embedder of this component should be the source of // words, the embedder of this component should be the source of
// truth, not the native component. // truth, not the native component.
if (this.refs[REF_PICKER] && this.state.selectedIndex !== this._lastNativePosition) { if (
this.refs[REF_PICKER].setNativeProps({selected: this.state.selectedIndex}); this.refs[REF_PICKER] &&
this.state.selectedIndex !== this._lastNativePosition
) {
this.refs[REF_PICKER].setNativeProps({
selected: this.state.selectedIndex,
});
this._lastNativePosition = this.state.selectedIndex; this._lastNativePosition = this.state.selectedIndex;
} }
} }
@ -152,10 +162,18 @@ const cfg = {
nativeOnly: { nativeOnly: {
items: true, items: true,
selected: true, selected: true,
} },
}; };
const DropdownPicker = requireNativeComponent('AndroidDropdownPicker', PickerAndroid, cfg); const DropdownPicker = requireNativeComponent(
const DialogPicker = requireNativeComponent('AndroidDialogPicker', PickerAndroid, cfg); 'AndroidDropdownPicker',
PickerAndroid,
cfg,
);
const DialogPicker = requireNativeComponent(
'AndroidDialogPicker',
PickerAndroid,
cfg,
);
module.exports = PickerAndroid; module.exports = PickerAndroid;

View File

@ -4,7 +4,9 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
*/ */
'use strict'; 'use strict';
module.exports = require('UnimplementedView'); module.exports = require('UnimplementedView');

View File

@ -6,7 +6,10 @@
* *
* *
* This is a controlled component version of RCTPickerIOS * This is a controlled component version of RCTPickerIOS
*
* @format
*/ */
'use strict'; 'use strict';
module.exports = require('UnimplementedView'); module.exports = require('UnimplementedView');

View File

@ -6,7 +6,10 @@
* *
* *
* This is a controlled component version of RCTPickerIOS * This is a controlled component version of RCTPickerIOS
*
* @format
*/ */
'use strict'; 'use strict';
const NativeMethodsMixin = require('NativeMethodsMixin'); const NativeMethodsMixin = require('NativeMethodsMixin');
@ -46,7 +49,7 @@ const PickerIOS = createReactClass({
_stateFromProps: function(props) { _stateFromProps: function(props) {
let selectedIndex = 0; let selectedIndex = 0;
const items = []; const items = [];
React.Children.toArray(props.children).forEach(function (child, index) { React.Children.toArray(props.children).forEach(function(child, index) {
if (child.props.value === props.selectedValue) { if (child.props.value === props.selectedValue) {
selectedIndex = index; selectedIndex = index;
} }
@ -63,7 +66,7 @@ const PickerIOS = createReactClass({
return ( return (
<View style={this.props.style}> <View style={this.props.style}>
<RCTPickerIOS <RCTPickerIOS
ref={picker => this._picker = picker} ref={picker => (this._picker = picker)}
style={[styles.pickerIOS, this.props.itemStyle]} style={[styles.pickerIOS, this.props.itemStyle]}
items={this.state.items} items={this.state.items}
selectedIndex={this.state.selectedIndex} selectedIndex={this.state.selectedIndex}
@ -80,7 +83,10 @@ const PickerIOS = createReactClass({
this.props.onChange(event); this.props.onChange(event);
} }
if (this.props.onValueChange) { if (this.props.onValueChange) {
this.props.onValueChange(event.nativeEvent.newValue, event.nativeEvent.newIndex); this.props.onValueChange(
event.nativeEvent.newValue,
event.nativeEvent.newIndex,
);
} }
// The picker is a controlled component. This means we expect the // The picker is a controlled component. This means we expect the
@ -89,9 +95,12 @@ const PickerIOS = createReactClass({
// disallow/undo/mutate the selection of certain values. In other // disallow/undo/mutate the selection of certain values. In other
// words, the embedder of this component should be the source of // words, the embedder of this component should be the source of
// truth, not the native component. // truth, not the native component.
if (this._picker && this.state.selectedIndex !== event.nativeEvent.newIndex) { if (
this._picker &&
this.state.selectedIndex !== event.nativeEvent.newIndex
) {
this._picker.setNativeProps({ this._picker.setNativeProps({
selectedIndex: this.state.selectedIndex selectedIndex: this.state.selectedIndex,
}); });
} }
}, },
@ -119,16 +128,20 @@ const styles = StyleSheet.create({
}, },
}); });
const RCTPickerIOS = requireNativeComponent('RCTPicker', { const RCTPickerIOS = requireNativeComponent(
propTypes: { 'RCTPicker',
style: itemStylePropType, {
propTypes: {
style: itemStylePropType,
},
}, },
}, { {
nativeOnly: { nativeOnly: {
items: true, items: true,
onChange: true, onChange: true,
selectedIndex: true, selectedIndex: true,
},
}, },
}); );
module.exports = PickerIOS; module.exports = PickerIOS;

View File

@ -4,7 +4,9 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
*/ */
'use strict'; 'use strict';
module.exports = require('UnimplementedView'); module.exports = require('UnimplementedView');

View File

@ -1,10 +1,10 @@
/** /**
* Copyright (c) 2015-present, Facebook, Inc. * Copyright (c) 2015-present, Facebook, Inc.
* *
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
*/ */
'use strict'; 'use strict';
@ -40,7 +40,7 @@ const styles = StyleSheet.create({
color: '#333333', color: '#333333',
margin: 5, margin: 5,
fontSize: 10, fontSize: 10,
} },
}); });
module.exports = DummyProgressViewIOS; module.exports = DummyProgressViewIOS;

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const Image = require('Image'); const Image = require('Image');
@ -65,7 +67,7 @@ const ProgressViewIOS = createReactClass({
style={[styles.progressView, this.props.style]} style={[styles.progressView, this.props.style]}
/> />
); );
} },
}); });
const styles = StyleSheet.create({ const styles = StyleSheet.create({
@ -76,7 +78,7 @@ const styles = StyleSheet.create({
const RCTProgressView = requireNativeComponent( const RCTProgressView = requireNativeComponent(
'RCTProgressView', 'RCTProgressView',
ProgressViewIOS ProgressViewIOS,
); );
module.exports = ProgressViewIOS; module.exports = ProgressViewIOS;

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const ColorPropType = require('ColorPropType'); const ColorPropType = require('ColorPropType');
@ -19,8 +21,8 @@ const createReactClass = require('create-react-class');
const requireNativeComponent = require('requireNativeComponent'); const requireNativeComponent = require('requireNativeComponent');
if (Platform.OS === 'android') { if (Platform.OS === 'android') {
const AndroidSwipeRefreshLayout = const AndroidSwipeRefreshLayout = require('UIManager')
require('UIManager').AndroidSwipeRefreshLayout; .AndroidSwipeRefreshLayout;
var RefreshLayoutConsts = AndroidSwipeRefreshLayout var RefreshLayoutConsts = AndroidSwipeRefreshLayout
? AndroidSwipeRefreshLayout.Constants ? AndroidSwipeRefreshLayout.Constants
: {SIZE: {}}; : {SIZE: {}};
@ -125,7 +127,10 @@ const RefreshControl = createReactClass({
* Size of the refresh indicator, see RefreshControl.SIZE. * Size of the refresh indicator, see RefreshControl.SIZE.
* @platform android * @platform android
*/ */
size: PropTypes.oneOf([RefreshLayoutConsts.SIZE.DEFAULT, RefreshLayoutConsts.SIZE.LARGE]), size: PropTypes.oneOf([
RefreshLayoutConsts.SIZE.DEFAULT,
RefreshLayoutConsts.SIZE.LARGE,
]),
/** /**
* Progress view top offset * Progress view top offset
* @platform android * @platform android
@ -156,7 +161,9 @@ const RefreshControl = createReactClass({
return ( return (
<NativeRefreshControl <NativeRefreshControl
{...this.props} {...this.props}
ref={ref => {this._nativeRef = ref;}} ref={ref => {
this._nativeRef = ref;
}}
onRefresh={this._onRefresh} onRefresh={this._onRefresh}
/> />
); );
@ -176,12 +183,12 @@ const RefreshControl = createReactClass({
if (Platform.OS === 'ios') { if (Platform.OS === 'ios') {
var NativeRefreshControl = requireNativeComponent( var NativeRefreshControl = requireNativeComponent(
'RCTRefreshControl', 'RCTRefreshControl',
RefreshControl RefreshControl,
); );
} else if (Platform.OS === 'android') { } else if (Platform.OS === 'android') {
var NativeRefreshControl = requireNativeComponent( var NativeRefreshControl = requireNativeComponent(
'AndroidSwipeRefreshLayout', 'AndroidSwipeRefreshLayout',
RefreshControl RefreshControl,
); );
} }

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const React = require('React'); const React = require('React');

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
module.exports = require('View'); module.exports = require('View');

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const Dimensions = require('Dimensions'); const Dimensions = require('Dimensions');
@ -21,7 +23,7 @@ const nullthrows = require('fbjs/lib/nullthrows');
const performanceNow = require('fbjs/lib/performanceNow'); const performanceNow = require('fbjs/lib/performanceNow');
const warning = require('fbjs/lib/warning'); const warning = require('fbjs/lib/warning');
const { ScrollViewManager } = require('NativeModules'); const {ScrollViewManager} = require('NativeModules');
/** /**
* Mixin that can be integrated in order to handle scrolling that plays well * Mixin that can be integrated in order to handle scrolling that plays well
@ -104,11 +106,11 @@ const { ScrollViewManager } = require('NativeModules');
const IS_ANIMATING_TOUCH_START_THRESHOLD_MS = 16; const IS_ANIMATING_TOUCH_START_THRESHOLD_MS = 16;
type State = { type State = {
isTouching: boolean, isTouching: boolean,
lastMomentumScrollBeginTime: number, lastMomentumScrollBeginTime: number,
lastMomentumScrollEndTime: number, lastMomentumScrollEndTime: number,
observedScrollSinceBecomingResponder: boolean, observedScrollSinceBecomingResponder: boolean,
becameResponderWhileAnimating: boolean, becameResponderWhileAnimating: boolean,
}; };
type Event = Object; type Event = Object;
@ -165,9 +167,11 @@ const ScrollResponderMixin = {
scrollResponderHandleStartShouldSetResponder: function(e: Event): boolean { scrollResponderHandleStartShouldSetResponder: function(e: Event): boolean {
const currentlyFocusedTextInput = TextInputState.currentlyFocusedField(); const currentlyFocusedTextInput = TextInputState.currentlyFocusedField();
if (this.props.keyboardShouldPersistTaps === 'handled' && if (
this.props.keyboardShouldPersistTaps === 'handled' &&
currentlyFocusedTextInput != null && currentlyFocusedTextInput != null &&
e.target !== currentlyFocusedTextInput) { e.target !== currentlyFocusedTextInput
) {
return true; return true;
} }
return false; return false;
@ -184,7 +188,9 @@ const ScrollResponderMixin = {
* *
* Invoke this from an `onStartShouldSetResponderCapture` event. * Invoke this from an `onStartShouldSetResponderCapture` event.
*/ */
scrollResponderHandleStartShouldSetResponderCapture: function(e: Event): boolean { scrollResponderHandleStartShouldSetResponderCapture: function(
e: Event,
): boolean {
// The scroll view should receive taps instead of its descendants if: // The scroll view should receive taps instead of its descendants if:
// * it is already animating/decelerating // * it is already animating/decelerating
if (this.scrollResponderIsAnimating()) { if (this.scrollResponderIsAnimating()) {
@ -197,11 +203,13 @@ const ScrollResponderMixin = {
// then the second tap goes to the actual interior view) // then the second tap goes to the actual interior view)
const currentlyFocusedTextInput = TextInputState.currentlyFocusedField(); const currentlyFocusedTextInput = TextInputState.currentlyFocusedField();
const {keyboardShouldPersistTaps} = this.props; const {keyboardShouldPersistTaps} = this.props;
const keyboardNeverPersistTaps = !keyboardShouldPersistTaps || const keyboardNeverPersistTaps =
keyboardShouldPersistTaps === 'never'; !keyboardShouldPersistTaps || keyboardShouldPersistTaps === 'never';
if (keyboardNeverPersistTaps && if (
keyboardNeverPersistTaps &&
currentlyFocusedTextInput != null currentlyFocusedTextInput != null
/* && !TextInputState.isTextInput(e.target) */) { /* && !TextInputState.isTextInput(e.target) */
) {
return true; return true;
} }
@ -218,8 +226,7 @@ const ScrollResponderMixin = {
* altogether. To improve this, find a way to disable the `UIScrollView` after * altogether. To improve this, find a way to disable the `UIScrollView` after
* a touch has already started. * a touch has already started.
*/ */
scrollResponderHandleResponderReject: function() { scrollResponderHandleResponderReject: function() {},
},
/** /**
* We will allow the scroll view to give up its lock iff it acquired the lock * We will allow the scroll view to give up its lock iff it acquired the lock
@ -270,12 +277,14 @@ const ScrollResponderMixin = {
// By default scroll views will unfocus a textField // By default scroll views will unfocus a textField
// if another touch occurs outside of it // if another touch occurs outside of it
const currentlyFocusedTextInput = TextInputState.currentlyFocusedField(); const currentlyFocusedTextInput = TextInputState.currentlyFocusedField();
if (this.props.keyboardShouldPersistTaps !== true && if (
this.props.keyboardShouldPersistTaps !== true &&
this.props.keyboardShouldPersistTaps !== 'always' && this.props.keyboardShouldPersistTaps !== 'always' &&
currentlyFocusedTextInput != null && currentlyFocusedTextInput != null &&
e.target !== currentlyFocusedTextInput && e.target !== currentlyFocusedTextInput &&
!this.state.observedScrollSinceBecomingResponder && !this.state.observedScrollSinceBecomingResponder &&
!this.state.becameResponderWhileAnimating) { !this.state.becameResponderWhileAnimating
) {
this.props.onScrollResponderKeyboardDismissed && this.props.onScrollResponderKeyboardDismissed &&
this.props.onScrollResponderKeyboardDismissed(e); this.props.onScrollResponderKeyboardDismissed(e);
TextInputState.blurTextInput(currentlyFocusedTextInput); TextInputState.blurTextInput(currentlyFocusedTextInput);
@ -318,8 +327,10 @@ const ScrollResponderMixin = {
// - If velocity is non-zero, then the interaction will stop when momentum scroll ends or // - If velocity is non-zero, then the interaction will stop when momentum scroll ends or
// another drag starts and ends. // another drag starts and ends.
// - If we don't get velocity, better to stop the interaction twice than not stop it. // - If we don't get velocity, better to stop the interaction twice than not stop it.
if (!this.scrollResponderIsAnimating() && if (
(!velocity || velocity.x === 0 && velocity.y === 0)) { !this.scrollResponderIsAnimating() &&
(!velocity || (velocity.x === 0 && velocity.y === 0))
) {
FrameRateLogger.endScroll(); FrameRateLogger.endScroll();
} }
this.props.onScrollEndDrag && this.props.onScrollEndDrag(e); this.props.onScrollEndDrag && this.props.onScrollEndDrag(e);
@ -380,9 +391,12 @@ const ScrollResponderMixin = {
*/ */
scrollResponderIsAnimating: function(): boolean { scrollResponderIsAnimating: function(): boolean {
const now = performanceNow(); const now = performanceNow();
const timeSinceLastMomentumScrollEnd = now - this.state.lastMomentumScrollEndTime; const timeSinceLastMomentumScrollEnd =
const isAnimating = timeSinceLastMomentumScrollEnd < IS_ANIMATING_TOUCH_START_THRESHOLD_MS || now - this.state.lastMomentumScrollEndTime;
this.state.lastMomentumScrollEndTime < this.state.lastMomentumScrollBeginTime; const isAnimating =
timeSinceLastMomentumScrollEnd < IS_ANIMATING_TOUCH_START_THRESHOLD_MS ||
this.state.lastMomentumScrollEndTime <
this.state.lastMomentumScrollBeginTime;
return isAnimating; return isAnimating;
}, },
@ -392,9 +406,9 @@ const ScrollResponderMixin = {
* function otherwise `this` is used. * function otherwise `this` is used.
*/ */
scrollResponderGetScrollableNode: function(): any { scrollResponderGetScrollableNode: function(): any {
return this.getScrollableNode ? return this.getScrollableNode
this.getScrollableNode() : ? this.getScrollableNode()
ReactNative.findNodeHandle(this); : ReactNative.findNodeHandle(this);
}, },
/** /**
@ -409,12 +423,14 @@ const ScrollResponderMixin = {
* This is deprecated due to ambiguity (y before x), and SHOULD NOT BE USED. * This is deprecated due to ambiguity (y before x), and SHOULD NOT BE USED.
*/ */
scrollResponderScrollTo: function( scrollResponderScrollTo: function(
x?: number | { x?: number, y?: number, animated?: boolean }, x?: number | {x?: number, y?: number, animated?: boolean},
y?: number, y?: number,
animated?: boolean animated?: boolean,
) { ) {
if (typeof x === 'number') { if (typeof x === 'number') {
console.warn('`scrollResponderScrollTo(x, y, animated)` is deprecated. Use `scrollResponderScrollTo({x: 5, y: 5, animated: true})` instead.'); console.warn(
'`scrollResponderScrollTo(x, y, animated)` is deprecated. Use `scrollResponderScrollTo({x: 5, y: 5, animated: true})` instead.',
);
} else { } else {
({x, y, animated} = x || {}); ({x, y, animated} = x || {});
} }
@ -433,9 +449,7 @@ const ScrollResponderMixin = {
* *
* `scrollResponderScrollToEnd({animated: true})` * `scrollResponderScrollToEnd({animated: true})`
*/ */
scrollResponderScrollToEnd: function( scrollResponderScrollToEnd: function(options?: {animated?: boolean}) {
options?: { animated?: boolean },
) {
// Default to true // Default to true
const animated = (options && options.animated) !== false; const animated = (options && options.animated) !== false;
UIManager.dispatchViewManagerCommand( UIManager.dispatchViewManagerCommand(
@ -448,8 +462,13 @@ const ScrollResponderMixin = {
/** /**
* Deprecated, do not use. * Deprecated, do not use.
*/ */
scrollResponderScrollWithoutAnimationTo: function(offsetX: number, offsetY: number) { scrollResponderScrollWithoutAnimationTo: function(
console.warn('`scrollResponderScrollWithoutAnimationTo` is deprecated. Use `scrollResponderScrollTo` instead'); offsetX: number,
offsetY: number,
) {
console.warn(
'`scrollResponderScrollWithoutAnimationTo` is deprecated. Use `scrollResponderScrollTo` instead',
);
this.scrollResponderScrollTo({x: offsetX, y: offsetY, animated: false}); this.scrollResponderScrollTo({x: offsetX, y: offsetY, animated: false});
}, },
@ -460,17 +479,32 @@ const ScrollResponderMixin = {
* @platform ios * @platform ios
*/ */
scrollResponderZoomTo: function( scrollResponderZoomTo: function(
rect: {| x: number, y: number, width: number, height: number, animated?: boolean |}, rect: {|
animated?: boolean // deprecated, put this inside the rect argument instead x: number,
y: number,
width: number,
height: number,
animated?: boolean,
|},
animated?: boolean, // deprecated, put this inside the rect argument instead
) { ) {
invariant(ScrollViewManager && ScrollViewManager.zoomToRect, 'zoomToRect is not implemented'); invariant(
ScrollViewManager && ScrollViewManager.zoomToRect,
'zoomToRect is not implemented',
);
if ('animated' in rect) { if ('animated' in rect) {
animated = rect.animated; animated = rect.animated;
delete rect.animated; delete rect.animated;
} else if (typeof animated !== 'undefined') { } else if (typeof animated !== 'undefined') {
console.warn('`scrollResponderZoomTo` `animated` argument is deprecated. Use `options.animated` instead'); console.warn(
'`scrollResponderZoomTo` `animated` argument is deprecated. Use `options.animated` instead',
);
} }
ScrollViewManager.zoomToRect(this.scrollResponderGetScrollableNode(), rect, animated !== false); ScrollViewManager.zoomToRect(
this.scrollResponderGetScrollableNode(),
rect,
animated !== false,
);
}, },
/** /**
@ -480,7 +514,7 @@ const ScrollResponderMixin = {
UIManager.dispatchViewManagerCommand( UIManager.dispatchViewManagerCommand(
this.scrollResponderGetScrollableNode(), this.scrollResponderGetScrollableNode(),
UIManager.RCTScrollView.Commands.flashScrollIndicators, UIManager.RCTScrollView.Commands.flashScrollIndicators,
[] [],
); );
}, },
@ -494,14 +528,18 @@ const ScrollResponderMixin = {
* @param {bool} preventNegativeScrolling Whether to allow pulling the content * @param {bool} preventNegativeScrolling Whether to allow pulling the content
* down to make it meet the keyboard's top. Default is false. * down to make it meet the keyboard's top. Default is false.
*/ */
scrollResponderScrollNativeHandleToKeyboard: function(nodeHandle: any, additionalOffset?: number, preventNegativeScrollOffset?: bool) { scrollResponderScrollNativeHandleToKeyboard: function(
nodeHandle: any,
additionalOffset?: number,
preventNegativeScrollOffset?: boolean,
) {
this.additionalScrollOffset = additionalOffset || 0; this.additionalScrollOffset = additionalOffset || 0;
this.preventNegativeScrollOffset = !!preventNegativeScrollOffset; this.preventNegativeScrollOffset = !!preventNegativeScrollOffset;
UIManager.measureLayout( UIManager.measureLayout(
nodeHandle, nodeHandle,
ReactNative.findNodeHandle(this.getInnerViewNode()), ReactNative.findNodeHandle(this.getInnerViewNode()),
this.scrollResponderTextInputFocusError, this.scrollResponderTextInputFocusError,
this.scrollResponderInputMeasureAndScrollToKeyboard this.scrollResponderInputMeasureAndScrollToKeyboard,
); );
}, },
@ -515,12 +553,18 @@ const ScrollResponderMixin = {
* @param {number} width Width of the text input. * @param {number} width Width of the text input.
* @param {number} height Height of the text input. * @param {number} height Height of the text input.
*/ */
scrollResponderInputMeasureAndScrollToKeyboard: function(left: number, top: number, width: number, height: number) { scrollResponderInputMeasureAndScrollToKeyboard: function(
left: number,
top: number,
width: number,
height: number,
) {
let keyboardScreenY = Dimensions.get('window').height; let keyboardScreenY = Dimensions.get('window').height;
if (this.keyboardWillOpenTo) { if (this.keyboardWillOpenTo) {
keyboardScreenY = this.keyboardWillOpenTo.endCoordinates.screenY; keyboardScreenY = this.keyboardWillOpenTo.endCoordinates.screenY;
} }
let scrollOffsetY = top - keyboardScreenY + height + this.additionalScrollOffset; let scrollOffsetY =
top - keyboardScreenY + height + this.additionalScrollOffset;
// By default, this can scroll with negative offset, pulling the content // By default, this can scroll with negative offset, pulling the content
// down so that the target component's bottom meets the keyboard's top. // down so that the target component's bottom meets the keyboard's top.
@ -549,16 +593,34 @@ const ScrollResponderMixin = {
const {keyboardShouldPersistTaps} = this.props; const {keyboardShouldPersistTaps} = this.props;
warning( warning(
typeof keyboardShouldPersistTaps !== 'boolean', typeof keyboardShouldPersistTaps !== 'boolean',
`'keyboardShouldPersistTaps={${keyboardShouldPersistTaps}}' is deprecated. ` `'keyboardShouldPersistTaps={${keyboardShouldPersistTaps}}' is deprecated. ` +
+ `Use 'keyboardShouldPersistTaps="${keyboardShouldPersistTaps ? 'always' : 'never'}"' instead` `Use 'keyboardShouldPersistTaps="${
keyboardShouldPersistTaps ? 'always' : 'never'
}"' instead`,
); );
this.keyboardWillOpenTo = null; this.keyboardWillOpenTo = null;
this.additionalScrollOffset = 0; this.additionalScrollOffset = 0;
this.addListenerOn(Keyboard, 'keyboardWillShow', this.scrollResponderKeyboardWillShow); this.addListenerOn(
this.addListenerOn(Keyboard, 'keyboardWillHide', this.scrollResponderKeyboardWillHide); Keyboard,
this.addListenerOn(Keyboard, 'keyboardDidShow', this.scrollResponderKeyboardDidShow); 'keyboardWillShow',
this.addListenerOn(Keyboard, 'keyboardDidHide', this.scrollResponderKeyboardDidHide); this.scrollResponderKeyboardWillShow,
);
this.addListenerOn(
Keyboard,
'keyboardWillHide',
this.scrollResponderKeyboardWillHide,
);
this.addListenerOn(
Keyboard,
'keyboardDidShow',
this.scrollResponderKeyboardDidShow,
);
this.addListenerOn(
Keyboard,
'keyboardDidHide',
this.scrollResponderKeyboardDidHide,
);
}, },
/** /**
@ -611,8 +673,7 @@ const ScrollResponderMixin = {
scrollResponderKeyboardDidHide: function(e: Event) { scrollResponderKeyboardDidHide: function(e: Event) {
this.keyboardWillOpenTo = null; this.keyboardWillOpenTo = null;
this.props.onKeyboardDidHide && this.props.onKeyboardDidHide(e); this.props.onKeyboardDidHide && this.props.onKeyboardDidHide(e);
} },
}; };
const ScrollResponder = { const ScrollResponder = {

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const AnimatedImplementation = require('AnimatedImplementation'); const AnimatedImplementation = require('AnimatedImplementation');
@ -235,7 +237,13 @@ const ScrollView = createReactClass({
* - `false`, deprecated, use 'never' instead * - `false`, deprecated, use 'never' instead
* - `true`, deprecated, use 'always' instead * - `true`, deprecated, use 'always' instead
*/ */
keyboardShouldPersistTaps: PropTypes.oneOf(['always', 'never', 'handled', false, true]), keyboardShouldPersistTaps: PropTypes.oneOf([
'always',
'never',
'handled',
false,
true,
]),
/** /**
* When set, the scroll view will adjust the scroll position so that the first child that is * When set, the scroll view will adjust the scroll position so that the first child that is
* currently visible and at or beyond `minIndexForVisible` will not change position. This is * currently visible and at or beyond `minIndexForVisible` will not change position. This is
@ -274,7 +282,7 @@ const ScrollView = createReactClass({
* @platform ios * @platform ios
*/ */
minimumZoomScale: PropTypes.number, minimumZoomScale: PropTypes.number,
/** /**
* Enables nested scrolling for Android API level 21+. * Enables nested scrolling for Android API level 21+.
* Nested scrolling is supported by default on iOS * Nested scrolling is supported by default on iOS
* @platform android * @platform android
@ -321,10 +329,10 @@ const ScrollView = createReactClass({
*/ */
pagingEnabled: PropTypes.bool, pagingEnabled: PropTypes.bool,
/** /**
* When true, ScrollView allows use of pinch gestures to zoom in and out. * When true, ScrollView allows use of pinch gestures to zoom in and out.
* The default value is true. * The default value is true.
* @platform ios * @platform ios
*/ */
pinchGestureEnabled: PropTypes.bool, pinchGestureEnabled: PropTypes.bool,
/** /**
* When false, the view cannot be scrolled via touch interaction. * When false, the view cannot be scrolled via touch interaction.
@ -453,7 +461,7 @@ const ScrollView = createReactClass({
*/ */
scrollPerfTag: PropTypes.string, scrollPerfTag: PropTypes.string,
/** /**
* Used to override default value of overScroll mode. * Used to override default value of overScroll mode.
* *
* Possible values: * Possible values:
@ -465,11 +473,7 @@ const ScrollView = createReactClass({
* *
* @platform android * @platform android
*/ */
overScrollMode: PropTypes.oneOf([ overScrollMode: PropTypes.oneOf(['auto', 'always', 'never']),
'auto',
'always',
'never',
]),
/** /**
* When true, ScrollView will emit updateChildFrames data in scroll events, * When true, ScrollView will emit updateChildFrames data in scroll events,
* otherwise will not compute or emit child frame data. This only exists * otherwise will not compute or emit child frame data. This only exists
@ -491,18 +495,20 @@ const ScrollView = createReactClass({
* `import IMAGE from './image.jpg'`. * `import IMAGE from './image.jpg'`.
* @platform vr * @platform vr
*/ */
scrollBarThumbImage: PropTypes.oneOfType([ scrollBarThumbImage: PropTypes.oneOfType([
PropTypes.shape({ PropTypes.shape({
uri: PropTypes.string, uri: PropTypes.string,
}), }),
// Opaque type returned by import IMAGE from './image.jpg' // Opaque type returned by import IMAGE from './image.jpg'
PropTypes.number, PropTypes.number,
]), ]),
}, },
mixins: [ScrollResponder.Mixin], mixins: [ScrollResponder.Mixin],
_scrollAnimatedValue: (new AnimatedImplementation.Value(0): AnimatedImplementation.Value), _scrollAnimatedValue: (new AnimatedImplementation.Value(
0,
): AnimatedImplementation.Value),
_scrollAnimatedValueAttachment: (null: ?{detach: () => void}), _scrollAnimatedValueAttachment: (null: ?{detach: () => void}),
_stickyHeaderRefs: (new Map(): Map<number, ScrollViewStickyHeader>), _stickyHeaderRefs: (new Map(): Map<number, ScrollViewStickyHeader>),
_headerLayoutYs: (new Map(): Map<string, number>), _headerLayoutYs: (new Map(): Map<string, number>),
@ -514,8 +520,12 @@ const ScrollView = createReactClass({
}, },
UNSAFE_componentWillMount: function() { UNSAFE_componentWillMount: function() {
this._scrollAnimatedValue = new AnimatedImplementation.Value(this.props.contentOffset ? this.props.contentOffset.y : 0); this._scrollAnimatedValue = new AnimatedImplementation.Value(
this._scrollAnimatedValue.setOffset(this.props.contentInset ? this.props.contentInset.top : 0); this.props.contentOffset ? this.props.contentOffset.y : 0,
);
this._scrollAnimatedValue.setOffset(
this.props.contentInset ? this.props.contentInset.top : 0,
);
this._stickyHeaderRefs = new Map(); this._stickyHeaderRefs = new Map();
this._headerLayoutYs = new Map(); this._headerLayoutYs = new Map();
}, },
@ -568,19 +578,23 @@ const ScrollView = createReactClass({
* This is deprecated due to ambiguity (y before x), and SHOULD NOT BE USED. * This is deprecated due to ambiguity (y before x), and SHOULD NOT BE USED.
*/ */
scrollTo: function( scrollTo: function(
y?: number | { x?: number, y?: number, animated?: boolean }, y?: number | {x?: number, y?: number, animated?: boolean},
x?: number, x?: number,
animated?: boolean animated?: boolean,
) { ) {
if (typeof y === 'number') { if (typeof y === 'number') {
console.warn('`scrollTo(y, x, animated)` is deprecated. Use `scrollTo({x: 5, y: 5, ' + console.warn(
'animated: true})` instead.'); '`scrollTo(y, x, animated)` is deprecated. Use `scrollTo({x: 5, y: 5, ' +
'animated: true})` instead.',
);
} else { } else {
({x, y, animated} = y || {}); ({x, y, animated} = y || {});
} }
this.getScrollResponder().scrollResponderScrollTo( this.getScrollResponder().scrollResponderScrollTo({
{x: x || 0, y: y || 0, animated: animated !== false} x: x || 0,
); y: y || 0,
animated: animated !== false,
});
}, },
/** /**
@ -591,9 +605,7 @@ const ScrollView = createReactClass({
* `scrollToEnd({animated: false})` for immediate scrolling. * `scrollToEnd({animated: false})` for immediate scrolling.
* If no options are passed, `animated` defaults to true. * If no options are passed, `animated` defaults to true.
*/ */
scrollToEnd: function( scrollToEnd: function(options?: {animated?: boolean}) {
options?: { animated?: boolean },
) {
// Default to true // Default to true
const animated = (options && options.animated) !== false; const animated = (options && options.animated) !== false;
this.getScrollResponder().scrollResponderScrollToEnd({ this.getScrollResponder().scrollResponderScrollToEnd({
@ -605,7 +617,9 @@ const ScrollView = createReactClass({
* Deprecated, use `scrollTo` instead. * Deprecated, use `scrollTo` instead.
*/ */
scrollWithoutAnimationTo: function(y: number = 0, x: number = 0) { scrollWithoutAnimationTo: function(y: number = 0, x: number = 0) {
console.warn('`scrollWithoutAnimationTo` is deprecated. Use `scrollTo` instead'); console.warn(
'`scrollWithoutAnimationTo` is deprecated. Use `scrollTo` instead',
);
this.scrollTo({x, y, animated: false}); this.scrollTo({x, y, animated: false});
}, },
@ -627,11 +641,14 @@ const ScrollView = createReactClass({
if (this._scrollAnimatedValueAttachment) { if (this._scrollAnimatedValueAttachment) {
this._scrollAnimatedValueAttachment.detach(); this._scrollAnimatedValueAttachment.detach();
} }
if (this.props.stickyHeaderIndices && this.props.stickyHeaderIndices.length > 0) { if (
this.props.stickyHeaderIndices &&
this.props.stickyHeaderIndices.length > 0
) {
this._scrollAnimatedValueAttachment = AnimatedImplementation.attachNativeEvent( this._scrollAnimatedValueAttachment = AnimatedImplementation.attachNativeEvent(
this._scrollViewRef, this._scrollViewRef,
'onScroll', 'onScroll',
[{nativeEvent: {contentOffset: {y: this._scrollAnimatedValue}}}] [{nativeEvent: {contentOffset: {y: this._scrollAnimatedValue}}}],
); );
} }
}, },
@ -658,10 +675,12 @@ const ScrollView = createReactClass({
this._headerLayoutYs.set(key, layoutY); this._headerLayoutYs.set(key, layoutY);
const indexOfIndex = this.props.stickyHeaderIndices.indexOf(index); const indexOfIndex = this.props.stickyHeaderIndices.indexOf(index);
const previousHeaderIndex = this.props.stickyHeaderIndices[indexOfIndex - 1]; const previousHeaderIndex = this.props.stickyHeaderIndices[
indexOfIndex - 1
];
if (previousHeaderIndex != null) { if (previousHeaderIndex != null) {
const previousHeader = this._stickyHeaderRefs.get( const previousHeader = this._stickyHeaderRefs.get(
this._getKeyForIndex(previousHeaderIndex, childArray) this._getKeyForIndex(previousHeaderIndex, childArray),
); );
previousHeader && previousHeader.setNextHeaderY(layoutY); previousHeader && previousHeader.setNextHeaderY(layoutY);
} }
@ -669,18 +688,25 @@ const ScrollView = createReactClass({
_handleScroll: function(e: Object) { _handleScroll: function(e: Object) {
if (__DEV__) { if (__DEV__) {
if (this.props.onScroll && this.props.scrollEventThrottle == null && Platform.OS === 'ios') { if (
this.props.onScroll &&
this.props.scrollEventThrottle == null &&
Platform.OS === 'ios'
) {
console.log( console.log(
'You specified `onScroll` on a <ScrollView> but not ' + 'You specified `onScroll` on a <ScrollView> but not ' +
'`scrollEventThrottle`. You will only receive one event. ' + '`scrollEventThrottle`. You will only receive one event. ' +
'Using `16` you get all the events but be aware that it may ' + 'Using `16` you get all the events but be aware that it may ' +
'cause frame drops, use a bigger number if you don\'t need as ' + "cause frame drops, use a bigger number if you don't need as " +
'much precision.' 'much precision.',
); );
} }
} }
if (Platform.OS === 'android') { if (Platform.OS === 'android') {
if (this.props.keyboardDismissMode === 'on-drag' && this.state.isTouching) { if (
this.props.keyboardDismissMode === 'on-drag' &&
this.state.isTouching
) {
dismissKeyboard(); dismissKeyboard();
} }
} }
@ -689,7 +715,7 @@ const ScrollView = createReactClass({
_handleLayout: function(e: Object) { _handleLayout: function(e: Object) {
if (this.props.invertStickyHeaders) { if (this.props.invertStickyHeaders) {
this.setState({ layoutHeight: e.nativeEvent.layout.height }); this.setState({layoutHeight: e.nativeEvent.layout.height});
} }
if (this.props.onLayout) { if (this.props.onLayout) {
this.props.onLayout(e); this.props.onLayout(e);
@ -698,7 +724,8 @@ const ScrollView = createReactClass({
_handleContentOnLayout: function(e: Object) { _handleContentOnLayout: function(e: Object) {
const {width, height} = e.nativeEvent.layout; const {width, height} = e.nativeEvent.layout;
this.props.onContentSizeChange && this.props.onContentSizeChange(width, height); this.props.onContentSizeChange &&
this.props.onContentSizeChange(width, height);
}, },
_scrollViewRef: (null: ?ScrollView), _scrollViewRef: (null: ?ScrollView),
@ -727,18 +754,18 @@ const ScrollView = createReactClass({
ScrollContentContainerViewClass = RCTScrollContentView; ScrollContentContainerViewClass = RCTScrollContentView;
warning( warning(
!this.props.snapToInterval || !this.props.pagingEnabled, !this.props.snapToInterval || !this.props.pagingEnabled,
'snapToInterval is currently ignored when pagingEnabled is true.' 'snapToInterval is currently ignored when pagingEnabled is true.',
); );
} }
invariant( invariant(
ScrollViewClass !== undefined, ScrollViewClass !== undefined,
'ScrollViewClass must not be undefined' 'ScrollViewClass must not be undefined',
); );
invariant( invariant(
ScrollContentContainerViewClass !== undefined, ScrollContentContainerViewClass !== undefined,
'ScrollContentContainerViewClass must not be undefined' 'ScrollContentContainerViewClass must not be undefined',
); );
const contentContainerStyle = [ const contentContainerStyle = [
@ -747,12 +774,14 @@ const ScrollView = createReactClass({
]; ];
if (__DEV__ && this.props.style) { if (__DEV__ && this.props.style) {
const style = flattenStyle(this.props.style); const style = flattenStyle(this.props.style);
const childLayoutProps = ['alignItems', 'justifyContent'] const childLayoutProps = ['alignItems', 'justifyContent'].filter(
.filter((prop) => style && style[prop] !== undefined); prop => style && style[prop] !== undefined,
);
invariant( invariant(
childLayoutProps.length === 0, childLayoutProps.length === 0,
'ScrollView child layout (' + JSON.stringify(childLayoutProps) + 'ScrollView child layout (' +
') must be applied through the contentContainerStyle prop.' JSON.stringify(childLayoutProps) +
') must be applied through the contentContainerStyle prop.',
); );
} }
@ -764,34 +793,38 @@ const ScrollView = createReactClass({
} }
const {stickyHeaderIndices} = this.props; const {stickyHeaderIndices} = this.props;
const hasStickyHeaders = stickyHeaderIndices && stickyHeaderIndices.length > 0; const hasStickyHeaders =
const childArray = hasStickyHeaders && React.Children.toArray(this.props.children); stickyHeaderIndices && stickyHeaderIndices.length > 0;
const children = hasStickyHeaders ? const childArray =
childArray.map((child, index) => { hasStickyHeaders && React.Children.toArray(this.props.children);
const indexOfIndex = child ? stickyHeaderIndices.indexOf(index) : -1; const children = hasStickyHeaders
if (indexOfIndex > -1) { ? childArray.map((child, index) => {
const key = child.key; const indexOfIndex = child ? stickyHeaderIndices.indexOf(index) : -1;
const nextIndex = stickyHeaderIndices[indexOfIndex + 1]; if (indexOfIndex > -1) {
return ( const key = child.key;
<ScrollViewStickyHeader const nextIndex = stickyHeaderIndices[indexOfIndex + 1];
key={key} return (
ref={(ref) => this._setStickyHeaderRef(key, ref)} <ScrollViewStickyHeader
nextHeaderLayoutY={ key={key}
this._headerLayoutYs.get(this._getKeyForIndex(nextIndex, childArray)) ref={ref => this._setStickyHeaderRef(key, ref)}
} nextHeaderLayoutY={this._headerLayoutYs.get(
onLayout={(event) => this._onStickyHeaderLayout(index, event, key)} this._getKeyForIndex(nextIndex, childArray),
scrollAnimatedValue={this._scrollAnimatedValue} )}
inverted={this.props.invertStickyHeaders} onLayout={event =>
scrollViewHeight={this.state.layoutHeight}> this._onStickyHeaderLayout(index, event, key)
{child} }
</ScrollViewStickyHeader> scrollAnimatedValue={this._scrollAnimatedValue}
); inverted={this.props.invertStickyHeaders}
} else { scrollViewHeight={this.state.layoutHeight}>
return child; {child}
} </ScrollViewStickyHeader>
}) : );
this.props.children; } else {
const contentContainer = return child;
}
})
: this.props.children;
const contentContainer = (
<ScrollContentContainerViewClass <ScrollContentContainerViewClass
{...contentSizeChangeProps} {...contentSizeChangeProps}
ref={this._setInnerViewRef} ref={this._setInnerViewRef}
@ -799,28 +832,31 @@ const ScrollView = createReactClass({
removeClippedSubviews={ removeClippedSubviews={
// Subview clipping causes issues with sticky headers on Android and // Subview clipping causes issues with sticky headers on Android and
// would be hard to fix properly in a performant way. // would be hard to fix properly in a performant way.
Platform.OS === 'android' && hasStickyHeaders ? Platform.OS === 'android' && hasStickyHeaders
false : ? false
this.props.removeClippedSubviews : this.props.removeClippedSubviews
} }
collapsable={false}> collapsable={false}>
{children} {children}
</ScrollContentContainerViewClass>; </ScrollContentContainerViewClass>
);
const alwaysBounceHorizontal = const alwaysBounceHorizontal =
this.props.alwaysBounceHorizontal !== undefined ? this.props.alwaysBounceHorizontal !== undefined
this.props.alwaysBounceHorizontal : ? this.props.alwaysBounceHorizontal
this.props.horizontal; : this.props.horizontal;
const alwaysBounceVertical = const alwaysBounceVertical =
this.props.alwaysBounceVertical !== undefined ? this.props.alwaysBounceVertical !== undefined
this.props.alwaysBounceVertical : ? this.props.alwaysBounceVertical
!this.props.horizontal; : !this.props.horizontal;
const DEPRECATED_sendUpdatedChildFrames = const DEPRECATED_sendUpdatedChildFrames = !!this.props
!!this.props.DEPRECATED_sendUpdatedChildFrames; .DEPRECATED_sendUpdatedChildFrames;
const baseStyle = this.props.horizontal ? styles.baseHorizontal : styles.baseVertical; const baseStyle = this.props.horizontal
? styles.baseHorizontal
: styles.baseVertical;
const props = { const props = {
...this.props, ...this.props,
alwaysBounceHorizontal, alwaysBounceHorizontal,
@ -836,25 +872,33 @@ const ScrollView = createReactClass({
onResponderReject: this.scrollResponderHandleResponderReject, onResponderReject: this.scrollResponderHandleResponderReject,
onResponderRelease: this.scrollResponderHandleResponderRelease, onResponderRelease: this.scrollResponderHandleResponderRelease,
onResponderTerminate: this.scrollResponderHandleTerminate, onResponderTerminate: this.scrollResponderHandleTerminate,
onResponderTerminationRequest: this.scrollResponderHandleTerminationRequest, onResponderTerminationRequest: this
.scrollResponderHandleTerminationRequest,
onScroll: this._handleScroll, onScroll: this._handleScroll,
onScrollBeginDrag: this.scrollResponderHandleScrollBeginDrag, onScrollBeginDrag: this.scrollResponderHandleScrollBeginDrag,
onScrollEndDrag: this.scrollResponderHandleScrollEndDrag, onScrollEndDrag: this.scrollResponderHandleScrollEndDrag,
onScrollShouldSetResponder: this.scrollResponderHandleScrollShouldSetResponder, onScrollShouldSetResponder: this
onStartShouldSetResponder: this.scrollResponderHandleStartShouldSetResponder, .scrollResponderHandleScrollShouldSetResponder,
onStartShouldSetResponderCapture: this.scrollResponderHandleStartShouldSetResponderCapture, onStartShouldSetResponder: this
.scrollResponderHandleStartShouldSetResponder,
onStartShouldSetResponderCapture: this
.scrollResponderHandleStartShouldSetResponderCapture,
onTouchEnd: this.scrollResponderHandleTouchEnd, onTouchEnd: this.scrollResponderHandleTouchEnd,
onTouchMove: this.scrollResponderHandleTouchMove, onTouchMove: this.scrollResponderHandleTouchMove,
onTouchStart: this.scrollResponderHandleTouchStart, onTouchStart: this.scrollResponderHandleTouchStart,
onTouchCancel: this.scrollResponderHandleTouchCancel, onTouchCancel: this.scrollResponderHandleTouchCancel,
scrollBarThumbImage: resolveAssetSource(this.props.scrollBarThumbImage), scrollBarThumbImage: resolveAssetSource(this.props.scrollBarThumbImage),
scrollEventThrottle: hasStickyHeaders ? 1 : this.props.scrollEventThrottle, scrollEventThrottle: hasStickyHeaders
sendMomentumEvents: (this.props.onMomentumScrollBegin || this.props.onMomentumScrollEnd) ? ? 1
true : false, : this.props.scrollEventThrottle,
sendMomentumEvents:
this.props.onMomentumScrollBegin || this.props.onMomentumScrollEnd
? true
: false,
DEPRECATED_sendUpdatedChildFrames, DEPRECATED_sendUpdatedChildFrames,
}; };
const { decelerationRate } = this.props; const {decelerationRate} = this.props;
if (decelerationRate) { if (decelerationRate) {
props.decelerationRate = processDecelerationRate(decelerationRate); props.decelerationRate = processDecelerationRate(decelerationRate);
} }
@ -881,9 +925,12 @@ const ScrollView = createReactClass({
return React.cloneElement( return React.cloneElement(
refreshControl, refreshControl,
{style: props.style}, {style: props.style},
<ScrollViewClass {...props} style={baseStyle} ref={this._setScrollViewRef}> <ScrollViewClass
{...props}
style={baseStyle}
ref={this._setScrollViewRef}>
{contentContainer} {contentContainer}
</ScrollViewClass> </ScrollViewClass>,
); );
} }
} }
@ -892,7 +939,7 @@ const ScrollView = createReactClass({
{contentContainer} {contentContainer}
</ScrollViewClass> </ScrollViewClass>
); );
} },
}); });
const styles = StyleSheet.create({ const styles = StyleSheet.create({
@ -923,29 +970,29 @@ if (Platform.OS === 'android') {
nativeOnlyProps = { nativeOnlyProps = {
nativeOnly: { nativeOnly: {
sendMomentumEvents: true, sendMomentumEvents: true,
} },
}; };
AndroidScrollView = requireNativeComponent( AndroidScrollView = requireNativeComponent(
'RCTScrollView', 'RCTScrollView',
(ScrollView: React.ComponentType<any>), (ScrollView: React.ComponentType<any>),
nativeOnlyProps nativeOnlyProps,
); );
AndroidHorizontalScrollView = requireNativeComponent( AndroidHorizontalScrollView = requireNativeComponent(
'AndroidHorizontalScrollView', 'AndroidHorizontalScrollView',
(ScrollView: React.ComponentType<any>), (ScrollView: React.ComponentType<any>),
nativeOnlyProps nativeOnlyProps,
); );
AndroidHorizontalScrollContentView = requireNativeComponent( AndroidHorizontalScrollContentView = requireNativeComponent(
'AndroidHorizontalScrollContentView' 'AndroidHorizontalScrollContentView',
); );
} else if (Platform.OS === 'ios') { } else if (Platform.OS === 'ios') {
nativeOnlyProps = { nativeOnlyProps = {
nativeOnly: { nativeOnly: {
onMomentumScrollBegin: true, onMomentumScrollBegin: true,
onMomentumScrollEnd : true, onMomentumScrollEnd: true,
onScrollBeginDrag: true, onScrollBeginDrag: true,
onScrollEndDrag: true, onScrollEndDrag: true,
} },
}; };
RCTScrollView = requireNativeComponent( RCTScrollView = requireNativeComponent(
'RCTScrollView', 'RCTScrollView',
@ -955,8 +1002,7 @@ if (Platform.OS === 'android') {
RCTScrollContentView = requireNativeComponent('RCTScrollContentView', View); RCTScrollContentView = requireNativeComponent('RCTScrollContentView', View);
} else { } else {
nativeOnlyProps = { nativeOnlyProps = {
nativeOnly: { nativeOnly: {},
}
}; };
RCTScrollView = requireNativeComponent( RCTScrollView = requireNativeComponent(
'RCTScrollView', 'RCTScrollView',

View File

@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
@ -27,9 +28,7 @@ class ScrollViewMock extends ScrollViewComponent {
return ( return (
<RCTScrollView {...this.props}> <RCTScrollView {...this.props}>
{this.props.refreshControl} {this.props.refreshControl}
<View> <View>{this.props.children}</View>
{this.props.children}
</View>
</RCTScrollView> </RCTScrollView>
); );
} }

View File

@ -4,7 +4,9 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
*/ */
'use strict'; 'use strict';
function processDecelerationRate(decelerationRate) { function processDecelerationRate(decelerationRate) {

View File

@ -1,10 +1,10 @@
/** /**
* Copyright (c) 2015-present, Facebook, Inc. * Copyright (c) 2015-present, Facebook, Inc.
* *
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
*/ */
'use strict'; 'use strict';
@ -40,7 +40,7 @@ const styles = StyleSheet.create({
color: '#333333', color: '#333333',
margin: 5, margin: 5,
fontSize: 10, fontSize: 10,
} },
}); });
module.exports = DummySegmentedControlIOS; module.exports = DummySegmentedControlIOS;

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const NativeMethodsMixin = require('NativeMethodsMixin'); const NativeMethodsMixin = require('NativeMethodsMixin');
@ -89,19 +91,20 @@ const SegmentedControlIOS = createReactClass({
* If true, then selecting a segment won't persist visually. * If true, then selecting a segment won't persist visually.
* The `onValueChange` callback will still work as expected. * The `onValueChange` callback will still work as expected.
*/ */
momentary: PropTypes.bool momentary: PropTypes.bool,
}, },
getDefaultProps: function(): DefaultProps { getDefaultProps: function(): DefaultProps {
return { return {
values: [], values: [],
enabled: true enabled: true,
}; };
}, },
_onChange: function(event: Event) { _onChange: function(event: Event) {
this.props.onChange && this.props.onChange(event); this.props.onChange && this.props.onChange(event);
this.props.onValueChange && this.props.onValueChange(event.nativeEvent.value); this.props.onValueChange &&
this.props.onValueChange(event.nativeEvent.value);
}, },
render: function() { render: function() {
@ -113,7 +116,7 @@ const SegmentedControlIOS = createReactClass({
onChange={this._onChange} onChange={this._onChange}
/> />
); );
} },
}); });
const styles = StyleSheet.create({ const styles = StyleSheet.create({
@ -124,7 +127,7 @@ const styles = StyleSheet.create({
const RCTSegmentedControl = requireNativeComponent( const RCTSegmentedControl = requireNativeComponent(
'RCTSegmentedControl', 'RCTSegmentedControl',
SegmentedControlIOS SegmentedControlIOS,
); );
module.exports = SegmentedControlIOS; module.exports = SegmentedControlIOS;

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const Image = require('Image'); const Image = require('Image');
@ -192,13 +194,13 @@ const Slider = createReactClass({
testID: PropTypes.string, testID: PropTypes.string,
}, },
getDefaultProps: function() : any { getDefaultProps: function(): any {
return { return {
disabled: false, disabled: false,
value: 0, value: 0,
minimumValue: 0, minimumValue: 0,
maximumValue: 1, maximumValue: 1,
step: 0 step: 0,
}; };
}, },
@ -206,8 +208,8 @@ const Slider = createReactClass({
uiViewClassName: 'RCTSlider', uiViewClassName: 'RCTSlider',
validAttributes: { validAttributes: {
...ReactNativeViewAttributes.RCTView, ...ReactNativeViewAttributes.RCTView,
value: true value: true,
} },
}, },
render: function() { render: function() {
@ -220,15 +222,17 @@ const Slider = createReactClass({
/* $FlowFixMe(>=0.54.0 site=react_native_fb,react_native_oss) This comment /* $FlowFixMe(>=0.54.0 site=react_native_fb,react_native_oss) This comment
* suppresses an error found when Flow v0.54 was deployed. To see the error * suppresses an error found when Flow v0.54 was deployed. To see the error
* delete this comment and run Flow. */ * delete this comment and run Flow. */
props.onValueChange = onValueChange && ((event: Event) => { props.onValueChange =
let userEvent = true; onValueChange &&
if (Platform.OS === 'android') { ((event: Event) => {
// On Android there's a special flag telling us the user is let userEvent = true;
// dragging the slider. if (Platform.OS === 'android') {
userEvent = event.nativeEvent.fromUser; // On Android there's a special flag telling us the user is
} // dragging the slider.
onValueChange && userEvent && onValueChange(event.nativeEvent.value); userEvent = event.nativeEvent.fromUser;
}); }
onValueChange && userEvent && onValueChange(event.nativeEvent.value);
});
/* $FlowFixMe(>=0.54.0 site=react_native_fb,react_native_oss) This comment /* $FlowFixMe(>=0.54.0 site=react_native_fb,react_native_oss) This comment
* suppresses an error found when Flow v0.54 was deployed. To see the error * suppresses an error found when Flow v0.54 was deployed. To see the error
@ -238,17 +242,21 @@ const Slider = createReactClass({
/* $FlowFixMe(>=0.54.0 site=react_native_fb,react_native_oss) This comment /* $FlowFixMe(>=0.54.0 site=react_native_fb,react_native_oss) This comment
* suppresses an error found when Flow v0.54 was deployed. To see the error * suppresses an error found when Flow v0.54 was deployed. To see the error
* delete this comment and run Flow. */ * delete this comment and run Flow. */
props.onSlidingComplete = onSlidingComplete && ((event: Event) => { props.onSlidingComplete =
onSlidingComplete && onSlidingComplete(event.nativeEvent.value); onSlidingComplete &&
}); ((event: Event) => {
onSlidingComplete && onSlidingComplete(event.nativeEvent.value);
});
return <RCTSlider return (
{...props} <RCTSlider
enabled={!this.props.disabled} {...props}
onStartShouldSetResponder={() => true} enabled={!this.props.disabled}
onResponderTerminationRequest={() => false} onStartShouldSetResponder={() => true}
/>; onResponderTerminationRequest={() => false}
} />
);
},
}); });
let styles; let styles;
@ -269,7 +277,7 @@ if (Platform.OS === 'android') {
options = { options = {
nativeOnly: { nativeOnly: {
enabled: true, enabled: true,
} },
}; };
} }
const RCTSlider = requireNativeComponent('RCTSlider', Slider, options); const RCTSlider = requireNativeComponent('RCTSlider', Slider, options);

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const React = require('React'); const React = require('React');
@ -26,18 +28,16 @@ const React = require('React');
* React reconciliation. * React reconciliation.
*/ */
class StaticContainer extends React.Component<Object> { class StaticContainer extends React.Component<Object> {
shouldComponentUpdate(nextProps: Object): boolean { shouldComponentUpdate(nextProps: Object): boolean {
return !!nextProps.shouldUpdate; return !!nextProps.shouldUpdate;
} }
render() { render() {
const child = this.props.children; const child = this.props.children;
return (child === null || child === false) return child === null || child === false
? null ? null
: React.Children.only(child); : React.Children.only(child);
} }
} }
module.exports = StaticContainer; module.exports = StaticContainer;

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const React = require('React'); const React = require('React');
@ -21,7 +23,7 @@ class StaticRenderer extends React.Component<{
render: PropTypes.func.isRequired, render: PropTypes.func.isRequired,
}; };
shouldComponentUpdate(nextProps: { shouldUpdate: boolean }): boolean { shouldComponentUpdate(nextProps: {shouldUpdate: boolean}): boolean {
return nextProps.shouldUpdate; return nextProps.shouldUpdate;
} }

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const React = require('React'); const React = require('React');
@ -24,7 +26,7 @@ export type StatusBarStyle = $Enum<{
/** /**
* Default status bar style (dark for iOS, light for Android) * Default status bar style (dark for iOS, light for Android)
*/ */
'default': string, default: string,
/** /**
* Dark background, white texts and icons * Dark background, white texts and icons
*/ */
@ -42,15 +44,15 @@ export type StatusBarAnimation = $Enum<{
/** /**
* No animation * No animation
*/ */
'none': string, none: string,
/** /**
* Fade animation * Fade animation
*/ */
'fade': string, fade: string,
/** /**
* Slide animation * Slide animation
*/ */
'slide': string, slide: string,
}>; }>;
type DefaultProps = { type DefaultProps = {
@ -62,7 +64,7 @@ type DefaultProps = {
*/ */
function mergePropsStack( function mergePropsStack(
propsStack: Array<Object>, propsStack: Array<Object>,
defaultValues: Object defaultValues: Object,
): Object { ): Object {
return propsStack.reduce((prev, cur) => { return propsStack.reduce((prev, cur) => {
for (const prop in cur) { for (const prop in cur) {
@ -223,7 +225,7 @@ class StatusBar extends React.Component<{
static setNetworkActivityIndicatorVisible(visible: boolean) { static setNetworkActivityIndicatorVisible(visible: boolean) {
if (Platform.OS !== 'ios') { if (Platform.OS !== 'ios') {
console.warn( console.warn(
'`setNetworkActivityIndicatorVisible` is only available on iOS' '`setNetworkActivityIndicatorVisible` is only available on iOS',
); );
return; return;
} }
@ -345,7 +347,7 @@ class StatusBar extends React.Component<{
const oldProps = StatusBar._currentValues; const oldProps = StatusBar._currentValues;
const mergedProps = mergePropsStack( const mergedProps = mergePropsStack(
StatusBar._propsStack, StatusBar._propsStack,
StatusBar._defaultProps StatusBar._defaultProps,
); );
// Update the props that have changed using the merged values from the props stack. // Update the props that have changed using the merged values from the props stack.
@ -356,13 +358,15 @@ class StatusBar extends React.Component<{
) { ) {
StatusBarManager.setStyle( StatusBarManager.setStyle(
mergedProps.barStyle.value, mergedProps.barStyle.value,
mergedProps.barStyle.animated mergedProps.barStyle.animated,
); );
} }
if (!oldProps || oldProps.hidden.value !== mergedProps.hidden.value) { if (!oldProps || oldProps.hidden.value !== mergedProps.hidden.value) {
StatusBarManager.setHidden( StatusBarManager.setHidden(
mergedProps.hidden.value, mergedProps.hidden.value,
mergedProps.hidden.animated ? mergedProps.hidden.transition : 'none' mergedProps.hidden.animated
? mergedProps.hidden.transition
: 'none',
); );
} }
@ -372,7 +376,7 @@ class StatusBar extends React.Component<{
mergedProps.networkActivityIndicatorVisible mergedProps.networkActivityIndicatorVisible
) { ) {
StatusBarManager.setNetworkActivityIndicatorVisible( StatusBarManager.setNetworkActivityIndicatorVisible(
mergedProps.networkActivityIndicatorVisible mergedProps.networkActivityIndicatorVisible,
); );
} }
} else if (Platform.OS === 'android') { } else if (Platform.OS === 'android') {
@ -388,7 +392,7 @@ class StatusBar extends React.Component<{
) { ) {
StatusBarManager.setColor( StatusBarManager.setColor(
processColor(mergedProps.backgroundColor.value), processColor(mergedProps.backgroundColor.value),
mergedProps.backgroundColor.animated mergedProps.backgroundColor.animated,
); );
} }
if (!oldProps || oldProps.hidden.value !== mergedProps.hidden.value) { if (!oldProps || oldProps.hidden.value !== mergedProps.hidden.value) {

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const NativeEventEmitter = require('NativeEventEmitter'); const NativeEventEmitter = require('NativeEventEmitter');

View File

@ -4,12 +4,14 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const NativeEventEmitter = require('NativeEventEmitter'); const NativeEventEmitter = require('NativeEventEmitter');
const { StatusBarManager } = require('NativeModules'); const {StatusBarManager} = require('NativeModules');
/** /**
* Use `StatusBar` for mutating the status bar. * Use `StatusBar` for mutating the status bar.

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
import type EventEmitter from 'EventEmitter'; import type EventEmitter from 'EventEmitter';
@ -21,7 +23,6 @@ import type EventEmitter from 'EventEmitter';
const Subscribable = {}; const Subscribable = {};
Subscribable.Mixin = { Subscribable.Mixin = {
UNSAFE_componentWillMount: function() { UNSAFE_componentWillMount: function() {
this._subscribableSubscriptions = []; this._subscribableSubscriptions = [];
}, },
@ -29,9 +30,10 @@ Subscribable.Mixin = {
componentWillUnmount: function() { componentWillUnmount: function() {
// This null check is a fix for a broken version of uglify-es. Should be deleted eventually // This null check is a fix for a broken version of uglify-es. Should be deleted eventually
// https://github.com/facebook/react-native/issues/17348 // https://github.com/facebook/react-native/issues/17348
this._subscribableSubscriptions && this._subscribableSubscriptions.forEach( this._subscribableSubscriptions &&
(subscription) => subscription.remove() this._subscribableSubscriptions.forEach(subscription =>
); subscription.remove(),
);
this._subscribableSubscriptions = null; this._subscribableSubscriptions = null;
}, },
@ -52,12 +54,12 @@ Subscribable.Mixin = {
eventEmitter: EventEmitter, eventEmitter: EventEmitter,
eventType: string, eventType: string,
listener: Function, listener: Function,
context: Object context: Object,
) { ) {
this._subscribableSubscriptions.push( this._subscribableSubscriptions.push(
eventEmitter.addListener(eventType, listener, context) eventEmitter.addListener(eventType, listener, context),
); );
} },
}; };
module.exports = Subscribable; module.exports = Subscribable;

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const ColorPropType = require('ColorPropType'); const ColorPropType = require('ColorPropType');
@ -93,7 +95,8 @@ const Switch = createReactClass({
* suppresses an error when upgrading Flow's support for React. To see the * suppresses an error when upgrading Flow's support for React. To see the
* error delete this comment and run Flow. */ * error delete this comment and run Flow. */
this.props.onChange && this.props.onChange(event); this.props.onChange && this.props.onChange(event);
this.props.onValueChange && this.props.onValueChange(event.nativeEvent.value); this.props.onValueChange &&
this.props.onValueChange(event.nativeEvent.value);
}, },
render: function() { render: function() {
@ -113,17 +116,21 @@ const Switch = createReactClass({
/* $FlowFixMe(>=0.70.0 site=react_native_fb) This comment suppresses an /* $FlowFixMe(>=0.70.0 site=react_native_fb) This comment suppresses an
* error found when Flow v0.70 was deployed. To see the error delete * error found when Flow v0.70 was deployed. To see the error delete
* this comment and run Flow. */ * this comment and run Flow. */
props.trackTintColor = this.props.value ? this.props.onTintColor : this.props.tintColor; props.trackTintColor = this.props.value
? this.props.onTintColor
: this.props.tintColor;
} else if (Platform.OS === 'ios') { } else if (Platform.OS === 'ios') {
props.style = [styles.rctSwitchIOS, this.props.style]; props.style = [styles.rctSwitchIOS, this.props.style];
} }
return ( return (
<RCTSwitch <RCTSwitch
{...props} {...props}
/* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This ref={ref => {
* comment suppresses an error when upgrading Flow's support for React. /* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This
* To see the error delete this comment and run Flow. */ * comment suppresses an error when upgrading Flow's support for React.
ref={(ref) => { this._rctSwitch = ref; }} * To see the error delete this comment and run Flow. */
this._rctSwitch = ref;
}}
onChange={this._onChange} onChange={this._onChange}
/> />
); );
@ -134,7 +141,7 @@ const styles = StyleSheet.create({
rctSwitchIOS: { rctSwitchIOS: {
height: 31, height: 31,
width: 51, width: 51,
} },
}); });
if (Platform.OS === 'android') { if (Platform.OS === 'android') {
@ -144,13 +151,13 @@ if (Platform.OS === 'android') {
on: true, on: true,
enabled: true, enabled: true,
trackTintColor: true, trackTintColor: true,
} },
}); });
} else { } else {
var RCTSwitch = requireNativeComponent('RCTSwitch', Switch, { var RCTSwitch = requireNativeComponent('RCTSwitch', Switch, {
nativeOnly: { nativeOnly: {
onChange: true onChange: true,
} },
}); });
} }

View File

@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
@ -29,7 +30,7 @@ class DummyTabBarIOS extends React.Component<$FlowFixMeProps> {
const styles = StyleSheet.create({ const styles = StyleSheet.create({
tabGroup: { tabGroup: {
flex: 1, flex: 1,
} },
}); });
module.exports = DummyTabBarIOS; module.exports = DummyTabBarIOS;

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const ColorPropType = require('ColorPropType'); const ColorPropType = require('ColorPropType');
@ -20,17 +22,19 @@ const requireNativeComponent = require('requireNativeComponent');
import type {DangerouslyImpreciseStyleProp} from 'StyleSheet'; import type {DangerouslyImpreciseStyleProp} from 'StyleSheet';
import type {ViewProps} from 'ViewPropTypes'; import type {ViewProps} from 'ViewPropTypes';
class TabBarIOS extends React.Component<ViewProps & { class TabBarIOS extends React.Component<
style?: DangerouslyImpreciseStyleProp, ViewProps & {
unselectedTintColor?: string, style?: DangerouslyImpreciseStyleProp,
tintColor?: string, unselectedTintColor?: string,
unselectedItemTintColor?: string, tintColor?: string,
barTintColor?: string, unselectedItemTintColor?: string,
barStyle?: 'default' | 'black', barTintColor?: string,
translucent?: boolean, barStyle?: 'default' | 'black',
itemPositioning?: 'fill' | 'center' | 'auto', translucent?: boolean,
children: React.Node, itemPositioning?: 'fill' | 'center' | 'auto',
}> { children: React.Node,
},
> {
static Item = TabBarItemIOS; static Item = TabBarItemIOS;
static propTypes = { static propTypes = {
@ -94,7 +98,7 @@ class TabBarIOS extends React.Component<ViewProps & {
const styles = StyleSheet.create({ const styles = StyleSheet.create({
tabGroup: { tabGroup: {
flex: 1, flex: 1,
} },
}); });
const RCTTabBar = requireNativeComponent('RCTTabBar', TabBarIOS); const RCTTabBar = requireNativeComponent('RCTTabBar', TabBarIOS);

View File

@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
*/ */
'use strict'; 'use strict';
@ -18,9 +19,7 @@ class DummyTab extends React.Component {
return <View />; return <View />;
} }
return ( return (
<View style={[this.props.style, styles.tab]}> <View style={[this.props.style, styles.tab]}>{this.props.children}</View>
{this.props.children}
</View>
); );
} }
} }
@ -35,7 +34,7 @@ const styles = StyleSheet.create({
left: 0, left: 0,
borderColor: 'red', borderColor: 'red',
borderWidth: 1, borderWidth: 1,
} },
}); });
module.exports = DummyTab; module.exports = DummyTab;

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @noflow * @noflow
*/ */
'use strict'; 'use strict';
const ColorPropType = require('ColorPropType'); const ColorPropType = require('ColorPropType');
@ -26,10 +28,7 @@ class TabBarItemIOS extends React.Component {
/** /**
* Little red bubble that sits at the top right of the icon. * Little red bubble that sits at the top right of the icon.
*/ */
badge: PropTypes.oneOfType([ badge: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
PropTypes.string,
PropTypes.number,
]),
/** /**
* Background color for the badge. Available since iOS 10. * Background color for the badge. Available since iOS 10.
*/ */
@ -105,7 +104,7 @@ class TabBarItemIOS extends React.Component {
} }
} }
UNSAFE_componentWillReceiveProps(nextProps: { selected?: boolean }) { UNSAFE_componentWillReceiveProps(nextProps: {selected?: boolean}) {
if (this.state.hasBeenSelected || nextProps.selected) { if (this.state.hasBeenSelected || nextProps.selected) {
this.setState({hasBeenSelected: true}); this.setState({hasBeenSelected: true});
} }
@ -117,18 +116,17 @@ class TabBarItemIOS extends React.Component {
// if the tab has already been shown once, always continue to show it so we // if the tab has already been shown once, always continue to show it so we
// preserve state between tab transitions // preserve state between tab transitions
if (this.state.hasBeenSelected) { if (this.state.hasBeenSelected) {
var tabContents = var tabContents = (
<StaticContainer shouldUpdate={this.props.selected}> <StaticContainer shouldUpdate={this.props.selected}>
{children} {children}
</StaticContainer>; </StaticContainer>
);
} else { } else {
var tabContents = <View />; var tabContents = <View />;
} }
return ( return (
<RCTTabBarItem <RCTTabBarItem {...props} style={[styles.tab, style]}>
{...props}
style={[styles.tab, style]}>
{tabContents} {tabContents}
</RCTTabBarItem> </RCTTabBarItem>
); );
@ -142,7 +140,7 @@ const styles = StyleSheet.create({
right: 0, right: 0,
bottom: 0, bottom: 0,
left: 0, left: 0,
} },
}); });
const RCTTabBarItem = requireNativeComponent('RCTTabBarItem', TabBarItemIOS); const RCTTabBarItem = requireNativeComponent('RCTTabBarItem', TabBarItemIOS);

View File

@ -4,12 +4,15 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @flow
* *
* This class is responsible for coordinating the "focused" * This class is responsible for coordinating the "focused"
* state for TextInputs. All calls relating to the keyboard * state for TextInputs. All calls relating to the keyboard
* should be funneled through here * should be funneled through here
*
* @format
* @flow
*/ */
'use strict'; 'use strict';
const Platform = require('Platform'); const Platform = require('Platform');
@ -18,7 +21,7 @@ const UIManager = require('UIManager');
const inputs = new Set(); const inputs = new Set();
const TextInputState = { const TextInputState = {
/** /**
* Internal state * Internal state
*/ */
_currentlyFocusedID: (null: ?number), _currentlyFocusedID: (null: ?number),
@ -45,7 +48,7 @@ const TextInputState = {
UIManager.dispatchViewManagerCommand( UIManager.dispatchViewManagerCommand(
textFieldID, textFieldID,
UIManager.AndroidTextInput.Commands.focusTextInput, UIManager.AndroidTextInput.Commands.focusTextInput,
null null,
); );
} }
} }
@ -65,7 +68,7 @@ const TextInputState = {
UIManager.dispatchViewManagerCommand( UIManager.dispatchViewManagerCommand(
textFieldID, textFieldID,
UIManager.AndroidTextInput.Commands.blurTextInput, UIManager.AndroidTextInput.Commands.blurTextInput,
null null,
); );
} }
} }

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const TimePickerModule = require('NativeModules').TimePickerAndroid; const TimePickerModule = require('NativeModules').TimePickerAndroid;
@ -31,7 +33,6 @@ const TimePickerModule = require('NativeModules').TimePickerAndroid;
* ``` * ```
*/ */
class TimePickerAndroid { class TimePickerAndroid {
/** /**
* Opens the standard Android time picker dialog. * Opens the standard Android time picker dialog.
* *
@ -58,11 +59,15 @@ class TimePickerAndroid {
/** /**
* A time has been selected. * A time has been selected.
*/ */
static get timeSetAction() { return 'timeSetAction'; } static get timeSetAction() {
return 'timeSetAction';
}
/** /**
* The dialog has been dismissed. * The dialog has been dismissed.
*/ */
static get dismissedAction() { return 'dismissedAction'; } static get dismissedAction() {
return 'dismissedAction';
}
} }
module.exports = TimePickerAndroid; module.exports = TimePickerAndroid;

View File

@ -4,14 +4,16 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const TimePickerAndroid = { const TimePickerAndroid = {
async open(options: Object): Promise<Object> { async open(options: Object): Promise<Object> {
return Promise.reject({ return Promise.reject({
message: 'TimePickerAndroid is not supported on this platform.' message: 'TimePickerAndroid is not supported on this platform.',
}); });
}, },
}; };

View File

@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
@ -33,7 +34,6 @@ const RCTToastAndroid = require('NativeModules').ToastAndroid;
*/ */
const ToastAndroid = { const ToastAndroid = {
// Toast duration constants // Toast duration constants
SHORT: RCTToastAndroid.SHORT, SHORT: RCTToastAndroid.SHORT,
LONG: RCTToastAndroid.LONG, LONG: RCTToastAndroid.LONG,
@ -43,14 +43,11 @@ const ToastAndroid = {
BOTTOM: RCTToastAndroid.BOTTOM, BOTTOM: RCTToastAndroid.BOTTOM,
CENTER: RCTToastAndroid.CENTER, CENTER: RCTToastAndroid.CENTER,
show: function ( show: function(message: string, duration: number): void {
message: string,
duration: number
): void {
RCTToastAndroid.show(message, duration); RCTToastAndroid.show(message, duration);
}, },
showWithGravity: function ( showWithGravity: function(
message: string, message: string,
duration: number, duration: number,
gravity: number, gravity: number,
@ -58,14 +55,20 @@ const ToastAndroid = {
RCTToastAndroid.showWithGravity(message, duration, gravity); RCTToastAndroid.showWithGravity(message, duration, gravity);
}, },
showWithGravityAndOffset: function ( showWithGravityAndOffset: function(
message: string, message: string,
duration: number, duration: number,
gravity: number, gravity: number,
xOffset: number, xOffset: number,
yOffset: number, yOffset: number,
): void { ): void {
RCTToastAndroid.showWithGravityAndOffset(message, duration, gravity, xOffset, yOffset); RCTToastAndroid.showWithGravityAndOffset(
message,
duration,
gravity,
xOffset,
yOffset,
);
}, },
}; };

View File

@ -4,21 +4,18 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @noflow * @noflow
*/ */
'use strict'; 'use strict';
const warning = require('fbjs/lib/warning'); const warning = require('fbjs/lib/warning');
const ToastAndroid = { const ToastAndroid = {
show: function(message: string, duration: number): void {
show: function (
message: string,
duration: number
): void {
warning(false, 'ToastAndroid is not supported on this platform.'); warning(false, 'ToastAndroid is not supported on this platform.');
}, },
}; };
module.exports = ToastAndroid; module.exports = ToastAndroid;

View File

@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
*/ */
'use strict'; 'use strict';
@ -82,12 +83,14 @@ const ToolbarAndroid = createReactClass({
* `ifRoom` or `never` * `ifRoom` or `never`
* * `showWithText`: boolean, whether to show text alongside the icon or not * * `showWithText`: boolean, whether to show text alongside the icon or not
*/ */
actions: PropTypes.arrayOf(PropTypes.shape({ actions: PropTypes.arrayOf(
title: PropTypes.string.isRequired, PropTypes.shape({
icon: optionalImageSource, title: PropTypes.string.isRequired,
show: PropTypes.oneOf(['always', 'ifRoom', 'never']), icon: optionalImageSource,
showWithText: PropTypes.bool show: PropTypes.oneOf(['always', 'ifRoom', 'never']),
})), showWithText: PropTypes.bool,
}),
),
/** /**
* Sets the toolbar logo. * Sets the toolbar logo.
*/ */
@ -183,7 +186,8 @@ const ToolbarAndroid = createReactClass({
action.icon = resolveAssetSource(action.icon); action.icon = resolveAssetSource(action.icon);
} }
if (action.show) { if (action.show) {
action.show = UIManager.ToolbarAndroid.Constants.ShowAsAction[action.show]; action.show =
UIManager.ToolbarAndroid.Constants.ShowAsAction[action.show];
} }
nativeActions.push(action); nativeActions.push(action);
} }
@ -206,7 +210,7 @@ const ToolbarAndroid = createReactClass({
const NativeToolbar = requireNativeComponent('ToolbarAndroid', ToolbarAndroid, { const NativeToolbar = requireNativeComponent('ToolbarAndroid', ToolbarAndroid, {
nativeOnly: { nativeOnly: {
nativeActions: true, nativeActions: true,
} },
}); });
module.exports = ToolbarAndroid; module.exports = ToolbarAndroid;

View File

@ -4,7 +4,9 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
*/ */
'use strict'; 'use strict';
module.exports = require('UnimplementedView'); module.exports = require('UnimplementedView');

View File

@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
*/ */
'use strict'; 'use strict';
@ -36,7 +37,7 @@ BoundingDimensions.prototype.destructor = function() {
BoundingDimensions.getPooledFromElement = function(element) { BoundingDimensions.getPooledFromElement = function(element) {
return BoundingDimensions.getPooled( return BoundingDimensions.getPooled(
element.offsetWidth, element.offsetWidth,
element.offsetHeight element.offsetHeight,
); );
}; };

View File

@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */

View File

@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
*/ */
'use strict'; 'use strict';

View File

@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
*/ */
'use strict'; 'use strict';
@ -110,14 +111,14 @@ const normalizeColor = require('normalizeColor');
* Touchable states. * Touchable states.
*/ */
const States = keyMirror({ const States = keyMirror({
NOT_RESPONDER: null, // Not the responder NOT_RESPONDER: null, // Not the responder
RESPONDER_INACTIVE_PRESS_IN: null, // Responder, inactive, in the `PressRect` RESPONDER_INACTIVE_PRESS_IN: null, // Responder, inactive, in the `PressRect`
RESPONDER_INACTIVE_PRESS_OUT: null, // Responder, inactive, out of `PressRect` RESPONDER_INACTIVE_PRESS_OUT: null, // Responder, inactive, out of `PressRect`
RESPONDER_ACTIVE_PRESS_IN: null, // Responder, active, in the `PressRect` RESPONDER_ACTIVE_PRESS_IN: null, // Responder, active, in the `PressRect`
RESPONDER_ACTIVE_PRESS_OUT: null, // Responder, active, out of `PressRect` RESPONDER_ACTIVE_PRESS_OUT: null, // Responder, active, out of `PressRect`
RESPONDER_ACTIVE_LONG_PRESS_IN: null, // Responder, active, in the `PressRect`, after long press threshold RESPONDER_ACTIVE_LONG_PRESS_IN: null, // Responder, active, in the `PressRect`, after long press threshold
RESPONDER_ACTIVE_LONG_PRESS_OUT: null, // Responder, active, out of `PressRect`, after long press threshold RESPONDER_ACTIVE_LONG_PRESS_OUT: null, // Responder, active, out of `PressRect`, after long press threshold
ERROR: null ERROR: null,
}); });
/** /**
@ -125,7 +126,7 @@ const States = keyMirror({
*/ */
const IsActive = { const IsActive = {
RESPONDER_ACTIVE_PRESS_OUT: true, RESPONDER_ACTIVE_PRESS_OUT: true,
RESPONDER_ACTIVE_PRESS_IN: true RESPONDER_ACTIVE_PRESS_IN: true,
}; };
/** /**
@ -230,7 +231,7 @@ const Transitions = {
ENTER_PRESS_RECT: States.NOT_RESPONDER, ENTER_PRESS_RECT: States.NOT_RESPONDER,
LEAVE_PRESS_RECT: States.NOT_RESPONDER, LEAVE_PRESS_RECT: States.NOT_RESPONDER,
LONG_PRESS_DETECTED: States.NOT_RESPONDER, LONG_PRESS_DETECTED: States.NOT_RESPONDER,
} },
}; };
// ==== Typical Constants for integrating into UI components ==== // ==== Typical Constants for integrating into UI components ====
@ -324,11 +325,15 @@ const TouchableMixin = {
evt.dispatchConfig = {}; evt.dispatchConfig = {};
if (myTag === evt.tag) { if (myTag === evt.tag) {
if (evt.eventType === 'focus') { if (evt.eventType === 'focus') {
cmp.touchableHandleActivePressIn && cmp.touchableHandleActivePressIn(evt); cmp.touchableHandleActivePressIn &&
cmp.touchableHandleActivePressIn(evt);
} else if (evt.eventType === 'blur') { } else if (evt.eventType === 'blur') {
cmp.touchableHandleActivePressOut && cmp.touchableHandleActivePressOut(evt); cmp.touchableHandleActivePressOut &&
cmp.touchableHandleActivePressOut(evt);
} else if (evt.eventType === 'select') { } else if (evt.eventType === 'select') {
cmp.touchableHandlePress && !cmp.props.disabled && cmp.touchableHandlePress(evt); cmp.touchableHandlePress &&
!cmp.props.disabled &&
cmp.touchableHandlePress(evt);
} }
} }
}); });
@ -356,7 +361,7 @@ const TouchableMixin = {
*/ */
touchableGetInitialState: function() { touchableGetInitialState: function() {
return { return {
touchable: {touchState: undefined, responderID: null} touchable: {touchState: undefined, responderID: null},
}; };
}, },
@ -378,7 +383,7 @@ const TouchableMixin = {
/** /**
* Return true to cancel press on long press. * Return true to cancel press on long press.
*/ */
touchableLongPressCancelsPress: function () { touchableLongPressCancelsPress: function() {
return true; return true;
}, },
@ -401,25 +406,27 @@ const TouchableMixin = {
this.state.touchable.responderID = dispatchID; this.state.touchable.responderID = dispatchID;
this._receiveSignal(Signals.RESPONDER_GRANT, e); this._receiveSignal(Signals.RESPONDER_GRANT, e);
let delayMS = let delayMS =
this.touchableGetHighlightDelayMS !== undefined ? this.touchableGetHighlightDelayMS !== undefined
Math.max(this.touchableGetHighlightDelayMS(), 0) : HIGHLIGHT_DELAY_MS; ? Math.max(this.touchableGetHighlightDelayMS(), 0)
: HIGHLIGHT_DELAY_MS;
delayMS = isNaN(delayMS) ? HIGHLIGHT_DELAY_MS : delayMS; delayMS = isNaN(delayMS) ? HIGHLIGHT_DELAY_MS : delayMS;
if (delayMS !== 0) { if (delayMS !== 0) {
this.touchableDelayTimeout = setTimeout( this.touchableDelayTimeout = setTimeout(
this._handleDelay.bind(this, e), this._handleDelay.bind(this, e),
delayMS delayMS,
); );
} else { } else {
this._handleDelay(e); this._handleDelay(e);
} }
let longDelayMS = let longDelayMS =
this.touchableGetLongPressDelayMS !== undefined ? this.touchableGetLongPressDelayMS !== undefined
Math.max(this.touchableGetLongPressDelayMS(), 10) : LONG_PRESS_DELAY_MS; ? Math.max(this.touchableGetLongPressDelayMS(), 10)
: LONG_PRESS_DELAY_MS;
longDelayMS = isNaN(longDelayMS) ? LONG_PRESS_DELAY_MS : longDelayMS; longDelayMS = isNaN(longDelayMS) ? LONG_PRESS_DELAY_MS : longDelayMS;
this.longPressDelayTimeout = setTimeout( this.longPressDelayTimeout = setTimeout(
this._handleLongDelay.bind(this, e), this._handleLongDelay.bind(this, e),
longDelayMS + delayMS longDelayMS + delayMS,
); );
}, },
@ -443,7 +450,9 @@ const TouchableMixin = {
touchableHandleResponderMove: function(e) { touchableHandleResponderMove: function(e) {
// Not enough time elapsed yet, wait for highlight - // Not enough time elapsed yet, wait for highlight -
// this is just a perf optimization. // this is just a perf optimization.
if (this.state.touchable.touchState === States.RESPONDER_INACTIVE_PRESS_IN) { if (
this.state.touchable.touchState === States.RESPONDER_INACTIVE_PRESS_IN
) {
return; return;
} }
@ -454,21 +463,23 @@ const TouchableMixin = {
const positionOnActivate = this.state.touchable.positionOnActivate; const positionOnActivate = this.state.touchable.positionOnActivate;
const dimensionsOnActivate = this.state.touchable.dimensionsOnActivate; const dimensionsOnActivate = this.state.touchable.dimensionsOnActivate;
const pressRectOffset = this.touchableGetPressRectOffset ? const pressRectOffset = this.touchableGetPressRectOffset
this.touchableGetPressRectOffset() : { ? this.touchableGetPressRectOffset()
left: PRESS_EXPAND_PX, : {
right: PRESS_EXPAND_PX, left: PRESS_EXPAND_PX,
top: PRESS_EXPAND_PX, right: PRESS_EXPAND_PX,
bottom: PRESS_EXPAND_PX top: PRESS_EXPAND_PX,
}; bottom: PRESS_EXPAND_PX,
};
let pressExpandLeft = pressRectOffset.left; let pressExpandLeft = pressRectOffset.left;
let pressExpandTop = pressRectOffset.top; let pressExpandTop = pressRectOffset.top;
let pressExpandRight = pressRectOffset.right; let pressExpandRight = pressRectOffset.right;
let pressExpandBottom = pressRectOffset.bottom; let pressExpandBottom = pressRectOffset.bottom;
const hitSlop = this.touchableGetHitSlop ? const hitSlop = this.touchableGetHitSlop
this.touchableGetHitSlop() : null; ? this.touchableGetHitSlop()
: null;
if (hitSlop) { if (hitSlop) {
pressExpandLeft += hitSlop.left; pressExpandLeft += hitSlop.left;
@ -482,21 +493,26 @@ const TouchableMixin = {
const pageY = touch && touch.pageY; const pageY = touch && touch.pageY;
if (this.pressInLocation) { if (this.pressInLocation) {
const movedDistance = this._getDistanceBetweenPoints(pageX, pageY, this.pressInLocation.pageX, this.pressInLocation.pageY); const movedDistance = this._getDistanceBetweenPoints(
pageX,
pageY,
this.pressInLocation.pageX,
this.pressInLocation.pageY,
);
if (movedDistance > LONG_PRESS_ALLOWED_MOVEMENT) { if (movedDistance > LONG_PRESS_ALLOWED_MOVEMENT) {
this._cancelLongPressDelayTimeout(); this._cancelLongPressDelayTimeout();
} }
} }
const isTouchWithinActive = const isTouchWithinActive =
pageX > positionOnActivate.left - pressExpandLeft && pageX > positionOnActivate.left - pressExpandLeft &&
pageY > positionOnActivate.top - pressExpandTop && pageY > positionOnActivate.top - pressExpandTop &&
pageX < pageX <
positionOnActivate.left + positionOnActivate.left +
dimensionsOnActivate.width + dimensionsOnActivate.width +
pressExpandRight && pressExpandRight &&
pageY < pageY <
positionOnActivate.top + positionOnActivate.top +
dimensionsOnActivate.height + dimensionsOnActivate.height +
pressExpandBottom; pressExpandBottom;
if (isTouchWithinActive) { if (isTouchWithinActive) {
@ -574,8 +590,6 @@ const TouchableMixin = {
* touchableGetPressRectOffset: function * touchableGetPressRectOffset: function
*/ */
// ==== Internal Logic ==== // ==== Internal Logic ====
/** /**
@ -608,8 +622,14 @@ const TouchableMixin = {
Position.release(this.state.touchable.positionOnActivate); Position.release(this.state.touchable.positionOnActivate);
this.state.touchable.dimensionsOnActivate && this.state.touchable.dimensionsOnActivate &&
BoundingDimensions.release(this.state.touchable.dimensionsOnActivate); BoundingDimensions.release(this.state.touchable.dimensionsOnActivate);
this.state.touchable.positionOnActivate = Position.getPooled(globalX, globalY); this.state.touchable.positionOnActivate = Position.getPooled(
this.state.touchable.dimensionsOnActivate = BoundingDimensions.getPooled(w, h); globalX,
globalY,
);
this.state.touchable.dimensionsOnActivate = BoundingDimensions.getPooled(
w,
h,
);
}, },
_handleDelay: function(e) { _handleDelay: function(e) {
@ -620,11 +640,18 @@ const TouchableMixin = {
_handleLongDelay: function(e) { _handleLongDelay: function(e) {
this.longPressDelayTimeout = null; this.longPressDelayTimeout = null;
const curState = this.state.touchable.touchState; const curState = this.state.touchable.touchState;
if (curState !== States.RESPONDER_ACTIVE_PRESS_IN && if (
curState !== States.RESPONDER_ACTIVE_LONG_PRESS_IN) { curState !== States.RESPONDER_ACTIVE_PRESS_IN &&
console.error('Attempted to transition from state `' + curState + '` to `' + curState !== States.RESPONDER_ACTIVE_LONG_PRESS_IN
States.RESPONDER_ACTIVE_LONG_PRESS_IN + '`, which is not supported. This is ' + ) {
'most likely due to `Touchable.longPressDelayTimeout` not being cancelled.'); console.error(
'Attempted to transition from state `' +
curState +
'` to `' +
States.RESPONDER_ACTIVE_LONG_PRESS_IN +
'`, which is not supported. This is ' +
'most likely due to `Touchable.longPressDelayTimeout` not being cancelled.',
);
} else { } else {
this._receiveSignal(Signals.LONG_PRESS_DETECTED, e); this._receiveSignal(Signals.LONG_PRESS_DETECTED, e);
} }
@ -647,14 +674,24 @@ const TouchableMixin = {
} }
if (!nextState) { if (!nextState) {
throw new Error( throw new Error(
'Unrecognized signal `' + signal + '` or state `' + curState + 'Unrecognized signal `' +
'` for Touchable responder `' + responderID + '`' signal +
'` or state `' +
curState +
'` for Touchable responder `' +
responderID +
'`',
); );
} }
if (nextState === States.ERROR) { if (nextState === States.ERROR) {
throw new Error( throw new Error(
'Touchable cannot transition from `' + curState + '` to `' + signal + 'Touchable cannot transition from `' +
'` for responder `' + responderID + '`' curState +
'` to `' +
signal +
'` for responder `' +
responderID +
'`',
); );
} }
if (curState !== nextState) { if (curState !== nextState) {
@ -663,14 +700,16 @@ const TouchableMixin = {
} }
}, },
_cancelLongPressDelayTimeout: function () { _cancelLongPressDelayTimeout: function() {
this.longPressDelayTimeout && clearTimeout(this.longPressDelayTimeout); this.longPressDelayTimeout && clearTimeout(this.longPressDelayTimeout);
this.longPressDelayTimeout = null; this.longPressDelayTimeout = null;
}, },
_isHighlight: function (state) { _isHighlight: function(state) {
return state === States.RESPONDER_ACTIVE_PRESS_IN || return (
state === States.RESPONDER_ACTIVE_LONG_PRESS_IN; state === States.RESPONDER_ACTIVE_PRESS_IN ||
state === States.RESPONDER_ACTIVE_LONG_PRESS_IN
);
}, },
_savePressInLocation: function(e) { _savePressInLocation: function(e) {
@ -682,7 +721,7 @@ const TouchableMixin = {
this.pressInLocation = {pageX, pageY, locationX, locationY}; this.pressInLocation = {pageX, pageY, locationX, locationY};
}, },
_getDistanceBetweenPoints: function (aX, aY, bX, bY) { _getDistanceBetweenPoints: function(aX, aY, bX, bY) {
const deltaX = aX - bX; const deltaX = aX - bX;
const deltaY = aY - bY; const deltaY = aY - bY;
return Math.sqrt(deltaX * deltaX + deltaY * deltaY); return Math.sqrt(deltaX * deltaX + deltaY * deltaY);
@ -728,12 +767,11 @@ const TouchableMixin = {
if (IsPressingIn[curState] && signal === Signals.RESPONDER_RELEASE) { if (IsPressingIn[curState] && signal === Signals.RESPONDER_RELEASE) {
const hasLongPressHandler = !!this.props.onLongPress; const hasLongPressHandler = !!this.props.onLongPress;
const pressIsLongButStillCallOnPress = const pressIsLongButStillCallOnPress =
IsLongPressingIn[curState] && ( // We *are* long pressing.. IsLongPressingIn[curState] && // We *are* long pressing.. // But either has no long handler
(// But either has no long handler (!hasLongPressHandler || !this.touchableLongPressCancelsPress()); // or we're told to ignore it.
!hasLongPressHandler || !this.touchableLongPressCancelsPress()) // or we're told to ignore it.
);
const shouldInvokePress = !IsLongPressingIn[curState] || pressIsLongButStillCallOnPress; const shouldInvokePress =
!IsLongPressingIn[curState] || pressIsLongButStillCallOnPress;
if (shouldInvokePress && this.touchableHandlePress) { if (shouldInvokePress && this.touchableHandlePress) {
if (!newIsHighlight && !curIsHighlight) { if (!newIsHighlight && !curIsHighlight) {
// we never highlighted because of delay, but we should highlight now // we never highlighted because of delay, but we should highlight now
@ -750,11 +788,11 @@ const TouchableMixin = {
this.touchableDelayTimeout && clearTimeout(this.touchableDelayTimeout); this.touchableDelayTimeout && clearTimeout(this.touchableDelayTimeout);
this.touchableDelayTimeout = null; this.touchableDelayTimeout = null;
}, },
_playTouchSound: function() { _playTouchSound: function() {
UIManager.playTouchSound(); UIManager.playTouchSound();
}, },
_startHighlight: function(e) { _startHighlight: function(e) {
this._savePressInLocation(e); this._savePressInLocation(e);
this.touchableHandleActivePressIn && this.touchableHandleActivePressIn(e); this.touchableHandleActivePressIn && this.touchableHandleActivePressIn(e);
@ -762,7 +800,10 @@ const TouchableMixin = {
_endHighlight: function(e) { _endHighlight: function(e) {
if (this.touchableHandleActivePressOut) { if (this.touchableHandleActivePressOut) {
if (this.touchableGetPressOutDelayMS && this.touchableGetPressOutDelayMS()) { if (
this.touchableGetPressOutDelayMS &&
this.touchableGetPressOutDelayMS()
) {
this.pressOutDelayTimeout = setTimeout(() => { this.pressOutDelayTimeout = setTimeout(() => {
this.touchableHandleActivePressOut(e); this.touchableHandleActivePressOut(e);
}, this.touchableGetPressOutDelayMS()); }, this.touchableGetPressOutDelayMS());
@ -771,7 +812,6 @@ const TouchableMixin = {
} }
} }
}, },
}; };
const Touchable = { const Touchable = {
@ -785,14 +825,17 @@ const Touchable = {
return null; return null;
} }
if (!__DEV__) { if (!__DEV__) {
throw Error('Touchable.TOUCH_TARGET_DEBUG should not be enabled in prod!'); throw Error(
'Touchable.TOUCH_TARGET_DEBUG should not be enabled in prod!',
);
} }
const debugHitSlopStyle = {}; const debugHitSlopStyle = {};
hitSlop = hitSlop || {top: 0, bottom: 0, left: 0, right: 0}; hitSlop = hitSlop || {top: 0, bottom: 0, left: 0, right: 0};
for (const key in hitSlop) { for (const key in hitSlop) {
debugHitSlopStyle[key] = -hitSlop[key]; debugHitSlopStyle[key] = -hitSlop[key];
} }
const hexColor = '#' + ('00000000' + normalizeColor(color).toString(16)).substr(-8); const hexColor =
'#' + ('00000000' + normalizeColor(color).toString(16)).substr(-8);
return ( return (
<View <View
pointerEvents="none" pointerEvents="none"
@ -802,11 +845,11 @@ const Touchable = {
borderWidth: 1, borderWidth: 1,
borderStyle: 'dashed', borderStyle: 'dashed',
backgroundColor: hexColor.slice(0, -2) + '0F', // Less opaque backgroundColor: hexColor.slice(0, -2) + '0F', // Less opaque
...debugHitSlopStyle ...debugHitSlopStyle,
}} }}
/> />
); );
} },
}; };
module.exports = Touchable; module.exports = Touchable;

View File

@ -4,7 +4,9 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
*/ */
'use strict'; 'use strict';
const Platform = require('Platform'); const Platform = require('Platform');
@ -112,7 +114,10 @@ const TouchableNativeFeedback = createReactClass({
* Available on android API level 21+. * Available on android API level 21+.
*/ */
SelectableBackgroundBorderless: function() { SelectableBackgroundBorderless: function() {
return {type: 'ThemeAttrAndroid', attribute: 'selectableItemBackgroundBorderless'}; return {
type: 'ThemeAttrAndroid',
attribute: 'selectableItemBackgroundBorderless',
};
}, },
/** /**
* Creates an object that represents ripple drawable with specified color (as a * Creates an object that represents ripple drawable with specified color (as a
@ -125,12 +130,16 @@ const TouchableNativeFeedback = createReactClass({
* @param borderless If the ripple can render outside it's bounds * @param borderless If the ripple can render outside it's bounds
*/ */
Ripple: function(color: string, borderless: boolean) { Ripple: function(color: string, borderless: boolean) {
return {type: 'RippleAndroid', color: processColor(color), borderless: borderless}; return {
type: 'RippleAndroid',
color: processColor(color),
borderless: borderless,
};
}, },
canUseNativeForeground: function() { canUseNativeForeground: function() {
return Platform.OS === 'android' && Platform.Version >= 23; return Platform.OS === 'android' && Platform.Version >= 23;
} },
}, },
mixins: [Touchable.Mixin], mixins: [Touchable.Mixin],
@ -161,7 +170,10 @@ const TouchableNativeFeedback = createReactClass({
this.props.onPressIn && this.props.onPressIn(e); this.props.onPressIn && this.props.onPressIn(e);
this._dispatchPressedStateChange(true); this._dispatchPressedStateChange(true);
if (this.pressInLocation) { if (this.pressInLocation) {
this._dispatchHotspotUpdate(this.pressInLocation.locationX, this.pressInLocation.locationY); this._dispatchHotspotUpdate(
this.pressInLocation.locationX,
this.pressInLocation.locationY,
);
} }
}, },
@ -201,14 +213,17 @@ const TouchableNativeFeedback = createReactClass({
_handleResponderMove: function(e) { _handleResponderMove: function(e) {
this.touchableHandleResponderMove(e); this.touchableHandleResponderMove(e);
this._dispatchHotspotUpdate(e.nativeEvent.locationX, e.nativeEvent.locationY); this._dispatchHotspotUpdate(
e.nativeEvent.locationX,
e.nativeEvent.locationY,
);
}, },
_dispatchHotspotUpdate: function(destX, destY) { _dispatchHotspotUpdate: function(destX, destY) {
UIManager.dispatchViewManagerCommand( UIManager.dispatchViewManagerCommand(
ReactNative.findNodeHandle(this), ReactNative.findNodeHandle(this),
UIManager.RCTView.Commands.hotspotUpdate, UIManager.RCTView.Commands.hotspotUpdate,
[destX || 0, destY || 0] [destX || 0, destY || 0],
); );
}, },
@ -216,7 +231,7 @@ const TouchableNativeFeedback = createReactClass({
UIManager.dispatchViewManagerCommand( UIManager.dispatchViewManagerCommand(
ReactNative.findNodeHandle(this), ReactNative.findNodeHandle(this),
UIManager.RCTView.Commands.setPressed, UIManager.RCTView.Commands.setPressed,
[pressed] [pressed],
); );
}, },
@ -227,16 +242,26 @@ const TouchableNativeFeedback = createReactClass({
if (!Array.isArray(children)) { if (!Array.isArray(children)) {
children = [children]; children = [children];
} }
children.push(Touchable.renderDebugView({color: 'brown', hitSlop: this.props.hitSlop})); children.push(
Touchable.renderDebugView({
color: 'brown',
hitSlop: this.props.hitSlop,
}),
);
} }
if (this.props.useForeground && !TouchableNativeFeedback.canUseNativeForeground()) { if (
this.props.useForeground &&
!TouchableNativeFeedback.canUseNativeForeground()
) {
console.warn( console.warn(
'Requested foreground ripple, but it is not available on this version of Android. ' + 'Requested foreground ripple, but it is not available on this version of Android. ' +
'Consider calling TouchableNativeFeedback.canUseNativeForeground() and using a different ' + 'Consider calling TouchableNativeFeedback.canUseNativeForeground() and using a different ' +
'Touchable if the result is false.'); 'Touchable if the result is false.',
);
} }
const drawableProp = const drawableProp =
this.props.useForeground && TouchableNativeFeedback.canUseNativeForeground() this.props.useForeground &&
TouchableNativeFeedback.canUseNativeForeground()
? 'nativeForegroundAndroid' ? 'nativeForegroundAndroid'
: 'nativeBackgroundAndroid'; : 'nativeBackgroundAndroid';
const childProps = { const childProps = {
@ -253,7 +278,8 @@ const TouchableNativeFeedback = createReactClass({
isTVSelectable: true, isTVSelectable: true,
hasTVPreferredFocus: this.props.hasTVPreferredFocus, hasTVPreferredFocus: this.props.hasTVPreferredFocus,
onStartShouldSetResponder: this.touchableHandleStartShouldSetResponder, onStartShouldSetResponder: this.touchableHandleStartShouldSetResponder,
onResponderTerminationRequest: this.touchableHandleResponderTerminationRequest, onResponderTerminationRequest: this
.touchableHandleResponderTerminationRequest,
onResponderGrant: this.touchableHandleResponderGrant, onResponderGrant: this.touchableHandleResponderGrant,
onResponderMove: this._handleResponderMove, onResponderMove: this._handleResponderMove,
onResponderRelease: this.touchableHandleResponderRelease, onResponderRelease: this.touchableHandleResponderRelease,
@ -263,11 +289,8 @@ const TouchableNativeFeedback = createReactClass({
// We need to clone the actual element so that the ripple background drawable // We need to clone the actual element so that the ripple background drawable
// can be applied directly to the background of this element rather than to // can be applied directly to the background of this element rather than to
// a wrapper view as done in other Touchable* // a wrapper view as done in other Touchable*
return React.cloneElement( return React.cloneElement(child, childProps);
child, },
childProps
);
}
}); });
module.exports = TouchableNativeFeedback; module.exports = TouchableNativeFeedback;

View File

@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
*/ */
'use strict'; 'use strict';
@ -22,7 +23,9 @@ class DummyTouchableNativeFeedback extends React.Component {
render() { render() {
return ( return (
<View style={[styles.container, this.props.style]}> <View style={[styles.container, this.props.style]}>
<Text style={styles.info}>TouchableNativeFeedback is not supported on this platform!</Text> <Text style={styles.info}>
TouchableNativeFeedback is not supported on this platform!
</Text>
</View> </View>
); );
} }
@ -42,7 +45,7 @@ const styles = StyleSheet.create({
info: { info: {
color: '#333333', color: '#333333',
margin: 20, margin: 20,
} },
}); });
module.exports = DummyTouchableNativeFeedback; module.exports = DummyTouchableNativeFeedback;

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @noflow * @noflow
*/ */
'use strict'; 'use strict';
// Note (avik): add @flow when Flow supports spread properties in propTypes // Note (avik): add @flow when Flow supports spread properties in propTypes
@ -167,15 +169,12 @@ const TouchableOpacity = createReactClass({
* Animate the touchable to a new opacity. * Animate the touchable to a new opacity.
*/ */
setOpacityTo: function(value: number, duration: number) { setOpacityTo: function(value: number, duration: number) {
Animated.timing( Animated.timing(this.state.anim, {
this.state.anim, toValue: value,
{ duration: duration,
toValue: value, easing: Easing.inOut(Easing.quad),
duration: duration, useNativeDriver: true,
easing: Easing.inOut(Easing.quad), }).start();
useNativeDriver: true,
}
).start();
}, },
/** /**
@ -217,8 +216,9 @@ const TouchableOpacity = createReactClass({
}, },
touchableGetLongPressDelayMS: function() { touchableGetLongPressDelayMS: function() {
return this.props.delayLongPress === 0 ? 0 : return this.props.delayLongPress === 0
this.props.delayLongPress || 500; ? 0
: this.props.delayLongPress || 500;
}, },
touchableGetPressOutDelayMS: function() { touchableGetPressOutDelayMS: function() {
@ -230,16 +230,13 @@ const TouchableOpacity = createReactClass({
}, },
_opacityInactive: function(duration: number) { _opacityInactive: function(duration: number) {
this.setOpacityTo( this.setOpacityTo(this._getChildStyleOpacityWithDefault(), duration);
this._getChildStyleOpacityWithDefault(),
duration
);
}, },
_getChildStyleOpacityWithDefault: function() { _getChildStyleOpacityWithDefault: function() {
const childStyle = flattenStyle(this.props.style) || {}; const childStyle = flattenStyle(this.props.style) || {};
return childStyle.opacity == undefined ? 1 : childStyle.opacity; return childStyle.opacity == undefined ? 1 : childStyle.opacity;
}, },
render: function() { render: function() {
return ( return (
@ -257,13 +254,18 @@ const TouchableOpacity = createReactClass({
tvParallaxProperties={this.props.tvParallaxProperties} tvParallaxProperties={this.props.tvParallaxProperties}
hitSlop={this.props.hitSlop} hitSlop={this.props.hitSlop}
onStartShouldSetResponder={this.touchableHandleStartShouldSetResponder} onStartShouldSetResponder={this.touchableHandleStartShouldSetResponder}
onResponderTerminationRequest={this.touchableHandleResponderTerminationRequest} onResponderTerminationRequest={
this.touchableHandleResponderTerminationRequest
}
onResponderGrant={this.touchableHandleResponderGrant} onResponderGrant={this.touchableHandleResponderGrant}
onResponderMove={this.touchableHandleResponderMove} onResponderMove={this.touchableHandleResponderMove}
onResponderRelease={this.touchableHandleResponderRelease} onResponderRelease={this.touchableHandleResponderRelease}
onResponderTerminate={this.touchableHandleResponderTerminate}> onResponderTerminate={this.touchableHandleResponderTerminate}>
{this.props.children} {this.props.children}
{Touchable.renderDebugView({color: 'cyan', hitSlop: this.props.hitSlop})} {Touchable.renderDebugView({
color: 'cyan',
hitSlop: this.props.hitSlop,
})}
</Animated.View> </Animated.View>
); );
}, },

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const EdgeInsetsPropType = require('EdgeInsetsPropType'); const EdgeInsetsPropType = require('EdgeInsetsPropType');
@ -46,9 +48,7 @@ const TouchableWithoutFeedback = createReactClass({
propTypes: { propTypes: {
accessible: PropTypes.bool, accessible: PropTypes.bool,
accessibilityComponentType: PropTypes.oneOf( accessibilityComponentType: PropTypes.oneOf(AccessibilityComponentTypes),
AccessibilityComponentTypes
),
accessibilityTraits: PropTypes.oneOfType([ accessibilityTraits: PropTypes.oneOfType([
PropTypes.oneOf(AccessibilityTraits), PropTypes.oneOf(AccessibilityTraits),
PropTypes.arrayOf(PropTypes.oneOf(AccessibilityTraits)), PropTypes.arrayOf(PropTypes.oneOf(AccessibilityTraits)),
@ -63,14 +63,14 @@ const TouchableWithoutFeedback = createReactClass({
*/ */
onPress: PropTypes.func, onPress: PropTypes.func,
/** /**
* Called as soon as the touchable element is pressed and invoked even before onPress. * Called as soon as the touchable element is pressed and invoked even before onPress.
* This can be useful when making network requests. * This can be useful when making network requests.
*/ */
onPressIn: PropTypes.func, onPressIn: PropTypes.func,
/** /**
* Called as soon as the touch is released even before onPress. * Called as soon as the touch is released even before onPress.
*/ */
onPressOut: PropTypes.func, onPressOut: PropTypes.func,
/** /**
* Invoked on mount and layout changes with * Invoked on mount and layout changes with
* *
@ -156,8 +156,9 @@ const TouchableWithoutFeedback = createReactClass({
}, },
touchableGetLongPressDelayMS: function(): number { touchableGetLongPressDelayMS: function(): number {
return this.props.delayLongPress === 0 ? 0 : return this.props.delayLongPress === 0
this.props.delayLongPress || 500; ? 0
: this.props.delayLongPress || 500;
}, },
touchableGetPressOutDelayMS: function(): number { touchableGetPressOutDelayMS: function(): number {
@ -172,15 +173,25 @@ const TouchableWithoutFeedback = createReactClass({
warning( warning(
!child.type || child.type.displayName !== 'Text', !child.type || child.type.displayName !== 'Text',
'TouchableWithoutFeedback does not work well with Text children. Wrap children in a View instead. See ' + 'TouchableWithoutFeedback does not work well with Text children. Wrap children in a View instead. See ' +
((child._owner && child._owner.getName && child._owner.getName()) || '<unknown>') ((child._owner && child._owner.getName && child._owner.getName()) ||
'<unknown>'),
); );
if (Touchable.TOUCH_TARGET_DEBUG && child.type && child.type.displayName === 'View') { if (
Touchable.TOUCH_TARGET_DEBUG &&
child.type &&
child.type.displayName === 'View'
) {
children = React.Children.toArray(children); children = React.Children.toArray(children);
children.push(Touchable.renderDebugView({color: 'red', hitSlop: this.props.hitSlop})); children.push(
Touchable.renderDebugView({color: 'red', hitSlop: this.props.hitSlop}),
);
} }
const style = (Touchable.TOUCH_TARGET_DEBUG && child.type && child.type.displayName === 'Text') ? const style =
[child.props.style, {color: 'red'}] : Touchable.TOUCH_TARGET_DEBUG &&
child.props.style; child.type &&
child.type.displayName === 'Text'
? [child.props.style, {color: 'red'}]
: child.props.style;
return (React: any).cloneElement(child, { return (React: any).cloneElement(child, {
accessible: this.props.accessible !== false, accessible: this.props.accessible !== false,
accessibilityLabel: this.props.accessibilityLabel, accessibilityLabel: this.props.accessibilityLabel,
@ -191,7 +202,8 @@ const TouchableWithoutFeedback = createReactClass({
onLayout: this.props.onLayout, onLayout: this.props.onLayout,
hitSlop: this.props.hitSlop, hitSlop: this.props.hitSlop,
onStartShouldSetResponder: this.touchableHandleStartShouldSetResponder, onStartShouldSetResponder: this.touchableHandleStartShouldSetResponder,
onResponderTerminationRequest: this.touchableHandleResponderTerminationRequest, onResponderTerminationRequest: this
.touchableHandleResponderTerminationRequest,
onResponderGrant: this.touchableHandleResponderGrant, onResponderGrant: this.touchableHandleResponderGrant,
onResponderMove: this.touchableHandleResponderMove, onResponderMove: this.touchableHandleResponderMove,
onResponderRelease: this.touchableHandleResponderRelease, onResponderRelease: this.touchableHandleResponderRelease,
@ -199,7 +211,7 @@ const TouchableWithoutFeedback = createReactClass({
style, style,
children, children,
}); });
} },
}); });
module.exports = TouchableWithoutFeedback; module.exports = TouchableWithoutFeedback;

View File

@ -3,7 +3,10 @@
* *
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*
* @format
*/ */
'use strict'; 'use strict';
module.exports = () => true; module.exports = () => true;

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @emails oncall+react_native * @emails oncall+react_native
*/ */
'use strict'; 'use strict';
const React = require('React'); const React = require('React');
@ -18,7 +20,7 @@ describe('TouchableHighlight', () => {
const instance = ReactTestRenderer.create( const instance = ReactTestRenderer.create(
<TouchableHighlight style={{}}> <TouchableHighlight style={{}}>
<Text>Touchable</Text> <Text>Touchable</Text>
</TouchableHighlight> </TouchableHighlight>,
); );
expect(instance.toJSON()).toMatchSnapshot(); expect(instance.toJSON()).toMatchSnapshot();

View File

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const invariant = require('fbjs/lib/invariant'); const invariant = require('fbjs/lib/invariant');
@ -14,7 +16,7 @@ const ensureComponentIsNative = function(component: any) {
invariant( invariant(
component && typeof component.setNativeProps === 'function', component && typeof component.setNativeProps === 'function',
'Touchable child must either be native or forward setNativeProps to a ' + 'Touchable child must either be native or forward setNativeProps to a ' +
'native component' 'native component',
); );
}; };

View File

@ -4,17 +4,22 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
'use strict'; 'use strict';
const invariant = require('fbjs/lib/invariant'); const invariant = require('fbjs/lib/invariant');
const ensurePositiveDelayProps = function(props: any) { const ensurePositiveDelayProps = function(props: any) {
invariant( invariant(
!(props.delayPressIn < 0 || props.delayPressOut < 0 || !(
props.delayLongPress < 0), props.delayPressIn < 0 ||
'Touchable components cannot have negative delay properties' props.delayPressOut < 0 ||
props.delayLongPress < 0
),
'Touchable components cannot have negative delay properties',
); );
}; };

View File

@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */

View File

@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
* @format
* @flow * @flow
*/ */
@ -27,10 +28,10 @@ const ReactNativeStyleAttributes = {
...keyMirror(ImageStylePropTypes), ...keyMirror(ImageStylePropTypes),
}; };
ReactNativeStyleAttributes.transform = { process: processTransform }; ReactNativeStyleAttributes.transform = {process: processTransform};
ReactNativeStyleAttributes.shadowOffset = { diff: sizesDiffer }; ReactNativeStyleAttributes.shadowOffset = {diff: sizesDiffer};
const colorAttributes = { process: processColor }; const colorAttributes = {process: processColor};
ReactNativeStyleAttributes.backgroundColor = colorAttributes; ReactNativeStyleAttributes.backgroundColor = colorAttributes;
ReactNativeStyleAttributes.borderBottomColor = colorAttributes; ReactNativeStyleAttributes.borderBottomColor = colorAttributes;
ReactNativeStyleAttributes.borderColor = colorAttributes; ReactNativeStyleAttributes.borderColor = colorAttributes;

Some files were not shown because too many files have changed in this diff Show More