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 коммит произвёл Facebook Github Bot
Родитель 1e2de71290
Коммит d01ab66b47
301 изменённых файлов: 6259 добавлений и 3781 удалений

Просмотреть файл

@ -4,7 +4,9 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
// TODO: Move this into an ART mode called "serialized" or something
@ -19,7 +21,6 @@ const CURVE_TO = 3;
const ARC = 4;
const SerializablePath = Class(Path, {
initialize: function(path) {
this.reset();
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) {
if (rx !== ry || rotation) {
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);
@ -66,8 +78,7 @@ const SerializablePath = Class(Path, {
toJSON: function() {
return this.path;
}
},
});
module.exports = SerializablePath;

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @emails oncall+react_native
*/
'use strict';
const Easing = require('Easing');
@ -88,23 +90,363 @@ describe('Easing', () => {
}
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],
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],
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,
],
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) {

Просмотреть файл

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

Просмотреть файл

@ -74,7 +74,10 @@ describe('bezier', function() {
describe('common properties', function() {
it('should be the right value at extremes', 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);
expect(easing(0)).toBe(0);
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() {
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 projected = bezier(b, a, d, c);
const composed = function(x) {
@ -96,7 +102,10 @@ describe('bezier', function() {
describe('two same instances', function() {
it('should be strictly equals', 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);
});
});
@ -104,14 +113,20 @@ describe('bezier', function() {
describe('symetric curves', function() {
it('should have a central value y~=0.5 at x=0.5', 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);
assertClose(easing(0.5), 0.5, 2);
});
});
it('should be symmetrical', 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 sym = function(x) {
return 1 - easing(1 - x);

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow
*/
'use strict';
const MissingNativeEventEmitterShim = require('MissingNativeEventEmitterShim');
@ -23,7 +25,6 @@ const invariant = require('fbjs/lib/invariant');
* See http://facebook.github.io/react-native/docs/appstate.html
*/
class AppState extends NativeEventEmitter {
_eventHandlers: Object;
currentState: ?string;
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
// whenever the state changes, even if nobody cares. We should just
// deprecate the `currentState` property and get rid of this.
this.addListener(
'appStateDidChange',
(appStateData) => {
eventUpdated = true;
this.currentState = appStateData.app_state;
}
);
this.addListener('appStateDidChange', appStateData => {
eventUpdated = true;
this.currentState = appStateData.app_state;
});
// 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
// prop and expose `getCurrentAppState` method directly.
RCTAppState.getCurrentAppState(
(appStateData) => {
// It's possible that the state will have changed here & listeners need to be notified
if (!eventUpdated && this.currentState !== appStateData.app_state) {
this.currentState = appStateData.app_state;
this.emit('appStateDidChange', appStateData);
}
},
logError
);
RCTAppState.getCurrentAppState(appStateData => {
// It's possible that the state will have changed here & listeners need to be notified
if (!eventUpdated && this.currentState !== appStateData.app_state) {
this.currentState = appStateData.app_state;
this.emit('appStateDidChange', appStateData);
}
}, logError);
}
// 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
// change though, as both the method and event names are different
// (addListener events are currently required to be globally unique).
/**
/**
* Add a handler to AppState changes by listening to the `change` event type
* and providing the handler.
*
* See http://facebook.github.io/react-native/docs/appstate.html#addeventlistener
*/
addEventListener(
type: string,
handler: Function
) {
addEventListener(type: string, handler: Function) {
invariant(
['change', 'memoryWarning'].indexOf(type) !== -1,
'Trying to subscribe to unknown event: "%s"', type
'Trying to subscribe to unknown event: "%s"',
type,
);
if (type === 'change') {
this._eventHandlers[type].set(handler, this.addListener(
'appStateDidChange',
(appStateData) => {
this._eventHandlers[type].set(
handler,
this.addListener('appStateDidChange', appStateData => {
handler(appStateData.app_state);
}
));
}),
);
} else if (type === 'memoryWarning') {
this._eventHandlers[type].set(handler, this.addListener(
'memoryWarning',
handler
));
this._eventHandlers[type].set(
handler,
this.addListener('memoryWarning', handler),
);
}
}
@ -109,13 +102,11 @@ class AppState extends NativeEventEmitter {
*
* See http://facebook.github.io/react-native/docs/appstate.html#removeeventlistener
*/
removeEventListener(
type: string,
handler: Function
) {
removeEventListener(type: string, handler: Function) {
invariant(
['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)) {
return;

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow
*/
'use strict';
const RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
@ -14,12 +16,14 @@ const infoLog = require('infoLog');
import type EmitterSubscription from 'EmitterSubscription';
type ExtraData = { [key: string]: string };
type ExtraData = {[key: string]: string};
type SourceCallback = () => string;
type DebugData = { extras: ExtraData, files: ExtraData };
type DebugData = {extras: ExtraData, files: ExtraData};
function defaultExtras() {
BugReporting.addFileSource('react_hierarchy.txt', () => require('dumpReactTree')());
BugReporting.addFileSource('react_hierarchy.txt', () =>
require('dumpReactTree')(),
);
}
/**
@ -36,14 +40,20 @@ class BugReporting {
static _maybeInit() {
if (!BugReporting._subscription) {
BugReporting._subscription = RCTDeviceEventEmitter
.addListener('collectBugExtraData', BugReporting.collectExtraData, null);
BugReporting._subscription = RCTDeviceEventEmitter.addListener(
'collectBugExtraData',
BugReporting.collectExtraData,
null,
);
defaultExtras();
}
if (!BugReporting._redboxSubscription) {
BugReporting._redboxSubscription = RCTDeviceEventEmitter
.addListener('collectRedBoxExtraData', BugReporting.collectExtraData, null);
BugReporting._redboxSubscription = RCTDeviceEventEmitter.addListener(
'collectRedBoxExtraData',
BugReporting.collectExtraData,
null,
);
}
}
@ -55,7 +65,10 @@ class BugReporting {
*
* 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);
}
@ -67,17 +80,30 @@ class BugReporting {
*
* 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);
}
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();
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);
return {remove: () => { source.delete(key); }};
return {
remove: () => {
source.delete(key);
},
};
}
/**
@ -106,7 +132,7 @@ class BugReporting {
RedBoxNativeModule.setExtraData &&
RedBoxNativeModule.setExtraData(extraData, 'From BugReporting.js');
return { extras: extraData, files: fileData };
return {extras: extraData, files: fileData};
}
}

Просмотреть файл

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

Просмотреть файл

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow
*/
'use strict';
/**
@ -31,7 +33,10 @@ function getData(element: Object): Object {
if (typeof element !== 'object') {
nodeType = 'Text';
text = element + '';
} else if (element._currentElement === null || element._currentElement === false) {
} else if (
element._currentElement === null ||
element._currentElement === false
) {
nodeType = 'Empty';
} else if (element._renderedComponent) {
nodeType = 'NativeWrapper';
@ -65,7 +70,11 @@ function getData(element: Object): Object {
name = element.getName();
// 0.14 top-level wrapper
// 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';
}
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) {
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) {
parent[last] = value;
}
@ -158,7 +167,11 @@ function copyWithSetImpl(obj, path, idx, value) {
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);
}

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
@ -17,7 +18,9 @@ class DummyDatePickerIOS extends React.Component {
render() {
return (
<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>
);
}
@ -37,7 +40,7 @@ const styles = StyleSheet.create({
datePickerText: {
color: '#333333',
margin: 20,
}
},
});
module.exports = DummyDatePickerIOS;

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -6,7 +6,10 @@
*
*
* This is a controlled component version of RCTPickerIOS
*
* @format
*/
'use strict';
const NativeMethodsMixin = require('NativeMethodsMixin');
@ -46,7 +49,7 @@ const PickerIOS = createReactClass({
_stateFromProps: function(props) {
let selectedIndex = 0;
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) {
selectedIndex = index;
}
@ -63,7 +66,7 @@ const PickerIOS = createReactClass({
return (
<View style={this.props.style}>
<RCTPickerIOS
ref={picker => this._picker = picker}
ref={picker => (this._picker = picker)}
style={[styles.pickerIOS, this.props.itemStyle]}
items={this.state.items}
selectedIndex={this.state.selectedIndex}
@ -80,7 +83,10 @@ const PickerIOS = createReactClass({
this.props.onChange(event);
}
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
@ -89,9 +95,12 @@ const PickerIOS = createReactClass({
// disallow/undo/mutate the selection of certain values. In other
// words, the embedder of this component should be the source of
// 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({
selectedIndex: this.state.selectedIndex
selectedIndex: this.state.selectedIndex,
});
}
},
@ -119,16 +128,20 @@ const styles = StyleSheet.create({
},
});
const RCTPickerIOS = requireNativeComponent('RCTPicker', {
propTypes: {
style: itemStylePropType,
const RCTPickerIOS = requireNativeComponent(
'RCTPicker',
{
propTypes: {
style: itemStylePropType,
},
},
}, {
nativeOnly: {
items: true,
onChange: true,
selectedIndex: true,
{
nativeOnly: {
items: true,
onChange: true,
selectedIndex: true,
},
},
});
);
module.exports = PickerIOS;

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow
*/
'use strict';
import type EventEmitter from 'EventEmitter';
@ -21,7 +23,6 @@ import type EventEmitter from 'EventEmitter';
const Subscribable = {};
Subscribable.Mixin = {
UNSAFE_componentWillMount: function() {
this._subscribableSubscriptions = [];
},
@ -29,9 +30,10 @@ Subscribable.Mixin = {
componentWillUnmount: function() {
// 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
this._subscribableSubscriptions && this._subscribableSubscriptions.forEach(
(subscription) => subscription.remove()
);
this._subscribableSubscriptions &&
this._subscribableSubscriptions.forEach(subscription =>
subscription.remove(),
);
this._subscribableSubscriptions = null;
},
@ -52,12 +54,12 @@ Subscribable.Mixin = {
eventEmitter: EventEmitter,
eventType: string,
listener: Function,
context: Object
context: Object,
) {
this._subscribableSubscriptions.push(
eventEmitter.addListener(eventType, listener, context)
eventEmitter.addListener(eventType, listener, context),
);
}
},
};
module.exports = Subscribable;

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -4,8 +4,10 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @noflow
*/
'use strict';
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.
*/
badge: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]),
badge: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
/**
* 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) {
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
// preserve state between tab transitions
if (this.state.hasBeenSelected) {
var tabContents =
var tabContents = (
<StaticContainer shouldUpdate={this.props.selected}>
{children}
</StaticContainer>;
</StaticContainer>
);
} else {
var tabContents = <View />;
}
return (
<RCTTabBarItem
{...props}
style={[styles.tab, style]}>
<RCTTabBarItem {...props} style={[styles.tab, style]}>
{tabContents}
</RCTTabBarItem>
);
@ -142,7 +140,7 @@ const styles = StyleSheet.create({
right: 0,
bottom: 0,
left: 0,
}
},
});
const RCTTabBarItem = requireNativeComponent('RCTTabBarItem', TabBarItemIOS);

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -4,21 +4,18 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @noflow
*/
'use strict';
const warning = require('fbjs/lib/warning');
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.');
},
};
module.exports = ToastAndroid;

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -4,7 +4,9 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
const Platform = require('Platform');
@ -112,7 +114,10 @@ const TouchableNativeFeedback = createReactClass({
* Available on android API level 21+.
*/
SelectableBackgroundBorderless: function() {
return {type: 'ThemeAttrAndroid', attribute: 'selectableItemBackgroundBorderless'};
return {
type: 'ThemeAttrAndroid',
attribute: 'selectableItemBackgroundBorderless',
};
},
/**
* 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
*/
Ripple: function(color: string, borderless: boolean) {
return {type: 'RippleAndroid', color: processColor(color), borderless: borderless};
return {
type: 'RippleAndroid',
color: processColor(color),
borderless: borderless,
};
},
canUseNativeForeground: function() {
return Platform.OS === 'android' && Platform.Version >= 23;
}
},
},
mixins: [Touchable.Mixin],
@ -161,7 +170,10 @@ const TouchableNativeFeedback = createReactClass({
this.props.onPressIn && this.props.onPressIn(e);
this._dispatchPressedStateChange(true);
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) {
this.touchableHandleResponderMove(e);
this._dispatchHotspotUpdate(e.nativeEvent.locationX, e.nativeEvent.locationY);
this._dispatchHotspotUpdate(
e.nativeEvent.locationX,
e.nativeEvent.locationY,
);
},
_dispatchHotspotUpdate: function(destX, destY) {
UIManager.dispatchViewManagerCommand(
ReactNative.findNodeHandle(this),
UIManager.RCTView.Commands.hotspotUpdate,
[destX || 0, destY || 0]
[destX || 0, destY || 0],
);
},
@ -216,7 +231,7 @@ const TouchableNativeFeedback = createReactClass({
UIManager.dispatchViewManagerCommand(
ReactNative.findNodeHandle(this),
UIManager.RCTView.Commands.setPressed,
[pressed]
[pressed],
);
},
@ -227,16 +242,26 @@ const TouchableNativeFeedback = createReactClass({
if (!Array.isArray(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(
'Requested foreground ripple, but it is not available on this version of Android. ' +
'Consider calling TouchableNativeFeedback.canUseNativeForeground() and using a different ' +
'Touchable if the result is false.');
'Consider calling TouchableNativeFeedback.canUseNativeForeground() and using a different ' +
'Touchable if the result is false.',
);
}
const drawableProp =
this.props.useForeground && TouchableNativeFeedback.canUseNativeForeground()
this.props.useForeground &&
TouchableNativeFeedback.canUseNativeForeground()
? 'nativeForegroundAndroid'
: 'nativeBackgroundAndroid';
const childProps = {
@ -253,7 +278,8 @@ const TouchableNativeFeedback = createReactClass({
isTVSelectable: true,
hasTVPreferredFocus: this.props.hasTVPreferredFocus,
onStartShouldSetResponder: this.touchableHandleStartShouldSetResponder,
onResponderTerminationRequest: this.touchableHandleResponderTerminationRequest,
onResponderTerminationRequest: this
.touchableHandleResponderTerminationRequest,
onResponderGrant: this.touchableHandleResponderGrant,
onResponderMove: this._handleResponderMove,
onResponderRelease: this.touchableHandleResponderRelease,
@ -263,11 +289,8 @@ const TouchableNativeFeedback = createReactClass({
// 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
// a wrapper view as done in other Touchable*
return React.cloneElement(
child,
childProps
);
}
return React.cloneElement(child, childProps);
},
});
module.exports = TouchableNativeFeedback;

Просмотреть файл

@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
@ -22,7 +23,9 @@ class DummyTouchableNativeFeedback extends React.Component {
render() {
return (
<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>
);
}
@ -42,7 +45,7 @@ const styles = StyleSheet.create({
info: {
color: '#333333',
margin: 20,
}
},
});
module.exports = DummyTouchableNativeFeedback;

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше