Compare commits
@@ -1,8 +1,8 @@
|
||||
environment:
|
||||
ANDROID_HOME: "C:\\android-sdk-windows"
|
||||
ANDROID_NDK: "C:\\android-sdk-windows\\android-ndk-r17c"
|
||||
ANDROID_BUILD_VERSION: 27
|
||||
ANDROID_TOOLS_VERSION: 27.0.3
|
||||
ANDROID_BUILD_VERSION: 28
|
||||
ANDROID_TOOLS_VERSION: 28.0.3
|
||||
|
||||
GRADLE_OPTS: -Dorg.gradle.daemon=false
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
[android]
|
||||
target = android-27
|
||||
target = android-28
|
||||
|
||||
[download]
|
||||
max_number_of_retries = 3
|
||||
|
||||
@@ -28,11 +28,11 @@ aliases:
|
||||
|
||||
- &restore-cache-android-packages
|
||||
keys:
|
||||
- v1-android-sdkmanager-packages-api-27-alpha-{{ checksum "scripts/.tests.env" }}
|
||||
- v1-android-sdkmanager-packages-api-28-alpha-{{ checksum "scripts/.tests.env" }}
|
||||
- &save-cache-android-packages
|
||||
paths:
|
||||
- /opt/android/sdk
|
||||
key: v1-android-sdkmanager-packages-api-27-alpha-{{ checksum "scripts/.tests.env" }}
|
||||
key: v1-android-sdkmanager-packages-api-28-alpha-{{ checksum "scripts/.tests.env" }}
|
||||
|
||||
- &restore-cache-gradle
|
||||
keys:
|
||||
@@ -84,6 +84,14 @@ aliases:
|
||||
- ReactAndroid/build/third-party-ndk
|
||||
key: v1-gradle-{{ checksum "ReactAndroid/build.gradle" }}-{{ checksum "scripts/circleci/gradle_download_deps.sh" }}
|
||||
|
||||
- &restore-cache-homebrew
|
||||
keys:
|
||||
- v1-homebrew
|
||||
- &save-cache-homebrew
|
||||
paths:
|
||||
- /usr/local/Homebrew
|
||||
key: v1-homebrew
|
||||
|
||||
# Branch Filtering
|
||||
- &filter-only-master-stable
|
||||
branches:
|
||||
@@ -233,7 +241,7 @@ aliases:
|
||||
|
||||
- &compile-native-libs
|
||||
name: Compile Native Libs for Unit and Integration Tests
|
||||
command: ./gradlew :ReactAndroid:packageReactNdkLibsForBuck -Pjobs=$BUILD_THREADS -Pcom.android.build.threadPoolSize=1
|
||||
command: ./gradlew :ReactAndroid:packageReactNdkLibsForBuck -Pjobs=$BUILD_THREADS
|
||||
no_output_timeout: 6m
|
||||
|
||||
- &run-android-unit-tests
|
||||
@@ -277,20 +285,12 @@ aliases:
|
||||
|
||||
- &boot-simulator-iphone
|
||||
name: Boot iPhone Simulator
|
||||
command: xcrun simctl boot "iPhone 5s" || true
|
||||
|
||||
- &boot-simulator-appletv
|
||||
name: Boot Apple TV Simulator
|
||||
command: xcrun simctl boot "Apple TV" || true
|
||||
command: source scripts/.tests.env && xcrun simctl boot "$IOS_DEVICE" || true
|
||||
|
||||
- &run-objc-ios-tests
|
||||
name: iOS Test Suite
|
||||
command: ./scripts/objc-test-ios.sh test
|
||||
|
||||
- &run-objc-tvos-tests
|
||||
name: tvOS Test Suite
|
||||
command: ./scripts/objc-test-tvos.sh test
|
||||
|
||||
- &display-broken-tests-warning
|
||||
name: Running broken tests (Ignore any failures past this point)
|
||||
command: |
|
||||
@@ -304,16 +304,12 @@ aliases:
|
||||
|
||||
- &run-e2e-tests
|
||||
name: End-to-End Test Suite (Disabled)
|
||||
command: ./scripts/circleci/exec_author_check.sh node ./scripts/run-ci-e2e-tests.js --android --ios --tvos --js --retries 3;
|
||||
command: ./scripts/circleci/exec_author_check.sh node ./scripts/run-ci-e2e-tests.js --android --ios --js --retries 3;
|
||||
|
||||
- &run-objc-ios-e2e-tests
|
||||
name: iOS End-to-End Test Suite (Disabled)
|
||||
command: ./scripts/circleci/exec_author_check.sh node ./scripts/run-ci-e2e-tests.js --ios --retries 3;
|
||||
|
||||
- &run-objc-tvos-e2e-tests
|
||||
name: tvOS End-to-End Test Suite (Disabled)
|
||||
command: ./scripts/circleci/exec_author_check.sh node ./scripts/run-ci-e2e-tests.js --tvos --js --retries 3;
|
||||
|
||||
- &run-android-e2e-tests
|
||||
name: Android End-to-End Test Suite (Disabled)
|
||||
command: ./scripts/circleci/exec_author_check.sh node ./scripts/run-ci-e2e-tests.js --android --retries 3;
|
||||
@@ -337,7 +333,7 @@ js_defaults: &js_defaults
|
||||
android_defaults: &android_defaults
|
||||
<<: *defaults
|
||||
docker:
|
||||
- image: circleci/android:api-27-node8-alpha
|
||||
- image: circleci/android:api-28-node8-alpha
|
||||
resource_class: "large"
|
||||
environment:
|
||||
- TERM: "dumb"
|
||||
@@ -350,7 +346,7 @@ android_defaults: &android_defaults
|
||||
macos_defaults: &macos_defaults
|
||||
<<: *defaults
|
||||
macos:
|
||||
xcode: "9.4.0"
|
||||
xcode: "10.1.0"
|
||||
|
||||
version: 2
|
||||
jobs:
|
||||
@@ -416,51 +412,19 @@ jobs:
|
||||
- store_test_results:
|
||||
path: ~/react-native/reports/junit
|
||||
|
||||
# Runs unit tests on iOS and Apple TV devices
|
||||
test_objc:
|
||||
# Runs unit tests on iOS devices
|
||||
test_ios:
|
||||
<<: *macos_defaults
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/react-native
|
||||
|
||||
- run: *boot-simulator-iphone
|
||||
- run: *boot-simulator-appletv
|
||||
|
||||
- restore-cache: *restore-cache-homebrew
|
||||
- run: *brew-install-watchman
|
||||
|
||||
- save-cache: *save-cache-homebrew
|
||||
- run: *run-objc-ios-tests
|
||||
- run: *run-objc-tvos-tests
|
||||
|
||||
# TODO: Fix these failing tests.
|
||||
- run: *display-broken-tests-warning
|
||||
- run: *run-podspec-tests
|
||||
- run: *run-objc-ios-e2e-tests
|
||||
- run: *run-objc-tvos-e2e-tests
|
||||
|
||||
- store_test_results:
|
||||
path: ~/react-native/reports/junit
|
||||
|
||||
# Xcode 10: Runs unit tests on iOS and Apple TV devices
|
||||
test_objc_xcode10:
|
||||
<<: *defaults
|
||||
macos:
|
||||
xcode: "10.0.0"
|
||||
steps:
|
||||
- checkout
|
||||
- run: *setup-artifacts
|
||||
- run: *yarn
|
||||
|
||||
- run: *boot-simulator-iphone
|
||||
- run: *boot-simulator-appletv
|
||||
- run: *brew-install-watchman
|
||||
|
||||
- run: *run-objc-ios-tests
|
||||
- run: *run-objc-tvos-tests
|
||||
|
||||
# TODO: Fix these failing tests.
|
||||
- run: *display-broken-tests-warning
|
||||
- run: *run-podspec-tests
|
||||
- run: *run-objc-ios-e2e-tests
|
||||
- run: *run-objc-tvos-e2e-tests
|
||||
|
||||
- store_test_results:
|
||||
path: ~/react-native/reports/junit
|
||||
@@ -703,8 +667,8 @@ workflows:
|
||||
requires:
|
||||
- checkout_code
|
||||
|
||||
# Test iOS & tvOS
|
||||
- test_objc:
|
||||
# Test iOS
|
||||
- test_ios:
|
||||
filters: *filter-ignore-gh-pages
|
||||
requires:
|
||||
- checkout_code
|
||||
@@ -715,8 +679,6 @@ workflows:
|
||||
- checkout_code
|
||||
|
||||
# Tooling Compatibility Checks
|
||||
- test_objc_xcode10:
|
||||
filters: *filter-ignore-gh-pages
|
||||
- test_node10:
|
||||
filters: *filter-ignore-gh-pages
|
||||
|
||||
|
||||
@@ -22,9 +22,6 @@
|
||||
; Ignore polyfills
|
||||
.*/Libraries/polyfills/.*
|
||||
|
||||
; Ignore metro
|
||||
.*/node_modules/metro/.*
|
||||
|
||||
; These should not be required directly
|
||||
; require from fbjs/lib instead: require('fbjs/lib/invariant')
|
||||
.*/node_modules/invariant/.*
|
||||
@@ -102,3 +99,6 @@ untyped-type-import
|
||||
|
||||
[version]
|
||||
^0.86.0
|
||||
|
||||
[untyped]
|
||||
.*/node_modules/metro/.*
|
||||
|
||||
@@ -22,9 +22,6 @@
|
||||
; Ignore polyfills
|
||||
.*/Libraries/polyfills/.*
|
||||
|
||||
; Ignore metro
|
||||
.*/node_modules/metro/.*
|
||||
|
||||
; These should not be required directly
|
||||
; require from fbjs/lib instead: require('fbjs/lib/invariant')
|
||||
.*/node_modules/invariant/.*
|
||||
@@ -102,3 +99,6 @@ untyped-type-import
|
||||
|
||||
[version]
|
||||
^0.86.0
|
||||
|
||||
[untyped]
|
||||
.*/node_modules/metro/.*
|
||||
|
||||
@@ -50,7 +50,7 @@ ADD react.gradle /app/react.gradle
|
||||
RUN ./gradlew :ReactAndroid:downloadBoost :ReactAndroid:downloadDoubleConversion :ReactAndroid:downloadFolly :ReactAndroid:downloadGlog :ReactAndroid:downloadJSCHeaders
|
||||
|
||||
# compile native libs with Gradle script, we need bridge for unit and integration tests
|
||||
RUN ./gradlew :ReactAndroid:packageReactNdkLibsForBuck -Pjobs=1 -Pcom.android.build.threadPoolSize=1
|
||||
RUN ./gradlew :ReactAndroid:packageReactNdkLibsForBuck -Pjobs=1
|
||||
|
||||
# add all react-native code
|
||||
ADD . /app
|
||||
|
||||
@@ -23,8 +23,8 @@ LABEL maintainer="Héctor Ramos <hector@fb.com>"
|
||||
|
||||
# set default build arguments
|
||||
ARG SDK_VERSION=sdk-tools-linux-3859397.zip
|
||||
ARG ANDROID_BUILD_VERSION=27
|
||||
ARG ANDROID_TOOLS_VERSION=27.0.3
|
||||
ARG ANDROID_BUILD_VERSION=28
|
||||
ARG ANDROID_TOOLS_VERSION=28.0.3
|
||||
ARG BUCK_VERSION=v2018.10.29.01
|
||||
ARG NDK_VERSION=17c
|
||||
ARG NODE_VERSION=8.10.0
|
||||
|
||||
@@ -112,6 +112,7 @@ const ActivityIndicator = (
|
||||
|
||||
// $FlowFixMe - TODO T29156721 `React.forwardRef` is not defined in Flow, yet.
|
||||
const ActivityIndicatorWithRef = React.forwardRef(ActivityIndicator);
|
||||
ActivityIndicatorWithRef.displayName = 'ActivityIndicator';
|
||||
|
||||
ActivityIndicatorWithRef.defaultProps = {
|
||||
animating: true,
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @emails oncall+react_native
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const React = require('React');
|
||||
const ActivityIndicator = require('ActivityIndicator');
|
||||
const render = require('../../../../jest/renderer');
|
||||
|
||||
describe('ActivityIndicator', () => {
|
||||
it('should set displayName to prevent <Component /> regressions', () => {
|
||||
expect(ActivityIndicator.displayName).toBe('ActivityIndicator');
|
||||
});
|
||||
|
||||
it('should render as <ActivityIndicator> when mocked', () => {
|
||||
const instance = render.create(
|
||||
<ActivityIndicator size="large" color="#0000ff" />,
|
||||
);
|
||||
expect(instance).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should shallow render as <ActivityIndicator> when mocked', () => {
|
||||
const output = render.shallow(
|
||||
<ActivityIndicator size="large" color="#0000ff" />,
|
||||
);
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should shallow render as <ForwardRef(ActivityIndicator)> when not mocked', () => {
|
||||
jest.dontMock('ActivityIndicator');
|
||||
|
||||
const output = render.shallow(
|
||||
<ActivityIndicator size="large" color="#0000ff" />,
|
||||
);
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render as <View> when not mocked', () => {
|
||||
jest.dontMock('ActivityIndicator');
|
||||
|
||||
const instance = render.create(
|
||||
<ActivityIndicator size="large" color="#0000ff" />,
|
||||
);
|
||||
expect(instance).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,54 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ActivityIndicator should render as <ActivityIndicator> when mocked 1`] = `
|
||||
<ActivityIndicator
|
||||
animating={true}
|
||||
color="#0000ff"
|
||||
hidesWhenStopped={true}
|
||||
size="large"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`ActivityIndicator should render as <View> when not mocked 1`] = `
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"justifyContent": "center",
|
||||
}
|
||||
}
|
||||
>
|
||||
<RCTActivityIndicatorView
|
||||
animating={true}
|
||||
color="#0000ff"
|
||||
hidesWhenStopped={true}
|
||||
indeterminate={true}
|
||||
size="large"
|
||||
style={
|
||||
Object {
|
||||
"height": 36,
|
||||
"width": 36,
|
||||
}
|
||||
}
|
||||
styleAttr="Normal"
|
||||
/>
|
||||
</View>
|
||||
`;
|
||||
|
||||
exports[`ActivityIndicator should shallow render as <ActivityIndicator> when mocked 1`] = `
|
||||
<ActivityIndicator
|
||||
animating={true}
|
||||
color="#0000ff"
|
||||
hidesWhenStopped={true}
|
||||
size="large"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`ActivityIndicator should shallow render as <ForwardRef(ActivityIndicator)> when not mocked 1`] = `
|
||||
<ForwardRef(ActivityIndicator)
|
||||
animating={true}
|
||||
color="#0000ff"
|
||||
hidesWhenStopped={true}
|
||||
size="large"
|
||||
/>
|
||||
`;
|
||||
@@ -148,6 +148,7 @@ class DatePickerIOS extends React.Component<Props> {
|
||||
return (
|
||||
<View style={props.style}>
|
||||
<RCTDatePickerIOS
|
||||
testID={props.testID}
|
||||
ref={picker => {
|
||||
this._picker = picker;
|
||||
}}
|
||||
|
||||
@@ -47,6 +47,7 @@ type RCTPickerIOSType = Class<
|
||||
onStartShouldSetResponder: () => boolean,
|
||||
selectedIndex: number,
|
||||
style?: ?TextStyleProp,
|
||||
testID?: ?string,
|
||||
|}>,
|
||||
>,
|
||||
>;
|
||||
@@ -114,6 +115,7 @@ class PickerIOS extends React.Component<Props, State> {
|
||||
ref={picker => {
|
||||
this._picker = picker;
|
||||
}}
|
||||
testID={this.props.testID}
|
||||
style={[styles.pickerIOS, this.props.itemStyle]}
|
||||
items={this.state.items}
|
||||
selectedIndex={this.state.selectedIndex}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @flow strict-local
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
@@ -103,56 +103,13 @@ type Props = $ReadOnly<{|
|
||||
barStyle?: ?('default' | 'light-content' | 'dark-content'),
|
||||
|}>;
|
||||
|
||||
type StackEntryProps = {|
|
||||
/**
|
||||
* The background color of the status bar.
|
||||
*
|
||||
* @platform android
|
||||
*/
|
||||
backgroundColor: {|
|
||||
value: ?string,
|
||||
animated: ?boolean,
|
||||
|},
|
||||
/**
|
||||
* Sets the color of the status bar text.
|
||||
*/
|
||||
barStyle: {|
|
||||
value: ?string,
|
||||
animated: ?boolean,
|
||||
|},
|
||||
/**
|
||||
* If the status bar is translucent.
|
||||
* When translucent is set to true, the app will draw under the status bar.
|
||||
* This is useful when using a semi transparent status bar color.
|
||||
*/
|
||||
translucent: ?boolean,
|
||||
/**
|
||||
*
|
||||
*/
|
||||
hidden: {|
|
||||
value: ?boolean,
|
||||
animated: boolean,
|
||||
transition: ?('slide' | 'fade'),
|
||||
|},
|
||||
/**
|
||||
* If the network activity indicator should be visible.
|
||||
*
|
||||
* @platform ios
|
||||
*/
|
||||
networkActivityIndicatorVisible: ?boolean,
|
||||
|};
|
||||
|
||||
/**
|
||||
* Merges the prop stack with the default values.
|
||||
*/
|
||||
function mergePropsStack(
|
||||
propsStack: $ReadOnlyArray<StackEntryProps>,
|
||||
defaultValues: StackEntryProps,
|
||||
): StackEntryProps {
|
||||
const init: StackEntryProps = {
|
||||
...defaultValues,
|
||||
};
|
||||
|
||||
propsStack: Array<Object>,
|
||||
defaultValues: Object,
|
||||
): Object {
|
||||
return propsStack.reduce((prev, cur) => {
|
||||
for (const prop in cur) {
|
||||
if (cur[prop] != null) {
|
||||
@@ -160,31 +117,39 @@ function mergePropsStack(
|
||||
}
|
||||
}
|
||||
return prev;
|
||||
}, init);
|
||||
}, Object.assign({}, defaultValues));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object to insert in the props stack from the props
|
||||
* and the transition/animation info.
|
||||
*/
|
||||
function createStackEntry(props: Props): StackEntryProps {
|
||||
function createStackEntry(props: any): any {
|
||||
return {
|
||||
backgroundColor: {
|
||||
value: props.backgroundColor,
|
||||
animated: props.animated,
|
||||
},
|
||||
barStyle: {
|
||||
value: props.barStyle,
|
||||
animated: props.animated,
|
||||
},
|
||||
translucent: props.translucent || false,
|
||||
hidden: {
|
||||
value: props.hidden,
|
||||
animated: props.animated || false,
|
||||
transition: props.showHideTransition,
|
||||
},
|
||||
networkActivityIndicatorVisible:
|
||||
props.networkActivityIndicatorVisible || false,
|
||||
backgroundColor:
|
||||
props.backgroundColor != null
|
||||
? {
|
||||
value: props.backgroundColor,
|
||||
animated: props.animated,
|
||||
}
|
||||
: null,
|
||||
barStyle:
|
||||
props.barStyle != null
|
||||
? {
|
||||
value: props.barStyle,
|
||||
animated: props.animated,
|
||||
}
|
||||
: null,
|
||||
translucent: props.translucent,
|
||||
hidden:
|
||||
props.hidden != null
|
||||
? {
|
||||
value: props.hidden,
|
||||
animated: props.animated,
|
||||
transition: props.showHideTransition,
|
||||
}
|
||||
: null,
|
||||
networkActivityIndicatorVisible: props.networkActivityIndicatorVisible,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -228,9 +193,9 @@ function createStackEntry(props: Props): StackEntryProps {
|
||||
* `currentHeight` (Android only) The height of the status bar.
|
||||
*/
|
||||
class StatusBar extends React.Component<Props> {
|
||||
static _propsStack: Array<StackEntryProps> = [];
|
||||
static _propsStack = [];
|
||||
|
||||
static _defaultProps: StackEntryProps = createStackEntry({
|
||||
static _defaultProps = createStackEntry({
|
||||
animated: false,
|
||||
showHideTransition: 'fade',
|
||||
backgroundColor: 'black',
|
||||
@@ -265,9 +230,10 @@ class StatusBar extends React.Component<Props> {
|
||||
* changing the status bar hidden property.
|
||||
*/
|
||||
static setHidden(hidden: boolean, animation?: StatusBarAnimation) {
|
||||
animation = animation || 'none';
|
||||
StatusBar._defaultProps.hidden.value = hidden;
|
||||
if (Platform.OS === 'ios') {
|
||||
StatusBarManager.setHidden(hidden, animation || 'none');
|
||||
StatusBarManager.setHidden(hidden, animation);
|
||||
} else if (Platform.OS === 'android') {
|
||||
StatusBarManager.setHidden(hidden);
|
||||
}
|
||||
@@ -279,9 +245,10 @@ class StatusBar extends React.Component<Props> {
|
||||
* @param animated Animate the style change.
|
||||
*/
|
||||
static setBarStyle(style: StatusBarStyle, animated?: boolean) {
|
||||
animated = animated || false;
|
||||
StatusBar._defaultProps.barStyle.value = style;
|
||||
if (Platform.OS === 'ios') {
|
||||
StatusBarManager.setStyle(style, animated || false);
|
||||
StatusBarManager.setStyle(style, animated);
|
||||
} else if (Platform.OS === 'android') {
|
||||
StatusBarManager.setStyle(style);
|
||||
}
|
||||
@@ -312,8 +279,9 @@ class StatusBar extends React.Component<Props> {
|
||||
console.warn('`setBackgroundColor` is only available on Android');
|
||||
return;
|
||||
}
|
||||
animated = animated || false;
|
||||
StatusBar._defaultProps.backgroundColor.value = color;
|
||||
StatusBarManager.setColor(processColor(color), animated || false);
|
||||
StatusBarManager.setColor(processColor(color), animated);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1265,7 +1265,11 @@ const TextInput = createReactClass({
|
||||
}
|
||||
},
|
||||
|
||||
_onBlur: function(event: BlurEvent) {
|
||||
_onBlur: function(event: Event) {
|
||||
// This is a hack to fix https://fburl.com/toehyir8
|
||||
// @todo(rsnara) Figure out why this is necessary.
|
||||
this.blur();
|
||||
|
||||
if (this.props.onBlur) {
|
||||
this.props.onBlur(event);
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/**
|
||||
* @generated by scripts/bump-oss-version.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @generated by scripts/bump-oss-version.js
|
||||
* @flow
|
||||
*/
|
||||
|
||||
exports.version = {
|
||||
major: 0,
|
||||
minor: 0,
|
||||
patch: 0,
|
||||
minor: 58,
|
||||
patch: 3,
|
||||
prerelease: null,
|
||||
};
|
||||
|
||||
@@ -32,8 +32,18 @@ RCT_EXPORT_MODULE()
|
||||
{
|
||||
CGImageSourceRef imageSource = CGImageSourceCreateWithData((CFDataRef)imageData, NULL);
|
||||
NSDictionary<NSString *, id> *properties = (__bridge_transfer NSDictionary *)CGImageSourceCopyProperties(imageSource, NULL);
|
||||
NSUInteger loopCount = [properties[(id)kCGImagePropertyGIFDictionary][(id)kCGImagePropertyGIFLoopCount] unsignedIntegerValue];
|
||||
|
||||
NSUInteger loopCount = 0;
|
||||
if ([[properties[(id)kCGImagePropertyGIFDictionary] allKeys] containsObject:(id)kCGImagePropertyGIFLoopCount]) {
|
||||
loopCount = [properties[(id)kCGImagePropertyGIFDictionary][(id)kCGImagePropertyGIFLoopCount] unsignedIntegerValue];
|
||||
if (loopCount == 0) {
|
||||
// A loop count of 0 means infinite
|
||||
loopCount = HUGE_VALF;
|
||||
} else {
|
||||
// A loop count of 1 means it should repeat twice, 2 means, thrice, etc.
|
||||
loopCount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
UIImage *image = nil;
|
||||
size_t imageCount = CGImageSourceGetCount(imageSource);
|
||||
if (imageCount > 1) {
|
||||
@@ -84,11 +94,12 @@ RCT_EXPORT_MODULE()
|
||||
// Create animation
|
||||
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"contents"];
|
||||
animation.calculationMode = kCAAnimationDiscrete;
|
||||
animation.repeatCount = loopCount == 0 ? HUGE_VALF : loopCount;
|
||||
animation.repeatCount = loopCount;
|
||||
animation.keyTimes = keyTimes;
|
||||
animation.values = images;
|
||||
animation.duration = duration;
|
||||
animation.removedOnCompletion = NO;
|
||||
animation.fillMode = kCAFillModeForwards;
|
||||
image.reactKeyframeAnimation = animation;
|
||||
|
||||
} else {
|
||||
|
||||
@@ -32,8 +32,6 @@ static NSString *RCTCacheKeyForImage(NSString *imageTag, CGSize size, CGFloat sc
|
||||
NSOperationQueue *_imageDecodeQueue;
|
||||
NSCache *_decodedImageCache;
|
||||
NSMutableDictionary *_cacheStaleTimes;
|
||||
|
||||
NSDateFormatter *_headerDateFormatter;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
@@ -50,7 +48,7 @@ static NSString *RCTCacheKeyForImage(NSString *imageTag, CGSize size, CGFloat sc
|
||||
selector:@selector(clearCache)
|
||||
name:UIApplicationWillResignActiveNotification
|
||||
object:nil];
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -137,14 +135,16 @@ static NSString *RCTCacheKeyForImage(NSString *imageTag, CGSize size, CGFloat sc
|
||||
}
|
||||
|
||||
- (NSDate *)dateWithHeaderString:(NSString *)headerDateString {
|
||||
if (_headerDateFormatter == nil) {
|
||||
_headerDateFormatter = [[NSDateFormatter alloc] init];
|
||||
_headerDateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
|
||||
_headerDateFormatter.dateFormat = @"EEE',' dd MMM yyyy HH':'mm':'ss 'GMT'";
|
||||
_headerDateFormatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
|
||||
}
|
||||
static NSDateFormatter *formatter;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
formatter = [[NSDateFormatter alloc] init];
|
||||
formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
|
||||
formatter.dateFormat = @"EEE',' dd MMM yyyy HH':'mm':'ss 'GMT'";
|
||||
formatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
|
||||
});
|
||||
|
||||
return [_headerDateFormatter dateFromString:headerDateString];
|
||||
return [formatter dateFromString:headerDateString];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -12,7 +12,12 @@
|
||||
|
||||
jest.mock('ErrorUtils').mock('BatchedBridge');
|
||||
|
||||
const isWindows = process.platform === 'win32';
|
||||
function expectToBeCalledOnce(fn) {
|
||||
// todo fix this test case on widnows
|
||||
if (isWindows) {
|
||||
return;
|
||||
}
|
||||
expect(fn.mock.calls.length).toBe(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
3ff2c7ccd4d174786aed0f16cc0dd784816ae977
|
||||
6bf5e859860938b8cb7153ee928c01ad45656969
|
||||
@@ -956,10 +956,6 @@ var eventTypes$1 = {
|
||||
}
|
||||
}
|
||||
},
|
||||
customBubblingEventTypes$1 =
|
||||
ReactNativeViewConfigRegistry.customBubblingEventTypes,
|
||||
customDirectEventTypes$1 =
|
||||
ReactNativeViewConfigRegistry.customDirectEventTypes,
|
||||
ReactNativeBridgeEventPlugin = {
|
||||
eventTypes: ReactNativeViewConfigRegistry.eventTypes,
|
||||
extractEvents: function(
|
||||
@@ -969,8 +965,10 @@ var eventTypes$1 = {
|
||||
nativeEventTarget
|
||||
) {
|
||||
if (null == targetInst) return null;
|
||||
var bubbleDispatchConfig = customBubblingEventTypes$1[topLevelType],
|
||||
directDispatchConfig = customDirectEventTypes$1[topLevelType];
|
||||
var bubbleDispatchConfig =
|
||||
ReactNativeViewConfigRegistry.customBubblingEventTypes[topLevelType],
|
||||
directDispatchConfig =
|
||||
ReactNativeViewConfigRegistry.customDirectEventTypes[topLevelType];
|
||||
invariant(
|
||||
bubbleDispatchConfig || directDispatchConfig,
|
||||
'Unsupported top level event type "%s" dispatched',
|
||||
@@ -1505,7 +1503,7 @@ function dispatchEvent(target, topLevelType, nativeEvent) {
|
||||
function shim$1() {
|
||||
invariant(
|
||||
!1,
|
||||
"The current renderer does not support hyration. This error is likely caused by a bug in React. Please file an issue."
|
||||
"The current renderer does not support hydration. This error is likely caused by a bug in React. Please file an issue."
|
||||
);
|
||||
}
|
||||
var nextReactTag = 2;
|
||||
@@ -1619,17 +1617,19 @@ function getStackByFiberInDevAndProd(workInProgress) {
|
||||
var info = "";
|
||||
do {
|
||||
a: switch (workInProgress.tag) {
|
||||
case 2:
|
||||
case 16:
|
||||
case 0:
|
||||
case 1:
|
||||
case 5:
|
||||
case 8:
|
||||
case 13:
|
||||
case 3:
|
||||
case 4:
|
||||
case 6:
|
||||
case 7:
|
||||
case 10:
|
||||
case 9:
|
||||
var JSCompiler_inline_result = "";
|
||||
break a;
|
||||
default:
|
||||
var owner = workInProgress._debugOwner,
|
||||
source = workInProgress._debugSource,
|
||||
name = getComponentName(workInProgress.type);
|
||||
var JSCompiler_inline_result = null;
|
||||
JSCompiler_inline_result = null;
|
||||
owner && (JSCompiler_inline_result = getComponentName(owner.type));
|
||||
owner = name;
|
||||
name = "";
|
||||
@@ -1643,9 +1643,6 @@ function getStackByFiberInDevAndProd(workInProgress) {
|
||||
: JSCompiler_inline_result &&
|
||||
(name = " (created by " + JSCompiler_inline_result + ")");
|
||||
JSCompiler_inline_result = "\n in " + (owner || "Unknown") + name;
|
||||
break a;
|
||||
default:
|
||||
JSCompiler_inline_result = "";
|
||||
}
|
||||
info += JSCompiler_inline_result;
|
||||
workInProgress = workInProgress.return;
|
||||
@@ -3379,7 +3376,8 @@ function updateMemoComponent(
|
||||
"function" === typeof type &&
|
||||
!shouldConstruct(type) &&
|
||||
void 0 === type.defaultProps &&
|
||||
null === Component.compare
|
||||
null === Component.compare &&
|
||||
void 0 === Component.defaultProps
|
||||
)
|
||||
return (
|
||||
(workInProgress.tag = 15),
|
||||
@@ -3817,7 +3815,6 @@ function updateSuspenseComponent(
|
||||
nextDidTimeout
|
||||
? ((renderExpirationTime = nextProps.fallback),
|
||||
(nextProps = createWorkInProgress(mode, mode.pendingProps, 0)),
|
||||
(nextProps.effectTag |= 2),
|
||||
0 === (workInProgress.mode & 1) &&
|
||||
((nextDidTimeout =
|
||||
null !== workInProgress.memoizedState
|
||||
@@ -3830,7 +3827,6 @@ function updateSuspenseComponent(
|
||||
renderExpirationTime,
|
||||
current$$1.expirationTime
|
||||
)),
|
||||
(mode.effectTag |= 2),
|
||||
(renderExpirationTime = nextProps),
|
||||
(nextProps.childExpirationTime = 0),
|
||||
(renderExpirationTime.return = mode.return = workInProgress))
|
||||
@@ -3844,9 +3840,7 @@ function updateSuspenseComponent(
|
||||
nextDidTimeout
|
||||
? ((nextDidTimeout = nextProps.fallback),
|
||||
(nextProps = createFiberFromFragment(null, mode, 0, null)),
|
||||
(nextProps.effectTag |= 2),
|
||||
(nextProps.child = current$$1),
|
||||
(current$$1.return = nextProps),
|
||||
0 === (workInProgress.mode & 1) &&
|
||||
(nextProps.child =
|
||||
null !== workInProgress.memoizedState
|
||||
@@ -4082,8 +4076,9 @@ function beginWork(current$$1, workInProgress, renderExpirationTime) {
|
||||
default:
|
||||
invariant(
|
||||
!1,
|
||||
"Element type is invalid. Received a promise that resolves to: %s. Promise elements must resolve to a class or function.",
|
||||
current$$1
|
||||
"Element type is invalid. Received a promise that resolves to: %s. Lazy element type must resolve to a class or function.%s",
|
||||
current$$1,
|
||||
""
|
||||
);
|
||||
}
|
||||
return getDerivedStateFromProps;
|
||||
@@ -4390,9 +4385,10 @@ function beginWork(current$$1, workInProgress, renderExpirationTime) {
|
||||
return (
|
||||
(context = workInProgress.type),
|
||||
(hasContext = resolveDefaultProps(
|
||||
context.type,
|
||||
context,
|
||||
workInProgress.pendingProps
|
||||
)),
|
||||
(hasContext = resolveDefaultProps(context.type, hasContext)),
|
||||
updateMemoComponent(
|
||||
current$$1,
|
||||
workInProgress,
|
||||
@@ -4979,20 +4975,22 @@ function completeUnitOfWork(workInProgress) {
|
||||
break a;
|
||||
}
|
||||
instance = null !== instance;
|
||||
viewConfig = null !== current && null !== current.memoizedState;
|
||||
renderExpirationTime =
|
||||
null !== current && null !== current.memoizedState;
|
||||
null !== current &&
|
||||
!instance &&
|
||||
viewConfig &&
|
||||
renderExpirationTime &&
|
||||
((current = current.child.sibling),
|
||||
null !== current &&
|
||||
reconcileChildFibers(
|
||||
current$$1,
|
||||
current,
|
||||
null,
|
||||
renderExpirationTime
|
||||
));
|
||||
((viewConfig = current$$1.firstEffect),
|
||||
null !== viewConfig
|
||||
? ((current$$1.firstEffect = current),
|
||||
(current.nextEffect = viewConfig))
|
||||
: ((current$$1.firstEffect = current$$1.lastEffect = current),
|
||||
(current.nextEffect = null)),
|
||||
(current.effectTag = 8)));
|
||||
if (
|
||||
instance !== viewConfig ||
|
||||
instance !== renderExpirationTime ||
|
||||
(0 === (current$$1.effectTag & 1) && instance)
|
||||
)
|
||||
current$$1.effectTag |= 4;
|
||||
@@ -5183,14 +5181,7 @@ function renderRoot(root$jscomp$0, isYieldy) {
|
||||
thenable.then(returnFiber$jscomp$0, returnFiber$jscomp$0);
|
||||
if (0 === (value.mode & 1)) {
|
||||
value.effectTag |= 64;
|
||||
reconcileChildren(
|
||||
sourceFiber$jscomp$0.alternate,
|
||||
sourceFiber$jscomp$0,
|
||||
null,
|
||||
returnFiber
|
||||
);
|
||||
sourceFiber$jscomp$0.effectTag &= -1025;
|
||||
sourceFiber$jscomp$0.effectTag &= -933;
|
||||
sourceFiber$jscomp$0.effectTag &= -1957;
|
||||
1 === sourceFiber$jscomp$0.tag &&
|
||||
null === sourceFiber$jscomp$0.alternate &&
|
||||
(sourceFiber$jscomp$0.tag = 17);
|
||||
@@ -5447,7 +5438,7 @@ function scheduleWorkToRoot(fiber, expirationTime) {
|
||||
}
|
||||
node = node.return;
|
||||
}
|
||||
return null === root ? null : root;
|
||||
return root;
|
||||
}
|
||||
function scheduleWork(fiber, expirationTime) {
|
||||
fiber = scheduleWorkToRoot(fiber, expirationTime);
|
||||
@@ -5944,9 +5935,14 @@ function completeRoot$1(root, finishedWork$jscomp$0, expirationTime) {
|
||||
}
|
||||
prevState.return = null;
|
||||
prevState.child = null;
|
||||
prevState.alternate &&
|
||||
((prevState.alternate.child = null),
|
||||
(prevState.alternate.return = null));
|
||||
prevState.memoizedState = null;
|
||||
prevState.updateQueue = null;
|
||||
var alternate = prevState.alternate;
|
||||
null !== alternate &&
|
||||
((alternate.return = null),
|
||||
(alternate.child = null),
|
||||
(alternate.memoizedState = null),
|
||||
(alternate.updateQueue = null));
|
||||
}
|
||||
nextEffect = nextEffect.nextEffect;
|
||||
}
|
||||
@@ -6101,7 +6097,7 @@ function onUncaughtError(error) {
|
||||
nextFlushedRoot.expirationTime = 0;
|
||||
hasUnhandledError || ((hasUnhandledError = !0), (unhandledError = error));
|
||||
}
|
||||
function findHostInstance$1(component) {
|
||||
function findHostInstance(component) {
|
||||
var fiber = component._reactInternalFiber;
|
||||
void 0 === fiber &&
|
||||
("function" === typeof component.render
|
||||
@@ -6214,7 +6210,7 @@ function findNodeHandle(componentOrHandle) {
|
||||
if (componentOrHandle._nativeTag) return componentOrHandle._nativeTag;
|
||||
if (componentOrHandle.canonical && componentOrHandle.canonical._nativeTag)
|
||||
return componentOrHandle.canonical._nativeTag;
|
||||
componentOrHandle = findHostInstance$1(componentOrHandle);
|
||||
componentOrHandle = findHostInstance(componentOrHandle);
|
||||
return null == componentOrHandle
|
||||
? componentOrHandle
|
||||
: componentOrHandle.canonical
|
||||
@@ -6310,7 +6306,7 @@ var roots = new Map(),
|
||||
};
|
||||
return ReactNativeComponent;
|
||||
})(React.Component);
|
||||
})(findNodeHandle, findHostInstance$1),
|
||||
})(findNodeHandle, findHostInstance),
|
||||
findNodeHandle: findNodeHandle,
|
||||
render: function(element, containerTag, callback) {
|
||||
var root = roots.get(containerTag);
|
||||
@@ -6418,7 +6414,7 @@ var roots = new Map(),
|
||||
TextInputState.blurTextInput(findNodeHandle(this));
|
||||
}
|
||||
};
|
||||
})(findNodeHandle, findHostInstance$1)
|
||||
})(findNodeHandle, findHostInstance)
|
||||
}
|
||||
};
|
||||
(function(devToolsConfig) {
|
||||
|
||||
@@ -957,10 +957,6 @@ var eventTypes$1 = {
|
||||
}
|
||||
}
|
||||
},
|
||||
customBubblingEventTypes$1 =
|
||||
ReactNativeViewConfigRegistry.customBubblingEventTypes,
|
||||
customDirectEventTypes$1 =
|
||||
ReactNativeViewConfigRegistry.customDirectEventTypes,
|
||||
ReactNativeBridgeEventPlugin = {
|
||||
eventTypes: ReactNativeViewConfigRegistry.eventTypes,
|
||||
extractEvents: function(
|
||||
@@ -970,8 +966,10 @@ var eventTypes$1 = {
|
||||
nativeEventTarget
|
||||
) {
|
||||
if (null == targetInst) return null;
|
||||
var bubbleDispatchConfig = customBubblingEventTypes$1[topLevelType],
|
||||
directDispatchConfig = customDirectEventTypes$1[topLevelType];
|
||||
var bubbleDispatchConfig =
|
||||
ReactNativeViewConfigRegistry.customBubblingEventTypes[topLevelType],
|
||||
directDispatchConfig =
|
||||
ReactNativeViewConfigRegistry.customDirectEventTypes[topLevelType];
|
||||
invariant(
|
||||
bubbleDispatchConfig || directDispatchConfig,
|
||||
'Unsupported top level event type "%s" dispatched',
|
||||
@@ -1506,7 +1504,7 @@ function dispatchEvent(target, topLevelType, nativeEvent) {
|
||||
function shim$1() {
|
||||
invariant(
|
||||
!1,
|
||||
"The current renderer does not support hyration. This error is likely caused by a bug in React. Please file an issue."
|
||||
"The current renderer does not support hydration. This error is likely caused by a bug in React. Please file an issue."
|
||||
);
|
||||
}
|
||||
var nextReactTag = 2;
|
||||
@@ -1620,17 +1618,19 @@ function getStackByFiberInDevAndProd(workInProgress) {
|
||||
var info = "";
|
||||
do {
|
||||
a: switch (workInProgress.tag) {
|
||||
case 2:
|
||||
case 16:
|
||||
case 0:
|
||||
case 1:
|
||||
case 5:
|
||||
case 8:
|
||||
case 13:
|
||||
case 3:
|
||||
case 4:
|
||||
case 6:
|
||||
case 7:
|
||||
case 10:
|
||||
case 9:
|
||||
var JSCompiler_inline_result = "";
|
||||
break a;
|
||||
default:
|
||||
var owner = workInProgress._debugOwner,
|
||||
source = workInProgress._debugSource,
|
||||
name = getComponentName(workInProgress.type);
|
||||
var JSCompiler_inline_result = null;
|
||||
JSCompiler_inline_result = null;
|
||||
owner && (JSCompiler_inline_result = getComponentName(owner.type));
|
||||
owner = name;
|
||||
name = "";
|
||||
@@ -1644,9 +1644,6 @@ function getStackByFiberInDevAndProd(workInProgress) {
|
||||
: JSCompiler_inline_result &&
|
||||
(name = " (created by " + JSCompiler_inline_result + ")");
|
||||
JSCompiler_inline_result = "\n in " + (owner || "Unknown") + name;
|
||||
break a;
|
||||
default:
|
||||
JSCompiler_inline_result = "";
|
||||
}
|
||||
info += JSCompiler_inline_result;
|
||||
workInProgress = workInProgress.return;
|
||||
@@ -3437,7 +3434,8 @@ function updateMemoComponent(
|
||||
"function" === typeof type &&
|
||||
!shouldConstruct(type) &&
|
||||
void 0 === type.defaultProps &&
|
||||
null === Component.compare
|
||||
null === Component.compare &&
|
||||
void 0 === Component.defaultProps
|
||||
)
|
||||
return (
|
||||
(workInProgress.tag = 15),
|
||||
@@ -3885,7 +3883,6 @@ function updateSuspenseComponent(
|
||||
current$$1.pendingProps,
|
||||
0
|
||||
);
|
||||
renderExpirationTime.effectTag |= 2;
|
||||
0 === (workInProgress.mode & 1) &&
|
||||
((nextDidTimeout =
|
||||
null !== workInProgress.memoizedState
|
||||
@@ -3905,7 +3902,6 @@ function updateSuspenseComponent(
|
||||
nextProps,
|
||||
mode.expirationTime
|
||||
);
|
||||
nextProps.effectTag |= 2;
|
||||
mode = renderExpirationTime;
|
||||
renderExpirationTime.childExpirationTime = 0;
|
||||
renderExpirationTime = nextProps;
|
||||
@@ -3920,9 +3916,7 @@ function updateSuspenseComponent(
|
||||
else if (((current$$1 = current$$1.child), nextDidTimeout)) {
|
||||
nextDidTimeout = nextProps.fallback;
|
||||
nextProps = createFiberFromFragment(null, mode, 0, null);
|
||||
nextProps.effectTag |= 2;
|
||||
nextProps.child = current$$1;
|
||||
current$$1.return = nextProps;
|
||||
0 === (workInProgress.mode & 1) &&
|
||||
(nextProps.child =
|
||||
null !== workInProgress.memoizedState
|
||||
@@ -4170,8 +4164,9 @@ function beginWork(current$$1, workInProgress, renderExpirationTime) {
|
||||
default:
|
||||
invariant(
|
||||
!1,
|
||||
"Element type is invalid. Received a promise that resolves to: %s. Promise elements must resolve to a class or function.",
|
||||
current$$1
|
||||
"Element type is invalid. Received a promise that resolves to: %s. Lazy element type must resolve to a class or function.%s",
|
||||
current$$1,
|
||||
""
|
||||
);
|
||||
}
|
||||
return getDerivedStateFromProps;
|
||||
@@ -4479,9 +4474,10 @@ function beginWork(current$$1, workInProgress, renderExpirationTime) {
|
||||
return (
|
||||
(context = workInProgress.type),
|
||||
(hasContext = resolveDefaultProps(
|
||||
context.type,
|
||||
context,
|
||||
workInProgress.pendingProps
|
||||
)),
|
||||
(hasContext = resolveDefaultProps(context.type, hasContext)),
|
||||
updateMemoComponent(
|
||||
current$$1,
|
||||
workInProgress,
|
||||
@@ -4906,14 +4902,7 @@ function throwException(
|
||||
thenable.then(returnFiber, returnFiber);
|
||||
if (0 === (value.mode & 1)) {
|
||||
value.effectTag |= 64;
|
||||
reconcileChildren(
|
||||
sourceFiber.alternate,
|
||||
sourceFiber,
|
||||
null,
|
||||
renderExpirationTime
|
||||
);
|
||||
sourceFiber.effectTag &= -1025;
|
||||
sourceFiber.effectTag &= -933;
|
||||
sourceFiber.effectTag &= -1957;
|
||||
1 === sourceFiber.tag &&
|
||||
null === sourceFiber.alternate &&
|
||||
(sourceFiber.tag = 17);
|
||||
@@ -5033,7 +5022,7 @@ var DispatcherWithoutHooks = { readContext: readContext },
|
||||
invariant(
|
||||
null != tracing.__interactionsRef &&
|
||||
null != tracing.__interactionsRef.current,
|
||||
"It is not supported to run the profiling version of a renderer (for example, `react-dom/profiling`) without also replacing the `schedule/tracing` module with `schedule/tracing-profiling`. Your bundler might have a setting for aliasing both modules. Learn more at http://fb.me/react-profiling"
|
||||
"It is not supported to run the profiling version of a renderer (for example, `react-dom/profiling`) without also replacing the `scheduler/tracing` module with `scheduler/tracing-profiling`. Your bundler might have a setting for aliasing both modules. Learn more at http://fb.me/react-profiling"
|
||||
);
|
||||
var isWorking = !1,
|
||||
nextUnitOfWork = null,
|
||||
@@ -5171,9 +5160,14 @@ function commitAllHostEffects() {
|
||||
}
|
||||
effectTag.return = null;
|
||||
effectTag.child = null;
|
||||
effectTag.alternate &&
|
||||
((effectTag.alternate.child = null),
|
||||
(effectTag.alternate.return = null));
|
||||
effectTag.memoizedState = null;
|
||||
effectTag.updateQueue = null;
|
||||
effectTag = effectTag.alternate;
|
||||
null !== effectTag &&
|
||||
((effectTag.return = null),
|
||||
(effectTag.child = null),
|
||||
(effectTag.memoizedState = null),
|
||||
(effectTag.updateQueue = null));
|
||||
}
|
||||
nextEffect = nextEffect.nextEffect;
|
||||
}
|
||||
@@ -5586,20 +5580,22 @@ function completeUnitOfWork(workInProgress) {
|
||||
break a;
|
||||
}
|
||||
fiber = null !== fiber;
|
||||
viewConfig = null !== current && null !== current.memoizedState;
|
||||
renderExpirationTime =
|
||||
null !== current && null !== current.memoizedState;
|
||||
null !== current &&
|
||||
!fiber &&
|
||||
viewConfig &&
|
||||
renderExpirationTime &&
|
||||
((current = current.child.sibling),
|
||||
null !== current &&
|
||||
reconcileChildFibers(
|
||||
current$$1,
|
||||
current,
|
||||
null,
|
||||
renderExpirationTime
|
||||
));
|
||||
((viewConfig = current$$1.firstEffect),
|
||||
null !== viewConfig
|
||||
? ((current$$1.firstEffect = current),
|
||||
(current.nextEffect = viewConfig))
|
||||
: ((current$$1.firstEffect = current$$1.lastEffect = current),
|
||||
(current.nextEffect = null)),
|
||||
(current.effectTag = 8)));
|
||||
if (
|
||||
fiber !== viewConfig ||
|
||||
fiber !== renderExpirationTime ||
|
||||
(0 === (current$$1.effectTag & 1) && fiber)
|
||||
)
|
||||
current$$1.effectTag |= 4;
|
||||
@@ -5959,9 +5955,10 @@ function scheduleWorkToRoot(fiber, expirationTime) {
|
||||
}
|
||||
node = node.return;
|
||||
}
|
||||
if (null === root) return null;
|
||||
fiber = tracing.__interactionsRef.current;
|
||||
if (0 < fiber.size) {
|
||||
if (
|
||||
null !== root &&
|
||||
((fiber = tracing.__interactionsRef.current), 0 < fiber.size)
|
||||
) {
|
||||
alternate = root.pendingInteractionMap;
|
||||
var pendingInteractions = alternate.get(expirationTime);
|
||||
null != pendingInteractions
|
||||
@@ -6290,7 +6287,7 @@ function onUncaughtError(error) {
|
||||
nextFlushedRoot.expirationTime = 0;
|
||||
hasUnhandledError || ((hasUnhandledError = !0), (unhandledError = error));
|
||||
}
|
||||
function findHostInstance$1(component) {
|
||||
function findHostInstance(component) {
|
||||
var fiber = component._reactInternalFiber;
|
||||
void 0 === fiber &&
|
||||
("function" === typeof component.render
|
||||
@@ -6403,7 +6400,7 @@ function findNodeHandle(componentOrHandle) {
|
||||
if (componentOrHandle._nativeTag) return componentOrHandle._nativeTag;
|
||||
if (componentOrHandle.canonical && componentOrHandle.canonical._nativeTag)
|
||||
return componentOrHandle.canonical._nativeTag;
|
||||
componentOrHandle = findHostInstance$1(componentOrHandle);
|
||||
componentOrHandle = findHostInstance(componentOrHandle);
|
||||
return null == componentOrHandle
|
||||
? componentOrHandle
|
||||
: componentOrHandle.canonical
|
||||
@@ -6499,7 +6496,7 @@ var roots = new Map(),
|
||||
};
|
||||
return ReactNativeComponent;
|
||||
})(React.Component);
|
||||
})(findNodeHandle, findHostInstance$1),
|
||||
})(findNodeHandle, findHostInstance),
|
||||
findNodeHandle: findNodeHandle,
|
||||
render: function(element, containerTag, callback) {
|
||||
var root = roots.get(containerTag);
|
||||
@@ -6612,7 +6609,7 @@ var roots = new Map(),
|
||||
TextInputState.blurTextInput(findNodeHandle(this));
|
||||
}
|
||||
};
|
||||
})(findNodeHandle, findHostInstance$1)
|
||||
})(findNodeHandle, findHostInstance)
|
||||
}
|
||||
};
|
||||
(function(devToolsConfig) {
|
||||
|
||||
@@ -956,10 +956,6 @@ var eventTypes$1 = {
|
||||
}
|
||||
}
|
||||
},
|
||||
customBubblingEventTypes$1 =
|
||||
ReactNativeViewConfigRegistry.customBubblingEventTypes,
|
||||
customDirectEventTypes$1 =
|
||||
ReactNativeViewConfigRegistry.customDirectEventTypes,
|
||||
ReactNativeBridgeEventPlugin = {
|
||||
eventTypes: ReactNativeViewConfigRegistry.eventTypes,
|
||||
extractEvents: function(
|
||||
@@ -969,8 +965,10 @@ var eventTypes$1 = {
|
||||
nativeEventTarget
|
||||
) {
|
||||
if (null == targetInst) return null;
|
||||
var bubbleDispatchConfig = customBubblingEventTypes$1[topLevelType],
|
||||
directDispatchConfig = customDirectEventTypes$1[topLevelType];
|
||||
var bubbleDispatchConfig =
|
||||
ReactNativeViewConfigRegistry.customBubblingEventTypes[topLevelType],
|
||||
directDispatchConfig =
|
||||
ReactNativeViewConfigRegistry.customDirectEventTypes[topLevelType];
|
||||
invariant(
|
||||
bubbleDispatchConfig || directDispatchConfig,
|
||||
'Unsupported top level event type "%s" dispatched',
|
||||
@@ -1077,9 +1075,6 @@ function _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam) {
|
||||
});
|
||||
}
|
||||
RCTEventEmitter.register({
|
||||
getListener: getListener,
|
||||
registrationNames: registrationNameModules,
|
||||
_receiveRootNodeIDEvent: _receiveRootNodeIDEvent,
|
||||
receiveEvent: function(rootNodeID, topLevelType, nativeEventParam) {
|
||||
_receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam);
|
||||
},
|
||||
@@ -1606,7 +1601,7 @@ function setTimeoutCallback() {
|
||||
function shim$1() {
|
||||
invariant(
|
||||
!1,
|
||||
"The current renderer does not support hyration. This error is likely caused by a bug in React. Please file an issue."
|
||||
"The current renderer does not support hydration. This error is likely caused by a bug in React. Please file an issue."
|
||||
);
|
||||
}
|
||||
var UPDATE_SIGNAL = {},
|
||||
@@ -1642,17 +1637,19 @@ function getStackByFiberInDevAndProd(workInProgress) {
|
||||
var info = "";
|
||||
do {
|
||||
a: switch (workInProgress.tag) {
|
||||
case 2:
|
||||
case 16:
|
||||
case 0:
|
||||
case 1:
|
||||
case 5:
|
||||
case 8:
|
||||
case 13:
|
||||
case 3:
|
||||
case 4:
|
||||
case 6:
|
||||
case 7:
|
||||
case 10:
|
||||
case 9:
|
||||
var JSCompiler_inline_result = "";
|
||||
break a;
|
||||
default:
|
||||
var owner = workInProgress._debugOwner,
|
||||
source = workInProgress._debugSource,
|
||||
name = getComponentName(workInProgress.type);
|
||||
var JSCompiler_inline_result = null;
|
||||
JSCompiler_inline_result = null;
|
||||
owner && (JSCompiler_inline_result = getComponentName(owner.type));
|
||||
owner = name;
|
||||
name = "";
|
||||
@@ -1666,9 +1663,6 @@ function getStackByFiberInDevAndProd(workInProgress) {
|
||||
: JSCompiler_inline_result &&
|
||||
(name = " (created by " + JSCompiler_inline_result + ")");
|
||||
JSCompiler_inline_result = "\n in " + (owner || "Unknown") + name;
|
||||
break a;
|
||||
default:
|
||||
JSCompiler_inline_result = "";
|
||||
}
|
||||
info += JSCompiler_inline_result;
|
||||
workInProgress = workInProgress.return;
|
||||
@@ -3402,7 +3396,8 @@ function updateMemoComponent(
|
||||
"function" === typeof type &&
|
||||
!shouldConstruct(type) &&
|
||||
void 0 === type.defaultProps &&
|
||||
null === Component.compare
|
||||
null === Component.compare &&
|
||||
void 0 === Component.defaultProps
|
||||
)
|
||||
return (
|
||||
(workInProgress.tag = 15),
|
||||
@@ -3840,7 +3835,6 @@ function updateSuspenseComponent(
|
||||
nextDidTimeout
|
||||
? ((renderExpirationTime = nextProps.fallback),
|
||||
(nextProps = createWorkInProgress(mode, mode.pendingProps, 0)),
|
||||
(nextProps.effectTag |= 2),
|
||||
0 === (workInProgress.mode & 1) &&
|
||||
((nextDidTimeout =
|
||||
null !== workInProgress.memoizedState
|
||||
@@ -3853,7 +3847,6 @@ function updateSuspenseComponent(
|
||||
renderExpirationTime,
|
||||
current$$1.expirationTime
|
||||
)),
|
||||
(mode.effectTag |= 2),
|
||||
(renderExpirationTime = nextProps),
|
||||
(nextProps.childExpirationTime = 0),
|
||||
(renderExpirationTime.return = mode.return = workInProgress))
|
||||
@@ -3867,9 +3860,7 @@ function updateSuspenseComponent(
|
||||
nextDidTimeout
|
||||
? ((nextDidTimeout = nextProps.fallback),
|
||||
(nextProps = createFiberFromFragment(null, mode, 0, null)),
|
||||
(nextProps.effectTag |= 2),
|
||||
(nextProps.child = current$$1),
|
||||
(current$$1.return = nextProps),
|
||||
0 === (workInProgress.mode & 1) &&
|
||||
(nextProps.child =
|
||||
null !== workInProgress.memoizedState
|
||||
@@ -4105,8 +4096,9 @@ function beginWork(current$$1, workInProgress, renderExpirationTime) {
|
||||
default:
|
||||
invariant(
|
||||
!1,
|
||||
"Element type is invalid. Received a promise that resolves to: %s. Promise elements must resolve to a class or function.",
|
||||
current$$1
|
||||
"Element type is invalid. Received a promise that resolves to: %s. Lazy element type must resolve to a class or function.%s",
|
||||
current$$1,
|
||||
""
|
||||
);
|
||||
}
|
||||
return getDerivedStateFromProps;
|
||||
@@ -4413,9 +4405,10 @@ function beginWork(current$$1, workInProgress, renderExpirationTime) {
|
||||
return (
|
||||
(context = workInProgress.type),
|
||||
(hasContext = resolveDefaultProps(
|
||||
context.type,
|
||||
context,
|
||||
workInProgress.pendingProps
|
||||
)),
|
||||
(hasContext = resolveDefaultProps(context.type, hasContext)),
|
||||
updateMemoComponent(
|
||||
current$$1,
|
||||
workInProgress,
|
||||
@@ -4942,7 +4935,12 @@ function commitWork(current$$1, finishedWork) {
|
||||
}
|
||||
else {
|
||||
if (6 === newProps.tag) throw Error("Not yet implemented.");
|
||||
if (null !== newProps.child) {
|
||||
if (13 === newProps.tag && null !== newProps.memoizedState) {
|
||||
current$$1 = newProps.child.sibling;
|
||||
current$$1.return = newProps;
|
||||
newProps = current$$1;
|
||||
continue;
|
||||
} else if (null !== newProps.child) {
|
||||
newProps.child.return = newProps;
|
||||
newProps = newProps.child;
|
||||
continue;
|
||||
@@ -5225,20 +5223,22 @@ function completeUnitOfWork(workInProgress) {
|
||||
break a;
|
||||
}
|
||||
newProps = null !== newProps;
|
||||
type = null !== current && null !== current.memoizedState;
|
||||
renderExpirationTime =
|
||||
null !== current && null !== current.memoizedState;
|
||||
null !== current &&
|
||||
!newProps &&
|
||||
type &&
|
||||
((current = current.child.sibling),
|
||||
null !== current &&
|
||||
reconcileChildFibers(
|
||||
current$$1,
|
||||
current,
|
||||
null,
|
||||
renderExpirationTime
|
||||
));
|
||||
renderExpirationTime &&
|
||||
((type = current.child.sibling),
|
||||
null !== type &&
|
||||
((current = current$$1.firstEffect),
|
||||
null !== current
|
||||
? ((current$$1.firstEffect = type),
|
||||
(type.nextEffect = current))
|
||||
: ((current$$1.firstEffect = current$$1.lastEffect = type),
|
||||
(type.nextEffect = null)),
|
||||
(type.effectTag = 8)));
|
||||
if (
|
||||
newProps !== type ||
|
||||
newProps !== renderExpirationTime ||
|
||||
(0 === (current$$1.effectTag & 1) && newProps)
|
||||
)
|
||||
current$$1.effectTag |= 4;
|
||||
@@ -5432,14 +5432,7 @@ function renderRoot(root$jscomp$0, isYieldy) {
|
||||
thenable.then(returnFiber$jscomp$0, returnFiber$jscomp$0);
|
||||
if (0 === (value.mode & 1)) {
|
||||
value.effectTag |= 64;
|
||||
reconcileChildren(
|
||||
sourceFiber$jscomp$0.alternate,
|
||||
sourceFiber$jscomp$0,
|
||||
null,
|
||||
returnFiber
|
||||
);
|
||||
sourceFiber$jscomp$0.effectTag &= -1025;
|
||||
sourceFiber$jscomp$0.effectTag &= -933;
|
||||
sourceFiber$jscomp$0.effectTag &= -1957;
|
||||
1 === sourceFiber$jscomp$0.tag &&
|
||||
null === sourceFiber$jscomp$0.alternate &&
|
||||
(sourceFiber$jscomp$0.tag = 17);
|
||||
@@ -5696,7 +5689,7 @@ function scheduleWorkToRoot(fiber, expirationTime) {
|
||||
}
|
||||
node = node.return;
|
||||
}
|
||||
return null === root ? null : root;
|
||||
return root;
|
||||
}
|
||||
function scheduleWork(fiber, expirationTime) {
|
||||
fiber = scheduleWorkToRoot(fiber, expirationTime);
|
||||
@@ -6121,13 +6114,18 @@ function completeRoot(root, finishedWork$jscomp$0, expirationTime) {
|
||||
commitWork(nextEffect.alternate, nextEffect);
|
||||
break;
|
||||
case 8:
|
||||
(prevState = nextEffect),
|
||||
unmountHostComponents(prevState),
|
||||
(prevState.return = null),
|
||||
(prevState.child = null),
|
||||
prevState.alternate &&
|
||||
((prevState.alternate.child = null),
|
||||
(prevState.alternate.return = null));
|
||||
prevState = nextEffect;
|
||||
unmountHostComponents(prevState);
|
||||
prevState.return = null;
|
||||
prevState.child = null;
|
||||
prevState.memoizedState = null;
|
||||
prevState.updateQueue = null;
|
||||
var alternate = prevState.alternate;
|
||||
null !== alternate &&
|
||||
((alternate.return = null),
|
||||
(alternate.child = null),
|
||||
(alternate.memoizedState = null),
|
||||
(alternate.updateQueue = null));
|
||||
}
|
||||
nextEffect = nextEffect.nextEffect;
|
||||
}
|
||||
@@ -6151,24 +6149,24 @@ function completeRoot(root, finishedWork$jscomp$0, expirationTime) {
|
||||
var effectTag$jscomp$0 = nextEffect.effectTag;
|
||||
if (effectTag$jscomp$0 & 36) {
|
||||
var current$$1$jscomp$1 = nextEffect.alternate;
|
||||
current$$1 = nextEffect;
|
||||
prevProps = currentRef;
|
||||
switch (current$$1.tag) {
|
||||
alternate = nextEffect;
|
||||
current$$1 = currentRef;
|
||||
switch (alternate.tag) {
|
||||
case 0:
|
||||
case 11:
|
||||
case 15:
|
||||
break;
|
||||
case 1:
|
||||
var instance$jscomp$0 = current$$1.stateNode;
|
||||
if (current$$1.effectTag & 4)
|
||||
var instance$jscomp$0 = alternate.stateNode;
|
||||
if (alternate.effectTag & 4)
|
||||
if (null === current$$1$jscomp$1)
|
||||
instance$jscomp$0.componentDidMount();
|
||||
else {
|
||||
var prevProps$jscomp$0 =
|
||||
current$$1.elementType === current$$1.type
|
||||
alternate.elementType === alternate.type
|
||||
? current$$1$jscomp$1.memoizedProps
|
||||
: resolveDefaultProps(
|
||||
current$$1.type,
|
||||
alternate.type,
|
||||
current$$1$jscomp$1.memoizedProps
|
||||
);
|
||||
instance$jscomp$0.componentDidUpdate(
|
||||
@@ -6177,32 +6175,32 @@ function completeRoot(root, finishedWork$jscomp$0, expirationTime) {
|
||||
instance$jscomp$0.__reactInternalSnapshotBeforeUpdate
|
||||
);
|
||||
}
|
||||
var updateQueue = current$$1.updateQueue;
|
||||
var updateQueue = alternate.updateQueue;
|
||||
null !== updateQueue &&
|
||||
commitUpdateQueue(
|
||||
current$$1,
|
||||
alternate,
|
||||
updateQueue,
|
||||
instance$jscomp$0,
|
||||
prevProps
|
||||
current$$1
|
||||
);
|
||||
break;
|
||||
case 3:
|
||||
var _updateQueue = current$$1.updateQueue;
|
||||
var _updateQueue = alternate.updateQueue;
|
||||
if (null !== _updateQueue) {
|
||||
prevState = null;
|
||||
if (null !== current$$1.child)
|
||||
switch (current$$1.child.tag) {
|
||||
prevProps = null;
|
||||
if (null !== alternate.child)
|
||||
switch (alternate.child.tag) {
|
||||
case 5:
|
||||
prevState = current$$1.child.stateNode;
|
||||
prevProps = alternate.child.stateNode;
|
||||
break;
|
||||
case 1:
|
||||
prevState = current$$1.child.stateNode;
|
||||
prevProps = alternate.child.stateNode;
|
||||
}
|
||||
commitUpdateQueue(
|
||||
current$$1,
|
||||
alternate,
|
||||
_updateQueue,
|
||||
prevState,
|
||||
prevProps
|
||||
prevProps,
|
||||
current$$1
|
||||
);
|
||||
}
|
||||
break;
|
||||
@@ -6276,7 +6274,7 @@ function onUncaughtError(error) {
|
||||
nextFlushedRoot.expirationTime = 0;
|
||||
hasUnhandledError || ((hasUnhandledError = !0), (unhandledError = error));
|
||||
}
|
||||
function findHostInstance$1(component) {
|
||||
function findHostInstance(component) {
|
||||
var fiber = component._reactInternalFiber;
|
||||
void 0 === fiber &&
|
||||
("function" === typeof component.render
|
||||
@@ -6389,7 +6387,7 @@ function findNodeHandle(componentOrHandle) {
|
||||
if (componentOrHandle._nativeTag) return componentOrHandle._nativeTag;
|
||||
if (componentOrHandle.canonical && componentOrHandle.canonical._nativeTag)
|
||||
return componentOrHandle.canonical._nativeTag;
|
||||
componentOrHandle = findHostInstance$1(componentOrHandle);
|
||||
componentOrHandle = findHostInstance(componentOrHandle);
|
||||
return null == componentOrHandle
|
||||
? componentOrHandle
|
||||
: componentOrHandle.canonical
|
||||
@@ -6485,7 +6483,7 @@ var roots = new Map(),
|
||||
};
|
||||
return ReactNativeComponent;
|
||||
})(React.Component);
|
||||
})(findNodeHandle, findHostInstance$1),
|
||||
})(findNodeHandle, findHostInstance),
|
||||
findNodeHandle: findNodeHandle,
|
||||
render: function(element, containerTag, callback) {
|
||||
var root = roots.get(containerTag);
|
||||
@@ -6598,7 +6596,7 @@ var roots = new Map(),
|
||||
TextInputState.blurTextInput(findNodeHandle(this));
|
||||
}
|
||||
};
|
||||
})(findNodeHandle, findHostInstance$1),
|
||||
})(findNodeHandle, findHostInstance),
|
||||
computeComponentStackForErrorReporting: function(reactTag) {
|
||||
return (reactTag = getInstanceFromTag(reactTag))
|
||||
? getStackByFiberInDevAndProd(reactTag)
|
||||
|
||||
@@ -957,10 +957,6 @@ var eventTypes$1 = {
|
||||
}
|
||||
}
|
||||
},
|
||||
customBubblingEventTypes$1 =
|
||||
ReactNativeViewConfigRegistry.customBubblingEventTypes,
|
||||
customDirectEventTypes$1 =
|
||||
ReactNativeViewConfigRegistry.customDirectEventTypes,
|
||||
ReactNativeBridgeEventPlugin = {
|
||||
eventTypes: ReactNativeViewConfigRegistry.eventTypes,
|
||||
extractEvents: function(
|
||||
@@ -970,8 +966,10 @@ var eventTypes$1 = {
|
||||
nativeEventTarget
|
||||
) {
|
||||
if (null == targetInst) return null;
|
||||
var bubbleDispatchConfig = customBubblingEventTypes$1[topLevelType],
|
||||
directDispatchConfig = customDirectEventTypes$1[topLevelType];
|
||||
var bubbleDispatchConfig =
|
||||
ReactNativeViewConfigRegistry.customBubblingEventTypes[topLevelType],
|
||||
directDispatchConfig =
|
||||
ReactNativeViewConfigRegistry.customDirectEventTypes[topLevelType];
|
||||
invariant(
|
||||
bubbleDispatchConfig || directDispatchConfig,
|
||||
'Unsupported top level event type "%s" dispatched',
|
||||
@@ -1078,9 +1076,6 @@ function _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam) {
|
||||
});
|
||||
}
|
||||
RCTEventEmitter.register({
|
||||
getListener: getListener,
|
||||
registrationNames: registrationNameModules,
|
||||
_receiveRootNodeIDEvent: _receiveRootNodeIDEvent,
|
||||
receiveEvent: function(rootNodeID, topLevelType, nativeEventParam) {
|
||||
_receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam);
|
||||
},
|
||||
@@ -1607,7 +1602,7 @@ function setTimeoutCallback() {
|
||||
function shim$1() {
|
||||
invariant(
|
||||
!1,
|
||||
"The current renderer does not support hyration. This error is likely caused by a bug in React. Please file an issue."
|
||||
"The current renderer does not support hydration. This error is likely caused by a bug in React. Please file an issue."
|
||||
);
|
||||
}
|
||||
var UPDATE_SIGNAL = {},
|
||||
@@ -1643,17 +1638,19 @@ function getStackByFiberInDevAndProd(workInProgress) {
|
||||
var info = "";
|
||||
do {
|
||||
a: switch (workInProgress.tag) {
|
||||
case 2:
|
||||
case 16:
|
||||
case 0:
|
||||
case 1:
|
||||
case 5:
|
||||
case 8:
|
||||
case 13:
|
||||
case 3:
|
||||
case 4:
|
||||
case 6:
|
||||
case 7:
|
||||
case 10:
|
||||
case 9:
|
||||
var JSCompiler_inline_result = "";
|
||||
break a;
|
||||
default:
|
||||
var owner = workInProgress._debugOwner,
|
||||
source = workInProgress._debugSource,
|
||||
name = getComponentName(workInProgress.type);
|
||||
var JSCompiler_inline_result = null;
|
||||
JSCompiler_inline_result = null;
|
||||
owner && (JSCompiler_inline_result = getComponentName(owner.type));
|
||||
owner = name;
|
||||
name = "";
|
||||
@@ -1667,9 +1664,6 @@ function getStackByFiberInDevAndProd(workInProgress) {
|
||||
: JSCompiler_inline_result &&
|
||||
(name = " (created by " + JSCompiler_inline_result + ")");
|
||||
JSCompiler_inline_result = "\n in " + (owner || "Unknown") + name;
|
||||
break a;
|
||||
default:
|
||||
JSCompiler_inline_result = "";
|
||||
}
|
||||
info += JSCompiler_inline_result;
|
||||
workInProgress = workInProgress.return;
|
||||
@@ -3460,7 +3454,8 @@ function updateMemoComponent(
|
||||
"function" === typeof type &&
|
||||
!shouldConstruct(type) &&
|
||||
void 0 === type.defaultProps &&
|
||||
null === Component.compare
|
||||
null === Component.compare &&
|
||||
void 0 === Component.defaultProps
|
||||
)
|
||||
return (
|
||||
(workInProgress.tag = 15),
|
||||
@@ -3908,7 +3903,6 @@ function updateSuspenseComponent(
|
||||
current$$1.pendingProps,
|
||||
0
|
||||
);
|
||||
renderExpirationTime.effectTag |= 2;
|
||||
0 === (workInProgress.mode & 1) &&
|
||||
((nextDidTimeout =
|
||||
null !== workInProgress.memoizedState
|
||||
@@ -3928,7 +3922,6 @@ function updateSuspenseComponent(
|
||||
nextProps,
|
||||
mode.expirationTime
|
||||
);
|
||||
nextProps.effectTag |= 2;
|
||||
mode = renderExpirationTime;
|
||||
renderExpirationTime.childExpirationTime = 0;
|
||||
renderExpirationTime = nextProps;
|
||||
@@ -3943,9 +3936,7 @@ function updateSuspenseComponent(
|
||||
else if (((current$$1 = current$$1.child), nextDidTimeout)) {
|
||||
nextDidTimeout = nextProps.fallback;
|
||||
nextProps = createFiberFromFragment(null, mode, 0, null);
|
||||
nextProps.effectTag |= 2;
|
||||
nextProps.child = current$$1;
|
||||
current$$1.return = nextProps;
|
||||
0 === (workInProgress.mode & 1) &&
|
||||
(nextProps.child =
|
||||
null !== workInProgress.memoizedState
|
||||
@@ -4193,8 +4184,9 @@ function beginWork(current$$1, workInProgress, renderExpirationTime) {
|
||||
default:
|
||||
invariant(
|
||||
!1,
|
||||
"Element type is invalid. Received a promise that resolves to: %s. Promise elements must resolve to a class or function.",
|
||||
current$$1
|
||||
"Element type is invalid. Received a promise that resolves to: %s. Lazy element type must resolve to a class or function.%s",
|
||||
current$$1,
|
||||
""
|
||||
);
|
||||
}
|
||||
return getDerivedStateFromProps;
|
||||
@@ -4502,9 +4494,10 @@ function beginWork(current$$1, workInProgress, renderExpirationTime) {
|
||||
return (
|
||||
(context = workInProgress.type),
|
||||
(hasContext = resolveDefaultProps(
|
||||
context.type,
|
||||
context,
|
||||
workInProgress.pendingProps
|
||||
)),
|
||||
(hasContext = resolveDefaultProps(context.type, hasContext)),
|
||||
updateMemoComponent(
|
||||
current$$1,
|
||||
workInProgress,
|
||||
@@ -5031,7 +5024,12 @@ function commitWork(current$$1, finishedWork) {
|
||||
}
|
||||
else {
|
||||
if (6 === newProps.tag) throw Error("Not yet implemented.");
|
||||
if (null !== newProps.child) {
|
||||
if (13 === newProps.tag && null !== newProps.memoizedState) {
|
||||
current$$1 = newProps.child.sibling;
|
||||
current$$1.return = newProps;
|
||||
newProps = current$$1;
|
||||
continue;
|
||||
} else if (null !== newProps.child) {
|
||||
newProps.child.return = newProps;
|
||||
newProps = newProps.child;
|
||||
continue;
|
||||
@@ -5149,14 +5147,7 @@ function throwException(
|
||||
thenable.then(returnFiber, returnFiber);
|
||||
if (0 === (value.mode & 1)) {
|
||||
value.effectTag |= 64;
|
||||
reconcileChildren(
|
||||
sourceFiber.alternate,
|
||||
sourceFiber,
|
||||
null,
|
||||
renderExpirationTime
|
||||
);
|
||||
sourceFiber.effectTag &= -1025;
|
||||
sourceFiber.effectTag &= -933;
|
||||
sourceFiber.effectTag &= -1957;
|
||||
1 === sourceFiber.tag &&
|
||||
null === sourceFiber.alternate &&
|
||||
(sourceFiber.tag = 17);
|
||||
@@ -5276,7 +5267,7 @@ var DispatcherWithoutHooks = { readContext: readContext },
|
||||
invariant(
|
||||
null != tracing.__interactionsRef &&
|
||||
null != tracing.__interactionsRef.current,
|
||||
"It is not supported to run the profiling version of a renderer (for example, `react-dom/profiling`) without also replacing the `schedule/tracing` module with `schedule/tracing-profiling`. Your bundler might have a setting for aliasing both modules. Learn more at http://fb.me/react-profiling"
|
||||
"It is not supported to run the profiling version of a renderer (for example, `react-dom/profiling`) without also replacing the `scheduler/tracing` module with `scheduler/tracing-profiling`. Your bundler might have a setting for aliasing both modules. Learn more at http://fb.me/react-profiling"
|
||||
);
|
||||
var isWorking = !1,
|
||||
nextUnitOfWork = null,
|
||||
@@ -5356,9 +5347,14 @@ function commitAllHostEffects() {
|
||||
unmountHostComponents(effectTag),
|
||||
(effectTag.return = null),
|
||||
(effectTag.child = null),
|
||||
effectTag.alternate &&
|
||||
((effectTag.alternate.child = null),
|
||||
(effectTag.alternate.return = null));
|
||||
(effectTag.memoizedState = null),
|
||||
(effectTag.updateQueue = null),
|
||||
(effectTag = effectTag.alternate),
|
||||
null !== effectTag &&
|
||||
((effectTag.return = null),
|
||||
(effectTag.child = null),
|
||||
(effectTag.memoizedState = null),
|
||||
(effectTag.updateQueue = null));
|
||||
}
|
||||
nextEffect = nextEffect.nextEffect;
|
||||
}
|
||||
@@ -5769,19 +5765,24 @@ function completeUnitOfWork(workInProgress) {
|
||||
break a;
|
||||
}
|
||||
fiber = null !== fiber;
|
||||
type = null !== current && null !== current.memoizedState;
|
||||
renderExpirationTime =
|
||||
null !== current && null !== current.memoizedState;
|
||||
null !== current &&
|
||||
!fiber &&
|
||||
type &&
|
||||
((current = current.child.sibling),
|
||||
null !== current &&
|
||||
reconcileChildFibers(
|
||||
current$$1,
|
||||
current,
|
||||
null,
|
||||
renderExpirationTime
|
||||
));
|
||||
if (fiber !== type || (0 === (current$$1.effectTag & 1) && fiber))
|
||||
renderExpirationTime &&
|
||||
((type = current.child.sibling),
|
||||
null !== type &&
|
||||
((current = current$$1.firstEffect),
|
||||
null !== current
|
||||
? ((current$$1.firstEffect = type),
|
||||
(type.nextEffect = current))
|
||||
: ((current$$1.firstEffect = current$$1.lastEffect = type),
|
||||
(type.nextEffect = null)),
|
||||
(type.effectTag = 8)));
|
||||
if (
|
||||
fiber !== renderExpirationTime ||
|
||||
(0 === (current$$1.effectTag & 1) && fiber)
|
||||
)
|
||||
current$$1.effectTag |= 4;
|
||||
break;
|
||||
case 7:
|
||||
@@ -6147,9 +6148,10 @@ function scheduleWorkToRoot(fiber, expirationTime) {
|
||||
}
|
||||
node = node.return;
|
||||
}
|
||||
if (null === root) return null;
|
||||
fiber = tracing.__interactionsRef.current;
|
||||
if (0 < fiber.size) {
|
||||
if (
|
||||
null !== root &&
|
||||
((fiber = tracing.__interactionsRef.current), 0 < fiber.size)
|
||||
) {
|
||||
alternate = root.pendingInteractionMap;
|
||||
var pendingInteractions = alternate.get(expirationTime);
|
||||
null != pendingInteractions
|
||||
@@ -6478,7 +6480,7 @@ function onUncaughtError(error) {
|
||||
nextFlushedRoot.expirationTime = 0;
|
||||
hasUnhandledError || ((hasUnhandledError = !0), (unhandledError = error));
|
||||
}
|
||||
function findHostInstance$1(component) {
|
||||
function findHostInstance(component) {
|
||||
var fiber = component._reactInternalFiber;
|
||||
void 0 === fiber &&
|
||||
("function" === typeof component.render
|
||||
@@ -6591,7 +6593,7 @@ function findNodeHandle(componentOrHandle) {
|
||||
if (componentOrHandle._nativeTag) return componentOrHandle._nativeTag;
|
||||
if (componentOrHandle.canonical && componentOrHandle.canonical._nativeTag)
|
||||
return componentOrHandle.canonical._nativeTag;
|
||||
componentOrHandle = findHostInstance$1(componentOrHandle);
|
||||
componentOrHandle = findHostInstance(componentOrHandle);
|
||||
return null == componentOrHandle
|
||||
? componentOrHandle
|
||||
: componentOrHandle.canonical
|
||||
@@ -6687,7 +6689,7 @@ var roots = new Map(),
|
||||
};
|
||||
return ReactNativeComponent;
|
||||
})(React.Component);
|
||||
})(findNodeHandle, findHostInstance$1),
|
||||
})(findNodeHandle, findHostInstance),
|
||||
findNodeHandle: findNodeHandle,
|
||||
render: function(element, containerTag, callback) {
|
||||
var root = roots.get(containerTag);
|
||||
@@ -6805,7 +6807,7 @@ var roots = new Map(),
|
||||
TextInputState.blurTextInput(findNodeHandle(this));
|
||||
}
|
||||
};
|
||||
})(findNodeHandle, findHostInstance$1),
|
||||
})(findNodeHandle, findHostInstance),
|
||||
computeComponentStackForErrorReporting: function(reactTag) {
|
||||
return (reactTag = getInstanceFromTag(reactTag))
|
||||
? getStackByFiberInDevAndProd(reactTag)
|
||||
|
||||
@@ -59,6 +59,7 @@ export type ReactContext<T> = {
|
||||
|
||||
_currentValue: T,
|
||||
_currentValue2: T,
|
||||
_threadCount: number,
|
||||
|
||||
// DEV only
|
||||
_currentRenderer?: Object | null,
|
||||
|
||||
@@ -110,7 +110,21 @@ static UIColor *defaultPlaceholderColor()
|
||||
|
||||
- (void)setAttributedText:(NSAttributedString *)attributedText
|
||||
{
|
||||
[super setAttributedText:attributedText];
|
||||
// Using `setAttributedString:` while user is typing breaks some internal mechanics
|
||||
// when entering complex input languages such as Chinese, Korean or Japanese.
|
||||
// see: https://github.com/facebook/react-native/issues/19339
|
||||
|
||||
// We try to avoid calling this method as much as we can.
|
||||
// If the text has changed, there is nothing we can do.
|
||||
if (![super.attributedText.string isEqualToString:attributedText.string]) {
|
||||
[super setAttributedText:attributedText];
|
||||
} else {
|
||||
// But if the text is preserved, we just copying the attributes from the source string.
|
||||
if (![super.attributedText isEqualToAttributedString:attributedText]) {
|
||||
[self copyTextAttributesFrom:attributedText];
|
||||
}
|
||||
}
|
||||
|
||||
[self textDidChange];
|
||||
}
|
||||
|
||||
@@ -241,4 +255,20 @@ static UIColor *defaultPlaceholderColor()
|
||||
_placeholderView.hidden = !isVisible;
|
||||
}
|
||||
|
||||
#pragma mark - Utility Methods
|
||||
|
||||
- (void)copyTextAttributesFrom:(NSAttributedString *)sourceString
|
||||
{
|
||||
[self.textStorage beginEditing];
|
||||
|
||||
NSTextStorage *textStorage = self.textStorage;
|
||||
[sourceString enumerateAttributesInRange:NSMakeRange(0, sourceString.length)
|
||||
options:NSAttributedStringEnumerationReverse
|
||||
usingBlock:^(NSDictionary<NSAttributedStringKey,id> * _Nonnull attrs, NSRange range, BOOL * _Nonnull stop) {
|
||||
[textStorage setAttributes:attrs range:range];
|
||||
}];
|
||||
|
||||
[self.textStorage endEditing];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -14,6 +14,7 @@ const invariant = require('fbjs/lib/invariant');
|
||||
|
||||
let showedListViewDeprecation = false;
|
||||
let showedSwipeableListViewDeprecation = false;
|
||||
let showedWebWiewDeprecation = false;
|
||||
|
||||
// Export React, plus some native additions.
|
||||
module.exports = {
|
||||
@@ -170,6 +171,15 @@ module.exports = {
|
||||
return require('VirtualizedList');
|
||||
},
|
||||
get WebView() {
|
||||
if (!showedWebWiewDeprecation) {
|
||||
console.warn(
|
||||
'WebView has been extracted from react-native core and will be removed in a future release. ' +
|
||||
"It can now be installed and imported from 'react-native-webview' instead of 'react-native'. " +
|
||||
'See https://github.com/react-native-community/react-native-webview for more informations.',
|
||||
);
|
||||
|
||||
showedWebWiewDeprecation = true;
|
||||
}
|
||||
return require('WebView');
|
||||
},
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ function mergeInto(one, two) {
|
||||
if (two != null) {
|
||||
checkMergeObjectArg(two);
|
||||
for (var key in two) {
|
||||
if (!two.hasOwnProperty(key)) {
|
||||
if (!Object.prototype.hasOwnProperty.call(two, key)) {
|
||||
continue;
|
||||
}
|
||||
one[key] = two[key];
|
||||
|
||||
@@ -104,10 +104,10 @@ EXTERNAL SOURCES:
|
||||
SPEC CHECKSUMS:
|
||||
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
|
||||
DoubleConversion: bb338842f62ab1d708ceb63ec3d999f0f3d98ecd
|
||||
Folly: cd7933b82a5f7673ed71bafe631f44a575ae77ab
|
||||
Folly: de497beb10f102453a1afa9edbf8cf8a251890de
|
||||
glog: aefd1eb5dda2ab95ba0938556f34b98e2da3a60d
|
||||
React: 9b873b38b92ed8012d7cdf3b965477095ed364c4
|
||||
yoga: b1ce48b6cf950b98deae82838f5173ea7cf89e85
|
||||
yoga: 0885622311729a02c2bc02dca97167787a51488b
|
||||
|
||||
PODFILE CHECKSUM: 7af77fbc34af9646e8c6389e7e2c0b4663bb16d9
|
||||
|
||||
|
||||
@@ -58,6 +58,29 @@ Run the following commands from the react-native folder:
|
||||
|
||||
_Note: The native libs are still built using gradle. Full build with buck is coming soon(tm)._
|
||||
|
||||
## Running Detox Tests on iOS
|
||||
|
||||
Install Detox from [here](https://github.com/wix/Detox/blob/master/docs/Introduction.GettingStarted.md).
|
||||
|
||||
To run the e2e tests locally, run the following commands from the react-native folder:
|
||||
|
||||
yarn build-ios-e2e
|
||||
yarn test-ios-e2e
|
||||
|
||||
These are the equivalent of running:
|
||||
|
||||
detox build -c ios.sim.release
|
||||
detox test -c ios.sim.release --cleanup
|
||||
|
||||
These build the app in Release mode, so the production code is bundled and included in the built app.
|
||||
|
||||
When developing E2E tests, you may want to run in development mode, so that changes to the production code show up immediately. To do this, run:
|
||||
|
||||
detox build -c ios.sim.debug
|
||||
detox test -c ios.sim.debug
|
||||
|
||||
You will also need to have Metro Bundler running in another terminal. Note that if you've previously run the E2E tests in release mode, you may need to delete the `RNTester/build` folder before rerunning `detox build`.
|
||||
|
||||
## Built from source
|
||||
|
||||
Building the app on both iOS and Android means building the React Native framework from source. This way you're running the latest native and JS code the way you see it in your clone of the github repo.
|
||||
|
||||
@@ -131,6 +131,7 @@
|
||||
C654F0B31EB34A73000B7A9A /* RNTesterTestModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C654F0B21EB34A73000B7A9A /* RNTesterTestModule.m */; };
|
||||
C654F17E1EB34D24000B7A9A /* RNTesterTestModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C654F0B21EB34A73000B7A9A /* RNTesterTestModule.m */; };
|
||||
D85B829E1AB6D5D7003F4FE2 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D85B829C1AB6D5CE003F4FE2 /* libRCTVibration.a */; };
|
||||
E77B20F321C481F8007FDF6D /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDEBC7DA214C681C00DD5AC8 /* JavaScriptCore.framework */; };
|
||||
ED2970992150247000B7C4FE /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ED2970982150247000B7C4FE /* JavaScriptCore.framework */; };
|
||||
EDEBC856214C774100DD5AC8 /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDEBC7DA214C681C00DD5AC8 /* JavaScriptCore.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
@@ -573,6 +574,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
E77B20F321C481F8007FDF6D /* JavaScriptCore.framework in Frameworks */,
|
||||
19BA89031F8439A700741C5A /* libRCTBlob.a in Frameworks */,
|
||||
192F69DA1E8240E2008692C7 /* libRCTAnimation.a in Frameworks */,
|
||||
14D6D71E1B2222EF001FB087 /* libRCTActionSheet.a in Frameworks */,
|
||||
@@ -1682,7 +1684,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "export NODE_BINARY=node\n$SRCROOT/../scripts/react-native-xcode.sh RNTester/js/RNTesterApp.ios.js";
|
||||
shellScript = "export NODE_BINARY=node\n$SRCROOT/../scripts/react-native-xcode.sh RNTester/js/RNTesterApp.ios.js\n";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>UIStatusBarStyle</key>
|
||||
<string>UIStatusBarStyleBlackTranslucent</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
|
||||
@@ -49,20 +49,21 @@
|
||||
configurationBlock:nil];
|
||||
}
|
||||
|
||||
- (void)testTheTester_ExpectError
|
||||
{
|
||||
[_runner runTest:_cmd
|
||||
module:@"IntegrationTestHarnessTest"
|
||||
initialProps:@{@"shouldThrow": @YES}
|
||||
configurationBlock:nil
|
||||
expectErrorRegex:@"because shouldThrow"];
|
||||
}
|
||||
// Disabled
|
||||
//- (void)testTheTester_ExpectError
|
||||
//{
|
||||
// [_runner runTest:_cmd
|
||||
// module:@"IntegrationTestHarnessTest"
|
||||
// initialProps:@{@"shouldThrow": @YES}
|
||||
//configurationBlock:nil
|
||||
// expectErrorRegex:@"because shouldThrow"];
|
||||
//}
|
||||
|
||||
#pragma mark - JS tests
|
||||
|
||||
// This list should be kept in sync with IntegrationTestsApp.js
|
||||
RCT_TEST(IntegrationTestHarnessTest)
|
||||
RCT_TEST(TimersTest)
|
||||
// RCT_TEST(TimersTest) // Disabled due to issue introduced in 61346d3
|
||||
RCT_TEST(AsyncStorageTest)
|
||||
RCT_TEST(AppEventsTest)
|
||||
//RCT_TEST(ImageCachePolicyTest) // This test never passed.
|
||||
@@ -71,7 +72,7 @@ RCT_TEST(ImageSnapshotTest)
|
||||
RCT_TEST(SimpleSnapshotTest)
|
||||
RCT_TEST(SyncMethodTest)
|
||||
RCT_TEST(PromiseTest)
|
||||
RCT_TEST_ONLY_WITH_PACKAGER(WebSocketTest)
|
||||
RCT_TEST_ONLY_WITH_PACKAGER(WebSocketTest) // Requires a WebSocket test server, see scripts/objc-test.sh
|
||||
RCT_TEST(AccessibilityManagerTest)
|
||||
|
||||
#if !TARGET_OS_TV // tvOS does not fully support WebView
|
||||
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 110 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 149 KiB |
|
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 153 KiB |
|
After Width: | Height: | Size: 313 KiB |
|
Before Width: | Height: | Size: 147 KiB After Width: | Height: | Size: 285 KiB |
|
After Width: | Height: | Size: 586 KiB |
|
Before Width: | Height: | Size: 166 KiB After Width: | Height: | Size: 167 KiB |
|
After Width: | Height: | Size: 336 KiB |
|
Before Width: | Height: | Size: 145 KiB After Width: | Height: | Size: 143 KiB |
|
After Width: | Height: | Size: 266 KiB |
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 80 KiB |
|
After Width: | Height: | Size: 158 KiB |
|
Before Width: | Height: | Size: 365 KiB After Width: | Height: | Size: 322 KiB |
|
After Width: | Height: | Size: 562 KiB |
|
Before Width: | Height: | Size: 200 KiB After Width: | Height: | Size: 200 KiB |
|
After Width: | Height: | Size: 367 KiB |
@@ -91,8 +91,8 @@ def enableSeparateBuildPerCPUArchitecture = true
|
||||
def enableProguardInReleaseBuilds = true
|
||||
|
||||
android {
|
||||
compileSdkVersion 27
|
||||
buildToolsVersion "27.0.3"
|
||||
compileSdkVersion 28
|
||||
buildToolsVersion "28.0.2"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.facebook.react.uiapp"
|
||||
@@ -131,7 +131,7 @@ android {
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation 'com.android.support:appcompat-v7:27.1.1'
|
||||
implementation 'com.android.support:appcompat-v7:28.0.0'
|
||||
|
||||
// Build React Native from source
|
||||
implementation project(':ReactAndroid')
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @emails oncall+react_native
|
||||
* @format
|
||||
*/
|
||||
|
||||
/* global device, element, by, expect */
|
||||
|
||||
describe('Button', () => {
|
||||
beforeAll(async () => {
|
||||
await device.reloadReactNative();
|
||||
await element(by.id('explorer_search')).replaceText('<Button>');
|
||||
await element(
|
||||
by.label('<Button> Simple React Native button component.'),
|
||||
).tap();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
//TODO - remove app state persistency, till then, we must go back to main screen,
|
||||
await element(by.label('Back')).tap();
|
||||
});
|
||||
|
||||
it('Simple button should be tappable', async () => {
|
||||
await element(by.label('Press Me')).tap();
|
||||
await expect(element(by.text('Simple has been pressed!'))).toBeVisible();
|
||||
await element(by.text('OK')).tap();
|
||||
});
|
||||
|
||||
it('Adjusted color button should be tappable', async () => {
|
||||
await element(by.label('Press Purple')).tap();
|
||||
await expect(element(by.text('Purple has been pressed!'))).toBeVisible();
|
||||
await element(by.text('OK')).tap();
|
||||
});
|
||||
|
||||
it("Two buttons with JustifyContent:'space-between' should be tappable", async () => {
|
||||
await element(by.label('This looks great!')).tap();
|
||||
await expect(element(by.text('Left has been pressed!'))).toBeVisible();
|
||||
await element(by.text('OK')).tap();
|
||||
|
||||
await element(by.label('Ok!')).tap();
|
||||
await expect(element(by.text('Right has been pressed!'))).toBeVisible();
|
||||
await element(by.text('OK')).tap();
|
||||
});
|
||||
|
||||
it('Disabled button should not interact', async () => {
|
||||
await element(by.label('I Am Disabled')).tap();
|
||||
await expect(
|
||||
element(by.text('Disabled has been pressed!')),
|
||||
).toBeNotVisible();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @emails oncall+react_native
|
||||
* @format
|
||||
*/
|
||||
|
||||
/* global element, by, expect */
|
||||
|
||||
describe('DatePickerIOS', () => {
|
||||
beforeAll(async () => {
|
||||
await element(by.id('explorer_search')).replaceText('<DatePickerIOS>');
|
||||
await element(
|
||||
by.label(
|
||||
'<DatePickerIOS> Select dates and times using the native UIDatePicker.',
|
||||
),
|
||||
).tap();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await element(by.label('Back')).tap();
|
||||
});
|
||||
|
||||
it('Should change indicator with datetime picker', async () => {
|
||||
const testID = 'date-and-time';
|
||||
const indicatorID = 'date-and-time-indicator';
|
||||
|
||||
const testElement = await element(
|
||||
by.type('UIPickerView').withAncestor(by.id(testID)),
|
||||
);
|
||||
const indicator = await element(by.id(indicatorID));
|
||||
|
||||
await expect(testElement).toBeVisible();
|
||||
await expect(indicator).toBeVisible();
|
||||
|
||||
await testElement.setColumnToValue(0, 'Dec 4');
|
||||
await testElement.setColumnToValue(1, '4');
|
||||
await testElement.setColumnToValue(2, '10');
|
||||
await testElement.setColumnToValue(3, 'AM');
|
||||
|
||||
await expect(indicator).toHaveText('12/4/2005 4:10 AM');
|
||||
});
|
||||
|
||||
it('Should change indicator with date-only picker', async () => {
|
||||
const testID = 'date-only';
|
||||
const indicatorID = 'date-and-time-indicator';
|
||||
|
||||
const testElement = await element(
|
||||
by.type('UIPickerView').withAncestor(by.id(testID)),
|
||||
);
|
||||
const indicator = await element(by.id(indicatorID));
|
||||
|
||||
await expect(testElement).toBeVisible();
|
||||
await expect(indicator).toBeVisible();
|
||||
|
||||
await testElement.setColumnToValue(0, 'November');
|
||||
await testElement.setColumnToValue(1, '3');
|
||||
await testElement.setColumnToValue(2, '2006');
|
||||
|
||||
await expect(indicator).toHaveText('11/3/2006 4:10 AM');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @emails oncall+react_native
|
||||
* @format
|
||||
*/
|
||||
|
||||
/* global element, by, expect */
|
||||
|
||||
describe('Picker', () => {
|
||||
beforeAll(async () => {
|
||||
await element(by.id('explorer_search')).replaceText('<Picker>');
|
||||
await element(
|
||||
by.label(
|
||||
'<Picker> Provides multiple options to choose from, using either a dropdown menu or a dialog.',
|
||||
),
|
||||
).tap();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await element(by.label('Back')).tap();
|
||||
});
|
||||
|
||||
it('should be selectable by ID', async () => {
|
||||
await expect(element(by.id('basic-picker'))).toBeVisible();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @emails oncall+react_native
|
||||
* @format
|
||||
*/
|
||||
|
||||
/* global device, element, by, expect */
|
||||
|
||||
const jestExpect = require('expect');
|
||||
|
||||
describe('Switch', () => {
|
||||
beforeEach(async () => {
|
||||
await device.reloadReactNative();
|
||||
await element(by.id('explorer_search')).replaceText('<Switch>');
|
||||
await element(by.label('<Switch> Native boolean input')).tap();
|
||||
});
|
||||
|
||||
it('Switch that starts off should switch', async () => {
|
||||
const testID = 'on-off-initial-off';
|
||||
const indicatorID = 'on-off-initial-off-indicator';
|
||||
|
||||
await expect(element(by.id(testID))).toHaveValue('0');
|
||||
await expect(element(by.id(indicatorID))).toHaveText('Off');
|
||||
await element(by.id(testID)).tap();
|
||||
await expect(element(by.id(testID))).toHaveValue('1');
|
||||
await expect(element(by.id(indicatorID))).toHaveText('On');
|
||||
});
|
||||
|
||||
it('Switch that starts on should switch', async () => {
|
||||
const testID = 'on-off-initial-on';
|
||||
const indicatorID = 'on-off-initial-on-indicator';
|
||||
|
||||
await expect(element(by.id(testID))).toHaveValue('1');
|
||||
await expect(element(by.id(indicatorID))).toHaveText('On');
|
||||
await element(by.id(testID)).tap();
|
||||
await expect(element(by.id(testID))).toHaveValue('0');
|
||||
await expect(element(by.id(indicatorID))).toHaveText('Off');
|
||||
});
|
||||
|
||||
it('disabled switch should not toggle', async () => {
|
||||
const onTestID = 'disabled-initial-on';
|
||||
const offTestID = 'disabled-initial-off';
|
||||
const onIndicatorID = 'disabled-initial-on-indicator';
|
||||
const offIndicatorID = 'disabled-initial-off-indicator';
|
||||
|
||||
await expect(element(by.id(onTestID))).toHaveValue('1');
|
||||
await expect(element(by.id(onIndicatorID))).toHaveText('On');
|
||||
|
||||
try {
|
||||
await element(by.id(onTestID)).tap();
|
||||
throw new Error('Does not match');
|
||||
} catch (err) {
|
||||
jestExpect(err.message.message).toEqual(
|
||||
jestExpect.stringContaining(
|
||||
'Cannot perform action due to constraint(s) failure',
|
||||
),
|
||||
);
|
||||
}
|
||||
await expect(element(by.id(onTestID))).toHaveValue('1');
|
||||
await expect(element(by.id(onIndicatorID))).toHaveText('On');
|
||||
|
||||
await expect(element(by.id(offTestID))).toHaveValue('0');
|
||||
await expect(element(by.id(offIndicatorID))).toHaveText('Off');
|
||||
try {
|
||||
await element(by.id(offTestID)).tap();
|
||||
throw new Error('Does not match');
|
||||
} catch (err) {
|
||||
jestExpect(err.message.message).toEqual(
|
||||
jestExpect.stringContaining(
|
||||
'Cannot perform action due to constraint(s) failure',
|
||||
),
|
||||
);
|
||||
}
|
||||
await expect(element(by.id(offTestID))).toHaveValue('0');
|
||||
await expect(element(by.id(offIndicatorID))).toHaveText('Off');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @emails oncall+react_native
|
||||
* @format
|
||||
*/
|
||||
|
||||
/* global element, by, expect */
|
||||
|
||||
describe('Touchable', () => {
|
||||
beforeAll(async () => {
|
||||
await element(by.id('explorer_search')).replaceText('<Touchable*');
|
||||
await element(
|
||||
by.label('<Touchable*> and onPress Touchable and onPress examples.'),
|
||||
).tap();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
//TODO - remove app state persistency, till then, we must go back to main screen,
|
||||
await element(by.label('Back')).tap();
|
||||
});
|
||||
|
||||
it('Touchable Highlight should be tappable', async () => {
|
||||
const buttonID = 'touchable_highlight_image_button';
|
||||
const button2ID = 'touchable_highlight_text_button';
|
||||
const consoleID = 'touchable_highlight_console';
|
||||
|
||||
await element(by.id(buttonID)).tap();
|
||||
await expect(element(by.id(consoleID))).toHaveText(
|
||||
'TouchableHighlight onPress',
|
||||
);
|
||||
|
||||
await element(by.id(buttonID)).tap();
|
||||
await expect(element(by.id(consoleID))).toHaveText(
|
||||
'2x TouchableHighlight onPress',
|
||||
);
|
||||
|
||||
await element(by.id(button2ID)).tap();
|
||||
await expect(element(by.id(consoleID))).toHaveText(
|
||||
'3x TouchableHighlight onPress',
|
||||
);
|
||||
});
|
||||
|
||||
it('Touchable Without Feedback should be tappable', async () => {
|
||||
const buttonID = 'touchable_without_feedback_button';
|
||||
const consoleID = 'touchable_without_feedback_console';
|
||||
|
||||
await element(by.id(buttonID)).tap();
|
||||
await expect(element(by.id(consoleID))).toHaveText(
|
||||
'TouchableWithoutFeedback onPress',
|
||||
);
|
||||
|
||||
await element(by.id(buttonID)).tap();
|
||||
await expect(element(by.id(consoleID))).toHaveText(
|
||||
'2x TouchableWithoutFeedback onPress',
|
||||
);
|
||||
});
|
||||
|
||||
it('Text should be tappable', async () => {
|
||||
const buttonID = 'tappable_text';
|
||||
const consoleID = 'tappable_text_console';
|
||||
|
||||
await element(by.id(buttonID)).tap();
|
||||
await expect(element(by.id(consoleID))).toHaveText('text onPress');
|
||||
|
||||
await element(by.id(buttonID)).tap();
|
||||
await expect(element(by.id(consoleID))).toHaveText('2x text onPress');
|
||||
});
|
||||
});
|
||||
@@ -46,10 +46,13 @@ class DatePickerExample extends React.Component<
|
||||
return (
|
||||
<View>
|
||||
<WithLabel label="Value:">
|
||||
<Text>
|
||||
<Text testID="date-and-time-indicator">
|
||||
{this.state.date.toLocaleDateString() +
|
||||
' ' +
|
||||
this.state.date.toLocaleTimeString()}
|
||||
this.state.date.toLocaleTimeString([], {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
})}
|
||||
</Text>
|
||||
</WithLabel>
|
||||
<WithLabel label="Timezone:">
|
||||
@@ -62,6 +65,7 @@ class DatePickerExample extends React.Component<
|
||||
</WithLabel>
|
||||
<Heading label="Date + time picker" />
|
||||
<DatePickerIOS
|
||||
testID="date-and-time"
|
||||
date={this.state.date}
|
||||
mode="datetime"
|
||||
timeZoneOffsetInMinutes={this.state.timeZoneOffsetInHours * 60}
|
||||
@@ -69,6 +73,7 @@ class DatePickerExample extends React.Component<
|
||||
/>
|
||||
<Heading label="Date picker" />
|
||||
<DatePickerIOS
|
||||
testID="date-only"
|
||||
date={this.state.date}
|
||||
mode="date"
|
||||
timeZoneOffsetInMinutes={this.state.timeZoneOffsetInHours * 60}
|
||||
@@ -76,6 +81,7 @@ class DatePickerExample extends React.Component<
|
||||
/>
|
||||
<Heading label="Time picker, 10-minute interval" />
|
||||
<DatePickerIOS
|
||||
testID="time-only"
|
||||
date={this.state.date}
|
||||
mode="time"
|
||||
timeZoneOffsetInMinutes={this.state.timeZoneOffsetInHours * 60}
|
||||
|
||||
@@ -38,6 +38,7 @@ class PickerExample extends React.Component<{}, $FlowFixMeState> {
|
||||
<RNTesterPage title="<Picker>">
|
||||
<RNTesterBlock title="Basic Picker">
|
||||
<Picker
|
||||
testID="basic-picker"
|
||||
style={styles.picker}
|
||||
selectedValue={this.state.selected1}
|
||||
onValueChange={this.onValueChange.bind(this, 'selected1')}>
|
||||
|
||||
@@ -70,17 +70,8 @@ class RNTesterApp extends React.Component<Props, RNTesterNavigationState> {
|
||||
);
|
||||
const urlAction = URIActionMap(url);
|
||||
const launchAction = exampleAction || urlAction;
|
||||
if (err || !storedString) {
|
||||
const initialAction = launchAction || {type: 'InitialAction'};
|
||||
this.setState(RNTesterNavigationReducer(undefined, initialAction));
|
||||
return;
|
||||
}
|
||||
const storedState = JSON.parse(storedString);
|
||||
if (launchAction) {
|
||||
this.setState(RNTesterNavigationReducer(storedState, launchAction));
|
||||
return;
|
||||
}
|
||||
this.setState(storedState);
|
||||
const initialAction = launchAction || {type: 'InitialAction'};
|
||||
this.setState(RNTesterNavigationReducer(undefined, initialAction));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -179,7 +170,10 @@ RNTesterList.ComponentExamples.concat(RNTesterList.APIExamples).forEach(
|
||||
render() {
|
||||
return (
|
||||
<SnapshotViewIOS>
|
||||
<RNTesterExampleContainer module={ExampleModule} />
|
||||
<RNTesterExampleContainer
|
||||
module={ExampleModule}
|
||||
displayFilter={false}
|
||||
/>
|
||||
</SnapshotViewIOS>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
const React = require('react');
|
||||
const {Platform} = require('react-native');
|
||||
const RNTesterBlock = require('./RNTesterBlock');
|
||||
const RNTesterExampleFilter = require('./RNTesterExampleFilter');
|
||||
const RNTesterPage = require('./RNTesterPage');
|
||||
|
||||
class RNTesterExampleContainer extends React.Component {
|
||||
@@ -37,9 +38,36 @@ class RNTesterExampleContainer extends React.Component {
|
||||
return <this.props.module />;
|
||||
}
|
||||
|
||||
if (
|
||||
this.props.displayFilter === false ||
|
||||
this.props.module.examples.length === 1
|
||||
) {
|
||||
return (
|
||||
<RNTesterPage title={this.props.title}>
|
||||
{this.props.module.examples.map(this.renderExample)}
|
||||
</RNTesterPage>
|
||||
);
|
||||
}
|
||||
|
||||
const filter = ({example, filterRegex}) => filterRegex.test(example.title);
|
||||
|
||||
const sections = [
|
||||
{
|
||||
data: this.props.module.examples,
|
||||
title: 'EXAMPLES',
|
||||
key: 'e',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<RNTesterPage title={this.props.title}>
|
||||
{this.props.module.examples.map(this.renderExample)}
|
||||
<RNTesterExampleFilter
|
||||
sections={sections}
|
||||
filter={filter}
|
||||
render={({filteredSections}) =>
|
||||
filteredSections[0].data.map(this.renderExample)
|
||||
}
|
||||
/>
|
||||
</RNTesterPage>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const React = require('react');
|
||||
const StyleSheet = require('StyleSheet');
|
||||
const TextInput = require('TextInput');
|
||||
const View = require('View');
|
||||
|
||||
type Props = {
|
||||
filter: Function,
|
||||
render: Function,
|
||||
/*
|
||||
* $FlowFixMe: We shoudl better type this (ideally so that render and filter are
|
||||
* aware of what they receive)
|
||||
*/
|
||||
sections: Object,
|
||||
disableSearch?: boolean,
|
||||
};
|
||||
|
||||
type State = {
|
||||
filter: string,
|
||||
};
|
||||
|
||||
class RNTesterExampleFilter extends React.Component<Props, State> {
|
||||
state = {filter: ''};
|
||||
|
||||
render() {
|
||||
const filterText = this.state.filter;
|
||||
let filterRegex = /.*/;
|
||||
|
||||
try {
|
||||
filterRegex = new RegExp(String(filterText), 'i');
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
'Failed to create RegExp: %s\n%s',
|
||||
filterText,
|
||||
error.message,
|
||||
);
|
||||
}
|
||||
|
||||
const filter = example =>
|
||||
this.props.disableSearch || this.props.filter({example, filterRegex});
|
||||
|
||||
const filteredSections = this.props.sections.map(section => ({
|
||||
...section,
|
||||
data: section.data.filter(filter),
|
||||
}));
|
||||
|
||||
return (
|
||||
<View>
|
||||
{this._renderTextInput()}
|
||||
{this.props.render({filteredSections})}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_renderTextInput(): ?React.Element<any> {
|
||||
if (this.props.disableSearch) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<View style={styles.searchRow}>
|
||||
<TextInput
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
clearButtonMode="always"
|
||||
onChangeText={text => {
|
||||
this.setState(() => ({filter: text}));
|
||||
}}
|
||||
placeholder="Search..."
|
||||
underlineColorAndroid="transparent"
|
||||
style={styles.searchTextInput}
|
||||
testID="explorer_search"
|
||||
value={this.state.filter}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
searchRow: {
|
||||
backgroundColor: '#eeeeee',
|
||||
padding: 10,
|
||||
},
|
||||
searchTextInput: {
|
||||
backgroundColor: 'white',
|
||||
borderColor: '#cccccc',
|
||||
borderRadius: 3,
|
||||
borderWidth: 1,
|
||||
paddingLeft: 8,
|
||||
paddingVertical: 0,
|
||||
height: 35,
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = RNTesterExampleFilter;
|
||||
@@ -15,17 +15,15 @@ const React = require('react');
|
||||
const SectionList = require('SectionList');
|
||||
const StyleSheet = require('StyleSheet');
|
||||
const Text = require('Text');
|
||||
const TextInput = require('TextInput');
|
||||
const TouchableHighlight = require('TouchableHighlight');
|
||||
const RNTesterActions = require('./RNTesterActions');
|
||||
const RNTesterStatePersister = require('./RNTesterStatePersister');
|
||||
const RNTesterExampleFilter = require('./RNTesterExampleFilter');
|
||||
const View = require('View');
|
||||
|
||||
/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found when
|
||||
* making Flow check .android.js files. */
|
||||
import type {RNTesterExample} from './RNTesterList.ios';
|
||||
import type {PassProps} from './RNTesterStatePersister';
|
||||
import type {TextStyleProp, ViewStyleProp} from 'StyleSheet';
|
||||
import type {ViewStyleProp} from 'StyleSheet';
|
||||
|
||||
type Props = {
|
||||
onNavigate: Function,
|
||||
@@ -33,8 +31,6 @@ type Props = {
|
||||
ComponentExamples: Array<RNTesterExample>,
|
||||
APIExamples: Array<RNTesterExample>,
|
||||
},
|
||||
persister: PassProps<*>,
|
||||
searchTextInputStyle: TextStyleProp,
|
||||
style?: ?ViewStyleProp,
|
||||
};
|
||||
|
||||
@@ -74,55 +70,47 @@ const renderSectionHeader = ({section}) => (
|
||||
|
||||
class RNTesterExampleList extends React.Component<Props, $FlowFixMeState> {
|
||||
render() {
|
||||
const filterText = this.props.persister.state.filter;
|
||||
let filterRegex = /.*/;
|
||||
|
||||
try {
|
||||
filterRegex = new RegExp(String(filterText), 'i');
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
'Failed to create RegExp: %s\n%s',
|
||||
filterText,
|
||||
error.message,
|
||||
);
|
||||
}
|
||||
|
||||
const filter = example =>
|
||||
const filter = ({example, filterRegex}) =>
|
||||
/* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an
|
||||
* error found when Flow v0.68 was deployed. To see the error delete this
|
||||
* comment and run Flow. */
|
||||
this.props.disableSearch ||
|
||||
(filterRegex.test(example.module.title) &&
|
||||
(!Platform.isTV || example.supportsTVOS));
|
||||
* error found when Flow v0.68 was deployed. To see the error delete this
|
||||
* comment and run Flow. */
|
||||
filterRegex.test(example.module.title) &&
|
||||
(!Platform.isTV || example.supportsTVOS);
|
||||
|
||||
const sections = [
|
||||
{
|
||||
data: this.props.list.ComponentExamples.filter(filter),
|
||||
data: this.props.list.ComponentExamples,
|
||||
title: 'COMPONENTS',
|
||||
key: 'c',
|
||||
},
|
||||
{
|
||||
data: this.props.list.APIExamples.filter(filter),
|
||||
data: this.props.list.APIExamples,
|
||||
title: 'APIS',
|
||||
key: 'a',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<View style={[styles.listContainer, this.props.style]}>
|
||||
{this._renderTitleRow()}
|
||||
{this._renderTextInput()}
|
||||
<SectionList
|
||||
ItemSeparatorComponent={ItemSeparator}
|
||||
contentContainerStyle={{backgroundColor: 'white'}}
|
||||
style={styles.list}
|
||||
<RNTesterExampleFilter
|
||||
sections={sections}
|
||||
renderItem={this._renderItem}
|
||||
enableEmptySections={true}
|
||||
itemShouldUpdate={this._itemShouldUpdate}
|
||||
keyboardShouldPersistTaps="handled"
|
||||
automaticallyAdjustContentInsets={false}
|
||||
keyboardDismissMode="on-drag"
|
||||
renderSectionHeader={renderSectionHeader}
|
||||
filter={filter}
|
||||
render={({filteredSections}) => (
|
||||
<SectionList
|
||||
ItemSeparatorComponent={ItemSeparator}
|
||||
contentContainerStyle={styles.sectionListContentContainer}
|
||||
style={styles.list}
|
||||
sections={filteredSections}
|
||||
renderItem={this._renderItem}
|
||||
enableEmptySections={true}
|
||||
itemShouldUpdate={this._itemShouldUpdate}
|
||||
keyboardShouldPersistTaps="handled"
|
||||
automaticallyAdjustContentInsets={false}
|
||||
keyboardDismissMode="on-drag"
|
||||
renderSectionHeader={renderSectionHeader}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
@@ -164,32 +152,6 @@ class RNTesterExampleList extends React.Component<Props, $FlowFixMeState> {
|
||||
);
|
||||
}
|
||||
|
||||
_renderTextInput(): ?React.Element<any> {
|
||||
/* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an
|
||||
* error found when Flow v0.68 was deployed. To see the error delete this
|
||||
* comment and run Flow. */
|
||||
if (this.props.disableSearch) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<View style={styles.searchRow}>
|
||||
<TextInput
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
clearButtonMode="always"
|
||||
onChangeText={text => {
|
||||
this.props.persister.setState(() => ({filter: text}));
|
||||
}}
|
||||
placeholder="Search..."
|
||||
underlineColorAndroid="transparent"
|
||||
style={[styles.searchTextInput, this.props.searchTextInputStyle]}
|
||||
testID="explorer_search"
|
||||
value={this.props.persister.state.filter}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_handleRowPress(exampleKey: string): void {
|
||||
this.props.onNavigate(RNTesterActions.ExampleAction(exampleKey));
|
||||
}
|
||||
@@ -199,17 +161,6 @@ const ItemSeparator = ({highlighted}) => (
|
||||
<View style={highlighted ? styles.separatorHighlighted : styles.separator} />
|
||||
);
|
||||
|
||||
/* $FlowFixMe(>=0.85.0 site=react_native_fb) This comment suppresses an error
|
||||
* found when Flow v0.85 was deployed. To see the error, delete this comment
|
||||
* and run Flow. */
|
||||
RNTesterExampleList = RNTesterStatePersister.createContainer(
|
||||
RNTesterExampleList,
|
||||
{
|
||||
cacheKeySuffix: () => 'mainList',
|
||||
getInitialState: () => ({filter: ''}),
|
||||
},
|
||||
);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
listContainer: {
|
||||
flex: 1,
|
||||
@@ -238,6 +189,9 @@ const styles = StyleSheet.create({
|
||||
height: StyleSheet.hairlineWidth,
|
||||
backgroundColor: 'rgb(217, 217, 217)',
|
||||
},
|
||||
sectionListContentContainer: {
|
||||
backgroundColor: 'white',
|
||||
},
|
||||
rowTitleText: {
|
||||
fontSize: 17,
|
||||
fontWeight: '500',
|
||||
@@ -247,19 +201,6 @@ const styles = StyleSheet.create({
|
||||
color: '#888888',
|
||||
lineHeight: 20,
|
||||
},
|
||||
searchRow: {
|
||||
backgroundColor: '#eeeeee',
|
||||
padding: 10,
|
||||
},
|
||||
searchTextInput: {
|
||||
backgroundColor: 'white',
|
||||
borderColor: '#cccccc',
|
||||
borderRadius: 3,
|
||||
borderWidth: 1,
|
||||
paddingLeft: 8,
|
||||
paddingVertical: 0,
|
||||
height: 35,
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = RNTesterExampleList;
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const ActivityIndicator = require('ActivityIndicator');
|
||||
const Platform = require('Platform');
|
||||
const React = require('react');
|
||||
const ReactNative = require('react-native');
|
||||
@@ -155,7 +154,6 @@ if (Platform.OS === 'ios') {
|
||||
autoscrollToTopThreshold: 10,
|
||||
}}
|
||||
style={styles.scrollView}>
|
||||
<ActivityIndicator style={{height: 40}} />
|
||||
{this.state.items.map(item =>
|
||||
React.cloneElement(item, {key: item.props.msg}),
|
||||
)}
|
||||
@@ -168,7 +166,6 @@ if (Platform.OS === 'ios') {
|
||||
autoscrollToTopThreshold: 10,
|
||||
}}
|
||||
style={[styles.scrollView, styles.horizontalScrollView]}>
|
||||
<ActivityIndicator style={{width: 40}} />
|
||||
{this.state.items.map(item =>
|
||||
React.cloneElement(item, {key: item.props.msg, style: null}),
|
||||
)}
|
||||
|
||||
@@ -11,10 +11,37 @@
|
||||
'use strict';
|
||||
|
||||
const React = require('react');
|
||||
const ReactNative = require('react-native');
|
||||
const {Switch, Text, View} = ReactNative;
|
||||
const {Switch, Text, View} = require('react-native');
|
||||
|
||||
class BasicSwitchExample extends React.Component<{}, $FlowFixMeState> {
|
||||
type OnOffIndicatorProps = $ReadOnly<{|on: boolean, testID: string|}>;
|
||||
function OnOffIndicator({on, testID}: OnOffIndicatorProps) {
|
||||
return <Text testID={testID}>{on ? 'On' : 'Off'}</Text>;
|
||||
}
|
||||
|
||||
type ExampleRowProps = $ReadOnly<{|children: React.Node|}>;
|
||||
function ExampleRow({children}: ExampleRowProps) {
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: 10,
|
||||
}}>
|
||||
{children}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
type SimpleSwitchExampleState = $ReadOnly<{|
|
||||
trueSwitchIsOn: boolean,
|
||||
falseSwitchIsOn: boolean,
|
||||
|}>;
|
||||
|
||||
class BasicSwitchExample extends React.Component<
|
||||
{||},
|
||||
SimpleSwitchExampleState,
|
||||
> {
|
||||
state = {
|
||||
trueSwitchIsOn: true,
|
||||
falseSwitchIsOn: false,
|
||||
@@ -23,26 +50,72 @@ class BasicSwitchExample extends React.Component<{}, $FlowFixMeState> {
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<Switch
|
||||
onValueChange={value => this.setState({falseSwitchIsOn: value})}
|
||||
style={{marginBottom: 10}}
|
||||
value={this.state.falseSwitchIsOn}
|
||||
/>
|
||||
<Switch
|
||||
onValueChange={value => this.setState({trueSwitchIsOn: value})}
|
||||
value={this.state.trueSwitchIsOn}
|
||||
/>
|
||||
<ExampleRow>
|
||||
<Switch
|
||||
testID="on-off-initial-off"
|
||||
onValueChange={value => this.setState({falseSwitchIsOn: value})}
|
||||
value={this.state.falseSwitchIsOn}
|
||||
/>
|
||||
<OnOffIndicator
|
||||
on={this.state.falseSwitchIsOn}
|
||||
testID="on-off-initial-off-indicator"
|
||||
/>
|
||||
</ExampleRow>
|
||||
<ExampleRow>
|
||||
<Switch
|
||||
testID="on-off-initial-on"
|
||||
onValueChange={value => this.setState({trueSwitchIsOn: value})}
|
||||
value={this.state.trueSwitchIsOn}
|
||||
/>
|
||||
<OnOffIndicator
|
||||
on={this.state.trueSwitchIsOn}
|
||||
testID="on-off-initial-on-indicator"
|
||||
/>
|
||||
</ExampleRow>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DisabledSwitchExample extends React.Component<{}> {
|
||||
class DisabledSwitchExample extends React.Component<
|
||||
{||},
|
||||
SimpleSwitchExampleState,
|
||||
> {
|
||||
state = {
|
||||
trueSwitchIsOn: true,
|
||||
falseSwitchIsOn: false,
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<Switch disabled={true} style={{marginBottom: 10}} value={true} />
|
||||
<Switch disabled={true} value={false} />
|
||||
<ExampleRow>
|
||||
<Switch
|
||||
testID="disabled-initial-off"
|
||||
disabled={true}
|
||||
onValueChange={value => this.setState({falseSwitchIsOn: value})}
|
||||
value={this.state.falseSwitchIsOn}
|
||||
/>
|
||||
|
||||
<OnOffIndicator
|
||||
on={this.state.falseSwitchIsOn}
|
||||
testID="disabled-initial-off-indicator"
|
||||
/>
|
||||
</ExampleRow>
|
||||
|
||||
<ExampleRow>
|
||||
<Switch
|
||||
testID="disabled-initial-on"
|
||||
disabled={true}
|
||||
onValueChange={value => this.setState({trueSwitchIsOn: value})}
|
||||
value={this.state.trueSwitchIsOn}
|
||||
/>
|
||||
|
||||
<OnOffIndicator
|
||||
on={this.state.trueSwitchIsOn}
|
||||
testID="disabled-initial-on-indicator"
|
||||
/>
|
||||
</ExampleRow>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -45,30 +45,7 @@ exports.examples = [
|
||||
'background color change as well with the activeOpacity and ' +
|
||||
'underlayColor props.',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<View style={styles.row}>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
onPress={() => console.log('stock THW image - highlight')}>
|
||||
<Image source={heartImage} style={styles.image} />
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
activeOpacity={1}
|
||||
tvParallaxProperties={{
|
||||
pressMagnification: 1.3,
|
||||
pressDuration: 0.6,
|
||||
}}
|
||||
underlayColor="rgb(210, 230, 255)"
|
||||
onPress={() => console.log('custom THW text - highlight')}>
|
||||
<View style={styles.wrapperCustom}>
|
||||
<Text style={styles.text}>Tap Here For Custom Highlight!</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
return <TouchableHighlightBox />;
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -157,6 +134,57 @@ exports.examples = [
|
||||
},
|
||||
];
|
||||
|
||||
class TouchableHighlightBox extends React.Component<{}, $FlowFixMeState> {
|
||||
state = {
|
||||
timesPressed: 0,
|
||||
};
|
||||
|
||||
touchableOnPress = () => {
|
||||
this.setState({
|
||||
timesPressed: this.state.timesPressed + 1,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
let textLog = '';
|
||||
if (this.state.timesPressed > 1) {
|
||||
textLog = this.state.timesPressed + 'x TouchableHighlight onPress';
|
||||
} else if (this.state.timesPressed > 0) {
|
||||
textLog = 'TouchableHighlight onPress';
|
||||
}
|
||||
|
||||
return (
|
||||
<View>
|
||||
<View style={styles.row}>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
testID="touchable_highlight_image_button"
|
||||
onPress={this.touchableOnPress}>
|
||||
<Image source={heartImage} style={styles.image} />
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
testID="touchable_highlight_text_button"
|
||||
activeOpacity={1}
|
||||
tvParallaxProperties={{
|
||||
pressMagnification: 1.3,
|
||||
pressDuration: 0.6,
|
||||
}}
|
||||
underlayColor="rgb(210, 230, 255)"
|
||||
onPress={this.touchableOnPress}>
|
||||
<View style={styles.wrapperCustom}>
|
||||
<Text style={styles.text}>Tap Here For Custom Highlight!</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
<View style={styles.logBox}>
|
||||
<Text testID="touchable_highlight_console">{textLog}</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TouchableWithoutFeedbackBox extends React.Component<{}, $FlowFixMeState> {
|
||||
state = {
|
||||
timesPressed: 0,
|
||||
@@ -178,13 +206,15 @@ class TouchableWithoutFeedbackBox extends React.Component<{}, $FlowFixMeState> {
|
||||
|
||||
return (
|
||||
<View>
|
||||
<TouchableWithoutFeedback onPress={this.textOnPress}>
|
||||
<TouchableWithoutFeedback
|
||||
onPress={this.textOnPress}
|
||||
testID="touchable_without_feedback_button">
|
||||
<View style={styles.wrapperCustom}>
|
||||
<Text style={styles.text}>Tap Here For No Feedback!</Text>
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
<View style={styles.logBox}>
|
||||
<Text>{textLog}</Text>
|
||||
<Text testID="touchable_without_feedback_console">{textLog}</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
@@ -212,11 +242,14 @@ class TextOnPressBox extends React.Component<{}, $FlowFixMeState> {
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Text style={styles.textBlock} onPress={this.textOnPress}>
|
||||
<Text
|
||||
style={styles.textBlock}
|
||||
testID="tappable_text"
|
||||
onPress={this.textOnPress}>
|
||||
Text has built-in onPress handling
|
||||
</Text>
|
||||
<View style={styles.logBox}>
|
||||
<Text>{textLog}</Text>
|
||||
<Text testID="tappable_text_console">{textLog}</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -12,6 +12,7 @@ NSString *const RCTErrorDomain = @"RCTErrorDomain";
|
||||
NSString *const RCTJSStackTraceKey = @"RCTJSStackTraceKey";
|
||||
NSString *const RCTJSRawStackTraceKey = @"RCTJSRawStackTraceKey";
|
||||
NSString *const RCTFatalExceptionName = @"RCTFatalException";
|
||||
NSString *const RCTUntruncatedMessageKey = @"RCTUntruncatedMessageKey";
|
||||
|
||||
static NSString *const RCTAssertFunctionStack = @"RCTAssertFunctionStack";
|
||||
|
||||
@@ -128,8 +129,20 @@ void RCTFatal(NSError *error)
|
||||
@try {
|
||||
#endif
|
||||
NSString *name = [NSString stringWithFormat:@"%@: %@", RCTFatalExceptionName, error.localizedDescription];
|
||||
NSString *message = RCTFormatError(error.localizedDescription, error.userInfo[RCTJSStackTraceKey], 75);
|
||||
@throw [[NSException alloc] initWithName:name reason:message userInfo:nil];
|
||||
|
||||
// Truncate the localized description to 175 characters to avoid wild screen overflows
|
||||
NSString *message = RCTFormatError(error.localizedDescription, error.userInfo[RCTJSStackTraceKey], 175);
|
||||
|
||||
// Attach an untruncated copy of the description to the userInfo, in case it is needed
|
||||
NSMutableDictionary *userInfo = [error.userInfo mutableCopy];
|
||||
[userInfo setObject:RCTFormatError(error.localizedDescription, error.userInfo[RCTJSStackTraceKey], -1)
|
||||
forKey:RCTUntruncatedMessageKey];
|
||||
|
||||
// Expected resulting exception information:
|
||||
// name: RCTFatalException: <underlying error description>
|
||||
// reason: <underlying error description plus JS stack trace, truncated to 175 characters>
|
||||
// userInfo: <underlying error userinfo, plus untruncated description plus JS stack trace>
|
||||
@throw [[NSException alloc] initWithName:name reason:message userInfo:userInfo];
|
||||
#if DEBUG
|
||||
} @catch (NSException *e) {}
|
||||
#endif
|
||||
|
||||
@@ -21,8 +21,8 @@ static void __makeVersion()
|
||||
{
|
||||
__rnVersion = @{
|
||||
RCTVersionMajor: @(0),
|
||||
RCTVersionMinor: @(0),
|
||||
RCTVersionPatch: @(0),
|
||||
RCTVersionMinor: @(58),
|
||||
RCTVersionPatch: @(3),
|
||||
RCTVersionPrerelease: [NSNull null],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
#else
|
||||
self.windowLevel = UIWindowLevelStatusBar - 1;
|
||||
#endif
|
||||
self.backgroundColor = [UIColor colorWithRed:0.8 green:0 blue:0 alpha:1];
|
||||
self.backgroundColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1];
|
||||
self.hidden = YES;
|
||||
|
||||
UIViewController *rootController = [UIViewController new];
|
||||
@@ -58,7 +58,7 @@
|
||||
const CGFloat buttonHeight = 60;
|
||||
|
||||
CGRect detailsFrame = rootView.bounds;
|
||||
detailsFrame.size.height -= buttonHeight;
|
||||
detailsFrame.size.height -= buttonHeight + [self bottomSafeViewHeight];
|
||||
|
||||
_stackTraceTableView = [[UITableView alloc] initWithFrame:detailsFrame style:UITableViewStylePlain];
|
||||
_stackTraceTableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
@@ -73,10 +73,10 @@
|
||||
[rootView addSubview:_stackTraceTableView];
|
||||
|
||||
#if TARGET_OS_SIMULATOR
|
||||
NSString *reloadText = @"Reload JS (\u2318R)";
|
||||
NSString *dismissText = @"Dismiss (ESC)";
|
||||
NSString *copyText = @"Copy (\u2325\u2318C)";
|
||||
NSString *extraText = @"Extra Info (\u2318E)";
|
||||
NSString *reloadText = @"Reload\n(\u2318R)";
|
||||
NSString *dismissText = @"Dismiss\n(ESC)";
|
||||
NSString *copyText = @"Copy\n(\u2325\u2318C)";
|
||||
NSString *extraText = @"Extra Info\n(\u2318E)";
|
||||
#else
|
||||
NSString *reloadText = @"Reload JS";
|
||||
NSString *dismissText = @"Dismiss";
|
||||
@@ -88,53 +88,85 @@
|
||||
dismissButton.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin;
|
||||
dismissButton.accessibilityIdentifier = @"redbox-dismiss";
|
||||
dismissButton.titleLabel.font = [UIFont systemFontOfSize:13];
|
||||
dismissButton.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
|
||||
dismissButton.titleLabel.textAlignment = NSTextAlignmentCenter;
|
||||
dismissButton.backgroundColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1];
|
||||
[dismissButton setTitle:dismissText forState:UIControlStateNormal];
|
||||
[dismissButton setTitleColor:[UIColor colorWithWhite:1 alpha:0.5] forState:UIControlStateNormal];
|
||||
[dismissButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted];
|
||||
[dismissButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
|
||||
[dismissButton setTitleColor:[UIColor colorWithWhite:1 alpha:0.5] forState:UIControlStateHighlighted];
|
||||
[dismissButton addTarget:self action:@selector(dismiss) forControlEvents:UIControlEventTouchUpInside];
|
||||
|
||||
UIButton *reloadButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
reloadButton.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin;
|
||||
reloadButton.accessibilityIdentifier = @"redbox-reload";
|
||||
reloadButton.titleLabel.font = [UIFont systemFontOfSize:13];
|
||||
|
||||
reloadButton.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
|
||||
reloadButton.titleLabel.textAlignment = NSTextAlignmentCenter;
|
||||
reloadButton.backgroundColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1];
|
||||
[reloadButton setTitle:reloadText forState:UIControlStateNormal];
|
||||
[reloadButton setTitleColor:[UIColor colorWithWhite:1 alpha:0.5] forState:UIControlStateNormal];
|
||||
[reloadButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted];
|
||||
[reloadButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
|
||||
[reloadButton setTitleColor:[UIColor colorWithWhite:1 alpha:0.5] forState:UIControlStateHighlighted];
|
||||
[reloadButton addTarget:self action:@selector(reload) forControlEvents:UIControlEventTouchUpInside];
|
||||
|
||||
UIButton *copyButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
copyButton.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin;
|
||||
copyButton.accessibilityIdentifier = @"redbox-copy";
|
||||
copyButton.titleLabel.font = [UIFont systemFontOfSize:13];
|
||||
copyButton.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
|
||||
copyButton.titleLabel.textAlignment = NSTextAlignmentCenter;
|
||||
copyButton.backgroundColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1];
|
||||
[copyButton setTitle:copyText forState:UIControlStateNormal];
|
||||
[copyButton setTitleColor:[UIColor colorWithWhite:1 alpha:0.5] forState:UIControlStateNormal];
|
||||
[copyButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted];
|
||||
[copyButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
|
||||
[copyButton setTitleColor:[UIColor colorWithWhite:1 alpha:0.5] forState:UIControlStateHighlighted];
|
||||
[copyButton addTarget:self action:@selector(copyStack) forControlEvents:UIControlEventTouchUpInside];
|
||||
|
||||
UIButton *extraButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
extraButton.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin;
|
||||
extraButton.accessibilityIdentifier = @"redbox-extra";
|
||||
extraButton.titleLabel.font = [UIFont systemFontOfSize:13];
|
||||
extraButton.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
|
||||
extraButton.titleLabel.textAlignment = NSTextAlignmentCenter;
|
||||
extraButton.backgroundColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1];
|
||||
[extraButton setTitle:extraText forState:UIControlStateNormal];
|
||||
[extraButton setTitleColor:[UIColor colorWithWhite:1 alpha:0.5] forState:UIControlStateNormal];
|
||||
[extraButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted];
|
||||
[extraButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
|
||||
[extraButton setTitleColor:[UIColor colorWithWhite:1 alpha:0.5] forState:UIControlStateHighlighted];
|
||||
[extraButton addTarget:self action:@selector(showExtraDataViewController) forControlEvents:UIControlEventTouchUpInside];
|
||||
|
||||
CGFloat buttonWidth = self.bounds.size.width / 4;
|
||||
dismissButton.frame = CGRectMake(0, self.bounds.size.height - buttonHeight, buttonWidth, buttonHeight);
|
||||
reloadButton.frame = CGRectMake(buttonWidth, self.bounds.size.height - buttonHeight, buttonWidth, buttonHeight);
|
||||
copyButton.frame = CGRectMake(buttonWidth * 2, self.bounds.size.height - buttonHeight, buttonWidth, buttonHeight);
|
||||
extraButton.frame = CGRectMake(buttonWidth * 3, self.bounds.size.height - buttonHeight, buttonWidth, buttonHeight);
|
||||
CGFloat bottomButtonHeight = self.bounds.size.height - buttonHeight - [self bottomSafeViewHeight];
|
||||
|
||||
dismissButton.frame = CGRectMake(0, bottomButtonHeight, buttonWidth, buttonHeight);
|
||||
reloadButton.frame = CGRectMake(buttonWidth, bottomButtonHeight, buttonWidth, buttonHeight);
|
||||
copyButton.frame = CGRectMake(buttonWidth * 2, bottomButtonHeight, buttonWidth, buttonHeight);
|
||||
extraButton.frame = CGRectMake(buttonWidth * 3, bottomButtonHeight, buttonWidth, buttonHeight);
|
||||
|
||||
UIView *topBorder = [[UIView alloc] initWithFrame:CGRectMake(0, bottomButtonHeight + 1, rootView.frame.size.width, 1)];
|
||||
topBorder.backgroundColor = [UIColor colorWithRed:0.70 green:0.70 blue:0.70 alpha:1.0];
|
||||
|
||||
[rootView addSubview:dismissButton];
|
||||
[rootView addSubview:reloadButton];
|
||||
[rootView addSubview:copyButton];
|
||||
[rootView addSubview:extraButton];
|
||||
[rootView addSubview:topBorder];
|
||||
|
||||
UIView *bottomSafeView = [UIView new];
|
||||
bottomSafeView.backgroundColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1];
|
||||
bottomSafeView.frame = CGRectMake(0, self.bounds.size.height - [self bottomSafeViewHeight], self.bounds.size.width, [self bottomSafeViewHeight]);
|
||||
|
||||
[rootView addSubview:bottomSafeView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSInteger)bottomSafeViewHeight
|
||||
{
|
||||
if (@available(iOS 11.0, *)) {
|
||||
return [UIApplication sharedApplication].delegate.window.safeAreaInsets.bottom;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
|
||||
|
||||
- (void)dealloc
|
||||
@@ -247,14 +279,14 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
|
||||
- (UITableViewCell *)reuseCell:(UITableViewCell *)cell forErrorMessage:(NSString *)message
|
||||
{
|
||||
if (!cell) {
|
||||
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"msg-cell"];
|
||||
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"msg-cell"];
|
||||
cell.textLabel.accessibilityIdentifier = @"redbox-error";
|
||||
cell.textLabel.textColor = [UIColor whiteColor];
|
||||
cell.textLabel.font = [UIFont boldSystemFontOfSize:16];
|
||||
cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
|
||||
cell.textLabel.numberOfLines = 0;
|
||||
cell.detailTextLabel.textColor = [UIColor whiteColor];
|
||||
cell.backgroundColor = [UIColor clearColor];
|
||||
cell.backgroundColor = [UIColor colorWithRed:0.82 green:0.10 blue:0.15 alpha:1.0];
|
||||
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||
}
|
||||
|
||||
@@ -267,11 +299,11 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
|
||||
{
|
||||
if (!cell) {
|
||||
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cell"];
|
||||
cell.textLabel.textColor = [UIColor colorWithWhite:1 alpha:0.9];
|
||||
cell.textLabel.textColor = [UIColor whiteColor];
|
||||
cell.textLabel.font = [UIFont fontWithName:@"Menlo-Regular" size:14];
|
||||
cell.textLabel.lineBreakMode = NSLineBreakByCharWrapping;
|
||||
cell.textLabel.numberOfLines = 2;
|
||||
cell.detailTextLabel.textColor = [UIColor colorWithWhite:1 alpha:0.7];
|
||||
cell.detailTextLabel.textColor = [UIColor colorWithRed:0.70 green:0.70 blue:0.70 alpha:1.0];
|
||||
cell.detailTextLabel.font = [UIFont fontWithName:@"Menlo-Regular" size:11];
|
||||
cell.detailTextLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
|
||||
cell.backgroundColor = [UIColor clearColor];
|
||||
|
||||
@@ -4023,14 +4023,10 @@
|
||||
"../third-party/glog-0.3.5/src/glog/raw_logging.h",
|
||||
"../third-party/glog-0.3.5/src/glog/stl_logging.h",
|
||||
"../third-party/glog-0.3.5/src/glog/vlog_is_on.h",
|
||||
"../third-party/folly-2018.10.22.00/folly/detail/MallocImpl.cpp",
|
||||
"../third-party/folly-2018.10.22.00/folly/portability/BitsFunctexcept.cpp",
|
||||
"../third-party/folly-2018.10.22.00/folly/memory/detail/MallocImpl.cpp",
|
||||
"../third-party/folly-2018.10.22.00/folly/Demangle.cpp",
|
||||
"../third-party/folly-2018.10.22.00/folly/StringBase.cpp",
|
||||
"../third-party/folly-2018.10.22.00/folly/Unicode.cpp",
|
||||
"../third-party/folly-2018.10.22.00/folly/AtomicIntrusiveLinkedList.h",
|
||||
"../third-party/folly-2018.10.22.00/folly/Bits.cpp",
|
||||
"../third-party/folly-2018.10.22.00/folly/Bits.h",
|
||||
"../third-party/folly-2018.10.22.00/folly/Conv.cpp",
|
||||
"../third-party/folly-2018.10.22.00/folly/Conv.h",
|
||||
"../third-party/folly-2018.10.22.00/folly/dynamic-inl.h",
|
||||
@@ -4043,6 +4039,15 @@
|
||||
"../third-party/folly-2018.10.22.00/folly/MoveWrapper.h",
|
||||
"../third-party/folly-2018.10.22.00/folly/Optional.h",
|
||||
"../third-party/folly-2018.10.22.00/folly/ScopeGuard.h",
|
||||
"../third-party/folly-2018.10.22.00/folly/json_pointer.cpp",
|
||||
"../third-party/folly-2018.10.22.00/folly/String.cpp",
|
||||
"../third-party/folly-2018.10.22.00/folly/detail/Demangle.cpp",
|
||||
"../third-party/folly-2018.10.22.00/folly/hash/SpookyHashV2.cpp",
|
||||
"../third-party/folly-2018.10.22.00/folly/lang/ColdClass.cpp",
|
||||
"../third-party/folly-2018.10.22.00/folly/container/detail/F14Table.cpp",
|
||||
"../third-party/folly-2018.10.22.00/folly/ScopeGuard.cpp",
|
||||
"../third-party/folly-2018.10.22.00/folly/lang/Assume.cpp",
|
||||
"../third-party/folly-2018.10.22.00/folly/Format.cpp",
|
||||
"../third-party/double-conversion-1.1.6/src/bignum-dtoa.cc",
|
||||
"../third-party/double-conversion-1.1.6/src/bignum-dtoa.h",
|
||||
"../third-party/double-conversion-1.1.6/src/bignum.cc",
|
||||
|
||||
@@ -303,7 +303,10 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
||||
contentOffset.y = -(scrollViewSize.height - subviewSize.height) / 2.0;
|
||||
}
|
||||
}
|
||||
super.contentOffset = contentOffset;
|
||||
|
||||
super.contentOffset = CGPointMake(
|
||||
RCTSanitizeNaNValue(contentOffset.x, @"scrollView.contentOffset.x"),
|
||||
RCTSanitizeNaNValue(contentOffset.y, @"scrollView.contentOffset.y"));
|
||||
}
|
||||
|
||||
- (void)setFrame:(CGRect)frame
|
||||
|
||||
@@ -266,8 +266,8 @@ task packageReactNdkLibsForBuck(dependsOn: packageReactNdkLibs, type: Copy) {
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 27
|
||||
buildToolsVersion "27.0.3"
|
||||
compileSdkVersion 28
|
||||
buildToolsVersion "28.0.2"
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 16
|
||||
@@ -316,14 +316,14 @@ android {
|
||||
dependencies {
|
||||
api 'com.facebook.infer.annotation:infer-annotation:0.11.2'
|
||||
api 'javax.inject:javax.inject:1'
|
||||
api 'com.android.support:appcompat-v7:27.1.1'
|
||||
api 'com.android.support:appcompat-v7:28.0.0'
|
||||
api "com.facebook.fresco:fresco:${FRESCO_VERSION}"
|
||||
api "com.facebook.fresco:imagepipeline-okhttp3:${FRESCO_VERSION}"
|
||||
api 'com.facebook.soloader:soloader:0.5.1'
|
||||
api 'com.google.code.findbugs:jsr305:3.0.2'
|
||||
api "com.squareup.okhttp3:okhttp:${OKHTTP_VERSION}"
|
||||
api "com.squareup.okhttp3:okhttp-urlconnection:${OKHTTP_VERSION}"
|
||||
api 'com.squareup.okio:okio:1.14.0'
|
||||
api 'com.squareup.okio:okio:1.15.0'
|
||||
compile 'org.webkit:android-jsc:r174650'
|
||||
|
||||
testImplementation "junit:junit:${JUNIT_VERSION}"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
VERSION_NAME=1000.0.0-master
|
||||
VERSION_NAME=0.58.3
|
||||
GROUP=com.facebook.react
|
||||
|
||||
POM_NAME=ReactNative
|
||||
@@ -13,7 +13,7 @@ FEST_ASSERT_CORE_VERSION=2.0M10
|
||||
|
||||
ANDROID_SUPPORT_TEST_VERSION=1.0.2
|
||||
FRESCO_VERSION=1.10.0
|
||||
OKHTTP_VERSION=3.11.0
|
||||
OKHTTP_VERSION=3.12.1
|
||||
|
||||
BOOST_VERSION=1_63_0
|
||||
DOUBLE_CONVERSION_VERSION=1.1.6
|
||||
|
||||
@@ -8,8 +8,8 @@ fb_native.android_prebuilt_aar(
|
||||
|
||||
fb_native.remote_file(
|
||||
name = "appcompat-binary-aar",
|
||||
sha1 = "22b1ef4ff9ef1a3513c18eb132d597eac6ef1a86",
|
||||
url = "mvn:com.android.support:appcompat-v7:aar:27.1.1",
|
||||
sha1 = "132586ec59604a86703796851a063a0ac61f697b",
|
||||
url = "mvn:com.android.support:appcompat-v7:aar:28.0.0",
|
||||
)
|
||||
|
||||
fb_native.android_prebuilt_aar(
|
||||
|
||||
@@ -28,7 +28,6 @@ rn_android_library(
|
||||
"PUBLIC",
|
||||
],
|
||||
deps = [
|
||||
react_native_dep("third-party/android/support-annotations:android-support-annotations"),
|
||||
react_native_dep("java/com/facebook/debug/debugoverlay/model:model"),
|
||||
react_native_dep("java/com/facebook/systrace:systrace"),
|
||||
react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"),
|
||||
|
||||
@@ -7,48 +7,119 @@
|
||||
|
||||
package com.facebook.react.bridge;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
/*
|
||||
* Interface that represents a JavaScript Promise which can be passed to the native module as a
|
||||
* method parameter.
|
||||
*
|
||||
* Methods annotated with {@link ReactMethod} that use {@link Promise} as type of the last parameter
|
||||
* Methods annotated with {@link ReactMethod} that use a {@link Promise} as the last parameter
|
||||
* will be marked as "promise" and will return a promise when invoked from JavaScript.
|
||||
*/
|
||||
public interface Promise {
|
||||
|
||||
/**
|
||||
* Successfully resolve the Promise.
|
||||
* Successfully resolve the Promise with an optional value.
|
||||
*
|
||||
* @param value Object
|
||||
*/
|
||||
void resolve(@Nullable Object value);
|
||||
|
||||
/**
|
||||
* Report an error which wasn't caused by an exception.
|
||||
* Report an error without an exception using a custom code and error message.
|
||||
*
|
||||
* @param code String
|
||||
* @param message String
|
||||
*/
|
||||
void reject(String code, String message);
|
||||
|
||||
/**
|
||||
* Report an exception.
|
||||
* Report an exception with a custom code.
|
||||
*
|
||||
* @param code String
|
||||
* @param throwable Throwable
|
||||
*/
|
||||
void reject(String code, Throwable e);
|
||||
void reject(String code, Throwable throwable);
|
||||
|
||||
/**
|
||||
* Report an exception with a custom error message.
|
||||
* Report an exception with a custom code and error message.
|
||||
*
|
||||
* @param code String
|
||||
* @param message String
|
||||
* @param throwable Throwable
|
||||
*/
|
||||
void reject(String code, String message, Throwable e);
|
||||
void reject(String code, String message, Throwable throwable);
|
||||
|
||||
/**
|
||||
* Report an error which wasn't caused by an exception.
|
||||
* @deprecated Prefer passing a module-specific error code to JS.
|
||||
* Using this method will pass the error code "EUNSPECIFIED".
|
||||
*/
|
||||
@Deprecated
|
||||
void reject(String message);
|
||||
|
||||
/**
|
||||
* Report an exception, with default error code.
|
||||
* Useful in catch-all scenarios where it's unclear why the error occurred.
|
||||
*
|
||||
* @param throwable Throwable
|
||||
*/
|
||||
void reject(Throwable reason);
|
||||
void reject(Throwable throwable);
|
||||
|
||||
/* ---------------------------
|
||||
* With userInfo WritableMap
|
||||
* --------------------------- */
|
||||
|
||||
/**
|
||||
* Report an exception, with default error code, with userInfo.
|
||||
* Useful in catch-all scenarios where it's unclear why the error occurred.
|
||||
*
|
||||
* @param throwable Throwable
|
||||
* @param userInfo WritableMap
|
||||
*/
|
||||
void reject(Throwable throwable, WritableMap userInfo);
|
||||
|
||||
/**
|
||||
* Reject with a code and userInfo WritableMap.
|
||||
*
|
||||
* @param code String
|
||||
* @param userInfo WritableMap
|
||||
*/
|
||||
void reject(String code, @Nonnull WritableMap userInfo);
|
||||
|
||||
/**
|
||||
* Report an exception with a custom code and userInfo.
|
||||
*
|
||||
* @param code String
|
||||
* @param throwable Throwable
|
||||
* @param userInfo WritableMap
|
||||
*/
|
||||
void reject(String code, Throwable throwable, WritableMap userInfo);
|
||||
|
||||
/**
|
||||
* Report an error with a custom code, error message and userInfo,
|
||||
* an error not caused by an exception.
|
||||
*
|
||||
* @param code String
|
||||
* @param message String
|
||||
* @param userInfo WritableMap
|
||||
*/
|
||||
void reject(String code, String message, @Nonnull WritableMap userInfo);
|
||||
|
||||
/**
|
||||
* Report an exception with a custom code, error message and userInfo.
|
||||
*
|
||||
* @param code String
|
||||
* @param message String
|
||||
* @param throwable Throwable
|
||||
* @param userInfo WritableMap
|
||||
*/
|
||||
void reject(String code, String message, Throwable throwable, WritableMap userInfo);
|
||||
|
||||
/* ------------
|
||||
* Deprecated
|
||||
* ------------ */
|
||||
|
||||
/**
|
||||
* Report an error which wasn't caused by an exception.
|
||||
*
|
||||
* @deprecated Prefer passing a module-specific error code to JS.
|
||||
* Using this method will pass the error code "EUNSPECIFIED".
|
||||
*/
|
||||
@Deprecated
|
||||
void reject(String message);
|
||||
}
|
||||
|
||||
@@ -5,67 +5,242 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implementation of two javascript functions that can be used to resolve or reject a js promise.
|
||||
*/
|
||||
package com.facebook.react.bridge;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/*
|
||||
* Implementation of {@link Promise} that represents a JavaScript Promise which can be passed to the
|
||||
* native module as a method parameter.
|
||||
*
|
||||
* Methods annotated with {@link ReactMethod} that use a {@link Promise} as the last parameter
|
||||
* will be marked as "promise" and will return a promise when invoked from JavaScript.
|
||||
*/
|
||||
public class PromiseImpl implements Promise {
|
||||
// Number of stack frames to parse and return to mReject.invoke
|
||||
// for ERROR_MAP_KEY_NATIVE_STACK
|
||||
private static final int ERROR_STACK_FRAME_LIMIT = 10;
|
||||
|
||||
private static final String DEFAULT_ERROR = "EUNSPECIFIED";
|
||||
private static final String ERROR_DEFAULT_CODE = "EUNSPECIFIED";
|
||||
private static final String ERROR_DEFAULT_MESSAGE = "Error not specified.";
|
||||
|
||||
private @Nullable Callback mResolve;
|
||||
private @Nullable Callback mReject;
|
||||
// Keys for mReject's WritableMap
|
||||
private static final String ERROR_MAP_KEY_CODE = "code";
|
||||
private static final String ERROR_MAP_KEY_MESSAGE = "message";
|
||||
private static final String ERROR_MAP_KEY_USER_INFO = "userInfo";
|
||||
private static final String ERROR_MAP_KEY_NATIVE_STACK = "nativeStackAndroid";
|
||||
|
||||
// Keys for ERROR_MAP_KEY_NATIVE_STACK's StackFrame maps
|
||||
private static final String STACK_FRAME_KEY_FILE = "file";
|
||||
private static final String STACK_FRAME_KEY_LINE_NUMBER = "lineNumber";
|
||||
private static final String STACK_FRAME_KEY_METHOD_NAME = "methodName";
|
||||
|
||||
private @Nullable
|
||||
Callback mResolve;
|
||||
private @Nullable
|
||||
Callback mReject;
|
||||
|
||||
public PromiseImpl(@Nullable Callback resolve, @Nullable Callback reject) {
|
||||
mResolve = resolve;
|
||||
mReject = reject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Successfully resolve the Promise with an optional value.
|
||||
*
|
||||
* @param value Object
|
||||
*/
|
||||
@Override
|
||||
public void resolve(Object value) {
|
||||
if (mResolve != null) {
|
||||
mResolve.invoke(value);
|
||||
mResolve = null;
|
||||
mReject = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Report an error without an exception using a custom code and error message.
|
||||
*
|
||||
* @param code String
|
||||
* @param message String
|
||||
*/
|
||||
@Override
|
||||
public void reject(String code, String message) {
|
||||
reject(code, message, /*Throwable*/null);
|
||||
reject(code, message, /*Throwable*/null, /*WritableMap*/null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report an exception with a custom code.
|
||||
*
|
||||
* @param code String
|
||||
* @param throwable Throwable
|
||||
*/
|
||||
@Override
|
||||
public void reject(String code, Throwable throwable) {
|
||||
reject(code, /*Message*/null, throwable, /*WritableMap*/null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report an exception with a custom code and error message.
|
||||
*
|
||||
* @param code String
|
||||
* @param message String
|
||||
* @param throwable Throwable
|
||||
*/
|
||||
@Override
|
||||
public void reject(String code, String message, Throwable throwable) {
|
||||
reject(code, message, throwable, /*WritableMap*/null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report an exception, with default error code.
|
||||
* Useful in catch-all scenarios where it's unclear why the error occurred.
|
||||
*
|
||||
* @param throwable Throwable
|
||||
*/
|
||||
@Override
|
||||
public void reject(Throwable throwable) {
|
||||
reject(/*Code*/null, /*Message*/null, throwable, /*WritableMap*/null);
|
||||
}
|
||||
|
||||
/* ---------------------------
|
||||
* With userInfo WritableMap
|
||||
* --------------------------- */
|
||||
|
||||
/**
|
||||
* Report an exception, with default error code, with userInfo.
|
||||
* Useful in catch-all scenarios where it's unclear why the error occurred.
|
||||
*
|
||||
* @param throwable Throwable
|
||||
* @param userInfo WritableMap
|
||||
*/
|
||||
@Override
|
||||
public void reject(Throwable throwable, WritableMap userInfo) {
|
||||
reject(/*Code*/null, /*Message*/null, throwable, userInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reject with a code and userInfo WritableMap.
|
||||
*
|
||||
* @param code String
|
||||
* @param userInfo WritableMap
|
||||
*/
|
||||
@Override
|
||||
public void reject(String code, @Nonnull WritableMap userInfo) {
|
||||
reject(code, /*Message*/null, /*Throwable*/null, userInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report an exception with a custom code and userInfo.
|
||||
*
|
||||
* @param code String
|
||||
* @param throwable Throwable
|
||||
* @param userInfo WritableMap
|
||||
*/
|
||||
@Override
|
||||
public void reject(String code, Throwable throwable, WritableMap userInfo) {
|
||||
reject(code, /*Message*/null, throwable, userInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report an error with a custom code, error message and userInfo,
|
||||
* an error not caused by an exception.
|
||||
*
|
||||
* @param code String
|
||||
* @param message String
|
||||
* @param userInfo WritableMap
|
||||
*/
|
||||
@Override
|
||||
public void reject(String code, String message, @Nonnull WritableMap userInfo) {
|
||||
reject(code, message, /*Throwable*/null, userInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report an exception with a custom code, error message and userInfo.
|
||||
*
|
||||
* @param code String
|
||||
* @param message String
|
||||
* @param throwable Throwable
|
||||
* @param userInfo WritableMap
|
||||
*/
|
||||
@Override
|
||||
public void reject(
|
||||
@Nullable String code,
|
||||
@Nullable String message,
|
||||
@Nullable Throwable throwable,
|
||||
@Nullable WritableMap userInfo
|
||||
) {
|
||||
if (mReject == null) {
|
||||
mResolve = null;
|
||||
return;
|
||||
}
|
||||
|
||||
WritableNativeMap errorInfo = new WritableNativeMap();
|
||||
|
||||
if (code == null) {
|
||||
errorInfo.putString(ERROR_MAP_KEY_CODE, ERROR_DEFAULT_CODE);
|
||||
} else {
|
||||
errorInfo.putString(ERROR_MAP_KEY_CODE, code);
|
||||
}
|
||||
|
||||
// Use the custom message if provided otherwise use the throwable message.
|
||||
if (message != null) {
|
||||
errorInfo.putString(ERROR_MAP_KEY_MESSAGE, message);
|
||||
} else if (throwable != null) {
|
||||
errorInfo.putString(ERROR_MAP_KEY_MESSAGE, throwable.getMessage());
|
||||
} else {
|
||||
// The JavaScript side expects a map with at least an error message.
|
||||
// /Libraries/BatchedBridge/NativeModules.js -> createErrorFromErrorData
|
||||
// TYPE: (errorData: { message: string })
|
||||
errorInfo.putString(ERROR_MAP_KEY_MESSAGE, ERROR_DEFAULT_MESSAGE);
|
||||
}
|
||||
|
||||
// For consistency with iOS ensure userInfo key exists, even if we null it.
|
||||
// iOS: /React/Base/RCTUtils.m -> RCTJSErrorFromCodeMessageAndNSError
|
||||
if (userInfo != null) {
|
||||
errorInfo.putMap(ERROR_MAP_KEY_USER_INFO, userInfo);
|
||||
} else {
|
||||
errorInfo.putNull(ERROR_MAP_KEY_USER_INFO);
|
||||
}
|
||||
|
||||
// Attach a nativeStackAndroid array if a throwable was passed
|
||||
// this matches iOS behavior - iOS adds a `nativeStackIOS` property
|
||||
// iOS: /React/Base/RCTUtils.m -> RCTJSErrorFromCodeMessageAndNSError
|
||||
if (throwable != null) {
|
||||
StackTraceElement[] stackTrace = throwable.getStackTrace();
|
||||
WritableNativeArray nativeStackAndroid = new WritableNativeArray();
|
||||
|
||||
// Build an an Array of StackFrames to match JavaScript:
|
||||
// iOS: /Libraries/Core/Devtools/parseErrorStack.js -> StackFrame
|
||||
for (int i = 0; i < stackTrace.length && i < ERROR_STACK_FRAME_LIMIT; i++) {
|
||||
StackTraceElement frame = stackTrace[i];
|
||||
WritableMap frameMap = new WritableNativeMap();
|
||||
// NOTE: no column number exists StackTraceElement
|
||||
frameMap.putString(STACK_FRAME_KEY_FILE, frame.getFileName());
|
||||
frameMap.putInt(STACK_FRAME_KEY_LINE_NUMBER, frame.getLineNumber());
|
||||
frameMap.putString(STACK_FRAME_KEY_METHOD_NAME, frame.getMethodName());
|
||||
nativeStackAndroid.pushMap(frameMap);
|
||||
}
|
||||
|
||||
errorInfo.putArray(ERROR_MAP_KEY_NATIVE_STACK, nativeStackAndroid);
|
||||
} else {
|
||||
errorInfo.putArray(ERROR_MAP_KEY_NATIVE_STACK, new WritableNativeArray());
|
||||
}
|
||||
|
||||
mReject.invoke(errorInfo);
|
||||
mResolve = null;
|
||||
mReject = null;
|
||||
}
|
||||
|
||||
/* ------------
|
||||
* Deprecated
|
||||
* ------------ */
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void reject(String message) {
|
||||
reject(DEFAULT_ERROR, message, /*Throwable*/null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reject(String code, Throwable e) {
|
||||
reject(code, e.getMessage(), e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reject(Throwable e) {
|
||||
reject(DEFAULT_ERROR, e.getMessage(), e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reject(String code, String message, @Nullable Throwable e) {
|
||||
if (mReject != null) {
|
||||
if (code == null) {
|
||||
code = DEFAULT_ERROR;
|
||||
}
|
||||
// The JavaScript side expects a map with at least the error message.
|
||||
// It is possible to expose all kind of information. It will be available on the JS
|
||||
// error instance.
|
||||
WritableNativeMap errorInfo = new WritableNativeMap();
|
||||
errorInfo.putString("code", code);
|
||||
errorInfo.putString("message", message);
|
||||
// TODO(8850038): add the stack trace info in, need to figure out way to serialize that
|
||||
mReject.invoke(errorInfo);
|
||||
}
|
||||
reject(/*Code*/null, message, /*Throwable*/null, /*WritableMap*/null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ rn_android_library(
|
||||
],
|
||||
deps = [
|
||||
react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"),
|
||||
react_native_dep("third-party/android/support-annotations:android-support-annotations"),
|
||||
react_native_dep("third-party/java/infer-annotations:infer-annotations"),
|
||||
react_native_dep("third-party/java/jsr-305:jsr-305"),
|
||||
react_native_dep("third-party/java/okhttp:okhttp3"),
|
||||
|
||||
@@ -4,7 +4,6 @@ rn_android_library(
|
||||
name = "blob",
|
||||
srcs = glob(["**/*.java"]),
|
||||
provided_deps = [
|
||||
react_native_dep("third-party/android/support-annotations:android-support-annotations"),
|
||||
react_native_dep("third-party/android/support/v4:lib-support-v4"),
|
||||
],
|
||||
visibility = [
|
||||
|
||||
@@ -4,7 +4,6 @@ rn_android_library(
|
||||
name = "fresco",
|
||||
srcs = glob(["**/*.java"]),
|
||||
provided_deps = [
|
||||
react_native_dep("third-party/android/support-annotations:android-support-annotations"),
|
||||
react_native_dep("third-party/android/support/v4:lib-support-v4"),
|
||||
],
|
||||
visibility = [
|
||||
|
||||
@@ -103,7 +103,7 @@ public class NetInfoModule extends ReactContextBaseJavaModule
|
||||
@ReactMethod
|
||||
public void getCurrentConnectivity(Promise promise) {
|
||||
if (mNoNetworkPermission) {
|
||||
promise.reject(ERROR_MISSING_PERMISSION, MISSING_PERMISSION_MESSAGE, null);
|
||||
promise.reject(ERROR_MISSING_PERMISSION, MISSING_PERMISSION_MESSAGE);
|
||||
return;
|
||||
}
|
||||
promise.resolve(createConnectivityEventMap());
|
||||
@@ -112,7 +112,7 @@ public class NetInfoModule extends ReactContextBaseJavaModule
|
||||
@ReactMethod
|
||||
public void isConnectionMetered(Promise promise) {
|
||||
if (mNoNetworkPermission) {
|
||||
promise.reject(ERROR_MISSING_PERMISSION, MISSING_PERMISSION_MESSAGE, null);
|
||||
promise.reject(ERROR_MISSING_PERMISSION, MISSING_PERMISSION_MESSAGE);
|
||||
return;
|
||||
}
|
||||
promise.resolve(ConnectivityManagerCompat.isActiveNetworkMetered(mConnectivityManager));
|
||||
|
||||
@@ -163,7 +163,7 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
|
||||
* @param context the ReactContext of the application
|
||||
*/
|
||||
public NetworkingModule(final ReactApplicationContext context) {
|
||||
this(context, null, OkHttpClientProvider.createClient(), null);
|
||||
this(context, null, OkHttpClientProvider.createClient(context), null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -174,7 +174,7 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
|
||||
public NetworkingModule(
|
||||
ReactApplicationContext context,
|
||||
List<NetworkInterceptorCreator> networkInterceptorCreators) {
|
||||
this(context, null, OkHttpClientProvider.createClient(), networkInterceptorCreators);
|
||||
this(context, null, OkHttpClientProvider.createClient(context), networkInterceptorCreators);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -183,7 +183,7 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
|
||||
* caller does not provide one explicitly
|
||||
*/
|
||||
public NetworkingModule(ReactApplicationContext context, String defaultUserAgent) {
|
||||
this(context, defaultUserAgent, OkHttpClientProvider.createClient(), null);
|
||||
this(context, defaultUserAgent, OkHttpClientProvider.createClient(context), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -7,16 +7,19 @@
|
||||
|
||||
package com.facebook.react.modules.network;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
|
||||
import com.facebook.common.logging.FLog;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import okhttp3.Cache;
|
||||
import okhttp3.ConnectionSpec;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.TlsVersion;
|
||||
@@ -57,6 +60,13 @@ public class OkHttpClientProvider {
|
||||
return createClientBuilder().build();
|
||||
}
|
||||
|
||||
public static OkHttpClient createClient(Context context) {
|
||||
if (sFactory != null) {
|
||||
return sFactory.createNewNetworkModuleClient();
|
||||
}
|
||||
return createClientBuilder(context).build();
|
||||
}
|
||||
|
||||
public static OkHttpClient.Builder createClientBuilder() {
|
||||
// No timeouts by default
|
||||
OkHttpClient.Builder client = new OkHttpClient.Builder()
|
||||
@@ -68,6 +78,24 @@ public class OkHttpClientProvider {
|
||||
return enableTls12OnPreLollipop(client);
|
||||
}
|
||||
|
||||
public static OkHttpClient.Builder createClientBuilder(Context context) {
|
||||
int cacheSize = 10 * 1024 * 1024; // 10 Mo
|
||||
return createClientBuilder(context, cacheSize);
|
||||
}
|
||||
|
||||
public static OkHttpClient.Builder createClientBuilder(Context context, int cacheSize) {
|
||||
OkHttpClient.Builder client = createClientBuilder();
|
||||
|
||||
if (cacheSize == 0) {
|
||||
return client;
|
||||
}
|
||||
|
||||
File cacheDirectory = new File(context.getCacheDir(), "http-cache");
|
||||
Cache cache = new Cache(cacheDirectory, cacheSize);
|
||||
|
||||
return client.cache(cache);
|
||||
}
|
||||
|
||||
/*
|
||||
On Android 4.1-4.4 (API level 16 to 19) TLS 1.1 and 1.2 are
|
||||
available but not enabled by default. The following method
|
||||
|
||||
@@ -166,7 +166,7 @@ public class StatusBarModule extends ReactContextBaseJavaModule {
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void setStyle(final String style) {
|
||||
public void setStyle(@Nullable final String style) {
|
||||
final Activity activity = getCurrentActivity();
|
||||
if (activity == null) {
|
||||
FLog.w(ReactConstants.TAG, "StatusBarModule: Ignored status bar change, current activity is null.");
|
||||
@@ -181,7 +181,7 @@ public class StatusBarModule extends ReactContextBaseJavaModule {
|
||||
public void run() {
|
||||
View decorView = activity.getWindow().getDecorView();
|
||||
decorView.setSystemUiVisibility(
|
||||
style.equals("dark-content") ? View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR : 0);
|
||||
"dark-content".equals(style) ? View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR : 0);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -16,7 +16,7 @@ import java.util.Map;
|
||||
public class ReactNativeVersion {
|
||||
public static final Map<String, Object> VERSION = MapBuilder.<String, Object>of(
|
||||
"major", 0,
|
||||
"minor", 0,
|
||||
"patch", 0,
|
||||
"minor", 58,
|
||||
"patch", 3,
|
||||
"prerelease", null);
|
||||
}
|
||||
|
||||
@@ -357,7 +357,7 @@ public final class WebSocketModule extends ReactContextBaseJavaModule {
|
||||
requestURI.getHost(),
|
||||
requestURI.getPort());
|
||||
} else {
|
||||
defaultOrigin = String.format("%s://%s/", scheme, requestURI.getHost());
|
||||
defaultOrigin = String.format("%s://%s", scheme, requestURI.getHost());
|
||||
}
|
||||
|
||||
return defaultOrigin;
|
||||
|
||||
@@ -13,7 +13,6 @@ rn_android_library(
|
||||
),
|
||||
provided_deps = [
|
||||
react_native_dep("third-party/android/support/v4:lib-support-v4"),
|
||||
react_native_dep("third-party/android/support-annotations:android-support-annotations"),
|
||||
],
|
||||
required_for_source_only_abi = True,
|
||||
visibility = [
|
||||
|
||||
@@ -626,6 +626,7 @@ public class UIViewOperationQueue {
|
||||
private long mProfiledBatchRunStartTime;
|
||||
private long mProfiledBatchBatchedExecutionTime;
|
||||
private long mProfiledBatchNonBatchedExecutionTime;
|
||||
private long mThreadCpuTime;
|
||||
|
||||
public UIViewOperationQueue(
|
||||
ReactApplicationContext reactContext,
|
||||
@@ -664,6 +665,7 @@ public class UIViewOperationQueue {
|
||||
perfMap.put("RunStartTime", mProfiledBatchRunStartTime);
|
||||
perfMap.put("BatchedExecutionTime", mProfiledBatchBatchedExecutionTime);
|
||||
perfMap.put("NonBatchedExecutionTime", mProfiledBatchNonBatchedExecutionTime);
|
||||
perfMap.put("NativeModulesThreadCpuTime", mThreadCpuTime);
|
||||
return perfMap;
|
||||
}
|
||||
|
||||
@@ -866,6 +868,7 @@ public class UIViewOperationQueue {
|
||||
.flush();
|
||||
try {
|
||||
final long dispatchViewUpdatesTime = SystemClock.uptimeMillis();
|
||||
final long nativeModulesThreadCpuTime = SystemClock.currentThreadTimeMillis();
|
||||
|
||||
// Store the current operation queues to dispatch and create new empty ones to continue
|
||||
// receiving new operations
|
||||
@@ -920,6 +923,7 @@ public class UIViewOperationQueue {
|
||||
mProfiledBatchLayoutTime = layoutTime;
|
||||
mProfiledBatchDispatchViewUpdatesTime = dispatchViewUpdatesTime;
|
||||
mProfiledBatchRunStartTime = runStartTime;
|
||||
mThreadCpuTime = nativeModulesThreadCpuTime;
|
||||
|
||||
Systrace.beginAsyncSection(
|
||||
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
|
||||
|
||||
@@ -5,7 +5,6 @@ rn_android_library(
|
||||
srcs = glob(["*.java"]),
|
||||
provided_deps = [
|
||||
react_native_dep("third-party/android/support/v4:lib-support-v4"),
|
||||
react_native_dep("third-party/android/support-annotations:android-support-annotations"),
|
||||
],
|
||||
visibility = [
|
||||
"PUBLIC",
|
||||
|
||||
@@ -8,7 +8,6 @@ rn_android_library(
|
||||
name = "imageevents",
|
||||
srcs = IMAGE_EVENT_FILES,
|
||||
provided_deps = [
|
||||
react_native_dep("third-party/android/support-annotations:android-support-annotations"),
|
||||
react_native_dep("third-party/android/support/v4:lib-support-v4"),
|
||||
],
|
||||
required_for_source_only_abi = True,
|
||||
@@ -27,7 +26,6 @@ rn_android_library(
|
||||
exclude = IMAGE_EVENT_FILES,
|
||||
),
|
||||
provided_deps = [
|
||||
react_native_dep("third-party/android/support-annotations:android-support-annotations"),
|
||||
react_native_dep("third-party/android/support/v4:lib-support-v4"),
|
||||
],
|
||||
visibility = [
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
package com.facebook.react.views.modal;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
@@ -15,6 +16,7 @@ import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewStructure;
|
||||
import android.view.WindowManager;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.widget.FrameLayout;
|
||||
@@ -73,6 +75,12 @@ public class ReactModalHostView extends ViewGroup implements LifecycleEventListe
|
||||
mHostView = new DialogRootViewGroup(context);
|
||||
}
|
||||
|
||||
@TargetApi(23)
|
||||
@Override
|
||||
public void dispatchProvideStructure(ViewStructure structure) {
|
||||
mHostView.dispatchProvideStructure(structure);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
// Do nothing as we are laid out by UIManager
|
||||
|
||||
@@ -151,10 +151,14 @@ public abstract class ReactBaseTextShadowNode extends LayoutShadowNode {
|
||||
if (textShadowNode.mIsLineThroughTextDecorationSet) {
|
||||
ops.add(new SetSpanOperation(start, end, new StrikethroughSpan()));
|
||||
}
|
||||
if ((textShadowNode.mTextShadowOffsetDx != 0
|
||||
|| textShadowNode.mTextShadowOffsetDy != 0
|
||||
|| textShadowNode.mTextShadowRadius != 0)
|
||||
&& Color.alpha(textShadowNode.mTextShadowColor) != 0) {
|
||||
if (
|
||||
(
|
||||
textShadowNode.mTextShadowOffsetDx != 0 ||
|
||||
textShadowNode.mTextShadowOffsetDy != 0 ||
|
||||
textShadowNode.mTextShadowRadius != 0
|
||||
) &&
|
||||
Color.alpha(textShadowNode.mTextShadowColor) != 0
|
||||
) {
|
||||
ops.add(
|
||||
new SetSpanOperation(
|
||||
start,
|
||||
@@ -270,7 +274,7 @@ public abstract class ReactBaseTextShadowNode extends LayoutShadowNode {
|
||||
|
||||
protected float mTextShadowOffsetDx = 0;
|
||||
protected float mTextShadowOffsetDy = 0;
|
||||
protected float mTextShadowRadius = 1;
|
||||
protected float mTextShadowRadius = 0;
|
||||
protected int mTextShadowColor = DEFAULT_TEXT_SHADOW_COLOR;
|
||||
|
||||
protected boolean mIsUnderlineTextDecorationSet = false;
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<item>
|
||||
<shape android:shape="rectangle" >
|
||||
<solid android:color="#1A1A1A" />
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
<item android:bottom="-2dp" android:right="-2dp" android:left="-2dp">
|
||||
<shape>
|
||||
<solid android:color="@android:color/transparent" />
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="#B3B3B3" />
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
||||
@@ -19,7 +19,7 @@
|
||||
android:id="@+id/rn_frame_file"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="#E6B8B8"
|
||||
android:textColor="#B3B3B3"
|
||||
android:textSize="12sp"
|
||||
android:fontFamily="monospace"
|
||||
/>
|
||||
|
||||
@@ -7,4 +7,5 @@
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
android:background="#D01926"
|
||||
/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="#E80000"
|
||||
android:background="#1A1A1A"
|
||||
>
|
||||
<ListView
|
||||
android:id="@+id/rn_redbox_stack"
|
||||
@@ -53,6 +53,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:background="@drawable/redbox_top_border_background"
|
||||
>
|
||||
<Button
|
||||
android:id="@+id/rn_redbox_dismiss_button"
|
||||
|
||||