mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Compare commits
+101
-24
@@ -2,12 +2,12 @@ aliases:
|
||||
# Cache Management
|
||||
- &restore-yarn-cache
|
||||
keys:
|
||||
- v1-yarn-cache-{{ arch }}-{{ checksum "package.json" }}
|
||||
- v1-yarn-cache-{{ arch }}
|
||||
- v2-yarn-cache-{{ arch }}-{{ checksum "package.json" }}
|
||||
- v2-yarn-cache-{{ arch }}
|
||||
- &save-yarn-cache
|
||||
paths:
|
||||
- ~/.cache/yarn
|
||||
key: v1-yarn-cache-{{ arch }}-{{ checksum "package.json" }}
|
||||
key: v2-yarn-cache-{{ arch }}-{{ checksum "package.json" }}
|
||||
|
||||
- &restore-node-modules
|
||||
keys:
|
||||
@@ -26,28 +26,44 @@ aliases:
|
||||
- node_modules
|
||||
key: v1-analysis-dependencies-{{ arch }}-{{ checksum "package.json" }}{{ checksum "bots/package.json" }}
|
||||
|
||||
- &restore-cache-android-packages
|
||||
keys:
|
||||
- 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-28-alpha-{{ checksum "scripts/.tests.env" }}
|
||||
|
||||
- &restore-cache-gradle
|
||||
keys:
|
||||
- v1-gradle-{{ .Branch }}-{{ checksum "build.gradle" }}-{{ checksum "ReactAndroid/build.gradle" }}
|
||||
- v2-gradle-{{ .Branch }}-{{ checksum "build.gradle" }}-{{ checksum "ReactAndroid/build.gradle" }}
|
||||
# Fallback in case checksum fails
|
||||
- v1-gradle-{{ .Branch }}-{{ checksum "build.gradle" }}-
|
||||
- v1-gradle-{{ .Branch }}-
|
||||
- v2-gradle-{{ .Branch }}-{{ checksum "build.gradle" }}-
|
||||
- v2-gradle-{{ .Branch }}-
|
||||
# Fallback in case this is a first-time run on a fork
|
||||
- v1-gradle-master-
|
||||
- v2-gradle-master-
|
||||
- &save-cache-gradle
|
||||
paths:
|
||||
- ~/.gradle
|
||||
key: v1-gradle-{{ .Branch }}-{{ checksum "build.gradle" }}-{{ checksum "ReactAndroid/build.gradle" }}
|
||||
key: v2-gradle-{{ .Branch }}-{{ checksum "build.gradle" }}-{{ checksum "ReactAndroid/build.gradle" }}
|
||||
|
||||
- &restore-cache-ndk
|
||||
keys:
|
||||
- v3-android-ndk-r17c-{{ checksum "scripts/android-setup.sh" }}
|
||||
- &save-cache-ndk
|
||||
paths:
|
||||
- /opt/ndk
|
||||
key: v3-android-ndk-r17c-{{ checksum "scripts/android-setup.sh" }}
|
||||
|
||||
- &restore-cache-downloads-buck
|
||||
keys:
|
||||
- v3-buck-v2019.01.10.01-{{ checksum "scripts/circleci/buck_fetch.sh" }}}
|
||||
- v3-buck-v2019.01.10.01-
|
||||
- v4-buck-v2019.01.10.01-{{ checksum "scripts/circleci/buck_fetch.sh" }}}
|
||||
- v4-buck-v2019.01.10.01-
|
||||
- &save-cache-downloads-buck
|
||||
paths:
|
||||
- ~/buck
|
||||
- ~/okbuck
|
||||
key: v3-buck-v2019.01.10.01-{{ checksum "scripts/circleci/buck_fetch.sh" }}
|
||||
key: v4-buck-v2019.01.10.01-{{ checksum "scripts/circleci/buck_fetch.sh" }}
|
||||
|
||||
- &restore-cache-watchman
|
||||
keys:
|
||||
@@ -59,14 +75,14 @@ aliases:
|
||||
|
||||
- &restore-cache-downloads-gradle
|
||||
keys:
|
||||
- v1-gradle-{{ checksum "ReactAndroid/build.gradle" }}-{{ checksum "scripts/circleci/gradle_download_deps.sh" }}
|
||||
- v1-gradle-
|
||||
- v2-gradle-{{ checksum "ReactAndroid/build.gradle" }}-{{ checksum "scripts/circleci/gradle_download_deps.sh" }}
|
||||
- v2-gradle-
|
||||
- &save-cache-downloads-gradle
|
||||
paths:
|
||||
- ~/.gradle
|
||||
- ReactAndroid/build/downloads
|
||||
- ReactAndroid/build/third-party-ndk
|
||||
key: v1-gradle-{{ checksum "ReactAndroid/build.gradle" }}-{{ checksum "scripts/circleci/gradle_download_deps.sh" }}
|
||||
key: v2-gradle-{{ checksum "ReactAndroid/build.gradle" }}-{{ checksum "scripts/circleci/gradle_download_deps.sh" }}
|
||||
|
||||
- &restore-cache-homebrew
|
||||
keys:
|
||||
@@ -99,6 +115,11 @@ aliases:
|
||||
- /.*-stable/
|
||||
- gh-pages
|
||||
|
||||
# Dependency Management
|
||||
- &install-ndk
|
||||
name: Install Android NDK
|
||||
command: source scripts/android-setup.sh && getAndroidNDK
|
||||
|
||||
- &yarn
|
||||
name: Run Yarn
|
||||
command: |
|
||||
@@ -108,9 +129,20 @@ aliases:
|
||||
yarn install --non-interactive --cache-folder ~/.cache/yarn
|
||||
fi
|
||||
|
||||
- &install-yarn
|
||||
name: Install Yarn
|
||||
command: |
|
||||
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
|
||||
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
|
||||
sudo apt-get update && sudo apt-get install yarn
|
||||
|
||||
- &install-buck
|
||||
name: Install BUCK
|
||||
command: |
|
||||
if [[ ! -e ~/buck ]]; then
|
||||
git clone https://github.com/facebook/buck.git ~/buck --branch v2019.01.10.01 --depth=1
|
||||
fi
|
||||
cd ~/buck && ant
|
||||
buck --version
|
||||
# Install related tooling
|
||||
if [[ ! -e ~/okbuck ]]; then
|
||||
@@ -118,6 +150,30 @@ aliases:
|
||||
fi
|
||||
mkdir -p ~/react-native/tooling/junit
|
||||
cp -R ~/okbuck/tooling/junit/* ~/react-native/tooling/junit/.
|
||||
|
||||
- &create-ndk-directory
|
||||
name: Create Android NDK Directory
|
||||
command: |
|
||||
if [[ ! -e /opt/ndk ]]; then
|
||||
sudo mkdir /opt/ndk
|
||||
fi
|
||||
sudo chown ${USER:=$(/usr/bin/id -run)}:$USER /opt/ndk
|
||||
|
||||
# CircleCI does not support interpolating env variables in the environment
|
||||
# https://circleci.com/docs/2.0/env-vars/#interpolating-environment-variables-to-set-other-environment-variables
|
||||
- &configure-android-path
|
||||
name: Configure Environment Variables
|
||||
command: |
|
||||
echo 'export PATH=${ANDROID_NDK}:~/buck/bin:$PATH' >> $BASH_ENV
|
||||
source $BASH_ENV
|
||||
- &install-android-packages
|
||||
name: Install Android SDK Packages
|
||||
command: source scripts/android-setup.sh && getAndroidPackages
|
||||
|
||||
- &install-android-build-dependencies
|
||||
name: Install Android Build Dependencies
|
||||
command: ./scripts/circleci/apt-get-android-deps.sh
|
||||
|
||||
- &validate-android-sdk
|
||||
name: Validate Android SDK Install
|
||||
command: ./scripts/validate-android-sdk.sh
|
||||
@@ -187,7 +243,7 @@ aliases:
|
||||
|
||||
- &build-js-bundle
|
||||
name: Build JavaScript Bundle
|
||||
command: node cli.js bundle --max-workers 2 --platform android --dev true --entry-file ReactAndroid/src/androidTest/js/TestBundle.js --bundle-output ReactAndroid/src/androidTest/assets/AndroidTestBundle.js
|
||||
command: node cli.js bundle --max-workers 2 --platform android --dev true --entry-file ReactAndroid/src/androidTest/js/TestBundle.js --bundle-output ReactAndroid/src/androidTest/assets/AndroidTestBundle.js --reactNativePath .
|
||||
|
||||
- &compile-native-libs
|
||||
name: Compile Native Libs for Unit and Integration Tests
|
||||
@@ -208,7 +264,7 @@ aliases:
|
||||
|
||||
- &build-android-rntester-app
|
||||
name: Build Android RNTester App
|
||||
command: ./gradlew RNTester:android:app:assembleRelease
|
||||
command: ./gradlew RNTester:android:app:assembleRelease -Pjobs=$BUILD_THREADS
|
||||
|
||||
- &collect-android-test-results
|
||||
name: Collect Test Results
|
||||
@@ -283,13 +339,14 @@ js_defaults: &js_defaults
|
||||
android_defaults: &android_defaults
|
||||
<<: *defaults
|
||||
docker:
|
||||
- image: reactnativecommunity/react-native-android
|
||||
- image: circleci/android:api-28-node8-alpha
|
||||
resource_class: "large"
|
||||
environment:
|
||||
- TERM: "dumb"
|
||||
- ADB_INSTALL_TIMEOUT: 10
|
||||
- _JAVA_OPTIONS: "-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap"
|
||||
- GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.jvmargs="-XX:+HeapDumpOnOutOfMemoryError"'
|
||||
- ANDROID_NDK: '/opt/ndk/android-ndk-r17c'
|
||||
- BUILD_THREADS: 2
|
||||
|
||||
macos_defaults: &macos_defaults
|
||||
@@ -415,6 +472,15 @@ jobs:
|
||||
- attach_workspace:
|
||||
at: ~/react-native
|
||||
|
||||
# Configure Android SDK and related dependencies
|
||||
- run: *configure-android-path
|
||||
# Android build deps install from the network faster than cache
|
||||
- run: *install-android-build-dependencies
|
||||
|
||||
- restore-cache: *restore-cache-android-packages
|
||||
- run: *install-android-packages
|
||||
- save-cache: *save-cache-android-packages
|
||||
|
||||
# Validate Android SDK installation and packages
|
||||
- run: *validate-android-sdk
|
||||
|
||||
@@ -424,6 +490,12 @@ jobs:
|
||||
|
||||
# Keep configuring Android dependencies while AVD boots up
|
||||
|
||||
# Install Android NDK
|
||||
- run: *create-ndk-directory
|
||||
- restore-cache: *restore-cache-ndk
|
||||
- run: *install-ndk
|
||||
- save-cache: *save-cache-ndk
|
||||
|
||||
# Install Buck
|
||||
- restore-cache: *restore-cache-downloads-buck
|
||||
- run: *install-buck
|
||||
@@ -547,21 +619,26 @@ jobs:
|
||||
<<: *android_defaults
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
- restore-cache: *restore-yarn-cache
|
||||
- run: *yarn
|
||||
|
||||
# Configure Android SDK and related dependencies
|
||||
- run: *configure-android-path
|
||||
- run: *install-android-build-dependencies
|
||||
|
||||
- run: *install-android-packages
|
||||
|
||||
# Install Android NDK
|
||||
- run: *create-ndk-directory
|
||||
- restore-cache: *restore-cache-ndk
|
||||
- run: *install-ndk
|
||||
|
||||
# Fetch dependencies using Buck
|
||||
- restore-cache: *restore-cache-downloads-buck
|
||||
- run: *install-buck
|
||||
- run: *download-dependencies-buck
|
||||
|
||||
# Fetch dependencies using Gradle
|
||||
- restore-cache: *restore-cache-downloads-gradle
|
||||
- run: *download-dependencies-gradle
|
||||
|
||||
- restore-cache: *restore-yarn-cache
|
||||
- run: *yarn
|
||||
|
||||
- run:
|
||||
name: Authenticate with npm
|
||||
command: echo "//registry.npmjs.org/:_authToken=${CIRCLE_NPM_TOKEN}" > ~/.npmrc
|
||||
|
||||
@@ -31,7 +31,7 @@ watchman shutdown-server
|
||||
|
||||
# integration tests
|
||||
# build JS bundle for instrumentation tests
|
||||
node cli.js bundle --platform android --dev true --entry-file ReactAndroid/src/androidTest/js/TestBundle.js --bundle-output ReactAndroid/src/androidTest/assets/AndroidTestBundle.js
|
||||
node cli.js bundle --platform android --dev true --entry-file ReactAndroid/src/androidTest/js/TestBundle.js --bundle-output ReactAndroid/src/androidTest/assets/AndroidTestBundle.js --reactNativePath .
|
||||
|
||||
# build test APK
|
||||
# shellcheck disable=SC1091
|
||||
|
||||
@@ -803,6 +803,47 @@ describe('Animated tests', () => {
|
||||
expect(value1.__getValue()).toBe(1492);
|
||||
});
|
||||
|
||||
it('should get updates for derived animated nodes', () => {
|
||||
const value1 = new Animated.Value(40);
|
||||
const value2 = new Animated.Value(50);
|
||||
const value3 = new Animated.Value(0);
|
||||
const value4 = Animated.add(value3, Animated.multiply(value1, value2));
|
||||
const callback = jest.fn();
|
||||
const view = new Animated.__PropsOnlyForTests(
|
||||
{
|
||||
style: {
|
||||
transform: [
|
||||
{
|
||||
translateX: value4,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
callback,
|
||||
);
|
||||
const listener = jest.fn();
|
||||
const id = value4.addListener(listener);
|
||||
value3.setValue(137);
|
||||
expect(listener.mock.calls.length).toBe(1);
|
||||
expect(listener).toBeCalledWith({value: 2137});
|
||||
value1.setValue(0);
|
||||
expect(listener.mock.calls.length).toBe(2);
|
||||
expect(listener).toBeCalledWith({value: 137});
|
||||
expect(view.__getValue()).toEqual({
|
||||
style: {
|
||||
transform: [
|
||||
{
|
||||
translateX: 137,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
value4.removeListener(id);
|
||||
value1.setValue(40);
|
||||
expect(listener.mock.calls.length).toBe(2);
|
||||
expect(value4.__getValue()).toBe(2137);
|
||||
});
|
||||
|
||||
it('should removeAll', () => {
|
||||
const value1 = new Animated.Value(0);
|
||||
const listener = jest.fn();
|
||||
|
||||
@@ -19,11 +19,34 @@ describe('Animated Mock', () => {
|
||||
Object.keys(AnimatedImplementation),
|
||||
);
|
||||
});
|
||||
it('matches implementation params', () => {
|
||||
Object.keys(AnimatedImplementation).forEach(key =>
|
||||
expect(AnimatedImplementation[key].length).toEqual(
|
||||
AnimatedMock[key].length,
|
||||
),
|
||||
);
|
||||
it('matches implementation params', done => {
|
||||
Object.keys(AnimatedImplementation).forEach(key => {
|
||||
if (AnimatedImplementation[key].length !== AnimatedMock[key].length) {
|
||||
done(
|
||||
new Error(
|
||||
'key ' +
|
||||
key +
|
||||
' had different lengths: ' +
|
||||
JSON.stringify(
|
||||
{
|
||||
impl: {
|
||||
len: AnimatedImplementation[key].length,
|
||||
type: typeof AnimatedImplementation[key],
|
||||
val: AnimatedImplementation[key].toString(),
|
||||
},
|
||||
mock: {
|
||||
len: AnimatedMock[key].length,
|
||||
type: typeof AnimatedMock[key],
|
||||
val: AnimatedMock[key].toString(),
|
||||
},
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,4 +14,6 @@ const ScrollView = require('ScrollView');
|
||||
|
||||
const createAnimatedComponent = require('createAnimatedComponent');
|
||||
|
||||
module.exports = createAnimatedComponent(ScrollView);
|
||||
module.exports = createAnimatedComponent(ScrollView, {
|
||||
scrollEventThrottle: 0.0001,
|
||||
});
|
||||
|
||||
@@ -16,7 +16,7 @@ const DeprecatedViewStylePropTypes = require('DeprecatedViewStylePropTypes');
|
||||
|
||||
const invariant = require('invariant');
|
||||
|
||||
function createAnimatedComponent(Component: any): any {
|
||||
function createAnimatedComponent(Component: any, defaultProps: any): any {
|
||||
invariant(
|
||||
typeof Component !== 'function' ||
|
||||
(Component.prototype && Component.prototype.isReactComponent),
|
||||
@@ -149,6 +149,7 @@ function createAnimatedComponent(Component: any): any {
|
||||
const props = this._propsAnimated.__getValue();
|
||||
return (
|
||||
<Component
|
||||
{...defaultProps}
|
||||
{...props}
|
||||
ref={this._setComponentRef}
|
||||
// The native driver updates views directly through the UI thread so we
|
||||
|
||||
@@ -11,11 +11,18 @@
|
||||
|
||||
const NativeAnimatedHelper = require('../NativeAnimatedHelper');
|
||||
|
||||
const NativeAnimatedAPI = NativeAnimatedHelper.API;
|
||||
const invariant = require('invariant');
|
||||
|
||||
type ValueListenerCallback = (state: {value: number}) => mixed;
|
||||
|
||||
let _uniqueId = 1;
|
||||
|
||||
// Note(vjeux): this would be better as an interface but flow doesn't
|
||||
// support them yet
|
||||
class AnimatedNode {
|
||||
_listeners: {[key: string]: ValueListenerCallback};
|
||||
__nativeAnimatedValueListener: ?any;
|
||||
__attach(): void {}
|
||||
__detach(): void {
|
||||
if (this.__isNative && this.__nativeTag != null) {
|
||||
@@ -36,11 +43,103 @@ class AnimatedNode {
|
||||
/* Methods and props used by native Animated impl */
|
||||
__isNative: boolean;
|
||||
__nativeTag: ?number;
|
||||
|
||||
constructor() {
|
||||
this._listeners = {};
|
||||
}
|
||||
|
||||
__makeNative() {
|
||||
if (!this.__isNative) {
|
||||
throw new Error('This node cannot be made a "native" animated node');
|
||||
}
|
||||
|
||||
if (this.hasListeners()) {
|
||||
this._startListeningToNativeValueUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an asynchronous listener to the value so you can observe updates from
|
||||
* animations. This is useful because there is no way to
|
||||
* synchronously read the value because it might be driven natively.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvalue.html#addlistener
|
||||
*/
|
||||
addListener(callback: (value: any) => mixed): string {
|
||||
const id = String(_uniqueId++);
|
||||
this._listeners[id] = callback;
|
||||
if (this.__isNative) {
|
||||
this._startListeningToNativeValueUpdates();
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a listener. The `id` param shall match the identifier
|
||||
* previously returned by `addListener()`.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvalue.html#removelistener
|
||||
*/
|
||||
removeListener(id: string): void {
|
||||
delete this._listeners[id];
|
||||
if (this.__isNative && !this.hasListeners()) {
|
||||
this._stopListeningForNativeValueUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all registered listeners.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvalue.html#removealllisteners
|
||||
*/
|
||||
removeAllListeners(): void {
|
||||
this._listeners = {};
|
||||
if (this.__isNative) {
|
||||
this._stopListeningForNativeValueUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
hasListeners(): boolean {
|
||||
return !!Object.keys(this._listeners).length;
|
||||
}
|
||||
|
||||
_startListeningToNativeValueUpdates() {
|
||||
if (this.__nativeAnimatedValueListener) {
|
||||
return;
|
||||
}
|
||||
|
||||
NativeAnimatedAPI.startListeningToAnimatedNodeValue(this.__getNativeTag());
|
||||
this.__nativeAnimatedValueListener = NativeAnimatedHelper.nativeEventEmitter.addListener(
|
||||
'onAnimatedValueUpdate',
|
||||
data => {
|
||||
if (data.tag !== this.__getNativeTag()) {
|
||||
return;
|
||||
}
|
||||
this._onAnimatedValueUpdateReceived(data.value);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
_onAnimatedValueUpdateReceived(value: number) {
|
||||
this.__callListeners(value);
|
||||
}
|
||||
|
||||
__callListeners(value: number): void {
|
||||
for (const key in this._listeners) {
|
||||
this._listeners[key]({value});
|
||||
}
|
||||
}
|
||||
|
||||
_stopListeningForNativeValueUpdates() {
|
||||
if (!this.__nativeAnimatedValueListener) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.__nativeAnimatedValueListener.remove();
|
||||
this.__nativeAnimatedValueListener = null;
|
||||
NativeAnimatedAPI.stopListeningToAnimatedNodeValue(this.__getNativeTag());
|
||||
}
|
||||
|
||||
__getNativeTag(): ?number {
|
||||
NativeAnimatedHelper.assertNativeAnimatedModule();
|
||||
invariant(
|
||||
|
||||
@@ -20,10 +20,6 @@ import type AnimatedTracking from './AnimatedTracking';
|
||||
|
||||
const NativeAnimatedAPI = NativeAnimatedHelper.API;
|
||||
|
||||
type ValueListenerCallback = (state: {value: number}) => void;
|
||||
|
||||
let _uniqueId = 1;
|
||||
|
||||
/**
|
||||
* Animated works by building a directed acyclic graph of dependencies
|
||||
* transparently when you render your Animated components.
|
||||
@@ -77,15 +73,12 @@ class AnimatedValue extends AnimatedWithChildren {
|
||||
_offset: number;
|
||||
_animation: ?Animation;
|
||||
_tracking: ?AnimatedTracking;
|
||||
_listeners: {[key: string]: ValueListenerCallback};
|
||||
__nativeAnimatedValueListener: ?any;
|
||||
|
||||
constructor(value: number) {
|
||||
super();
|
||||
this._startingValue = this._value = value;
|
||||
this._offset = 0;
|
||||
this._animation = null;
|
||||
this._listeners = {};
|
||||
}
|
||||
|
||||
__detach() {
|
||||
@@ -97,14 +90,6 @@ class AnimatedValue extends AnimatedWithChildren {
|
||||
return this._value + this._offset;
|
||||
}
|
||||
|
||||
__makeNative() {
|
||||
super.__makeNative();
|
||||
|
||||
if (Object.keys(this._listeners).length) {
|
||||
this._startListeningToNativeValueUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Directly set the value. This will stop any animations running on the value
|
||||
* and update all the bound properties.
|
||||
@@ -167,74 +152,6 @@ class AnimatedValue extends AnimatedWithChildren {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an asynchronous listener to the value so you can observe updates from
|
||||
* animations. This is useful because there is no way to
|
||||
* synchronously read the value because it might be driven natively.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvalue.html#addlistener
|
||||
*/
|
||||
addListener(callback: ValueListenerCallback): string {
|
||||
const id = String(_uniqueId++);
|
||||
this._listeners[id] = callback;
|
||||
if (this.__isNative) {
|
||||
this._startListeningToNativeValueUpdates();
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a listener. The `id` param shall match the identifier
|
||||
* previously returned by `addListener()`.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvalue.html#removelistener
|
||||
*/
|
||||
removeListener(id: string): void {
|
||||
delete this._listeners[id];
|
||||
if (this.__isNative && Object.keys(this._listeners).length === 0) {
|
||||
this._stopListeningForNativeValueUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all registered listeners.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvalue.html#removealllisteners
|
||||
*/
|
||||
removeAllListeners(): void {
|
||||
this._listeners = {};
|
||||
if (this.__isNative) {
|
||||
this._stopListeningForNativeValueUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
_startListeningToNativeValueUpdates() {
|
||||
if (this.__nativeAnimatedValueListener) {
|
||||
return;
|
||||
}
|
||||
|
||||
NativeAnimatedAPI.startListeningToAnimatedNodeValue(this.__getNativeTag());
|
||||
this.__nativeAnimatedValueListener = NativeAnimatedHelper.nativeEventEmitter.addListener(
|
||||
'onAnimatedValueUpdate',
|
||||
data => {
|
||||
if (data.tag !== this.__getNativeTag()) {
|
||||
return;
|
||||
}
|
||||
this._updateValue(data.value, false /* flush */);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
_stopListeningForNativeValueUpdates() {
|
||||
if (!this.__nativeAnimatedValueListener) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.__nativeAnimatedValueListener.remove();
|
||||
this.__nativeAnimatedValueListener = null;
|
||||
NativeAnimatedAPI.stopListeningToAnimatedNodeValue(this.__getNativeTag());
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops any running animation or tracking. `callback` is invoked with the
|
||||
* final value after stopping the animation, which is useful for updating
|
||||
@@ -259,6 +176,10 @@ class AnimatedValue extends AnimatedWithChildren {
|
||||
this._value = this._startingValue;
|
||||
}
|
||||
|
||||
_onAnimatedValueUpdateReceived(value: number): void {
|
||||
this._updateValue(value, false /*flush*/);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolates the value before updating the property, e.g. mapping 0-1 to
|
||||
* 0-10.
|
||||
@@ -321,9 +242,7 @@ class AnimatedValue extends AnimatedWithChildren {
|
||||
if (flush) {
|
||||
_flush(this);
|
||||
}
|
||||
for (const key in this._listeners) {
|
||||
this._listeners[key]({value: this.__getValue()});
|
||||
}
|
||||
super.__callListeners(this.__getValue());
|
||||
}
|
||||
|
||||
__getNativeConfig(): Object {
|
||||
|
||||
@@ -14,7 +14,7 @@ const AnimatedWithChildren = require('./AnimatedWithChildren');
|
||||
|
||||
const invariant = require('invariant');
|
||||
|
||||
type ValueXYListenerCallback = (value: {x: number, y: number}) => void;
|
||||
type ValueXYListenerCallback = (value: {x: number, y: number}) => mixed;
|
||||
|
||||
let _uniqueId = 1;
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ class AnimatedWithChildren extends AnimatedNode {
|
||||
);
|
||||
}
|
||||
}
|
||||
super.__makeNative();
|
||||
}
|
||||
|
||||
__addChild(child: AnimatedNode): void {
|
||||
@@ -69,6 +70,17 @@ class AnimatedWithChildren extends AnimatedNode {
|
||||
__getChildren(): Array<AnimatedNode> {
|
||||
return this._children;
|
||||
}
|
||||
|
||||
__callListeners(value: number): void {
|
||||
super.__callListeners(value);
|
||||
if (!this.__isNative) {
|
||||
for (const child of this._children) {
|
||||
if (child.__getValue) {
|
||||
child.__callListeners(child.__getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AnimatedWithChildren;
|
||||
|
||||
@@ -52,9 +52,14 @@ RCT_EXPORT_MODULE(ImagePickerIOS);
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (BOOL)requiresMainQueueSetup
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"AVCaptureDeviceDidStartRunningNotification" object:nil];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"AVCaptureDeviceDidStartRunningNotification" object:nil];
|
||||
}
|
||||
|
||||
- (dispatch_queue_t)methodQueue
|
||||
|
||||
@@ -65,6 +65,7 @@ class KeyboardAvoidingView extends React.Component<Props, State> {
|
||||
_frame: ?ViewLayout = null;
|
||||
_subscriptions: Array<EmitterSubscription> = [];
|
||||
viewRef: {current: React.ElementRef<any> | null};
|
||||
_initialFrameHeight: number = 0;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
@@ -113,19 +114,11 @@ class KeyboardAvoidingView extends React.Component<Props, State> {
|
||||
|
||||
_onLayout = (event: ViewLayoutEvent) => {
|
||||
this._frame = event.nativeEvent.layout;
|
||||
};
|
||||
|
||||
UNSAFE_componentWillUpdate(nextProps: Props, nextState: State): void {
|
||||
if (
|
||||
nextState.bottom === this.state.bottom &&
|
||||
this.props.behavior === 'height' &&
|
||||
nextProps.behavior === 'height'
|
||||
) {
|
||||
// If the component rerenders without an internal state change, e.g.
|
||||
// triggered by parent component re-rendering, no need for bottom to change.
|
||||
nextState.bottom = 0;
|
||||
if (!this._initialFrameHeight) {
|
||||
// save the initial frame height, before the keyboard is visible
|
||||
this._initialFrameHeight = this._frame.height;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
componentDidMount(): void {
|
||||
if (Platform.OS === 'ios') {
|
||||
@@ -166,7 +159,7 @@ class KeyboardAvoidingView extends React.Component<Props, State> {
|
||||
// this.frame.height will never go back to its original value.
|
||||
// When height changes, we need to disable flex.
|
||||
heightStyle = {
|
||||
height: this._frame.height - bottomHeight,
|
||||
height: this._initialFrameHeight - bottomHeight,
|
||||
flex: 0,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -195,11 +195,16 @@ type IOSProps = $ReadOnly<{|
|
||||
* (as a time interval in ms). A lower number yields better accuracy for code
|
||||
* that is tracking the scroll position, but can lead to scroll performance
|
||||
* problems due to the volume of information being send over the bridge.
|
||||
* You will not notice a difference between values set between 1-16 as the
|
||||
* JS run loop is synced to the screen refresh rate. If you do not need precise
|
||||
* scroll position tracking, set this value higher to limit the information
|
||||
* being sent across the bridge. The default value is zero, which results in
|
||||
* the scroll event being sent only once each time the view is scrolled.
|
||||
*
|
||||
* Values between 0 and 17ms indicate 60fps updates are needed and throttling
|
||||
* will be disabled.
|
||||
*
|
||||
* If you do not need precise scroll position tracking, set this value higher
|
||||
* to limit the information being sent across the bridge.
|
||||
*
|
||||
* The default value is zero, which results in the scroll event being sent only
|
||||
* once each time the view is scrolled.
|
||||
*
|
||||
* @platform ios
|
||||
*/
|
||||
scrollEventThrottle?: ?number,
|
||||
@@ -210,6 +215,12 @@ type IOSProps = $ReadOnly<{|
|
||||
* @platform ios
|
||||
*/
|
||||
scrollIndicatorInsets?: ?EdgeInsetsProp,
|
||||
/**
|
||||
* When true, the scroll view can be programmatically scrolled beyond its
|
||||
* content size. The default value is false.
|
||||
* @platform ios
|
||||
*/
|
||||
scrollToOverflowEnabled?: ?boolean,
|
||||
/**
|
||||
* When true, the scroll view scrolls to top when the status bar is tapped.
|
||||
* The default value is true.
|
||||
@@ -651,6 +662,18 @@ class ScrollView extends React.Component<Props, State> {
|
||||
this._headerLayoutYs = new Map();
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
const currentContentInsetTop = this.props.contentInset
|
||||
? this.props.contentInset.top
|
||||
: 0;
|
||||
const nextContentInsetTop = nextProps.contentInset
|
||||
? nextProps.contentInset.top
|
||||
: 0;
|
||||
if (currentContentInsetTop !== nextContentInsetTop) {
|
||||
this._scrollAnimatedValue.setOffset(nextContentInsetTop || 0);
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this._updateAnimatedNodeAttachment();
|
||||
}
|
||||
|
||||
@@ -137,6 +137,8 @@ class Switch extends React.Component<Props> {
|
||||
on: value === true,
|
||||
style,
|
||||
thumbTintColor: _thumbColor,
|
||||
trackColorForFalse: _trackColorForFalse,
|
||||
trackColorForTrue: _trackColorForTrue,
|
||||
trackTintColor:
|
||||
value === true ? _trackColorForTrue : _trackColorForFalse,
|
||||
}: NativeAndroidProps)
|
||||
|
||||
@@ -223,6 +223,21 @@ type IOSProps = $ReadOnly<{|
|
||||
|}>;
|
||||
|
||||
type AndroidProps = $ReadOnly<{|
|
||||
autoCompleteType?: ?(
|
||||
| 'cc-csc'
|
||||
| 'cc-exp'
|
||||
| 'cc-exp-month'
|
||||
| 'cc-exp-year'
|
||||
| 'cc-number'
|
||||
| 'email'
|
||||
| 'name'
|
||||
| 'password'
|
||||
| 'postal-code'
|
||||
| 'street-address'
|
||||
| 'tel'
|
||||
| 'username'
|
||||
| 'off'
|
||||
),
|
||||
returnKeyLabel?: ?string,
|
||||
numberOfLines?: ?number,
|
||||
disableFullscreenUI?: ?boolean,
|
||||
@@ -230,6 +245,13 @@ type AndroidProps = $ReadOnly<{|
|
||||
underlineColorAndroid?: ?ColorValue,
|
||||
inlineImageLeft?: ?string,
|
||||
inlineImagePadding?: ?number,
|
||||
importantForAutofill?: ?(
|
||||
| 'auto'
|
||||
| 'no'
|
||||
| 'noExcludeDescendants'
|
||||
| 'yes'
|
||||
| 'yesExcludeDescendants'
|
||||
),
|
||||
|}>;
|
||||
|
||||
type Props = $ReadOnly<{|
|
||||
@@ -413,6 +435,45 @@ const TextInput = createReactClass({
|
||||
'words',
|
||||
'characters',
|
||||
]),
|
||||
/**
|
||||
* Determines which content to suggest on auto complete, e.g.`username`.
|
||||
* To disable auto complete, use `off`.
|
||||
*
|
||||
* *Android Only*
|
||||
*
|
||||
* The following values work on Android only:
|
||||
*
|
||||
* - `username`
|
||||
* - `password`
|
||||
* - `email`
|
||||
* - `name`
|
||||
* - `tel`
|
||||
* - `street-address`
|
||||
* - `postal-code`
|
||||
* - `cc-number`
|
||||
* - `cc-csc`
|
||||
* - `cc-exp`
|
||||
* - `cc-exp-month`
|
||||
* - `cc-exp-year`
|
||||
* - `off`
|
||||
*
|
||||
* @platform android
|
||||
*/
|
||||
autoCompleteType: PropTypes.oneOf([
|
||||
'cc-csc',
|
||||
'cc-exp',
|
||||
'cc-exp-month',
|
||||
'cc-exp-year',
|
||||
'cc-number',
|
||||
'email',
|
||||
'name',
|
||||
'password',
|
||||
'postal-code',
|
||||
'street-address',
|
||||
'tel',
|
||||
'username',
|
||||
'off',
|
||||
]),
|
||||
/**
|
||||
* If `false`, disables auto-correct. The default value is `true`.
|
||||
*/
|
||||
|
||||
@@ -484,6 +484,7 @@ const TouchableMixin = {
|
||||
* Place as callback for a DOM element's `onResponderRelease` event.
|
||||
*/
|
||||
touchableHandleResponderRelease: function(e: PressEvent) {
|
||||
this.pressInLocation = null;
|
||||
this._receiveSignal(Signals.RESPONDER_RELEASE, e);
|
||||
},
|
||||
|
||||
@@ -491,6 +492,7 @@ const TouchableMixin = {
|
||||
* Place as callback for a DOM element's `onResponderTerminate` event.
|
||||
*/
|
||||
touchableHandleResponderTerminate: function(e: PressEvent) {
|
||||
this.pressInLocation = null;
|
||||
this._receiveSignal(Signals.RESPONDER_TERMINATED, e);
|
||||
},
|
||||
|
||||
@@ -558,9 +560,13 @@ const TouchableMixin = {
|
||||
dimensionsOnActivate.height +
|
||||
pressExpandBottom;
|
||||
if (isTouchWithinActive) {
|
||||
const prevState = this.state.touchable.touchState;
|
||||
this._receiveSignal(Signals.ENTER_PRESS_RECT, e);
|
||||
const curState = this.state.touchable.touchState;
|
||||
if (curState === States.RESPONDER_INACTIVE_PRESS_IN) {
|
||||
if (
|
||||
curState === States.RESPONDER_INACTIVE_PRESS_IN &&
|
||||
prevState !== States.RESPONDER_INACTIVE_PRESS_IN
|
||||
) {
|
||||
// fix for t7967420
|
||||
this._cancelLongPressDelayTimeout();
|
||||
}
|
||||
|
||||
@@ -46,6 +46,22 @@ type FocusEvent = TargetEvent;
|
||||
|
||||
const PRESS_RETENTION_OFFSET = {top: 20, left: 20, right: 20, bottom: 30};
|
||||
|
||||
const OVERRIDE_PROPS = [
|
||||
'accessibilityComponentType',
|
||||
'accessibilityLabel',
|
||||
'accessibilityHint',
|
||||
'accessibilityIgnoresInvertColors',
|
||||
'accessibilityRole',
|
||||
'accessibilityStates',
|
||||
'accessibilityTraits',
|
||||
'hitSlop',
|
||||
'nativeID',
|
||||
'onBlur',
|
||||
'onFocus',
|
||||
'onLayout',
|
||||
'testID',
|
||||
];
|
||||
|
||||
export type Props = $ReadOnly<{|
|
||||
accessible?: ?boolean,
|
||||
accessibilityComponentType?: ?AccessibilityComponentType,
|
||||
@@ -92,6 +108,7 @@ const TouchableWithoutFeedback = ((createReactClass({
|
||||
accessibilityComponentType: PropTypes.oneOf(
|
||||
DeprecatedAccessibilityComponentTypes,
|
||||
),
|
||||
accessibilityIgnoresInvertColors: PropTypes.bool,
|
||||
accessibilityRole: PropTypes.oneOf(DeprecatedAccessibilityRoles),
|
||||
accessibilityStates: PropTypes.arrayOf(
|
||||
PropTypes.oneOf(DeprecatedAccessibilityStates),
|
||||
@@ -239,18 +256,17 @@ const TouchableWithoutFeedback = ((createReactClass({
|
||||
Touchable.renderDebugView({color: 'red', hitSlop: this.props.hitSlop}),
|
||||
);
|
||||
}
|
||||
|
||||
const overrides = {};
|
||||
for (const prop of OVERRIDE_PROPS) {
|
||||
if (this.props[prop] !== undefined) {
|
||||
overrides[prop] = this.props[prop];
|
||||
}
|
||||
}
|
||||
|
||||
return (React: any).cloneElement(child, {
|
||||
...overrides,
|
||||
accessible: this.props.accessible !== false,
|
||||
accessibilityLabel: this.props.accessibilityLabel,
|
||||
accessibilityHint: this.props.accessibilityHint,
|
||||
accessibilityComponentType: this.props.accessibilityComponentType,
|
||||
accessibilityRole: this.props.accessibilityRole,
|
||||
accessibilityStates: this.props.accessibilityStates,
|
||||
accessibilityTraits: this.props.accessibilityTraits,
|
||||
nativeID: this.props.nativeID,
|
||||
testID: this.props.testID,
|
||||
onLayout: this.props.onLayout,
|
||||
hitSlop: this.props.hitSlop,
|
||||
onStartShouldSetResponder: this.touchableHandleStartShouldSetResponder,
|
||||
onResponderTerminationRequest: this
|
||||
.touchableHandleResponderTerminationRequest,
|
||||
|
||||
@@ -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: 59,
|
||||
patch: 8,
|
||||
prerelease: null,
|
||||
};
|
||||
|
||||
@@ -14,8 +14,6 @@ const {freeze, seal, preventExtensions} = Object;
|
||||
|
||||
function setup() {
|
||||
jest.setMock('../../vendor/core/_shouldPolyfillES6Collection', () => true);
|
||||
jest.unmock('_wrapObjectFreezeAndFriends');
|
||||
require('_wrapObjectFreezeAndFriends');
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
|
||||
@@ -18,10 +18,8 @@ const {polyfillGlobal} = require('PolyfillFunctions');
|
||||
*/
|
||||
const _shouldPolyfillCollection = require('_shouldPolyfillES6Collection');
|
||||
if (_shouldPolyfillCollection('Map')) {
|
||||
require('_wrapObjectFreezeAndFriends');
|
||||
polyfillGlobal('Map', () => require('Map'));
|
||||
}
|
||||
if (_shouldPolyfillCollection('Set')) {
|
||||
require('_wrapObjectFreezeAndFriends');
|
||||
polyfillGlobal('Set', () => require('Set'));
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ const BorderBox = require('BorderBox');
|
||||
const React = require('React');
|
||||
const StyleSheet = require('StyleSheet');
|
||||
const View = require('View');
|
||||
const Dimensions = require('Dimensions');
|
||||
|
||||
const flattenStyle = require('flattenStyle');
|
||||
const resolveBoxStyle = require('resolveBoxStyle');
|
||||
@@ -21,8 +22,8 @@ const resolveBoxStyle = require('resolveBoxStyle');
|
||||
class ElementBox extends React.Component<$FlowFixMeProps> {
|
||||
render() {
|
||||
const style = flattenStyle(this.props.style) || {};
|
||||
const margin = resolveBoxStyle('margin', style);
|
||||
const padding = resolveBoxStyle('padding', style);
|
||||
let margin = resolveBoxStyle('margin', style);
|
||||
let padding = resolveBoxStyle('padding', style);
|
||||
|
||||
const frameStyle = {...this.props.frame};
|
||||
const contentStyle = {
|
||||
@@ -31,6 +32,8 @@ class ElementBox extends React.Component<$FlowFixMeProps> {
|
||||
};
|
||||
|
||||
if (margin != null) {
|
||||
margin = resolveRelativeSizes(margin);
|
||||
|
||||
frameStyle.top -= margin.top;
|
||||
frameStyle.left -= margin.left;
|
||||
frameStyle.height += margin.top + margin.bottom;
|
||||
@@ -51,6 +54,8 @@ class ElementBox extends React.Component<$FlowFixMeProps> {
|
||||
}
|
||||
|
||||
if (padding != null) {
|
||||
padding = resolveRelativeSizes(padding);
|
||||
|
||||
contentStyle.width -= padding.left + padding.right;
|
||||
contentStyle.height -= padding.top + padding.bottom;
|
||||
}
|
||||
@@ -82,4 +87,51 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
});
|
||||
|
||||
type Style = {
|
||||
top: number,
|
||||
right: number,
|
||||
bottom: number,
|
||||
left: number,
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolves relative sizes (percentages and auto) in a style object.
|
||||
*
|
||||
* @param style the style to resolve
|
||||
* @return a modified copy
|
||||
*/
|
||||
function resolveRelativeSizes(style: $ReadOnly<Style>): Style {
|
||||
let resolvedStyle = Object.assign({}, style);
|
||||
resolveSizeInPlace(resolvedStyle, 'top', 'height');
|
||||
resolveSizeInPlace(resolvedStyle, 'right', 'width');
|
||||
resolveSizeInPlace(resolvedStyle, 'bottom', 'height');
|
||||
resolveSizeInPlace(resolvedStyle, 'left', 'width');
|
||||
return resolvedStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the given size of a style object in place.
|
||||
*
|
||||
* @param style the style object to modify
|
||||
* @param direction the direction to resolve (e.g. 'top')
|
||||
* @param dimension the window dimension that this direction belongs to (e.g. 'height')
|
||||
*/
|
||||
function resolveSizeInPlace(
|
||||
style: Style,
|
||||
direction: string,
|
||||
dimension: string,
|
||||
) {
|
||||
if (style[direction] !== null && typeof style[direction] === 'string') {
|
||||
if (style[direction].indexOf('%') !== -1) {
|
||||
style[direction] =
|
||||
(parseFloat(style[direction]) / 100.0) *
|
||||
Dimensions.get('window')[dimension];
|
||||
}
|
||||
if (style[direction] === 'auto') {
|
||||
// Ignore auto sizing in frame drawing due to complexity of correctly rendering this
|
||||
style[direction] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ElementBox;
|
||||
|
||||
@@ -88,6 +88,16 @@ class NetworkOverlay extends React.Component<Props, State> {
|
||||
_requestsListView: ?React.ElementRef<typeof FlatList>;
|
||||
_detailScrollView: ?React.ElementRef<typeof ScrollView>;
|
||||
|
||||
// Metrics are used to decide when if the request list should be sticky, and
|
||||
// scroll to the bottom as new network requests come in, or if the user has
|
||||
// intentionally scrolled away from the bottom - to instead flash the scroll bar
|
||||
// and keep the current position
|
||||
_requestsListViewScrollMetrics = {
|
||||
offset: 0,
|
||||
visibleLength: 0,
|
||||
contentLength: 0,
|
||||
};
|
||||
|
||||
// Map of `socketId` -> `index in `this.state.requests`.
|
||||
_socketIdMap = {};
|
||||
// Map of `xhr._index` -> `index in `this.state.requests`.
|
||||
@@ -121,7 +131,7 @@ class NetworkOverlay extends React.Component<Props, State> {
|
||||
{
|
||||
requests: this.state.requests.concat(_xhr),
|
||||
},
|
||||
this._scrollRequestsToBottom,
|
||||
this._indicateAdditionalRequests,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -214,7 +224,7 @@ class NetworkOverlay extends React.Component<Props, State> {
|
||||
{
|
||||
requests: this.state.requests.concat(_webSocket),
|
||||
},
|
||||
this._scrollRequestsToBottom,
|
||||
this._indicateAdditionalRequests,
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -383,11 +393,35 @@ class NetworkOverlay extends React.Component<Props, State> {
|
||||
);
|
||||
}
|
||||
|
||||
_scrollRequestsToBottom(): void {
|
||||
_indicateAdditionalRequests = (): void => {
|
||||
if (this._requestsListView) {
|
||||
this._requestsListView.scrollToEnd();
|
||||
const distanceFromEndThreshold = LISTVIEW_CELL_HEIGHT * 2;
|
||||
const {
|
||||
offset,
|
||||
visibleLength,
|
||||
contentLength,
|
||||
} = this._requestsListViewScrollMetrics;
|
||||
const distanceFromEnd = contentLength - visibleLength - offset;
|
||||
const isCloseToEnd = distanceFromEnd <= distanceFromEndThreshold;
|
||||
if (isCloseToEnd) {
|
||||
this._requestsListView.scrollToEnd();
|
||||
} else {
|
||||
this._requestsListView.flashScrollIndicators();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_captureRequestsListView = (listRef: ?FlatList<NetworkRequestInfo>): void => {
|
||||
this._requestsListView = listRef;
|
||||
};
|
||||
|
||||
_requestsListViewOnScroll = (e: Object): void => {
|
||||
this._requestsListViewScrollMetrics.offset = e.nativeEvent.contentOffset.y;
|
||||
this._requestsListViewScrollMetrics.visibleLength =
|
||||
e.nativeEvent.layoutMeasurement.height;
|
||||
this._requestsListViewScrollMetrics.contentLength =
|
||||
e.nativeEvent.contentSize.height;
|
||||
};
|
||||
|
||||
/**
|
||||
* Popup a scrollView to dynamically show detailed information of
|
||||
@@ -446,7 +480,8 @@ class NetworkOverlay extends React.Component<Props, State> {
|
||||
</View>
|
||||
|
||||
<FlatList
|
||||
ref={listRef => (this._requestsListView = listRef)}
|
||||
ref={this._captureRequestsListView}
|
||||
onScroll={this._requestsListViewOnScroll}
|
||||
style={styles.listView}
|
||||
data={requests}
|
||||
renderItem={this._renderItem}
|
||||
|
||||
@@ -22,6 +22,11 @@
|
||||
|
||||
+ (BOOL)application:(nonnull UIApplication *)application
|
||||
continueUserActivity:(nonnull NSUserActivity *)userActivity
|
||||
restorationHandler:(nonnull void (^)(NSArray *__nullable))restorationHandler;
|
||||
restorationHandler:
|
||||
#if __has_include(<UIKitCore/UIUserActivity.h>) && defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 12000) /* __IPHONE_12_0 */
|
||||
(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> *_Nullable))restorationHandler;
|
||||
#else
|
||||
(nonnull void (^)(NSArray *_Nullable))restorationHandler;
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
@@ -67,8 +67,12 @@ RCT_EXPORT_MODULE()
|
||||
|
||||
+ (BOOL)application:(UIApplication *)application
|
||||
continueUserActivity:(NSUserActivity *)userActivity
|
||||
restorationHandler:(void (^)(NSArray * __nullable))restorationHandler
|
||||
{
|
||||
restorationHandler:
|
||||
#if __has_include(<UIKitCore/UIUserActivity.h>) && defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 12000) /* __IPHONE_12_0 */
|
||||
(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> *_Nullable))restorationHandler {
|
||||
#else
|
||||
(nonnull void (^)(NSArray *_Nullable))restorationHandler {
|
||||
#endif
|
||||
if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) {
|
||||
NSDictionary *payload = @{@"url": userActivity.webpageURL.absoluteString};
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kOpenURLNotification
|
||||
|
||||
@@ -893,7 +893,10 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
||||
element.props.onLayout(event);
|
||||
}
|
||||
},
|
||||
style: [element.props.style, inversionStyle],
|
||||
style: StyleSheet.compose(
|
||||
inversionStyle,
|
||||
element.props.style,
|
||||
),
|
||||
}),
|
||||
);
|
||||
}
|
||||
@@ -937,7 +940,7 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
||||
: this.props.inverted,
|
||||
stickyHeaderIndices,
|
||||
};
|
||||
if (inversionStyle && itemCount !== 0) {
|
||||
if (inversionStyle) {
|
||||
/* $FlowFixMe(>=0.70.0 site=react_native_fb) This comment suppresses an
|
||||
* error found when Flow v0.70 was deployed. To see the error delete
|
||||
* this comment and run Flow. */
|
||||
@@ -979,7 +982,19 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
||||
tuple.viewabilityHelper.resetViewableIndices();
|
||||
});
|
||||
}
|
||||
// The `this._hiPriInProgress` is guaranteeing a hiPri cell update will only happen
|
||||
// once per fiber update. The `_scheduleCellsToRenderUpdate` will set it to true
|
||||
// if a hiPri update needs to perform. If `componentDidUpdate` is triggered with
|
||||
// `this._hiPriInProgress=true`, means it's triggered by the hiPri update. The
|
||||
// `_scheduleCellsToRenderUpdate` will check this condition and not perform
|
||||
// another hiPri update.
|
||||
const hiPriInProgress = this._hiPriInProgress;
|
||||
this._scheduleCellsToRenderUpdate();
|
||||
// Make sure setting `this._hiPriInProgress` back to false after `componentDidUpdate`
|
||||
// is triggered with `this._hiPriInProgress = true`
|
||||
if (hiPriInProgress) {
|
||||
this._hiPriInProgress = false;
|
||||
}
|
||||
}
|
||||
|
||||
_averageCellLength = 0;
|
||||
@@ -990,13 +1005,14 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
||||
_frames = {};
|
||||
_footerLength = 0;
|
||||
_hasDataChangedSinceEndReached = true;
|
||||
_hasDoneInitialScroll = false;
|
||||
_hasInteracted = false;
|
||||
_hasMore = false;
|
||||
_hasWarned = {};
|
||||
_highestMeasuredFrameIndex = 0;
|
||||
_headerLength = 0;
|
||||
_hiPriInProgress: boolean = false; // flag to prevent infinite hiPri cell limit update
|
||||
_highestMeasuredFrameIndex = 0;
|
||||
_indicesToKeys: Map<number, string> = new Map();
|
||||
_hasDoneInitialScroll = false;
|
||||
_nestedChildLists: Map<
|
||||
string,
|
||||
{ref: ?VirtualizedList, state: ?ChildListState},
|
||||
@@ -1106,6 +1122,7 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
this._computeBlankness();
|
||||
this._updateViewableItems(this.props.data);
|
||||
}
|
||||
|
||||
_onCellUnmount = (cellKey: string) => {
|
||||
@@ -1181,7 +1198,8 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
||||
|
||||
_renderDebugOverlay() {
|
||||
const normalize =
|
||||
this._scrollMetrics.visibleLength / this._scrollMetrics.contentLength;
|
||||
this._scrollMetrics.visibleLength /
|
||||
(this._scrollMetrics.contentLength || 1);
|
||||
const framesInLayout = [];
|
||||
const itemCount = this.props.getItemCount(this.props.data);
|
||||
for (let ii = 0; ii < itemCount; ii++) {
|
||||
@@ -1418,7 +1436,10 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
||||
// Otherwise, it would just render as many cells as it can (of zero dimension),
|
||||
// each time through attempting to render more (limited by maxToRenderPerBatch),
|
||||
// starving the renderer from actually laying out the objects and computing _averageCellLength.
|
||||
if (hiPri && this._averageCellLength) {
|
||||
// If this is triggered in an `componentDidUpdate` followed by a hiPri cellToRenderUpdate
|
||||
// We shouldn't do another hipri cellToRenderUpdate
|
||||
if (hiPri && this._averageCellLength && !this._hiPriInProgress) {
|
||||
this._hiPriInProgress = true;
|
||||
// Don't worry about interactions when scrolling quickly; focus on filling content as fast
|
||||
// as possible.
|
||||
this._updateCellsToRenderBatcher.dispose({abort: true});
|
||||
|
||||
@@ -146,7 +146,7 @@ class VirtualizedSectionList<SectionT: SectionBase> extends React.PureComponent<
|
||||
sectionIndex: number,
|
||||
viewPosition?: number,
|
||||
}) {
|
||||
let index = Platform.OS === 'ios' ? params.itemIndex : params.itemIndex - 1;
|
||||
let index = Platform.OS === 'ios' ? params.itemIndex : params.itemIndex + 1;
|
||||
for (let ii = 0; ii < params.sectionIndex; ii++) {
|
||||
index += this.props.sections[ii].data.length + 2;
|
||||
}
|
||||
@@ -221,9 +221,9 @@ class VirtualizedSectionList<SectionT: SectionBase> extends React.PureComponent<
|
||||
trailingSection?: ?SectionT,
|
||||
} {
|
||||
let itemIndex = index;
|
||||
const defaultKeyExtractor = this.props.keyExtractor;
|
||||
for (let ii = 0; ii < this.props.sections.length; ii++) {
|
||||
const section = this.props.sections[ii];
|
||||
const {sections} = this.props;
|
||||
for (let ii = 0; ii < sections.length; ii++) {
|
||||
const section = sections[ii];
|
||||
const key = section.key || String(ii);
|
||||
itemIndex -= 1; // The section adds an item for the header
|
||||
if (itemIndex >= section.data.length + 1) {
|
||||
@@ -234,7 +234,7 @@ class VirtualizedSectionList<SectionT: SectionBase> extends React.PureComponent<
|
||||
key: key + ':header',
|
||||
index: null,
|
||||
header: true,
|
||||
trailingSection: this.props.sections[ii + 1],
|
||||
trailingSection: sections[ii + 1],
|
||||
};
|
||||
} else if (itemIndex === section.data.length) {
|
||||
return {
|
||||
@@ -242,18 +242,21 @@ class VirtualizedSectionList<SectionT: SectionBase> extends React.PureComponent<
|
||||
key: key + ':footer',
|
||||
index: null,
|
||||
header: false,
|
||||
trailingSection: this.props.sections[ii + 1],
|
||||
trailingSection: sections[ii + 1],
|
||||
};
|
||||
} else {
|
||||
const keyExtractor = section.keyExtractor || defaultKeyExtractor;
|
||||
const keyExtractor = section.keyExtractor || this.props.keyExtractor;
|
||||
return {
|
||||
section,
|
||||
key: key + ':' + keyExtractor(section.data[itemIndex], itemIndex),
|
||||
index: itemIndex,
|
||||
leadingItem: section.data[itemIndex - 1],
|
||||
leadingSection: this.props.sections[ii - 1],
|
||||
trailingItem: section.data[itemIndex + 1],
|
||||
trailingSection: this.props.sections[ii + 1],
|
||||
leadingSection: sections[ii - 1],
|
||||
trailingItem:
|
||||
section.data.length > itemIndex + 1
|
||||
? section.data[itemIndex + 1]
|
||||
: undefined,
|
||||
trailingSection: sections[ii + 1],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
f24a0da6e0f59484e5aafd0825bb1a6ed27d7182
|
||||
8e25ed20bd27d126f670d04680db85209f779056
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3188,6 +3188,8 @@ function updateReducer(reducer) {
|
||||
is(newState, hook.memoizedState) || (didReceiveUpdate = !0);
|
||||
hook.memoizedState = newState;
|
||||
hook.baseUpdate === queue.last && (hook.baseState = newState);
|
||||
queue.eagerReducer = reducer;
|
||||
queue.eagerState = newState;
|
||||
return [newState, _dispatch];
|
||||
}
|
||||
}
|
||||
@@ -3508,6 +3510,8 @@ function tryHydrate(fiber, nextInstance) {
|
||||
(nextInstance = shim$1(nextInstance, fiber.pendingProps)),
|
||||
null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1
|
||||
);
|
||||
case 13:
|
||||
return !1;
|
||||
default:
|
||||
return !1;
|
||||
}
|
||||
@@ -4571,19 +4575,19 @@ function beginWork(current$$1, workInProgress, renderExpirationTime) {
|
||||
null !== dependency &&
|
||||
dependency.expirationTime < renderExpirationTime &&
|
||||
(dependency.expirationTime = renderExpirationTime);
|
||||
dependency = renderExpirationTime;
|
||||
for (var node = oldValue.return; null !== node; ) {
|
||||
dependency = node.alternate;
|
||||
if (node.childExpirationTime < renderExpirationTime)
|
||||
(node.childExpirationTime = renderExpirationTime),
|
||||
null !== dependency &&
|
||||
dependency.childExpirationTime <
|
||||
renderExpirationTime &&
|
||||
(dependency.childExpirationTime = renderExpirationTime);
|
||||
var alternate = node.alternate;
|
||||
if (node.childExpirationTime < dependency)
|
||||
(node.childExpirationTime = dependency),
|
||||
null !== alternate &&
|
||||
alternate.childExpirationTime < dependency &&
|
||||
(alternate.childExpirationTime = dependency);
|
||||
else if (
|
||||
null !== dependency &&
|
||||
dependency.childExpirationTime < renderExpirationTime
|
||||
null !== alternate &&
|
||||
alternate.childExpirationTime < dependency
|
||||
)
|
||||
dependency.childExpirationTime = renderExpirationTime;
|
||||
alternate.childExpirationTime = dependency;
|
||||
else break;
|
||||
node = node.return;
|
||||
}
|
||||
@@ -4713,12 +4717,11 @@ function beginWork(current$$1, workInProgress, renderExpirationTime) {
|
||||
renderExpirationTime
|
||||
)
|
||||
);
|
||||
default:
|
||||
invariant(
|
||||
!1,
|
||||
"Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue."
|
||||
);
|
||||
}
|
||||
invariant(
|
||||
!1,
|
||||
"Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue."
|
||||
);
|
||||
}
|
||||
var valueCursor = { current: null },
|
||||
currentlyRenderingFiber = null,
|
||||
@@ -5361,6 +5364,8 @@ function unwindWork(workInProgress) {
|
||||
workInProgress)
|
||||
: null
|
||||
);
|
||||
case 18:
|
||||
return null;
|
||||
case 4:
|
||||
return popHostContainer(workInProgress), null;
|
||||
case 10:
|
||||
@@ -5686,6 +5691,7 @@ function commitPassiveEffects(root, firstEffect) {
|
||||
isRendering = previousIsRendering;
|
||||
previousIsRendering = root.expirationTime;
|
||||
0 !== previousIsRendering && requestWork(root, previousIsRendering);
|
||||
isBatchingUpdates || isRendering || performWork(1073741823, !1);
|
||||
}
|
||||
function flushPassiveEffects() {
|
||||
if (null !== passiveEffectCallbackHandle) {
|
||||
@@ -5960,6 +5966,8 @@ function completeUnitOfWork(workInProgress) {
|
||||
case 17:
|
||||
isContextProvider(current$$1.type) && popContext(current$$1);
|
||||
break;
|
||||
case 18:
|
||||
break;
|
||||
default:
|
||||
invariant(
|
||||
!1,
|
||||
@@ -6050,7 +6058,7 @@ function renderRoot(root$jscomp$0, isYieldy) {
|
||||
do {
|
||||
try {
|
||||
if (isYieldy)
|
||||
for (; null !== nextUnitOfWork && !shouldYieldToRenderer(); )
|
||||
for (; null !== nextUnitOfWork && !(frameDeadline <= now$1()); )
|
||||
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
|
||||
else
|
||||
for (; null !== nextUnitOfWork; )
|
||||
@@ -6136,27 +6144,24 @@ function renderRoot(root$jscomp$0, isYieldy) {
|
||||
sourceFiber$jscomp$0.expirationTime = 1073741823;
|
||||
break a;
|
||||
}
|
||||
sourceFiber$jscomp$0 = root.pingCache;
|
||||
null === sourceFiber$jscomp$0
|
||||
? ((sourceFiber$jscomp$0 = root.pingCache = new PossiblyWeakMap()),
|
||||
(returnFiber$jscomp$0 = new Set()),
|
||||
sourceFiber$jscomp$0.set(thenable, returnFiber$jscomp$0))
|
||||
: ((returnFiber$jscomp$0 = sourceFiber$jscomp$0.get(
|
||||
thenable
|
||||
)),
|
||||
void 0 === returnFiber$jscomp$0 &&
|
||||
((returnFiber$jscomp$0 = new Set()),
|
||||
sourceFiber$jscomp$0.set(
|
||||
thenable,
|
||||
returnFiber$jscomp$0
|
||||
)));
|
||||
returnFiber$jscomp$0.has(returnFiber) ||
|
||||
(returnFiber$jscomp$0.add(returnFiber),
|
||||
sourceFiber$jscomp$0 = root;
|
||||
returnFiber$jscomp$0 = returnFiber;
|
||||
var pingCache = sourceFiber$jscomp$0.pingCache;
|
||||
null === pingCache
|
||||
? ((pingCache = sourceFiber$jscomp$0.pingCache = new PossiblyWeakMap()),
|
||||
(current$$1 = new Set()),
|
||||
pingCache.set(thenable, current$$1))
|
||||
: ((current$$1 = pingCache.get(thenable)),
|
||||
void 0 === current$$1 &&
|
||||
((current$$1 = new Set()),
|
||||
pingCache.set(thenable, current$$1)));
|
||||
current$$1.has(returnFiber$jscomp$0) ||
|
||||
(current$$1.add(returnFiber$jscomp$0),
|
||||
(sourceFiber$jscomp$0 = pingSuspendedRoot.bind(
|
||||
null,
|
||||
root,
|
||||
sourceFiber$jscomp$0,
|
||||
thenable,
|
||||
returnFiber
|
||||
returnFiber$jscomp$0
|
||||
)),
|
||||
thenable.then(sourceFiber$jscomp$0, sourceFiber$jscomp$0));
|
||||
-1 === earliestTimeoutMs
|
||||
@@ -6200,24 +6205,25 @@ function renderRoot(root$jscomp$0, isYieldy) {
|
||||
break a;
|
||||
case 1:
|
||||
if (
|
||||
((thenable = value),
|
||||
(earliestTimeoutMs = root.type),
|
||||
(startTimeMs = root.stateNode),
|
||||
((earliestTimeoutMs = value),
|
||||
(startTimeMs = root.type),
|
||||
(sourceFiber$jscomp$0 = root.stateNode),
|
||||
0 === (root.effectTag & 64) &&
|
||||
("function" ===
|
||||
typeof earliestTimeoutMs.getDerivedStateFromError ||
|
||||
(null !== startTimeMs &&
|
||||
"function" === typeof startTimeMs.componentDidCatch &&
|
||||
typeof startTimeMs.getDerivedStateFromError ||
|
||||
(null !== sourceFiber$jscomp$0 &&
|
||||
"function" ===
|
||||
typeof sourceFiber$jscomp$0.componentDidCatch &&
|
||||
(null === legacyErrorBoundariesThatAlreadyFailed ||
|
||||
!legacyErrorBoundariesThatAlreadyFailed.has(
|
||||
startTimeMs
|
||||
sourceFiber$jscomp$0
|
||||
)))))
|
||||
) {
|
||||
root.effectTag |= 2048;
|
||||
root.expirationTime = returnFiber;
|
||||
returnFiber = createClassErrorUpdate(
|
||||
root,
|
||||
thenable,
|
||||
earliestTimeoutMs,
|
||||
returnFiber
|
||||
);
|
||||
enqueueCapturedUpdate(root, returnFiber);
|
||||
@@ -6477,7 +6483,7 @@ function onSuspend(
|
||||
msUntilTimeout
|
||||
) {
|
||||
root.expirationTime = rootExpirationTime;
|
||||
0 !== msUntilTimeout || shouldYieldToRenderer()
|
||||
0 !== msUntilTimeout || frameDeadline <= now$1()
|
||||
? 0 < msUntilTimeout &&
|
||||
(root.timeoutHandle = scheduleTimeout(
|
||||
onTimeout.bind(null, root, finishedWork, suspendedExpirationTime),
|
||||
@@ -6577,27 +6583,19 @@ function findHighestPriorityRoot() {
|
||||
nextFlushedRoot = highestPriorityRoot;
|
||||
nextFlushedExpirationTime = highestPriorityWork;
|
||||
}
|
||||
var didYield = !1;
|
||||
function shouldYieldToRenderer() {
|
||||
return didYield ? !0 : frameDeadline <= now$1() ? (didYield = !0) : !1;
|
||||
}
|
||||
function performAsyncWork() {
|
||||
try {
|
||||
if (!shouldYieldToRenderer() && null !== firstScheduledRoot) {
|
||||
recomputeCurrentRendererTime();
|
||||
var root = firstScheduledRoot;
|
||||
do {
|
||||
var expirationTime = root.expirationTime;
|
||||
0 !== expirationTime &&
|
||||
currentRendererTime <= expirationTime &&
|
||||
(root.nextExpirationTimeToWorkOn = currentRendererTime);
|
||||
root = root.nextScheduledRoot;
|
||||
} while (root !== firstScheduledRoot);
|
||||
}
|
||||
performWork(0, !0);
|
||||
} finally {
|
||||
didYield = !1;
|
||||
function performAsyncWork(didTimeout) {
|
||||
if (didTimeout && null !== firstScheduledRoot) {
|
||||
recomputeCurrentRendererTime();
|
||||
didTimeout = firstScheduledRoot;
|
||||
do {
|
||||
var expirationTime = didTimeout.expirationTime;
|
||||
0 !== expirationTime &&
|
||||
currentRendererTime <= expirationTime &&
|
||||
(didTimeout.nextExpirationTimeToWorkOn = currentRendererTime);
|
||||
didTimeout = didTimeout.nextScheduledRoot;
|
||||
} while (didTimeout !== firstScheduledRoot);
|
||||
}
|
||||
performWork(0, !0);
|
||||
}
|
||||
function performWork(minExpirationTime, isYieldy) {
|
||||
findHighestPriorityRoot();
|
||||
@@ -6608,7 +6606,10 @@ function performWork(minExpirationTime, isYieldy) {
|
||||
null !== nextFlushedRoot &&
|
||||
0 !== nextFlushedExpirationTime &&
|
||||
minExpirationTime <= nextFlushedExpirationTime &&
|
||||
!(didYield && currentRendererTime > nextFlushedExpirationTime);
|
||||
!(
|
||||
frameDeadline <= now$1() &&
|
||||
currentRendererTime > nextFlushedExpirationTime
|
||||
);
|
||||
|
||||
)
|
||||
performWorkOnRoot(
|
||||
@@ -6676,7 +6677,7 @@ function performWorkOnRoot(root, expirationTime, isYieldy) {
|
||||
renderRoot(root, isYieldy),
|
||||
(_finishedWork = root.finishedWork),
|
||||
null !== _finishedWork &&
|
||||
(shouldYieldToRenderer()
|
||||
(frameDeadline <= now$1()
|
||||
? (root.finishedWork = _finishedWork)
|
||||
: completeRoot$1(root, _finishedWork, expirationTime)));
|
||||
} else
|
||||
@@ -6917,18 +6918,20 @@ var roots = new Map(),
|
||||
maybeInstance = findHostInstance(this);
|
||||
} catch (error) {}
|
||||
if (null != maybeInstance) {
|
||||
var viewConfig =
|
||||
var nativeTag =
|
||||
maybeInstance._nativeTag || maybeInstance.canonical._nativeTag;
|
||||
maybeInstance =
|
||||
maybeInstance.viewConfig || maybeInstance.canonical.viewConfig;
|
||||
nativeProps = diffProperties(
|
||||
null,
|
||||
emptyObject,
|
||||
nativeProps,
|
||||
viewConfig.validAttributes
|
||||
maybeInstance.validAttributes
|
||||
);
|
||||
null != nativeProps &&
|
||||
UIManager.updateView(
|
||||
maybeInstance._nativeTag,
|
||||
viewConfig.uiViewClassName,
|
||||
nativeTag,
|
||||
maybeInstance.uiViewClassName,
|
||||
nativeProps
|
||||
);
|
||||
}
|
||||
@@ -6937,6 +6940,21 @@ var roots = new Map(),
|
||||
})(React.Component);
|
||||
})(findNodeHandle, findHostInstance),
|
||||
findNodeHandle: findNodeHandle,
|
||||
setNativeProps: function(handle, nativeProps) {
|
||||
null != handle._nativeTag &&
|
||||
((nativeProps = diffProperties(
|
||||
null,
|
||||
emptyObject,
|
||||
nativeProps,
|
||||
handle.viewConfig.validAttributes
|
||||
)),
|
||||
null != nativeProps &&
|
||||
UIManager.updateView(
|
||||
handle._nativeTag,
|
||||
handle.viewConfig.uiViewClassName,
|
||||
nativeProps
|
||||
));
|
||||
},
|
||||
render: function(element, containerTag, callback) {
|
||||
var root = roots.get(containerTag);
|
||||
if (!root) {
|
||||
@@ -7022,17 +7040,20 @@ var roots = new Map(),
|
||||
maybeInstance = findHostInstance(this);
|
||||
} catch (error) {}
|
||||
if (null != maybeInstance) {
|
||||
var viewConfig = maybeInstance.viewConfig;
|
||||
var nativeTag =
|
||||
maybeInstance._nativeTag || maybeInstance.canonical._nativeTag;
|
||||
maybeInstance =
|
||||
maybeInstance.viewConfig || maybeInstance.canonical.viewConfig;
|
||||
nativeProps = diffProperties(
|
||||
null,
|
||||
emptyObject,
|
||||
nativeProps,
|
||||
viewConfig.validAttributes
|
||||
maybeInstance.validAttributes
|
||||
);
|
||||
null != nativeProps &&
|
||||
UIManager.updateView(
|
||||
maybeInstance._nativeTag,
|
||||
viewConfig.uiViewClassName,
|
||||
nativeTag,
|
||||
maybeInstance.uiViewClassName,
|
||||
nativeProps
|
||||
);
|
||||
}
|
||||
@@ -7068,7 +7089,7 @@ var roots = new Map(),
|
||||
findFiberByHostInstance: getInstanceFromInstance,
|
||||
getInspectorDataForViewTag: getInspectorDataForViewTag,
|
||||
bundleType: 0,
|
||||
version: "16.8.1",
|
||||
version: "16.8.3",
|
||||
rendererPackageName: "react-native-renderer"
|
||||
});
|
||||
var ReactFabric$2 = { default: ReactFabric },
|
||||
|
||||
@@ -3208,6 +3208,8 @@ function updateReducer(reducer) {
|
||||
is(newState, hook.memoizedState) || (didReceiveUpdate = !0);
|
||||
hook.memoizedState = newState;
|
||||
hook.baseUpdate === queue.last && (hook.baseState = newState);
|
||||
queue.eagerReducer = reducer;
|
||||
queue.eagerState = newState;
|
||||
return [newState, _dispatch];
|
||||
}
|
||||
}
|
||||
@@ -3538,6 +3540,8 @@ function tryHydrate(fiber, nextInstance) {
|
||||
(nextInstance = shim$1(nextInstance, fiber.pendingProps)),
|
||||
null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1
|
||||
);
|
||||
case 13:
|
||||
return !1;
|
||||
default:
|
||||
return !1;
|
||||
}
|
||||
@@ -4644,19 +4648,19 @@ function beginWork(current$$1, workInProgress, renderExpirationTime) {
|
||||
null !== dependency &&
|
||||
dependency.expirationTime < renderExpirationTime &&
|
||||
(dependency.expirationTime = renderExpirationTime);
|
||||
dependency = renderExpirationTime;
|
||||
for (var node = oldValue.return; null !== node; ) {
|
||||
dependency = node.alternate;
|
||||
if (node.childExpirationTime < renderExpirationTime)
|
||||
(node.childExpirationTime = renderExpirationTime),
|
||||
null !== dependency &&
|
||||
dependency.childExpirationTime <
|
||||
renderExpirationTime &&
|
||||
(dependency.childExpirationTime = renderExpirationTime);
|
||||
var alternate = node.alternate;
|
||||
if (node.childExpirationTime < dependency)
|
||||
(node.childExpirationTime = dependency),
|
||||
null !== alternate &&
|
||||
alternate.childExpirationTime < dependency &&
|
||||
(alternate.childExpirationTime = dependency);
|
||||
else if (
|
||||
null !== dependency &&
|
||||
dependency.childExpirationTime < renderExpirationTime
|
||||
null !== alternate &&
|
||||
alternate.childExpirationTime < dependency
|
||||
)
|
||||
dependency.childExpirationTime = renderExpirationTime;
|
||||
alternate.childExpirationTime = dependency;
|
||||
else break;
|
||||
node = node.return;
|
||||
}
|
||||
@@ -4786,12 +4790,11 @@ function beginWork(current$$1, workInProgress, renderExpirationTime) {
|
||||
renderExpirationTime
|
||||
)
|
||||
);
|
||||
default:
|
||||
invariant(
|
||||
!1,
|
||||
"Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue."
|
||||
);
|
||||
}
|
||||
invariant(
|
||||
!1,
|
||||
"Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue."
|
||||
);
|
||||
}
|
||||
var valueCursor = { current: null },
|
||||
currentlyRenderingFiber = null,
|
||||
@@ -5465,22 +5468,23 @@ function throwException(
|
||||
sourceFiber.expirationTime = 1073741823;
|
||||
return;
|
||||
}
|
||||
sourceFiber = root.pingCache;
|
||||
null === sourceFiber
|
||||
? ((sourceFiber = root.pingCache = new PossiblyWeakMap()),
|
||||
(returnFiber = new Set()),
|
||||
sourceFiber.set(thenable, returnFiber))
|
||||
: ((returnFiber = sourceFiber.get(thenable)),
|
||||
void 0 === returnFiber &&
|
||||
((returnFiber = new Set()),
|
||||
sourceFiber.set(thenable, returnFiber)));
|
||||
returnFiber.has(renderExpirationTime) ||
|
||||
(returnFiber.add(renderExpirationTime),
|
||||
sourceFiber = root;
|
||||
returnFiber = renderExpirationTime;
|
||||
var pingCache = sourceFiber.pingCache;
|
||||
null === pingCache
|
||||
? ((pingCache = sourceFiber.pingCache = new PossiblyWeakMap()),
|
||||
(current$$1 = new Set()),
|
||||
pingCache.set(thenable, current$$1))
|
||||
: ((current$$1 = pingCache.get(thenable)),
|
||||
void 0 === current$$1 &&
|
||||
((current$$1 = new Set()), pingCache.set(thenable, current$$1)));
|
||||
current$$1.has(returnFiber) ||
|
||||
(current$$1.add(returnFiber),
|
||||
(sourceFiber = pingSuspendedRoot.bind(
|
||||
null,
|
||||
root,
|
||||
sourceFiber,
|
||||
thenable,
|
||||
renderExpirationTime
|
||||
returnFiber
|
||||
)),
|
||||
(sourceFiber = tracing.unstable_wrap(sourceFiber)),
|
||||
thenable.then(sourceFiber, sourceFiber));
|
||||
@@ -5528,21 +5532,21 @@ function throwException(
|
||||
return;
|
||||
case 1:
|
||||
if (
|
||||
((thenable = value),
|
||||
(earliestTimeoutMs = root.type),
|
||||
(startTimeMs = root.stateNode),
|
||||
((earliestTimeoutMs = value),
|
||||
(startTimeMs = root.type),
|
||||
(sourceFiber = root.stateNode),
|
||||
0 === (root.effectTag & 64) &&
|
||||
("function" === typeof earliestTimeoutMs.getDerivedStateFromError ||
|
||||
(null !== startTimeMs &&
|
||||
"function" === typeof startTimeMs.componentDidCatch &&
|
||||
("function" === typeof startTimeMs.getDerivedStateFromError ||
|
||||
(null !== sourceFiber &&
|
||||
"function" === typeof sourceFiber.componentDidCatch &&
|
||||
(null === legacyErrorBoundariesThatAlreadyFailed ||
|
||||
!legacyErrorBoundariesThatAlreadyFailed.has(startTimeMs)))))
|
||||
!legacyErrorBoundariesThatAlreadyFailed.has(sourceFiber)))))
|
||||
) {
|
||||
root.effectTag |= 2048;
|
||||
root.expirationTime = renderExpirationTime;
|
||||
renderExpirationTime = createClassErrorUpdate(
|
||||
root,
|
||||
thenable,
|
||||
earliestTimeoutMs,
|
||||
renderExpirationTime
|
||||
);
|
||||
enqueueCapturedUpdate(root, renderExpirationTime);
|
||||
@@ -5583,6 +5587,8 @@ function unwindWork(workInProgress) {
|
||||
workInProgress)
|
||||
: null
|
||||
);
|
||||
case 18:
|
||||
return null;
|
||||
case 4:
|
||||
return popHostContainer(workInProgress), null;
|
||||
case 10:
|
||||
@@ -5927,6 +5933,7 @@ function commitPassiveEffects(root, firstEffect) {
|
||||
isRendering = previousIsRendering;
|
||||
previousIsRendering = root.expirationTime;
|
||||
0 !== previousIsRendering && requestWork(root, previousIsRendering);
|
||||
isBatchingUpdates || isRendering || performWork(1073741823, !1);
|
||||
}
|
||||
function flushPassiveEffects() {
|
||||
if (null !== passiveEffectCallbackHandle) {
|
||||
@@ -6241,6 +6248,8 @@ function completeUnitOfWork(workInProgress) {
|
||||
case 17:
|
||||
isContextProvider(current$$1.type) && popContext(current$$1);
|
||||
break;
|
||||
case 18:
|
||||
break;
|
||||
default:
|
||||
invariant(
|
||||
!1,
|
||||
@@ -6387,7 +6396,7 @@ function renderRoot(root, isYieldy) {
|
||||
do {
|
||||
try {
|
||||
if (isYieldy)
|
||||
for (; null !== nextUnitOfWork && !shouldYieldToRenderer(); )
|
||||
for (; null !== nextUnitOfWork && !(frameDeadline <= now$1()); )
|
||||
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
|
||||
else
|
||||
for (; null !== nextUnitOfWork; )
|
||||
@@ -6680,7 +6689,7 @@ function onSuspend(
|
||||
msUntilTimeout
|
||||
) {
|
||||
root.expirationTime = rootExpirationTime;
|
||||
0 !== msUntilTimeout || shouldYieldToRenderer()
|
||||
0 !== msUntilTimeout || frameDeadline <= now$1()
|
||||
? 0 < msUntilTimeout &&
|
||||
(root.timeoutHandle = scheduleTimeout(
|
||||
onTimeout.bind(null, root, finishedWork, suspendedExpirationTime),
|
||||
@@ -6780,27 +6789,19 @@ function findHighestPriorityRoot() {
|
||||
nextFlushedRoot = highestPriorityRoot;
|
||||
nextFlushedExpirationTime = highestPriorityWork;
|
||||
}
|
||||
var didYield = !1;
|
||||
function shouldYieldToRenderer() {
|
||||
return didYield ? !0 : frameDeadline <= now$1() ? (didYield = !0) : !1;
|
||||
}
|
||||
function performAsyncWork() {
|
||||
try {
|
||||
if (!shouldYieldToRenderer() && null !== firstScheduledRoot) {
|
||||
recomputeCurrentRendererTime();
|
||||
var root = firstScheduledRoot;
|
||||
do {
|
||||
var expirationTime = root.expirationTime;
|
||||
0 !== expirationTime &&
|
||||
currentRendererTime <= expirationTime &&
|
||||
(root.nextExpirationTimeToWorkOn = currentRendererTime);
|
||||
root = root.nextScheduledRoot;
|
||||
} while (root !== firstScheduledRoot);
|
||||
}
|
||||
performWork(0, !0);
|
||||
} finally {
|
||||
didYield = !1;
|
||||
function performAsyncWork(didTimeout) {
|
||||
if (didTimeout && null !== firstScheduledRoot) {
|
||||
recomputeCurrentRendererTime();
|
||||
didTimeout = firstScheduledRoot;
|
||||
do {
|
||||
var expirationTime = didTimeout.expirationTime;
|
||||
0 !== expirationTime &&
|
||||
currentRendererTime <= expirationTime &&
|
||||
(didTimeout.nextExpirationTimeToWorkOn = currentRendererTime);
|
||||
didTimeout = didTimeout.nextScheduledRoot;
|
||||
} while (didTimeout !== firstScheduledRoot);
|
||||
}
|
||||
performWork(0, !0);
|
||||
}
|
||||
function performWork(minExpirationTime, isYieldy) {
|
||||
findHighestPriorityRoot();
|
||||
@@ -6811,7 +6812,10 @@ function performWork(minExpirationTime, isYieldy) {
|
||||
null !== nextFlushedRoot &&
|
||||
0 !== nextFlushedExpirationTime &&
|
||||
minExpirationTime <= nextFlushedExpirationTime &&
|
||||
!(didYield && currentRendererTime > nextFlushedExpirationTime);
|
||||
!(
|
||||
frameDeadline <= now$1() &&
|
||||
currentRendererTime > nextFlushedExpirationTime
|
||||
);
|
||||
|
||||
)
|
||||
performWorkOnRoot(
|
||||
@@ -6879,7 +6883,7 @@ function performWorkOnRoot(root, expirationTime, isYieldy) {
|
||||
renderRoot(root, isYieldy),
|
||||
(_finishedWork = root.finishedWork),
|
||||
null !== _finishedWork &&
|
||||
(shouldYieldToRenderer()
|
||||
(frameDeadline <= now$1()
|
||||
? (root.finishedWork = _finishedWork)
|
||||
: completeRoot$1(root, _finishedWork, expirationTime)));
|
||||
} else
|
||||
@@ -7120,18 +7124,20 @@ var roots = new Map(),
|
||||
maybeInstance = findHostInstance(this);
|
||||
} catch (error) {}
|
||||
if (null != maybeInstance) {
|
||||
var viewConfig =
|
||||
var nativeTag =
|
||||
maybeInstance._nativeTag || maybeInstance.canonical._nativeTag;
|
||||
maybeInstance =
|
||||
maybeInstance.viewConfig || maybeInstance.canonical.viewConfig;
|
||||
nativeProps = diffProperties(
|
||||
null,
|
||||
emptyObject,
|
||||
nativeProps,
|
||||
viewConfig.validAttributes
|
||||
maybeInstance.validAttributes
|
||||
);
|
||||
null != nativeProps &&
|
||||
UIManager.updateView(
|
||||
maybeInstance._nativeTag,
|
||||
viewConfig.uiViewClassName,
|
||||
nativeTag,
|
||||
maybeInstance.uiViewClassName,
|
||||
nativeProps
|
||||
);
|
||||
}
|
||||
@@ -7140,6 +7146,21 @@ var roots = new Map(),
|
||||
})(React.Component);
|
||||
})(findNodeHandle, findHostInstance),
|
||||
findNodeHandle: findNodeHandle,
|
||||
setNativeProps: function(handle, nativeProps) {
|
||||
null != handle._nativeTag &&
|
||||
((nativeProps = diffProperties(
|
||||
null,
|
||||
emptyObject,
|
||||
nativeProps,
|
||||
handle.viewConfig.validAttributes
|
||||
)),
|
||||
null != nativeProps &&
|
||||
UIManager.updateView(
|
||||
handle._nativeTag,
|
||||
handle.viewConfig.uiViewClassName,
|
||||
nativeProps
|
||||
));
|
||||
},
|
||||
render: function(element, containerTag, callback) {
|
||||
var root = roots.get(containerTag);
|
||||
if (!root) {
|
||||
@@ -7230,17 +7251,20 @@ var roots = new Map(),
|
||||
maybeInstance = findHostInstance(this);
|
||||
} catch (error) {}
|
||||
if (null != maybeInstance) {
|
||||
var viewConfig = maybeInstance.viewConfig;
|
||||
var nativeTag =
|
||||
maybeInstance._nativeTag || maybeInstance.canonical._nativeTag;
|
||||
maybeInstance =
|
||||
maybeInstance.viewConfig || maybeInstance.canonical.viewConfig;
|
||||
nativeProps = diffProperties(
|
||||
null,
|
||||
emptyObject,
|
||||
nativeProps,
|
||||
viewConfig.validAttributes
|
||||
maybeInstance.validAttributes
|
||||
);
|
||||
null != nativeProps &&
|
||||
UIManager.updateView(
|
||||
maybeInstance._nativeTag,
|
||||
viewConfig.uiViewClassName,
|
||||
nativeTag,
|
||||
maybeInstance.uiViewClassName,
|
||||
nativeProps
|
||||
);
|
||||
}
|
||||
@@ -7276,7 +7300,7 @@ var roots = new Map(),
|
||||
findFiberByHostInstance: getInstanceFromInstance,
|
||||
getInspectorDataForViewTag: getInspectorDataForViewTag,
|
||||
bundleType: 0,
|
||||
version: "16.8.1",
|
||||
version: "16.8.3",
|
||||
rendererPackageName: "react-native-renderer"
|
||||
});
|
||||
var ReactFabric$2 = { default: ReactFabric },
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3224,6 +3224,8 @@ function updateReducer(reducer) {
|
||||
is(newState, hook.memoizedState) || (didReceiveUpdate = !0);
|
||||
hook.memoizedState = newState;
|
||||
hook.baseUpdate === queue.last && (hook.baseState = newState);
|
||||
queue.eagerReducer = reducer;
|
||||
queue.eagerState = newState;
|
||||
return [newState, _dispatch];
|
||||
}
|
||||
}
|
||||
@@ -3544,6 +3546,8 @@ function tryHydrate(fiber, nextInstance) {
|
||||
(nextInstance = shim$1(nextInstance, fiber.pendingProps)),
|
||||
null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1
|
||||
);
|
||||
case 13:
|
||||
return !1;
|
||||
default:
|
||||
return !1;
|
||||
}
|
||||
@@ -4607,19 +4611,19 @@ function beginWork(current$$1, workInProgress, renderExpirationTime) {
|
||||
null !== dependency &&
|
||||
dependency.expirationTime < renderExpirationTime &&
|
||||
(dependency.expirationTime = renderExpirationTime);
|
||||
dependency = renderExpirationTime;
|
||||
for (var node = oldValue.return; null !== node; ) {
|
||||
dependency = node.alternate;
|
||||
if (node.childExpirationTime < renderExpirationTime)
|
||||
(node.childExpirationTime = renderExpirationTime),
|
||||
null !== dependency &&
|
||||
dependency.childExpirationTime <
|
||||
renderExpirationTime &&
|
||||
(dependency.childExpirationTime = renderExpirationTime);
|
||||
var alternate = node.alternate;
|
||||
if (node.childExpirationTime < dependency)
|
||||
(node.childExpirationTime = dependency),
|
||||
null !== alternate &&
|
||||
alternate.childExpirationTime < dependency &&
|
||||
(alternate.childExpirationTime = dependency);
|
||||
else if (
|
||||
null !== dependency &&
|
||||
dependency.childExpirationTime < renderExpirationTime
|
||||
null !== alternate &&
|
||||
alternate.childExpirationTime < dependency
|
||||
)
|
||||
dependency.childExpirationTime = renderExpirationTime;
|
||||
alternate.childExpirationTime = dependency;
|
||||
else break;
|
||||
node = node.return;
|
||||
}
|
||||
@@ -4749,12 +4753,11 @@ function beginWork(current$$1, workInProgress, renderExpirationTime) {
|
||||
renderExpirationTime
|
||||
)
|
||||
);
|
||||
default:
|
||||
invariant(
|
||||
!1,
|
||||
"Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue."
|
||||
);
|
||||
}
|
||||
invariant(
|
||||
!1,
|
||||
"Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue."
|
||||
);
|
||||
}
|
||||
var valueCursor = { current: null },
|
||||
currentlyRenderingFiber = null,
|
||||
@@ -5091,7 +5094,7 @@ function logCapturedError(capturedError) {
|
||||
: Error("Unspecified error at:" + componentStack);
|
||||
ExceptionsManager.handleException(error, !1);
|
||||
}
|
||||
var PossiblyWeakSet = "function" === typeof WeakSet ? WeakSet : Set;
|
||||
var PossiblyWeakSet$1 = "function" === typeof WeakSet ? WeakSet : Set;
|
||||
function logError(boundary, errorInfo) {
|
||||
var source = errorInfo.source,
|
||||
stack = errorInfo.stack;
|
||||
@@ -5304,7 +5307,7 @@ function commitPlacement(finishedWork) {
|
||||
parentFiber.sibling.return = parentFiber.return;
|
||||
for (
|
||||
parentFiber = parentFiber.sibling;
|
||||
5 !== parentFiber.tag && 6 !== parentFiber.tag;
|
||||
5 !== parentFiber.tag && 6 !== parentFiber.tag && 18 !== parentFiber.tag;
|
||||
|
||||
) {
|
||||
if (parentFiber.effectTag & 2) continue b;
|
||||
@@ -5548,9 +5551,9 @@ function commitWork(current$$1, finishedWork) {
|
||||
finishedWork.updateQueue = null;
|
||||
var retryCache = finishedWork.stateNode;
|
||||
null === retryCache &&
|
||||
(retryCache = finishedWork.stateNode = new PossiblyWeakSet());
|
||||
(retryCache = finishedWork.stateNode = new PossiblyWeakSet$1());
|
||||
instance.forEach(function(thenable) {
|
||||
var retry = retryTimedOutBoundary.bind(null, finishedWork, thenable);
|
||||
var retry = resolveRetryThenable.bind(null, finishedWork, thenable);
|
||||
retryCache.has(thenable) ||
|
||||
(retryCache.add(thenable), thenable.then(retry, retry));
|
||||
});
|
||||
@@ -5635,6 +5638,8 @@ function unwindWork(workInProgress) {
|
||||
workInProgress)
|
||||
: null
|
||||
);
|
||||
case 18:
|
||||
return null;
|
||||
case 4:
|
||||
return popHostContainer(workInProgress), null;
|
||||
case 10:
|
||||
@@ -5890,6 +5895,7 @@ function commitPassiveEffects(root, firstEffect) {
|
||||
isRendering = previousIsRendering;
|
||||
previousIsRendering = root.expirationTime;
|
||||
0 !== previousIsRendering && requestWork(root, previousIsRendering);
|
||||
isBatchingUpdates || isRendering || performWork(1073741823, !1);
|
||||
}
|
||||
function flushPassiveEffects() {
|
||||
if (null !== passiveEffectCallbackHandle) {
|
||||
@@ -6167,6 +6173,8 @@ function completeUnitOfWork(workInProgress) {
|
||||
case 17:
|
||||
isContextProvider(current$$1.type) && popContext(current$$1);
|
||||
break;
|
||||
case 18:
|
||||
break;
|
||||
default:
|
||||
invariant(
|
||||
!1,
|
||||
@@ -6260,7 +6268,7 @@ function renderRoot(root$jscomp$0, isYieldy) {
|
||||
do {
|
||||
try {
|
||||
if (isYieldy)
|
||||
for (; null !== nextUnitOfWork && !shouldYieldToRenderer(); )
|
||||
for (; null !== nextUnitOfWork && !(frameDeadline <= now$1()); )
|
||||
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
|
||||
else
|
||||
for (; null !== nextUnitOfWork; )
|
||||
@@ -6346,27 +6354,24 @@ function renderRoot(root$jscomp$0, isYieldy) {
|
||||
sourceFiber$jscomp$0.expirationTime = 1073741823;
|
||||
break a;
|
||||
}
|
||||
sourceFiber$jscomp$0 = root.pingCache;
|
||||
null === sourceFiber$jscomp$0
|
||||
? ((sourceFiber$jscomp$0 = root.pingCache = new PossiblyWeakMap()),
|
||||
(returnFiber$jscomp$0 = new Set()),
|
||||
sourceFiber$jscomp$0.set(thenable, returnFiber$jscomp$0))
|
||||
: ((returnFiber$jscomp$0 = sourceFiber$jscomp$0.get(
|
||||
thenable
|
||||
)),
|
||||
void 0 === returnFiber$jscomp$0 &&
|
||||
((returnFiber$jscomp$0 = new Set()),
|
||||
sourceFiber$jscomp$0.set(
|
||||
thenable,
|
||||
returnFiber$jscomp$0
|
||||
)));
|
||||
returnFiber$jscomp$0.has(returnFiber) ||
|
||||
(returnFiber$jscomp$0.add(returnFiber),
|
||||
sourceFiber$jscomp$0 = root;
|
||||
returnFiber$jscomp$0 = returnFiber;
|
||||
var pingCache = sourceFiber$jscomp$0.pingCache;
|
||||
null === pingCache
|
||||
? ((pingCache = sourceFiber$jscomp$0.pingCache = new PossiblyWeakMap()),
|
||||
(current$$1 = new Set()),
|
||||
pingCache.set(thenable, current$$1))
|
||||
: ((current$$1 = pingCache.get(thenable)),
|
||||
void 0 === current$$1 &&
|
||||
((current$$1 = new Set()),
|
||||
pingCache.set(thenable, current$$1)));
|
||||
current$$1.has(returnFiber$jscomp$0) ||
|
||||
(current$$1.add(returnFiber$jscomp$0),
|
||||
(sourceFiber$jscomp$0 = pingSuspendedRoot.bind(
|
||||
null,
|
||||
root,
|
||||
sourceFiber$jscomp$0,
|
||||
thenable,
|
||||
returnFiber
|
||||
returnFiber$jscomp$0
|
||||
)),
|
||||
thenable.then(sourceFiber$jscomp$0, sourceFiber$jscomp$0));
|
||||
-1 === earliestTimeoutMs
|
||||
@@ -6410,24 +6415,25 @@ function renderRoot(root$jscomp$0, isYieldy) {
|
||||
break a;
|
||||
case 1:
|
||||
if (
|
||||
((thenable = value),
|
||||
(earliestTimeoutMs = root.type),
|
||||
(startTimeMs = root.stateNode),
|
||||
((earliestTimeoutMs = value),
|
||||
(startTimeMs = root.type),
|
||||
(sourceFiber$jscomp$0 = root.stateNode),
|
||||
0 === (root.effectTag & 64) &&
|
||||
("function" ===
|
||||
typeof earliestTimeoutMs.getDerivedStateFromError ||
|
||||
(null !== startTimeMs &&
|
||||
"function" === typeof startTimeMs.componentDidCatch &&
|
||||
typeof startTimeMs.getDerivedStateFromError ||
|
||||
(null !== sourceFiber$jscomp$0 &&
|
||||
"function" ===
|
||||
typeof sourceFiber$jscomp$0.componentDidCatch &&
|
||||
(null === legacyErrorBoundariesThatAlreadyFailed ||
|
||||
!legacyErrorBoundariesThatAlreadyFailed.has(
|
||||
startTimeMs
|
||||
sourceFiber$jscomp$0
|
||||
)))))
|
||||
) {
|
||||
root.effectTag |= 2048;
|
||||
root.expirationTime = returnFiber;
|
||||
returnFiber = createClassErrorUpdate(
|
||||
root,
|
||||
thenable,
|
||||
earliestTimeoutMs,
|
||||
returnFiber
|
||||
);
|
||||
enqueueCapturedUpdate(root, returnFiber);
|
||||
@@ -6604,7 +6610,7 @@ function pingSuspendedRoot(root, thenable, pingTime) {
|
||||
0 !== pingTime && requestWork(root, pingTime);
|
||||
}
|
||||
}
|
||||
function retryTimedOutBoundary(boundaryFiber, thenable) {
|
||||
function resolveRetryThenable(boundaryFiber, thenable) {
|
||||
var retryCache = boundaryFiber.stateNode;
|
||||
null !== retryCache && retryCache.delete(thenable);
|
||||
thenable = requestCurrentTime();
|
||||
@@ -6701,7 +6707,7 @@ function onSuspend(
|
||||
msUntilTimeout
|
||||
) {
|
||||
root.expirationTime = rootExpirationTime;
|
||||
0 !== msUntilTimeout || shouldYieldToRenderer()
|
||||
0 !== msUntilTimeout || frameDeadline <= now$1()
|
||||
? 0 < msUntilTimeout &&
|
||||
(root.timeoutHandle = scheduleTimeout(
|
||||
onTimeout.bind(null, root, finishedWork, suspendedExpirationTime),
|
||||
@@ -6801,27 +6807,19 @@ function findHighestPriorityRoot() {
|
||||
nextFlushedRoot = highestPriorityRoot;
|
||||
nextFlushedExpirationTime = highestPriorityWork;
|
||||
}
|
||||
var didYield = !1;
|
||||
function shouldYieldToRenderer() {
|
||||
return didYield ? !0 : frameDeadline <= now$1() ? (didYield = !0) : !1;
|
||||
}
|
||||
function performAsyncWork() {
|
||||
try {
|
||||
if (!shouldYieldToRenderer() && null !== firstScheduledRoot) {
|
||||
recomputeCurrentRendererTime();
|
||||
var root = firstScheduledRoot;
|
||||
do {
|
||||
var expirationTime = root.expirationTime;
|
||||
0 !== expirationTime &&
|
||||
currentRendererTime <= expirationTime &&
|
||||
(root.nextExpirationTimeToWorkOn = currentRendererTime);
|
||||
root = root.nextScheduledRoot;
|
||||
} while (root !== firstScheduledRoot);
|
||||
}
|
||||
performWork(0, !0);
|
||||
} finally {
|
||||
didYield = !1;
|
||||
function performAsyncWork(didTimeout) {
|
||||
if (didTimeout && null !== firstScheduledRoot) {
|
||||
recomputeCurrentRendererTime();
|
||||
didTimeout = firstScheduledRoot;
|
||||
do {
|
||||
var expirationTime = didTimeout.expirationTime;
|
||||
0 !== expirationTime &&
|
||||
currentRendererTime <= expirationTime &&
|
||||
(didTimeout.nextExpirationTimeToWorkOn = currentRendererTime);
|
||||
didTimeout = didTimeout.nextScheduledRoot;
|
||||
} while (didTimeout !== firstScheduledRoot);
|
||||
}
|
||||
performWork(0, !0);
|
||||
}
|
||||
function performWork(minExpirationTime, isYieldy) {
|
||||
findHighestPriorityRoot();
|
||||
@@ -6832,7 +6830,10 @@ function performWork(minExpirationTime, isYieldy) {
|
||||
null !== nextFlushedRoot &&
|
||||
0 !== nextFlushedExpirationTime &&
|
||||
minExpirationTime <= nextFlushedExpirationTime &&
|
||||
!(didYield && currentRendererTime > nextFlushedExpirationTime);
|
||||
!(
|
||||
frameDeadline <= now$1() &&
|
||||
currentRendererTime > nextFlushedExpirationTime
|
||||
);
|
||||
|
||||
)
|
||||
performWorkOnRoot(
|
||||
@@ -6900,7 +6901,7 @@ function performWorkOnRoot(root, expirationTime, isYieldy) {
|
||||
renderRoot(root, isYieldy),
|
||||
(_finishedWork = root.finishedWork),
|
||||
null !== _finishedWork &&
|
||||
(shouldYieldToRenderer()
|
||||
(frameDeadline <= now$1()
|
||||
? (root.finishedWork = _finishedWork)
|
||||
: completeRoot(root, _finishedWork, expirationTime)));
|
||||
} else
|
||||
@@ -7141,18 +7142,20 @@ var roots = new Map(),
|
||||
maybeInstance = findHostInstance(this);
|
||||
} catch (error) {}
|
||||
if (null != maybeInstance) {
|
||||
var viewConfig =
|
||||
var nativeTag =
|
||||
maybeInstance._nativeTag || maybeInstance.canonical._nativeTag;
|
||||
maybeInstance =
|
||||
maybeInstance.viewConfig || maybeInstance.canonical.viewConfig;
|
||||
nativeProps = diffProperties(
|
||||
null,
|
||||
emptyObject,
|
||||
nativeProps,
|
||||
viewConfig.validAttributes
|
||||
maybeInstance.validAttributes
|
||||
);
|
||||
null != nativeProps &&
|
||||
UIManager.updateView(
|
||||
maybeInstance._nativeTag,
|
||||
viewConfig.uiViewClassName,
|
||||
nativeTag,
|
||||
maybeInstance.uiViewClassName,
|
||||
nativeProps
|
||||
);
|
||||
}
|
||||
@@ -7161,6 +7164,21 @@ var roots = new Map(),
|
||||
})(React.Component);
|
||||
})(findNodeHandle, findHostInstance),
|
||||
findNodeHandle: findNodeHandle,
|
||||
setNativeProps: function(handle, nativeProps) {
|
||||
null != handle._nativeTag &&
|
||||
((nativeProps = diffProperties(
|
||||
null,
|
||||
emptyObject,
|
||||
nativeProps,
|
||||
handle.viewConfig.validAttributes
|
||||
)),
|
||||
null != nativeProps &&
|
||||
UIManager.updateView(
|
||||
handle._nativeTag,
|
||||
handle.viewConfig.uiViewClassName,
|
||||
nativeProps
|
||||
));
|
||||
},
|
||||
render: function(element, containerTag, callback) {
|
||||
var root = roots.get(containerTag);
|
||||
if (!root) {
|
||||
@@ -7251,17 +7269,20 @@ var roots = new Map(),
|
||||
maybeInstance = findHostInstance(this);
|
||||
} catch (error) {}
|
||||
if (null != maybeInstance) {
|
||||
var viewConfig = maybeInstance.viewConfig;
|
||||
var nativeTag =
|
||||
maybeInstance._nativeTag || maybeInstance.canonical._nativeTag;
|
||||
maybeInstance =
|
||||
maybeInstance.viewConfig || maybeInstance.canonical.viewConfig;
|
||||
nativeProps = diffProperties(
|
||||
null,
|
||||
emptyObject,
|
||||
nativeProps,
|
||||
viewConfig.validAttributes
|
||||
maybeInstance.validAttributes
|
||||
);
|
||||
null != nativeProps &&
|
||||
UIManager.updateView(
|
||||
maybeInstance._nativeTag,
|
||||
viewConfig.uiViewClassName,
|
||||
nativeTag,
|
||||
maybeInstance.uiViewClassName,
|
||||
nativeProps
|
||||
);
|
||||
}
|
||||
@@ -7302,7 +7323,7 @@ var roots = new Map(),
|
||||
findFiberByHostInstance: getInstanceFromTag,
|
||||
getInspectorDataForViewTag: getInspectorDataForViewTag,
|
||||
bundleType: 0,
|
||||
version: "16.8.1",
|
||||
version: "16.8.3",
|
||||
rendererPackageName: "react-native-renderer"
|
||||
});
|
||||
var ReactNativeRenderer$2 = { default: ReactNativeRenderer },
|
||||
|
||||
@@ -3244,6 +3244,8 @@ function updateReducer(reducer) {
|
||||
is(newState, hook.memoizedState) || (didReceiveUpdate = !0);
|
||||
hook.memoizedState = newState;
|
||||
hook.baseUpdate === queue.last && (hook.baseState = newState);
|
||||
queue.eagerReducer = reducer;
|
||||
queue.eagerState = newState;
|
||||
return [newState, _dispatch];
|
||||
}
|
||||
}
|
||||
@@ -3574,6 +3576,8 @@ function tryHydrate(fiber, nextInstance) {
|
||||
(nextInstance = shim$1(nextInstance, fiber.pendingProps)),
|
||||
null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1
|
||||
);
|
||||
case 13:
|
||||
return !1;
|
||||
default:
|
||||
return !1;
|
||||
}
|
||||
@@ -4680,19 +4684,19 @@ function beginWork(current$$1, workInProgress, renderExpirationTime) {
|
||||
null !== dependency &&
|
||||
dependency.expirationTime < renderExpirationTime &&
|
||||
(dependency.expirationTime = renderExpirationTime);
|
||||
dependency = renderExpirationTime;
|
||||
for (var node = oldValue.return; null !== node; ) {
|
||||
dependency = node.alternate;
|
||||
if (node.childExpirationTime < renderExpirationTime)
|
||||
(node.childExpirationTime = renderExpirationTime),
|
||||
null !== dependency &&
|
||||
dependency.childExpirationTime <
|
||||
renderExpirationTime &&
|
||||
(dependency.childExpirationTime = renderExpirationTime);
|
||||
var alternate = node.alternate;
|
||||
if (node.childExpirationTime < dependency)
|
||||
(node.childExpirationTime = dependency),
|
||||
null !== alternate &&
|
||||
alternate.childExpirationTime < dependency &&
|
||||
(alternate.childExpirationTime = dependency);
|
||||
else if (
|
||||
null !== dependency &&
|
||||
dependency.childExpirationTime < renderExpirationTime
|
||||
null !== alternate &&
|
||||
alternate.childExpirationTime < dependency
|
||||
)
|
||||
dependency.childExpirationTime = renderExpirationTime;
|
||||
alternate.childExpirationTime = dependency;
|
||||
else break;
|
||||
node = node.return;
|
||||
}
|
||||
@@ -4822,12 +4826,11 @@ function beginWork(current$$1, workInProgress, renderExpirationTime) {
|
||||
renderExpirationTime
|
||||
)
|
||||
);
|
||||
default:
|
||||
invariant(
|
||||
!1,
|
||||
"Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue."
|
||||
);
|
||||
}
|
||||
invariant(
|
||||
!1,
|
||||
"Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue."
|
||||
);
|
||||
}
|
||||
var valueCursor = { current: null },
|
||||
currentlyRenderingFiber = null,
|
||||
@@ -5164,7 +5167,7 @@ function logCapturedError(capturedError) {
|
||||
: Error("Unspecified error at:" + componentStack);
|
||||
ExceptionsManager.handleException(error, !1);
|
||||
}
|
||||
var PossiblyWeakSet = "function" === typeof WeakSet ? WeakSet : Set;
|
||||
var PossiblyWeakSet$1 = "function" === typeof WeakSet ? WeakSet : Set;
|
||||
function logError(boundary, errorInfo) {
|
||||
var source = errorInfo.source,
|
||||
stack = errorInfo.stack;
|
||||
@@ -5377,7 +5380,7 @@ function commitPlacement(finishedWork) {
|
||||
parentFiber.sibling.return = parentFiber.return;
|
||||
for (
|
||||
parentFiber = parentFiber.sibling;
|
||||
5 !== parentFiber.tag && 6 !== parentFiber.tag;
|
||||
5 !== parentFiber.tag && 6 !== parentFiber.tag && 18 !== parentFiber.tag;
|
||||
|
||||
) {
|
||||
if (parentFiber.effectTag & 2) continue b;
|
||||
@@ -5621,9 +5624,9 @@ function commitWork(current$$1, finishedWork) {
|
||||
finishedWork.updateQueue = null;
|
||||
var retryCache = finishedWork.stateNode;
|
||||
null === retryCache &&
|
||||
(retryCache = finishedWork.stateNode = new PossiblyWeakSet());
|
||||
(retryCache = finishedWork.stateNode = new PossiblyWeakSet$1());
|
||||
instance.forEach(function(thenable) {
|
||||
var retry = retryTimedOutBoundary.bind(null, finishedWork, thenable);
|
||||
var retry = resolveRetryThenable.bind(null, finishedWork, thenable);
|
||||
retry = tracing.unstable_wrap(retry);
|
||||
retryCache.has(thenable) ||
|
||||
(retryCache.add(thenable), thenable.then(retry, retry));
|
||||
@@ -5740,22 +5743,23 @@ function throwException(
|
||||
sourceFiber.expirationTime = 1073741823;
|
||||
return;
|
||||
}
|
||||
sourceFiber = root.pingCache;
|
||||
null === sourceFiber
|
||||
? ((sourceFiber = root.pingCache = new PossiblyWeakMap()),
|
||||
(returnFiber = new Set()),
|
||||
sourceFiber.set(thenable, returnFiber))
|
||||
: ((returnFiber = sourceFiber.get(thenable)),
|
||||
void 0 === returnFiber &&
|
||||
((returnFiber = new Set()),
|
||||
sourceFiber.set(thenable, returnFiber)));
|
||||
returnFiber.has(renderExpirationTime) ||
|
||||
(returnFiber.add(renderExpirationTime),
|
||||
sourceFiber = root;
|
||||
returnFiber = renderExpirationTime;
|
||||
var pingCache = sourceFiber.pingCache;
|
||||
null === pingCache
|
||||
? ((pingCache = sourceFiber.pingCache = new PossiblyWeakMap()),
|
||||
(current$$1 = new Set()),
|
||||
pingCache.set(thenable, current$$1))
|
||||
: ((current$$1 = pingCache.get(thenable)),
|
||||
void 0 === current$$1 &&
|
||||
((current$$1 = new Set()), pingCache.set(thenable, current$$1)));
|
||||
current$$1.has(returnFiber) ||
|
||||
(current$$1.add(returnFiber),
|
||||
(sourceFiber = pingSuspendedRoot.bind(
|
||||
null,
|
||||
root,
|
||||
sourceFiber,
|
||||
thenable,
|
||||
renderExpirationTime
|
||||
returnFiber
|
||||
)),
|
||||
(sourceFiber = tracing.unstable_wrap(sourceFiber)),
|
||||
thenable.then(sourceFiber, sourceFiber));
|
||||
@@ -5803,21 +5807,21 @@ function throwException(
|
||||
return;
|
||||
case 1:
|
||||
if (
|
||||
((thenable = value),
|
||||
(earliestTimeoutMs = root.type),
|
||||
(startTimeMs = root.stateNode),
|
||||
((earliestTimeoutMs = value),
|
||||
(startTimeMs = root.type),
|
||||
(sourceFiber = root.stateNode),
|
||||
0 === (root.effectTag & 64) &&
|
||||
("function" === typeof earliestTimeoutMs.getDerivedStateFromError ||
|
||||
(null !== startTimeMs &&
|
||||
"function" === typeof startTimeMs.componentDidCatch &&
|
||||
("function" === typeof startTimeMs.getDerivedStateFromError ||
|
||||
(null !== sourceFiber &&
|
||||
"function" === typeof sourceFiber.componentDidCatch &&
|
||||
(null === legacyErrorBoundariesThatAlreadyFailed ||
|
||||
!legacyErrorBoundariesThatAlreadyFailed.has(startTimeMs)))))
|
||||
!legacyErrorBoundariesThatAlreadyFailed.has(sourceFiber)))))
|
||||
) {
|
||||
root.effectTag |= 2048;
|
||||
root.expirationTime = renderExpirationTime;
|
||||
renderExpirationTime = createClassErrorUpdate(
|
||||
root,
|
||||
thenable,
|
||||
earliestTimeoutMs,
|
||||
renderExpirationTime
|
||||
);
|
||||
enqueueCapturedUpdate(root, renderExpirationTime);
|
||||
@@ -5858,6 +5862,8 @@ function unwindWork(workInProgress) {
|
||||
workInProgress)
|
||||
: null
|
||||
);
|
||||
case 18:
|
||||
return null;
|
||||
case 4:
|
||||
return popHostContainer(workInProgress), null;
|
||||
case 10:
|
||||
@@ -6132,6 +6138,7 @@ function commitPassiveEffects(root, firstEffect) {
|
||||
isRendering = previousIsRendering;
|
||||
previousIsRendering = root.expirationTime;
|
||||
0 !== previousIsRendering && requestWork(root, previousIsRendering);
|
||||
isBatchingUpdates || isRendering || performWork(1073741823, !1);
|
||||
}
|
||||
function flushPassiveEffects() {
|
||||
if (null !== passiveEffectCallbackHandle) {
|
||||
@@ -6453,6 +6460,8 @@ function completeUnitOfWork(workInProgress) {
|
||||
case 17:
|
||||
isContextProvider(current$$1.type) && popContext(current$$1);
|
||||
break;
|
||||
case 18:
|
||||
break;
|
||||
default:
|
||||
invariant(
|
||||
!1,
|
||||
@@ -6607,7 +6616,7 @@ function renderRoot(root, isYieldy) {
|
||||
do {
|
||||
try {
|
||||
if (isYieldy)
|
||||
for (; null !== nextUnitOfWork && !shouldYieldToRenderer(); )
|
||||
for (; null !== nextUnitOfWork && !(frameDeadline <= now$1()); )
|
||||
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
|
||||
else
|
||||
for (; null !== nextUnitOfWork; )
|
||||
@@ -6788,7 +6797,7 @@ function pingSuspendedRoot(root, thenable, pingTime) {
|
||||
0 !== pingTime && requestWork(root, pingTime);
|
||||
}
|
||||
}
|
||||
function retryTimedOutBoundary(boundaryFiber, thenable) {
|
||||
function resolveRetryThenable(boundaryFiber, thenable) {
|
||||
var retryCache = boundaryFiber.stateNode;
|
||||
null !== retryCache && retryCache.delete(thenable);
|
||||
thenable = requestCurrentTime();
|
||||
@@ -6911,7 +6920,7 @@ function onSuspend(
|
||||
msUntilTimeout
|
||||
) {
|
||||
root.expirationTime = rootExpirationTime;
|
||||
0 !== msUntilTimeout || shouldYieldToRenderer()
|
||||
0 !== msUntilTimeout || frameDeadline <= now$1()
|
||||
? 0 < msUntilTimeout &&
|
||||
(root.timeoutHandle = scheduleTimeout(
|
||||
onTimeout.bind(null, root, finishedWork, suspendedExpirationTime),
|
||||
@@ -7011,27 +7020,19 @@ function findHighestPriorityRoot() {
|
||||
nextFlushedRoot = highestPriorityRoot;
|
||||
nextFlushedExpirationTime = highestPriorityWork;
|
||||
}
|
||||
var didYield = !1;
|
||||
function shouldYieldToRenderer() {
|
||||
return didYield ? !0 : frameDeadline <= now$1() ? (didYield = !0) : !1;
|
||||
}
|
||||
function performAsyncWork() {
|
||||
try {
|
||||
if (!shouldYieldToRenderer() && null !== firstScheduledRoot) {
|
||||
recomputeCurrentRendererTime();
|
||||
var root = firstScheduledRoot;
|
||||
do {
|
||||
var expirationTime = root.expirationTime;
|
||||
0 !== expirationTime &&
|
||||
currentRendererTime <= expirationTime &&
|
||||
(root.nextExpirationTimeToWorkOn = currentRendererTime);
|
||||
root = root.nextScheduledRoot;
|
||||
} while (root !== firstScheduledRoot);
|
||||
}
|
||||
performWork(0, !0);
|
||||
} finally {
|
||||
didYield = !1;
|
||||
function performAsyncWork(didTimeout) {
|
||||
if (didTimeout && null !== firstScheduledRoot) {
|
||||
recomputeCurrentRendererTime();
|
||||
didTimeout = firstScheduledRoot;
|
||||
do {
|
||||
var expirationTime = didTimeout.expirationTime;
|
||||
0 !== expirationTime &&
|
||||
currentRendererTime <= expirationTime &&
|
||||
(didTimeout.nextExpirationTimeToWorkOn = currentRendererTime);
|
||||
didTimeout = didTimeout.nextScheduledRoot;
|
||||
} while (didTimeout !== firstScheduledRoot);
|
||||
}
|
||||
performWork(0, !0);
|
||||
}
|
||||
function performWork(minExpirationTime, isYieldy) {
|
||||
findHighestPriorityRoot();
|
||||
@@ -7042,7 +7043,10 @@ function performWork(minExpirationTime, isYieldy) {
|
||||
null !== nextFlushedRoot &&
|
||||
0 !== nextFlushedExpirationTime &&
|
||||
minExpirationTime <= nextFlushedExpirationTime &&
|
||||
!(didYield && currentRendererTime > nextFlushedExpirationTime);
|
||||
!(
|
||||
frameDeadline <= now$1() &&
|
||||
currentRendererTime > nextFlushedExpirationTime
|
||||
);
|
||||
|
||||
)
|
||||
performWorkOnRoot(
|
||||
@@ -7110,7 +7114,7 @@ function performWorkOnRoot(root, expirationTime, isYieldy) {
|
||||
renderRoot(root, isYieldy),
|
||||
(_finishedWork = root.finishedWork),
|
||||
null !== _finishedWork &&
|
||||
(shouldYieldToRenderer()
|
||||
(frameDeadline <= now$1()
|
||||
? (root.finishedWork = _finishedWork)
|
||||
: completeRoot(root, _finishedWork, expirationTime)));
|
||||
} else
|
||||
@@ -7351,18 +7355,20 @@ var roots = new Map(),
|
||||
maybeInstance = findHostInstance(this);
|
||||
} catch (error) {}
|
||||
if (null != maybeInstance) {
|
||||
var viewConfig =
|
||||
var nativeTag =
|
||||
maybeInstance._nativeTag || maybeInstance.canonical._nativeTag;
|
||||
maybeInstance =
|
||||
maybeInstance.viewConfig || maybeInstance.canonical.viewConfig;
|
||||
nativeProps = diffProperties(
|
||||
null,
|
||||
emptyObject,
|
||||
nativeProps,
|
||||
viewConfig.validAttributes
|
||||
maybeInstance.validAttributes
|
||||
);
|
||||
null != nativeProps &&
|
||||
UIManager.updateView(
|
||||
maybeInstance._nativeTag,
|
||||
viewConfig.uiViewClassName,
|
||||
nativeTag,
|
||||
maybeInstance.uiViewClassName,
|
||||
nativeProps
|
||||
);
|
||||
}
|
||||
@@ -7371,6 +7377,21 @@ var roots = new Map(),
|
||||
})(React.Component);
|
||||
})(findNodeHandle, findHostInstance),
|
||||
findNodeHandle: findNodeHandle,
|
||||
setNativeProps: function(handle, nativeProps) {
|
||||
null != handle._nativeTag &&
|
||||
((nativeProps = diffProperties(
|
||||
null,
|
||||
emptyObject,
|
||||
nativeProps,
|
||||
handle.viewConfig.validAttributes
|
||||
)),
|
||||
null != nativeProps &&
|
||||
UIManager.updateView(
|
||||
handle._nativeTag,
|
||||
handle.viewConfig.uiViewClassName,
|
||||
nativeProps
|
||||
));
|
||||
},
|
||||
render: function(element, containerTag, callback) {
|
||||
var root = roots.get(containerTag);
|
||||
if (!root) {
|
||||
@@ -7466,17 +7487,20 @@ var roots = new Map(),
|
||||
maybeInstance = findHostInstance(this);
|
||||
} catch (error) {}
|
||||
if (null != maybeInstance) {
|
||||
var viewConfig = maybeInstance.viewConfig;
|
||||
var nativeTag =
|
||||
maybeInstance._nativeTag || maybeInstance.canonical._nativeTag;
|
||||
maybeInstance =
|
||||
maybeInstance.viewConfig || maybeInstance.canonical.viewConfig;
|
||||
nativeProps = diffProperties(
|
||||
null,
|
||||
emptyObject,
|
||||
nativeProps,
|
||||
viewConfig.validAttributes
|
||||
maybeInstance.validAttributes
|
||||
);
|
||||
null != nativeProps &&
|
||||
UIManager.updateView(
|
||||
maybeInstance._nativeTag,
|
||||
viewConfig.uiViewClassName,
|
||||
nativeTag,
|
||||
maybeInstance.uiViewClassName,
|
||||
nativeProps
|
||||
);
|
||||
}
|
||||
@@ -7517,7 +7541,7 @@ var roots = new Map(),
|
||||
findFiberByHostInstance: getInstanceFromTag,
|
||||
getInspectorDataForViewTag: getInspectorDataForViewTag,
|
||||
bundleType: 0,
|
||||
version: "16.8.1",
|
||||
version: "16.8.3",
|
||||
rendererPackageName: "react-native-renderer"
|
||||
});
|
||||
var ReactNativeRenderer$2 = { default: ReactNativeRenderer },
|
||||
|
||||
@@ -131,6 +131,7 @@ type SecretInternalsFabricType = {
|
||||
export type ReactNativeType = {
|
||||
NativeComponent: typeof ReactNativeComponent,
|
||||
findNodeHandle(componentOrHandle: any): ?number,
|
||||
setNativeProps(handle: any, nativeProps: Object): void,
|
||||
render(
|
||||
element: React$Element<any>,
|
||||
containerTag: any,
|
||||
@@ -146,6 +147,7 @@ export type ReactNativeType = {
|
||||
export type ReactFabricType = {
|
||||
NativeComponent: typeof ReactNativeComponent,
|
||||
findNodeHandle(componentOrHandle: any): ?number,
|
||||
setNativeProps(handle: any, nativeProps: Object): void,
|
||||
render(
|
||||
element: React$Element<any>,
|
||||
containerTag: any,
|
||||
|
||||
@@ -159,7 +159,7 @@ NSString *const RCTTextAttributesTagAttributeName = @"RCTTextAttributesTagAttrib
|
||||
}
|
||||
|
||||
// Shadow
|
||||
if (!CGSizeEqualToSize(_textShadowOffset, CGSizeZero)) {
|
||||
if (!isnan(_textShadowRadius)) {
|
||||
NSShadow *shadow = [NSShadow new];
|
||||
shadow.shadowOffset = _textShadowOffset;
|
||||
shadow.shadowBlurRadius = _textShadowRadius;
|
||||
|
||||
@@ -35,6 +35,13 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)didSetProps:(NSArray<NSString *> *)changedProps
|
||||
{
|
||||
[super didSetProps:changedProps];
|
||||
|
||||
self.textAttributes.opacity = NAN;
|
||||
}
|
||||
|
||||
- (BOOL)isYogaLeafNode
|
||||
{
|
||||
return YES;
|
||||
|
||||
@@ -43,6 +43,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@property (nonatomic, assign) BOOL blurOnSubmit;
|
||||
@property (nonatomic, assign) BOOL selectTextOnFocus;
|
||||
@property (nonatomic, assign) BOOL clearTextOnFocus;
|
||||
@property (nonatomic, assign) BOOL secureTextEntry;
|
||||
@property (nonatomic, copy) RCTTextSelection *selection;
|
||||
@property (nonatomic, strong, nullable) NSNumber *maxLength;
|
||||
@property (nonatomic, copy) NSAttributedString *attributedText;
|
||||
|
||||
@@ -141,9 +141,9 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithFrame:(CGRect)frame)
|
||||
|
||||
[attributedTextCopy removeAttribute:RCTTextAttributesTagAttributeName
|
||||
range:NSMakeRange(0, attributedTextCopy.length)];
|
||||
|
||||
|
||||
textNeedsUpdate = ([self textOf:attributedTextCopy equals:backedTextInputViewTextCopy] == NO);
|
||||
|
||||
|
||||
if (eventLag == 0 && textNeedsUpdate) {
|
||||
UITextRange *selection = self.backedTextInputView.selectedTextRange;
|
||||
NSInteger oldTextLength = self.backedTextInputView.attributedText.string.length;
|
||||
@@ -203,9 +203,65 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithFrame:(CGRect)frame)
|
||||
{
|
||||
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
|
||||
if (@available(iOS 10.0, *)) {
|
||||
|
||||
static dispatch_once_t onceToken;
|
||||
static NSDictionary<NSString *, NSString *> *contentTypeMap;
|
||||
|
||||
dispatch_once(&onceToken, ^{
|
||||
contentTypeMap = @{@"none": @"",
|
||||
@"URL": UITextContentTypeURL,
|
||||
@"addressCity": UITextContentTypeAddressCity,
|
||||
@"addressCityAndState":UITextContentTypeAddressCityAndState,
|
||||
@"addressState": UITextContentTypeAddressState,
|
||||
@"countryName": UITextContentTypeCountryName,
|
||||
@"creditCardNumber": UITextContentTypeCreditCardNumber,
|
||||
@"emailAddress": UITextContentTypeEmailAddress,
|
||||
@"familyName": UITextContentTypeFamilyName,
|
||||
@"fullStreetAddress": UITextContentTypeFullStreetAddress,
|
||||
@"givenName": UITextContentTypeGivenName,
|
||||
@"jobTitle": UITextContentTypeJobTitle,
|
||||
@"location": UITextContentTypeLocation,
|
||||
@"middleName": UITextContentTypeMiddleName,
|
||||
@"name": UITextContentTypeName,
|
||||
@"namePrefix": UITextContentTypeNamePrefix,
|
||||
@"nameSuffix": UITextContentTypeNameSuffix,
|
||||
@"nickname": UITextContentTypeNickname,
|
||||
@"organizationName": UITextContentTypeOrganizationName,
|
||||
@"postalCode": UITextContentTypePostalCode,
|
||||
@"streetAddressLine1": UITextContentTypeStreetAddressLine1,
|
||||
@"streetAddressLine2": UITextContentTypeStreetAddressLine2,
|
||||
@"sublocality": UITextContentTypeSublocality,
|
||||
@"telephoneNumber": UITextContentTypeTelephoneNumber,
|
||||
};
|
||||
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
|
||||
if (@available(iOS 11.0, tvOS 11.0, *)) {
|
||||
NSDictionary<NSString *, NSString *> * iOS11extras = @{@"username": UITextContentTypeUsername,
|
||||
@"password": UITextContentTypePassword};
|
||||
|
||||
NSMutableDictionary<NSString *, NSString *> * iOS11baseMap = [contentTypeMap mutableCopy];
|
||||
[iOS11baseMap addEntriesFromDictionary:iOS11extras];
|
||||
|
||||
contentTypeMap = [iOS11baseMap copy];
|
||||
}
|
||||
#endif
|
||||
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 120000 /* __IPHONE_12_0 */
|
||||
if (@available(iOS 12.0, tvOS 12.0, *)) {
|
||||
NSDictionary<NSString *, NSString *> * iOS12extras = @{@"newPassword": UITextContentTypeNewPassword,
|
||||
@"oneTimeCode": UITextContentTypeOneTimeCode};
|
||||
|
||||
NSMutableDictionary<NSString *, NSString *> * iOS12baseMap = [contentTypeMap mutableCopy];
|
||||
[iOS12baseMap addEntriesFromDictionary:iOS12extras];
|
||||
|
||||
contentTypeMap = [iOS12baseMap copy];
|
||||
}
|
||||
#endif
|
||||
});
|
||||
|
||||
// Setting textContentType to an empty string will disable any
|
||||
// default behaviour, like the autofill bar for password inputs
|
||||
self.backedTextInputView.textContentType = [type isEqualToString:@"none"] ? @"" : type;
|
||||
self.backedTextInputView.textContentType = contentTypeMap[type] ?: type;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -227,6 +283,24 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithFrame:(CGRect)frame)
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)secureTextEntry {
|
||||
return self.backedTextInputView.secureTextEntry;
|
||||
}
|
||||
|
||||
- (void)setSecureTextEntry:(BOOL)secureTextEntry {
|
||||
UIView<RCTBackedTextInputViewProtocol> *textInputView = self.backedTextInputView;
|
||||
|
||||
if (textInputView.secureTextEntry != secureTextEntry) {
|
||||
textInputView.secureTextEntry = secureTextEntry;
|
||||
|
||||
// Fix #5859, see https://stackoverflow.com/questions/14220187/uitextfield-has-trailing-whitespace-after-securetextentry-toggle/22537788#22537788
|
||||
NSAttributedString *originalText = [textInputView.attributedText copy];
|
||||
self.backedTextInputView.attributedText = [NSAttributedString new];
|
||||
self.backedTextInputView.attributedText = originalText;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#pragma mark - RCTBackedTextInputDelegate
|
||||
|
||||
- (BOOL)textInputShouldBeginEditing
|
||||
@@ -330,18 +404,12 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithFrame:(CGRect)frame)
|
||||
}
|
||||
}
|
||||
|
||||
if (range.location + range.length > _predictedText.length) {
|
||||
// _predictedText got out of sync in a bad way, so let's just force sync it. Haven't been able to repro this, but
|
||||
// it's causing a real crash here: #6523822
|
||||
NSString *previousText = backedTextInputView.attributedText.string ?: @"";
|
||||
|
||||
if (range.location + range.length > backedTextInputView.attributedText.string.length) {
|
||||
_predictedText = backedTextInputView.attributedText.string;
|
||||
}
|
||||
|
||||
NSString *previousText = [_predictedText substringWithRange:range] ?: @"";
|
||||
|
||||
if (!_predictedText || backedTextInputView.attributedText.string.length == 0) {
|
||||
_predictedText = text;
|
||||
} else {
|
||||
_predictedText = [_predictedText stringByReplacingCharactersInRange:range withString:text];
|
||||
_predictedText = [backedTextInputView.attributedText.string stringByReplacingCharactersInRange:range withString:text];
|
||||
}
|
||||
|
||||
if (_onTextInput) {
|
||||
@@ -376,7 +444,6 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithFrame:(CGRect)frame)
|
||||
[self textInputShouldChangeTextInRange:predictionRange replacementText:replacement];
|
||||
// JS will assume the selection changed based on the location of our shouldChangeTextInRange, so reset it.
|
||||
[self textInputDidChangeSelection];
|
||||
_predictedText = backedTextInputView.attributedText.string;
|
||||
}
|
||||
|
||||
_nativeEventCount++;
|
||||
|
||||
@@ -43,12 +43,12 @@ RCT_REMAP_VIEW_PROPERTY(keyboardAppearance, backedTextInputView.keyboardAppearan
|
||||
RCT_REMAP_VIEW_PROPERTY(placeholder, backedTextInputView.placeholder, NSString)
|
||||
RCT_REMAP_VIEW_PROPERTY(placeholderTextColor, backedTextInputView.placeholderColor, UIColor)
|
||||
RCT_REMAP_VIEW_PROPERTY(returnKeyType, backedTextInputView.returnKeyType, UIReturnKeyType)
|
||||
RCT_REMAP_VIEW_PROPERTY(secureTextEntry, backedTextInputView.secureTextEntry, BOOL)
|
||||
RCT_REMAP_VIEW_PROPERTY(selectionColor, backedTextInputView.tintColor, UIColor)
|
||||
RCT_REMAP_VIEW_PROPERTY(spellCheck, backedTextInputView.spellCheckingType, UITextSpellCheckingType)
|
||||
RCT_REMAP_VIEW_PROPERTY(caretHidden, backedTextInputView.caretHidden, BOOL)
|
||||
RCT_REMAP_VIEW_PROPERTY(clearButtonMode, backedTextInputView.clearButtonMode, UITextFieldViewMode)
|
||||
RCT_REMAP_VIEW_PROPERTY(scrollEnabled, backedTextInputView.scrollEnabled, BOOL)
|
||||
RCT_EXPORT_VIEW_PROPERTY(secureTextEntry, BOOL)
|
||||
RCT_EXPORT_VIEW_PROPERTY(blurOnSubmit, BOOL)
|
||||
RCT_EXPORT_VIEW_PROPERTY(clearTextOnFocus, BOOL)
|
||||
RCT_EXPORT_VIEW_PROPERTY(keyboardType, UIKeyboardType)
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
@implementation RCTUITextField {
|
||||
RCTBackedTextFieldDelegateAdapter *_textInputDelegateAdapter;
|
||||
NSMutableAttributedString *_attributesHolder;
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
@@ -26,7 +25,6 @@
|
||||
object:self];
|
||||
|
||||
_textInputDelegateAdapter = [[RCTBackedTextFieldDelegateAdapter alloc] initWithTextField:self];
|
||||
_attributesHolder = [[NSMutableAttributedString alloc] init];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -119,48 +117,6 @@
|
||||
return [super caretRectForPosition:position];
|
||||
}
|
||||
|
||||
#pragma mark - Fix for CJK Languages
|
||||
|
||||
/*
|
||||
* The workaround to fix inputting complex locales (like CJK languages).
|
||||
* When we use `setAttrbutedText:` while user is inputting text in a complex
|
||||
* locale (like Chinese, Japanese or Korean), some internal state breaks and
|
||||
* input stops working.
|
||||
*
|
||||
* To workaround that, we don't skip underlying attributedString in the text
|
||||
* field if only attributes were changed. We keep track of these attributes in
|
||||
* a local variable.
|
||||
*
|
||||
* There are two methods that are altered by this workaround:
|
||||
*
|
||||
* (1) `-setAttributedText:`
|
||||
* Applies the attributed string change to a local variable `_attributesHolder` instead of calling `-[super setAttributedText:]`.
|
||||
* If new attributed text differs from the existing one only in attributes,
|
||||
* skips `-[super setAttributedText:`] completely.
|
||||
*
|
||||
* (2) `-attributedText`
|
||||
* Return `_attributesHolder` context.
|
||||
* Updates `_atributesHolder` before returning if the underlying `super.attributedText.string` was changed.
|
||||
*
|
||||
*/
|
||||
- (void)setAttributedText:(NSAttributedString *)attributedText
|
||||
{
|
||||
BOOL textWasChanged = ![_attributesHolder.string isEqualToString:attributedText.string];
|
||||
[_attributesHolder setAttributedString:attributedText];
|
||||
|
||||
if (textWasChanged) {
|
||||
[super setAttributedText:attributedText];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSAttributedString *)attributedText
|
||||
{
|
||||
if (![super.attributedText.string isEqualToString:_attributesHolder.string]) {
|
||||
[_attributesHolder setAttributedString:super.attributedText];
|
||||
}
|
||||
|
||||
return _attributesHolder;
|
||||
}
|
||||
|
||||
#pragma mark - Positioning Overrides
|
||||
|
||||
|
||||
@@ -148,9 +148,9 @@ static void my_os_log_error_impl(void *dso, os_log_t log, os_log_type_t type, co
|
||||
{
|
||||
__weak RCTSRWebSocket *socket = _socket;
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
// Only reconnect if the observer wasn't stoppped while we were waiting
|
||||
if (socket) {
|
||||
[self start];
|
||||
[self start];
|
||||
if (!socket) {
|
||||
[self reconnect];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Vendored
-3
@@ -26,9 +26,6 @@ module.exports = (function(global, undefined) {
|
||||
return global.Map;
|
||||
}
|
||||
|
||||
// In case this module has not already been evaluated, import it now.
|
||||
require('./_wrapObjectFreezeAndFriends');
|
||||
|
||||
const hasOwn = Object.prototype.hasOwnProperty;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @author Ben Newman (@benjamn) <ben@benjamn.com>
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
let testMap; // Initialized lazily.
|
||||
function getTestMap() {
|
||||
return testMap || (testMap = new (require('./Map'))());
|
||||
}
|
||||
|
||||
// Wrap Object.{freeze,seal,preventExtensions} so each function adds its
|
||||
// argument to a Map first, which gives our ./Map.js polyfill a chance to
|
||||
// tag the object before it becomes non-extensible.
|
||||
['freeze', 'seal', 'preventExtensions'].forEach(name => {
|
||||
const method = Object[name];
|
||||
if (typeof method === 'function') {
|
||||
(Object: any)[name] = function(obj) {
|
||||
try {
|
||||
// If .set succeeds, also call .delete to avoid leaking memory.
|
||||
getTestMap()
|
||||
.set(obj, obj)
|
||||
.delete(obj);
|
||||
} finally {
|
||||
// If .set fails, the exception will be silently swallowed
|
||||
// by this return-from-finally statement, and the method will
|
||||
// behave exactly as it did before it was wrapped.
|
||||
return method.call(Object, obj);
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
+9
-1
@@ -16,6 +16,8 @@ const EventSubscriptionVendor = require('EventSubscriptionVendor');
|
||||
|
||||
const invariant = require('invariant');
|
||||
|
||||
const sparseFilterPredicate = () => true;
|
||||
|
||||
/**
|
||||
* @class EventEmitter
|
||||
* @description
|
||||
@@ -151,7 +153,13 @@ class EventEmitter {
|
||||
listeners(eventType: string): [EmitterSubscription] {
|
||||
const subscriptions = this._subscriber.getSubscriptionsForType(eventType);
|
||||
return subscriptions
|
||||
? subscriptions.map(subscription => subscription.listener)
|
||||
? subscriptions
|
||||
// We filter out missing entries because the array is sparse.
|
||||
// "callbackfn is called only for elements of the array which actually
|
||||
// exist; it is not called for missing elements of the array."
|
||||
// https://www.ecma-international.org/ecma-262/9.0/index.html#sec-array.prototype.filter
|
||||
.filter(sparseFilterPredicate)
|
||||
.map(subscription => subscription.listener)
|
||||
: [];
|
||||
}
|
||||
|
||||
|
||||
@@ -1688,7 +1688,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "export NODE_BINARY=node\n$SRCROOT/../scripts/react-native-xcode.sh RNTester/js/RNTesterApp.ios.js\n";
|
||||
shellScript = "export EXTRA_PACKAGER_ARGS=\"--reactNativePath $SRCROOT/../\"\nexport NODE_BINARY=node\n$SRCROOT/../scripts/react-native-xcode.sh RNTester/js/RNTesterApp.ios.js\n";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
|
||||
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 145 KiB After Width: | Height: | Size: 145 KiB |
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 308 KiB After Width: | Height: | Size: 309 KiB |
@@ -69,7 +69,8 @@ project.ext.react = [
|
||||
bundleAssetName: "RNTesterApp.android.bundle",
|
||||
entryFile: file("../../js/RNTesterApp.android.js"),
|
||||
root: "$rootDir",
|
||||
inputExcludes: ["android/**", "./**", ".gradle/**"]
|
||||
inputExcludes: ["android/**", "./**", ".gradle/**"],
|
||||
extraPackagerArgs: ["--reactNativePath", "$rootDir"]
|
||||
]
|
||||
|
||||
apply from: "../../../react.gradle"
|
||||
@@ -101,7 +102,7 @@ android {
|
||||
defaultConfig {
|
||||
applicationId "com.facebook.react.uiapp"
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 27
|
||||
targetSdkVersion 28
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
}
|
||||
|
||||
@@ -27,33 +27,34 @@ describe('DatePickerIOS', () => {
|
||||
it('Should change indicator with datetime picker', async () => {
|
||||
await openExampleWithTitle('Date and time picker');
|
||||
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));
|
||||
const dateIndicator = await element(by.id('date-indicator'));
|
||||
const timeIndicator = await element(by.id('time-indicator'));
|
||||
|
||||
await expect(testElement).toBeVisible();
|
||||
await expect(indicator).toBeVisible();
|
||||
await expect(dateIndicator).toBeVisible();
|
||||
await expect(timeIndicator).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');
|
||||
await expect(dateIndicator).toHaveText('12/4/2005');
|
||||
await expect(timeIndicator).toHaveText('4:10 AM');
|
||||
});
|
||||
|
||||
it('Should change indicator with date-only picker', async () => {
|
||||
await openExampleWithTitle('Date only');
|
||||
await openExampleWithTitle('Date only picker');
|
||||
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));
|
||||
const indicator = await element(by.id('date-indicator'));
|
||||
|
||||
await expect(testElement).toBeVisible();
|
||||
await expect(indicator).toBeVisible();
|
||||
@@ -62,6 +63,6 @@ describe('DatePickerIOS', () => {
|
||||
await testElement.setColumnToValue(1, '3');
|
||||
await testElement.setColumnToValue(2, '2006');
|
||||
|
||||
await expect(indicator).toHaveText('11/3/2006 4:10 AM');
|
||||
await expect(indicator).toHaveText('11/3/2006');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -111,6 +111,31 @@ class AccessibilityAndroidExample extends React.Component {
|
||||
</View>
|
||||
</RNTesterBlock>
|
||||
|
||||
<RNTesterBlock title="Touchable with accessibilityRole = header">
|
||||
<View
|
||||
accessible={true}
|
||||
accessibilityLabel="I'm a header, so I read it instead of embedded text."
|
||||
accessibilityRole="header">
|
||||
<Text style={{color: 'green'}}>This is</Text>
|
||||
<Text style={{color: 'blue'}}>
|
||||
nontouchable accessible view with label.
|
||||
</Text>
|
||||
</View>
|
||||
</RNTesterBlock>
|
||||
|
||||
<RNTesterBlock title="Touchable with accessibilityRole = link">
|
||||
<TouchableWithoutFeedback
|
||||
onPress={() =>
|
||||
ToastAndroid.show('Toasts work by default', ToastAndroid.SHORT)
|
||||
}
|
||||
accessibilityRole="link">
|
||||
<View style={styles.embedded}>
|
||||
<Text>Click me</Text>
|
||||
<Text>Or not</Text>
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
</RNTesterBlock>
|
||||
|
||||
<RNTesterBlock title="Touchable with accessibilityRole = button">
|
||||
<TouchableWithoutFeedback
|
||||
onPress={() =>
|
||||
|
||||
@@ -12,11 +12,10 @@
|
||||
|
||||
const React = require('react');
|
||||
const ReactNative = require('react-native');
|
||||
const {DatePickerIOS, StyleSheet, Text, TextInput, View} = ReactNative;
|
||||
const {DatePickerIOS, StyleSheet, Text, View} = ReactNative;
|
||||
|
||||
type State = {|
|
||||
date: Date,
|
||||
timeZoneOffsetInHours: number,
|
||||
|};
|
||||
|
||||
type Props = {|
|
||||
@@ -26,43 +25,25 @@ type Props = {|
|
||||
class WithDatePickerData extends React.Component<Props, State> {
|
||||
state = {
|
||||
date: new Date(),
|
||||
timeZoneOffsetInHours: (-1 * new Date().getTimezoneOffset()) / 60,
|
||||
};
|
||||
|
||||
onDateChange = date => {
|
||||
this.setState({date: date});
|
||||
};
|
||||
|
||||
onTimezoneChange = event => {
|
||||
const offset = parseInt(event.nativeEvent.text, 10);
|
||||
if (isNaN(offset)) {
|
||||
return;
|
||||
}
|
||||
this.setState({timeZoneOffsetInHours: offset});
|
||||
};
|
||||
|
||||
render() {
|
||||
// Ideally, the timezone input would be a picker rather than a
|
||||
// text input, but we don't have any pickers yet :(
|
||||
return (
|
||||
<View>
|
||||
<WithLabel label="Value:">
|
||||
<Text testID="date-and-time-indicator">
|
||||
{this.state.date.toLocaleDateString() +
|
||||
' ' +
|
||||
this.state.date.toLocaleTimeString([], {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
})}
|
||||
<Text testID="date-indicator">
|
||||
{this.state.date.toLocaleDateString()}
|
||||
</Text>
|
||||
<Text testID="time-indicator">
|
||||
{this.state.date.toLocaleTimeString([], {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
})}
|
||||
</Text>
|
||||
</WithLabel>
|
||||
<WithLabel label="Timezone:">
|
||||
<TextInput
|
||||
onChange={this.onTimezoneChange}
|
||||
style={styles.textinput}
|
||||
value={this.state.timeZoneOffsetInHours.toString()}
|
||||
/>
|
||||
<Text> hours from UTC</Text>
|
||||
</WithLabel>
|
||||
{this.props.children(this.state, this.onDateChange)}
|
||||
</View>
|
||||
@@ -124,7 +105,6 @@ exports.examples = [
|
||||
testID="date-and-time"
|
||||
date={state.date}
|
||||
mode="datetime"
|
||||
timeZoneOffsetInMinutes={state.timeZoneOffsetInHours * 60}
|
||||
onDateChange={onDateChange}
|
||||
/>
|
||||
)}
|
||||
@@ -142,7 +122,6 @@ exports.examples = [
|
||||
testID="date-only"
|
||||
date={state.date}
|
||||
mode="date"
|
||||
timeZoneOffsetInMinutes={state.timeZoneOffsetInHours * 60}
|
||||
onDateChange={onDateChange}
|
||||
/>
|
||||
)}
|
||||
@@ -151,16 +130,16 @@ exports.examples = [
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Time only picker, 10-minute interval',
|
||||
title: 'Picker with 20-minute interval',
|
||||
render: function(): React.Element<any> {
|
||||
return (
|
||||
<WithDatePickerData>
|
||||
{(state, onDateChange) => (
|
||||
<DatePickerIOS
|
||||
testID="time-only"
|
||||
testID="date-and-time-with-interval"
|
||||
date={state.date}
|
||||
mode="time"
|
||||
timeZoneOffsetInMinutes={state.timeZoneOffsetInHours * 60}
|
||||
minuteInterval={20}
|
||||
mode="datetime"
|
||||
onDateChange={onDateChange}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -54,6 +54,10 @@ class BasicSwitchExample extends React.Component<
|
||||
<Switch
|
||||
testID="on-off-initial-off"
|
||||
onValueChange={value => this.setState({falseSwitchIsOn: value})}
|
||||
trackColor={{
|
||||
true: 'yellow',
|
||||
false: 'purple',
|
||||
}}
|
||||
value={this.state.falseSwitchIsOn}
|
||||
/>
|
||||
<OnOffIndicator
|
||||
|
||||
@@ -325,6 +325,12 @@ class TextExample extends React.Component<{}> {
|
||||
right right right right right right right right right right right
|
||||
right right
|
||||
</Text>
|
||||
<Text style={{textAlign: 'justify'}}>
|
||||
justify (works when api level >= 26 otherwise fallbacks to "left"):
|
||||
this text component{"'"}s contents are laid out with "textAlign:
|
||||
justify" and as you can see all of the lines except the last one
|
||||
span the available width of the parent container.
|
||||
</Text>
|
||||
</RNTesterBlock>
|
||||
<RNTesterBlock title="Unicode">
|
||||
<View>
|
||||
@@ -615,11 +621,13 @@ class TextExample extends React.Component<{}> {
|
||||
Works with other text styles
|
||||
</Text>
|
||||
</RNTesterBlock>
|
||||
<RNTesterBlock title="Substring Emoji (should only see 'test')">
|
||||
<Text>{'test🙃'.substring(0, 5)}</Text>
|
||||
</RNTesterBlock>
|
||||
</RNTesterPage>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
backgroundColorText: {
|
||||
left: 5,
|
||||
|
||||
@@ -428,6 +428,12 @@ exports.examples = [
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Substring Emoji (should only see 'test')",
|
||||
render: function() {
|
||||
return <Text>{'test🙃'.substring(0, 5)}</Text>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Text metrics',
|
||||
render: function() {
|
||||
|
||||
@@ -212,7 +212,11 @@ class SecureEntryExample extends React.Component<$FlowFixMeProps, any> {
|
||||
* comment and run Flow. */
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {text: ''};
|
||||
this.state = {
|
||||
text: '',
|
||||
password: '',
|
||||
isSecureTextEntry: true,
|
||||
};
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
@@ -225,6 +229,26 @@ class SecureEntryExample extends React.Component<$FlowFixMeProps, any> {
|
||||
value={this.state.text}
|
||||
/>
|
||||
<Text>Current text is: {this.state.text}</Text>
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
}}>
|
||||
<TextInput
|
||||
style={styles.default}
|
||||
defaultValue="cde"
|
||||
onChangeText={text => this.setState({password: text})}
|
||||
secureTextEntry={this.state.isSecureTextEntry}
|
||||
value={this.state.password}
|
||||
/>
|
||||
<Switch
|
||||
onValueChange={value => {
|
||||
this.setState({isSecureTextEntry: value});
|
||||
}}
|
||||
style={{marginLeft: 4}}
|
||||
value={this.state.isSecureTextEntry}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -1085,4 +1109,19 @@ exports.examples = [
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Text Content Type',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<WithLabel label="emailAddress">
|
||||
<TextInput textContentType="emailAddress" style={styles.default} />
|
||||
</WithLabel>
|
||||
<WithLabel label="name">
|
||||
<TextInput textContentType="name" style={styles.default} />
|
||||
</WithLabel>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@@ -66,6 +66,7 @@ Pod::Spec.new do |s|
|
||||
"React/Views/RCTSlider*",
|
||||
"React/Views/RCTSwitch*",
|
||||
"React/Views/RCTWebView*"
|
||||
ss.compiler_flags = folly_compiler_flags
|
||||
ss.header_dir = "React"
|
||||
ss.framework = "JavaScriptCore"
|
||||
ss.libraries = "stdc++"
|
||||
@@ -116,6 +117,8 @@ Pod::Spec.new do |s|
|
||||
ss.dependency "React/cxxreact"
|
||||
ss.dependency "React/jsi"
|
||||
ss.dependency "Folly", folly_version
|
||||
ss.dependency "DoubleConversion"
|
||||
ss.dependency "glog"
|
||||
ss.compiler_flags = folly_compiler_flags
|
||||
ss.source_files = "ReactCommon/jsiexecutor/jsireact/*.{cpp,h}"
|
||||
ss.private_header_files = "ReactCommon/jsiexecutor/jsireact/*.h"
|
||||
@@ -125,6 +128,8 @@ Pod::Spec.new do |s|
|
||||
|
||||
s.subspec "jsi" do |ss|
|
||||
ss.dependency "Folly", folly_version
|
||||
ss.dependency "DoubleConversion"
|
||||
ss.dependency "glog"
|
||||
ss.compiler_flags = folly_compiler_flags
|
||||
ss.source_files = "ReactCommon/jsi/*.{cpp,h}"
|
||||
ss.private_header_files = "ReactCommon/jsi/*.h"
|
||||
@@ -142,6 +147,8 @@ Pod::Spec.new do |s|
|
||||
ss.dependency "React/jsinspector"
|
||||
ss.dependency "boost-for-react-native", "1.63.0"
|
||||
ss.dependency "Folly", folly_version
|
||||
ss.dependency "DoubleConversion"
|
||||
ss.dependency "glog"
|
||||
ss.compiler_flags = folly_compiler_flags
|
||||
ss.source_files = "ReactCommon/cxxreact/*.{cpp,h}"
|
||||
ss.exclude_files = "ReactCommon/cxxreact/SampleCxxModule.*"
|
||||
|
||||
@@ -292,6 +292,8 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
||||
* Any thread
|
||||
*/
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
// WARNING: Invalidation is async, so it may not finish before re-setting up the bridge,
|
||||
// causing some issues. TODO: revisit this post-Fabric/TurboModule.
|
||||
[self invalidate];
|
||||
// Reload is a special case, do not preserve launchOptions and treat reload as a fresh start
|
||||
self->_launchOptions = nil;
|
||||
|
||||
@@ -73,6 +73,17 @@ RCT_EXTERN void RCTRegisterModule(Class); \
|
||||
+ (NSString *)moduleName { return @#js_name; } \
|
||||
+ (void)load { RCTRegisterModule(self); }
|
||||
|
||||
/**
|
||||
* Same as RCT_EXPORT_MODULE, but uses __attribute__((constructor)) for module
|
||||
* registration. Useful for registering swift classes that forbids use of load
|
||||
* Used in RCT_EXTERN_REMAP_MODULE
|
||||
*/
|
||||
#define RCT_EXPORT_MODULE_NO_LOAD(js_name, objc_name) \
|
||||
RCT_EXTERN void RCTRegisterModule(Class); \
|
||||
+ (NSString *)moduleName { return @#js_name; } \
|
||||
__attribute__((constructor)) static void \
|
||||
RCT_CONCAT(initialize_, objc_name)() { RCTRegisterModule([objc_name class]); }
|
||||
|
||||
/**
|
||||
* To improve startup performance users may want to generate their module lists
|
||||
* at build time and hook the delegate to merge with the runtime list. This
|
||||
@@ -250,7 +261,7 @@ RCT_EXTERN void RCTRegisterModule(Class); \
|
||||
@interface objc_name (RCTExternModule) <RCTBridgeModule> \
|
||||
@end \
|
||||
@implementation objc_name (RCTExternModule) \
|
||||
RCT_EXPORT_MODULE(js_name)
|
||||
RCT_EXPORT_MODULE_NO_LOAD(js_name, objc_name)
|
||||
|
||||
/**
|
||||
* Use this macro in accordance with RCT_EXTERN_MODULE to export methods
|
||||
|
||||
+10
-1
@@ -53,12 +53,21 @@ RCT_NUMBER_CONVERTER(NSUInteger, unsignedIntegerValue)
|
||||
|
||||
RCT_JSON_CONVERTER(NSArray)
|
||||
RCT_JSON_CONVERTER(NSDictionary)
|
||||
RCT_JSON_CONVERTER(NSString)
|
||||
RCT_JSON_CONVERTER(NSNumber)
|
||||
|
||||
RCT_CUSTOM_CONVERTER(NSSet *, NSSet, [NSSet setWithArray:json])
|
||||
RCT_CUSTOM_CONVERTER(NSData *, NSData, [json dataUsingEncoding:NSUTF8StringEncoding])
|
||||
|
||||
+ (NSString *)NSString:(id)json
|
||||
{
|
||||
if ([json isKindOfClass:NSString.class]) {
|
||||
return json;
|
||||
} else if (json && json != (id)kCFNull) {
|
||||
return [NSString stringWithFormat:@"%@",json];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (NSIndexSet *)NSIndexSet:(id)json
|
||||
{
|
||||
json = [self NSNumberArray:json];
|
||||
|
||||
@@ -708,13 +708,11 @@ UIImage *__nullable RCTImageFromLocalAssetURL(NSURL *imageURL)
|
||||
|
||||
if (!image) {
|
||||
// Attempt to load from the file system
|
||||
NSData *fileData;
|
||||
if (imageURL.pathExtension.length == 0) {
|
||||
fileData = [NSData dataWithContentsOfURL:[imageURL URLByAppendingPathExtension:@"png"]];
|
||||
} else {
|
||||
fileData = [NSData dataWithContentsOfURL:imageURL];
|
||||
NSString *filePath = [NSString stringWithUTF8String:[imageURL fileSystemRepresentation]];
|
||||
if (filePath.pathExtension.length == 0) {
|
||||
filePath = [filePath stringByAppendingPathExtension:@"png"];
|
||||
}
|
||||
image = [UIImage imageWithData:fileData];
|
||||
image = [UIImage imageWithContentsOfFile:filePath];
|
||||
}
|
||||
|
||||
if (!image && !bundle) {
|
||||
|
||||
@@ -21,8 +21,8 @@ static void __makeVersion()
|
||||
{
|
||||
__rnVersion = @{
|
||||
RCTVersionMajor: @(0),
|
||||
RCTVersionMinor: @(0),
|
||||
RCTVersionPatch: @(0),
|
||||
RCTVersionMinor: @(59),
|
||||
RCTVersionPatch: @(8),
|
||||
RCTVersionPrerelease: [NSNull null],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -357,7 +357,9 @@ struct RCTInstanceCallback : public InstanceCallback {
|
||||
dispatch_group_leave(prepareBridge);
|
||||
} onProgress:^(RCTLoadingProgress *progressData) {
|
||||
#if RCT_DEV && __has_include("RCTDevLoadingView.h")
|
||||
RCTDevLoadingView *loadingView = [weakSelf moduleForClass:[RCTDevLoadingView class]];
|
||||
// Note: RCTDevLoadingView should have been loaded at this point, so no need to allow lazy loading.
|
||||
RCTDevLoadingView *loadingView = [weakSelf moduleForName:RCTBridgeModuleNameForClass([RCTDevLoadingView class])
|
||||
lazilyLoadIfNecessary:NO];
|
||||
[loadingView updateProgress:progressData];
|
||||
#endif
|
||||
}];
|
||||
|
||||
@@ -201,7 +201,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
||||
[self abort:@"Websocket exception"
|
||||
withCause:error];
|
||||
}
|
||||
if (!_closed) {
|
||||
if (!_closed && [error code] != ECONNREFUSED) {
|
||||
[self reconnect];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
@implementation RCTDeviceInfo {
|
||||
#if !TARGET_OS_TV
|
||||
UIInterfaceOrientation _currentInterfaceOrientation;
|
||||
NSDictionary *_currentInterfaceDimensions;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -48,6 +49,13 @@ RCT_EXPORT_MODULE()
|
||||
selector:@selector(interfaceOrientationDidChange)
|
||||
name:UIApplicationDidChangeStatusBarOrientationNotification
|
||||
object:nil];
|
||||
|
||||
_currentInterfaceDimensions = RCTExportedDimensions(_bridge);
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(interfaceFrameDidChange)
|
||||
name:UIApplicationDidBecomeActiveNotification
|
||||
object:nil];
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -77,16 +85,23 @@ static NSDictionary *RCTExportedDimensions(RCTBridge *bridge)
|
||||
RCTAssertMainQueue();
|
||||
|
||||
RCTDimensions dimensions = RCTGetDimensions(bridge.accessibilityManager.multiplier);
|
||||
typeof (dimensions.window) window = dimensions.window; // Window and Screen are considered equal for iOS.
|
||||
NSDictionary<NSString *, NSNumber *> *dims = @{
|
||||
typeof (dimensions.window) window = dimensions.window;
|
||||
NSDictionary<NSString *, NSNumber *> *dimsWindow = @{
|
||||
@"width": @(window.width),
|
||||
@"height": @(window.height),
|
||||
@"scale": @(window.scale),
|
||||
@"fontScale": @(window.fontScale)
|
||||
};
|
||||
typeof (dimensions.screen) screen = dimensions.screen;
|
||||
NSDictionary<NSString *, NSNumber *> *dimsScreen = @{
|
||||
@"width": @(screen.width),
|
||||
@"height": @(screen.height),
|
||||
@"scale": @(screen.scale),
|
||||
@"fontScale": @(screen.fontScale)
|
||||
};
|
||||
return @{
|
||||
@"window": dims,
|
||||
@"screen": dims
|
||||
@"window": dimsWindow,
|
||||
@"screen": dimsScreen
|
||||
};
|
||||
}
|
||||
|
||||
@@ -163,6 +178,31 @@ static NSDictionary *RCTExportedDimensions(RCTBridge *bridge)
|
||||
_currentInterfaceOrientation = nextOrientation;
|
||||
}
|
||||
|
||||
|
||||
- (void)interfaceFrameDidChange
|
||||
{
|
||||
__weak typeof(self) weakSelf = self;
|
||||
RCTExecuteOnMainQueue(^{
|
||||
[weakSelf _interfaceFrameDidChange];
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
- (void)_interfaceFrameDidChange
|
||||
{
|
||||
NSDictionary *nextInterfaceDimensions = RCTExportedDimensions(_bridge);
|
||||
|
||||
if (!([nextInterfaceDimensions isEqual:_currentInterfaceDimensions])) {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
[_bridge.eventDispatcher sendDeviceEventWithName:@"didUpdateDimensions"
|
||||
body:nextInterfaceDimensions];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
_currentInterfaceDimensions = nextInterfaceDimensions;
|
||||
}
|
||||
|
||||
#endif // TARGET_OS_TV
|
||||
|
||||
|
||||
|
||||
@@ -9,13 +9,15 @@
|
||||
|
||||
#import <React/RCTBridgeModule.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol RCTExceptionsManagerDelegate <NSObject>
|
||||
|
||||
- (void)handleSoftJSExceptionWithMessage:(NSString *)message stack:(NSArray *)stack exceptionId:(NSNumber *)exceptionId;
|
||||
- (void)handleFatalJSExceptionWithMessage:(NSString *)message stack:(NSArray *)stack exceptionId:(NSNumber *)exceptionId;
|
||||
- (void)handleSoftJSExceptionWithMessage:(nullable NSString *)message stack:(nullable NSArray *)stack exceptionId:(NSNumber *)exceptionId;
|
||||
- (void)handleFatalJSExceptionWithMessage:(nullable NSString *)message stack:(nullable NSArray *)stack exceptionId:(NSNumber *)exceptionId;
|
||||
|
||||
@optional
|
||||
- (void)updateJSExceptionWithMessage:(NSString *)message stack:(NSArray *)stack exceptionId:(NSNumber *)exceptionId;
|
||||
- (void)updateJSExceptionWithMessage:(nullable NSString *)message stack:(nullable NSArray *)stack exceptionId:(NSNumber *)exceptionId;
|
||||
|
||||
@end
|
||||
|
||||
@@ -23,11 +25,13 @@
|
||||
|
||||
- (instancetype)initWithDelegate:(id<RCTExceptionsManagerDelegate>)delegate;
|
||||
|
||||
- (void)reportSoftException:(NSString *)message stack:(NSArray<NSDictionary *> *)stack exceptionId:(nonnull NSNumber *)exceptionId;
|
||||
- (void)reportFatalException:(NSString *)message stack:(NSArray<NSDictionary *> *)stack exceptionId:(nonnull NSNumber *)exceptionId;
|
||||
- (void)reportSoftException:(nullable NSString *)message stack:(nullable NSArray<NSDictionary *> *)stack exceptionId:(NSNumber *)exceptionId;
|
||||
- (void)reportFatalException:(nullable NSString *)message stack:(nullable NSArray<NSDictionary *> *)stack exceptionId:(NSNumber *)exceptionId;
|
||||
|
||||
@property (nonatomic, weak) id<RCTExceptionsManagerDelegate> delegate;
|
||||
|
||||
@property (nonatomic, assign) NSUInteger maxReloadAttempts;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -156,6 +156,9 @@ RCT_EXPORT_MODULE()
|
||||
if (!_devMenuItem) {
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
__weak RCTDevSettings *devSettings = self.bridge.devSettings;
|
||||
if (devSettings.isPerfMonitorShown) {
|
||||
[weakSelf show];
|
||||
}
|
||||
_devMenuItem =
|
||||
[RCTDevMenuItem buttonItemWithTitleBlock:^NSString *{
|
||||
return (devSettings.isPerfMonitorShown) ?
|
||||
|
||||
@@ -985,7 +985,6 @@
|
||||
59EDBCC61FDF4E55003573DE /* (null) in Copy Headers */ = {isa = PBXBuildFile; };
|
||||
59EDBCC71FDF4E55003573DE /* RCTScrollView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 59EDBCA31FDF4E0C003573DE /* RCTScrollView.h */; };
|
||||
59EDBCC81FDF4E55003573DE /* RCTScrollViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 59EDBCA51FDF4E0C003573DE /* RCTScrollViewManager.h */; };
|
||||
5CE2080220772F7D009A43B3 /* YGConfig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5CE2080020772F7C009A43B3 /* YGConfig.cpp */; };
|
||||
5CE2080320772F7D009A43B3 /* YGConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CE2080120772F7C009A43B3 /* YGConfig.h */; };
|
||||
657734841EE834C900A0E9EA /* RCTInspectorDevServerHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 657734821EE834C900A0E9EA /* RCTInspectorDevServerHelper.h */; };
|
||||
657734851EE834C900A0E9EA /* RCTInspectorDevServerHelper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 657734831EE834C900A0E9EA /* RCTInspectorDevServerHelper.mm */; };
|
||||
@@ -1047,13 +1046,11 @@
|
||||
A2440AA21DF8D854006E7BFC /* RCTReloadCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = A2440AA01DF8D854006E7BFC /* RCTReloadCommand.h */; };
|
||||
A2440AA31DF8D854006E7BFC /* RCTReloadCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = A2440AA11DF8D854006E7BFC /* RCTReloadCommand.m */; };
|
||||
A2440AA41DF8D865006E7BFC /* RCTReloadCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = A2440AA01DF8D854006E7BFC /* RCTReloadCommand.h */; };
|
||||
AC4A6AF921FB4EA900FBEC39 /* YGMarker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AC4A6AF821FB4EA900FBEC39 /* YGMarker.cpp */; };
|
||||
AC4A6AFA21FB4EBF00FBEC39 /* YGMarker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AC4A6AF821FB4EA900FBEC39 /* YGMarker.cpp */; };
|
||||
AC4A6AFB21FB4ECA00FBEC39 /* YGMarker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AC4A6AF821FB4EA900FBEC39 /* YGMarker.cpp */; };
|
||||
AC52CEDE21FB3FF9003C6BEC /* instrumentation.h in Headers */ = {isa = PBXBuildFile; fileRef = AC52CEDD21FB3FF9003C6BEC /* instrumentation.h */; };
|
||||
AC52CEDF21FB401D003C6BEC /* instrumentation.h in Headers */ = {isa = PBXBuildFile; fileRef = AC52CEDD21FB3FF9003C6BEC /* instrumentation.h */; };
|
||||
AC52CEE021FB403B003C6BEC /* instrumentation.h in Headers */ = {isa = PBXBuildFile; fileRef = AC52CEDD21FB3FF9003C6BEC /* instrumentation.h */; };
|
||||
AC6B69E321B1467C00B2B68A /* YGValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AC6B69E121B1467C00B2B68A /* YGValue.cpp */; };
|
||||
AC6B69E421B1467C00B2B68A /* YGValue.h in Headers */ = {isa = PBXBuildFile; fileRef = AC6B69E221B1467C00B2B68A /* YGValue.h */; };
|
||||
AC6B69E521B1469A00B2B68A /* YGValue.h in Headers */ = {isa = PBXBuildFile; fileRef = AC6B69E221B1467C00B2B68A /* YGValue.h */; };
|
||||
AC6B69E621B146A500B2B68A /* YGValue.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = AC6B69E221B1467C00B2B68A /* YGValue.h */; };
|
||||
@@ -4427,7 +4424,6 @@
|
||||
352DCFF01D19F4C20056D623 /* RCTI18nUtil.m in Sources */,
|
||||
66CD94B71F1045E700CB3C7C /* RCTMaskedViewManager.m in Sources */,
|
||||
008341F61D1DB34400876D9A /* RCTJSStackFrame.m in Sources */,
|
||||
AC4A6AF921FB4EA900FBEC39 /* YGMarker.cpp in Sources */,
|
||||
13134C961E296B2A00B9F3CB /* RCTObjcExecutor.mm in Sources */,
|
||||
59D031FB1F8353D3008361F0 /* RCTSafeAreaViewManager.m in Sources */,
|
||||
83CBBACC1A6023D300E9B192 /* RCTConvert.m in Sources */,
|
||||
@@ -4459,7 +4455,6 @@
|
||||
13134C8E1E296B2A00B9F3CB /* RCTMessageThread.mm in Sources */,
|
||||
599FAA381FB274980058CCF6 /* RCTSurface.mm in Sources */,
|
||||
59D031EF1F8353D3008361F0 /* RCTSafeAreaShadowView.m in Sources */,
|
||||
AC6B69E321B1467C00B2B68A /* YGValue.cpp in Sources */,
|
||||
3D1E68DB1CABD13900DD7465 /* RCTDisplayLink.m in Sources */,
|
||||
14F3620E1AABD06A001CE568 /* RCTSwitchManager.m in Sources */,
|
||||
13B080201A69489C00A75B9A /* RCTActivityIndicatorViewManager.m in Sources */,
|
||||
@@ -4516,7 +4511,6 @@
|
||||
13A1F71E1A75392D00D3D453 /* RCTKeyCommands.m in Sources */,
|
||||
83CBBA531A601E3B00E9B192 /* RCTUtils.m in Sources */,
|
||||
130443C61E401A8C00D93A67 /* RCTConvert+Transform.m in Sources */,
|
||||
5CE2080220772F7D009A43B3 /* YGConfig.cpp in Sources */,
|
||||
191E3EC11C29DC3800C180A6 /* RCTRefreshControl.m in Sources */,
|
||||
3DCE532B1FEAB23100613583 /* RCTDatePickerManager.m in Sources */,
|
||||
13C156051AB1A2840079392D /* RCTWebView.m in Sources */,
|
||||
|
||||
@@ -7,19 +7,32 @@
|
||||
|
||||
#import "RCTUIUtils.h"
|
||||
|
||||
#import "RCTUtils.h"
|
||||
|
||||
RCTDimensions RCTGetDimensions(CGFloat fontScale)
|
||||
{
|
||||
UIScreen *mainScreen = UIScreen.mainScreen;
|
||||
CGSize screenSize = mainScreen.bounds.size;
|
||||
|
||||
UIView *mainWindow;
|
||||
mainWindow = RCTKeyWindow();
|
||||
CGSize windowSize = mainWindow.bounds.size;
|
||||
|
||||
RCTDimensions result;
|
||||
typeof (result.window) dims = {
|
||||
typeof (result.screen) dimsScreen = {
|
||||
.width = screenSize.width,
|
||||
.height = screenSize.height,
|
||||
.scale = mainScreen.scale,
|
||||
.fontScale = fontScale
|
||||
};
|
||||
result.window = dims;
|
||||
result.screen = dims;
|
||||
typeof (result.window) dimsWindow = {
|
||||
.width = windowSize.width,
|
||||
.height = windowSize.height,
|
||||
.scale = mainScreen.scale,
|
||||
.fontScale = fontScale
|
||||
};
|
||||
result.screen = dimsScreen;
|
||||
result.window = dimsWindow;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -224,13 +224,15 @@ static UIImage *RCTGetSolidBorderImage(RCTCornerRadii cornerRadii,
|
||||
borderInsets.right + MAX(cornerInsets.bottomRight.width, cornerInsets.topRight.width)
|
||||
};
|
||||
|
||||
// Asymmetrical edgeInsets cause strange artifacting on iOS 10 and earlier.
|
||||
edgeInsets = (UIEdgeInsets){
|
||||
MAX(edgeInsets.top, edgeInsets.bottom),
|
||||
MAX(edgeInsets.left, edgeInsets.right),
|
||||
MAX(edgeInsets.top, edgeInsets.bottom),
|
||||
MAX(edgeInsets.left, edgeInsets.right),
|
||||
};
|
||||
if (hasCornerRadii) {
|
||||
// Asymmetrical edgeInsets cause strange artifacting on iOS 10 and earlier.
|
||||
edgeInsets = (UIEdgeInsets){
|
||||
MAX(edgeInsets.top, edgeInsets.bottom),
|
||||
MAX(edgeInsets.left, edgeInsets.right),
|
||||
MAX(edgeInsets.top, edgeInsets.bottom),
|
||||
MAX(edgeInsets.left, edgeInsets.right),
|
||||
};
|
||||
}
|
||||
|
||||
const CGSize size = makeStretchable ? (CGSize){
|
||||
// 1pt for the middle stretchable area along each axis
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
@implementation RCTRefreshControl {
|
||||
BOOL _isInitialRender;
|
||||
BOOL _currentRefreshingState;
|
||||
UInt64 _currentRefreshingStateClock;
|
||||
UInt64 _currentRefreshingStateTimestamp;
|
||||
BOOL _refreshingProgrammatically;
|
||||
NSString *_title;
|
||||
UIColor *_titleColor;
|
||||
@@ -21,6 +23,8 @@
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
[self addTarget:self action:@selector(refreshControlValueChanged) forControlEvents:UIControlEventValueChanged];
|
||||
_currentRefreshingStateClock = 1;
|
||||
_currentRefreshingStateTimestamp = 0;
|
||||
_isInitialRender = true;
|
||||
_currentRefreshingState = false;
|
||||
}
|
||||
@@ -49,6 +53,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
|
||||
|
||||
- (void)beginRefreshingProgrammatically
|
||||
{
|
||||
UInt64 beginRefreshingTimestamp = _currentRefreshingStateTimestamp;
|
||||
_refreshingProgrammatically = YES;
|
||||
// When using begin refreshing we need to adjust the ScrollView content offset manually.
|
||||
UIScrollView *scrollView = (UIScrollView *)self.superview;
|
||||
@@ -62,7 +67,10 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
|
||||
animations:^(void) {
|
||||
[scrollView setContentOffset:offset];
|
||||
} completion:^(__unused BOOL finished) {
|
||||
[super beginRefreshing];
|
||||
if(beginRefreshingTimestamp == self->_currentRefreshingStateTimestamp) {
|
||||
[super beginRefreshing];
|
||||
[self setCurrentRefreshingState:super.refreshing];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -72,6 +80,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
|
||||
// endRefreshing otherwise the next pull to refresh will not work properly.
|
||||
UIScrollView *scrollView = (UIScrollView *)self.superview;
|
||||
if (_refreshingProgrammatically && scrollView.contentOffset.y < 0) {
|
||||
UInt64 endRefreshingTimestamp = _currentRefreshingStateTimestamp;
|
||||
CGPoint offset = {scrollView.contentOffset.x, 0};
|
||||
[UIView animateWithDuration:0.25
|
||||
delay:0
|
||||
@@ -79,7 +88,10 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
|
||||
animations:^(void) {
|
||||
[scrollView setContentOffset:offset];
|
||||
} completion:^(__unused BOOL finished) {
|
||||
[super endRefreshing];
|
||||
if(endRefreshingTimestamp == self->_currentRefreshingStateTimestamp) {
|
||||
[super endRefreshing];
|
||||
[self setCurrentRefreshingState:super.refreshing];
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
[super endRefreshing];
|
||||
@@ -120,7 +132,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
|
||||
- (void)setRefreshing:(BOOL)refreshing
|
||||
{
|
||||
if (_currentRefreshingState != refreshing) {
|
||||
_currentRefreshingState = refreshing;
|
||||
[self setCurrentRefreshingState:refreshing];
|
||||
|
||||
if (refreshing) {
|
||||
if (!_isInitialRender) {
|
||||
@@ -132,9 +144,15 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setCurrentRefreshingState:(BOOL)refreshing
|
||||
{
|
||||
_currentRefreshingState = refreshing;
|
||||
_currentRefreshingStateTimestamp = _currentRefreshingStateClock++;
|
||||
}
|
||||
|
||||
- (void)refreshControlValueChanged
|
||||
{
|
||||
_currentRefreshingState = super.refreshing;
|
||||
[self setCurrentRefreshingState:super.refreshing];
|
||||
_refreshingProgrammatically = NO;
|
||||
|
||||
if (_onRefresh) {
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
@property (nonatomic, assign) NSTimeInterval scrollEventThrottle;
|
||||
@property (nonatomic, assign) BOOL centerContent;
|
||||
@property (nonatomic, copy) NSDictionary *maintainVisibleContentPosition;
|
||||
@property (nonatomic, assign) BOOL scrollToOverflowEnabled;
|
||||
@property (nonatomic, assign) int snapToInterval;
|
||||
@property (nonatomic, copy) NSArray<NSNumber *> *snapToOffsets;
|
||||
@property (nonatomic, assign) BOOL snapToStart;
|
||||
|
||||
@@ -588,8 +588,19 @@ static inline void RCTApplyTransformationAccordingLayoutDirection(UIView *view,
|
||||
- (void)scrollToOffset:(CGPoint)offset animated:(BOOL)animated
|
||||
{
|
||||
if (!CGPointEqualToPoint(_scrollView.contentOffset, offset)) {
|
||||
CGRect maxRect = CGRectMake(fmin(-_scrollView.contentInset.left, 0),
|
||||
fmin(-_scrollView.contentInset.top, 0),
|
||||
fmax(_scrollView.contentSize.width - _scrollView.bounds.size.width + _scrollView.contentInset.right + fmax(_scrollView.contentInset.left, 0), 0.01),
|
||||
fmax(_scrollView.contentSize.height - _scrollView.bounds.size.height + _scrollView.contentInset.bottom + fmax(_scrollView.contentInset.top, 0), 0.01)); // Make width and height greater than 0
|
||||
// Ensure at least one scroll event will fire
|
||||
_allowNextScrollNoMatterWhat = YES;
|
||||
if (!CGRectContainsPoint(maxRect, offset) && !self.scrollToOverflowEnabled) {
|
||||
CGFloat x = fmax(offset.x, CGRectGetMinX(maxRect));
|
||||
x = fmin(x, CGRectGetMaxX(maxRect));
|
||||
CGFloat y = fmax(offset.y, CGRectGetMinY(maxRect));
|
||||
y = fmin(y, CGRectGetMaxY(maxRect));
|
||||
offset = CGPointMake(x, y);
|
||||
}
|
||||
[_scrollView setContentOffset:offset animated:animated];
|
||||
}
|
||||
}
|
||||
@@ -665,16 +676,19 @@ RCT_SCROLL_EVENT_HANDLER(scrollViewDidScrollToTop, onScrollToTop)
|
||||
|
||||
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
|
||||
{
|
||||
[self updateClippedSubviews];
|
||||
NSTimeInterval now = CACurrentMediaTime();
|
||||
[self updateClippedSubviews];
|
||||
/**
|
||||
* TODO: this logic looks wrong, and it may be because it is. Currently, if _scrollEventThrottle
|
||||
* is set to zero (the default), the "didScroll" event is only sent once per scroll, instead of repeatedly
|
||||
* while scrolling as expected. However, if you "fix" that bug, ScrollView will generate repeated
|
||||
* warnings, and behave strangely (ListView works fine however), so don't fix it unless you fix that too!
|
||||
*
|
||||
* We limit the delta to 17ms so that small throttles intended to enable 60fps updates will not
|
||||
* inadvertantly filter out any scroll events.
|
||||
*/
|
||||
if (_allowNextScrollNoMatterWhat ||
|
||||
(_scrollEventThrottle > 0 && _scrollEventThrottle < (now - _lastScrollDispatchTime))) {
|
||||
(_scrollEventThrottle > 0 && _scrollEventThrottle < MAX(17, now - _lastScrollDispatchTime))) {
|
||||
|
||||
if (_DEPRECATED_sendUpdatedChildFrames) {
|
||||
// Calculate changed frames
|
||||
|
||||
@@ -80,6 +80,7 @@ RCT_EXPORT_VIEW_PROPERTY(scrollEventThrottle, NSTimeInterval)
|
||||
RCT_EXPORT_VIEW_PROPERTY(zoomScale, CGFloat)
|
||||
RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets)
|
||||
RCT_EXPORT_VIEW_PROPERTY(scrollIndicatorInsets, UIEdgeInsets)
|
||||
RCT_EXPORT_VIEW_PROPERTY(scrollToOverflowEnabled, BOOL)
|
||||
RCT_EXPORT_VIEW_PROPERTY(snapToInterval, int)
|
||||
RCT_EXPORT_VIEW_PROPERTY(snapToOffsets, NSArray<NSNumber *>)
|
||||
RCT_EXPORT_VIEW_PROPERTY(snapToStart, BOOL)
|
||||
|
||||
@@ -274,7 +274,7 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion(16)
|
||||
targetSdkVersion(27)
|
||||
targetSdkVersion(28)
|
||||
versionCode(1)
|
||||
versionName("1.0")
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
VERSION_NAME=1000.0.0-master
|
||||
VERSION_NAME=0.59.8
|
||||
GROUP=com.facebook.react
|
||||
|
||||
POM_NAME=ReactNative
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.facebook.react">
|
||||
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
||||
|
||||
<application />
|
||||
|
||||
</manifest>
|
||||
|
||||
@@ -34,10 +34,12 @@ public interface ReactPackage {
|
||||
* @param reactContext react application context that can be used to create modules
|
||||
* @return list of native modules to register with the newly created catalyst instance
|
||||
*/
|
||||
@Nonnull
|
||||
List<NativeModule> createNativeModules(@Nonnull ReactApplicationContext reactContext);
|
||||
|
||||
/**
|
||||
* @return a list of view managers that should be registered with {@link UIManagerModule}
|
||||
*/
|
||||
@Nonnull
|
||||
List<ViewManager> createViewManagers(@Nonnull ReactApplicationContext reactContext);
|
||||
}
|
||||
|
||||
+2
-1
@@ -7,6 +7,7 @@
|
||||
|
||||
package com.facebook.react.modules.core;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import android.net.Uri;
|
||||
@@ -27,7 +28,7 @@ import com.facebook.react.module.annotations.ReactModule;
|
||||
public class DeviceEventManagerModule extends ReactContextBaseJavaModule {
|
||||
public static final String NAME = "DeviceEventManager";
|
||||
public interface RCTDeviceEventEmitter extends JavaScriptModule {
|
||||
void emit(String eventName, @Nullable Object data);
|
||||
void emit(@Nonnull String eventName, @Nullable Object data);
|
||||
}
|
||||
|
||||
private final Runnable mInvokeDefaultBackPressRunnable;
|
||||
|
||||
@@ -8,6 +8,7 @@ rn_android_library(
|
||||
],
|
||||
deps = [
|
||||
react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"),
|
||||
react_native_dep("third-party/android/support/v4:lib-support-v4"),
|
||||
react_native_dep("third-party/java/infer-annotations:infer-annotations"),
|
||||
react_native_dep("third-party/java/jsr-305:jsr-305"),
|
||||
react_native_target("java/com/facebook/react/bridge:bridge"),
|
||||
|
||||
@@ -9,6 +9,7 @@ package com.facebook.react.modules.location;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.location.Location;
|
||||
import android.location.LocationListener;
|
||||
import android.location.LocationManager;
|
||||
@@ -16,6 +17,7 @@ import android.location.LocationProvider;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import com.facebook.common.logging.FLog;
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.Callback;
|
||||
@@ -193,7 +195,7 @@ public class LocationModule extends ReactContextBaseJavaModule {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getValidProvider(LocationManager locationManager, boolean highAccuracy) {
|
||||
private String getValidProvider(LocationManager locationManager, boolean highAccuracy) {
|
||||
String provider =
|
||||
highAccuracy ? LocationManager.GPS_PROVIDER : LocationManager.NETWORK_PROVIDER;
|
||||
if (!locationManager.isProviderEnabled(provider)) {
|
||||
@@ -204,6 +206,11 @@ public class LocationModule extends ReactContextBaseJavaModule {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// If it's an enabled provider, but we don't have permissions, ignore it
|
||||
int finePermission = ContextCompat.checkSelfPermission(getReactApplicationContext(), android.Manifest.permission.ACCESS_FINE_LOCATION);
|
||||
if (provider.equals(LocationManager.GPS_PROVIDER) && finePermission != PackageManager.PERMISSION_GRANTED) {
|
||||
return null;
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
|
||||
|
||||
+54
-17
@@ -56,7 +56,10 @@ public class ForwardingCookieHandler extends CookieHandler {
|
||||
@Override
|
||||
public Map<String, List<String>> get(URI uri, Map<String, List<String>> headers)
|
||||
throws IOException {
|
||||
String cookies = getCookieManager().getCookie(uri.toString());
|
||||
CookieManager cookieManager = getCookieManager();
|
||||
if (cookieManager == null) return Collections.emptyMap();
|
||||
|
||||
String cookies = cookieManager.getCookie(uri.toString());
|
||||
if (TextUtils.isEmpty(cookies)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
@@ -80,7 +83,10 @@ public class ForwardingCookieHandler extends CookieHandler {
|
||||
new GuardedResultAsyncTask<Boolean>(mContext) {
|
||||
@Override
|
||||
protected Boolean doInBackgroundGuarded() {
|
||||
getCookieManager().removeAllCookie();
|
||||
CookieManager cookieManager = getCookieManager();
|
||||
if (cookieManager != null) {
|
||||
cookieManager.removeAllCookie();
|
||||
}
|
||||
mCookieSaver.onCookiesModified();
|
||||
return true;
|
||||
}
|
||||
@@ -96,31 +102,40 @@ public class ForwardingCookieHandler extends CookieHandler {
|
||||
}
|
||||
|
||||
private void clearCookiesAsync(final Callback callback) {
|
||||
getCookieManager().removeAllCookies(
|
||||
new ValueCallback<Boolean>() {
|
||||
@Override
|
||||
public void onReceiveValue(Boolean value) {
|
||||
mCookieSaver.onCookiesModified();
|
||||
callback.invoke(value);
|
||||
}
|
||||
});
|
||||
CookieManager cookieManager = getCookieManager();
|
||||
if (cookieManager != null) {
|
||||
cookieManager.removeAllCookies(
|
||||
new ValueCallback<Boolean>() {
|
||||
@Override
|
||||
public void onReceiveValue(Boolean value) {
|
||||
mCookieSaver.onCookiesModified();
|
||||
callback.invoke(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
if (USES_LEGACY_STORE) {
|
||||
getCookieManager().removeExpiredCookie();
|
||||
CookieManager cookieManager = getCookieManager();
|
||||
if (cookieManager != null) {
|
||||
cookieManager.removeExpiredCookie();
|
||||
}
|
||||
mCookieSaver.persistCookies();
|
||||
}
|
||||
}
|
||||
|
||||
private void addCookies(final String url, final List<String> cookies) {
|
||||
final CookieManager cookieManager = getCookieManager();
|
||||
if (cookieManager == null) return;
|
||||
|
||||
if (USES_LEGACY_STORE) {
|
||||
runInBackground(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (String cookie : cookies) {
|
||||
getCookieManager().setCookie(url, cookie);
|
||||
cookieManager.setCookie(url, cookie);
|
||||
}
|
||||
mCookieSaver.onCookiesModified();
|
||||
}
|
||||
@@ -129,14 +144,17 @@ public class ForwardingCookieHandler extends CookieHandler {
|
||||
for (String cookie : cookies) {
|
||||
addCookieAsync(url, cookie);
|
||||
}
|
||||
getCookieManager().flush();
|
||||
cookieManager.flush();
|
||||
mCookieSaver.onCookiesModified();
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(21)
|
||||
private void addCookieAsync(String url, String cookie) {
|
||||
getCookieManager().setCookie(url, cookie, null);
|
||||
CookieManager cookieManager = getCookieManager();
|
||||
if (cookieManager != null) {
|
||||
cookieManager.setCookie(url, cookie, null);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isCookieHeader(String name) {
|
||||
@@ -156,10 +174,26 @@ public class ForwardingCookieHandler extends CookieHandler {
|
||||
* Instantiating CookieManager in KitKat+ will load the Chromium task taking a 100ish ms so we
|
||||
* do it lazily to make sure it's done on a background thread as needed.
|
||||
*/
|
||||
private CookieManager getCookieManager() {
|
||||
private @Nullable CookieManager getCookieManager() {
|
||||
if (mCookieManager == null) {
|
||||
possiblyWorkaroundSyncManager(mContext);
|
||||
mCookieManager = CookieManager.getInstance();
|
||||
try {
|
||||
mCookieManager = CookieManager.getInstance();
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=559720
|
||||
return null;
|
||||
} catch (Exception exception) {
|
||||
String message = exception.getMessage();
|
||||
// We cannot catch MissingWebViewPackageException as it is in a private / system API
|
||||
// class. This validates the exception's message to ensure we are only handling this
|
||||
// specific exception.
|
||||
// https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/webkit/WebViewFactory.java#98
|
||||
if (message != null && message.contains("No WebView installed")) {
|
||||
return null;
|
||||
} else {
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
if (USES_LEGACY_STORE) {
|
||||
mCookieManager.removeExpiredCookie();
|
||||
@@ -228,7 +262,10 @@ public class ForwardingCookieHandler extends CookieHandler {
|
||||
|
||||
@TargetApi(21)
|
||||
private void flush() {
|
||||
getCookieManager().flush();
|
||||
CookieManager cookieManager = getCookieManager();
|
||||
if (cookieManager != null) {
|
||||
cookieManager.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.facebook.react.modules.network;
|
||||
|
||||
/**
|
||||
*
|
||||
* The class purpose is to weaken too strict OkHttp restriction on http headers.
|
||||
* See: https://github.com/square/okhttp/issues/2016
|
||||
* Auth headers might have an Authentication information. It is better to get 401 from the
|
||||
* server in this case, rather than non descriptive error as 401 could be handled to invalidate
|
||||
* the wrong token in the client code.
|
||||
*/
|
||||
public class HeaderUtil {
|
||||
|
||||
public static String stripHeaderName(String name) {
|
||||
StringBuilder builder = new StringBuilder(name.length());
|
||||
boolean modified = false;
|
||||
for (int i = 0, length = name.length(); i < length; i++) {
|
||||
char c = name.charAt(i);
|
||||
if (c > '\u0020' && c < '\u007f') {
|
||||
builder.append(c);
|
||||
} else {
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
return modified ? builder.toString() : name;
|
||||
}
|
||||
|
||||
public static String stripHeaderValue(String value) {
|
||||
StringBuilder builder = new StringBuilder(value.length());
|
||||
boolean modified = false;
|
||||
for (int i = 0, length = value.length(); i < length; i++) {
|
||||
char c = value.charAt(i);
|
||||
if ((c > '\u001f' && c < '\u007f') || c == '\t' ) {
|
||||
builder.append(c);
|
||||
} else {
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
return modified ? builder.toString() : value;
|
||||
}
|
||||
}
|
||||
+31
-4
@@ -9,6 +9,7 @@ package com.facebook.react.modules.network;
|
||||
import android.net.Uri;
|
||||
import android.util.Base64;
|
||||
|
||||
import com.facebook.common.logging.FLog;
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.GuardedAsyncTask;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
@@ -104,6 +105,7 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
|
||||
|
||||
protected static final String NAME = "Networking";
|
||||
|
||||
private static final String TAG = "NetworkingModule";
|
||||
private static final String CONTENT_ENCODING_HEADER_NAME = "content-encoding";
|
||||
private static final String CONTENT_TYPE_HEADER_NAME = "content-type";
|
||||
private static final String REQUEST_BODY_KEY_STRING = "string";
|
||||
@@ -234,10 +236,29 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void sendRequest(
|
||||
String method,
|
||||
String url,
|
||||
final int requestId,
|
||||
ReadableArray headers,
|
||||
ReadableMap data,
|
||||
final String responseType,
|
||||
final boolean useIncrementalUpdates,
|
||||
int timeout,
|
||||
boolean withCredentials) {
|
||||
try {
|
||||
sendRequestInternal(method, url, requestId, headers, data, responseType,
|
||||
useIncrementalUpdates, timeout, withCredentials);
|
||||
} catch (Throwable th) {
|
||||
FLog.e(TAG, "Failed to send url request: " + url, th);
|
||||
ResponseUtil.onRequestError(getEventEmitter(), requestId, th.getMessage(), th);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param timeout value of 0 results in no timeout
|
||||
*/
|
||||
public void sendRequest(
|
||||
public void sendRequestInternal(
|
||||
String method,
|
||||
String url,
|
||||
final int requestId,
|
||||
@@ -372,7 +393,13 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
requestBody = RequestBody.create(contentMediaType, body);
|
||||
// Use getBytes() to convert the body into a byte[], preventing okhttp from
|
||||
// appending the character set to the Content-Type header when otherwise unspecified
|
||||
// https://github.com/facebook/react-native/issues/8237
|
||||
Charset charset = contentMediaType == null
|
||||
? StandardCharsets.UTF_8
|
||||
: contentMediaType.charset(StandardCharsets.UTF_8);
|
||||
requestBody = RequestBody.create(contentMediaType, body.getBytes(charset));
|
||||
}
|
||||
} else if (data.hasKey(REQUEST_BODY_KEY_BASE64)) {
|
||||
if (contentType == null) {
|
||||
@@ -714,8 +741,8 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
|
||||
if (header == null || header.size() != 2) {
|
||||
return null;
|
||||
}
|
||||
String headerName = header.getString(0);
|
||||
String headerValue = header.getString(1);
|
||||
String headerName = HeaderUtil.stripHeaderName(header.getString(0));
|
||||
String headerValue = HeaderUtil.stripHeaderValue(header.getString(1));
|
||||
if (headerName == null || headerValue == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
+10
-1
@@ -13,6 +13,8 @@ import android.os.Build;
|
||||
import com.facebook.common.logging.FLog;
|
||||
|
||||
import java.io.File;
|
||||
import java.security.Provider;
|
||||
import java.security.Security;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -69,7 +71,14 @@ public class OkHttpClientProvider {
|
||||
.writeTimeout(0, TimeUnit.MILLISECONDS)
|
||||
.cookieJar(new ReactCookieJarContainer());
|
||||
|
||||
return enableTls12OnPreLollipop(client);
|
||||
try {
|
||||
Class ConscryptProvider = Class.forName("org.conscrypt.OpenSSLProvider");
|
||||
Security.insertProviderAt(
|
||||
(Provider) ConscryptProvider.newInstance(), 1);
|
||||
return client;
|
||||
} catch (Exception e) {
|
||||
return enableTls12OnPreLollipop(client);
|
||||
}
|
||||
}
|
||||
|
||||
public static OkHttpClient.Builder createClientBuilder(Context context) {
|
||||
|
||||
@@ -85,7 +85,7 @@ public class ResponseUtil {
|
||||
RCTDeviceEventEmitter eventEmitter,
|
||||
int requestId,
|
||||
String error,
|
||||
IOException e) {
|
||||
Throwable e) {
|
||||
WritableArray args = Arguments.createArray();
|
||||
args.pushInt(requestId);
|
||||
args.pushString(error);
|
||||
|
||||
+2
-2
@@ -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", 59,
|
||||
"patch", 8,
|
||||
"prerelease", null);
|
||||
}
|
||||
|
||||
+23
-1
@@ -9,6 +9,9 @@ import android.content.Context;
|
||||
import android.support.v4.view.AccessibilityDelegateCompat;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
|
||||
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat;
|
||||
import android.text.SpannableString;
|
||||
import android.text.style.URLSpan;
|
||||
import android.view.View;
|
||||
import com.facebook.react.R;
|
||||
import java.util.Locale;
|
||||
@@ -98,7 +101,6 @@ public class AccessibilityDelegateUtil {
|
||||
public void onInitializeAccessibilityNodeInfo(
|
||||
View host, AccessibilityNodeInfoCompat info) {
|
||||
super.onInitializeAccessibilityNodeInfo(host, info);
|
||||
setRole(info, accessibilityRole, view.getContext());
|
||||
if (!(accessibilityHint == null)) {
|
||||
String contentDescription=(String)info.getContentDescription();
|
||||
if (contentDescription != null) {
|
||||
@@ -108,6 +110,8 @@ public class AccessibilityDelegateUtil {
|
||||
info.setContentDescription(accessibilityHint);
|
||||
}
|
||||
}
|
||||
|
||||
setRole(info, accessibilityRole, view.getContext());
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -127,6 +131,18 @@ public class AccessibilityDelegateUtil {
|
||||
if (Locale.getDefault().getLanguage().equals(new Locale("en").getLanguage())) {
|
||||
if (role.equals(AccessibilityRole.LINK)) {
|
||||
nodeInfo.setRoleDescription(context.getString(R.string.link_description));
|
||||
|
||||
if (nodeInfo.getContentDescription() != null) {
|
||||
SpannableString spannable = new SpannableString(nodeInfo.getContentDescription());
|
||||
spannable.setSpan(new URLSpan(""), 0, spannable.length(), 0);
|
||||
nodeInfo.setContentDescription(spannable);
|
||||
}
|
||||
|
||||
if (nodeInfo.getText() != null) {
|
||||
SpannableString spannable = new SpannableString(nodeInfo.getText());
|
||||
spannable.setSpan(new URLSpan(""), 0, spannable.length(), 0);
|
||||
nodeInfo.setText(spannable);
|
||||
}
|
||||
}
|
||||
if (role.equals(AccessibilityRole.SEARCH)) {
|
||||
nodeInfo.setRoleDescription(context.getString(R.string.search_description));
|
||||
@@ -140,6 +156,12 @@ public class AccessibilityDelegateUtil {
|
||||
if (role.equals(AccessibilityRole.ADJUSTABLE)) {
|
||||
nodeInfo.setRoleDescription(context.getString(R.string.adjustable_description));
|
||||
}
|
||||
if (role.equals(AccessibilityRole.HEADER)) {
|
||||
nodeInfo.setRoleDescription(context.getString(R.string.header_description));
|
||||
final AccessibilityNodeInfoCompat.CollectionItemInfoCompat itemInfo =
|
||||
AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain(0, 1, 0, 1, true);
|
||||
nodeInfo.setCollectionItemInfo(itemInfo);
|
||||
}
|
||||
}
|
||||
if (role.equals(AccessibilityRole.IMAGEBUTTON)) {
|
||||
nodeInfo.setClickable(true);
|
||||
|
||||
@@ -15,7 +15,9 @@ import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.uimanager.AccessibilityDelegateUtil.AccessibilityRole;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.facebook.react.uimanager.util.ReactFindViewUtil;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Base class that should be suitable for the majority of subclasses of {@link ViewManager}.
|
||||
@@ -58,12 +60,12 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
|
||||
private static double[] sTransformDecompositionArray = new double[16];
|
||||
|
||||
@ReactProp(name = PROP_BACKGROUND_COLOR, defaultInt = Color.TRANSPARENT, customType = "Color")
|
||||
public void setBackgroundColor(T view, int backgroundColor) {
|
||||
public void setBackgroundColor(@Nonnull T view, int backgroundColor) {
|
||||
view.setBackgroundColor(backgroundColor);
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_TRANSFORM)
|
||||
public void setTransform(T view, ReadableArray matrix) {
|
||||
public void setTransform(@Nonnull T view, @Nullable ReadableArray matrix) {
|
||||
if (matrix == null) {
|
||||
resetTransformProperty(view);
|
||||
} else {
|
||||
@@ -72,20 +74,17 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
|
||||
}
|
||||
|
||||
@ReactProp(name = ViewProps.OPACITY, defaultFloat = 1.f)
|
||||
public void setOpacity(T view, float opacity) {
|
||||
public void setOpacity(@Nonnull T view, float opacity) {
|
||||
view.setAlpha(opacity);
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_ELEVATION)
|
||||
public void setElevation(T view, float elevation) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
view.setElevation(PixelUtil.toPixelFromDIP(elevation));
|
||||
}
|
||||
// Do nothing on API < 21
|
||||
public void setElevation(@Nonnull T view, float elevation) {
|
||||
ViewCompat.setElevation(view, PixelUtil.toPixelFromDIP(elevation));
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_Z_INDEX)
|
||||
public void setZIndex(T view, float zIndex) {
|
||||
public void setZIndex(@Nonnull T view, float zIndex) {
|
||||
int integerZIndex = Math.round(zIndex);
|
||||
ViewGroupManager.setViewZIndex(view, integerZIndex);
|
||||
ViewParent parent = view.getParent();
|
||||
@@ -95,12 +94,12 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_RENDER_TO_HARDWARE_TEXTURE)
|
||||
public void setRenderToHardwareTexture(T view, boolean useHWTexture) {
|
||||
public void setRenderToHardwareTexture(@Nonnull T view, boolean useHWTexture) {
|
||||
view.setLayerType(useHWTexture ? View.LAYER_TYPE_HARDWARE : View.LAYER_TYPE_NONE, null);
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_TEST_ID)
|
||||
public void setTestId(T view, String testId) {
|
||||
public void setTestId(@Nonnull T view, String testId) {
|
||||
view.setTag(R.id.react_test_id, testId);
|
||||
|
||||
// temporarily set the tag and keyed tags to avoid end to end test regressions
|
||||
@@ -108,28 +107,28 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_NATIVE_ID)
|
||||
public void setNativeId(T view, String nativeId) {
|
||||
public void setNativeId(@Nonnull T view, String nativeId) {
|
||||
view.setTag(R.id.view_tag_native_id, nativeId);
|
||||
ReactFindViewUtil.notifyViewRendered(view);
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_ACCESSIBILITY_LABEL)
|
||||
public void setAccessibilityLabel(T view, String accessibilityLabel) {
|
||||
public void setAccessibilityLabel(@Nonnull T view, String accessibilityLabel) {
|
||||
view.setContentDescription(accessibilityLabel);
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_ACCESSIBILITY_COMPONENT_TYPE)
|
||||
public void setAccessibilityComponentType(T view, String accessibilityComponentType) {
|
||||
public void setAccessibilityComponentType(@Nonnull T view, String accessibilityComponentType) {
|
||||
AccessibilityHelper.updateAccessibilityComponentType(view, accessibilityComponentType);
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_ACCESSIBILITY_HINT)
|
||||
public void setAccessibilityHint(T view, String accessibilityHint) {
|
||||
public void setAccessibilityHint(@Nonnull T view, String accessibilityHint) {
|
||||
view.setTag(R.id.accessibility_hint, accessibilityHint);
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_ACCESSIBILITY_ROLE)
|
||||
public void setAccessibilityRole(T view, String accessibilityRole) {
|
||||
public void setAccessibilityRole(@Nonnull T view, @Nullable String accessibilityRole) {
|
||||
if (accessibilityRole == null) {
|
||||
return;
|
||||
}
|
||||
@@ -138,7 +137,7 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_ACCESSIBILITY_STATES)
|
||||
public void setViewStates(T view, ReadableArray accessibilityStates) {
|
||||
public void setViewStates(@Nonnull T view, @Nullable ReadableArray accessibilityStates) {
|
||||
view.setSelected(false);
|
||||
view.setEnabled(true);
|
||||
if (accessibilityStates == null) {
|
||||
@@ -155,7 +154,7 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_IMPORTANT_FOR_ACCESSIBILITY)
|
||||
public void setImportantForAccessibility(T view, String importantForAccessibility) {
|
||||
public void setImportantForAccessibility(@Nonnull T view, @Nullable String importantForAccessibility) {
|
||||
if (importantForAccessibility == null || importantForAccessibility.equals("auto")) {
|
||||
ViewCompat.setImportantForAccessibility(view, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
|
||||
} else if (importantForAccessibility.equals("yes")) {
|
||||
@@ -169,48 +168,46 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
|
||||
|
||||
@Deprecated
|
||||
@ReactProp(name = PROP_ROTATION)
|
||||
public void setRotation(T view, float rotation) {
|
||||
public void setRotation(@Nonnull T view, float rotation) {
|
||||
view.setRotation(rotation);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@ReactProp(name = PROP_SCALE_X, defaultFloat = 1f)
|
||||
public void setScaleX(T view, float scaleX) {
|
||||
public void setScaleX(@Nonnull T view, float scaleX) {
|
||||
view.setScaleX(scaleX);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@ReactProp(name = PROP_SCALE_Y, defaultFloat = 1f)
|
||||
public void setScaleY(T view, float scaleY) {
|
||||
public void setScaleY(@Nonnull T view, float scaleY) {
|
||||
view.setScaleY(scaleY);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@ReactProp(name = PROP_TRANSLATE_X, defaultFloat = 0f)
|
||||
public void setTranslateX(T view, float translateX) {
|
||||
public void setTranslateX(@Nonnull T view, float translateX) {
|
||||
view.setTranslationX(PixelUtil.toPixelFromDIP(translateX));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@ReactProp(name = PROP_TRANSLATE_Y, defaultFloat = 0f)
|
||||
public void setTranslateY(T view, float translateY) {
|
||||
public void setTranslateY(@Nonnull T view, float translateY) {
|
||||
view.setTranslationY(PixelUtil.toPixelFromDIP(translateY));
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_ACCESSIBILITY_LIVE_REGION)
|
||||
public void setAccessibilityLiveRegion(T view, String liveRegion) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
public void setAccessibilityLiveRegion(@Nonnull T view, @Nullable String liveRegion) {
|
||||
if (liveRegion == null || liveRegion.equals("none")) {
|
||||
view.setAccessibilityLiveRegion(View.ACCESSIBILITY_LIVE_REGION_NONE);
|
||||
ViewCompat.setAccessibilityLiveRegion(view, ViewCompat.ACCESSIBILITY_LIVE_REGION_NONE);
|
||||
} else if (liveRegion.equals("polite")) {
|
||||
view.setAccessibilityLiveRegion(View.ACCESSIBILITY_LIVE_REGION_POLITE);
|
||||
ViewCompat.setAccessibilityLiveRegion(view, ViewCompat.ACCESSIBILITY_LIVE_REGION_POLITE);
|
||||
} else if (liveRegion.equals("assertive")) {
|
||||
view.setAccessibilityLiveRegion(View.ACCESSIBILITY_LIVE_REGION_ASSERTIVE);
|
||||
ViewCompat.setAccessibilityLiveRegion(view, ViewCompat.ACCESSIBILITY_LIVE_REGION_ASSERTIVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void setTransformProperty(View view, ReadableArray transforms) {
|
||||
private static void setTransformProperty(@Nonnull View view, ReadableArray transforms) {
|
||||
TransformHelper.processTransform(transforms, sTransformDecompositionArray);
|
||||
MatrixMathHelper.decomposeMatrix(sTransformDecompositionArray, sMatrixDecompositionContext);
|
||||
view.setTranslationX(
|
||||
@@ -246,7 +243,7 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
|
||||
}
|
||||
}
|
||||
|
||||
private static void resetTransformProperty(View view) {
|
||||
private static void resetTransformProperty(@Nonnull View view) {
|
||||
view.setTranslationX(PixelUtil.toPixelFromDIP(0));
|
||||
view.setTranslationY(PixelUtil.toPixelFromDIP(0));
|
||||
view.setRotation(0);
|
||||
@@ -257,12 +254,12 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
|
||||
view.setCameraDistance(0);
|
||||
}
|
||||
|
||||
private void updateViewAccessibility(T view) {
|
||||
private void updateViewAccessibility(@Nonnull T view) {
|
||||
AccessibilityDelegateUtil.setDelegate(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAfterUpdateTransaction(T view) {
|
||||
protected void onAfterUpdateTransaction(@Nonnull T view) {
|
||||
super.onAfterUpdateTransaction(view);
|
||||
updateViewAccessibility(view);
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ import javax.annotation.Nullable;
|
||||
* shadow node hierarchy that is then mapped to a native view hierarchy.
|
||||
*/
|
||||
public class UIImplementation {
|
||||
protected Object uiImplementationThreadLock = new Object();
|
||||
|
||||
protected final EventDispatcher mEventDispatcher;
|
||||
protected final ReactApplicationContext mReactContext;
|
||||
@@ -197,23 +198,25 @@ public class UIImplementation {
|
||||
*/
|
||||
public <T extends SizeMonitoringFrameLayout & MeasureSpecProvider> void registerRootView(
|
||||
T rootView, int tag, ThemedReactContext context) {
|
||||
final ReactShadowNode rootCSSNode = createRootShadowNode();
|
||||
rootCSSNode.setReactTag(tag);
|
||||
rootCSSNode.setThemedContext(context);
|
||||
synchronized (uiImplementationThreadLock) {
|
||||
final ReactShadowNode rootCSSNode = createRootShadowNode();
|
||||
rootCSSNode.setReactTag(tag);
|
||||
rootCSSNode.setThemedContext(context);
|
||||
|
||||
int widthMeasureSpec = rootView.getWidthMeasureSpec();
|
||||
int heightMeasureSpec = rootView.getHeightMeasureSpec();
|
||||
updateRootView(rootCSSNode, widthMeasureSpec, heightMeasureSpec);
|
||||
int widthMeasureSpec = rootView.getWidthMeasureSpec();
|
||||
int heightMeasureSpec = rootView.getHeightMeasureSpec();
|
||||
updateRootView(rootCSSNode, widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
context.runOnNativeModulesQueueThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mShadowNodeRegistry.addRootNode(rootCSSNode);
|
||||
}
|
||||
});
|
||||
context.runOnNativeModulesQueueThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mShadowNodeRegistry.addRootNode(rootCSSNode);
|
||||
}
|
||||
});
|
||||
|
||||
// register it within NativeViewHierarchyManager
|
||||
mOperationsQueue.addRootView(tag, rootView, context);
|
||||
// register it within NativeViewHierarchyManager
|
||||
mOperationsQueue.addRootView(tag, rootView, context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -228,7 +231,9 @@ public class UIImplementation {
|
||||
* Unregisters a root node with a given tag from the shadow node registry
|
||||
*/
|
||||
public void removeRootShadowNode(int rootViewTag) {
|
||||
mShadowNodeRegistry.removeRootNode(rootViewTag);
|
||||
synchronized (uiImplementationThreadLock) {
|
||||
mShadowNodeRegistry.removeRootNode(rootViewTag);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -279,23 +284,25 @@ public class UIImplementation {
|
||||
* Invoked by React to create a new node with a given tag, class name and properties.
|
||||
*/
|
||||
public void createView(int tag, String className, int rootViewTag, ReadableMap props) {
|
||||
ReactShadowNode cssNode = createShadowNode(className);
|
||||
ReactShadowNode rootNode = mShadowNodeRegistry.getNode(rootViewTag);
|
||||
Assertions.assertNotNull(rootNode, "Root node with tag " + rootViewTag + " doesn't exist");
|
||||
cssNode.setReactTag(tag);
|
||||
cssNode.setViewClassName(className);
|
||||
cssNode.setRootTag(rootNode.getReactTag());
|
||||
cssNode.setThemedContext(rootNode.getThemedContext());
|
||||
synchronized (uiImplementationThreadLock) {
|
||||
ReactShadowNode cssNode = createShadowNode(className);
|
||||
ReactShadowNode rootNode = mShadowNodeRegistry.getNode(rootViewTag);
|
||||
Assertions.assertNotNull(rootNode, "Root node with tag " + rootViewTag + " doesn't exist");
|
||||
cssNode.setReactTag(tag);
|
||||
cssNode.setViewClassName(className);
|
||||
cssNode.setRootTag(rootNode.getReactTag());
|
||||
cssNode.setThemedContext(rootNode.getThemedContext());
|
||||
|
||||
mShadowNodeRegistry.addNode(cssNode);
|
||||
mShadowNodeRegistry.addNode(cssNode);
|
||||
|
||||
ReactStylesDiffMap styles = null;
|
||||
if (props != null) {
|
||||
styles = new ReactStylesDiffMap(props);
|
||||
cssNode.updateProperties(styles);
|
||||
ReactStylesDiffMap styles = null;
|
||||
if (props != null) {
|
||||
styles = new ReactStylesDiffMap(props);
|
||||
cssNode.updateProperties(styles);
|
||||
}
|
||||
|
||||
handleCreateView(cssNode, rootViewTag, styles);
|
||||
}
|
||||
|
||||
handleCreateView(cssNode, rootViewTag, styles);
|
||||
}
|
||||
|
||||
protected void handleCreateView(
|
||||
@@ -363,106 +370,108 @@ public class UIImplementation {
|
||||
@Nullable ReadableArray addChildTags,
|
||||
@Nullable ReadableArray addAtIndices,
|
||||
@Nullable ReadableArray removeFrom) {
|
||||
ReactShadowNode cssNodeToManage = mShadowNodeRegistry.getNode(viewTag);
|
||||
synchronized (uiImplementationThreadLock) {
|
||||
ReactShadowNode cssNodeToManage = mShadowNodeRegistry.getNode(viewTag);
|
||||
|
||||
int numToMove = moveFrom == null ? 0 : moveFrom.size();
|
||||
int numToAdd = addChildTags == null ? 0 : addChildTags.size();
|
||||
int numToRemove = removeFrom == null ? 0 : removeFrom.size();
|
||||
int numToMove = moveFrom == null ? 0 : moveFrom.size();
|
||||
int numToAdd = addChildTags == null ? 0 : addChildTags.size();
|
||||
int numToRemove = removeFrom == null ? 0 : removeFrom.size();
|
||||
|
||||
if (numToMove != 0 && (moveTo == null || numToMove != moveTo.size())) {
|
||||
throw new IllegalViewOperationException("Size of moveFrom != size of moveTo!");
|
||||
}
|
||||
|
||||
if (numToAdd != 0 && (addAtIndices == null || numToAdd != addAtIndices.size())) {
|
||||
throw new IllegalViewOperationException("Size of addChildTags != size of addAtIndices!");
|
||||
}
|
||||
|
||||
// We treat moves as an add and a delete
|
||||
ViewAtIndex[] viewsToAdd = new ViewAtIndex[numToMove + numToAdd];
|
||||
int[] indicesToRemove = new int[numToMove + numToRemove];
|
||||
int[] tagsToRemove = new int[indicesToRemove.length];
|
||||
int[] tagsToDelete = new int[numToRemove];
|
||||
|
||||
if (numToMove > 0) {
|
||||
Assertions.assertNotNull(moveFrom);
|
||||
Assertions.assertNotNull(moveTo);
|
||||
for (int i = 0; i < numToMove; i++) {
|
||||
int moveFromIndex = moveFrom.getInt(i);
|
||||
int tagToMove = cssNodeToManage.getChildAt(moveFromIndex).getReactTag();
|
||||
viewsToAdd[i] = new ViewAtIndex(
|
||||
tagToMove,
|
||||
moveTo.getInt(i));
|
||||
indicesToRemove[i] = moveFromIndex;
|
||||
tagsToRemove[i] = tagToMove;
|
||||
if (numToMove != 0 && (moveTo == null || numToMove != moveTo.size())) {
|
||||
throw new IllegalViewOperationException("Size of moveFrom != size of moveTo!");
|
||||
}
|
||||
}
|
||||
|
||||
if (numToAdd > 0) {
|
||||
Assertions.assertNotNull(addChildTags);
|
||||
Assertions.assertNotNull(addAtIndices);
|
||||
for (int i = 0; i < numToAdd; i++) {
|
||||
int viewTagToAdd = addChildTags.getInt(i);
|
||||
int indexToAddAt = addAtIndices.getInt(i);
|
||||
viewsToAdd[numToMove + i] = new ViewAtIndex(viewTagToAdd, indexToAddAt);
|
||||
if (numToAdd != 0 && (addAtIndices == null || numToAdd != addAtIndices.size())) {
|
||||
throw new IllegalViewOperationException("Size of addChildTags != size of addAtIndices!");
|
||||
}
|
||||
}
|
||||
|
||||
if (numToRemove > 0) {
|
||||
Assertions.assertNotNull(removeFrom);
|
||||
for (int i = 0; i < numToRemove; i++) {
|
||||
int indexToRemove = removeFrom.getInt(i);
|
||||
int tagToRemove = cssNodeToManage.getChildAt(indexToRemove).getReactTag();
|
||||
indicesToRemove[numToMove + i] = indexToRemove;
|
||||
tagsToRemove[numToMove + i] = tagToRemove;
|
||||
tagsToDelete[i] = tagToRemove;
|
||||
// We treat moves as an add and a delete
|
||||
ViewAtIndex[] viewsToAdd = new ViewAtIndex[numToMove + numToAdd];
|
||||
int[] indicesToRemove = new int[numToMove + numToRemove];
|
||||
int[] tagsToRemove = new int[indicesToRemove.length];
|
||||
int[] tagsToDelete = new int[numToRemove];
|
||||
|
||||
if (numToMove > 0) {
|
||||
Assertions.assertNotNull(moveFrom);
|
||||
Assertions.assertNotNull(moveTo);
|
||||
for (int i = 0; i < numToMove; i++) {
|
||||
int moveFromIndex = moveFrom.getInt(i);
|
||||
int tagToMove = cssNodeToManage.getChildAt(moveFromIndex).getReactTag();
|
||||
viewsToAdd[i] = new ViewAtIndex(
|
||||
tagToMove,
|
||||
moveTo.getInt(i));
|
||||
indicesToRemove[i] = moveFromIndex;
|
||||
tagsToRemove[i] = tagToMove;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NB: moveFrom and removeFrom are both relative to the starting state of the View's children.
|
||||
// moveTo and addAt are both relative to the final state of the View's children.
|
||||
//
|
||||
// 1) Sort the views to add and indices to remove by index
|
||||
// 2) Iterate the indices being removed from high to low and remove them. Going high to low
|
||||
// makes sure we remove the correct index when there are multiple to remove.
|
||||
// 3) Iterate the views being added by index low to high and add them. Like the view removal,
|
||||
// iteration direction is important to preserve the correct index.
|
||||
|
||||
Arrays.sort(viewsToAdd, ViewAtIndex.COMPARATOR);
|
||||
Arrays.sort(indicesToRemove);
|
||||
|
||||
// Apply changes to CSSNodeDEPRECATED hierarchy
|
||||
int lastIndexRemoved = -1;
|
||||
for (int i = indicesToRemove.length - 1; i >= 0; i--) {
|
||||
int indexToRemove = indicesToRemove[i];
|
||||
if (indexToRemove == lastIndexRemoved) {
|
||||
throw new IllegalViewOperationException("Repeated indices in Removal list for view tag: "
|
||||
+ viewTag);
|
||||
if (numToAdd > 0) {
|
||||
Assertions.assertNotNull(addChildTags);
|
||||
Assertions.assertNotNull(addAtIndices);
|
||||
for (int i = 0; i < numToAdd; i++) {
|
||||
int viewTagToAdd = addChildTags.getInt(i);
|
||||
int indexToAddAt = addAtIndices.getInt(i);
|
||||
viewsToAdd[numToMove + i] = new ViewAtIndex(viewTagToAdd, indexToAddAt);
|
||||
}
|
||||
}
|
||||
cssNodeToManage.removeChildAt(indicesToRemove[i]);
|
||||
lastIndexRemoved = indicesToRemove[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < viewsToAdd.length; i++) {
|
||||
ViewAtIndex viewAtIndex = viewsToAdd[i];
|
||||
ReactShadowNode cssNodeToAdd = mShadowNodeRegistry.getNode(viewAtIndex.mTag);
|
||||
if (cssNodeToAdd == null) {
|
||||
throw new IllegalViewOperationException("Trying to add unknown view tag: "
|
||||
+ viewAtIndex.mTag);
|
||||
if (numToRemove > 0) {
|
||||
Assertions.assertNotNull(removeFrom);
|
||||
for (int i = 0; i < numToRemove; i++) {
|
||||
int indexToRemove = removeFrom.getInt(i);
|
||||
int tagToRemove = cssNodeToManage.getChildAt(indexToRemove).getReactTag();
|
||||
indicesToRemove[numToMove + i] = indexToRemove;
|
||||
tagsToRemove[numToMove + i] = tagToRemove;
|
||||
tagsToDelete[i] = tagToRemove;
|
||||
}
|
||||
}
|
||||
cssNodeToManage.addChildAt(cssNodeToAdd, viewAtIndex.mIndex);
|
||||
}
|
||||
|
||||
if (!cssNodeToManage.isVirtual() && !cssNodeToManage.isVirtualAnchor()) {
|
||||
mNativeViewHierarchyOptimizer.handleManageChildren(
|
||||
cssNodeToManage,
|
||||
indicesToRemove,
|
||||
tagsToRemove,
|
||||
viewsToAdd,
|
||||
tagsToDelete);
|
||||
}
|
||||
// NB: moveFrom and removeFrom are both relative to the starting state of the View's children.
|
||||
// moveTo and addAt are both relative to the final state of the View's children.
|
||||
//
|
||||
// 1) Sort the views to add and indices to remove by index
|
||||
// 2) Iterate the indices being removed from high to low and remove them. Going high to low
|
||||
// makes sure we remove the correct index when there are multiple to remove.
|
||||
// 3) Iterate the views being added by index low to high and add them. Like the view removal,
|
||||
// iteration direction is important to preserve the correct index.
|
||||
|
||||
for (int i = 0; i < tagsToDelete.length; i++) {
|
||||
removeShadowNode(mShadowNodeRegistry.getNode(tagsToDelete[i]));
|
||||
Arrays.sort(viewsToAdd, ViewAtIndex.COMPARATOR);
|
||||
Arrays.sort(indicesToRemove);
|
||||
|
||||
// Apply changes to CSSNodeDEPRECATED hierarchy
|
||||
int lastIndexRemoved = -1;
|
||||
for (int i = indicesToRemove.length - 1; i >= 0; i--) {
|
||||
int indexToRemove = indicesToRemove[i];
|
||||
if (indexToRemove == lastIndexRemoved) {
|
||||
throw new IllegalViewOperationException("Repeated indices in Removal list for view tag: "
|
||||
+ viewTag);
|
||||
}
|
||||
cssNodeToManage.removeChildAt(indicesToRemove[i]);
|
||||
lastIndexRemoved = indicesToRemove[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < viewsToAdd.length; i++) {
|
||||
ViewAtIndex viewAtIndex = viewsToAdd[i];
|
||||
ReactShadowNode cssNodeToAdd = mShadowNodeRegistry.getNode(viewAtIndex.mTag);
|
||||
if (cssNodeToAdd == null) {
|
||||
throw new IllegalViewOperationException("Trying to add unknown view tag: "
|
||||
+ viewAtIndex.mTag);
|
||||
}
|
||||
cssNodeToManage.addChildAt(cssNodeToAdd, viewAtIndex.mIndex);
|
||||
}
|
||||
|
||||
if (!cssNodeToManage.isVirtual() && !cssNodeToManage.isVirtualAnchor()) {
|
||||
mNativeViewHierarchyOptimizer.handleManageChildren(
|
||||
cssNodeToManage,
|
||||
indicesToRemove,
|
||||
tagsToRemove,
|
||||
viewsToAdd,
|
||||
tagsToDelete);
|
||||
}
|
||||
|
||||
for (int i = 0; i < tagsToDelete.length; i++) {
|
||||
removeShadowNode(mShadowNodeRegistry.getNode(tagsToDelete[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -476,22 +485,23 @@ public class UIImplementation {
|
||||
public void setChildren(
|
||||
int viewTag,
|
||||
ReadableArray childrenTags) {
|
||||
synchronized (uiImplementationThreadLock) {
|
||||
ReactShadowNode cssNodeToManage = mShadowNodeRegistry.getNode(viewTag);
|
||||
|
||||
ReactShadowNode cssNodeToManage = mShadowNodeRegistry.getNode(viewTag);
|
||||
|
||||
for (int i = 0; i < childrenTags.size(); i++) {
|
||||
ReactShadowNode cssNodeToAdd = mShadowNodeRegistry.getNode(childrenTags.getInt(i));
|
||||
if (cssNodeToAdd == null) {
|
||||
throw new IllegalViewOperationException("Trying to add unknown view tag: "
|
||||
+ childrenTags.getInt(i));
|
||||
for (int i = 0; i < childrenTags.size(); i++) {
|
||||
ReactShadowNode cssNodeToAdd = mShadowNodeRegistry.getNode(childrenTags.getInt(i));
|
||||
if (cssNodeToAdd == null) {
|
||||
throw new IllegalViewOperationException("Trying to add unknown view tag: "
|
||||
+ childrenTags.getInt(i));
|
||||
}
|
||||
cssNodeToManage.addChildAt(cssNodeToAdd, i);
|
||||
}
|
||||
cssNodeToManage.addChildAt(cssNodeToAdd, i);
|
||||
}
|
||||
|
||||
if (!cssNodeToManage.isVirtual() && !cssNodeToManage.isVirtualAnchor()) {
|
||||
mNativeViewHierarchyOptimizer.handleSetChildren(
|
||||
cssNodeToManage,
|
||||
childrenTags);
|
||||
if (!cssNodeToManage.isVirtual() && !cssNodeToManage.isVirtualAnchor()) {
|
||||
mNativeViewHierarchyOptimizer.handleSetChildren(
|
||||
cssNodeToManage,
|
||||
childrenTags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@ import com.facebook.react.uimanager.annotations.ReactPropGroup;
|
||||
import com.facebook.react.uimanager.annotations.ReactPropertyHolder;
|
||||
import com.facebook.yoga.YogaMeasureMode;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
@@ -31,7 +33,7 @@ import javax.annotation.Nullable;
|
||||
public abstract class ViewManager<T extends View, C extends ReactShadowNode>
|
||||
extends BaseJavaModule {
|
||||
|
||||
public final void updateProperties(T viewToUpdate, ReactStylesDiffMap props) {
|
||||
public final void updateProperties(@Nonnull T viewToUpdate, ReactStylesDiffMap props) {
|
||||
ViewManagerPropertyUpdater.updateProps(this, viewToUpdate, props);
|
||||
onAfterUpdateTransaction(viewToUpdate);
|
||||
}
|
||||
@@ -39,8 +41,8 @@ public abstract class ViewManager<T extends View, C extends ReactShadowNode>
|
||||
/**
|
||||
* Creates a view and installs event emitters on it.
|
||||
*/
|
||||
public final T createView(
|
||||
ThemedReactContext reactContext,
|
||||
public final @Nonnull T createView(
|
||||
@Nonnull ThemedReactContext reactContext,
|
||||
JSResponderHandler jsResponderHandler) {
|
||||
T view = createViewInstance(reactContext);
|
||||
addEventEmitters(reactContext, view);
|
||||
@@ -54,7 +56,7 @@ public abstract class ViewManager<T extends View, C extends ReactShadowNode>
|
||||
* @return the name of this view manager. This will be the name used to reference this view
|
||||
* manager from JavaScript in createReactNativeComponentClass.
|
||||
*/
|
||||
public abstract String getName();
|
||||
public abstract @Nonnull String getName();
|
||||
|
||||
/**
|
||||
* This method should return a subclass of {@link ReactShadowNode} which will be then used for
|
||||
@@ -65,7 +67,7 @@ public abstract class ViewManager<T extends View, C extends ReactShadowNode>
|
||||
throw new RuntimeException("ViewManager subclasses must implement createShadowNodeInstance()");
|
||||
}
|
||||
|
||||
public C createShadowNodeInstance(ReactApplicationContext context) {
|
||||
public @Nonnull C createShadowNodeInstance(@Nonnull ReactApplicationContext context) {
|
||||
return createShadowNodeInstance();
|
||||
}
|
||||
|
||||
@@ -85,13 +87,13 @@ public abstract class ViewManager<T extends View, C extends ReactShadowNode>
|
||||
* Subclasses should return a new View instance of the proper type.
|
||||
* @param reactContext
|
||||
*/
|
||||
protected abstract T createViewInstance(ThemedReactContext reactContext);
|
||||
protected abstract @Nonnull T createViewInstance(@Nonnull ThemedReactContext reactContext);
|
||||
|
||||
/**
|
||||
* Called when view is detached from view hierarchy and allows for some additional cleanup by
|
||||
* the {@link ViewManager} subclass.
|
||||
*/
|
||||
public void onDropViewInstance(T view) {
|
||||
public void onDropViewInstance(@Nonnull T view) {
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,7 +101,7 @@ public abstract class ViewManager<T extends View, C extends ReactShadowNode>
|
||||
* might want to override this method if your view needs to emit events besides basic touch events
|
||||
* to JS (e.g. scroll events).
|
||||
*/
|
||||
protected void addEventEmitters(ThemedReactContext reactContext, T view) {
|
||||
protected void addEventEmitters(@Nonnull ThemedReactContext reactContext, @Nonnull T view) {
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,7 +110,7 @@ public abstract class ViewManager<T extends View, C extends ReactShadowNode>
|
||||
* you want to override this method you should call super.onAfterUpdateTransaction from it as
|
||||
* the parent class of the ViewManager may rely on callback being executed.
|
||||
*/
|
||||
protected void onAfterUpdateTransaction(T view) {
|
||||
protected void onAfterUpdateTransaction(@Nonnull T view) {
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,7 +124,7 @@ public abstract class ViewManager<T extends View, C extends ReactShadowNode>
|
||||
*
|
||||
* TODO(7247021): Replace updateExtraData with generic update props mechanism after D2086999
|
||||
*/
|
||||
public abstract void updateExtraData(T root, Object extraData);
|
||||
public abstract void updateExtraData(@Nonnull T root, Object extraData);
|
||||
|
||||
/**
|
||||
* Subclasses may use this method to receive events/commands directly from JS through the
|
||||
@@ -133,7 +135,7 @@ public abstract class ViewManager<T extends View, C extends ReactShadowNode>
|
||||
* @param commandId code of the command
|
||||
* @param args optional arguments for the command
|
||||
*/
|
||||
public void receiveCommand(T root, int commandId, @Nullable ReadableArray args) {
|
||||
public void receiveCommand(@Nonnull T root, int commandId, @Nullable ReadableArray args) {
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,7 +211,7 @@ public abstract class ViewManager<T extends View, C extends ReactShadowNode>
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public @Nullable Object updateLocalData(T view, ReactStylesDiffMap props, ReactStylesDiffMap localData) {
|
||||
public @Nullable Object updateLocalData(@Nonnull T view, ReactStylesDiffMap props, ReactStylesDiffMap localData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,8 +24,18 @@ public class JSStackTrace {
|
||||
stringBuilder
|
||||
.append(frame.getString("methodName"))
|
||||
.append("@")
|
||||
.append(parseFileId(frame))
|
||||
.append(frame.getInt("lineNumber"));
|
||||
.append(parseFileId(frame));
|
||||
|
||||
if (frame.hasKey("lineNumber") &&
|
||||
!frame.isNull("lineNumber") &&
|
||||
frame.getType("lineNumber") == ReadableType.Number) {
|
||||
stringBuilder
|
||||
.append(frame.getInt("lineNumber"));
|
||||
} else {
|
||||
stringBuilder
|
||||
.append(-1);
|
||||
}
|
||||
|
||||
if (frame.hasKey("column") &&
|
||||
!frame.isNull("column") &&
|
||||
frame.getType("column") == ReadableType.Number) {
|
||||
@@ -33,6 +43,7 @@ public class JSStackTrace {
|
||||
.append(":")
|
||||
.append(frame.getInt("column"));
|
||||
}
|
||||
|
||||
stringBuilder.append("\n");
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
|
||||
@@ -36,6 +36,7 @@ import javax.annotation.Nullable;
|
||||
if (mAllowChange && isChecked() != checked) {
|
||||
mAllowChange = false;
|
||||
super.setChecked(checked);
|
||||
setTrackColor(checked);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,8 +60,7 @@ import javax.annotation.Nullable;
|
||||
// If the switch has a different value than the value sent by JS, we must change it.
|
||||
if (isChecked() != on) {
|
||||
super.setChecked(on);
|
||||
Integer currentTrackColor = on ? mTrackColorForTrue : mTrackColorForFalse;
|
||||
setTrackColor(currentTrackColor);
|
||||
setTrackColor(on);
|
||||
}
|
||||
mAllowChange = true;
|
||||
}
|
||||
@@ -86,4 +86,13 @@ import javax.annotation.Nullable;
|
||||
setTrackColor(mTrackColorForFalse);
|
||||
}
|
||||
}
|
||||
|
||||
private void setTrackColor(boolean checked) {
|
||||
if (mTrackColorForTrue != null || mTrackColorForFalse != null) {
|
||||
// Update the track color to reflect the new value. We only want to do this if these
|
||||
// props were actually set from JS; otherwise we'll just reset the color to the default.
|
||||
Integer currentTrackColor = checked ? mTrackColorForTrue : mTrackColorForFalse;
|
||||
setTrackColor(currentTrackColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ rn_android_library(
|
||||
],
|
||||
deps = [
|
||||
YOGA_TARGET,
|
||||
react_native_dep("third-party/android/support/v4:lib-support-v4"),
|
||||
react_native_dep("third-party/android/support/v7/appcompat-orig:appcompat"),
|
||||
react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"),
|
||||
react_native_dep("third-party/java/infer-annotations:infer-annotations"),
|
||||
react_native_dep("third-party/java/jsr-305:jsr-305"),
|
||||
|
||||
+23
-11
@@ -265,6 +265,9 @@ public abstract class ReactBaseTextShadowNode extends LayoutShadowNode {
|
||||
protected int mTextAlign = Gravity.NO_GRAVITY;
|
||||
protected int mTextBreakStrategy =
|
||||
(Build.VERSION.SDK_INT < Build.VERSION_CODES.M) ? 0 : Layout.BREAK_STRATEGY_HIGH_QUALITY;
|
||||
protected int mJustificationMode =
|
||||
(Build.VERSION.SDK_INT < Build.VERSION_CODES.O) ? 0 : Layout.JUSTIFICATION_MODE_NONE;
|
||||
protected TextTransform mTextTransform = TextTransform.UNSET;
|
||||
|
||||
protected float mTextShadowOffsetDx = 0;
|
||||
protected float mTextShadowOffsetDy = 0;
|
||||
@@ -357,19 +360,28 @@ public abstract class ReactBaseTextShadowNode extends LayoutShadowNode {
|
||||
|
||||
@ReactProp(name = ViewProps.TEXT_ALIGN)
|
||||
public void setTextAlign(@Nullable String textAlign) {
|
||||
if (textAlign == null || "auto".equals(textAlign)) {
|
||||
mTextAlign = Gravity.NO_GRAVITY;
|
||||
} else if ("left".equals(textAlign)) {
|
||||
mTextAlign = Gravity.LEFT;
|
||||
} else if ("right".equals(textAlign)) {
|
||||
mTextAlign = Gravity.RIGHT;
|
||||
} else if ("center".equals(textAlign)) {
|
||||
mTextAlign = Gravity.CENTER_HORIZONTAL;
|
||||
} else if ("justify".equals(textAlign)) {
|
||||
// Fallback gracefully for cross-platform compat instead of error
|
||||
if ("justify".equals(textAlign)) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
mJustificationMode = Layout.JUSTIFICATION_MODE_INTER_WORD;
|
||||
}
|
||||
mTextAlign = Gravity.LEFT;
|
||||
} else {
|
||||
throw new JSApplicationIllegalArgumentException("Invalid textAlign: " + textAlign);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
mJustificationMode = Layout.JUSTIFICATION_MODE_NONE;
|
||||
}
|
||||
|
||||
if (textAlign == null || "auto".equals(textAlign)) {
|
||||
mTextAlign = Gravity.NO_GRAVITY;
|
||||
} else if ("left".equals(textAlign)) {
|
||||
mTextAlign = Gravity.LEFT;
|
||||
} else if ("right".equals(textAlign)) {
|
||||
mTextAlign = Gravity.RIGHT;
|
||||
} else if ("center".equals(textAlign)) {
|
||||
mTextAlign = Gravity.CENTER_HORIZONTAL;
|
||||
} else {
|
||||
throw new JSApplicationIllegalArgumentException("Invalid textAlign: " + textAlign);
|
||||
}
|
||||
|
||||
}
|
||||
markUpdated();
|
||||
}
|
||||
|
||||
@@ -99,14 +99,18 @@ public class ReactTextShadowNode extends ReactBaseTextShadowNode {
|
||||
new StaticLayout(
|
||||
text, textPaint, hintWidth, alignment, 1.f, 0.f, mIncludeFontPadding);
|
||||
} else {
|
||||
layout =
|
||||
StaticLayout.Builder builder =
|
||||
StaticLayout.Builder.obtain(text, 0, text.length(), textPaint, hintWidth)
|
||||
.setAlignment(alignment)
|
||||
.setLineSpacing(0.f, 1.f)
|
||||
.setIncludePad(mIncludeFontPadding)
|
||||
.setBreakStrategy(mTextBreakStrategy)
|
||||
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
|
||||
.build();
|
||||
.setAlignment(alignment)
|
||||
.setLineSpacing(0.f, 1.f)
|
||||
.setIncludePad(mIncludeFontPadding)
|
||||
.setBreakStrategy(mTextBreakStrategy)
|
||||
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
builder.setJustificationMode(mJustificationMode);
|
||||
}
|
||||
layout = builder.build();
|
||||
}
|
||||
|
||||
} else if (boring != null && (unconstrainedWidth || boring.width <= width)) {
|
||||
@@ -217,7 +221,8 @@ public class ReactTextShadowNode extends ReactBaseTextShadowNode {
|
||||
getPadding(Spacing.END),
|
||||
getPadding(Spacing.BOTTOM),
|
||||
getTextAlign(),
|
||||
mTextBreakStrategy);
|
||||
mTextBreakStrategy,
|
||||
mJustificationMode);
|
||||
uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ public class ReactTextUpdate {
|
||||
private final float mPaddingBottom;
|
||||
private final int mTextAlign;
|
||||
private final int mTextBreakStrategy;
|
||||
private final int mJustificationMode;
|
||||
|
||||
/**
|
||||
* @deprecated Use a non-deprecated constructor for ReactTextUpdate instead. This one remains
|
||||
@@ -49,7 +50,8 @@ public class ReactTextUpdate {
|
||||
paddingEnd,
|
||||
paddingBottom,
|
||||
textAlign,
|
||||
Layout.BREAK_STRATEGY_HIGH_QUALITY);
|
||||
Layout.BREAK_STRATEGY_HIGH_QUALITY,
|
||||
Layout.JUSTIFICATION_MODE_NONE);
|
||||
}
|
||||
|
||||
public ReactTextUpdate(
|
||||
@@ -61,7 +63,8 @@ public class ReactTextUpdate {
|
||||
float paddingEnd,
|
||||
float paddingBottom,
|
||||
int textAlign,
|
||||
int textBreakStrategy) {
|
||||
int textBreakStrategy,
|
||||
int justificationMode) {
|
||||
mText = text;
|
||||
mJsEventCounter = jsEventCounter;
|
||||
mContainsImages = containsImages;
|
||||
@@ -71,6 +74,7 @@ public class ReactTextUpdate {
|
||||
mPaddingBottom = paddingBottom;
|
||||
mTextAlign = textAlign;
|
||||
mTextBreakStrategy = textBreakStrategy;
|
||||
mJustificationMode = justificationMode;
|
||||
}
|
||||
|
||||
public Spannable getText() {
|
||||
@@ -108,4 +112,8 @@ public class ReactTextUpdate {
|
||||
public int getTextBreakStrategy() {
|
||||
return mTextBreakStrategy;
|
||||
}
|
||||
|
||||
public int getJustificationMode() {
|
||||
return mJustificationMode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,13 +10,13 @@ package com.facebook.react.views.text;
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.support.v7.widget.AppCompatTextView;
|
||||
import android.text.Layout;
|
||||
import android.text.Spannable;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
import android.view.Gravity;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import com.facebook.common.logging.FLog;
|
||||
import com.facebook.react.common.ReactConstants;
|
||||
import com.facebook.react.uimanager.ReactCompoundView;
|
||||
@@ -24,7 +24,7 @@ import com.facebook.react.uimanager.ViewDefaults;
|
||||
import com.facebook.react.views.view.ReactViewBackgroundManager;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class ReactTextView extends TextView implements ReactCompoundView {
|
||||
public class ReactTextView extends AppCompatTextView implements ReactCompoundView {
|
||||
|
||||
private static final ViewGroup.LayoutParams EMPTY_LAYOUT_PARAMS =
|
||||
new ViewGroup.LayoutParams(0, 0);
|
||||
@@ -72,6 +72,11 @@ public class ReactTextView extends TextView implements ReactCompoundView {
|
||||
setBreakStrategy(update.getTextBreakStrategy());
|
||||
}
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
if (getJustificationMode() != update.getJustificationMode()) {
|
||||
setJustificationMode(update.getJustificationMode());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -82,8 +82,10 @@ public class ReactTextViewManager
|
||||
// TODO add textBreakStrategy prop into local Data
|
||||
int textBreakStrategy = Layout.BREAK_STRATEGY_HIGH_QUALITY;
|
||||
|
||||
return
|
||||
new ReactTextUpdate(
|
||||
// TODO add justificationMode prop into local Data
|
||||
int justificationMode = Layout.JUSTIFICATION_MODE_NONE;
|
||||
|
||||
return new ReactTextUpdate(
|
||||
spanned,
|
||||
-1, // TODO add this into local Data?
|
||||
false, // TODO add this into local Data
|
||||
@@ -92,7 +94,8 @@ public class ReactTextViewManager
|
||||
textViewProps.getEndPadding(),
|
||||
textViewProps.getBottomPadding(),
|
||||
textViewProps.getTextAlign(),
|
||||
textBreakStrategy
|
||||
textBreakStrategy,
|
||||
justificationMode
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,8 @@ public class TextAttributeProps {
|
||||
protected int mTextAlign = Gravity.NO_GRAVITY;
|
||||
protected int mTextBreakStrategy =
|
||||
(Build.VERSION.SDK_INT < Build.VERSION_CODES.M) ? 0 : Layout.BREAK_STRATEGY_HIGH_QUALITY;
|
||||
protected int mJustificationMode =
|
||||
(Build.VERSION.SDK_INT < Build.VERSION_CODES.O) ? 0 : Layout.JUSTIFICATION_MODE_NONE;
|
||||
protected TextTransform mTextTransform = TextTransform.UNSET;
|
||||
|
||||
protected float mTextShadowOffsetDx = 0;
|
||||
@@ -204,19 +206,28 @@ public class TextAttributeProps {
|
||||
}
|
||||
|
||||
public void setTextAlign(@Nullable String textAlign) {
|
||||
if (textAlign == null || "auto".equals(textAlign)) {
|
||||
mTextAlign = Gravity.NO_GRAVITY;
|
||||
} else if ("left".equals(textAlign)) {
|
||||
mTextAlign = Gravity.LEFT;
|
||||
} else if ("right".equals(textAlign)) {
|
||||
mTextAlign = Gravity.RIGHT;
|
||||
} else if ("center".equals(textAlign)) {
|
||||
mTextAlign = Gravity.CENTER_HORIZONTAL;
|
||||
} else if ("justify".equals(textAlign)) {
|
||||
// Fallback gracefully for cross-platform compat instead of error
|
||||
if ("justify".equals(textAlign)) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
mJustificationMode = Layout.JUSTIFICATION_MODE_INTER_WORD;
|
||||
}
|
||||
mTextAlign = Gravity.LEFT;
|
||||
} else {
|
||||
throw new JSApplicationIllegalArgumentException("Invalid textAlign: " + textAlign);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
mJustificationMode = Layout.JUSTIFICATION_MODE_NONE;
|
||||
}
|
||||
|
||||
if (textAlign == null || "auto".equals(textAlign)) {
|
||||
mTextAlign = Gravity.NO_GRAVITY;
|
||||
} else if ("left".equals(textAlign)) {
|
||||
mTextAlign = Gravity.LEFT;
|
||||
} else if ("right".equals(textAlign)) {
|
||||
mTextAlign = Gravity.RIGHT;
|
||||
} else if ("center".equals(textAlign)) {
|
||||
mTextAlign = Gravity.CENTER_HORIZONTAL;
|
||||
} else {
|
||||
throw new JSApplicationIllegalArgumentException("Invalid textAlign: " + textAlign);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ rn_android_library(
|
||||
],
|
||||
deps = [
|
||||
YOGA_TARGET,
|
||||
react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"),
|
||||
react_native_dep("third-party/java/infer-annotations:infer-annotations"),
|
||||
react_native_dep("third-party/java/jsr-305:jsr-305"),
|
||||
react_native_target("java/com/facebook/react/bridge:bridge"),
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user