Prettier React Native Libraries
Reviewed By: sahrens Differential Revision: D7961488 fbshipit-source-id: 05f9b8b0b91ae77f9040a5321ccc18f7c3c1ce9a
This commit is contained in:
parent
1e2de71290
commit
d01ab66b47
|
@ -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;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue